diff --git a/src/pages/ExportPage.scss b/src/pages/ExportPage.scss
index 39eecb5..6a2ad67 100644
--- a/src/pages/ExportPage.scss
+++ b/src/pages/ExportPage.scss
@@ -320,6 +320,13 @@
font-weight: 600;
}
+ .card-title-meta {
+ color: var(--text-secondary);
+ font-size: 12px;
+ white-space: nowrap;
+ font-weight: 500;
+ }
+
.card-refresh-hint {
color: var(--text-tertiary);
font-size: 11px;
@@ -1108,6 +1115,8 @@
}
.table-wrap {
+ --contacts-message-col-width: 92px;
+ --contacts-action-col-width: 172px;
overflow: hidden;
border: 1px solid var(--border-color);
border-radius: 10px;
@@ -1227,6 +1236,37 @@
word-break: break-word;
}
+ .contacts-list-header {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 12px 8px;
+ border-bottom: 1px solid color-mix(in srgb, var(--border-color) 85%, transparent);
+ background: color-mix(in srgb, var(--bg-primary) 78%, var(--bg-secondary));
+ font-size: 12px;
+ color: var(--text-tertiary);
+ font-weight: 600;
+ letter-spacing: 0.01em;
+ flex-shrink: 0;
+ }
+
+ .contacts-list-header-main {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .contacts-list-header-count {
+ width: var(--contacts-message-col-width);
+ text-align: right;
+ flex-shrink: 0;
+ }
+
+ .contacts-list-header-actions {
+ width: var(--contacts-action-col-width);
+ text-align: right;
+ flex-shrink: 0;
+ }
+
.contacts-list {
flex: 1;
min-height: 0;
@@ -1335,21 +1375,15 @@
}
.row-message-count {
- min-width: 82px;
+ width: var(--contacts-message-col-width);
+ min-width: var(--contacts-message-col-width);
display: flex;
- flex-direction: column;
align-items: flex-end;
- gap: 2px;
+ justify-content: center;
flex-shrink: 0;
text-align: right;
}
- .row-message-count-label {
- font-size: 11px;
- color: var(--text-tertiary);
- line-height: 1;
- }
-
.row-message-count-value {
margin: 0;
font-size: 13px;
@@ -1504,6 +1538,8 @@
flex-direction: column;
align-items: flex-end;
gap: 4px;
+ width: var(--contacts-action-col-width);
+ flex-shrink: 0;
.row-action-main {
display: inline-flex;
@@ -2280,12 +2316,22 @@
}
@media (max-width: 720px) {
- .table-wrap .row-message-count {
- min-width: 66px;
+ .table-wrap {
+ --contacts-message-col-width: 66px;
+ --contacts-action-col-width: 148px;
}
- .table-wrap .row-message-count-label {
- display: none;
+ .table-wrap .contacts-list-header {
+ gap: 8px;
+ padding: 8px 10px 6px;
+ }
+
+ .table-wrap .contacts-list {
+ padding: 0 10px 10px;
+ }
+
+ .table-wrap .row-message-count {
+ min-width: var(--contacts-message-col-width);
}
.diag-panel-header {
diff --git a/src/pages/ExportPage.tsx b/src/pages/ExportPage.tsx
index dd9c447..4dabe1d 100644
--- a/src/pages/ExportPage.tsx
+++ b/src/pages/ExportPage.tsx
@@ -2610,7 +2610,7 @@ function ExportPage() {
...item,
label: contentTypeLabels[item.type],
stats: [
- { label: '已导出', value: exported }
+ { label: '已导出', value: exported, unit: '个对话' }
]
}
})
@@ -2619,9 +2619,9 @@ function ExportPage() {
type: 'sns' as ContentCardType,
icon: Aperture,
label: '朋友圈',
+ headerCount: snsStats.totalPosts,
stats: [
- { label: '朋友圈条数', value: snsStats.totalPosts },
- { label: '已导出', value: snsExportedCount }
+ { label: '已导出', value: snsExportedCount, unit: '条' }
]
}
@@ -3661,6 +3661,15 @@ function ExportPage() {
{card.label}
+ {card.type === 'sns' && (
+
+ {isCardStatsLoading ? (
+
+ 统计中...
+
+ ) : `${card.headerCount.toLocaleString()} 条`}
+
+ )}
{card.stats.map((stat) => (
@@ -3671,7 +3680,7 @@ function ExportPage() {
统计中...
- ) : stat.value.toLocaleString()}
+ ) : `${stat.value.toLocaleString()} ${stat.unit}`}
))}
@@ -3951,87 +3960,93 @@ function ExportPage() {
暂无联系人
) : (
-
-
- {visibleContacts.map((contact, idx) => {
- const absoluteIndex = contactStartIndex + idx
- const top = absoluteIndex * CONTACTS_LIST_VIRTUAL_ROW_HEIGHT
- const matchedSession = sessionRowByUsername.get(contact.username)
- const canExport = Boolean(matchedSession?.hasSession)
- const isRunning = canExport && runningSessionIds.has(contact.username)
- const isQueued = canExport && queuedSessionIds.has(contact.username)
- const isPaused = canExport && pausedSessionIds.has(contact.username)
- const recent = canExport ? formatRecentExportTime(lastExportBySession[contact.username], nowTick) : ''
- const countedMessages = normalizeMessageCount(sessionMessageCounts[contact.username])
- const hintedMessages = normalizeMessageCount(matchedSession?.messageCountHint)
- const displayedMessageCount = countedMessages ?? hintedMessages
- const messageCountLabel = !canExport
- ? '--'
- : typeof displayedMessageCount === 'number'
- ? displayedMessageCount.toLocaleString('zh-CN')
- : (isLoadingSessionCounts ? '统计中…' : '--')
- return (
-
-
-
- {contact.avatarUrl ? (
-

- ) : (
-
{getAvatarLetter(contact.displayName)}
- )}
-
-
-
{contact.displayName}
-
{contact.username}
-
-
- 总消息
-
- {messageCountLabel}
-
-
-
-
-
-
+ <>
+
+ 联系人(头像/名称/微信号)
+ 总消息
+ 操作
+
+
+
+ {visibleContacts.map((contact, idx) => {
+ const absoluteIndex = contactStartIndex + idx
+ const top = absoluteIndex * CONTACTS_LIST_VIRTUAL_ROW_HEIGHT
+ const matchedSession = sessionRowByUsername.get(contact.username)
+ const canExport = Boolean(matchedSession?.hasSession)
+ const isRunning = canExport && runningSessionIds.has(contact.username)
+ const isQueued = canExport && queuedSessionIds.has(contact.username)
+ const isPaused = canExport && pausedSessionIds.has(contact.username)
+ const recent = canExport ? formatRecentExportTime(lastExportBySession[contact.username], nowTick) : ''
+ const countedMessages = normalizeMessageCount(sessionMessageCounts[contact.username])
+ const hintedMessages = normalizeMessageCount(matchedSession?.messageCountHint)
+ const displayedMessageCount = countedMessages ?? hintedMessages
+ const messageCountLabel = !canExport
+ ? '--'
+ : typeof displayedMessageCount === 'number'
+ ? displayedMessageCount.toLocaleString('zh-CN')
+ : (isLoadingSessionCounts ? '统计中…' : '--')
+ return (
+
+
+
+ {contact.avatarUrl ? (
+

+ ) : (
+
{getAvatarLetter(contact.displayName)}
+ )}
+
+
+
{contact.displayName}
+
{contact.username}
+
+
+
+ {messageCountLabel}
+
+
+
+
+
+
+
+ {recent &&
{recent}}
- {recent &&
{recent}}
-
- )
- })}
+ )
+ })}
+
-
+ >
)}