From 1d8a7d2e6318bd85424ae3696a1efab0f9d14f53 Mon Sep 17 00:00:00 2001 From: xuncha <1658671838@qq.com> Date: Wed, 4 Mar 2026 21:26:20 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BA=AF=E9=BB=91?= =?UTF-8?q?=E7=99=BD=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SettingsPage.tsx | 8 ++++-- src/stores/themeStore.ts | 9 ++++++- src/styles/main.scss | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 375b9cd..a90c73e 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -979,8 +979,12 @@ function SettingsPage() {
setTheme(theme.id)}>
Date: Thu, 5 Mar 2026 14:26:37 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E9=A1=B5=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- electron/services/chatService.ts | 18 +++++++++- src/components/Sidebar.scss | 4 +-- src/components/Sidebar.tsx | 14 ++++++-- src/pages/ExportPage.scss | 7 ++-- src/pages/ExportPage.tsx | 4 ++- src/pages/SettingsPage.tsx | 30 ++++------------- src/styles/main.scss | 57 +++++++++++++++++--------------- src/types/models.ts | 1 + 9 files changed, 78 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index a173bbb..34a4ef5 100644 --- a/.gitignore +++ b/.gitignore @@ -64,4 +64,5 @@ chatlab-format.md AGENTS.md .claude/ .agents/ -resources/wx_send \ No newline at end of file +resources/wx_send +概述.md \ No newline at end of file diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index b77fa3a..e50817e 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -136,6 +136,7 @@ export interface ContactInfo { displayName: string remark?: string nickname?: string + alias?: string avatarUrl?: string type: 'friend' | 'group' | 'official' | 'former_friend' | 'other' } @@ -1392,6 +1393,7 @@ class ChatService { displayName, remark: row.remark || undefined, nickname: row.nick_name || undefined, + alias: row.alias || undefined, avatarUrl: undefined, type, lastContactTime: lastContactTimeMap.get(username) || 0 @@ -4630,9 +4632,23 @@ class ChatService { const result = await wcdbService.getContact(username) if (!result.success || !result.contact) return null const contact = result.contact as Record + let alias = String(contact.alias || contact.Alias || '') + // DLL 有时不返回 alias 字段,补一条直接 SQL 查询兜底 + if (!alias) { + try { + const safe = username.replace(/'/g, "''") + const sqlResult = await wcdbService.execQuery('contact', null, + `SELECT alias FROM contact WHERE username = '${safe}' LIMIT 1`) + if (sqlResult.success && Array.isArray(sqlResult.rows) && sqlResult.rows.length > 0) { + alias = String(sqlResult.rows[0]?.alias || sqlResult.rows[0]?.Alias || '') + } + } catch { + // 兜底失败不影响主流程 + } + } return { username: String(contact.username || contact.user_name || contact.userName || username || ''), - alias: String(contact.alias || contact.Alias || ''), + alias, remark: String(contact.remark || contact.Remark || ''), // 兼容不同表结构字段,避免 nick_name 丢失导致侧边栏退化到 wxid。 nickName: String(contact.nickName || contact.nick_name || contact.nickname || contact.NickName || '') diff --git a/src/components/Sidebar.scss b/src/components/Sidebar.scss index 81d1ec2..bdead0a 100644 --- a/src/components/Sidebar.scss +++ b/src/components/Sidebar.scss @@ -112,7 +112,7 @@ } span { - color: #fff; + color: var(--on-primary); font-size: 14px; font-weight: 600; } @@ -183,7 +183,7 @@ &.active { background: var(--primary); - color: white; + color: var(--on-primary); } } diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 1022607..b72ddcd 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -10,6 +10,7 @@ import './Sidebar.scss' interface SidebarUserProfile { wxid: string displayName: string + alias?: string avatarUrl?: string } @@ -29,6 +30,7 @@ const readSidebarUserProfileCache = (): SidebarUserProfile | null => { return { wxid: parsed.wxid, displayName: parsed.displayName, + alias: parsed.alias, avatarUrl: parsed.avatarUrl } } catch { @@ -193,6 +195,10 @@ function Sidebar() { if (fromContact) { patchUserProfile({ displayName: fromContact }, resolvedWxid) + // 同步补充微信号(alias) + if (myContact?.alias) { + patchUserProfile({ alias: myContact.alias }, resolvedWxid) + } return } @@ -209,6 +215,10 @@ function Sidebar() { if (bestName) { patchUserProfile({ displayName: bestName }, resolvedWxid) } + // 降级分支也补充微信号 + if (myContact?.alias) { + patchUserProfile({ alias: myContact.alias }, resolvedWxid) + } } catch (nameError) { console.error('加载侧边栏用户昵称失败:', nameError) } @@ -429,7 +439,7 @@ function Sidebar() { )}
setIsAccountMenuOpen(prev => !prev)} role="button" tabIndex={0} @@ -445,7 +455,7 @@ function Sidebar() {
{userProfile.displayName}
-
{userProfile.wxid || 'wxid 未识别'}
+
{userProfile.alias || userProfile.wxid || 'wxid 未识别'}
{!collapsed && ( diff --git a/src/pages/ExportPage.scss b/src/pages/ExportPage.scss index 4f26328..270f0c0 100644 --- a/src/pages/ExportPage.scss +++ b/src/pages/ExportPage.scss @@ -93,7 +93,7 @@ border-radius: 12px; padding: 12px; display: grid; - grid-template-columns: minmax(0, 1fr) max-content minmax(0, 1fr); + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; align-items: stretch; @@ -176,14 +176,13 @@ flex-direction: column; gap: 4px; min-width: 0; - width: fit-content; + width: 100%; max-width: 100%; - justify-self: start; z-index: 40; } .layout-trigger { - width: auto; + width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border-color); diff --git a/src/pages/ExportPage.tsx b/src/pages/ExportPage.tsx index 5768100..3b56b13 100644 --- a/src/pages/ExportPage.tsx +++ b/src/pages/ExportPage.tsx @@ -3301,6 +3301,8 @@ function ExportPage() { return ( (contact.displayName || '').toLowerCase().includes(keyword) || (contact.remark || '').toLowerCase().includes(keyword) || + (contact.nickname || '').toLowerCase().includes(keyword) || + (contact.alias || '').toLowerCase().includes(keyword) || contact.username.toLowerCase().includes(keyword) ) }) @@ -3841,7 +3843,7 @@ function ExportPage() {
{contact.displayName}
-
{contact.username}
+
{contact.alias || contact.username}
diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 9626fec..91b121a 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -36,18 +36,6 @@ interface WxidOption { modifiedTime: number } -const formatDbKeyFailureMessage = (error?: string, logs?: string[]): string => { - const base = String(error || '自动获取密钥失败').trim() - const tailLogs = Array.isArray(logs) - ? logs - .map(item => String(item || '').trim()) - .filter(Boolean) - .slice(-6) - : [] - if (tailLogs.length === 0) return base - return `${base};最近状态:${tailLogs.join(' | ')}` -} - function SettingsPage() { const { isDbConnected, @@ -115,12 +103,12 @@ function SettingsPage() { const [autoTranscribeVoice, setAutoTranscribeVoice] = useState(false) const [transcribeLanguages, setTranscribeLanguages] = useState(['zh']) - const [exportDefaultFormat, setExportDefaultFormat] = useState('json') + const [exportDefaultFormat, setExportDefaultFormat] = useState('excel') const [exportDefaultDateRange, setExportDefaultDateRange] = useState('today') const [exportDefaultMedia, setExportDefaultMedia] = useState(false) const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(false) const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true) - const [exportDefaultConcurrency, setExportDefaultConcurrency] = useState(4) + const [exportDefaultConcurrency, setExportDefaultConcurrency] = useState(2) const [notificationEnabled, setNotificationEnabled] = useState(true) const [notificationPosition, setNotificationPosition] = useState<'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'>('top-right') @@ -298,6 +286,7 @@ function SettingsPage() { const savedWhisperModelDir = await configService.getWhisperModelDir() const savedAutoTranscribe = await configService.getAutoTranscribeVoice() const savedTranscribeLanguages = await configService.getTranscribeLanguages() + const savedExportDefaultFormat = await configService.getExportDefaultFormat() const savedExportDefaultDateRange = await configService.getExportDefaultDateRange() const savedExportDefaultMedia = await configService.getExportDefaultMedia() const savedExportDefaultVoiceAsText = await configService.getExportDefaultVoiceAsText() @@ -338,13 +327,12 @@ function SettingsPage() { setLogEnabled(savedLogEnabled) setAutoTranscribeVoice(savedAutoTranscribe) setTranscribeLanguages(savedTranscribeLanguages) - setExportDefaultFormat('json') - await configService.setExportDefaultFormat('json') + setExportDefaultFormat(savedExportDefaultFormat || 'excel') setExportDefaultDateRange(savedExportDefaultDateRange || 'today') setExportDefaultMedia(savedExportDefaultMedia ?? false) setExportDefaultVoiceAsText(savedExportDefaultVoiceAsText ?? false) setExportDefaultExcelCompactColumns(savedExportDefaultExcelCompactColumns ?? true) - setExportDefaultConcurrency(savedExportDefaultConcurrency ?? 4) + setExportDefaultConcurrency(savedExportDefaultConcurrency ?? 2) setNotificationEnabled(savedNotificationEnabled) setNotificationPosition(savedNotificationPosition) @@ -737,10 +725,7 @@ function SettingsPage() { setIsManualStartPrompt(true) setDbKeyStatus('需要手动启动微信') } else { - if (result.error?.includes('尚未完成登录')) { - setDbKeyStatus('请先在微信完成登录后重试') - } - showMessage(formatDbKeyFailureMessage(result.error, result.logs), false) + showMessage(result.error || '自动获取密钥失败', false) } } } catch (e: any) { @@ -995,7 +980,7 @@ function SettingsPage() {
Date: Thu, 5 Mar 2026 14:31:15 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=9B=BE=E7=89=87=E8=A7=A3=E5=AF=86++?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ChatPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index 9650866..90df9aa 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -5194,13 +5194,13 @@ function MessageBubble({ imageClickTimerRef.current = window.setTimeout(() => { setImageClicked(false) }, 800) - console.info('[UI] image decrypt click', { + console.info('[UI] image decrypt click (force HD)', { sessionId: session.username, imageMd5: message.imageMd5, imageDatName: message.imageDatName, localId: message.localId }) - void requestImageDecrypt() + void requestImageDecrypt(true) }, [message.imageDatName, message.imageMd5, message.localId, requestImageDecrypt, session.username]) const handleOpenImageViewer = useCallback(async () => {