feat: sync vehicle monitoring and accumulated platform updates
Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates. Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import './governance-workflows.css';
|
||||
import { IconChevronDown, IconChevronLeft, IconChevronRight, IconClose, IconConnectionPoint1, IconDownload, IconMore, IconRefresh, IconSave, IconSearch, IconSetting, IconTickCircle } from '@douyinfe/semi-icons';
|
||||
import { Button, Card, CardGroup, Collapse, Descriptions, Dropdown, Input, Select, Table, Tag, Typography } from '@douyinfe/semi-ui';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
@@ -12,8 +13,7 @@ import { MobileFilterSheet, MobileFilterSheetSection } from '../shared/MobileFil
|
||||
import { TablePagination } from '../shared/TablePagination';
|
||||
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
||||
import { WorkspaceDetailSideSheet } from '../shared/WorkspaceDetailSideSheet';
|
||||
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
||||
import { WorkspaceMetricRail, type WorkspaceQueueMetricRailItem } from '../shared/WorkspaceMetricRail';
|
||||
import { WorkspaceMetricRail, type WorkspaceQueueMetricRailItem } from './GovernanceStatusStrip';
|
||||
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||
import { WorkspaceSideSheet } from '../shared/WorkspaceSideSheet';
|
||||
import { ProtocolTag } from '../shared/ProtocolTag';
|
||||
@@ -168,9 +168,10 @@ const ProtocolState = memo(function ProtocolState({
|
||||
}
|
||||
return <div className={`v2-access-protocol-cell is-${state}`} title={status?.latestReceivedAt ? `最新上报:${formatAccessTime(status.latestReceivedAt)}` : '当前未发现该协议来源'}>
|
||||
{protocolLabel ? <b className="v2-access-protocol-label">{protocolLabel}</b> : null}
|
||||
<span><i />{label}</span>
|
||||
<strong>{status?.connected ? <AccessTime value={status.latestReceivedAt} compact /> : '—'}</strong>
|
||||
<small>{status?.provider || (status?.connected ? '接入方未维护' : '未发现来源')}</small>
|
||||
{status?.connected ? <>
|
||||
<span className="v2-access-protocol-status-line"><span><i />{label}</span>{status.provider ? <small title={status.provider}>{status.provider}</small> : null}</span>
|
||||
<strong><AccessTime value={status.latestReceivedAt} compact /></strong>
|
||||
</> : <span className="v2-access-protocol-absent">未发现来源</span>}
|
||||
</div>;
|
||||
});
|
||||
|
||||
@@ -185,9 +186,10 @@ function connectionTagColor(state: AccessVehicleRow['connectionState']) {
|
||||
const ConnectionState = memo(function ConnectionState({ row }: { row: AccessVehicleRow }) {
|
||||
const summary = accessIssueSummary(row);
|
||||
return <div className={`v2-access-connection is-${row.connectionState}`}>
|
||||
<ConnectionTag row={row} />
|
||||
<span title={summary}>{summary}</span>
|
||||
<small>{row.actualProtocols.length ? `${row.actualProtocols.length} 个真实来源 · ${row.actualProtocols.join(' / ')}` : '当前没有真实来源证据'}</small>
|
||||
<div className="v2-access-connection-line"><ConnectionTag row={row} /><small>{row.actualProtocols.length} 个来源</small></div>
|
||||
{row.connectionState === 'healthy'
|
||||
? <span title={row.actualProtocols.join(' / ')}>{row.actualProtocols.join(' / ')}</span>
|
||||
: row.connectionState !== 'not_connected' ? <span title={summary}>{summary}</span> : null}
|
||||
</div>;
|
||||
});
|
||||
|
||||
@@ -237,7 +239,7 @@ const AccessVehicleTable = memo(function AccessVehicleTable({ rows, selectedVIN,
|
||||
dataSource={rows}
|
||||
rowKey="vin"
|
||||
pagination={false}
|
||||
empty={null}
|
||||
empty={<></>}
|
||||
onRow={(row) => row ? detailTriggerRow({
|
||||
className: [`is-state-${row.connectionState}`, selectedVIN === row.vin ? 'is-selected' : ''].filter(Boolean).join(' '),
|
||||
expanded: selectedVIN === row.vin,
|
||||
@@ -574,6 +576,10 @@ export default function AccessPage() {
|
||||
tone: 'warning',
|
||||
emphasis: 'primary'
|
||||
}),
|
||||
accessMetric('来源正常', summary?.healthyVehicles ?? 0, 'healthy', { tone: 'success' }),
|
||||
accessMetric('来源异常', summary?.degradedVehicles ?? 0, 'degraded', { tone: 'warning' }),
|
||||
accessMetric('尚无来源', summary?.neverReported ?? 0, 'not_connected', { tone: 'neutral' }),
|
||||
accessMetric('资料待维护', summary?.masterDataIncompleteVehicles ?? 0, 'master_data', { tone: 'neutral' }),
|
||||
accessMetric('全部车辆', summary?.totalVehicles ?? 0, '', {
|
||||
note: mobileLayout ? '权威主车辆' : '权威主车辆口径',
|
||||
tone: 'neutral',
|
||||
@@ -596,7 +602,7 @@ export default function AccessPage() {
|
||||
<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>
|
||||
</>;
|
||||
|
||||
return <div className="v2-access-page v2-access-page-v3">
|
||||
return <div className="v2-access-page v2-access-page-v3 governance-workspace">
|
||||
<div className="v2-access-discovery-shell">
|
||||
<WorkspaceCommandBar
|
||||
className="v2-access-command-bar"
|
||||
@@ -654,16 +660,7 @@ export default function AccessPage() {
|
||||
</MobileFilterSheetSection>
|
||||
</form>
|
||||
</MobileFilterSheet>
|
||||
</div> : <WorkspaceFilterPanel
|
||||
className="v2-access-filter-card-v3"
|
||||
title="接入筛选"
|
||||
description="车辆、接入状态、真实协议与品牌"
|
||||
mobileSummary={activeFilterCount ? `已启用 ${activeFilterCount} 项` : '全部主车辆'}
|
||||
expanded={!filtersCollapsed}
|
||||
status={activeFilterCount ? `${activeFilterCount} 项已启用` : '全部主车辆'}
|
||||
statusColor={activeFilterCount ? 'blue' : 'grey'}
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
>
|
||||
</div> : <section className="governance-query-bar" aria-label="接入筛选">
|
||||
<form className="v2-access-filter-v3" onSubmit={submit}>
|
||||
{filterFields}
|
||||
<div className="v2-access-filter-actions">
|
||||
@@ -671,7 +668,7 @@ export default function AccessPage() {
|
||||
<Button className="v2-secondary-button" theme="light" htmlType="button" onClick={resetFilters}>重置</Button>
|
||||
</div>
|
||||
</form>
|
||||
</WorkspaceFilterPanel>}
|
||||
</section>}
|
||||
</div>
|
||||
{summaryQuery.isError ? <InlineError message={summaryQuery.error instanceof Error ? summaryQuery.error.message : '接入汇总读取失败'} onRetry={() => summaryQuery.refetch()} /> : null}
|
||||
{vehiclesQuery.isError ? <InlineError message={vehiclesQuery.error instanceof Error ? vehiclesQuery.error.message : '接入车辆读取失败'} onRetry={() => vehiclesQuery.refetch()} /> : null}
|
||||
@@ -680,7 +677,7 @@ export default function AccessPage() {
|
||||
<WorkspacePanelHeader
|
||||
tone="primary"
|
||||
title="接入差异清单"
|
||||
description={`当前范围:${scopeLabels[criteria.connectionState] || '全部主车辆'} · 缺席协议仅表示当前未发现`}
|
||||
description={`当前范围:${scopeLabels[criteria.connectionState] || '全部主车辆'}`}
|
||||
actionsClassName="v2-access-table-actions"
|
||||
actions={mobileLayout ? null : <Button theme="light" icon={<IconDownload />} onClick={() => downloadRows(rows)} disabled={!rows.length}>导出当前页</Button>}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user