feat: guide history query start

This commit is contained in:
lingniu
2026-07-19 01:18:42 +08:00
parent 82f81eee33
commit e7b49df8ed
3 changed files with 23 additions and 8 deletions

View File

@@ -202,10 +202,14 @@ test('uses one focused Semi bottom SideSheet for the complete mobile history que
mocks.historyExports.mockResolvedValue([]); mocks.historyExports.mockResolvedValue([]);
renderPage('/history'); renderPage('/history');
await screen.findByText('等待查询历史数据'); await screen.findByText('选择车辆开始查询');
const trigger = screen.getByRole('button', { name: '修改查询范围:请选择车辆' }); const trigger = screen.getByRole('button', { name: '修改查询范围:请选择车辆' });
expect(trigger).toHaveAttribute('aria-expanded', 'false'); expect(trigger).toHaveAttribute('aria-expanded', 'false');
fireEvent.click(trigger); expect(screen.queryByRole('button', { name: '展开趋势' })).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: '打开历史数据工具' })).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Previous' })).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '选择车辆并查询' }));
expect(trigger).toHaveAttribute('aria-expanded', 'true');
const dialog = await screen.findByRole('dialog', { name: '历史查询范围' }); const dialog = await screen.findByRole('dialog', { name: '历史查询范围' });
expect(document.querySelector('.v2-history-filter-sidesheet')).toHaveClass('semi-sidesheet-bottom'); expect(document.querySelector('.v2-history-filter-sidesheet')).toHaveClass('semi-sidesheet-bottom');

View File

@@ -483,7 +483,7 @@ export default function HistoryPage() {
description={keywords.length ? `${(result?.total ?? 0).toLocaleString('zh-CN')} 条记录 · ${resultSummary?.vehicleCount ?? 0} 辆车辆 · ${summarySources}` : '选择车辆和时间范围后查询'} description={keywords.length ? `${(result?.total ?? 0).toLocaleString('zh-CN')} 条记录 · ${resultSummary?.vehicleCount ?? 0} 辆车辆 · ${summarySources}` : '选择车辆和时间范围后查询'}
meta={<span className="v2-history-result-meta"><Tag color="blue" type="light" size="small">{visibleMetrics.length} / {allMetrics.length} </Tag>{resultSummary ? <span>{resultSummary.queryDurationMs} ms</span> : null}</span>} meta={<span className="v2-history-result-meta"><Tag color="blue" type="light" size="small">{visibleMetrics.length} / {allMetrics.length} </Tag>{resultSummary ? <span>{resultSummary.queryDurationMs} ms</span> : null}</span>}
actionsClassName={`v2-history-result-actions${mobileLayout ? ' is-mobile-actions' : ''}`} actionsClassName={`v2-history-result-actions${mobileLayout ? ' is-mobile-actions' : ''}`}
actions={mobileLayout ? <> actions={mobileLayout ? keywords.length ? <>
<Button className={`v2-history-table-trend v2-workspace-mobile-tool-button is-muted${trendExpanded ? ' is-expanded' : ''}`} theme="light" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起' : '趋势'}</Button> <Button className={`v2-history-table-trend v2-workspace-mobile-tool-button is-muted${trendExpanded ? ' is-expanded' : ''}`} theme="light" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起' : '趋势'}</Button>
<Dropdown <Dropdown
trigger="click" trigger="click"
@@ -499,7 +499,7 @@ export default function HistoryPage() {
> >
<Button className="v2-workspace-mobile-tool-button is-muted" theme="light" aria-label="打开历史数据工具" aria-haspopup="menu" aria-expanded={mobileToolsOpen} icon={<IconSetting />}></Button> <Button className="v2-workspace-mobile-tool-button is-muted" theme="light" aria-label="打开历史数据工具" aria-haspopup="menu" aria-expanded={mobileToolsOpen} icon={<IconSetting />}></Button>
</Dropdown> </Dropdown>
</> : <> </> : null : <>
<Button className={`v2-history-table-trend${trendExpanded ? ' is-expanded' : ''}`} theme="borderless" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起趋势' : '聚合趋势'}</Button> <Button className={`v2-history-table-trend${trendExpanded ? ' is-expanded' : ''}`} theme="borderless" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起趋势' : '聚合趋势'}</Button>
<Button theme="borderless" aria-label="列设置" aria-haspopup="dialog" aria-expanded={columnSettingsOpen} aria-controls="v2-history-column-settings" icon={<IconSetting />} onClick={() => setColumnSettingsOpen((value) => !value)}></Button> <Button theme="borderless" aria-label="列设置" aria-haspopup="dialog" aria-expanded={columnSettingsOpen} aria-controls="v2-history-column-settings" icon={<IconSetting />} onClick={() => setColumnSettingsOpen((value) => !value)}></Button>
{exportAllowed ? <Button theme="borderless" aria-label="查看导出任务" aria-haspopup="dialog" aria-expanded={exportJobsOpen} aria-controls="v2-history-export-jobs" icon={<IconDownload />} onClick={() => setExportJobsOpen(true)}></Button> : null} {exportAllowed ? <Button theme="borderless" aria-label="查看导出任务" aria-haspopup="dialog" aria-expanded={exportJobsOpen} aria-controls="v2-history-export-jobs" icon={<IconDownload />} onClick={() => setExportJobsOpen(true)}></Button> : null}
@@ -516,14 +516,18 @@ export default function HistoryPage() {
> >
{mobileLayout {mobileLayout
? <div className="v2-history-mobile-list">{resultRows.map((row) => <Card key={row.id} className={`v2-history-mobile-card${selectedRow?.id === row.id ? ' is-selected' : ''}`} bodyStyle={{ padding: 0 }}><Button theme="borderless" type="tertiary" className="v2-history-mobile-action" aria-pressed={selectedRow?.id === row.id} aria-expanded={selectedRow?.id === row.id} aria-label={`查看 ${row.plate || row.vin} ${row.deviceTime} 数据详情`} onClick={() => selectRow(row)}><span className="v2-history-mobile-card-content"><header><span><strong>{row.plate || '未绑定车牌'}</strong><small>{row.vin}</small></span><span className={`v2-quality is-${row.quality}`}><i />{historyQualityLabel(row.quality)}</span></header><span className="v2-history-mobile-meta"><PlatformTime className="v2-history-time" value={row.deviceTime} /><ProtocolTag className="v2-history-protocol-tag" protocol={row.protocol} compact /></span>{isHealthyHistoryQuality(row.quality) ? null : <small className="v2-history-mobile-quality">{row.qualityReason || '平台未返回质量说明'}</small>}<dl>{visibleMetrics.slice(0, 4).map((metric) => <div key={metric.key}><dt>{metric.label}</dt><dd>{formatHistoryValue(row.values[metric.key], metric)}</dd></div>)}</dl><footer><IconChevronRight /></footer></span></Button></Card>)}</div> ? <div className="v2-history-mobile-list">{resultRows.map((row) => <Card key={row.id} className={`v2-history-mobile-card${selectedRow?.id === row.id ? ' is-selected' : ''}`} bodyStyle={{ padding: 0 }}><Button theme="borderless" type="tertiary" className="v2-history-mobile-action" aria-pressed={selectedRow?.id === row.id} aria-expanded={selectedRow?.id === row.id} aria-label={`查看 ${row.plate || row.vin} ${row.deviceTime} 数据详情`} onClick={() => selectRow(row)}><span className="v2-history-mobile-card-content"><header><span><strong>{row.plate || '未绑定车牌'}</strong><small>{row.vin}</small></span><span className={`v2-quality is-${row.quality}`}><i />{historyQualityLabel(row.quality)}</span></header><span className="v2-history-mobile-meta"><PlatformTime className="v2-history-time" value={row.deviceTime} /><ProtocolTag className="v2-history-protocol-tag" protocol={row.protocol} compact /></span>{isHealthyHistoryQuality(row.quality) ? null : <small className="v2-history-mobile-quality">{row.qualityReason || '平台未返回质量说明'}</small>}<dl>{visibleMetrics.slice(0, 4).map((metric) => <div key={metric.key}><dt>{metric.label}</dt><dd>{formatHistoryValue(row.values[metric.key], metric)}</dd></div>)}</dl><footer><IconChevronRight /></footer></span></Button></Card>)}</div>
: <HistoryDataTable rows={resultRows} metrics={visibleMetrics} selectedRowID={selectedRow?.id} onSelect={selectRow} />} : resultRows.length ? <HistoryDataTable rows={resultRows} metrics={visibleMetrics} selectedRowID={selectedRow?.id} onSelect={selectRow} /> : null}
{dataQuery.isPending && keywords.length {dataQuery.isPending && keywords.length
? <PanelLoading className="v2-history-loading" title="正在加载当前筛选范围的历史数据" description="按车辆、时间和协议整理可追溯证据。" /> ? <PanelLoading className="v2-history-loading" title="正在加载当前筛选范围的历史数据" description="按车辆、时间和协议整理可追溯证据。" />
: !resultRows.length : !resultRows.length
? <PanelEmpty className="v2-history-empty" title={keywords.length ? '当前条件没有历史记录' : '等待查询历史数据'} description={keywords.length ? '调整车辆、时间或数据来源后重试。' : '输入车牌或 VIN最多可同时查询 5 台车辆。'} /> ? <PanelEmpty className="v2-history-empty"
title={keywords.length ? '当前条件没有历史记录' : '选择车辆开始查询'}
description={keywords.length ? '调整车辆、时间或数据来源后重试。' : '支持车牌或 VIN最多可同时查询 5 台车辆。'}
action={mobileLayout ? <Button className="v2-history-empty-action" theme="solid" icon={<IconSearch />} aria-label={keywords.length ? '调整查询范围' : '选择车辆并查询'} onClick={() => setFiltersCollapsed(false)}>{keywords.length ? '调整查询范围' : '选择车辆并查询'}</Button> : null}
/>
: null} : null}
</div> </div>
<footer><TablePagination page={page} totalPages={totalPages} info={`${(result?.total ?? 0).toLocaleString('zh-CN')}`} onPageChange={(next) => setOffset((next - 1) * limit)} pageSize={mobileLayout ? undefined : limit} onPageSizeChange={(next) => { setLimit(next); setOffset(0); }} pageSizeOptions={mobileLayout ? undefined : [{ value: 20, label: '20 条/页' }, { value: 50, label: '50 条/页' }, { value: 100, label: '100 条/页' }]} /></footer> {keywords.length ? <footer><TablePagination page={page} totalPages={totalPages} info={`${(result?.total ?? 0).toLocaleString('zh-CN')}`} onPageChange={(next) => setOffset((next - 1) * limit)} pageSize={mobileLayout ? undefined : limit} onPageSizeChange={(next) => { setLimit(next); setOffset(0); }} pageSizeOptions={mobileLayout ? undefined : [{ value: 20, label: '20 条/页' }, { value: 50, label: '50 条/页' }, { value: 100, label: '100 条/页' }]} /></footer> : null}
</Card> </Card>
</div> </div>
{!mobileLayout && selectedRow ? <aside className="v2-history-side"><EvidencePanel row={selectedRow} metrics={visibleMetrics} onClose={closeSelectedRow} /></aside> : null} {!mobileLayout && selectedRow ? <aside className="v2-history-side"><EvidencePanel row={selectedRow} metrics={visibleMetrics} onClose={closeSelectedRow} /></aside> : null}

View File

@@ -17133,10 +17133,17 @@
} }
.v2-history-mobile-discovery > .v2-mobile-filter-toggle.semi-button { .v2-history-mobile-discovery > .v2-mobile-filter-toggle.semi-button {
min-height: 58px; min-height: 52px;
margin: 0; margin: 0;
} }
.v2-history-empty .v2-history-empty-action.semi-button {
min-width: 156px;
min-height: 42px;
border-radius: 9px;
font-weight: 700;
}
.v2-history-filter-sidesheet .semi-sidesheet-inner { .v2-history-filter-sidesheet .semi-sidesheet-inner {
width: 100vw !important; width: 100vw !important;
max-width: 100%; max-width: 100%;