From 8094333e3bd1165c472d4b400e888cb905b17a51 Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Tue, 23 Jun 2026 09:42:56 +0800 Subject: [PATCH] =?UTF-8?q?style(web):=20=E9=80=9A=E7=9F=A5=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E5=88=97=E8=A1=A8=E8=A1=8C=E5=B8=83=E5=B1=80=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E4=B8=8E=E6=97=B6=E9=97=B4=E6=A0=87=E7=AD=BE=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TopBar 通知行改为 row-main/row-head/row-foot 结构化布局,标题加粗、分类改为 pill、箭头随标题右侧 - formatNotificationTime 改名 formatNotificationTimeLabel,新增 ISO/短日期直通匹配与超长截断兜底 - 更新 sidebar-document-unread-dot 测试 --- web/src/components/layout/TopBar.vue | 62 +++++++++++++------ .../sidebar-document-unread-dot.test.mjs | 19 ++++++ 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/web/src/components/layout/TopBar.vue b/web/src/components/layout/TopBar.vue index 5ad4387..3a30cca 100644 --- a/web/src/components/layout/TopBar.vue +++ b/web/src/components/layout/TopBar.vue @@ -204,18 +204,22 @@ - - - {{ item.title }} - {{ item.badge }} + + + + {{ item.title }} + {{ item.badge }} + + - {{ item.description }} - - {{ item.category || '系统通知' }} - + {{ item.description }} + + {{ item.category || '系统通知' }} + -
@@ -516,12 +520,28 @@ function normalizeNotificationId(value) { return String(value || '').trim() } -function formatNotificationTime(value) { - const date = new Date(value) - if (!Number.isFinite(date.getTime())) { +function formatNotificationTimeLabel(value) { + const raw = String(value || '').trim() + if (!raw) { return '最近更新' } + const normalized = raw.replace('T', ' ') + const isoMatched = normalized.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/) + if (isoMatched) { + return `${isoMatched[2]}-${isoMatched[3]} ${isoMatched[4]}:${isoMatched[5]}` + } + + const shortMatched = normalized.match(/^(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/) + if (shortMatched) { + return `${shortMatched[1]}-${shortMatched[2]} ${shortMatched[3]}:${shortMatched[4]}` + } + + const date = new Date(raw) + if (!Number.isFinite(date.getTime())) { + return raw.length > 16 ? `${raw.slice(0, 16)}...` : raw + } + const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') const hour = String(date.getHours()).padStart(2, '0') @@ -560,13 +580,14 @@ const documentNotificationItems = computed(() => return { id, - kind: 'document', - title: `${row.documentTypeLabel || '单据'} ${row.documentNo || row.claimId || '待生成'}`, - description: resolveDocumentNotificationDescription(row), - time: formatNotificationTime(row.updatedAt || row.createdAt), - category: row.sourceLabel || '单据中心', - tone: resolveDocumentNotificationTone({ ...row, isUnread: unread }), - unread, + kind: 'document', + title: `${row.documentTypeLabel || '单据'} ${row.documentNo || row.claimId || '待生成'}`, + description: resolveDocumentNotificationDescription(row), + time: row.updatedAt || row.createdAt, + timeLabel: formatNotificationTimeLabel(row.updatedAt || row.createdAt), + category: row.sourceLabel || '单据中心', + tone: resolveDocumentNotificationTone({ ...row, isUnread: unread }), + unread, icon: row.source === 'approval' ? 'mdi mdi-clipboard-text-clock-outline' : 'mdi mdi-file-document-outline', badge: unread ? '新' : '', target: { @@ -587,12 +608,15 @@ const workbenchNotificationItems = computed(() => ( if (!id || isNotificationHidden(id)) { return null } + const notificationTime = item.time || item.updatedAt || item.due return { ...item, id, kind: 'workbench', category: item.category || '个人工作台', + time: notificationTime, + timeLabel: formatNotificationTimeLabel(item.time || item.updatedAt || item.due), unread: Boolean(item.unread) && !readNotificationIds.value.has(id), icon: item.icon || resolveNotificationIcon(item) } diff --git a/web/tests/sidebar-document-unread-dot.test.mjs b/web/tests/sidebar-document-unread-dot.test.mjs index 93e9de1..0eee735 100644 --- a/web/tests/sidebar-document-unread-dot.test.mjs +++ b/web/tests/sidebar-document-unread-dot.test.mjs @@ -96,6 +96,25 @@ test('topbar bell owns document center unread notifications', () => { assert.doesNotMatch(topbarStyles, /\.notification-dot/) }) +test('topbar notification popover uses inbox-style rows with formatted time labels', () => { + assert.match(topbar, /class="notification-row-main"/) + assert.match(topbar, /class="notification-row-head"/) + assert.match(topbar, /class="notification-row-title"/) + assert.match(topbar, /class="notification-context"/) + assert.match(topbar, /class="notification-row-foot"/) + assert.match(topbar, /class="notification-category-pill"/) + assert.match(topbar, /class="notification-time"/) + assert.match(topbar, /class="notification-row-action"/) + assert.match(topbar, /timeLabel:\s*formatNotificationTimeLabel\(row\.updatedAt \|\| row\.createdAt\)/) + assert.match(topbar, /timeLabel:\s*formatNotificationTimeLabel\(item\.time \|\| item\.updatedAt \|\| item\.due\)/) + assert.doesNotMatch(topbar, /