diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx index 7ca9fa0c..f8b08134 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx @@ -16,7 +16,7 @@ import { formatZhNumber, vehicleOperationStatusLabels } from '../domain/formatte import { protocolDisplayLabel, protocolSourceLabel } from '../domain/protocols'; import { isValidAMapCoordinate } from '../../integrations/amap'; import { FleetMap } from '../map/FleetMap'; -import { InlineError, PageLoading, PanelEmpty } from '../shared/AsyncState'; +import { InlineError, PageLoading, PanelEmpty, PanelLoading } from '../shared/AsyncState'; import { MonitorReturnBar } from '../shared/MonitorReturnBar'; import { PlatformTime } from '../shared/PlatformTime'; import { ProtocolTag } from '../shared/ProtocolTag'; @@ -280,7 +280,7 @@ function TelemetryPanel({ data, pending, error }: { data?: LatestTelemetryRespon { title: '数据来源', dataIndex: 'protocol', width: 180, render: (_: unknown, item: LatestTelemetryValue) => } ], []); const state = pending - ?
正在读取最新遥测按协议整理最新标量证据…
+ ? : error ?
最新遥测不可用{error}
: visibleMetrics.length === 0 diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx index 73d801ef..02ba91e5 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx @@ -10,7 +10,7 @@ import { canAdminister } from '../auth/session'; import { formatZhNumber } from '../domain/formatters'; import { useMobileLayout } from '../hooks/useMobileLayout'; import { QUERY_MEMORY, queryScopeKey, retainPreviousPageWithinScope } from '../queryPolicy'; -import { PanelEmpty } from '../shared/AsyncState'; +import { PanelEmpty, PanelLoading } from '../shared/AsyncState'; import { MobileFilterToggle } from '../shared/MobileFilterToggle'; import { MobileFilterSheet, MobileFilterSheetSection } from '../shared/MobileFilterSheet'; import { ProtocolTag } from '../shared/ProtocolTag'; @@ -328,7 +328,7 @@ export default function VehicleSearchWorkspace() { } /> {candidates.isFetching && !candidates.data - ?
正在读取授权车辆…
+ ? : candidates.isError ?
{candidates.error instanceof Error ? candidates.error.message : '授权车辆加载失败'}
: pageVehicles.length @@ -418,6 +418,6 @@ export default function VehicleSearchWorkspace() { />} {total > 0 ?
{ setPage(next); setCandidatesOpen(false); }} />
: null} - {syncOpen ? 正在加载主档同步工具…}> setSyncOpen(false)} /> : null} + {syncOpen ? }> setSyncOpen(false)} /> : null} ; } diff --git a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts index 95cdeaed..a67b80a9 100644 --- a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts +++ b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts @@ -110,6 +110,7 @@ describe('V2 production entry', () => { expect(corePageSources.VehiclePage).toContain(' { expect(corePageSources.VehiclePage).not.toContain(' import('./VehicleProfileSyncPanel'))"); + expect(vehicleSearchSource).toContain(' { expect(corePageSources.MonitorPage).toContain('车辆'); - expect(sourceEvidenceSource).toContain("import { Button, Card, Input, Spin, Tag } from '@douyinfe/semi-ui'"); + expect(sourceEvidenceSource).toContain("import { Button, Card, Input, Tag } from '@douyinfe/semi-ui'"); expect(sourceEvidenceSource).toContain(' { vi.mocked(useMobileLayout).mockReturnValue(false); }); -test('loads all source evidence only after the user expands it', async () => { +test('loads all source evidence in a Semi right SideSheet without reflowing the desktop record', async () => { const sourceEvidence = vi.spyOn(api, 'vehicleSourceEvidence').mockResolvedValue(evidence); const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); @@ -57,10 +57,16 @@ test('loads all source evidence only after the user expands it', async () => { fireEvent.click(screen.getByRole('button', { name: '查看全部来源' })); await waitFor(() => expect(sourceEvidence).toHaveBeenCalledTimes(1)); expect(await screen.findByText('北斗平台')).toBeInTheDocument(); - expect(view.container.querySelectorAll('.v2-source-evidence-card.semi-card')).toHaveLength(3); + expect(view.container.querySelector('.v2-source-evidence > .semi-card-body > .v2-source-evidence-body')).not.toBeInTheDocument(); + expect(document.querySelector('.v2-source-evidence-sidesheet')).toHaveClass('v2-workspace-detail-sidesheet'); + expect(document.querySelector('.v2-source-evidence-sidesheet .semi-sidesheet-inner')).toHaveStyle({ width: 'min(680px, calc(100vw - 24px))' }); + expect(document.querySelectorAll('.v2-source-evidence-sidesheet .v2-source-evidence-card.semi-card')).toHaveLength(3); expect(screen.getAllByText('当前推荐').every((item) => item.closest('.semi-tag'))).toBe(true); expect(screen.getAllByText('当前推荐').length).toBeGreaterThan(0); expect(screen.queryByText('13307795425')).not.toBeInTheDocument(); + + fireEvent.click(screen.getByRole('button', { name: '关闭来源证据' })); + await waitFor(() => expect(view.container.querySelector('.v2-source-evidence')).not.toHaveClass('is-open')); client.clear(); }); diff --git a/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx b/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx index e2fce3df..6e5b8954 100644 --- a/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx +++ b/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx @@ -1,13 +1,13 @@ import { useQuery } from '@tanstack/react-query'; import { IconSearch } from '@douyinfe/semi-icons'; -import { Button, Card, Input, Spin, Tag } from '@douyinfe/semi-ui'; +import { Button, Card, Input, Tag } from '@douyinfe/semi-ui'; import { useMemo, useState } from 'react'; import { api } from '../../api/client'; import type { VehicleLocationSourceEvidence, VehicleMileageSourceEvidence } from '../../api/types'; import { protocolDisplayLabel, protocolSourceLabel } from '../domain/protocols'; import { useMobileLayout } from '../hooks/useMobileLayout'; import { QUERY_MEMORY } from '../queryPolicy'; -import { PanelEmpty } from './AsyncState'; +import { PanelEmpty, PanelLoading } from './AsyncState'; import { WorkspaceDetailSideSheet } from './WorkspaceDetailSideSheet'; function today() { @@ -117,7 +117,7 @@ export function VehicleSourceEvidencePanel({ 终端已脱敏;推荐结果来自后台选举,不改动原始证据。 - {query.isPending ?
正在读取全部来源证据…
: null} + {query.isPending ? : null} {query.isError ?
{query.error instanceof Error ? query.error.message : '来源证据读取失败'}
: null} {query.data ? <>
@@ -138,13 +138,13 @@ export function VehicleSourceEvidencePanel({
位置与里程来源{description}
- {expanded && !mobileLayout ? evidenceBody : null} - {mobileLayout ? setExpanded(false)} >
{evidenceBody}
-
: null} + ; } diff --git a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css index 8b658e38..8e585c06 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -18338,6 +18338,58 @@ flex: none; } +@media (min-width: 681px) { + .v2-source-evidence-sidesheet .semi-sidesheet-inner { + border-radius: 16px 0 0 16px; + box-shadow: -18px 0 48px rgba(25, 45, 72, .18); + } + + .v2-source-evidence-sidesheet .semi-sidesheet-header { + min-height: 76px; + padding: 13px 18px; + } + + .v2-source-evidence-sidesheet .v2-source-evidence-sheet-body > .v2-source-evidence-body { + padding: 14px 14px 28px; + } + + .v2-source-evidence-sidesheet .v2-source-evidence-toolbar { + margin: -14px -14px 14px; + padding: 12px 16px; + } + + .v2-source-evidence-sidesheet .v2-source-evidence-group > div { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; + } +} + +.v2-source-evidence-sidesheet .v2-source-evidence-loading.v2-state-surface { + min-height: 190px; + margin-top: 10px; + border-color: #d9e3ee; + background: #fff; +} + +.v2-vehicle-directory-v3 .v2-vehicle-directory-loading.v2-state-surface { + min-height: 220px; + flex: 1 1 auto; + margin: 10px; +} + +.v2-vehicle-record-v3 .v2-telemetry-loading.v2-state-surface { + min-height: 190px; + margin: 10px; + border-color: #dce5ef; + background: #fbfdff; +} + +.v2-profile-sync-loading .v2-state-surface { + min-height: 180px; + border: 0; + box-shadow: none; +} + .v2-vehicle-record-v3.v2-vehicle-record-page { display: flex; width: 100%;