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() {
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 () => {