refine Semi UI history evidence workspace
This commit is contained in:
@@ -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');
|
||||||
|
|||||||
@@ -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="按车辆、时间和协议整理可追溯证据。" />
|
||||||
|
|||||||
@@ -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')]
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user