diff --git a/src/pages/ChatPage.scss b/src/pages/ChatPage.scss
index 1698bed..80e2a8b 100644
--- a/src/pages/ChatPage.scss
+++ b/src/pages/ChatPage.scss
@@ -3026,6 +3026,16 @@
font-size: 12px;
font-weight: 600;
color: var(--text-secondary);
+
+ &.loading {
+ color: var(--text-tertiary);
+ font-weight: 500;
+ }
+
+ &.failed {
+ color: #b45309;
+ font-weight: 600;
+ }
}
}
diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx
index d3da281..a96ee5e 100644
--- a/src/pages/ChatPage.tsx
+++ b/src/pages/ChatPage.tsx
@@ -260,6 +260,8 @@ interface SessionExportCacheMeta {
source: 'memory' | 'disk' | 'fresh'
}
+type GroupMessageCountStatus = 'loading' | 'ready' | 'failed'
+
interface GroupPanelMember {
username: string
displayName: string
@@ -271,6 +273,7 @@ interface GroupPanelMember {
isOwner?: boolean
isFriend: boolean
messageCount: number
+ messageCountStatus: GroupMessageCountStatus
}
interface SessionListCachePayload {
@@ -1131,7 +1134,10 @@ function ChatPage(props: ChatPageProps) {
}
}, [applySessionDetailStats, currentSessionId, isLoadingRelationStats])
- const normalizeGroupPanelMembers = useCallback((payload: GroupPanelMember[]): GroupPanelMember[] => {
+ const normalizeGroupPanelMembers = useCallback((
+ payload: GroupPanelMember[],
+ options?: { messageCountStatus?: GroupMessageCountStatus }
+ ): GroupPanelMember[] => {
const membersPayload = Array.isArray(payload) ? payload : []
return membersPayload
.map((member: GroupPanelMember): GroupPanelMember | null => {
@@ -1144,6 +1150,9 @@ function ChatPage(props: ChatPageProps) {
member.nickname ||
username
)
+ const rawStatus = member.messageCountStatus
+ const normalizedStatus: GroupMessageCountStatus = options?.messageCountStatus
+ ?? (rawStatus === 'loading' || rawStatus === 'failed' ? rawStatus : 'ready')
return {
username,
@@ -1155,7 +1164,8 @@ function ChatPage(props: ChatPageProps) {
groupNickname: member.groupNickname,
isOwner: Boolean(member.isOwner),
isFriend: Boolean(member.isFriend),
- messageCount: Number.isFinite(member.messageCount) ? Math.max(0, Math.floor(member.messageCount)) : 0
+ messageCount: Number.isFinite(member.messageCount) ? Math.max(0, Math.floor(member.messageCount)) : 0,
+ messageCountStatus: normalizedStatus
}
})
.filter((member: GroupPanelMember | null): member is GroupPanelMember => Boolean(member))
@@ -1166,7 +1176,8 @@ function ChatPage(props: ChatPageProps) {
const friendDiff = Number(b.isFriend) - Number(a.isFriend)
if (friendDiff !== 0) return friendDiff
- if (a.messageCount !== b.messageCount) return b.messageCount - a.messageCount
+ const canSortByCount = a.messageCountStatus === 'ready' && b.messageCountStatus === 'ready'
+ if (canSortByCount && a.messageCount !== b.messageCount) return b.messageCount - a.messageCount
return a.displayName.localeCompare(b.displayName, 'zh-Hans-CN')
})
}, [])
@@ -1241,6 +1252,21 @@ function ChatPage(props: ChatPageProps) {
}
}, [])
+ const setGroupMembersCountStatus = useCallback((
+ status: GroupMessageCountStatus,
+ options?: { onlyWhenNotReady?: boolean }
+ ) => {
+ setGroupPanelMembers((prev) => {
+ if (!Array.isArray(prev) || prev.length === 0) return prev
+ if (options?.onlyWhenNotReady && prev.some((member) => member.messageCountStatus === 'ready')) {
+ return prev
+ }
+ const next = normalizeGroupPanelMembers(prev, { messageCountStatus: status })
+ const changed = next.some((member, index) => member.messageCountStatus !== prev[index]?.messageCountStatus)
+ return changed ? next : prev
+ })
+ }, [normalizeGroupPanelMembers])
+
const syncGroupMembersMyCountFromDetail = useCallback((chatroomId: string, myMessageCount: number) => {
if (!chatroomId || !chatroomId.includes('@chatroom')) return
const normalizedCount = Number.isFinite(myMessageCount) ? Math.max(0, Math.floor(myMessageCount)) : 0
@@ -1319,6 +1345,7 @@ function ChatPage(props: ChatPageProps) {
const refreshMessageCountsInBackground = (forceRefresh: boolean) => {
startedBackgroundRefresh = true
setIsRefreshingGroupMembers(true)
+ setGroupMembersCountStatus('loading', { onlyWhenNotReady: true })
void (async () => {
try {
const countsResult = await getGroupMembersPanelDataWithTimeout(
@@ -1329,10 +1356,14 @@ function ChatPage(props: ChatPageProps) {
if (requestSeq !== groupMembersRequestSeqRef.current) return
if (!countsResult.success || !Array.isArray(countsResult.data)) {
setGroupMembersError('成员列表已加载,发言统计稍后再试')
+ setGroupMembersCountStatus('failed', { onlyWhenNotReady: true })
return
}
- const membersWithCounts = normalizeGroupPanelMembers(countsResult.data as GroupPanelMember[])
+ const membersWithCounts = normalizeGroupPanelMembers(
+ countsResult.data as GroupPanelMember[],
+ { messageCountStatus: 'ready' }
+ )
setGroupPanelMembers(membersWithCounts)
syncGroupMyMessagesFromMembers(chatroomId, membersWithCounts)
setGroupMembersError(null)
@@ -1341,6 +1372,7 @@ function ChatPage(props: ChatPageProps) {
} catch {
if (requestSeq !== groupMembersRequestSeqRef.current) return
setGroupMembersError('成员列表已加载,发言统计稍后再试')
+ setGroupMembersCountStatus('failed', { onlyWhenNotReady: true })
} finally {
if (requestSeq === groupMembersRequestSeqRef.current) {
setIsRefreshingGroupMembers(false)
@@ -1350,9 +1382,13 @@ function ChatPage(props: ChatPageProps) {
}
if (cacheFresh && cached) {
- setGroupPanelMembers(cached.members)
+ const cachedMembers = normalizeGroupPanelMembers(
+ cached.members,
+ { messageCountStatus: cached.includeMessageCounts ? 'ready' : 'loading' }
+ )
+ setGroupPanelMembers(cachedMembers)
if (cached.includeMessageCounts) {
- syncGroupMyMessagesFromMembers(chatroomId, cached.members)
+ syncGroupMyMessagesFromMembers(chatroomId, cachedMembers)
}
setGroupMembersError(null)
setGroupMembersLoadingHint('')
@@ -1368,9 +1404,13 @@ function ChatPage(props: ChatPageProps) {
setGroupMembersError(null)
if (hasCachedMembers && cached) {
- setGroupPanelMembers(cached.members)
+ const cachedMembers = normalizeGroupPanelMembers(
+ cached.members,
+ { messageCountStatus: cached.includeMessageCounts ? 'ready' : 'loading' }
+ )
+ setGroupPanelMembers(cachedMembers)
if (cached.includeMessageCounts) {
- syncGroupMyMessagesFromMembers(chatroomId, cached.members)
+ syncGroupMyMessagesFromMembers(chatroomId, cachedMembers)
}
setIsRefreshingGroupMembers(true)
setGroupMembersLoadingHint('')
@@ -1402,7 +1442,10 @@ function ChatPage(props: ChatPageProps) {
return
}
- const members = normalizeGroupPanelMembers(membersResult.data as GroupPanelMember[])
+ const members = normalizeGroupPanelMembers(
+ membersResult.data as GroupPanelMember[],
+ { messageCountStatus: 'loading' }
+ )
setGroupPanelMembers(members)
setGroupMembersError(null)
updateGroupMembersPanelCache(chatroomId, members, false)
@@ -3831,7 +3874,13 @@ function ChatPage(props: ChatPageProps) {
- {member.messageCount.toLocaleString()} 条
+
+ {member.messageCountStatus === 'loading'
+ ? '统计中'
+ : member.messageCountStatus === 'failed'
+ ? '统计失败'
+ : `${member.messageCount.toLocaleString()} 条`}
+
))}