From 8aaad71784985e4344caee01bf3d6bc2e36e1458 Mon Sep 17 00:00:00 2001 From: tisonhuang Date: Thu, 5 Mar 2026 09:34:57 +0800 Subject: [PATCH] refactor(sns): remove contact post-count stats flow --- electron/main.ts | 4 -- electron/preload.ts | 1 - electron/services/snsService.ts | 38 -------------- src/components/Sns/SnsFilterPanel.tsx | 16 +----- src/pages/SnsPage.scss | 19 ------- src/pages/SnsPage.tsx | 75 +-------------------------- src/types/electron.d.ts | 1 - 7 files changed, 3 insertions(+), 151 deletions(-) diff --git a/electron/main.ts b/electron/main.ts index 2b7feb4..7401603 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1260,10 +1260,6 @@ function registerIpcHandlers() { return snsService.getSnsUsernames() }) - ipcMain.handle('sns:getUserPostCounts', async () => { - return snsService.getUserPostCounts() - }) - ipcMain.handle('sns:getExportStats', async () => { return snsService.getExportStats() }) diff --git a/electron/preload.ts b/electron/preload.ts index 46349a6..068e488 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -337,7 +337,6 @@ contextBridge.exposeInMainWorld('electronAPI', { getTimeline: (limit: number, offset: number, usernames?: string[], keyword?: string, startTime?: number, endTime?: number) => ipcRenderer.invoke('sns:getTimeline', limit, offset, usernames, keyword, startTime, endTime), getSnsUsernames: () => ipcRenderer.invoke('sns:getSnsUsernames'), - getUserPostCounts: () => ipcRenderer.invoke('sns:getUserPostCounts'), getExportStatsFast: () => ipcRenderer.invoke('sns:getExportStatsFast'), getExportStats: () => ipcRenderer.invoke('sns:getExportStats'), debugResource: (url: string) => ipcRenderer.invoke('sns:debugResource', url), diff --git a/electron/services/snsService.ts b/electron/services/snsService.ts index 8cb56f6..6a537e6 100644 --- a/electron/services/snsService.ts +++ b/electron/services/snsService.ts @@ -701,44 +701,6 @@ class SnsService { return { success: false, error: primary.error || fallback.error || '获取朋友圈联系人失败' } } - async getUserPostCounts(): Promise<{ success: boolean; data?: Record; error?: string }> { - try { - const counts: Record = {} - const primary = await wcdbService.execQuery( - 'sns', - null, - "SELECT user_name AS username, COUNT(1) AS total FROM SnsTimeLine WHERE user_name IS NOT NULL AND user_name <> '' GROUP BY user_name" - ) - - let rows = primary.rows - if (!primary.success || !rows || rows.length === 0) { - const fallback = await wcdbService.execQuery( - 'sns', - null, - "SELECT userName AS username, COUNT(1) AS total FROM SnsTimeLine WHERE userName IS NOT NULL AND userName <> '' GROUP BY userName" - ) - if (!fallback.success || !fallback.rows || fallback.rows.length === 0) { - return { success: false, error: primary.error || fallback.error || '获取朋友圈联系人条数失败' } - } - rows = fallback.rows - } - - for (const row of rows) { - const usernameRaw = row?.username ?? row?.user_name ?? row?.userName ?? '' - const username = typeof usernameRaw === 'string' ? usernameRaw.trim() : String(usernameRaw || '').trim() - if (!username) continue - const countRaw = row?.total ?? row?.count ?? row?.cnt - const parsedCount = Number(countRaw) - counts[username] = Number.isFinite(parsedCount) && parsedCount > 0 - ? Math.floor(parsedCount) - : this.parseCountValue(row) - } - return { success: true, data: counts } - } catch (e) { - return { success: false, error: String(e) } - } - } - private async getExportStatsFromTableCount(myWxid?: string): Promise<{ totalPosts: number; totalFriends: number; myPosts: number | null }> { let totalPosts = 0 let totalFriends = 0 diff --git a/src/components/Sns/SnsFilterPanel.tsx b/src/components/Sns/SnsFilterPanel.tsx index ce0daee..35e23fe 100644 --- a/src/components/Sns/SnsFilterPanel.tsx +++ b/src/components/Sns/SnsFilterPanel.tsx @@ -7,8 +7,6 @@ interface Contact { username: string displayName: string avatarUrl?: string - postCount?: number - postCountStatus?: 'loading' | 'ready' | 'error' } interface SnsFilterPanelProps { @@ -59,22 +57,12 @@ export const SnsFilterPanel: React.FC = ({ setJumpTargetDate(undefined) } - const getPostCountDisplay = (contact: Contact) => { - if (contact.postCountStatus === 'error') { - return { text: '统计失败', className: 'is-error' } - } - if (contact.postCountStatus !== 'ready') { - return { text: '统计中', className: 'is-loading' } - } - return { text: `${Math.max(0, Number(contact.postCount || 0))} 条`, className: '' } - } - const getEmptyStateText = () => { if (loading && contacts.length === 0) { return '正在加载联系人...' } if (contacts.length === 0) { - return '有朋友圈数据的好友或者曾经的好友数量为 0' + return '暂无好友或曾经的好友' } return '没有找到联系人' } @@ -166,7 +154,6 @@ export const SnsFilterPanel: React.FC = ({
{filteredContacts.map(contact => { - const countDisplay = getPostCountDisplay(contact) return (
= ({
{contact.displayName} - {countDisplay.text}
) diff --git a/src/pages/SnsPage.scss b/src/pages/SnsPage.scss index 0e5a73f..bc52b0c 100644 --- a/src/pages/SnsPage.scss +++ b/src/pages/SnsPage.scss @@ -1083,11 +1083,6 @@ color: var(--primary); font-weight: 600; } - - .contact-post-count { - color: var(--primary); - opacity: 0.9; - } } /* If the NEXT item is also selected */ @@ -1124,20 +1119,6 @@ overflow: hidden; text-overflow: ellipsis; } - - .contact-post-count { - font-size: 12px; - color: var(--text-tertiary); - line-height: 1.2; - - &.is-loading { - font-style: italic; - } - - &.is-error { - color: var(--color-error, #f44336); - } - } } } } diff --git a/src/pages/SnsPage.tsx b/src/pages/SnsPage.tsx index a9ae083..e7caad5 100644 --- a/src/pages/SnsPage.tsx +++ b/src/pages/SnsPage.tsx @@ -10,16 +10,12 @@ import * as configService from '../services/config' const SNS_PAGE_CACHE_TTL_MS = 24 * 60 * 60 * 1000 const SNS_PAGE_CACHE_POST_LIMIT = 200 const SNS_PAGE_CACHE_SCOPE_FALLBACK = '__default__' -const CONTACTS_PRUNE_BATCH_SIZE = 40 -const CONTACTS_PRUNE_INTERVAL_MS = 80 interface Contact { username: string displayName: string avatarUrl?: string type?: 'friend' | 'former_friend' | 'sns_only' - postCount?: number - postCountStatus: 'loading' | 'ready' | 'error' } interface SnsOverviewStats { @@ -93,7 +89,6 @@ export default function SnsPage() { const cacheScopeKeyRef = useRef('') const scrollAdjustmentRef = useRef<{ scrollHeight: number; scrollTop: number } | null>(null) const contactsLoadTokenRef = useRef(0) - const contactsPruneTimerRef = useRef(null) // Sync posts ref useEffect(() => { @@ -114,14 +109,6 @@ export default function SnsPage() { useEffect(() => { jumpTargetDateRef.current = jumpTargetDate }, [jumpTargetDate]) - useEffect(() => { - return () => { - if (contactsPruneTimerRef.current !== null) { - window.clearTimeout(contactsPruneTimerRef.current) - contactsPruneTimerRef.current = null - } - } - }, []) // 在 DOM 更新后、浏览器绘制前同步调整滚动位置,防止向上加载时页面跳动 useLayoutEffect(() => { const snapshot = scrollAdjustmentRef.current; @@ -403,12 +390,8 @@ export default function SnsPage() { } }, [jumpTargetDate, persistSnsPageCache, searchKeyword, selectedUsernames]) - // Load Contacts(先展示全量好友/曾经好友,再按朋友圈条数逐步剔除 0 条联系人) + // Load Contacts(仅加载好友/曾经好友,不再统计朋友圈条数) const loadContacts = useCallback(async () => { - if (contactsPruneTimerRef.current !== null) { - window.clearTimeout(contactsPruneTimerRef.current) - contactsPruneTimerRef.current = null - } const requestToken = ++contactsLoadTokenRef.current setContactsLoading(true) try { @@ -422,8 +405,7 @@ export default function SnsPage() { username: c.username, displayName: c.displayName, avatarUrl: c.avatarUrl, - type: c.type === 'former_friend' ? 'former_friend' : 'friend', - postCountStatus: 'loading' + type: c.type === 'former_friend' ? 'former_friend' : 'friend' }) } } @@ -453,62 +435,9 @@ export default function SnsPage() { setContacts(contactsList) } } - - const snsCountsResult = await window.electronAPI.sns.getUserPostCounts() - if (requestToken !== contactsLoadTokenRef.current) return - - if (snsCountsResult.success && snsCountsResult.data) { - const snsPostCountMap = new Map( - Object.entries(snsCountsResult.data).map(([username, count]) => [username, Math.max(0, Number(count || 0))]) - ) - const contactsWithCounts: Contact[] = contactsList.map(contact => ({ - ...contact, - postCount: snsPostCountMap.get(contact.username) ?? 0, - postCountStatus: 'ready' as const - })) - setContacts(contactsWithCounts) - - const zeroCountUsernames = contactsWithCounts - .filter(contact => (contact.postCount || 0) <= 0) - .map(contact => contact.username) - - if (zeroCountUsernames.length > 0) { - let cursor = 0 - const pruneNextBatch = () => { - if (requestToken !== contactsLoadTokenRef.current) { - contactsPruneTimerRef.current = null - return - } - const batch = zeroCountUsernames.slice(cursor, cursor + CONTACTS_PRUNE_BATCH_SIZE) - if (batch.length === 0) { - contactsPruneTimerRef.current = null - return - } - const batchSet = new Set(batch) - setContacts(prev => prev.filter(contact => !batchSet.has(contact.username))) - cursor += CONTACTS_PRUNE_BATCH_SIZE - if (cursor < zeroCountUsernames.length) { - contactsPruneTimerRef.current = window.setTimeout(pruneNextBatch, CONTACTS_PRUNE_INTERVAL_MS) - } else { - contactsPruneTimerRef.current = null - } - } - contactsPruneTimerRef.current = window.setTimeout(pruneNextBatch, CONTACTS_PRUNE_INTERVAL_MS) - } - } else { - console.error('Failed to load SNS contact post counts:', snsCountsResult.error) - setContacts(prev => prev.map(contact => ({ - ...contact, - postCountStatus: 'error' - }))) - } } catch (error) { if (requestToken !== contactsLoadTokenRef.current) return console.error('Failed to load contacts:', error) - setContacts(prev => prev.map(contact => ({ - ...contact, - postCountStatus: 'error' - }))) } finally { if (requestToken === contactsLoadTokenRef.current) { setContactsLoading(false) diff --git a/src/types/electron.d.ts b/src/types/electron.d.ts index 0e0b558..f5895e3 100644 --- a/src/types/electron.d.ts +++ b/src/types/electron.d.ts @@ -770,7 +770,6 @@ export interface ElectronAPI { onExportProgress: (callback: (payload: { current: number; total: number; status: string }) => void) => () => void selectExportDir: () => Promise<{ canceled: boolean; filePath?: string }> getSnsUsernames: () => Promise<{ success: boolean; usernames?: string[]; error?: string }> - getUserPostCounts: () => Promise<{ success: boolean; data?: Record; error?: string }> getExportStatsFast: () => Promise<{ success: boolean; data?: { totalPosts: number; totalFriends: number; myPosts: number | null }; error?: string }> getExportStats: () => Promise<{ success: boolean; data?: { totalPosts: number; totalFriends: number; myPosts: number | null }; error?: string }> installBlockDeleteTrigger: () => Promise<{ success: boolean; alreadyInstalled?: boolean; error?: string }>