From 3130c42d76a3add04430ccff00c2546d1c1612d1 Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Wed, 3 Jun 2026 12:38:17 +0800 Subject: [PATCH] feat(workbench): separate stale progress items --- .../styles/components/personal-workbench.css | 36 ++++++++++++++++ .../components/business/PersonalWorkbench.vue | 42 ++++++++++++++++++- .../personal-workbench-assistant.test.mjs | 5 +++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/web/src/assets/styles/components/personal-workbench.css b/web/src/assets/styles/components/personal-workbench.css index 67eb13b..4874722 100644 --- a/web/src/assets/styles/components/personal-workbench.css +++ b/web/src/assets/styles/components/personal-workbench.css @@ -553,6 +553,7 @@ } .progress-row { + position: relative; display: grid; grid-template-columns: minmax(78px, 0.44fr) minmax(138px, 0.86fr) minmax(300px, 1.46fr) minmax(92px, auto); align-items: center; @@ -563,6 +564,41 @@ text-align: left; } +.progress-row.has-long-duration-divider { + margin-top: 13px; + padding-top: 13px; + border-top: 0; +} + +.progress-row.has-long-duration-divider::before { + content: "10日以上"; + position: absolute; + top: -9px; + left: 0; + z-index: 1; + display: inline-flex; + align-items: center; + height: 18px; + padding-right: 8px; + background: var(--workbench-surface); + color: var(--workbench-muted); + font-size: 11px; + font-weight: 850; + line-height: 1; + white-space: nowrap; +} + +.progress-row.has-long-duration-divider::after { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: var(--workbench-line-soft); + pointer-events: none; +} + .progress-time, .progress-identity, .progress-result { diff --git a/web/src/components/business/PersonalWorkbench.vue b/web/src/components/business/PersonalWorkbench.vue index 22c6257..3d208cc 100644 --- a/web/src/components/business/PersonalWorkbench.vue +++ b/web/src/components/business/PersonalWorkbench.vue @@ -203,6 +203,7 @@ :key="item.id" type="button" class="progress-row" + :class="{ 'has-long-duration-divider': item.hasLongDurationDivider }" @click="openWorkbenchTarget(item)" > @@ -464,12 +465,21 @@ const visibleProgressItems = computed(() => { const rows = Array.isArray(props.workbenchSummary.progressItems) ? props.workbenchSummary.progressItems : [] - return rows.slice(0, 5).map((item) => ({ + const progressRows = rows.slice(0, 5).map((item) => ({ ...item, - displayTime: formatProgressTime(item?.updatedAt) + displayTime: formatProgressTime(item?.updatedAt), + isLongDuration: isLongDurationProgress(item?.updatedAt) + })) + + return progressRows.map((item, index) => ({ + ...item, + hasLongDurationDivider: item.isLongDuration && !progressRows[index - 1]?.isLongDuration })) }) +const LONG_DURATION_DAYS = 10 +const DAY_MS = 24 * 60 * 60 * 1000 + function formatProgressTime(value) { const text = String(value || '').trim() if (!text) { @@ -484,6 +494,34 @@ function formatProgressTime(value) { return text } +function parseProgressDate(value) { + const text = String(value || '').trim() + if (!text) { + return null + } + + const localDateMatch = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text) + if (localDateMatch) { + return new Date( + Number(localDateMatch[1]), + Number(localDateMatch[2]) - 1, + Number(localDateMatch[3]) + ) + } + + const date = new Date(text) + return Number.isNaN(date.getTime()) ? null : date +} + +function isLongDurationProgress(value) { + const date = parseProgressDate(value) + if (!date) { + return false + } + + return (Date.now() - date.getTime()) / DAY_MS >= LONG_DURATION_DAYS +} + function buildSelectedFileKey(file) { return [file?.name, file?.size, file?.lastModified, file?.type].join('__') } diff --git a/web/tests/personal-workbench-assistant.test.mjs b/web/tests/personal-workbench-assistant.test.mjs index d010537..fb19243 100644 --- a/web/tests/personal-workbench-assistant.test.mjs +++ b/web/tests/personal-workbench-assistant.test.mjs @@ -145,10 +145,15 @@ test('workbench submit shows intent recognition feedback before assistant opens' test('workbench progress rows show update time first', () => { assert.match(workbench, /class="progress-time"/) + assert.match(workbench, /has-long-duration-divider/) + assert.match(workbench, /hasLongDurationDivider/) + assert.match(workbench, /const LONG_DURATION_DAYS = 10/) + assert.match(workbench, /isLongDurationProgress\(item\?\.updatedAt\)/) assert.match(workbench, /