feat(export): show loading icon for media metric columns

This commit is contained in:
aits2026
2026-03-05 16:34:16 +08:00
parent f18fb83a92
commit 4da697f507
2 changed files with 38 additions and 16 deletions

View File

@@ -1382,10 +1382,14 @@
line-height: 1.2;
color: var(--text-secondary);
font-variant-numeric: tabular-nums;
&.loading {
color: var(--text-tertiary);
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 14px;
}
.row-media-metric-icon {
color: var(--text-tertiary);
}
.row-message-stats {

View File

@@ -4185,22 +4185,24 @@ function ExportPage() {
const hintedMessages = normalizeMessageCount(matchedSession?.messageCountHint)
const displayedMessageCount = countedMessages ?? hintedMessages
const mediaMetric = sessionContentMetrics[contact.username]
const metricLoadingReady = canExport && isSessionCountStageReady
const messageCountLabel = !canExport
? '--'
: typeof displayedMessageCount === 'number'
? displayedMessageCount.toLocaleString('zh-CN')
: '获取中'
const metricToLabel = (value: unknown): string => {
const metricToDisplay = (value: unknown): { state: 'value'; text: string } | { state: 'loading' } | { state: 'na'; text: '--' } => {
const normalized = normalizeMessageCount(value)
if (!canExport) return '--'
if (!metricLoadingReady) return '--'
return typeof normalized === 'number' ? normalized.toLocaleString('zh-CN') : '...'
if (!canExport) return { state: 'na', text: '--' }
if (!isSessionCountStageReady) return { state: 'loading' }
if (typeof normalized === 'number') {
return { state: 'value', text: normalized.toLocaleString('zh-CN') }
}
const emojiLabel = metricToLabel(mediaMetric?.emojiMessages)
const voiceLabel = metricToLabel(mediaMetric?.voiceMessages)
const imageLabel = metricToLabel(mediaMetric?.imageMessages)
const videoLabel = metricToLabel(mediaMetric?.videoMessages)
return { state: 'loading' }
}
const emojiMetric = metricToDisplay(mediaMetric?.emojiMessages)
const voiceMetric = metricToDisplay(mediaMetric?.voiceMessages)
const imageMetric = metricToDisplay(mediaMetric?.imageMessages)
const videoMetric = metricToDisplay(mediaMetric?.videoMessages)
const openChatLabel = contact.type === 'friend'
? '打开私聊'
: contact.type === 'group'
@@ -4256,16 +4258,32 @@ function ExportPage() {
)}
</div>
<div className="row-media-metric">
<strong className={`row-media-metric-value ${emojiLabel === '...' ? 'loading' : ''}`}>{emojiLabel}</strong>
<strong className="row-media-metric-value">
{emojiMetric.state === 'loading'
? <Loader2 size={12} className="spin row-media-metric-icon" aria-label="统计加载中" />
: emojiMetric.text}
</strong>
</div>
<div className="row-media-metric">
<strong className={`row-media-metric-value ${voiceLabel === '...' ? 'loading' : ''}`}>{voiceLabel}</strong>
<strong className="row-media-metric-value">
{voiceMetric.state === 'loading'
? <Loader2 size={12} className="spin row-media-metric-icon" aria-label="统计加载中" />
: voiceMetric.text}
</strong>
</div>
<div className="row-media-metric">
<strong className={`row-media-metric-value ${imageLabel === '...' ? 'loading' : ''}`}>{imageLabel}</strong>
<strong className="row-media-metric-value">
{imageMetric.state === 'loading'
? <Loader2 size={12} className="spin row-media-metric-icon" aria-label="统计加载中" />
: imageMetric.text}
</strong>
</div>
<div className="row-media-metric">
<strong className={`row-media-metric-value ${videoLabel === '...' ? 'loading' : ''}`}>{videoLabel}</strong>
<strong className="row-media-metric-value">
{videoMetric.state === 'loading'
? <Loader2 size={12} className="spin row-media-metric-icon" aria-label="统计加载中" />
: videoMetric.text}
</strong>
</div>
<div className="row-action-cell">
<div className="row-action-main">