unify Semi UI workspace command hierarchy
This commit is contained in:
@@ -50,6 +50,8 @@ test('removes old access rows immediately when the vehicle filter scope changes'
|
||||
const view = render(<QueryClientProvider client={client}><MemoryRouter future={ROUTER_FUTURE} initialEntries={['/access?keyword=OLDVIN']}><AccessPage /></MemoryRouter></QueryClientProvider>);
|
||||
|
||||
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(`.${className}.semi-card`)).toBeInTheDocument();
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import type { AccessProtocolStatus, AccessQuery, AccessSummary, AccessThresholdC
|
||||
import { accessRowsToCSV, formatAccessTime, formatSeconds, updateProtocolThreshold } from '../domain/access';
|
||||
import { InlineError, PanelEmpty, PanelLoading } from '../shared/AsyncState';
|
||||
import { MetricActionButton } from '../shared/MetricActionButton';
|
||||
import { PageHeader } from '../shared/PageHeader';
|
||||
import { TablePagination } from '../shared/TablePagination';
|
||||
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
||||
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
||||
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||
import { detailTriggerRow } from '../shared/detailTriggerRow';
|
||||
@@ -201,8 +201,10 @@ 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">
|
||||
<PageHeader
|
||||
title="车辆接入管理"
|
||||
<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>}
|
||||
|
||||
@@ -59,6 +59,8 @@ test('renders reconciliation queue, loads evidence on demand and records review
|
||||
render(<QueryClientProvider client={client}><OperationsPage /></QueryClientProvider>);
|
||||
|
||||
expect(await screen.findByText('数据差异中心')).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: '运行与数据质量', level: 5 })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('运维质量操作')).toHaveClass('v2-workspace-command-bar', 'v2-ops-command-bar');
|
||||
expect(screen.getByRole('tab', { name: '差异处置', selected: true })).toHaveClass('semi-button');
|
||||
expect(screen.getByRole('tabpanel', { name: '差异处置' })).toBeInTheDocument();
|
||||
expect(screen.queryByText('先选择一辆车')).not.toBeInTheDocument();
|
||||
|
||||
@@ -5,9 +5,9 @@ import { FormEvent, useDeferredValue, useEffect, useState } from 'react';
|
||||
import { api } from '../../api/client';
|
||||
import type { VehicleCoverageRow, VehicleLocationSourceEvidence, VehicleSourceDiagnostic } from '../../api/types';
|
||||
import { InlineError } from '../shared/AsyncState';
|
||||
import { PageHeader } from '../shared/PageHeader';
|
||||
import { SegmentedTabs } from '../shared/SegmentedTabs';
|
||||
import { VehicleCandidateList } from '../shared/VehicleCandidateList';
|
||||
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
||||
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
||||
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||
import { LIVE_QUERY_POLICY, QUERY_MEMORY } from '../queryPolicy';
|
||||
@@ -340,8 +340,10 @@ export default function OperationsPage() {
|
||||
const healthIssueCount = linkIssueCount + runtimeIssueCount + capacityIssueCount + Number((data?.kafkaLag ?? 0) > 0);
|
||||
const overallStatus = !data ? 'unknown' : healthIssueCount > 0 ? 'warning' : 'ok';
|
||||
return <div className="v2-ops-page">
|
||||
<PageHeader
|
||||
title="运维质量"
|
||||
<WorkspaceCommandBar
|
||||
className="v2-ops-command-bar"
|
||||
ariaLabel="运维质量操作"
|
||||
title="运行与数据质量"
|
||||
description="先定位单车多来源问题,再核对服务和协议全局健康;所有结论来自服务端证据。"
|
||||
status={data?.runtime.dataMode === 'production' ? '生产模式' : '状态待确认'}
|
||||
statusColor={data?.runtime.dataMode === 'production' ? 'green' : 'orange'}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useSideSheetA11y } from '../hooks/useSideSheetA11y';
|
||||
import { TablePagination } from '../shared/TablePagination';
|
||||
import { VehicleCandidateList } from '../shared/VehicleCandidateList';
|
||||
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
||||
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
||||
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
|
||||
import { PanelEmpty, PanelLoading } from '../shared/AsyncState';
|
||||
@@ -244,17 +245,15 @@ export default function UsersPage() {
|
||||
};
|
||||
|
||||
return <div className="v2-user-admin">
|
||||
<div className="v2-user-command-bar" aria-label="账号管理操作">
|
||||
<div className="v2-user-command-copy">
|
||||
<strong>客户访问治理</strong>
|
||||
<span>菜单与车辆按最小权限开放,变更最多 30 秒生效</span>
|
||||
</div>
|
||||
<div className="v2-user-command-meta">
|
||||
<Tag color="blue" type="light" size="small">{customers.length} 个客户账号</Tag>
|
||||
<Typography.Text type="tertiary">本地账号 · 可扩展外部身份源</Typography.Text>
|
||||
<Button theme="solid" icon={<IconPlus />} aria-label="新建客户账号" onClick={startCreate}>新建客户账号</Button>
|
||||
</div>
|
||||
</div>
|
||||
<WorkspaceCommandBar
|
||||
className="v2-user-command-bar"
|
||||
ariaLabel="账号管理操作"
|
||||
title="客户访问治理"
|
||||
description="菜单与车辆按最小权限开放,变更最多 30 秒生效"
|
||||
status={`${customers.length} 个客户账号`}
|
||||
meta={<Typography.Text type="tertiary">本地账号 · 可扩展外部身份源</Typography.Text>}
|
||||
actions={<Button theme="solid" icon={<IconPlus />} aria-label="新建客户账号" onClick={startCreate}>新建客户账号</Button>}
|
||||
/>
|
||||
<WorkspaceFilterPanel
|
||||
className="v2-user-filter-panel"
|
||||
title="账号范围"
|
||||
|
||||
@@ -151,7 +151,8 @@ test('shows deduplicated Semi vehicle candidates and opens the selected VIN', as
|
||||
|
||||
const view = render(<QueryClientProvider client={client}><MemoryRouter initialEntries={['/vehicles']} future={ROUTER_FUTURE}><Routes><Route path="/vehicles" element={<VehiclePage />} /><Route path="/vehicles/:vin" element={<VehiclePage />} /></Routes></MemoryRouter></QueryClientProvider>);
|
||||
|
||||
expect(screen.getByRole('heading', { name: '车辆查询', level: 2 })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: '车辆快速定位', level: 5 })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('查车操作')).toHaveClass('v2-workspace-command-bar', 'v2-vehicle-command-bar');
|
||||
expect(screen.getByRole('heading', { name: '车辆定位', level: 5 }).closest('.semi-card')).toHaveClass('v2-vehicle-query-panel', 'v2-workspace-filter-panel');
|
||||
const input = screen.getByRole('textbox', { name: '搜索车辆' });
|
||||
expect(input).toHaveAttribute('aria-expanded', 'false');
|
||||
|
||||
@@ -17,11 +17,11 @@ import { isValidAMapCoordinate } from '../../integrations/amap';
|
||||
import { FleetMap } from '../map/FleetMap';
|
||||
import { InlineError, PageLoading } from '../shared/AsyncState';
|
||||
import { MonitorReturnBar } from '../shared/MonitorReturnBar';
|
||||
import { PageHeader } from '../shared/PageHeader';
|
||||
import { SegmentedTabs } from '../shared/SegmentedTabs';
|
||||
import { VehicleCandidateList } from '../shared/VehicleCandidateList';
|
||||
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
|
||||
import { VehicleSourceEvidencePanel } from '../shared/VehicleSourceEvidencePanel';
|
||||
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
||||
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
||||
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||
import { monitorReturnFromParams, withMonitorReturn } from '../routing/monitorContext';
|
||||
@@ -105,9 +105,11 @@ function VehicleSearch() {
|
||||
};
|
||||
const vehicleScope = candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权` : '授权范围';
|
||||
return <section className={`v2-vehicle-search-page${syncOpen ? ' has-sync-panel' : ''}${candidatesOpen ? ' has-candidates' : ''}`}>
|
||||
<PageHeader
|
||||
title="车辆查询"
|
||||
description="通过车牌、VIN 或终端手机号定位车辆,进入统一数字档案"
|
||||
<WorkspaceCommandBar
|
||||
className="v2-vehicle-command-bar"
|
||||
ariaLabel="查车操作"
|
||||
title="车辆快速定位"
|
||||
description="车牌、VIN 或手机号快速查车"
|
||||
status={candidates.isPending ? '正在读取授权范围' : vehicleScope}
|
||||
statusColor={candidates.isError ? 'red' : 'blue'}
|
||||
actions={canAdminister(session) ? <Button theme="light" onClick={() => setSyncOpen((value) => !value)}>{syncOpen ? '收起主档同步' : '批量同步主档'}</Button> : null}
|
||||
@@ -115,7 +117,7 @@ function VehicleSearch() {
|
||||
<WorkspaceFilterPanel
|
||||
className="v2-vehicle-query-panel"
|
||||
title="车辆定位"
|
||||
description="车牌优先、VIN 辅助,支持终端手机号精确定位"
|
||||
description="车牌优先,VIN 辅助"
|
||||
mobileSummary={deferredKeyword ? `正在查找 ${deferredKeyword}` : candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权车辆` : '正在读取授权范围'}
|
||||
expanded={!filtersCollapsed}
|
||||
status={deferredKeyword ? candidates.isFetching ? '正在查找' : `${options.length} 辆匹配` : vehicleScope}
|
||||
|
||||
@@ -55,14 +55,14 @@ describe('V2 production entry', () => {
|
||||
expect(source).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(source).toContain('<Button');
|
||||
}
|
||||
for (const name of ['VehiclePage', 'AccessPage', 'OperationsPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/PageHeader'");
|
||||
expect(corePageSources[name]).toContain('<PageHeader');
|
||||
}
|
||||
for (const name of ['AlertsPage', 'HistoryPage', 'StatisticsPage', 'UsersPage']) {
|
||||
for (const name of ['VehiclePage', 'AccessPage', 'OperationsPage', 'AlertsPage', 'HistoryPage', 'StatisticsPage', 'UsersPage']) {
|
||||
expect(corePageSources[name]).not.toContain("from '../shared/PageHeader'");
|
||||
expect(corePageSources[name]).not.toContain('<PageHeader');
|
||||
}
|
||||
for (const name of ['VehiclePage', 'AccessPage', 'OperationsPage', 'UsersPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/WorkspaceCommandBar'");
|
||||
expect(corePageSources[name]).toContain('<WorkspaceCommandBar');
|
||||
}
|
||||
expect(corePageSources.VehiclePage).toContain('<Select');
|
||||
expect(corePageSources.VehiclePage).toContain('<Card className="v2-identity-band v2-record-card v2-live-card v2-live-overview v2-vehicle-command-card"');
|
||||
expect(corePageSources.VehiclePage).toContain('className="v2-live-grid" role="list" aria-label="车辆实时指标"');
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { Tag, Typography } from '@douyinfe/semi-ui';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
export function PageHeader({
|
||||
title,
|
||||
description,
|
||||
status,
|
||||
statusColor = 'blue',
|
||||
meta,
|
||||
actions
|
||||
}: {
|
||||
title: string;
|
||||
description: string;
|
||||
status?: string;
|
||||
statusColor?: React.ComponentProps<typeof Tag>['color'];
|
||||
meta?: ReactNode;
|
||||
actions?: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<header className="v2-page-heading">
|
||||
<div className="v2-page-heading-copy">
|
||||
<div>
|
||||
<Title heading={2}>{title}</Title>
|
||||
{status ? <Tag color={statusColor} size="small">{status}</Tag> : null}
|
||||
</div>
|
||||
<Text type="secondary">{description}</Text>
|
||||
</div>
|
||||
{meta || actions ? <div className="v2-page-heading-aside">{meta}{actions}</div> : null}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { Button, Typography } from '@douyinfe/semi-ui';
|
||||
import { expect, test } from 'vitest';
|
||||
import { WorkspaceCommandBar } from './WorkspaceCommandBar';
|
||||
|
||||
test('renders a compact Semi workspace command hierarchy', () => {
|
||||
const view = render(<WorkspaceCommandBar
|
||||
className="custom-command"
|
||||
ariaLabel="测试工作区操作"
|
||||
title="测试工作区"
|
||||
description="说明当前任务和数据范围"
|
||||
status="12 条"
|
||||
meta={<Typography.Text type="tertiary">刚刚更新</Typography.Text>}
|
||||
actions={<Button theme="solid">执行</Button>}
|
||||
/>);
|
||||
|
||||
expect(screen.getByRole('heading', { name: '测试工作区', level: 5 })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('测试工作区操作')).toHaveClass('v2-workspace-command-bar', 'custom-command');
|
||||
expect(screen.getByText('12 条').closest('.semi-tag')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '执行' })).toHaveClass('semi-button');
|
||||
expect(view.container.querySelector('.v2-workspace-command-copy')).toHaveTextContent('说明当前任务和数据范围');
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import { Tag, Typography } from '@douyinfe/semi-ui';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
export function WorkspaceCommandBar({
|
||||
title,
|
||||
description,
|
||||
status,
|
||||
statusColor = 'blue',
|
||||
meta,
|
||||
actions,
|
||||
className = '',
|
||||
ariaLabel
|
||||
}: {
|
||||
title: ReactNode;
|
||||
description: ReactNode;
|
||||
status?: string;
|
||||
statusColor?: React.ComponentProps<typeof Tag>['color'];
|
||||
meta?: ReactNode;
|
||||
actions?: ReactNode;
|
||||
className?: string;
|
||||
ariaLabel?: string;
|
||||
}) {
|
||||
const rootClassName = ['v2-workspace-command-bar', className].filter(Boolean).join(' ');
|
||||
|
||||
return (
|
||||
<header className={rootClassName} aria-label={ariaLabel}>
|
||||
<div className="v2-workspace-command-copy">
|
||||
<Title heading={5}>{title}</Title>
|
||||
<Text type="tertiary">{description}</Text>
|
||||
</div>
|
||||
{status || meta || actions ? <div className="v2-workspace-command-actions">
|
||||
{status ? <Tag color={statusColor} type="light" size="small">{status}</Tag> : null}
|
||||
{meta ? <span className="v2-workspace-command-meta">{meta}</span> : null}
|
||||
{actions}
|
||||
</div> : null}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -1877,6 +1877,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.v2-assigned-vins {
|
||||
max-height: min(360px, 42dvh);
|
||||
@@ -6521,7 +6522,7 @@
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.v2-user-command-bar {
|
||||
.v2-workspace-command-bar {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 1480px;
|
||||
@@ -6538,35 +6539,37 @@
|
||||
box-shadow: 0 6px 20px rgba(31, 50, 76, .035);
|
||||
}
|
||||
|
||||
.v2-user-command-copy {
|
||||
.v2-workspace-command-copy {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.v2-user-command-copy strong {
|
||||
.v2-workspace-command-copy .semi-typography {
|
||||
color: #263b53;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -.012em;
|
||||
}
|
||||
|
||||
.v2-user-command-copy span {
|
||||
.v2-workspace-command-copy > .semi-typography:last-child {
|
||||
overflow: hidden;
|
||||
color: #7d8b9d;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.v2-user-command-meta {
|
||||
.v2-workspace-command-actions {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.v2-user-command-meta > .semi-tag {
|
||||
.v2-workspace-command-actions > .semi-tag {
|
||||
min-height: 24px;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 999px;
|
||||
@@ -6575,7 +6578,13 @@
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.v2-user-command-meta > .semi-typography {
|
||||
.v2-workspace-command-meta {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.v2-workspace-command-meta > .semi-typography {
|
||||
overflow: hidden;
|
||||
max-width: 220px;
|
||||
font-size: 10px;
|
||||
@@ -6583,7 +6592,7 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.v2-user-command-meta > .semi-button {
|
||||
.v2-workspace-command-actions > .semi-button {
|
||||
min-height: 36px;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 8px;
|
||||
@@ -6903,7 +6912,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 980px) and (min-width: 681px) {
|
||||
.v2-user-command-meta > .semi-typography {
|
||||
.v2-workspace-command-meta > .semi-typography {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -6929,35 +6938,50 @@
|
||||
padding: 7px 7px 10px;
|
||||
}
|
||||
|
||||
.v2-user-command-bar {
|
||||
.v2-workspace-command-bar {
|
||||
min-height: 48px;
|
||||
gap: 8px;
|
||||
border-radius: 9px;
|
||||
padding: 5px 6px 5px 10px;
|
||||
}
|
||||
|
||||
.v2-user-command-copy strong {
|
||||
.v2-workspace-command-copy > .semi-typography:first-child {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.v2-user-command-copy span,
|
||||
.v2-user-command-meta > .semi-tag,
|
||||
.v2-user-command-meta > .semi-typography {
|
||||
.v2-workspace-command-copy > .semi-typography:last-child,
|
||||
.v2-workspace-command-actions > .semi-tag,
|
||||
.v2-workspace-command-meta {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-user-command-meta > .semi-button {
|
||||
.v2-workspace-command-actions {
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.v2-workspace-command-actions > .semi-button {
|
||||
min-height: 38px;
|
||||
padding-inline: 9px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.v2-user-command-bar .v2-workspace-command-actions > .semi-button,
|
||||
.v2-access-command-bar .v2-workspace-command-actions > .semi-button,
|
||||
.v2-ops-command-bar .v2-workspace-command-actions > .semi-button {
|
||||
width: 40px;
|
||||
min-width: 40px;
|
||||
min-height: 40px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.v2-user-command-meta > .semi-button .semi-button-content {
|
||||
.v2-user-command-bar .v2-workspace-command-actions > .semi-button .semi-button-content,
|
||||
.v2-access-command-bar .v2-workspace-command-actions > .semi-button .semi-button-content,
|
||||
.v2-ops-command-bar .v2-workspace-command-actions > .semi-button .semi-button-content {
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.v2-user-command-meta > .semi-button .semi-icon {
|
||||
.v2-user-command-bar .v2-workspace-command-actions > .semi-button .semi-icon,
|
||||
.v2-access-command-bar .v2-workspace-command-actions > .semi-button .semi-icon,
|
||||
.v2-ops-command-bar .v2-workspace-command-actions > .semi-button .semi-icon {
|
||||
margin-right: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
@@ -7158,3 +7182,233 @@
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Final cascade layer for the shared command hierarchy. */
|
||||
.v2-workspace-command-bar {
|
||||
box-sizing: border-box;
|
||||
height: 52px;
|
||||
min-height: 52px;
|
||||
padding-block: 5px;
|
||||
}
|
||||
|
||||
.v2-workspace-command-copy {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.v2-workspace-command-copy > .semi-typography:first-child {
|
||||
margin: 0;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.v2-workspace-command-copy > .semi-typography:last-child {
|
||||
margin: 0;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel > .semi-card-body > .v2-workspace-filter-heading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel .v2-vehicle-search-form {
|
||||
display: flex;
|
||||
height: 54px;
|
||||
min-height: 54px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-top: 0;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel .v2-vehicle-search-form > .v2-vehicle-search-picker {
|
||||
width: auto;
|
||||
min-height: 40px;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel .v2-vehicle-search-form > .semi-button {
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.v2-ops-tabs {
|
||||
box-sizing: border-box;
|
||||
height: 44px;
|
||||
min-height: 44px;
|
||||
flex: 0 0 44px;
|
||||
overflow: hidden;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.v2-ops-tabs > .semi-button {
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.v2-workspace-command-bar {
|
||||
height: 48px;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel > .semi-card-body > .v2-workspace-filter-heading {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel .v2-vehicle-search-form {
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.v2-vehicle-search-page > .v2-workspace-command-bar {
|
||||
width: min(1280px, 100%);
|
||||
}
|
||||
|
||||
.v2-access-page-v3 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.v2-access-page-v3 > .v2-workspace-command-bar,
|
||||
.v2-ops-command-bar {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.v2-access-filter-card-v3 > .semi-card-body {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.v2-access-filter-card-v3 > .semi-card-body > .v2-workspace-filter-heading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 {
|
||||
min-height: 54px;
|
||||
grid-template-columns: minmax(220px, 1.35fr) repeat(3, minmax(128px, .7fr)) auto auto;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 7px 9px;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 > label {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 > label > span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 label > :is(.semi-input-wrapper, .semi-select),
|
||||
.v2-access-filter-v3 > .semi-button {
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
min-height: 38px;
|
||||
align-self: center;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.v2-access-table-v3.semi-card,
|
||||
.v2-access-table-v3 > .semi-card-body {
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.v2-ops-page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.v2-ops-workspace {
|
||||
min-height: 0;
|
||||
flex: 1 1 0;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
@media (max-width: 1120px) and (min-width: 681px) {
|
||||
.v2-access-filter-v3 {
|
||||
grid-template-columns: minmax(200px, 1fr) repeat(3, minmax(110px, .65fr)) auto auto;
|
||||
}
|
||||
|
||||
.v2-access-command-bar .v2-workspace-command-meta {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.v2-access-page-v3 {
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
gap: 7px;
|
||||
overflow: auto;
|
||||
padding: 7px 7px 14px;
|
||||
}
|
||||
|
||||
.v2-access-filter-card-v3 > .semi-card-body > .v2-workspace-filter-heading {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 {
|
||||
min-height: 0;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 > label {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.v2-access-filter-v3 > label > span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.v2-access-workspace-v3 {
|
||||
min-height: 540px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.v2-ops-page {
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
gap: 7px;
|
||||
overflow: auto;
|
||||
padding: 7px 7px 16px;
|
||||
}
|
||||
|
||||
.v2-ops-workspace {
|
||||
min-height: 0;
|
||||
flex: none;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user