refine Semi UI mileage workspace

This commit is contained in:
lingniu
2026-07-18 14:44:57 +08:00
parent c57caabaa0
commit fe056019eb
4 changed files with 88 additions and 28 deletions

View File

@@ -48,9 +48,12 @@ test('renders only the desktop matrix with dates as columns and a period total',
expect(screen.getAllByText('7/13').length).toBeGreaterThan(0); expect(screen.getAllByText('7/13').length).toBeGreaterThan(0);
expect(screen.getAllByText('7/14').length).toBeGreaterThan(0); expect(screen.getAllByText('7/14').length).toBeGreaterThan(0);
expect(screen.getAllByText('粤A12345').length).toBeGreaterThan(0); expect(screen.getAllByText('粤A12345').length).toBeGreaterThan(0);
expect(screen.getByLabelText('里程查询工作区')).toHaveClass('v2-workspace-command-bar', 'v2-mileage-command-bar');
expect(screen.getByRole('heading', { name: '车辆里程分析', level: 5 })).toBeInTheDocument();
expect(screen.getByLabelText('里程查询工作区')).toHaveTextContent('GB32960 优先');
expect(screen.getByRole('heading', { name: '里程范围', level: 5 })).toBeInTheDocument(); expect(screen.getByRole('heading', { name: '里程范围', level: 5 })).toBeInTheDocument();
expect(screen.getByText('车牌、自然日与里程数据源策略')).toBeInTheDocument(); expect(screen.getByText('车牌、自然日与里程数据源策略')).toBeInTheDocument();
expect(screen.getByText('1 辆 · 2 天').closest('.semi-tag')).toBeInTheDocument(); expect(screen.getAllByText('1 辆 · 2 天').some((element) => element.closest('.semi-tag'))).toBe(true);
expect(screen.queryByText('当日起始里程')).not.toBeInTheDocument(); expect(screen.queryByText('当日起始里程')).not.toBeInTheDocument();
expect(screen.queryByText('数据来源')).not.toBeInTheDocument(); expect(screen.queryByText('数据来源')).not.toBeInTheDocument();
expect(screen.queryByRole('img', { name: '每日行驶里程趋势图' })).not.toBeInTheDocument(); expect(screen.queryByRole('img', { name: '每日行驶里程趋势图' })).not.toBeInTheDocument();
@@ -60,6 +63,7 @@ test('renders only the desktop matrix with dates as columns and a period total',
expect(screen.getByText('已绑定主车辆').closest('.semi-card')).toHaveClass('v2-mileage-summary-card'); expect(screen.getByText('已绑定主车辆').closest('.semi-card')).toHaveClass('v2-mileage-summary-card');
expect(screen.getByText('车辆每日里程').closest('.semi-card')).toHaveClass('v2-mileage-results'); expect(screen.getByText('车辆每日里程').closest('.semi-card')).toHaveClass('v2-mileage-results');
expect(view.container.querySelector('.v2-mileage-query-panel.semi-card')).toBeInTheDocument(); expect(view.container.querySelector('.v2-mileage-query-panel.semi-card')).toBeInTheDocument();
expect(view.container.querySelector('.v2-mileage-discovery-shell > .v2-mileage-command-bar')).toBeInTheDocument();
expect(view.container.querySelector('.v2-mileage-page > .v2-page-heading')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-mileage-page > .v2-page-heading')).not.toBeInTheDocument();
expect(view.container.querySelector('.v2-mileage-summary.semi-card')).toHaveAttribute('aria-label', '里程查询统计信息'); expect(view.container.querySelector('.v2-mileage-summary.semi-card')).toHaveAttribute('aria-label', '里程查询统计信息');
expect(view.container.querySelector('.v2-mileage-summary-secondary.semi-card-group')).toBeInTheDocument(); expect(view.container.querySelector('.v2-mileage-summary-secondary.semi-card-group')).toBeInTheDocument();

View File

@@ -13,6 +13,7 @@ import { TablePagination } from '../shared/TablePagination';
import { VehicleCandidateList } from '../shared/VehicleCandidateList'; import { VehicleCandidateList } from '../shared/VehicleCandidateList';
import { mergeVehicleCandidates } from '../shared/vehicleCandidates'; import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel'; import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
import { WorkspaceMetricRail } from '../shared/WorkspaceMetricRail'; import { WorkspaceMetricRail } from '../shared/WorkspaceMetricRail';
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader'; import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
import { QUERY_MEMORY, retainPreviousPageWithinScope } from '../queryPolicy'; import { QUERY_MEMORY, retainPreviousPageWithinScope } from '../queryPolicy';
@@ -534,28 +535,39 @@ export default function StatisticsPage() {
return <div className="v2-mileage-page" ref={pageRef}> return <div className="v2-mileage-page" ref={pageRef}>
<MonitorReturnBar /> <MonitorReturnBar />
<WorkspaceFilterPanel <div className="v2-mileage-discovery-shell">
className="v2-mileage-query-panel" <WorkspaceCommandBar
title="里程范围" className="v2-mileage-command-bar"
description="车牌、自然日与里程数据源策略" ariaLabel="里程查询工作区"
mobileSummary={criteria.vehicles.length ? `已选 ${criteria.vehicles.length} 辆 · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}` : `全部车辆 · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}`} title="车辆里程分析"
expanded={!filtersCollapsed} description="按自然日对比车辆行驶里程与协议来源"
status={`${criteria.vehicles.length ? `${criteria.vehicles.length}` : '全部授权车辆'} · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}`} status={`${criteria.vehicles.length ? `${criteria.vehicles.length}` : '全部授权车辆'} · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}`}
statusColor={criteria.vehicles.length ? 'blue' : 'grey'} statusColor={criteria.vehicles.length ? 'blue' : 'grey'}
collapsedLabel="修改" meta={<span>{criteria.sources.find((source) => source.enabled)?.protocol ?? '未配置'} </span>}
onToggle={() => setFiltersCollapsed((value) => !value)} />
> <WorkspaceFilterPanel
<form className={`v2-mileage-filter${filtersCollapsed ? ' is-mobile-collapsed' : ''}`} onSubmit={submit}> className="v2-mileage-query-panel"
<VehicleMultiSelect value={draft.vehicles} onChange={(vehicles) => setDraft((current) => ({ ...current, vehicles }))} /> title="里程范围"
<label><span></span><Input aria-label="开始日期" type="date" value={draft.dateFrom} max={draft.dateTo} onChange={(value) => setDraft((current) => ({ ...current, dateFrom: value }))} /></label> description="车牌、自然日与里程数据源策略"
<label><span></span><Input aria-label="结束日期" type="date" value={draft.dateTo} min={draft.dateFrom} onChange={(value) => setDraft((current) => ({ ...current, dateTo: value }))} /></label> mobileSummary={criteria.vehicles.length ? `已选 ${criteria.vehicles.length} 辆 · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}` : `全部车辆 · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}`}
<Button className="v2-primary-button" theme="solid" htmlType="submit"></Button> expanded={!filtersCollapsed}
<SourceStrategy value={draft.sources} onChange={(sources) => setDraft((current) => ({ ...current, sources }))} /> status={`${criteria.vehicles.length ? `${criteria.vehicles.length}` : '全部授权车辆'} · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)}`}
<div className="v2-mileage-ranges"><span></span><Button theme={isSameRange(draft, todayRange) ? 'solid' : 'light'} onClick={() => setRange(todayRange)}></Button><Button theme={isSameRange(draft, yesterdayRange) ? 'solid' : 'light'} onClick={() => setRange(yesterdayRange)}></Button><Button theme={isSameRange(draft, sevenDayRange) ? 'solid' : 'light'} onClick={() => setRange(sevenDayRange)}> 7 </Button><Button theme={isSameRange(draft, thirtyDayRange) ? 'solid' : 'light'} onClick={() => setRange(thirtyDayRange)}> 30 </Button><Button theme={isSameRange(draft, ninetyDayRange) ? 'solid' : 'light'} onClick={() => setRange(ninetyDayRange)}> 90 </Button></div> statusColor={criteria.vehicles.length ? 'blue' : 'grey'}
</form> collapsedLabel="修改"
{validationError || criteriaError ? <p className="v2-mileage-validation" role="alert">{validationError || criteriaError}</p> : null} onToggle={() => setFiltersCollapsed((value) => !value)}
<SummaryRail data={statistics.data} criteria={criteria} fleetTotal={fleetVehicles.data?.total} loading={statistics.isLoading} /> >
</WorkspaceFilterPanel> <form className={`v2-mileage-filter${filtersCollapsed ? ' is-mobile-collapsed' : ''}`} onSubmit={submit}>
<VehicleMultiSelect value={draft.vehicles} onChange={(vehicles) => setDraft((current) => ({ ...current, vehicles }))} />
<label><span></span><Input aria-label="开始日期" type="date" value={draft.dateFrom} max={draft.dateTo} onChange={(value) => setDraft((current) => ({ ...current, dateFrom: value }))} /></label>
<label><span></span><Input aria-label="结束日期" type="date" value={draft.dateTo} min={draft.dateFrom} onChange={(value) => setDraft((current) => ({ ...current, dateTo: value }))} /></label>
<Button className="v2-primary-button" theme="solid" htmlType="submit"></Button>
<SourceStrategy value={draft.sources} onChange={(sources) => setDraft((current) => ({ ...current, sources }))} />
<div className="v2-mileage-ranges"><span></span><Button theme={isSameRange(draft, todayRange) ? 'solid' : 'light'} onClick={() => setRange(todayRange)}></Button><Button theme={isSameRange(draft, yesterdayRange) ? 'solid' : 'light'} onClick={() => setRange(yesterdayRange)}></Button><Button theme={isSameRange(draft, sevenDayRange) ? 'solid' : 'light'} onClick={() => setRange(sevenDayRange)}> 7 </Button><Button theme={isSameRange(draft, thirtyDayRange) ? 'solid' : 'light'} onClick={() => setRange(thirtyDayRange)}> 30 </Button><Button theme={isSameRange(draft, ninetyDayRange) ? 'solid' : 'light'} onClick={() => setRange(ninetyDayRange)}> 90 </Button></div>
</form>
{validationError || criteriaError ? <p className="v2-mileage-validation" role="alert">{validationError || criteriaError}</p> : null}
<SummaryRail data={statistics.data} criteria={criteria} fleetTotal={fleetVehicles.data?.total} loading={statistics.isLoading} />
</WorkspaceFilterPanel>
</div>
{statistics.isError || mileage.isError || fleetVehicles.isError ? <InlineError message={(statistics.error ?? mileage.error ?? fleetVehicles.error) instanceof Error ? (statistics.error ?? mileage.error ?? fleetVehicles.error as Error).message : '里程数据加载失败'} onRetry={() => { statistics.refetch(); mileage.refetch(); if (!hasVehicles) fleetVehicles.refetch(); }} /> : null} {statistics.isError || mileage.isError || fleetVehicles.isError ? <InlineError message={(statistics.error ?? mileage.error ?? fleetVehicles.error) instanceof Error ? (statistics.error ?? mileage.error ?? fleetVehicles.error as Error).message : '里程数据加载失败'} onRetry={() => { statistics.refetch(); mileage.refetch(); if (!hasVehicles) fleetVehicles.refetch(); }} /> : null}
<Card className="v2-mileage-results" bodyStyle={{ padding: 0 }}> <Card className="v2-mileage-results" bodyStyle={{ padding: 0 }}>
<WorkspacePanelHeader <WorkspacePanelHeader

View File

@@ -63,7 +63,7 @@ describe('V2 production entry', () => {
expect(corePageSources[name]).not.toContain("from '../shared/PageHeader'"); expect(corePageSources[name]).not.toContain("from '../shared/PageHeader'");
expect(corePageSources[name]).not.toContain('<PageHeader'); expect(corePageSources[name]).not.toContain('<PageHeader');
} }
for (const name of ['VehiclePage', 'TrackPage', 'AccessPage', 'OperationsPage', 'UsersPage']) { for (const name of ['VehiclePage', 'TrackPage', 'AccessPage', 'OperationsPage', 'StatisticsPage', 'UsersPage']) {
expect(corePageSources[name]).toContain("from '../shared/WorkspaceCommandBar'"); expect(corePageSources[name]).toContain("from '../shared/WorkspaceCommandBar'");
expect(corePageSources[name]).toContain('<WorkspaceCommandBar'); expect(corePageSources[name]).toContain('<WorkspaceCommandBar');
} }

View File

@@ -12194,11 +12194,46 @@
padding: 14px 18px 16px; padding: 14px 18px 16px;
} }
.v2-mileage-query-panel.v2-workspace-filter-panel.semi-card { .v2-mileage-discovery-shell {
display: grid;
min-width: 0;
flex: 0 0 auto;
gap: 0;
overflow: visible; overflow: visible;
border-color: #d8e3ef; border: 1px solid #d8e3ef;
border-radius: 12px; border-radius: 14px;
box-shadow: 0 8px 26px rgba(31, 53, 80, .055); background: #fff;
box-shadow: 0 9px 28px rgba(31, 53, 80, .055);
}
.v2-mileage-discovery-shell > .v2-mileage-command-bar {
width: 100%;
max-width: none;
height: 46px;
min-height: 46px;
border: 0;
border-bottom: 1px solid #e3eaf2;
border-radius: 14px 14px 0 0;
padding-inline: 13px 10px;
box-shadow: none;
}
.v2-mileage-command-bar .v2-workspace-command-meta {
color: #748499;
font-size: 10px;
font-variant-numeric: tabular-nums;
}
.v2-mileage-query-panel.v2-workspace-filter-panel.semi-card {
width: 100%;
overflow: visible;
border: 0;
border-radius: 0 0 14px 14px;
box-shadow: none;
}
.v2-mileage-discovery-shell > .v2-mileage-query-panel > .semi-card-body > .v2-workspace-filter-heading {
display: none;
} }
.v2-mileage-query-panel .v2-workspace-filter-heading { .v2-mileage-query-panel .v2-workspace-filter-heading {
@@ -12560,7 +12595,16 @@
padding: 8px; padding: 8px;
} }
.v2-mileage-discovery-shell {
display: contents;
}
.v2-mileage-discovery-shell > .v2-mileage-command-bar {
display: none;
}
.v2-mileage-query-panel.v2-workspace-filter-panel.semi-card { .v2-mileage-query-panel.v2-workspace-filter-panel.semi-card {
border: 1px solid #d8e3ef;
border-radius: 11px; border-radius: 11px;
box-shadow: 0 5px 18px rgba(31, 53, 80, .05); box-shadow: 0 5px 18px rgba(31, 53, 80, .05);
} }