mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 07:16:51 +00:00
fix(export,sns): preserve sns load state across route switches
This commit is contained in:
@@ -1977,8 +1977,40 @@ function ExportPage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
patchSessionLoadTraceStage(targetSessionIds, 'snsPostCounts', 'pending', { force: true })
|
const scopeKey = exportCacheScopeReadyRef.current
|
||||||
patchSessionLoadTraceStage(targetSessionIds, 'snsPostCounts', 'loading')
|
? exportCacheScopeRef.current
|
||||||
|
: await ensureExportCacheScope()
|
||||||
|
const targetSet = new Set(targetSessionIds)
|
||||||
|
let cachedCounts: Record<string, number> = {}
|
||||||
|
try {
|
||||||
|
const cached = await configService.getExportSnsUserPostCountsCache(scopeKey)
|
||||||
|
cachedCounts = cached?.counts || {}
|
||||||
|
} catch (cacheError) {
|
||||||
|
console.error('读取导出页朋友圈条数缓存失败:', cacheError)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedTargetCounts = Object.entries(cachedCounts).reduce<Record<string, number>>((acc, [sessionId, countRaw]) => {
|
||||||
|
if (!targetSet.has(sessionId)) return acc
|
||||||
|
const nextCount = Number(countRaw)
|
||||||
|
acc[sessionId] = Number.isFinite(nextCount) ? Math.max(0, Math.floor(nextCount)) : 0
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
const cachedReadySessionIds = Object.keys(cachedTargetCounts)
|
||||||
|
if (cachedReadySessionIds.length > 0) {
|
||||||
|
setSnsUserPostCounts(prev => ({ ...prev, ...cachedTargetCounts }))
|
||||||
|
patchSessionLoadTraceStage(cachedReadySessionIds, 'snsPostCounts', 'done')
|
||||||
|
}
|
||||||
|
|
||||||
|
const pendingSessionIds = options?.force
|
||||||
|
? targetSessionIds
|
||||||
|
: targetSessionIds.filter((sessionId) => !(sessionId in cachedTargetCounts))
|
||||||
|
if (pendingSessionIds.length === 0) {
|
||||||
|
setSnsUserPostCountsStatus('ready')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
patchSessionLoadTraceStage(pendingSessionIds, 'snsPostCounts', 'pending', { force: true })
|
||||||
|
patchSessionLoadTraceStage(pendingSessionIds, 'snsPostCounts', 'loading')
|
||||||
setSnsUserPostCountsStatus('loading')
|
setSnsUserPostCountsStatus('loading')
|
||||||
|
|
||||||
let normalizedCounts: Record<string, number> = {}
|
let normalizedCounts: Record<string, number> = {}
|
||||||
@@ -1987,7 +2019,7 @@ function ExportPage() {
|
|||||||
if (runToken !== snsUserPostCountsHydrationTokenRef.current) return
|
if (runToken !== snsUserPostCountsHydrationTokenRef.current) return
|
||||||
|
|
||||||
if (!result.success || !result.counts) {
|
if (!result.success || !result.counts) {
|
||||||
patchSessionLoadTraceStage(targetSessionIds, 'snsPostCounts', 'failed', {
|
patchSessionLoadTraceStage(pendingSessionIds, 'snsPostCounts', 'failed', {
|
||||||
error: result.error || '朋友圈条数统计失败'
|
error: result.error || '朋友圈条数统计失败'
|
||||||
})
|
})
|
||||||
setSnsUserPostCountsStatus('error')
|
setSnsUserPostCountsStatus('error')
|
||||||
@@ -2003,9 +2035,6 @@ function ExportPage() {
|
|||||||
|
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
const scopeKey = exportCacheScopeReadyRef.current
|
|
||||||
? exportCacheScopeRef.current
|
|
||||||
: await ensureExportCacheScope()
|
|
||||||
await configService.setExportSnsUserPostCountsCache(scopeKey, normalizedCounts)
|
await configService.setExportSnsUserPostCountsCache(scopeKey, normalizedCounts)
|
||||||
} catch (cacheError) {
|
} catch (cacheError) {
|
||||||
console.error('写入导出页朋友圈条数缓存失败:', cacheError)
|
console.error('写入导出页朋友圈条数缓存失败:', cacheError)
|
||||||
@@ -2014,7 +2043,7 @@ function ExportPage() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载朋友圈用户条数失败:', error)
|
console.error('加载朋友圈用户条数失败:', error)
|
||||||
if (runToken !== snsUserPostCountsHydrationTokenRef.current) return
|
if (runToken !== snsUserPostCountsHydrationTokenRef.current) return
|
||||||
patchSessionLoadTraceStage(targetSessionIds, 'snsPostCounts', 'failed', {
|
patchSessionLoadTraceStage(pendingSessionIds, 'snsPostCounts', 'failed', {
|
||||||
error: String(error)
|
error: String(error)
|
||||||
})
|
})
|
||||||
setSnsUserPostCountsStatus('error')
|
setSnsUserPostCountsStatus('error')
|
||||||
@@ -2025,7 +2054,7 @@ function ExportPage() {
|
|||||||
const applyBatch = () => {
|
const applyBatch = () => {
|
||||||
if (runToken !== snsUserPostCountsHydrationTokenRef.current) return
|
if (runToken !== snsUserPostCountsHydrationTokenRef.current) return
|
||||||
|
|
||||||
const batchSessionIds = targetSessionIds.slice(cursor, cursor + SNS_USER_POST_COUNT_BATCH_SIZE)
|
const batchSessionIds = pendingSessionIds.slice(cursor, cursor + SNS_USER_POST_COUNT_BATCH_SIZE)
|
||||||
if (batchSessionIds.length === 0) {
|
if (batchSessionIds.length === 0) {
|
||||||
setSnsUserPostCountsStatus('ready')
|
setSnsUserPostCountsStatus('ready')
|
||||||
snsUserPostCountsBatchTimerRef.current = null
|
snsUserPostCountsBatchTimerRef.current = null
|
||||||
@@ -2984,7 +3013,7 @@ function ExportPage() {
|
|||||||
}
|
}
|
||||||
setIsSessionEnriching(false)
|
setIsSessionEnriching(false)
|
||||||
setIsLoadingSessionCounts(false)
|
setIsLoadingSessionCounts(false)
|
||||||
setSnsUserPostCountsStatus('idle')
|
setSnsUserPostCountsStatus(prev => (prev === 'loading' ? 'idle' : prev))
|
||||||
}, [isExportRoute])
|
}, [isExportRoute])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -504,7 +504,10 @@ export default function SnsPage() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const hydrateContactPostCounts = useCallback(async (usernames: string[], options?: { force?: boolean }) => {
|
const hydrateContactPostCounts = useCallback(async (
|
||||||
|
usernames: string[],
|
||||||
|
options?: { force?: boolean; readyUsernames?: Set<string> }
|
||||||
|
) => {
|
||||||
const force = options?.force === true
|
const force = options?.force === true
|
||||||
const targets = usernames
|
const targets = usernames
|
||||||
.map((username) => String(username || '').trim())
|
.map((username) => String(username || '').trim())
|
||||||
@@ -512,7 +515,7 @@ export default function SnsPage() {
|
|||||||
stopContactsCountHydration(true)
|
stopContactsCountHydration(true)
|
||||||
if (targets.length === 0) return
|
if (targets.length === 0) return
|
||||||
|
|
||||||
const readySet = new Set(
|
const readySet = options?.readyUsernames || new Set(
|
||||||
contactsRef.current
|
contactsRef.current
|
||||||
.filter((contact) => contact.postCountStatus === 'ready' && typeof contact.postCount === 'number')
|
.filter((contact) => contact.postCountStatus === 'ready' && typeof contact.postCount === 'number')
|
||||||
.map((contact) => contact.username)
|
.map((contact) => contact.username)
|
||||||
@@ -625,8 +628,42 @@ export default function SnsPage() {
|
|||||||
setContactsLoading(true)
|
setContactsLoading(true)
|
||||||
try {
|
try {
|
||||||
const snsPostCountsScopeKey = await ensureSnsUserPostCountsCacheScopeKey()
|
const snsPostCountsScopeKey = await ensureSnsUserPostCountsCacheScopeKey()
|
||||||
const cachedPostCountsItem = await configService.getExportSnsUserPostCountsCache(snsPostCountsScopeKey)
|
const [cachedPostCountsItem, cachedContactsItem, cachedAvatarItem] = await Promise.all([
|
||||||
|
configService.getExportSnsUserPostCountsCache(snsPostCountsScopeKey),
|
||||||
|
configService.getContactsListCache(snsPostCountsScopeKey),
|
||||||
|
configService.getContactsAvatarCache(snsPostCountsScopeKey)
|
||||||
|
])
|
||||||
const cachedPostCounts = cachedPostCountsItem?.counts || {}
|
const cachedPostCounts = cachedPostCountsItem?.counts || {}
|
||||||
|
const cachedAvatarMap = cachedAvatarItem?.avatars || {}
|
||||||
|
const cachedContacts = (cachedContactsItem?.contacts || [])
|
||||||
|
.filter((contact) => contact.type === 'friend' || contact.type === 'former_friend')
|
||||||
|
.map((contact) => {
|
||||||
|
const cachedCount = cachedPostCounts[contact.username]
|
||||||
|
const hasCachedCount = typeof cachedCount === 'number' && Number.isFinite(cachedCount)
|
||||||
|
return {
|
||||||
|
username: contact.username,
|
||||||
|
displayName: contact.displayName || contact.username,
|
||||||
|
avatarUrl: cachedAvatarMap[contact.username]?.avatarUrl,
|
||||||
|
type: (contact.type === 'former_friend' ? 'former_friend' : 'friend') as 'friend' | 'former_friend',
|
||||||
|
lastSessionTimestamp: 0,
|
||||||
|
postCount: hasCachedCount ? Math.max(0, Math.floor(cachedCount)) : undefined,
|
||||||
|
postCountStatus: hasCachedCount ? 'ready' as ContactPostCountStatus : 'idle' as ContactPostCountStatus
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (requestToken !== contactsLoadTokenRef.current) return
|
||||||
|
if (cachedContacts.length > 0) {
|
||||||
|
const cachedContactsSorted = sortContactsForRanking(cachedContacts)
|
||||||
|
setContacts(cachedContactsSorted)
|
||||||
|
setContactsLoading(false)
|
||||||
|
const cachedReadyCount = cachedContactsSorted.filter(contact => contact.postCountStatus === 'ready').length
|
||||||
|
setContactsCountProgress({
|
||||||
|
resolved: cachedReadyCount,
|
||||||
|
total: cachedContactsSorted.length,
|
||||||
|
running: cachedReadyCount < cachedContactsSorted.length
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const [contactsResult, sessionsResult] = await Promise.all([
|
const [contactsResult, sessionsResult] = await Promise.all([
|
||||||
window.electronAPI.chat.getContacts(),
|
window.electronAPI.chat.getContacts(),
|
||||||
window.electronAPI.chat.getSessions()
|
window.electronAPI.chat.getSessions()
|
||||||
@@ -670,7 +707,15 @@ export default function SnsPage() {
|
|||||||
let contactsList = sortContactsForRanking(Array.from(contactMap.values()))
|
let contactsList = sortContactsForRanking(Array.from(contactMap.values()))
|
||||||
if (requestToken !== contactsLoadTokenRef.current) return
|
if (requestToken !== contactsLoadTokenRef.current) return
|
||||||
setContacts(contactsList)
|
setContacts(contactsList)
|
||||||
void hydrateContactPostCounts(contactsList.map(contact => contact.username))
|
const readyUsernames = new Set(
|
||||||
|
contactsList
|
||||||
|
.filter((contact) => contact.postCountStatus === 'ready' && typeof contact.postCount === 'number')
|
||||||
|
.map((contact) => contact.username)
|
||||||
|
)
|
||||||
|
void hydrateContactPostCounts(
|
||||||
|
contactsList.map(contact => contact.username),
|
||||||
|
{ readyUsernames }
|
||||||
|
)
|
||||||
|
|
||||||
const allUsernames = contactsList.map(c => c.username)
|
const allUsernames = contactsList.map(c => c.username)
|
||||||
|
|
||||||
@@ -880,6 +925,7 @@ export default function SnsPage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleChange = () => {
|
const handleChange = () => {
|
||||||
cacheScopeKeyRef.current = ''
|
cacheScopeKeyRef.current = ''
|
||||||
|
snsUserPostCountsCacheScopeKeyRef.current = ''
|
||||||
// wxid changed, reset everything
|
// wxid changed, reset everything
|
||||||
stopContactsCountHydration(true)
|
stopContactsCountHydration(true)
|
||||||
setContacts([])
|
setContacts([])
|
||||||
|
|||||||
Reference in New Issue
Block a user