refine Semi UI access workspace
This commit is contained in:
@@ -52,9 +52,11 @@ test('removes old access rows immediately when the vehicle filter scope changes'
|
||||
expect(await screen.findByText('旧接入车牌')).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: '真实来源与接入健康', level: 5 })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('接入管理操作')).toHaveClass('v2-workspace-command-bar', 'v2-access-command-bar');
|
||||
for (const className of ['v2-access-filter-card-v3', 'v2-access-kpis-card-v3', 'v2-access-table-v3']) {
|
||||
expect(view.container.querySelector('.v2-access-discovery-shell')).toBeInTheDocument();
|
||||
for (const className of ['v2-access-filter-card-v3', 'v2-access-table-v3']) {
|
||||
expect(view.container.querySelector(`.${className}.semi-card`)).toBeInTheDocument();
|
||||
}
|
||||
expect(screen.getByRole('navigation', { name: '接入差异筛选' })).toHaveClass('v2-access-status-tabs');
|
||||
const filterActions = view.container.querySelector<HTMLElement>('.v2-access-filter-actions');
|
||||
expect(filterActions).toBeInTheDocument();
|
||||
expect(within(filterActions!).getByRole('button', { name: '查询' })).toBeInTheDocument();
|
||||
@@ -66,6 +68,7 @@ test('removes old access rows immediately when the vehicle filter scope changes'
|
||||
expect(desktopRow).toHaveAttribute('aria-expanded', 'false');
|
||||
fireEvent.keyDown(desktopRow, { key: 'Enter' });
|
||||
expect(await screen.findByRole('button', { name: '关闭车辆接入详情' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('dialog', { name: '车辆接入详情' })).toBeInTheDocument();
|
||||
expect(desktopRow).toHaveAttribute('aria-expanded', 'true');
|
||||
const inspectorHeader = screen.getByRole('heading', { level: 5, name: '旧接入车牌' }).closest<HTMLElement>('.v2-workspace-panel-header');
|
||||
expect(inspectorHeader).toBeInTheDocument();
|
||||
@@ -143,9 +146,9 @@ test('renders mobile access vehicles as selectable Semi cards', async () => {
|
||||
expect(action.closest('.semi-card')).toHaveClass('v2-access-mobile-card');
|
||||
expect(view.container.querySelector('.v2-access-table-scroll-v3.is-mobile-scroll')).toHaveAttribute('tabindex', '0');
|
||||
expect(view.container.querySelector('.v2-access-table-scroll-v3.is-mobile-scroll')).toHaveAttribute('aria-label', '车辆接入列表,可上下滚动');
|
||||
expect(within(action).getByText('GB32960')).toBeInTheDocument();
|
||||
expect(within(action).getByText('JT808')).toBeInTheDocument();
|
||||
expect(within(action).getByText('YUTONG_MQTT')).toBeInTheDocument();
|
||||
expect(within(action).getByText('32960')).toBeInTheDocument();
|
||||
expect(within(action).getByText('808')).toBeInTheDocument();
|
||||
expect(within(action).getByText('宇通')).toBeInTheDocument();
|
||||
expect(action).toHaveAttribute('aria-pressed', 'false');
|
||||
expect(action).toHaveAttribute('aria-expanded', 'false');
|
||||
fireEvent.click(action);
|
||||
|
||||
@@ -29,10 +29,27 @@ const connectionLabels: Record<AccessVehicleRow['connectionState'], string> = {
|
||||
healthy: '已接来源正常', degraded: '部分来源异常', incomplete: '资料待维护', offline: '已接来源离线', not_connected: '尚无来源'
|
||||
};
|
||||
|
||||
const scopeLabels: Record<string, string> = {
|
||||
'': '全部主车辆',
|
||||
attention: '需关注车辆',
|
||||
master_data: '资料待维护',
|
||||
healthy: '已接来源正常',
|
||||
degraded: '部分来源异常',
|
||||
offline: '已接来源离线',
|
||||
not_connected: '尚无来源'
|
||||
};
|
||||
|
||||
function statusByProtocol(row: AccessVehicleRow, protocol: string) {
|
||||
return row.protocolStatuses.find((item) => item.protocol === protocol);
|
||||
}
|
||||
|
||||
function compactProtocolLabel(protocol: string) {
|
||||
if (protocol === 'GB32960') return '32960';
|
||||
if (protocol === 'JT808') return '808';
|
||||
if (protocol === 'YUTONG_MQTT') return '宇通';
|
||||
return protocol;
|
||||
}
|
||||
|
||||
function compactTime(value: string) {
|
||||
if (!value) return '—';
|
||||
const parsed = new Date(value);
|
||||
@@ -193,7 +210,7 @@ export default function AccessPage() {
|
||||
setOffset(0);
|
||||
}, [mobileLayout]);
|
||||
const rows = vehiclesQuery.data?.items ?? []; const selected = rows.find((row) => row.vin === selectedVIN);
|
||||
useSideSheetA11y(mobileLayout && Boolean(selected), '.v2-access-detail-sidesheet', 'v2-access-detail', '车辆接入详情', '关闭车辆接入详情');
|
||||
useSideSheetA11y(Boolean(selected), '.v2-access-detail-sidesheet', 'v2-access-detail', '车辆接入详情', '关闭车辆接入详情');
|
||||
useSideSheetA11y(editable && governanceOpen, '.v2-access-governance-sidesheet', 'v2-access-governance', '接入治理配置', '关闭接入治理配置');
|
||||
const syncURL = (filters: Filters) => { const next = new URLSearchParams(); Object.entries(filters).forEach(([key, value]) => { if (value) next.set(key, value); }); setSearchParams(next, { replace: true }); };
|
||||
const apply = (next: Filters) => { setDraft(next); setCriteria(next); setOffset(0); setSelectedVIN(''); syncURL(next); };
|
||||
@@ -202,78 +219,80 @@ export default function AccessPage() {
|
||||
const refresh = () => Promise.all([summaryQuery.refetch(), vehiclesQuery.refetch(), ...(editable ? [unresolvedQuery.refetch(), thresholdQuery.refetch()] : [])]);
|
||||
|
||||
return <div className="v2-access-page v2-access-page-v3">
|
||||
<WorkspaceCommandBar
|
||||
className="v2-access-command-bar"
|
||||
ariaLabel="接入管理操作"
|
||||
title="真实来源与接入健康"
|
||||
description="核对车辆真实存在的数据来源、在线健康和待维护资料,不对尚未接入的业务协议作推断。"
|
||||
status={summary ? `${summary.totalVehicles.toLocaleString('zh-CN')} 辆主车辆` : '正在读取车辆'}
|
||||
meta={<Typography.Text type="tertiary">数据时间 {summary?.asOf ? formatAccessTime(summary.asOf) : '—'}</Typography.Text>}
|
||||
actions={<>{editable ? <Button theme="light" icon={<IconSetting />} aria-haspopup="dialog" aria-controls="v2-access-governance" aria-expanded={governanceOpen} onClick={() => setGovernanceOpen(true)}>接入治理{unresolvedQuery.data?.total ? ` · ${unresolvedQuery.data.total}` : ''}</Button> : null}<Button theme="light" icon={<IconRefresh />} onClick={() => void refresh()}>刷新</Button></>}
|
||||
/>
|
||||
<WorkspaceFilterPanel
|
||||
className="v2-access-filter-card-v3"
|
||||
title="接入筛选"
|
||||
description="车辆、接入状态、真实协议与品牌"
|
||||
mobileSummary={Object.values(criteria).filter(Boolean).length ? `已启用 ${Object.values(criteria).filter(Boolean).length} 项` : '全部主车辆'}
|
||||
expanded={!filtersCollapsed}
|
||||
status={Object.values(criteria).filter(Boolean).length ? `${Object.values(criteria).filter(Boolean).length} 项已启用` : '全部主车辆'}
|
||||
statusColor={Object.values(criteria).filter(Boolean).length ? 'blue' : 'grey'}
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
>
|
||||
<form className="v2-access-filter-v3" onSubmit={submit}>
|
||||
<label className="is-search"><span>车辆</span><Input aria-label="车辆" prefix={<IconSearch />} value={draft.keyword} onChange={(value) => setDraft({ ...draft, keyword: value })} placeholder="车牌 / VIN" /></label>
|
||||
<label><span id="access-connection-label">接入状态</span><Select aria-labelledby="access-connection-label" value={draft.connectionState} onChange={(value) => setDraft({ ...draft, connectionState: String(value) })} optionList={[{ value: '', label: '全部状态' }, { value: 'attention', label: '需关注' }, { value: 'healthy', label: '已接来源正常' }, { value: 'master_data', label: '资料待维护' }, { value: 'degraded', label: '部分来源异常' }, { value: 'offline', label: '已接来源离线' }, { value: 'not_connected', label: '尚无来源' }]} /></label>
|
||||
<label><span id="access-protocol-label">真实协议</span><Select aria-labelledby="access-protocol-label" value={draft.protocol} onChange={(value) => setDraft({ ...draft, protocol: String(value) })} optionList={[{ value: '', label: '全部协议' }, ...PROTOCOLS.map((item) => ({ value: item, label: item }))]} /></label>
|
||||
<label><span id="access-oem-label">车辆品牌</span><Select aria-labelledby="access-oem-label" value={draft.oem} onChange={(value) => setDraft({ ...draft, oem: String(value) })} optionList={[{ value: '', label: '全部品牌' }, ...(summary?.oems.map((item) => ({ value: item.name, label: item.name })) ?? [])]} /></label>
|
||||
<div className="v2-access-filter-actions">
|
||||
<Button className="v2-primary-button" theme="solid" htmlType="submit">查询</Button>
|
||||
<Button className="v2-secondary-button" theme="light" htmlType="button" onClick={() => apply(EMPTY_FILTERS)}>重置</Button>
|
||||
</div>
|
||||
</form></WorkspaceFilterPanel>
|
||||
<div className="v2-access-discovery-shell">
|
||||
<WorkspaceCommandBar
|
||||
className="v2-access-command-bar"
|
||||
ariaLabel="接入管理操作"
|
||||
title="真实来源与接入健康"
|
||||
description="真实来源、在线健康与资料差异一处核对"
|
||||
status={summary ? `${summary.totalVehicles.toLocaleString('zh-CN')} 辆主车辆` : '正在读取车辆'}
|
||||
meta={<Typography.Text type="tertiary">数据时间 {summary?.asOf ? formatAccessTime(summary.asOf) : '—'}</Typography.Text>}
|
||||
actions={<>{editable ? <Button theme="light" icon={<IconSetting />} aria-haspopup="dialog" aria-controls="v2-access-governance" aria-expanded={governanceOpen} onClick={() => setGovernanceOpen(true)}>接入治理{unresolvedQuery.data?.total ? ` · ${unresolvedQuery.data.total}` : ''}</Button> : null}<Button theme="light" icon={<IconRefresh />} onClick={() => void refresh()}>刷新</Button></>}
|
||||
/>
|
||||
<WorkspaceFilterPanel
|
||||
className="v2-access-filter-card-v3"
|
||||
title="接入筛选"
|
||||
description="车辆、接入状态、真实协议与品牌"
|
||||
mobileSummary={Object.values(criteria).filter(Boolean).length ? `已启用 ${Object.values(criteria).filter(Boolean).length} 项` : '全部主车辆'}
|
||||
expanded={!filtersCollapsed}
|
||||
status={Object.values(criteria).filter(Boolean).length ? `${Object.values(criteria).filter(Boolean).length} 项已启用` : '全部主车辆'}
|
||||
statusColor={Object.values(criteria).filter(Boolean).length ? 'blue' : 'grey'}
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
>
|
||||
<form className="v2-access-filter-v3" onSubmit={submit}>
|
||||
<label className="is-search"><span>车辆</span><Input aria-label="车辆" prefix={<IconSearch />} value={draft.keyword} onChange={(value) => setDraft({ ...draft, keyword: value })} placeholder="车牌 / VIN" /></label>
|
||||
<label><span id="access-connection-label">接入状态</span><Select aria-labelledby="access-connection-label" value={draft.connectionState} onChange={(value) => setDraft({ ...draft, connectionState: String(value) })} optionList={[{ value: '', label: '全部状态' }, { value: 'attention', label: '需关注' }, { value: 'healthy', label: '已接来源正常' }, { value: 'master_data', label: '资料待维护' }, { value: 'degraded', label: '部分来源异常' }, { value: 'offline', label: '已接来源离线' }, { value: 'not_connected', label: '尚无来源' }]} /></label>
|
||||
<label><span id="access-protocol-label">真实协议</span><Select aria-labelledby="access-protocol-label" value={draft.protocol} onChange={(value) => setDraft({ ...draft, protocol: String(value) })} optionList={[{ value: '', label: '全部协议' }, ...PROTOCOLS.map((item) => ({ value: item, label: item }))]} /></label>
|
||||
<label><span id="access-oem-label">车辆品牌</span><Select aria-labelledby="access-oem-label" value={draft.oem} onChange={(value) => setDraft({ ...draft, oem: String(value) })} optionList={[{ value: '', label: '全部品牌' }, ...(summary?.oems.map((item) => ({ value: item.name, label: item.name })) ?? [])]} /></label>
|
||||
<div className="v2-access-filter-actions">
|
||||
<Button className="v2-primary-button" theme="solid" htmlType="submit">查询</Button>
|
||||
<Button className="v2-secondary-button" theme="light" htmlType="button" onClick={() => apply(EMPTY_FILTERS)}>重置</Button>
|
||||
</div>
|
||||
</form>
|
||||
</WorkspaceFilterPanel>
|
||||
</div>
|
||||
{summaryQuery.isError ? <InlineError message={summaryQuery.error instanceof Error ? summaryQuery.error.message : '接入汇总读取失败'} onRetry={() => summaryQuery.refetch()} /> : null}
|
||||
<Card className="v2-access-kpis-card-v3" bodyStyle={{ padding: 0 }}><section className="v2-access-kpis-v3">{[
|
||||
{ label: '主车辆', value: summary?.totalVehicles ?? 0, tone: 'all', connectionState: '', hint: '车辆主档' },
|
||||
{ label: '需关注', value: Math.max(0, (summary?.totalVehicles ?? 0) - (summary?.healthyVehicles ?? 0)), tone: 'attention', connectionState: 'attention' },
|
||||
{ label: '资料待维护', value: summary?.masterDataIncompleteVehicles ?? 0, tone: 'incomplete', connectionState: 'master_data' },
|
||||
{ label: '尚无来源', value: summary?.neverReported ?? 0, tone: 'never', connectionState: 'not_connected' }
|
||||
].map((item) => {
|
||||
const value = Number(item.value).toLocaleString('zh-CN');
|
||||
return <MetricActionButton key={item.label} label={item.label} value={value} hint={item.hint} tone={item.tone} active={criteria.connectionState === item.connectionState} ariaLabel={`筛选${item.label},共 ${value} 辆`} onClick={() => apply({ ...criteria, connectionState: item.connectionState })} />;
|
||||
})}</section></Card>
|
||||
{vehiclesQuery.isError ? <InlineError message={vehiclesQuery.error instanceof Error ? vehiclesQuery.error.message : '接入车辆读取失败'} onRetry={() => vehiclesQuery.refetch()} /> : null}
|
||||
<div className={`v2-access-workspace-v3 ${selected && !mobileLayout ? 'is-inspector-open' : ''}`}>
|
||||
<div className="v2-access-workspace-v3">
|
||||
<Card className="v2-access-table-v3" bodyStyle={{ padding: 0 }}>
|
||||
<WorkspacePanelHeader
|
||||
title="车辆真实接入来源"
|
||||
description="缺席协议只表示“当前未发现”,不会被推断成应接缺失;时间为各来源最后接收时间"
|
||||
title={scopeLabels[criteria.connectionState] || '车辆接入清单'}
|
||||
description="缺席协议仅表示当前未发现;优先核对异常、离线与资料差异"
|
||||
actionsClassName="v2-access-table-actions"
|
||||
actions={<><ProtocolCoverage summary={summary} /><Button theme="light" icon={<IconDownload />} onClick={() => downloadRows(rows)} disabled={!rows.length}>导出当前页</Button></>}
|
||||
/>
|
||||
<nav className="v2-access-status-tabs" aria-label="接入差异筛选">{[
|
||||
{ label: '主车辆', value: summary?.totalVehicles ?? 0, tone: 'all', connectionState: '', hint: '全部' },
|
||||
{ label: '需关注', value: Math.max(0, (summary?.totalVehicles ?? 0) - (summary?.healthyVehicles ?? 0)), tone: 'attention', connectionState: 'attention' },
|
||||
{ label: '资料待维护', value: summary?.masterDataIncompleteVehicles ?? 0, tone: 'incomplete', connectionState: 'master_data' },
|
||||
{ label: '尚无来源', value: summary?.neverReported ?? 0, tone: 'never', connectionState: 'not_connected' }
|
||||
].map((item) => {
|
||||
const value = Number(item.value).toLocaleString('zh-CN');
|
||||
return <MetricActionButton key={item.label} label={item.label} value={value} hint={item.hint} tone={item.tone} active={criteria.connectionState === item.connectionState} ariaLabel={`筛选${item.label},共 ${value} 辆`} onClick={() => apply({ ...criteria, connectionState: item.connectionState })} />;
|
||||
})}</nav>
|
||||
<div
|
||||
className={`v2-access-table-scroll-v3${mobileLayout ? ' is-mobile-scroll' : ''}`}
|
||||
tabIndex={mobileLayout ? 0 : undefined}
|
||||
aria-label={mobileLayout ? '车辆接入列表,可上下滚动' : undefined}
|
||||
>
|
||||
{mobileLayout
|
||||
? <div className="v2-access-mobile-list">{rows.map((row) => <Card key={row.vin} className={`v2-access-mobile-card${selected?.vin === row.vin ? ' is-selected' : ''}`} bodyStyle={{ padding: 0 }}><Button theme="borderless" type="tertiary" aria-pressed={selected?.vin === row.vin} aria-expanded={selected?.vin === row.vin} aria-label={`查看 ${row.plate || row.vin} 接入详情`} className="v2-access-mobile-action" onClick={() => setSelectedVIN(row.vin)}><span className="v2-access-mobile-card-content"><header><span><strong>{row.plate || '未绑定车牌'}</strong><small>{row.vin}</small></span><ConnectionState row={row} /></header><p>{row.oem || '品牌未维护'} · {row.model || row.company || '车型未维护'}</p><span className="v2-access-mobile-protocols">{PROTOCOLS.map((protocol) => <ProtocolState key={protocol} protocolLabel={protocol} status={statusByProtocol(row, protocol)} />)}</span><footer>查看接入详情<IconChevronRight /></footer></span></Button></Card>)}</div>
|
||||
? <div className="v2-access-mobile-list">{rows.map((row) => <Card key={row.vin} className={`v2-access-mobile-card${selected?.vin === row.vin ? ' is-selected' : ''}`} bodyStyle={{ padding: 0 }}><Button theme="borderless" type="tertiary" aria-pressed={selected?.vin === row.vin} aria-expanded={selected?.vin === row.vin} aria-label={`查看 ${row.plate || row.vin} 接入详情`} className="v2-access-mobile-action" onClick={() => setSelectedVIN(row.vin)}><span className="v2-access-mobile-card-content"><header><span><strong>{row.plate || '未绑定车牌'}</strong><small>{row.vin}</small></span><ConnectionState row={row} /></header><p>{row.oem || '品牌未维护'} · {row.model || row.company || '车型未维护'}</p><span className="v2-access-mobile-protocols">{PROTOCOLS.map((protocol) => <ProtocolState key={protocol} protocolLabel={compactProtocolLabel(protocol)} status={statusByProtocol(row, protocol)} />)}</span><footer>查看接入详情<IconChevronRight /></footer></span></Button></Card>)}</div>
|
||||
: <AccessVehicleTable rows={rows} selectedVIN={selectedVIN} onSelect={setSelectedVIN} />}
|
||||
{vehiclesQuery.isFetching ? <PanelLoading className="v2-access-loading" title="正在更新车辆接入状态…" description="当前列表返回后会自动替换。" compact={Boolean(rows.length)} /> : null}
|
||||
{!vehiclesQuery.isFetching && !rows.length ? <PanelEmpty className="v2-access-empty" title="没有匹配车辆" description="调整车牌、协议或接入状态筛选后重试。" /> : null}
|
||||
</div>
|
||||
<footer><TablePagination page={page} totalPages={totalPages} info={`共 ${(vehiclesQuery.data?.total ?? 0).toLocaleString('zh-CN')} 辆主车辆`} onPageChange={(next) => setOffset((next - 1) * limit)} pageSize={limit} pageSizeLabel="每页车辆数" onPageSizeChange={(next) => { setLimit(next); setOffset(0); }} pageSizeOptions={[{ value: 20, label: '20 辆/页' }, { value: 50, label: '50 辆/页' }, { value: 100, label: '100 辆/页' }]} /></footer>
|
||||
</Card>
|
||||
{!mobileLayout && selected ? <VehicleInspector row={selected} onClose={() => setSelectedVIN('')} /> : null}
|
||||
</div>
|
||||
<SideSheet
|
||||
className="v2-access-detail-sidesheet"
|
||||
visible={mobileLayout && Boolean(selected)}
|
||||
visible={Boolean(selected)}
|
||||
aria-label="车辆接入详情"
|
||||
width="100%"
|
||||
width={mobileLayout ? '100%' : 520}
|
||||
title={<div className="v2-access-sheet-title"><strong>车辆接入详情</strong><span>{selected ? `${selected.plate || '未绑定车牌'} · ${selected.vin}` : '来源、在线状态与接入证据'}</span></div>}
|
||||
onCancel={() => setSelectedVIN('')}
|
||||
>
|
||||
{mobileLayout && selected ? <VehicleInspector row={selected} onClose={() => setSelectedVIN('')} sheet /> : null}
|
||||
{selected ? <VehicleInspector row={selected} onClose={() => setSelectedVIN('')} sheet /> : null}
|
||||
</SideSheet>
|
||||
{editable ? <SideSheet
|
||||
className="v2-access-governance-sidesheet"
|
||||
|
||||
@@ -197,9 +197,12 @@ describe('V2 production entry', () => {
|
||||
expect(corePageSources.AccessPage).toContain('<Input');
|
||||
expect(corePageSources.AccessPage).toContain('<Select');
|
||||
expect(corePageSources.AccessPage).toContain('<Card');
|
||||
for (const surface of ['v2-access-kpis-card-v3', 'v2-access-table-v3']) {
|
||||
for (const surface of ['v2-access-table-v3']) {
|
||||
expect(corePageSources.AccessPage).toContain(`<Card className="${surface}"`);
|
||||
}
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-discovery-shell"');
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-status-tabs"');
|
||||
expect(corePageSources.AccessPage).not.toContain('className="v2-access-kpis-card-v3"');
|
||||
expect(corePageSources.AccessPage).toContain('<Card className={`v2-access-inspector-v3');
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-detail-sidesheet"');
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-governance-sidesheet"');
|
||||
|
||||
@@ -8300,12 +8300,39 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 8px;
|
||||
gap: 10px;
|
||||
overflow: hidden;
|
||||
padding: 12px 14px 14px;
|
||||
padding: 14px 16px 16px;
|
||||
}
|
||||
|
||||
.v2-access-discovery-shell {
|
||||
display: grid;
|
||||
flex: 0 0 auto;
|
||||
overflow: visible;
|
||||
gap: 0;
|
||||
border: 1px solid #dce4ee;
|
||||
border-radius: 14px;
|
||||
background: #fff;
|
||||
box-shadow: 0 9px 28px rgba(31, 53, 80, .055);
|
||||
}
|
||||
|
||||
.v2-access-discovery-shell > .v2-workspace-command-bar {
|
||||
width: 100%;
|
||||
min-height: 50px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #e6ecf3;
|
||||
border-radius: 14px 14px 0 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.v2-access-discovery-shell > .v2-access-filter-card-v3.semi-card {
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
border: 0;
|
||||
border-radius: 0 0 14px 14px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.v2-access-page-v3 > .v2-workspace-command-bar,
|
||||
.v2-ops-command-bar {
|
||||
max-width: none;
|
||||
}
|
||||
@@ -8362,20 +8389,6 @@
|
||||
box-shadow: 0 7px 16px rgba(18, 104, 243, .15);
|
||||
}
|
||||
|
||||
.v2-access-kpis-card-v3.semi-card,
|
||||
.v2-access-kpis-v3 {
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 .v2-metric-action {
|
||||
min-height: 58px;
|
||||
padding: 8px 14px;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 strong {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.v2-access-workspace-v3 {
|
||||
min-height: 0;
|
||||
flex: 1 1 0;
|
||||
@@ -8387,6 +8400,96 @@
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs {
|
||||
display: grid;
|
||||
min-height: 48px;
|
||||
flex: 0 0 auto;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #e4eaf2;
|
||||
background: #fbfcfe;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action.semi-button {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 48px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
padding: 0 14px;
|
||||
color: #66778d;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action + .v2-metric-action::before {
|
||||
position: absolute;
|
||||
inset: 10px auto 10px 0;
|
||||
width: 1px;
|
||||
background: #e1e7ef;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action:hover {
|
||||
background: #f4f8fe;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action.is-active {
|
||||
z-index: 1;
|
||||
background: #eef5ff;
|
||||
color: var(--v2-blue);
|
||||
box-shadow: inset 0 -3px var(--v2-blue);
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .semi-button-content,
|
||||
.v2-access-status-tabs .v2-metric-action-content {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action-content {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs small {
|
||||
overflow: hidden;
|
||||
color: inherit;
|
||||
font-size: 11px;
|
||||
font-weight: 650;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs strong {
|
||||
margin-left: auto;
|
||||
color: #304157;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .is-attention strong,
|
||||
.v2-access-status-tabs .is-incomplete strong {
|
||||
color: #c46b0d;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .is-never strong {
|
||||
color: #67778b;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs em {
|
||||
color: #8b98aa;
|
||||
font-size: 9px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.v2-access-table-v3 .semi-table-tbody > .semi-table-row > .semi-table-row-cell {
|
||||
height: 58px;
|
||||
padding-block: 6px;
|
||||
}
|
||||
|
||||
.v2-ops-page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -8427,6 +8530,23 @@
|
||||
padding: 7px 7px 8px;
|
||||
}
|
||||
|
||||
.v2-access-discovery-shell {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.v2-access-discovery-shell > .v2-workspace-command-bar {
|
||||
min-height: 48px;
|
||||
border: 1px solid #dce6f2;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(105deg, #fff 0%, #f8fbff 100%);
|
||||
}
|
||||
|
||||
.v2-access-discovery-shell > .v2-access-filter-card-v3.semi-card {
|
||||
border: 1px solid #dce6f2;
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--v2-shadow);
|
||||
}
|
||||
|
||||
.v2-access-filter-card-v3 > .semi-card-body > .v2-workspace-filter-heading {
|
||||
display: flex;
|
||||
}
|
||||
@@ -8457,42 +8577,6 @@
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.v2-access-kpis-card-v3.semi-card,
|
||||
.v2-access-kpis-v3 {
|
||||
min-height: 62px;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 .v2-metric-action {
|
||||
min-height: 62px;
|
||||
padding: 7px 6px;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 .v2-metric-action-content {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 small {
|
||||
overflow: hidden;
|
||||
font-size: 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 strong {
|
||||
margin-left: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.v2-access-kpis-v3 em {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-access-workspace-v3 {
|
||||
min-height: 0;
|
||||
flex: 1 1 0;
|
||||
@@ -8502,10 +8586,59 @@
|
||||
.v2-access-table-v3 > .semi-card-body > .v2-workspace-panel-header {
|
||||
min-height: 50px;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.v2-access-table-v3 .v2-workspace-panel-copy > .semi-typography {
|
||||
.v2-access-table-v3 .v2-workspace-panel-copy {
|
||||
width: auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.v2-access-table-v3 .v2-workspace-panel-copy > .semi-typography:not(h5) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-access-table-v3 .v2-workspace-panel-copy > h5.semi-typography {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.v2-access-table-v3 .v2-access-table-actions {
|
||||
width: auto;
|
||||
max-width: none;
|
||||
flex: 0 0 auto;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs {
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action.semi-button {
|
||||
height: 44px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action + .v2-metric-action::before {
|
||||
inset-block: 9px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs .v2-metric-action-content {
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs small {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs strong {
|
||||
margin-left: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.v2-access-status-tabs em {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -8557,11 +8690,11 @@
|
||||
}
|
||||
|
||||
.v2-access-mobile-card-content > header strong {
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.v2-access-mobile-card-content > header small {
|
||||
font-size: 8px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.v2-access-mobile-card-content > header .v2-access-connection {
|
||||
@@ -8581,8 +8714,8 @@
|
||||
|
||||
.v2-access-mobile-card-content > p {
|
||||
overflow: hidden;
|
||||
font-size: 9px;
|
||||
line-height: 12px;
|
||||
font-size: 10px;
|
||||
line-height: 13px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -8603,7 +8736,7 @@
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #50627a;
|
||||
font-size: 8px;
|
||||
font-size: 9px;
|
||||
line-height: 11px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -8612,7 +8745,7 @@
|
||||
.v2-access-mobile-list .v2-access-protocol-cell > span {
|
||||
justify-self: end;
|
||||
gap: 3px;
|
||||
font-size: 8px;
|
||||
font-size: 9px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
@@ -8623,7 +8756,7 @@
|
||||
|
||||
.v2-access-mobile-list .v2-access-protocol-cell > strong {
|
||||
grid-column: 1 / -1;
|
||||
font-size: 8px;
|
||||
font-size: 9px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
@@ -8648,6 +8781,22 @@
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.v2-access-detail-sidesheet .v2-access-protocol-details.semi-card-group {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
overflow-x: hidden;
|
||||
gap: 8px;
|
||||
padding: 10px;
|
||||
scroll-snap-type: none;
|
||||
}
|
||||
|
||||
.v2-access-detail-sidesheet .v2-access-protocol-detail.semi-card {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
flex: none;
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
.v2-ops-page {
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
|
||||
Reference in New Issue
Block a user