diff --git a/electron/services/accountDirResolver.ts b/electron/services/accountDirResolver.ts new file mode 100644 index 0000000..1ad8c7a --- /dev/null +++ b/electron/services/accountDirResolver.ts @@ -0,0 +1,73 @@ +import { existsSync, readdirSync, statSync } from 'fs' +import { join } from 'path' + +const accountDirCache = new Map() + +const cleanAccountDirName = (dirName: string): string => { + const trimmed = dirName.trim() + if (!trimmed) return trimmed + + if (trimmed.toLowerCase().startsWith('wxid_')) { + const match = trimmed.match(/^(wxid_[^_]+)/i) + if (match) return match[1] + return trimmed + } + + const suffixMatch = trimmed.match(/^(.+)_([a-zA-Z0-9]{4})$/) + if (suffixMatch) return suffixMatch[1] + + return trimmed +} + +const isDirectory = (path: string): boolean => { + try { + return statSync(path).isDirectory() + } catch { + return false + } +} + +export const resolveAccountDir = (dbPath?: string, wxid?: string): string | null => { + if (!dbPath || !wxid) return null + + const cleanedWxid = cleanAccountDirName(wxid) + const normalized = dbPath.replace(/[\\/]+$/, '') + const cacheKey = `${normalized}|${cleanedWxid.toLowerCase()}` + + const cached = accountDirCache.get(cacheKey) + if (cached && existsSync(cached)) return cached + if (cached && !existsSync(cached)) { + accountDirCache.delete(cacheKey) + } + + const lowerWxid = cleanedWxid.toLowerCase() + if (!lowerWxid.startsWith('wxid_')) { + const direct = join(normalized, cleanedWxid) + if (existsSync(direct) && isDirectory(direct)) { + accountDirCache.set(cacheKey, direct) + return direct + } + } + + try { + const entries = readdirSync(normalized) + for (const entry of entries) { + const entryPath = join(normalized, entry) + if (!isDirectory(entryPath)) continue + + const lowerEntry = entry.toLowerCase() + const isExactMatch = lowerEntry === lowerWxid + const isSuffixMatch = lowerEntry.startsWith(`${lowerWxid}_`) + const shouldMatch = lowerWxid.startsWith('wxid_') + ? isSuffixMatch + : (isExactMatch || isSuffixMatch) + + if (shouldMatch) { + accountDirCache.set(cacheKey, entryPath) + return entryPath + } + } + } catch { } + + return null +} diff --git a/electron/services/annualReportService.ts b/electron/services/annualReportService.ts index bf56492..04faedf 100644 --- a/electron/services/annualReportService.ts +++ b/electron/services/annualReportService.ts @@ -1,6 +1,6 @@ import { parentPort } from 'worker_threads' import { wcdbService } from './wcdbService' -import { ConfigService } from './config' +import { resolveAccountDir } from './accountDirResolver' export interface TopContact { username: string @@ -159,8 +159,7 @@ class AnnualReportService { if (!dbPath) return { success: false, error: '未配置数据库路径' } if (!decryptKey) return { success: false, error: '未配置解密密钥' } - const configService = ConfigService.getInstance() - const accountDir = configService.getAccountDir(dbPath, wxid) + const accountDir = resolveAccountDir(dbPath, wxid) if (!accountDir) return { success: false, error: '未找到账号目录' } const ok = await wcdbService.open(accountDir, decryptKey) diff --git a/electron/services/dualReportService.ts b/electron/services/dualReportService.ts index 07a6d4a..1d8de7b 100644 --- a/electron/services/dualReportService.ts +++ b/electron/services/dualReportService.ts @@ -1,6 +1,6 @@ import { parentPort } from 'worker_threads' import { wcdbService } from './wcdbService' -import { ConfigService } from './config' +import { resolveAccountDir } from './accountDirResolver' export interface DualReportMessage { @@ -110,8 +110,7 @@ class DualReportService { if (!dbPath) return { success: false, error: '未配置数据库路径' } if (!decryptKey) return { success: false, error: '未配置解密密钥' } - const configService = ConfigService.getInstance() - const accountDir = configService.getAccountDir(dbPath, wxid) + const accountDir = resolveAccountDir(dbPath, wxid) if (!accountDir) return { success: false, error: '无法找到账号目录' } const ok = await wcdbService.open(accountDir, decryptKey) if (!ok) return { success: false, error: 'WCDB 打开失败' }