refine Semi UI history evidence workspace

This commit is contained in:
lingniu
2026-07-18 20:51:50 +08:00
parent 9101d26005
commit 14e87f143d
4 changed files with 304 additions and 8 deletions

View File

@@ -158,8 +158,10 @@ test('clears stale rows, charts, and evidence as soon as the history scope chang
expect(desktopHistoryRow).toHaveAttribute('aria-expanded', 'true'); expect(desktopHistoryRow).toHaveAttribute('aria-expanded', 'true');
expect(await screen.findByText('OLDVIN-evidence')).toBeInTheDocument(); expect(await screen.findByText('OLDVIN-evidence')).toBeInTheDocument();
expect(view.container.querySelector('.v2-history-evidence-descriptions.semi-descriptions')).toBeInTheDocument(); expect(view.container.querySelector('.v2-history-evidence-descriptions.semi-descriptions')).toBeInTheDocument();
expect(view.container.querySelector('.v2-history-evidence-status')).toHaveTextContent('证据判读正常');
expect(view.container.querySelector('.v2-evidence-values.semi-descriptions')).toBeInTheDocument(); expect(view.container.querySelector('.v2-evidence-values.semi-descriptions')).toBeInTheDocument();
expect(view.container.querySelector('.v2-history-quality-tag.semi-tag')).toHaveTextContent('正常'); expect(view.container.querySelector('.v2-history-quality-tag.semi-tag')).toHaveTextContent('正常');
expect(view.container.querySelector('.v2-history-protocol-tag.semi-tag')).toHaveTextContent('JT808');
expect(view.container.querySelector('.v2-history-workspace')).toHaveClass('is-inspector-open'); expect(view.container.querySelector('.v2-history-workspace')).toHaveClass('is-inspector-open');
fireEvent.click(screen.getByRole('button', { name: '关闭数据详情' })); fireEvent.click(screen.getByRole('button', { name: '关闭数据详情' }));
expect(desktopHistoryRow).toHaveAttribute('aria-expanded', 'false'); expect(desktopHistoryRow).toHaveAttribute('aria-expanded', 'false');
@@ -170,6 +172,8 @@ test('clears stale rows, charts, and evidence as soon as the history scope chang
await waitFor(() => expect(mocks.historySeries).toHaveBeenCalledTimes(1)); await waitFor(() => expect(mocks.historySeries).toHaveBeenCalledTimes(1));
expect(screen.getByRole('heading', { level: 5, name: '聚合趋势' })).toBeInTheDocument(); expect(screen.getByRole('heading', { level: 5, name: '聚合趋势' })).toBeInTheDocument();
expect(view.container.querySelector('.v2-history-trend')).toHaveClass('is-expanded'); expect(view.container.querySelector('.v2-history-trend')).toHaveClass('is-expanded');
expect((await screen.findByText('覆盖 100.0%')).closest('.semi-tag')).toBeInTheDocument();
expect((await screen.findByText('时间窗完整')).closest('.semi-tag')).toBeInTheDocument();
fireEvent.change(screen.getByPlaceholderText('车牌 / VIN多台用逗号分隔'), { target: { value: 'NEWVIN' } }); fireEvent.change(screen.getByPlaceholderText('车牌 / VIN多台用逗号分隔'), { target: { value: 'NEWVIN' } });
fireEvent.click(screen.getByRole('button', { name: '查询' })); fireEvent.click(screen.getByRole('button', { name: '查询' }));
@@ -206,6 +210,7 @@ test('renders only selectable Semi history cards on mobile', async () => {
expect(action).toHaveAttribute('aria-expanded', '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('aria-label', '历史明细列表,可上下滚动');
expect(view.container.querySelector('.v2-history-table-scroll.is-mobile-scroll')).toHaveAttribute('tabindex', '0'); expect(view.container.querySelector('.v2-history-table-scroll.is-mobile-scroll')).toHaveAttribute('tabindex', '0');
expect(action.closest('.v2-history-mobile-card')?.querySelector('.v2-history-protocol-tag.semi-tag')).toHaveTextContent('JT808');
expect(view.container.querySelector('.v2-history-metric-scroll')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-history-metric-scroll')).not.toBeInTheDocument();
expect(view.container.querySelector('.v2-history-summary-rail')).toBeInTheDocument(); expect(view.container.querySelector('.v2-history-summary-rail')).toBeInTheDocument();
expect(view.container.querySelector('.v2-history-result-actions')).toHaveClass('is-mobile-actions'); expect(view.container.querySelector('.v2-history-result-actions')).toHaveClass('is-mobile-actions');

View File

@@ -44,6 +44,11 @@ function HistoryQualityTag({ quality }: { quality: string }) {
return <Tag className="v2-history-quality-tag" color={color} type="light" size="small">{historyQualityLabel(quality)}</Tag>; return <Tag className="v2-history-quality-tag" color={color} type="light" size="small">{historyQualityLabel(quality)}</Tag>;
} }
function HistoryProtocolTag({ protocol }: { protocol: string }) {
const color = protocol === 'GB32960' ? 'blue' : protocol === 'JT808' ? 'cyan' : protocol === 'YUTONG_MQTT' ? 'violet' : 'grey';
return <Tag className="v2-history-protocol-tag" color={color} type="light" size="small">{protocol || '未知来源'}</Tag>;
}
function HistoryTrend({ response, category, loading, error, hasMetrics, expanded, onToggle }: { function HistoryTrend({ response, category, loading, error, hasMetrics, expanded, onToggle }: {
response?: HistorySeriesResponse; response?: HistorySeriesResponse;
category: string; category: string;
@@ -61,10 +66,14 @@ function HistoryTrend({ response, category, loading, error, hasMetrics, expanded
: category === 'mileage' : category === 'mileage'
? '日里程按自然日通过明细核对' ? '日里程按自然日通过明细核对'
: '按查询时间窗汇总连续指标'; : '按查询时间窗汇总连续指标';
const coverageColor = coverage >= 95 ? 'green' : coverage >= 70 ? 'orange' : 'red';
const header = <WorkspacePanelHeader const header = <WorkspacePanelHeader
title="聚合趋势" title="聚合趋势"
description={description} description={description}
meta={summary ? `${formatSeriesGrain(summary.grainSeconds)}粒度 · 覆盖 ${coverage.toFixed(1)}% · ${summary.rawPointCount.toLocaleString('zh-CN')} 原始点` : undefined} meta={summary ? <span className="v2-history-trend-meta">
<Tag color={coverageColor} type="light" size="small"> {coverage.toFixed(1)}%</Tag>
<span>{formatSeriesGrain(summary.grainSeconds)} · {summary.rawPointCount.toLocaleString('zh-CN')} </span>
</span> : undefined}
actions={<Button actions={<Button
className="v2-history-trend-toggle is-expanded" className="v2-history-trend-toggle is-expanded"
theme="borderless" theme="borderless"
@@ -84,7 +93,12 @@ function HistoryTrend({ response, category, loading, error, hasMetrics, expanded
<g className="v2-chart-axis"><text x="49" y="14">{panel.maximum.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}</text><text x="49" y="100">{panel.minimum.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}</text><text x="54" y="112">{formatAxisTime(panel.start)}</text><text x="786" y="112" textAnchor="end">{formatAxisTime(panel.end)}</text></g> <g className="v2-chart-axis"><text x="49" y="14">{panel.maximum.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}</text><text x="49" y="100">{panel.minimum.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}</text><text x="54" y="112">{formatAxisTime(panel.start)}</text><text x="786" y="112" textAnchor="end">{formatAxisTime(panel.end)}</text></g>
{panel.lines.flatMap((line) => line.paths.map((path, index) => <path key={`${line.key}-${index}`} d={path} fill="none" stroke={line.color} strokeWidth="2" vectorEffect="non-scaling-stroke"><title>{line.label}</title></path>))} {panel.lines.flatMap((line) => line.paths.map((path, index) => <path key={`${line.key}-${index}`} d={path} fill="none" stroke={line.color} strokeWidth="2" vectorEffect="non-scaling-stroke"><title>{line.label}</title></path>))}
</svg><footer>{panel.lines.map((line) => <span key={line.key}><i style={{ background: line.color }} />{line.label}</span>)}</footer></article>)}</div> : <Empty className="v2-history-chart-empty" title="当前时间窗没有趋势点" description="没有可聚合的数值点,空窗不会被人工补值。" />} </svg><footer>{panel.lines.map((line) => <span key={line.key}><i style={{ background: line.color }} />{line.label}</span>)}</footer></article>)}</div> : <Empty className="v2-history-chart-empty" title="当前时间窗没有趋势点" description="没有可聚合的数值点,空窗不会被人工补值。" />}
{summary ? <small className="v2-history-trend-evidence">{summary.evidence} · {summary.missingBucketCount.toLocaleString('zh-CN')} / {summary.expectedBucketCount.toLocaleString('zh-CN')} · {summary.queryDurationMs} ms</small> : null} {summary ? <footer className="v2-history-trend-evidence">
<Tag color={summary.missingBucketCount ? 'orange' : 'green'} type="light" size="small">{summary.missingBucketCount ? '存在空窗' : '时间窗完整'}</Tag>
<span title={summary.evidence}>{summary.evidence}</span>
<strong> {summary.missingBucketCount.toLocaleString('zh-CN')} / {summary.expectedBucketCount.toLocaleString('zh-CN')} </strong>
<span> {summary.queryDurationMs} ms</span>
</footer> : null}
</Card>; </Card>;
} }
@@ -141,12 +155,22 @@ function ExportJobsPanel({ showHeader = true }: { showHeader?: boolean }) {
function EvidencePanel({ row, metrics, onClose, showHeader = true }: { row?: HistoryDataRow; metrics: HistoryMetricDefinition[]; onClose: () => void; showHeader?: boolean }) { function EvidencePanel({ row, metrics, onClose, showHeader = true }: { row?: HistoryDataRow; metrics: HistoryMetricDefinition[]; onClose: () => void; showHeader?: boolean }) {
return <Card className="v2-history-evidence" bodyStyle={{ padding: 0 }}>{showHeader ? <WorkspacePanelHeader title="数据详情" description={row ? `${row.plate || '未绑定车牌'} · ${row.protocol}` : '选择明细后核对来源与质量'} actions={row ? <Button theme="borderless" type="tertiary" icon={<IconClose />} onClick={onClose} aria-label="关闭数据详情" /> : null} /> : null} return <Card className="v2-history-evidence" bodyStyle={{ padding: 0 }}>{showHeader ? <WorkspacePanelHeader title="数据详情" description={row ? `${row.plate || '未绑定车牌'} · ${row.protocol}` : '选择明细后核对来源与质量'} actions={row ? <Button theme="borderless" type="tertiary" icon={<IconClose />} onClick={onClose} aria-label="关闭数据详情" /> : null} /> : null}
{row ? <><Descriptions className="v2-history-evidence-descriptions" align="left" size="small" data={[ {row ? <><div className={`v2-history-evidence-status${isHealthyHistoryQuality(row.quality) ? ' is-healthy' : ' is-attention'}`}>
<div>
<span></span>
<strong>{historyQualityLabel(row.quality)}</strong>
<small>{row.qualityReason || '平台未返回质量说明'}</small>
</div>
<div>
<HistoryProtocolTag protocol={row.protocol} />
<PlatformTime className="v2-history-time" value={row.deviceTime} />
</div>
</div><Descriptions className="v2-history-evidence-descriptions" align="left" size="small" data={[
{ key: '车牌', value: row.plate || '—' }, { key: '车牌', value: row.plate || '—' },
{ key: 'VIN', value: row.vin }, { key: 'VIN', value: row.vin },
{ key: '设备时间', value: <PlatformTime className="v2-history-time" value={row.deviceTime} /> }, { key: '设备时间', value: <PlatformTime className="v2-history-time" value={row.deviceTime} /> },
{ key: '服务时间', value: <PlatformTime className="v2-history-time" value={row.serverTime} /> }, { key: '服务时间', value: <PlatformTime className="v2-history-time" value={row.serverTime} /> },
{ key: '数据来源', value: <Tag color="blue" type="light" size="small">{row.protocol}</Tag> }, { key: '数据来源', value: <HistoryProtocolTag protocol={row.protocol} /> },
{ key: '数据质量', value: <HistoryQualityTag quality={row.quality} /> }, { key: '数据质量', value: <HistoryQualityTag quality={row.quality} /> },
{ key: '质量原因', value: row.qualityReason || '平台未返回质量说明' } { key: '质量原因', value: row.qualityReason || '平台未返回质量说明' }
]} /> ]} />
@@ -202,7 +226,7 @@ function HistoryDataTable({ rows, metrics, selectedRowID, onSelect }: { rows: Hi
{ title: '车牌', dataIndex: 'plate', width: 110, fixed: 'left' as const, className: 'v2-history-plate-column', render: (value: string) => value || '—' }, { title: '车牌', dataIndex: 'plate', width: 110, fixed: 'left' as const, className: 'v2-history-plate-column', render: (value: string) => value || '—' },
{ title: '服务时间', dataIndex: 'serverTime', width: 150, render: (value: string) => <PlatformTime className="v2-history-time" value={value} /> }, { title: '服务时间', dataIndex: 'serverTime', width: 150, render: (value: string) => <PlatformTime className="v2-history-time" value={value} /> },
{ title: 'VIN', dataIndex: 'vin', width: 160, render: (value: string) => <span className="v2-history-vin" title={value}>{value}</span> }, { title: 'VIN', dataIndex: 'vin', width: 160, render: (value: string) => <span className="v2-history-vin" title={value}>{value}</span> },
{ title: '协议', dataIndex: 'protocol', width: 100 }, { title: '协议', dataIndex: 'protocol', width: 110, render: (value: string) => <HistoryProtocolTag protocol={value} /> },
...metrics.map((metric) => ({ ...metrics.map((metric) => ({
title: `${metric.label}${metric.unit ? ` (${metric.unit})` : ''}`, title: `${metric.label}${metric.unit ? ` (${metric.unit})` : ''}`,
dataIndex: metric.key, dataIndex: metric.key,
@@ -461,7 +485,7 @@ export default function HistoryPage() {
onKeyDown={scrollHistoryTable} onKeyDown={scrollHistoryTable}
> >
{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><p><PlatformTime className="v2-history-time" value={row.deviceTime} /><b>{row.protocol}</b></p>{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} /><HistoryProtocolTag protocol={row.protocol} /></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} />} : <HistoryDataTable rows={resultRows} metrics={visibleMetrics} selectedRowID={selectedRow?.id} onSelect={selectRow} />}
{dataQuery.isPending && keywords.length {dataQuery.isPending && keywords.length
? <PanelLoading className="v2-history-loading" title="正在加载当前筛选范围的历史数据" description="按车辆、时间和协议整理可追溯证据。" /> ? <PanelLoading className="v2-history-loading" title="正在加载当前筛选范围的历史数据" description="按车辆、时间和协议整理可追溯证据。" />

View File

@@ -286,7 +286,7 @@ test('filters the customer directory by status and exposes the active result sco
} }
]); ]);
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
render(<QueryClientProvider client={client}><UsersPage /></QueryClientProvider>); const view = render(<QueryClientProvider client={client}><UsersPage /></QueryClientProvider>);
expect(await screen.findByRole('button', { name: /选择客户 华东客户/ })).toBeInTheDocument(); expect(await screen.findByRole('button', { name: /选择客户 华东客户/ })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /选择客户 西部客户/ })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /选择客户 西部客户/ })).toBeInTheDocument();
@@ -309,6 +309,14 @@ test('filters the customer directory by status and exposes the active result sco
await waitFor(() => expect(screen.getByRole('button', { name: /选择客户 华东客户/ })).toBeInTheDocument()); await waitFor(() => expect(screen.getByRole('button', { name: /选择客户 华东客户/ })).toBeInTheDocument());
expect(screen.getByRole('button', { name: /选择客户 西部客户/ })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /选择客户 西部客户/ })).toBeInTheDocument();
// Semi keeps the first Select popup mounted briefly while its close animation
// finishes. Remount before the second scope assertion so the test never clicks
// a stale portal when the full suite is under load.
view.unmount();
document.querySelectorAll('.semi-portal').forEach((portal) => portal.remove());
render(<QueryClientProvider client={client}><UsersPage /></QueryClientProvider>);
expect(await screen.findByRole('button', { name: /选择客户 华东客户/ })).toBeInTheDocument();
fireEvent.click(screen.getByRole('combobox', { name: '访问状态' })); fireEvent.click(screen.getByRole('combobox', { name: '访问状态' }));
const attentionOption = await waitFor(() => { const attentionOption = await waitFor(() => {
const options = [...document.querySelectorAll<HTMLElement>('.semi-select-option')] const options = [...document.querySelectorAll<HTMLElement>('.semi-select-option')]

View File

@@ -7358,7 +7358,8 @@
font-size: 9px; font-size: 9px;
} }
.v2-history-mobile-card-content p { .v2-history-mobile-card-content p,
.v2-history-mobile-meta {
margin: 5px 0; margin: 5px 0;
font-size: 9px; font-size: 9px;
} }
@@ -14311,6 +14312,199 @@
font-weight: 650; font-weight: 650;
} }
/*
* Semi UI history evidence refinement.
* Protocol, coverage and quality are decision signals, so they use one shared
* tag language instead of competing with dense identifiers and raw numbers.
*/
.v2-history-protocol-tag.semi-tag {
min-height: 22px;
flex: 0 0 auto;
border-radius: 999px;
padding-inline: 8px;
font-size: 10px;
font-weight: 700;
letter-spacing: .01em;
white-space: nowrap;
}
.v2-history-trend-meta {
display: inline-flex;
min-width: 0;
align-items: center;
gap: 8px;
}
.v2-history-trend-meta > .semi-tag {
min-height: 22px;
flex: 0 0 auto;
border-radius: 999px;
padding-inline: 8px;
font-size: 10px;
font-weight: 720;
}
.v2-history-trend-meta > span {
overflow: hidden;
color: #75859a;
font-size: 10px;
font-variant-numeric: tabular-nums;
text-overflow: ellipsis;
white-space: nowrap;
}
.v2-history-trend-panels article {
display: grid;
grid-template-rows: 28px minmax(0, 1fr) 23px;
border-color: #dfe7f0;
border-radius: 9px;
background: #fff;
}
.v2-history-trend-panels article > header {
height: auto;
padding-inline: 9px;
border-bottom: 1px solid #edf1f5;
background: #fbfcfe;
}
.v2-history-trend-panels article > header strong {
color: #33475f;
font-size: 11px;
}
.v2-history-trend-panels article > header span {
color: #8290a2;
font-size: 9px;
font-variant-numeric: tabular-nums;
}
.v2-history-trend-panels svg {
height: 100%;
min-height: 0;
}
.v2-history-trend-panels article > footer {
min-height: 23px;
border-top: 1px solid #f0f3f7;
padding-inline: 9px;
color: #65768b;
font-size: 9px;
}
.v2-history-trend-panels article > footer i {
width: 12px;
height: 3px;
border-radius: 999px;
}
.v2-chart-axis text {
fill: #6f7f93;
font-size: 9px;
}
.v2-history-trend-evidence {
display: flex;
min-height: 31px;
flex: 0 0 auto;
align-items: center;
gap: 8px;
overflow: hidden;
border-top: 1px solid #e8edf3;
padding: 4px 10px;
color: #748397;
font-size: 9px;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.v2-history-trend-evidence > .semi-tag {
min-height: 21px;
flex: 0 0 auto;
border-radius: 999px;
padding-inline: 7px;
font-size: 9px;
font-weight: 700;
}
.v2-history-trend-evidence > span:first-of-type {
min-width: 0;
flex: 1 1 auto;
overflow: hidden;
text-overflow: ellipsis;
}
.v2-history-trend-evidence > strong {
flex: 0 0 auto;
color: #596b80;
font-size: inherit;
font-weight: 700;
}
.v2-history-evidence-status {
display: grid;
min-height: 80px;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 12px;
border-bottom: 1px solid #dfe7f0;
padding: 11px 13px;
background: linear-gradient(135deg, #f7fafc 0%, #fff 100%);
}
.v2-history-evidence-status.is-healthy {
box-shadow: inset 3px 0 #18a86b;
}
.v2-history-evidence-status.is-attention {
box-shadow: inset 3px 0 #eda43a;
}
.v2-history-evidence-status > div {
display: flex;
min-width: 0;
flex-direction: column;
gap: 3px;
}
.v2-history-evidence-status > div:last-child {
align-items: flex-end;
gap: 7px;
}
.v2-history-evidence-status span {
color: #8290a2;
font-size: 10px;
font-weight: 650;
}
.v2-history-evidence-status strong {
color: #263b53;
font-size: 17px;
line-height: 1.2;
}
.v2-history-evidence-status small {
overflow: hidden;
color: #68798e;
font-size: 10px;
line-height: 1.45;
text-overflow: ellipsis;
white-space: nowrap;
}
.v2-history-evidence-status .v2-history-time {
color: #66788e;
font-size: 10px;
font-weight: 650;
}
.v2-history-data-table .v2-history-protocol-tag.semi-tag {
min-height: 21px;
padding-inline: 7px;
font-size: 9px;
}
@media (max-width: 900px) and (min-width: 681px) { @media (max-width: 900px) and (min-width: 681px) {
.v2-history-summary-rail > .semi-card-body { .v2-history-summary-rail > .semi-card-body {
grid-template-columns: minmax(230px, .7fr) minmax(0, 1.6fr); grid-template-columns: minmax(230px, .7fr) minmax(0, 1.6fr);
@@ -14351,6 +14545,71 @@
font-weight: 650; font-weight: 650;
} }
.v2-history-mobile-meta {
display: flex;
align-items: center;
justify-content: space-between;
margin-block: 6px;
}
.v2-history-mobile-meta .v2-history-protocol-tag.semi-tag {
min-height: 20px;
padding-inline: 7px;
font-size: 9px;
}
.v2-history-mobile-card-content dt {
font-size: 9px;
}
.v2-history-mobile-card-content dd {
font-size: 11px;
font-weight: 700;
}
.v2-history-trend .v2-workspace-panel-meta {
display: flex;
}
.v2-history-trend-meta > span {
display: none;
}
.v2-history-trend-meta > .semi-tag {
min-height: 20px;
padding-inline: 7px;
font-size: 9px;
}
.v2-history-trend-panels {
padding: 7px;
}
.v2-history-trend-evidence {
min-height: 29px;
gap: 6px;
padding-inline: 8px;
}
.v2-history-trend-evidence > span:first-of-type,
.v2-history-trend-evidence > span:last-child {
display: none;
}
.v2-history-evidence-status {
min-height: 74px;
gap: 8px;
padding: 9px 11px;
}
.v2-history-evidence-status strong {
font-size: 16px;
}
.v2-history-evidence-status small {
max-width: 205px;
}
.v2-history-summary-rail.semi-card { .v2-history-summary-rail.semi-card {
min-height: 132px; min-height: 132px;
overflow: visible; overflow: visible;