feat: unify mileage metrics with semi ui

This commit is contained in:
lingniu
2026-07-19 12:02:10 +08:00
parent 2e87378c92
commit 031e22de79
6 changed files with 124 additions and 29 deletions

View File

@@ -60,15 +60,18 @@ test('renders only the desktop matrix with dates as columns and a period total',
expect(screen.queryByText('车辆里程排名')).not.toBeInTheDocument();
expect(screen.getByText('已绑定主车辆')).toBeInTheDocument();
expect(screen.getByText('已选择 1 辆')).toBeInTheDocument();
expect(screen.getByText('已绑定主车辆').closest('.semi-card')).toHaveClass('v2-mileage-summary-card');
expect(screen.getByText('已绑定主车辆').closest('[role="listitem"]')).toHaveClass('is-primary', 'is-success');
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-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-summary.semi-card')).toHaveAttribute('aria-label', '里程查询统计信息');
expect(view.container.querySelector('.v2-mileage-summary-secondary.semi-card-group')).toBeInTheDocument();
expect(view.container.querySelectorAll('.v2-mileage-summary-card.semi-card')).toHaveLength(4);
expect(view.container.querySelector('.v2-mileage-summary-card.is-primary .v2-mileage-summary-value')).toHaveTextContent('193.3 km');
expect(view.container.querySelector('.v2-mileage-summary')).toHaveClass('v2-workspace-metric-rail', 'is-queue');
expect(view.container.querySelector('.v2-mileage-summary .v2-workspace-metric-list')).toHaveAttribute('aria-label', '里程查询统计信息');
expect(view.container.querySelectorAll('.v2-mileage-summary .v2-workspace-metric-list > span')).toHaveLength(4);
expect(view.container.querySelector('.v2-mileage-summary .v2-workspace-metric-list > span.is-primary')).toHaveTextContent('区间总里程193.3 km2 条车辆日记录');
expect(view.container.querySelector('.v2-mileage-summary .v2-workspace-metric-list')).toHaveTextContent('已绑定主车辆1 辆已选择 1 辆');
expect(view.container.querySelector('.v2-mileage-summary .v2-workspace-metric-list')).toHaveTextContent('统计天数2 天2026/07/13 — 07/14');
expect(view.container.querySelector('.v2-mileage-summary .v2-workspace-metric-list')).toHaveTextContent('日均里程96.7 km按有效车辆日平均');
expect(view.container.querySelector('.v2-mileage-table-wrap')).toBeInTheDocument();
expect(screen.getByRole('note', { name: '里程矩阵读表说明' })).toHaveTextContent('0 km已上报、无里程增量');
expect(screen.getByRole('note', { name: '里程矩阵读表说明' })).toHaveTextContent('—无可用里程');

View File

@@ -16,7 +16,7 @@ import { VehicleCandidateList } from '../shared/VehicleCandidateList';
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
import { WorkspaceMetricRail } from '../shared/WorkspaceMetricRail';
import { WorkspaceMetricRail, type WorkspaceQueueMetricRailItem } from '../shared/WorkspaceMetricRail';
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
import { WorkspaceSideSheet } from '../shared/WorkspaceSideSheet';
import { QUERY_MEMORY, retainPreviousPageWithinScope } from '../queryPolicy';
@@ -253,27 +253,42 @@ function SummaryRail({ data, criteria, fleetTotal, loading }: { data?: MileageSt
const summaryRange = criteria.dateFrom.slice(0, 4) === criteria.dateTo.slice(0, 4)
? `${criteria.dateFrom.replace(/-/g, '/')}${criteria.dateTo.slice(5).replace('-', '/')}`
: `${criteria.dateFrom.replace(/-/g, '/')}${criteria.dateTo.replace(/-/g, '/')}`;
const items = loading ? [
['已绑定主车辆', '—', '正在按新筛选范围查询'],
['统计天数', `${days}`, summaryRange],
['区间总里程', '—', '正在计算区间汇总'],
['日均里程', '—', '正在计算有效车辆日']
] : [
['已绑定主车辆', `${vehicleCount}`, criteria.vehicles.length ? `已选择 ${criteria.vehicles.length}` : `档案口径 · ${data?.vehicleCount ?? 0} 辆有里程`],
['统计天数', `${days}`, summaryRange],
['区间总里程', `${formatKm(data?.periodMileageKm)} km`, `${data?.recordCount ?? 0} 条车辆日记录`],
['日均里程', `${formatKm(data?.averageDailyMileageKm)} km`, '按有效车辆日平均']
const withUnit = (value: string | number, unit: string) => <>{value}<i className="v2-mileage-summary-unit"> {unit}</i></>;
const items: WorkspaceQueueMetricRailItem[] = [
{
label: '区间总里程',
value: loading ? '—' : withUnit(formatKm(data?.periodMileageKm), 'km'),
note: loading ? '正在计算区间汇总' : `${data?.recordCount ?? 0} 条车辆日记录`,
tone: 'primary',
emphasis: 'primary'
},
{
label: '已绑定主车辆',
value: loading ? '—' : withUnit(vehicleCount, '辆'),
note: loading ? '正在按新筛选范围查询' : criteria.vehicles.length ? `已选择 ${criteria.vehicles.length}` : `档案口径 · ${data?.vehicleCount ?? 0} 辆有里程`,
tone: 'success',
emphasis: 'primary'
},
{
label: '统计天数',
value: withUnit(days, '天'),
note: summaryRange,
tone: 'neutral',
emphasis: 'secondary'
},
{
label: '日均里程',
value: loading ? '—' : withUnit(formatKm(data?.averageDailyMileageKm), 'km'),
note: loading ? '正在计算有效车辆日' : '按有效车辆日平均',
tone: 'primary',
emphasis: 'secondary'
}
];
const primary = items[2];
const secondary = [items[0], items[1], items[3]];
return <WorkspaceMetricRail
variant="queue"
className="v2-mileage-summary"
cardClassName="v2-mileage-summary-card"
secondaryClassName="v2-mileage-summary-secondary"
primaryValueClassName="v2-mileage-summary-value"
ariaLabel="里程查询统计信息"
primary={{ label: primary[0], value: primary[1], note: primary[2] }}
secondary={secondary.map(([label, value, note], index) => ({ label, value, note, className: `is-${['fleet', 'range', 'average'][index]}` }))}
items={items}
/>;
}