diff --git a/.gitignore b/.gitignore index e6877f1..3433fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,10 @@ release # OS Thumbs.db +# Electron dev cache +.electron/ +.cache/ + # 忽略 Visual Studio 临时文件夹 @@ -50,4 +54,4 @@ Thumbs.db *.ipch *.aps -wcdb/ \ No newline at end of file +wcdb/ diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index 000e346..767cf6d 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -97,7 +97,7 @@ const SessionItem = React.memo(function SessionItem({ formatTime: (timestamp: number) => string }) { // 缓存格式化的时间 - const timeText = useMemo(() => + const timeText = useMemo(() => formatTime(session.lastTimestamp || session.sortTimestamp), [formatTime, session.lastTimestamp, session.sortTimestamp] ) @@ -287,7 +287,7 @@ function ChatPage(_props: ChatPageProps) { const [highlightedMessageKeys, setHighlightedMessageKeys] = useState([]) const [isRefreshingSessions, setIsRefreshingSessions] = useState(false) const [hasInitialMessages, setHasInitialMessages] = useState(false) - + // 联系人信息加载控制 const isEnrichingRef = useRef(false) const enrichCancelledRef = useRef(false) @@ -407,28 +407,28 @@ function ChatPage(_props: ChatPageProps) { // 分批异步加载联系人信息(优化性能:防止重复加载,滚动时暂停,只在空闲时加载) const enrichSessionsContactInfo = async (sessions: ChatSession[]) => { if (sessions.length === 0) return - + // 防止重复加载 if (isEnrichingRef.current) { console.log('[性能监控] 联系人信息正在加载中,跳过重复请求') return } - + isEnrichingRef.current = true enrichCancelledRef.current = false - + console.log(`[性能监控] 开始加载联系人信息,会话数: ${sessions.length}`) const totalStart = performance.now() - + // 延迟启动,等待UI渲染完成 await new Promise(resolve => setTimeout(resolve, 500)) - + // 检查是否被取消 if (enrichCancelledRef.current) { isEnrichingRef.current = false return } - + try { // 找出需要加载联系人信息的会话(没有缓存的) const needEnrich = sessions.filter(s => !s.avatarUrl && (!s.displayName || s.displayName === s.username)) @@ -443,7 +443,7 @@ function ChatPage(_props: ChatPageProps) { // 进一步减少批次大小,每批3个,避免DLL调用阻塞 const batchSize = 3 let loadedCount = 0 - + for (let i = 0; i < needEnrich.length; i += batchSize) { // 如果正在滚动,暂停加载 if (isScrollingRef.current) { @@ -454,14 +454,14 @@ function ChatPage(_props: ChatPageProps) { } if (enrichCancelledRef.current) break } - + // 检查是否被取消 if (enrichCancelledRef.current) break - + const batchStart = performance.now() const batch = needEnrich.slice(i, i + batchSize) const usernames = batch.map(s => s.username) - + // 使用 requestIdleCallback 延迟执行,避免阻塞UI await new Promise((resolve) => { if ('requestIdleCallback' in window) { @@ -474,13 +474,13 @@ function ChatPage(_props: ChatPageProps) { }, 300) } }) - + loadedCount += batch.length const batchTime = performance.now() - batchStart if (batchTime > 200) { console.warn(`[性能监控] 批次 ${Math.floor(i / batchSize) + 1}/${Math.ceil(needEnrich.length / batchSize)} 耗时: ${batchTime.toFixed(2)}ms (已加载: ${loadedCount}/${needEnrich.length})`) } - + // 批次间延迟,给UI更多时间(DLL调用可能阻塞,需要更长的延迟) if (i + batchSize < needEnrich.length && !enrichCancelledRef.current) { // 如果不在滚动,可以延迟短一点 @@ -488,7 +488,7 @@ function ChatPage(_props: ChatPageProps) { await new Promise(resolve => setTimeout(resolve, delay)) } } - + const totalTime = performance.now() - totalStart if (!enrichCancelledRef.current) { console.log(`[性能监控] 联系人信息加载完成,总耗时: ${totalTime.toFixed(2)}ms, 已加载: ${loadedCount}/${needEnrich.length}`) @@ -570,19 +570,19 @@ function ChatPage(_props: ChatPageProps) { try { // 在 DLL 调用前让出控制权(使用 setTimeout 0 代替 setImmediate) await new Promise(resolve => setTimeout(resolve, 0)) - + const dllStart = performance.now() const result = await window.electronAPI.chat.enrichSessionsContactInfo(usernames) const dllTime = performance.now() - dllStart - + // DLL 调用后再次让出控制权 await new Promise(resolve => setTimeout(resolve, 0)) - + const totalTime = performance.now() - startTime if (dllTime > 50 || totalTime > 100) { console.warn(`[性能监控] DLL调用耗时: ${dllTime.toFixed(2)}ms, 总耗时: ${totalTime.toFixed(2)}ms, usernames: ${usernames.length}`) } - + if (result.success && result.contacts) { // 将更新加入队列,而不是立即更新 for (const [username, contact] of Object.entries(result.contacts)) { @@ -644,7 +644,7 @@ function ChatPage(_props: ChatPageProps) { const session = sessionMapRef.current.get(sessionId) const unreadCount = session?.unreadCount ?? 0 const messageLimit = offset === 0 && unreadCount > 99 ? 30 : 50 - + if (offset === 0) { setLoadingMessages(true) setMessages([]) @@ -742,7 +742,7 @@ function ChatPage(_props: ChatPageProps) { scrollTimeoutRef.current = requestAnimationFrame(() => { if (!messageListRef.current) return - + const { scrollTop, clientHeight, scrollHeight } = messageListRef.current // 显示回到底部按钮:距离底部超过 300px @@ -842,7 +842,7 @@ function ChatPage(_props: ChatPageProps) { if (!isConnected && !isConnecting) { connect() } - + // 组件卸载时清理 return () => { avatarLoadQueue.clear() @@ -906,7 +906,7 @@ function ChatPage(_props: ChatPageProps) { }) } if (payloads.length > 0) { - window.electronAPI.image.preload(payloads).catch(() => {}) + window.electronAPI.image.preload(payloads).catch(() => { }) } }, [currentSessionId, messages]) @@ -1114,7 +1114,7 @@ function ChatPage(_props: ChatPageProps) { ))} ) : Array.isArray(filteredSessions) && filteredSessions.length > 0 ? ( -
{ @@ -1195,56 +1195,56 @@ function ChatPage(_props: ChatPageProps) { ref={messageListRef} onScroll={handleScroll} > - {hasMoreMessages && ( -
- {isLoadingMore ? ( - <> - - 加载更多... - - ) : ( - 向上滚动加载更多 - )} -
- )} - - {messages.map((msg, index) => { - const prevMsg = index > 0 ? messages[index - 1] : undefined - const showDateDivider = shouldShowDateDivider(msg, prevMsg) - - // 显示时间:第一条消息,或者与上一条消息间隔超过5分钟 - const showTime = !prevMsg || (msg.createTime - prevMsg.createTime > 300) - const isSent = msg.isSend === 1 - const isSystem = msg.localType === 10000 - - // 系统消息居中显示 - const wrapperClass = isSystem ? 'system' : (isSent ? 'sent' : 'received') - - const messageKey = getMessageKey(msg) - return ( -
- {showDateDivider && ( -
- {formatDateDivider(msg.createTime)} -
- )} - -
- ) - })} - - {/* 回到底部按钮 */} -
- - 回到底部 + {hasMoreMessages && ( +
+ {isLoadingMore ? ( + <> + + 加载更多... + + ) : ( + 向上滚动加载更多 + )}
+ )} + + {messages.map((msg, index) => { + const prevMsg = index > 0 ? messages[index - 1] : undefined + const showDateDivider = shouldShowDateDivider(msg, prevMsg) + + // 显示时间:第一条消息,或者与上一条消息间隔超过5分钟 + const showTime = !prevMsg || (msg.createTime - prevMsg.createTime > 300) + const isSent = msg.isSend === 1 + const isSystem = msg.localType === 10000 + + // 系统消息居中显示 + const wrapperClass = isSystem ? 'system' : (isSent ? 'sent' : 'received') + + const messageKey = getMessageKey(msg) + return ( +
+ {showDateDivider && ( +
+ {formatDateDivider(msg.createTime)} +
+ )} + +
+ ) + })} + + {/* 回到底部按钮 */} +
+ + 回到底部
+
{/* 会话详情面板 */} {showDetailPanel && ( @@ -1434,7 +1434,7 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }: bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50) { return 'image/webp' } - } catch {} + } catch { } return 'image/jpeg' }, []) @@ -1501,7 +1501,7 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }: setSenderAvatarUrl(result.avatarUrl) setSenderName(result.displayName) } - }).catch(() => {}).finally(() => { + }).catch(() => { }).finally(() => { senderAvatarLoading.delete(sender) }) } @@ -1597,7 +1597,7 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }: } setImageHasUpdate(Boolean(result.hasUpdate)) } - }).catch(() => {}) + }).catch(() => { }) return () => { cancelled = true } @@ -1685,6 +1685,12 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }: // 是否有引用消息 const hasQuote = message.quotedContent && message.quotedContent.length > 0 + // 去除企业微信 ID 前缀 + const cleanMessageContent = (content: string) => { + if (!content) return '' + return content.replace(/^[a-zA-Z0-9]+@openim:\n?/, '') + } + // 解析混合文本和表情 const renderTextWithEmoji = (text: string) => { if (!text) return text @@ -1895,14 +1901,14 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }:
{message.quotedSender && {message.quotedSender}} - {renderTextWithEmoji(message.quotedContent || '')} + {renderTextWithEmoji(cleanMessageContent(message.quotedContent || ''))}
-
{renderTextWithEmoji(message.parsedContent)}
+
{renderTextWithEmoji(cleanMessageContent(message.parsedContent))}
) } // 普通消息 - return
{renderTextWithEmoji(message.parsedContent)}
+ return
{renderTextWithEmoji(cleanMessageContent(message.parsedContent))}
} return ( diff --git a/src/pages/WelcomePage.tsx b/src/pages/WelcomePage.tsx index d7a08de..c346569 100644 --- a/src/pages/WelcomePage.tsx +++ b/src/pages/WelcomePage.tsx @@ -506,6 +506,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) { {dbKeyStatus &&
{dbKeyStatus}
}
获取密钥会自动识别最近登录的账号
+
如果获取秘钥失败 请在微信打开后等待10秒后再登录
)}