refine Semi UI track replay workspace

This commit is contained in:
lingniu
2026-07-18 12:21:42 +08:00
parent a00276816b
commit e5bf76ea15
4 changed files with 87 additions and 77 deletions

View File

@@ -255,9 +255,16 @@ test('uses a Semi bottom SideSheet for mobile track criteria and evidence', asyn
});
expect(sheet).toHaveClass('semi-sidesheet-inner');
expect(document.querySelector('.v2-track-detail-sidesheet .v2-track-rail')).toBeInTheDocument();
expect(document.querySelector('.v2-track-detail-sidesheet .v2-track-query-summary')).not.toBeInTheDocument();
expect(document.querySelector('.v2-track-detail-sidesheet .v2-track-query-summary')).toBeInTheDocument();
expect(screen.queryByRole('textbox', { name: '搜索轨迹车辆' })).not.toBeInTheDocument();
expect(screen.getByText('07-15 00:00 07-15 23:59 · 自动来源')).toBeInTheDocument();
expect(screen.getByText('8 km · 1 个停留 · 3 个事件')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /停留 00:05:00/ }));
expect(view.container.querySelector('.v2-track-page')).toHaveClass('is-rail-collapsed');
fireEvent.click(screen.getByRole('button', { name: '打开轨迹详情' }));
await screen.findByRole('dialog', { name: '轨迹查询与明细' });
fireEvent.click(screen.getByRole('button', { name: '修改条件' }));
expect(screen.getByRole('textbox', { name: '搜索轨迹车辆' })).toHaveValue('LTEST000000000001');
expect(screen.getByRole('button', { name: '关闭轨迹查询与明细' })).toBeInTheDocument();
});

View File

@@ -175,7 +175,7 @@ function OverviewPanel({ track }: { track: TrackPlaybackResponse }) {
</div>;
}
const TrackRail = memo(function TrackRail({ draft, track, loading, activeStopIndexes, activeEventIndexes, tab, queryCollapsed, mobileLayout, onDraft, onSubmit, onTab, onSelectIndex, onToggleQuery, onCollapse }: {
const TrackRail = memo(function TrackRail({ draft, track, loading, activeStopIndexes, activeEventIndexes, tab, queryCollapsed, onDraft, onSubmit, onTab, onSelectIndex, onToggleQuery, onCollapse }: {
draft: Draft;
track?: TrackPlaybackResponse;
loading: boolean;
@@ -183,7 +183,6 @@ const TrackRail = memo(function TrackRail({ draft, track, loading, activeStopInd
activeEventIndexes: readonly number[];
tab: PanelTab;
queryCollapsed: boolean;
mobileLayout: boolean;
onDraft: (draft: Draft) => void;
onSubmit: (event: FormEvent) => void;
onTab: (tab: PanelTab) => void;
@@ -216,7 +215,7 @@ const TrackRail = memo(function TrackRail({ draft, track, loading, activeStopInd
<Button className="v2-track-rail-hide" theme="borderless" aria-label="隐藏查询与明细" icon={<IconChevronLeft />} onClick={onCollapse}><span className="v2-track-rail-hide-label"></span></Button>
</>}
/>
{queryCollapsed && !mobileLayout ? <div className="v2-track-query-summary">
{queryCollapsed ? <div className="v2-track-query-summary">
<span><strong>{draft.keyword || '尚未选择车辆'}</strong><small>{draft.dateFrom.replace('T', ' ').slice(5)} {draft.dateTo.replace('T', ' ').slice(5)}</small></span>
<Tag color={draft.protocol ? 'blue' : 'grey'} type="light" size="small">{draft.protocol || '自动来源'}</Tag>
</div> : <form className="v2-track-query" onSubmit={onSubmit}>
@@ -361,6 +360,10 @@ export default function TrackPage() {
setSearchParams(preserveMonitorReturn(url, monitorReturn), { replace: true });
}, [draft, monitorReturn, setSearchParams]);
const selectIndex = useCallback((index: number) => { setPlaying(false); setActiveIndex(Math.max(0, Math.min(points.length - 1, index))); }, [points.length]);
const selectRailIndex = useCallback((index: number) => {
selectIndex(index);
if (mobileLayout) setRailCollapsed(true);
}, [mobileLayout, selectIndex]);
const collapseRail = useCallback(() => setRailCollapsed(true), []);
const togglePlayback = () => {
if (points.length < 2) return;
@@ -369,7 +372,7 @@ export default function TrackPage() {
setPlaying((value) => !value);
};
const progress = points.length > 1 ? boundedIndex / (points.length - 1) * 100 : 0;
const trackRail = <TrackRail draft={draft} track={track} loading={query.isFetching} activeStopIndexes={activeStopIndexes} activeEventIndexes={activeEventIndexes} tab={panelTab} queryCollapsed={queryCollapsed} mobileLayout={mobileLayout} onDraft={setDraft} onSubmit={submit} onTab={setPanelTab} onSelectIndex={selectIndex} onToggleQuery={() => setQueryCollapsed((value) => !value)} onCollapse={collapseRail} />;
const trackRail = <TrackRail draft={draft} track={track} loading={query.isFetching} activeStopIndexes={activeStopIndexes} activeEventIndexes={activeEventIndexes} tab={panelTab} queryCollapsed={queryCollapsed} onDraft={setDraft} onSubmit={submit} onTab={setPanelTab} onSelectIndex={selectRailIndex} onToggleQuery={() => setQueryCollapsed((value) => !value)} onCollapse={collapseRail} />;
return <div className={`v2-track-page${mobileLayout ? ' is-mobile-layout' : ''}${railCollapsed ? ' is-rail-collapsed' : ''}${monitorReturn ? ' has-monitor-return' : ''}`}>
<MonitorReturnBar />

View File

@@ -461,9 +461,9 @@ describe('V2 production entry', () => {
expect(reconciliationSource).toContain('<Tag className={`v2-reconcile-severity');
expect(reconciliationSource).toContain('<Tag className={`v2-reconcile-status');
expect(workspaceStyles).toContain('.v2-track-rail-expand {');
expect(workspaceStyles).toContain('bottom: calc(112px + env(safe-area-inset-bottom));');
expect(workspaceStyles).toContain('bottom: calc(116px + env(safe-area-inset-bottom));');
expect(workspaceStyles).toContain('.v2-track-stage:has(.v2-track-current-card) .v2-track-rail-expand {');
expect(workspaceStyles).toContain('bottom: calc(252px + env(safe-area-inset-bottom));');
expect(workspaceStyles).toContain('bottom: calc(264px + env(safe-area-inset-bottom));');
expect(v2Styles).toContain('grid-template-rows: minmax(0, 1fr);');
expect(appShellSource).toContain("section === 'tracks' ? ' is-track-workspace' : ''");
expect(corePageSources.TrackPage).toContain("monitorReturn ? ' has-monitor-return' : ''");

View File

@@ -45,7 +45,7 @@
/* Semi UI trajectory replay workspace: one evidence rail, one map overlay and
* one compact playback surface. */
.v2-track-page {
grid-template-columns: 326px minmax(0, 1fr);
grid-template-columns: 352px minmax(0, 1fr);
background: #edf2f7;
}
@@ -90,13 +90,13 @@
.v2-track-query-panel .v2-workspace-panel-copy > h5.semi-typography {
color: #26384f;
font-size: 15px;
font-size: 16px;
font-weight: 750;
}
.v2-track-query-panel .v2-workspace-panel-copy > .semi-typography {
color: #8491a2;
font-size: 10px;
font-size: 11px;
}
.v2-track-query-panel .v2-workspace-panel-actions {
@@ -105,13 +105,13 @@
.v2-track-query-panel .v2-track-query-toggle.semi-button {
width: auto;
min-width: 78px;
height: 32px;
min-width: 84px;
height: 34px;
justify-content: center;
border-radius: 7px;
padding: 0 8px;
padding: 0 10px;
color: #526780;
font-size: 10px;
font-size: 11px;
font-weight: 700;
}
@@ -128,24 +128,24 @@
}
.v2-track-query-panel .v2-track-query-summary {
min-height: 56px;
padding: 7px 12px 11px;
min-height: 58px;
padding: 8px 14px 11px;
background: linear-gradient(180deg, #fff 0%, #fbfcfe 100%);
}
.v2-track-query-panel .v2-track-query-summary strong {
color: #30445d;
font-size: 12px;
font-size: 13px;
}
.v2-track-query-panel .v2-track-query-summary small,
.v2-track-query-panel .v2-track-query-summary .semi-tag {
font-size: 9px;
font-size: 10px;
}
.v2-track-query-panel .v2-track-query {
border-bottom: 0;
padding: 10px 12px 13px;
padding: 12px 14px 15px;
}
.v2-track-rail-result {
@@ -158,31 +158,31 @@
}
.v2-track-result-header {
min-height: 62px;
min-height: 64px;
background: #fbfcfe;
padding: 9px 12px;
padding: 10px 14px;
}
.v2-track-result-header .v2-workspace-panel-copy > h5.semi-typography {
color: #25384f;
font-size: 14px;
font-size: 15px;
}
.v2-track-result-header .v2-workspace-panel-copy > .semi-typography {
color: #8592a3;
font-size: 9px;
font-size: 11px;
}
.v2-track-result-header .v2-workspace-panel-meta .semi-tag {
border-radius: 999px;
padding-inline: 8px;
font-size: 10px;
padding-inline: 10px;
font-size: 11px;
font-weight: 700;
}
.v2-track-rail-tabs {
height: 42px;
flex-basis: 42px;
height: 46px;
flex-basis: 46px;
border-block: 1px solid #e3e9f1;
border-bottom-color: #dfe6ef;
background: #fff;
@@ -190,8 +190,8 @@
}
.v2-track-rail-tabs > .semi-button {
height: 40px;
font-size: 11px;
height: 44px;
font-size: 12px;
}
.v2-track-rail-scroll {
@@ -224,7 +224,7 @@
.v2-track-overview-section .v2-workspace-panel-header .semi-tag {
flex: 0 0 auto;
border-radius: 999px;
font-size: 9px;
font-size: 10px;
}
.v2-track-quality-card.is-good {
@@ -285,8 +285,8 @@
.v2-track-current-card.semi-card {
top: 14px;
left: 14px;
width: min(360px, calc(100% - 330px));
min-width: 310px;
width: min(392px, calc(100% - 350px));
min-width: 340px;
border: 1px solid rgba(210, 221, 234, .97);
border-radius: 12px;
background: rgba(255, 255, 255, .97);
@@ -295,8 +295,8 @@
}
.v2-track-current-card .v2-workspace-panel-header {
min-height: 52px;
padding: 8px 11px;
min-height: 56px;
padding: 9px 12px;
}
.v2-track-current-card .v2-workspace-panel-meta .semi-tag {
@@ -304,7 +304,7 @@
justify-content: center;
border-radius: 999px;
padding-inline: 8px;
font-size: 10px;
font-size: 11px;
font-weight: 750;
}
@@ -316,7 +316,7 @@
.v2-track-current-card > .semi-card-body > .v2-track-current-metrics > span {
min-width: 0;
padding: 7px 9px;
padding: 9px 10px;
}
.v2-track-current-card > .semi-card-body > .v2-track-current-metrics > span + span {
@@ -325,32 +325,32 @@
.v2-track-current-card > .semi-card-body > .v2-track-current-metrics small {
color: #8491a2;
font-size: 9px;
font-size: 10px;
}
.v2-track-current-card > .semi-card-body > .v2-track-current-metrics strong {
margin-top: 4px;
color: #25384f;
font-size: 12px;
font-size: 14px;
text-shadow: none;
}
.v2-track-current-card > .semi-card-body > .v2-track-current-evidence {
display: flex;
min-height: 38px;
min-height: 42px;
align-items: center;
gap: 7px;
border: 0;
border-bottom: 1px solid #e8edf3;
padding: 6px 10px;
padding: 7px 11px;
color: #66778c;
font-size: 9px;
font-size: 10px;
}
.v2-track-current-evidence .semi-tag {
flex: 0 0 auto;
border-radius: 6px;
font-size: 8px;
font-size: 10px;
}
.v2-track-current-evidence > span {
@@ -380,7 +380,7 @@
.v2-track-current-evidence strong {
overflow: hidden;
color: #34475e;
font-size: 10px;
font-size: 11px;
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -388,7 +388,7 @@
.v2-track-current-evidence em {
flex: 0 0 auto;
color: #6d7e92;
font-size: 8px;
font-size: 9px;
font-style: normal;
white-space: nowrap;
}
@@ -397,20 +397,20 @@
margin-left: auto;
overflow: hidden;
color: #7c8a9d;
font-size: 8px;
font-size: 9px;
text-overflow: ellipsis;
white-space: nowrap;
}
.v2-track-current-card > .semi-card-body > p {
min-height: 34px;
padding: 8px 10px;
min-height: 38px;
padding: 9px 11px;
color: #52657b;
font-size: 9px;
font-size: 10px;
}
.v2-track-playback-dock.semi-card {
min-height: 96px;
min-height: 104px;
border-top-color: rgba(205, 216, 229, .98);
background: rgba(255, 255, 255, .97);
box-shadow: 0 -10px 30px rgba(24, 41, 63, .12);
@@ -423,18 +423,18 @@
}
.v2-track-playback-dock > .semi-card-body {
min-height: 96px;
grid-template-columns: 136px minmax(220px, 1fr) auto;
gap: 14px;
padding: 10px 14px !important;
min-height: 104px;
grid-template-columns: 150px minmax(240px, 1fr) auto;
gap: 16px;
padding: 11px 16px !important;
}
.v2-track-dock-summary strong {
font-size: 17px;
font-size: 20px;
}
.v2-track-dock-summary span {
font-size: 9px;
font-size: 11px;
}
.v2-track-segment-rail,
@@ -448,7 +448,7 @@
}
.v2-track-progress-meta {
font-size: 9px;
font-size: 10px;
}
.v2-track-dock-controls {
@@ -456,21 +456,21 @@
}
.v2-track-dock-controls > .semi-button {
width: 32px;
min-width: 32px;
height: 32px;
width: 36px;
min-width: 36px;
height: 36px;
border-radius: 8px;
}
.v2-track-dock-controls > .semi-button.is-primary {
width: 40px;
min-width: 40px;
height: 40px;
width: 44px;
min-width: 44px;
height: 44px;
}
@media (max-width: 1180px) {
.v2-track-page {
grid-template-columns: 304px minmax(0, 1fr);
grid-template-columns: 320px minmax(0, 1fr);
}
.v2-track-page.is-rail-collapsed {
@@ -479,14 +479,14 @@
.v2-track-current-card.semi-card {
top: 62px;
width: min(360px, calc(100% - 28px));
width: min(382px, calc(100% - 28px));
min-width: 0;
}
.v2-track-page.is-rail-collapsed .v2-track-current-card.semi-card {
top: 14px;
width: min(360px, calc(100% - 330px));
min-width: 310px;
width: min(382px, calc(100% - 350px));
min-width: 340px;
}
.v2-track-playback-dock > .semi-card-body {
@@ -512,12 +512,12 @@
}
.v2-track-query-panel .v2-track-query-header {
min-height: 52px;
padding: 8px 12px;
min-height: 54px;
padding: 8px 13px;
}
.v2-track-result-header {
min-height: 58px;
min-height: 60px;
}
.v2-track-stage-tools {
@@ -546,17 +546,17 @@
}
.v2-track-current-card .v2-workspace-panel-header {
min-height: 46px;
padding: 7px 9px;
min-height: 48px;
padding: 7px 10px;
}
.v2-track-current-card > .semi-card-body > .v2-track-current-metrics > span {
padding: 6px 9px;
padding: 7px 8px;
}
.v2-track-current-card > .semi-card-body > .v2-track-current-evidence {
min-height: 36px;
padding: 4px 9px;
min-height: 38px;
padding: 5px 9px;
}
.v2-track-current-evidence > small {
@@ -569,7 +569,7 @@
.v2-track-playback-dock.semi-card,
.v2-track-playback-dock > .semi-card-body {
min-height: 102px;
min-height: 106px;
}
.v2-track-playback-dock > .semi-card-body {
@@ -579,11 +579,11 @@
}
.v2-track-rail-expand {
bottom: calc(112px + env(safe-area-inset-bottom));
bottom: calc(116px + env(safe-area-inset-bottom));
}
.v2-track-stage:has(.v2-track-current-card) .v2-track-rail-expand {
bottom: calc(252px + env(safe-area-inset-bottom));
bottom: calc(264px + env(safe-area-inset-bottom));
}
}