From 39e527a21a5a0f501d595e82d0a137f2b84007f7 Mon Sep 17 00:00:00 2001 From: cc <98377878+hicccc77@users.noreply.github.com> Date: Sun, 10 May 2026 15:17:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=85=A8=E5=B1=80wx?= =?UTF-8?q?id=E9=94=99=E8=AF=AF=E6=B8=85=E6=B4=97=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron/main.ts | 14 +++++------ electron/services/analyticsService.ts | 8 +++---- electron/services/backupService.ts | 2 +- electron/services/bizService.ts | 2 +- electron/services/chatService.ts | 26 ++++++++++----------- electron/services/config.ts | 8 +++++++ electron/services/exportService.ts | 2 +- electron/services/groupAnalyticsService.ts | 4 ++-- electron/services/httpService.ts | 4 ++-- electron/services/imageDecryptService.ts | 2 +- electron/services/insightRecordService.ts | 2 +- electron/services/snsService.ts | 2 +- electron/services/videoService.ts | 2 +- electron/services/wcdbCore.ts | 16 ++++++++++++- src/services/config.ts | 27 +++++++++++++++++++++- 15 files changed, 84 insertions(+), 37 deletions(-) diff --git a/electron/main.ts b/electron/main.ts index 27c443c..58df32c 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -2430,7 +2430,7 @@ function registerIpcHandlers() { return { success: false, error: '请至少选择一项清理范围' } } - const rawWxid = String(cfg.get('myWxid') || '').trim() + const rawWxid = String(cfg.getMyWxidCleaned() || '').trim() if (!rawWxid) { return { success: false, error: '当前账号未登录或未识别,无法清理' } } @@ -3180,7 +3180,7 @@ function registerIpcHandlers() { const logEnabled = cfg.get('logEnabled') const dbPath = String(cfg.get('dbPath') || '').trim() const decryptKey = String(cfg.get('decryptKey') || '').trim() - const myWxid = String(cfg.get('myWxid') || '').trim() + const myWxid = String(cfg.getMyWxidCleaned() || '').trim() const imageKeys = cfg.getImageKeysForCurrentWxid() const resourcesPath = app.isPackaged ? join(process.resourcesPath, 'resources') @@ -3329,7 +3329,7 @@ function registerIpcHandlers() { options, dbPath: String(cfg.get('dbPath') || '').trim(), decryptKey: String(cfg.get('decryptKey') || '').trim(), - myWxid: String(cfg.get('myWxid') || '').trim(), + myWxid: String(cfg.getMyWxidCleaned() || '').trim(), imageXorKey: imageKeys.xorKey, imageAesKey: imageKeys.aesKey, resourcesPath: app.isPackaged ? join(process.resourcesPath, 'resources') : join(app.getAppPath(), 'resources'), @@ -3398,7 +3398,7 @@ function registerIpcHandlers() { options, dbPath: String(cfg.get('dbPath') || '').trim(), decryptKey: String(cfg.get('decryptKey') || '').trim(), - myWxid: String(cfg.get('myWxid') || '').trim(), + myWxid: String(cfg.getMyWxidCleaned() || '').trim(), resourcesPath: app.isPackaged ? join(process.resourcesPath, 'resources') : join(app.getAppPath(), 'resources'), userDataPath: app.getPath('userData'), logEnabled: cfg.get('logEnabled') @@ -3631,7 +3631,7 @@ function registerIpcHandlers() { return annualReportService.getAvailableYears({ dbPath: cfg.get('dbPath'), decryptKey: cfg.get('decryptKey'), - wxid: cfg.get('myWxid') + wxid: cfg.getMyWxidCleaned() }) }) @@ -3828,7 +3828,7 @@ function registerIpcHandlers() { const dbPath = cfg.get('dbPath') const decryptKey = cfg.get('decryptKey') - const wxid = cfg.get('myWxid') + const wxid = cfg.getMyWxidCleaned() const logEnabled = cfg.get('logEnabled') const resourcesPath = app.isPackaged @@ -3889,7 +3889,7 @@ function registerIpcHandlers() { const dbPath = cfg.get('dbPath') const decryptKey = cfg.get('decryptKey') - const wxid = cfg.get('myWxid') + const wxid = cfg.getMyWxidCleaned() const logEnabled = cfg.get('logEnabled') const friendUsername = payload?.friendUsername const year = payload?.year ?? 0 diff --git a/electron/services/analyticsService.ts b/electron/services/analyticsService.ts index a340b36..d50133e 100644 --- a/electron/services/analyticsService.ts +++ b/electron/services/analyticsService.ts @@ -127,6 +127,7 @@ class AnalyticsService { const wxid = this.configService.get('myWxid') const dbPath = this.configService.get('dbPath') const decryptKey = this.configService.get('decryptKey') + if (!wxid) return { success: false, error: '未配置微信ID' } if (!dbPath) return { success: false, error: '未配置数据库路径' } if (!decryptKey) return { success: false, error: '未配置解密密钥' } @@ -138,6 +139,7 @@ class AnalyticsService { if (!ok) return { success: false, error: 'WCDB 打开失败' } const cleanedWxid = this.cleanAccountDirName(wxid) + return { success: true, cleanedWxid } } @@ -237,8 +239,7 @@ class AnalyticsService { } private async computeAggregateByCursor(sessionIds: string[], beginTimestamp = 0, endTimestamp = 0): Promise { - const wxid = this.configService.get('myWxid') - const cleanedWxid = wxid ? this.cleanAccountDirName(wxid) : '' + const cleanedWxid = this.configService.getMyWxidCleaned() || '' const aggregate = { total: 0, @@ -275,8 +276,7 @@ class AnalyticsService { const myWxidLower = cleanedWxid.toLowerCase() isSend = ( senderLower === myWxidLower || - // 兼容非 wxid 开头的账号(如果文件夹名带后缀,如 custom_backup,而 sender 是 custom) - (myWxidLower.startsWith(senderLower + '_')) + senderLower.startsWith(myWxidLower + '_') ) } } diff --git a/electron/services/backupService.ts b/electron/services/backupService.ts index abc1367..e26a4a4 100644 --- a/electron/services/backupService.ts +++ b/electron/services/backupService.ts @@ -447,7 +447,7 @@ export class BackupService { } private async ensureConnected(wxidOverride?: string): Promise<{ success: boolean; wxid?: string; dbPath?: string; dbStorage?: string; error?: string }> { - const configuredWxid = String(this.configService.get('myWxid') || '').trim() + const configuredWxid = String(this.configService.getMyWxidCleaned() || '').trim() const wxid = String(wxidOverride || configuredWxid || '').trim() const dbPath = String(this.configService.get('dbPath') || '').trim() const decryptKey = String(this.configService.get('decryptKey') || '').trim() diff --git a/electron/services/bizService.ts b/electron/services/bizService.ts index a5bb984..2ee481e 100644 --- a/electron/services/bizService.ts +++ b/electron/services/bizService.ts @@ -100,7 +100,7 @@ export class BizService { const contactInfoMap = enrichment.success && enrichment.contacts ? enrichment.contacts : {} const root = this.configService.get('dbPath') - const myWxid = this.configService.get('myWxid') + const myWxid = this.configService.getMyWxidCleaned() const accountWxid = account || myWxid if (!root || !accountWxid) return [] diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index 9966927..b827d41 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -851,7 +851,7 @@ class ChatService { // 转换为 ChatSession(先加载缓存,但不等待额外状态查询) const sessions: ChatSession[] = [] const now = Date.now() - const myWxid = this.configService.get('myWxid') + const myWxid = this.configService.getMyWxidCleaned() for (const row of rows) { const username = @@ -1086,7 +1086,7 @@ class ChatService { const contactMap = await this.loadAntiRevokeContactMap(privateCandidateIds) const sessions: ChatSession[] = [] - const myWxid = this.configService.get('myWxid') + const myWxid = this.configService.getMyWxidCleaned() const now = Date.now() for (const { username, row } of candidateRows) { @@ -2027,7 +2027,7 @@ class ChatService { private getContactsCacheScope(): string { const dbPath = String(this.configService.get('dbPath') || '').trim() - const myWxid = String(this.configService.get('myWxid') || '').trim() + const myWxid = String(this.configService.getMyWxidCleaned() || '').trim() return `${dbPath}::${myWxid}` } @@ -3699,7 +3699,7 @@ class ChatService { } } - const myWxid = String(this.configService.get('myWxid') || '').trim() + const myWxid = String(this.configService.getMyWxidCleaned() || '').trim() const selfKeys = this.buildIdentityKeys(myWxid) if (selfKeys.length === 0) { return { @@ -3877,7 +3877,7 @@ class ChatService { private refreshSessionMessageCountCacheScope(): void { const dbPath = String(this.configService.get('dbPath') || '') - const myWxid = String(this.configService.get('myWxid') || '') + const myWxid = String(this.configService.getMyWxidCleaned() || '') const scope = `${dbPath}::${myWxid}` if (scope === this.sessionMessageCountCacheScope) { this.refreshSessionStatsCacheScope(scope) @@ -4831,7 +4831,7 @@ class ChatService { } mapRowsToMessagesLiteForApi(rows: Record[]): Message[] { - const myWxid = String(this.configService.get('myWxid') || '').trim() + const myWxid = String(this.configService.getMyWxidCleaned() || '').trim() const messages: Message[] = [] for (const row of rows) { const sourceInfo = this.getMessageSourceInfo(row) @@ -4882,7 +4882,7 @@ class ChatService { } private mapRowsToMessages(rows: Record[], sessionId: string): Message[] { - const myWxid = this.configService.get('myWxid') + const myWxid = this.configService.getMyWxidCleaned() const messages: Message[] = [] for (const row of rows) { @@ -7265,7 +7265,7 @@ class ChatService { } // 获取当前用户 wxid,用于识别"自己" - const myWxid = this.configService.get('myWxid') + const myWxid = this.configService.getMyWxidCleaned() const cleanedMyWxid = myWxid ? this.cleanAccountDirName(myWxid) : '' // 解析付款方名称:自己 > 群昵称 > 备注 > 昵称 > alias > wxid @@ -7319,7 +7319,7 @@ class ChatService { return { success: false, error: connectResult.error } } - const myWxid = this.configService.get('myWxid') + const myWxid = this.configService.getMyWxidCleaned() if (!myWxid) { return { success: false, error: '未配置微信ID' } } @@ -7963,7 +7963,7 @@ class ChatService { } if (pendingSessionIds.length > 0) { - const myWxid = this.configService.get('myWxid') || '' + const myWxid = this.configService.getMyWxidCleaned() || '' const selfIdentitySet = new Set(this.buildIdentityKeys(myWxid)) let usedBatchedCompute = false if (pendingSessionIds.length === 1) { @@ -8270,7 +8270,7 @@ class ChatService { // 构建查找候选 const candidates: string[] = [] - const myWxid = this.configService.get('myWxid') as string + const myWxid = this.configService.getMyWxidCleaned() as string // 如果有 senderWxid,优先使用(群聊中最重要) if (senderWxid) { @@ -8469,7 +8469,7 @@ class ChatService { if (!normalizedSessionId) return { success: true, prepared: 0 } if (!Array.isArray(messages) || messages.length === 0) return { success: true, prepared: 0 } - const myWxid = String(this.configService.get('myWxid') || '').trim() + const myWxid = String(this.configService.getMyWxidCleaned() || '').trim() const nowPrepared = new Set() const pending: Array<{ cacheKey: string @@ -9207,7 +9207,7 @@ class ChatService { let myWxid = String(options?.myWxid || '').trim() if (!myWxid) { - myWxid = String(this.configService.get('myWxid') || '').trim() + myWxid = String(this.configService.getMyWxidCleaned() || '').trim() } if (!myWxid) { return { success: false, error: '未识别当前账号 wxid' } diff --git a/electron/services/config.ts b/electron/services/config.ts index 9bd3f26..5dd014d 100644 --- a/electron/services/config.ts +++ b/electron/services/config.ts @@ -837,6 +837,14 @@ export class ConfigService { // === 工具方法 === + /** + * 获取当前用户 wxid(清洗后,不带后缀) + */ + getMyWxidCleaned(): string { + const wxid = this.get('myWxid') + return wxid ? this.cleanAccountDirName(wxid) : '' + } + /** * 获取当前 wxid 对应的图片密钥,优先从 wxidConfigs 中取,找不到则回退到全局配置 */ diff --git a/electron/services/exportService.ts b/electron/services/exportService.ts index 1816908..72198df 100644 --- a/electron/services/exportService.ts +++ b/electron/services/exportService.ts @@ -338,7 +338,7 @@ class ExportService { } private getConfiguredMyWxid(): string { - return String(this.runtimeConfig?.myWxid || this.configService.get('myWxid') || '').trim() + return String(this.runtimeConfig?.myWxid || this.configService.getMyWxidCleaned() || '').trim() } private normalizeSessionIds(sessionIds: string[]): string[] { diff --git a/electron/services/groupAnalyticsService.ts b/electron/services/groupAnalyticsService.ts index 7884abc..9d93072 100644 --- a/electron/services/groupAnalyticsService.ts +++ b/electron/services/groupAnalyticsService.ts @@ -251,7 +251,7 @@ class GroupAnalyticsService { } private async ensureConnected(): Promise<{ success: boolean; error?: string }> { - const wxid = this.configService.get('myWxid') + const wxid = this.configService.getMyWxidCleaned() const dbPath = this.configService.get('dbPath') const decryptKey = this.configService.get('decryptKey') if (!wxid) return { success: false, error: '未配置微信ID' } @@ -1557,7 +1557,7 @@ class GroupAnalyticsService { const phraseCounts = new Map() const emojiCounts = new Map() - const myWxid = String(this.configService.get('myWxid') || '').trim() + const myWxid = String(this.configService.getMyWxidCleaned() || '').trim() try { while (true) { diff --git a/electron/services/httpService.ts b/electron/services/httpService.ts index 1e9b014..dd447b4 100644 --- a/electron/services/httpService.ts +++ b/electron/services/httpService.ts @@ -674,7 +674,7 @@ class HttpService { const targets = messages.filter((msg) => !String(msg.senderUsername || '').trim()) if (targets.length === 0) return - const myWxid = (this.configService.get('myWxid') || '').trim() + const myWxid = (this.configService.getMyWxidCleaned() || '').trim() const MAX_DETAIL_BACKFILL = 120 if (targets.length > MAX_DETAIL_BACKFILL) { for (const msg of targets) { @@ -1832,7 +1832,7 @@ class HttpService { mediaMap: Map = new Map() ): Promise { const isGroup = talkerId.endsWith('@chatroom') - const myWxid = this.configService.get('myWxid') || '' + const myWxid = this.configService.getMyWxidCleaned() || '' const normalizedMyWxid = this.normalizeAccountId(myWxid).toLowerCase() // 收集所有发送者 diff --git a/electron/services/imageDecryptService.ts b/electron/services/imageDecryptService.ts index 6b9cc33..e8cc420 100644 --- a/electron/services/imageDecryptService.ts +++ b/electron/services/imageDecryptService.ts @@ -109,7 +109,7 @@ export class ImageDecryptService { } private getConfiguredMyWxid(): string { - return String(this.runtimeConfig?.myWxid || this.configService.get('myWxid') || '').trim() + return String(this.runtimeConfig?.myWxid || this.configService.getMyWxidCleaned() || '').trim() } private getConfiguredImageKeys(): { xorKey: unknown; aesKey: string } { diff --git a/electron/services/insightRecordService.ts b/electron/services/insightRecordService.ts index 9539ea7..762b372 100644 --- a/electron/services/insightRecordService.ts +++ b/electron/services/insightRecordService.ts @@ -116,7 +116,7 @@ class InsightRecordService { private getCurrentAccountScope(): string { const config = ConfigService.getInstance() - const myWxid = String(config.get('myWxid') || '').trim() + const myWxid = String(config.getMyWxidCleaned() || '').trim() if (myWxid) return `wxid:${myWxid}` const dbPath = String(config.get('dbPath') || '').trim() diff --git a/electron/services/snsService.ts b/electron/services/snsService.ts index 68cb0fb..65d4941 100644 --- a/electron/services/snsService.ts +++ b/electron/services/snsService.ts @@ -914,7 +914,7 @@ class SnsService { const allowTimelineFallback = options?.allowTimelineFallback ?? true const preferCache = options?.preferCache ?? false const now = Date.now() - const myWxid = this.toOptionalString(this.configService.get('myWxid')) + const myWxid = this.toOptionalString(this.configService.getMyWxidCleaned()) try { if (preferCache && this.exportStatsCache && now - this.exportStatsCache.updatedAt <= this.exportStatsCacheTtlMs) { diff --git a/electron/services/videoService.ts b/electron/services/videoService.ts index 33c6bb7..d562705 100644 --- a/electron/services/videoService.ts +++ b/electron/services/videoService.ts @@ -96,7 +96,7 @@ class VideoService { * 获取当前用户的wxid */ private getMyWxid(): string { - return this.configService.get('myWxid') || '' + return this.configService.getMyWxidCleaned() || '' } /** diff --git a/electron/services/wcdbCore.ts b/electron/services/wcdbCore.ts index 2f0288c..4e4e3af 100644 --- a/electron/services/wcdbCore.ts +++ b/electron/services/wcdbCore.ts @@ -11,6 +11,19 @@ export function getLastDllInitError(): string | null { return lastDllInitError } +function 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 +} + export class WcdbCore { private resourcesPath: string | null = null private userDataPath: string | null = null @@ -1607,7 +1620,8 @@ export class WcdbCore { } // 从账号目录路径中提取 wxid(目录名) - const wxid = basename(accountDir) + const rawWxid = basename(accountDir) + const wxid = cleanAccountDirName(rawWxid) this.handle = handle this.currentPath = accountDir diff --git a/src/services/config.ts b/src/services/config.ts index 777e4dd..96fd237 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -198,12 +198,37 @@ export async function setDbPath(path: string): Promise { await config.set(CONFIG_KEYS.DB_PATH, path) } -// 获取当前用户 wxid +// 清洗账号目录名称(移除后缀) +function cleanAccountDirName(dirName: string): string { + const trimmed = dirName.trim() + if (!trimmed) return trimmed + + // wxid_ 开头的特殊处理 + if (trimmed.toLowerCase().startsWith('wxid_')) { + const match = trimmed.match(/^(wxid_[^_]+)/i) + if (match) return match[1] + return trimmed + } + + // 移除4位后缀 + const suffixMatch = trimmed.match(/^(.+)_([a-zA-Z0-9]{4})$/) + if (suffixMatch) return suffixMatch[1] + + return trimmed +} + +// 获取当前用户 wxid(原始值,可能带后缀) export async function getMyWxid(): Promise { const value = await config.get(CONFIG_KEYS.MY_WXID) return value as string | null } +// 获取当前用户 wxid(清洗后,不带后缀) +export async function getMyWxidCleaned(): Promise { + const value = await getMyWxid() + return value ? cleanAccountDirName(value) : null +} + // 设置当前用户 wxid export async function setMyWxid(wxid: string): Promise { await config.set(CONFIG_KEYS.MY_WXID, wxid)