From cff2e07a5798f092c2d5cb839a868e37cdc6eb05 Mon Sep 17 00:00:00 2001 From: lingniu Date: Sat, 18 Jul 2026 04:02:49 +0800 Subject: [PATCH] refine Semi UI track and history workspaces --- .../web/src/v2/pages/HistoryPage.test.tsx | 2 + .../apps/web/src/v2/pages/HistoryPage.tsx | 6 +- .../apps/web/src/v2/pages/TrackPage.test.tsx | 2 + .../apps/web/src/v2/pages/TrackPage.tsx | 14 +- .../apps/web/src/v2/styles/workspace.css | 224 ++++++++++++------ 5 files changed, 170 insertions(+), 78 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.test.tsx index 6b4d1108..165c2a2c 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.test.tsx @@ -177,6 +177,8 @@ test('renders only selectable Semi history cards on mobile', async () => { expect(view.container.querySelector('.v2-history-data-table')).not.toBeInTheDocument(); expect(action).toHaveAttribute('aria-pressed', 'false'); expect(action).toHaveAttribute('aria-expanded', 'false'); + expect(view.container.querySelector('.v2-history-table-scroll.is-mobile-scroll')).toHaveAttribute('aria-label', '历史明细列表,可上下滚动'); + expect(view.container.querySelector('.v2-history-table-scroll.is-mobile-scroll')).toHaveAttribute('tabindex', '0'); expect(screen.queryByText('MOBILEVIN-evidence')).not.toBeInTheDocument(); expect((mocks.historyData.mock.calls[0]?.[0] as URLSearchParams).get('limit')).toBe('20'); expect(screen.queryByLabelText('每页数量')).not.toBeInTheDocument(); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.tsx index 30918ddd..9dea81c4 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/HistoryPage.tsx @@ -387,7 +387,11 @@ export default function HistoryPage() { } /> setVisibleMetrics(allMetrics.map((metric) => metric.key))} onReset={() => setVisibleMetrics(allMetrics.filter((metric) => metric.defaultVisible).map((metric) => metric.key))} onClose={() => setColumnSettingsOpen(false)} /> -
+
{mobileLayout ?
{resultRows.map((row) => )}
: } diff --git a/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx index 5f092b3c..50288adc 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx @@ -179,6 +179,8 @@ test('renders a map-first replay workspace and connects stop, event, and panel i expect(screen.queryByRole('textbox', { name: '搜索轨迹车辆' })).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-track-current-card.semi-card')).toBeInTheDocument(); expect(view.container.querySelector('.v2-track-current-coverage')).toBeInTheDocument(); + expect(view.container.querySelectorAll('.v2-track-current-metrics > span')).toHaveLength(4); + expect(view.container.querySelector('.v2-track-current-evidence')).toHaveTextContent('JT808时间窗完整3 → 3 点报警 —'); expect(view.container.querySelector('.v2-track-coverage-float')).not.toBeInTheDocument(); expect(screen.getByRole('toolbar', { name: '地图轨迹工具' })).toBeInTheDocument(); expect(view.container.querySelector('.v2-track-playback-dock.semi-card')).toBeInTheDocument(); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.tsx index 3d4ec856..218282f8 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.tsx @@ -393,11 +393,17 @@ export default function TrackPage() { {track?.points.length ? <> {number(progress, 0)}%} /> -
速度{number(current?.speedKmh ?? 0)} km/h方向{direction(current?.directionDeg)}SOC{current?.socAvailable ? `${number(current.socPercent)}%` : '—'}
-
{current?.protocol || '未知来源'}总里程 {number(current?.totalMileageKm ?? 0)} km{alarm(current?.alarmFlag)}
-
- {track.coverage.complete ? '时间窗完整' : '仅展示最新切片'}{track.coverage.evidence} +
+ 速度{number(current?.speedKmh ?? 0)} km/h + 方向{direction(current?.directionDeg)} + SOC{current?.socAvailable ? `${number(current.socPercent)}%` : '—'} + 总里程{number(current?.totalMileageKm ?? 0)} km +
+
+ {current?.protocol || '未知来源'} + {track.coverage.complete ? '时间窗完整' : '最新切片'} {track.coverage.processedPoints.toLocaleString('zh-CN')} → {track.coverage.returnedPoints.toLocaleString('zh-CN')} 点 + {alarm(current?.alarmFlag)}

{playing ? '播放中,暂停地址解析' : addressSettling ? '位置已变化,等待地址解析…' : addressQuery.isFetching ? '地址解析中…' : addressQuery.data?.formattedAddress || `${current?.longitude.toFixed(6)}, ${current?.latitude.toFixed(6)}`}

diff --git a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css index 3b1de103..0f533ee4 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -286,13 +286,13 @@ .v2-track-current-card > .semi-card-body > .v2-track-current-metrics { display: grid; - grid-template-columns: 1fr 1fr 1fr; + grid-template-columns: repeat(4, minmax(0, 1fr)); border-block: 1px solid #e5ebf2; } .v2-track-current-card > .semi-card-body > .v2-track-current-metrics > span { min-width: 0; - padding: 7px 11px; + padding: 7px 9px; } .v2-track-current-card > .semi-card-body > .v2-track-current-metrics > span + span { @@ -311,92 +311,73 @@ text-shadow: none; } -.v2-track-current-card > .semi-card-body > .v2-track-current-source { +.v2-track-current-card > .semi-card-body > .v2-track-current-evidence { display: flex; - min-height: 34px; - grid-template-columns: none; + min-height: 38px; align-items: center; - gap: 8px; + gap: 7px; border: 0; border-bottom: 1px solid #e8edf3; - padding: 5px 10px; + padding: 6px 10px; color: #66778c; font-size: 9px; } -.v2-track-current-source .semi-tag { +.v2-track-current-evidence .semi-tag { flex: 0 0 auto; border-radius: 6px; font-size: 8px; } -.v2-track-current-card > .semi-card-body > .v2-track-current-source > span { +.v2-track-current-evidence > span { + display: inline-flex; min-width: 0; + align-items: center; + gap: 6px; overflow: hidden; - padding: 0; text-overflow: ellipsis; white-space: nowrap; } -.v2-track-current-source > span:last-child { - margin-left: auto; -} - -.v2-track-current-card > .semi-card-body > .v2-track-current-coverage { - display: grid; - min-height: 42px; - grid-template-columns: 7px minmax(0, 1fr) auto; - align-items: center; - gap: 8px; - border: 0; - border-bottom: 1px solid #e8edf3; - padding: 7px 10px; -} - -.v2-track-current-coverage > i { +.v2-track-current-evidence > span > i { width: 7px; height: 7px; + flex: 0 0 auto; border-radius: 50%; background: #18a86b; box-shadow: 0 0 0 4px rgba(24, 168, 107, .1); } -.v2-track-current-coverage.is-warning > i { +.v2-track-current-evidence.is-warning > span > i { background: #eea33a; box-shadow: 0 0 0 4px rgba(238, 163, 58, .11); } -.v2-track-current-card > .semi-card-body > .v2-track-current-coverage > span { - display: grid; - min-width: 0; - gap: 2px; - padding: 0; -} - -.v2-track-current-coverage strong, -.v2-track-current-coverage small { +.v2-track-current-evidence strong { overflow: hidden; + color: #34475e; + font-size: 10px; text-overflow: ellipsis; white-space: nowrap; } -.v2-track-current-coverage strong { - color: #34475e; - font-size: 10px; -} - -.v2-track-current-coverage small { - color: #8795a8; - font-size: 8px; -} - -.v2-track-current-coverage em { +.v2-track-current-evidence em { + flex: 0 0 auto; color: #6d7e92; font-size: 8px; font-style: normal; white-space: nowrap; } +.v2-track-current-evidence > small { + margin-left: auto; + overflow: hidden; + color: #7c8a9d; + font-size: 8px; + text-overflow: ellipsis; + white-space: nowrap; +} + .v2-track-current-card > .semi-card-body > p { min-height: 34px; padding: 8px 10px; @@ -544,18 +525,12 @@ padding: 6px 9px; } - .v2-track-current-card > .semi-card-body > .v2-track-current-source { - min-height: 31px; + .v2-track-current-card > .semi-card-body > .v2-track-current-evidence { + min-height: 36px; padding: 4px 9px; } - .v2-track-current-card > .semi-card-body > .v2-track-current-coverage { - min-height: 34px; - grid-template-columns: 7px minmax(0, 1fr) auto; - padding: 5px 9px; - } - - .v2-track-current-coverage small { + .v2-track-current-evidence > small { display: none; } @@ -5710,23 +5685,23 @@ height: 100%; min-height: 0; gap: 8px; - overflow: auto; + overflow: hidden; padding: 8px; } .v2-history-context-card.semi-card { - min-height: 118px; + min-height: 110px; border-radius: 11px; } .v2-history-context { display: flex; - min-height: 118px; + min-height: 110px; flex-direction: column; } .v2-history-context .v2-history-metrics { - min-height: 54px; + min-height: 52px; grid-template-columns: auto minmax(0, 1fr) auto; gap: 7px; border-right: 0; @@ -5759,7 +5734,7 @@ } .v2-history-context .v2-history-summary { - min-height: 64px; + min-height: 58px; flex: 1; grid-template-columns: 1.1fr .72fr 1.18fr .78fr; } @@ -5788,13 +5763,15 @@ .v2-history-main { display: flex; - height: auto; + height: 100%; min-height: 0; + flex: 1 1 0; flex-direction: column; } .v2-history-main > .v2-history-table-card.semi-card { - min-height: 430px; + min-height: 0; + flex: 1 1 0; order: 1; } @@ -5806,9 +5783,9 @@ } .v2-history-table-card .v2-workspace-panel-header { - min-height: 68px; - align-items: flex-start; - padding: 9px 8px; + min-height: 58px; + align-items: center; + padding: 7px 8px; } .v2-history-table-card .v2-workspace-panel-copy > .semi-typography:last-child { @@ -5827,24 +5804,125 @@ } .v2-history-table-card .v2-workspace-panel-actions > .semi-button { - width: 34px; - min-width: 34px; - min-height: 34px; + width: 32px; + min-width: 32px; + min-height: 32px; padding: 0; } + .v2-history-workspace { + min-height: 0; + flex: 1 1 0; + overflow: hidden; + } + + .v2-history-table-card > .semi-card-body { + min-height: 0; + } + + .v2-history-table-scroll.is-mobile-scroll { + min-height: 0; + flex: 1 1 0; + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior: contain; + scrollbar-gutter: stable; + scrollbar-width: auto; + touch-action: pan-y; + -webkit-overflow-scrolling: touch; + } + + .v2-history-table-scroll.is-mobile-scroll:focus-visible { + outline: 2px solid rgba(18, 104, 223, .38); + outline-offset: -2px; + } + .v2-history-mobile-list { - gap: 7px; - padding: 7px; + gap: 6px; + padding: 6px; } .v2-history-mobile-list > .v2-history-mobile-card.semi-card { - border-radius: 9px; + border-radius: 8px; box-shadow: none; + contain-intrinsic-size: auto 124px; } .v2-history-mobile-card-content { - padding: 11px; + padding: 8px 9px; + } + + .v2-history-mobile-card-content header strong { + font-size: 13px; + } + + .v2-history-mobile-card-content header small { + margin-top: 1px; + font-size: 9px; + } + + .v2-history-mobile-card-content p { + margin: 5px 0; + font-size: 9px; + } + + .v2-history-mobile-quality { + margin: 0 0 6px; + overflow: hidden; + font-size: 9px; + line-height: 12px; + text-overflow: ellipsis; + white-space: nowrap; + } + + .v2-history-mobile-card-content dl { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 0; + padding-top: 6px; + } + + .v2-history-mobile-card-content dl > div { + min-width: 0; + padding: 0 5px; + } + + .v2-history-mobile-card-content dl > div:first-child { + padding-left: 0; + } + + .v2-history-mobile-card-content dl > div + div { + border-left: 1px solid #edf1f5; + } + + .v2-history-mobile-card-content dt { + overflow: hidden; + font-size: 8px; + text-overflow: ellipsis; + white-space: nowrap; + } + + .v2-history-mobile-card-content dd { + margin-top: 2px; + overflow: hidden; + font-size: 10px; + text-overflow: ellipsis; + white-space: nowrap; + } + + .v2-history-mobile-card-content footer { + display: none; + } +} + +@media (max-width: 360px) { + .v2-history-mobile-card-content dl { + grid-template-columns: repeat(2, minmax(0, 1fr)); + row-gap: 6px; + } + + .v2-history-mobile-card-content dl > div:nth-child(3) { + border-left: 0; + padding-left: 0; } }