删除偏移的全局结果查询入口
移除结果查询菜单、路由、页面及专用请求模型,保留测试控制台数据列表入口,并补充刷新、鉴权和未知路由的浏览器合同测试。
| | |
| | | "test:e2e:ticket10": "playwright test tests/e2e/pause-resume-reception.spec.ts", |
| | | "test:e2e:ticket11": "playwright test tests/e2e/collector-disconnect-recovery.spec.ts", |
| | | "test:e2e:ticket12": "playwright test tests/e2e/manual-end-sequential-join.spec.ts", |
| | | "test:e2e:ticket20": "playwright test tests/e2e/remove-drifted-result-query.spec.ts", |
| | | "test:contract:ticket09": "node tests/test-console-live.contract.test.mjs" |
| | | }, |
| | | "dependencies": { |
| | |
| | | interface TestOptionsResponse extends ApiResponse { data: TestConfigurationOptions } |
| | | export interface TestListResult { total: number; rows: TestRecord[] } |
| | | |
| | | export interface HistoricalResultRecord { |
| | | resultId: number |
| | | sourceType: 'CABINET_CHANNEL' | 'COLLECTOR_CHANNEL' | string |
| | | testId: number |
| | | testName: string |
| | | testStatus: TestStatusCode |
| | | receptionStatus: ReceptionStatusCode |
| | | relationId: number |
| | | batteryNo: string |
| | | sourceId: number |
| | | sourceIdentity: string |
| | | intervalId: number |
| | | intervalStartAtUtc: string |
| | | intervalEndAtUtc: string | null |
| | | cycleNo: number | null |
| | | stepNo: number | null |
| | | stepType: string | null |
| | | workStatus: string | null |
| | | voltageV: number | null |
| | | currentA: number | null |
| | | capacityAh: number | null |
| | | energyWh: number | null |
| | | metricCode: string | null |
| | | metricValue: number | null |
| | | unit: string |
| | | unitMetadata: string |
| | | integrityConclusion: string |
| | | deviceTimeUtc: string |
| | | deviceTimeRaw: string |
| | | serverReceivedAtUtc: string |
| | | } |
| | | interface HistoricalResultResponse extends ApiResponse { total: number; rows: HistoricalResultRecord[] } |
| | | |
| | | export interface HistoricalResultQuery { |
| | | pageNum: number |
| | | pageSize: number |
| | | testId?: number |
| | | testName?: string |
| | | batteryNo?: string |
| | | sourceType?: string |
| | | sourceId?: number |
| | | sourceChannelCode?: string |
| | | beginDeviceTime?: string |
| | | endDeviceTime?: string |
| | | cycleNo?: number |
| | | stepNo?: number |
| | | } |
| | | |
| | | export async function getHistoricalResultRecords(query: HistoricalResultQuery): Promise<{ total: number; rows: HistoricalResultRecord[] }> { |
| | | const params = new URLSearchParams() |
| | | Object.entries(query).forEach(([key, value]) => { |
| | | if (value !== undefined && value !== '' && value !== null) params.set(key, String(value)) |
| | | }) |
| | | const result = await request<HistoricalResultResponse>(`/system/test/results?${params.toString()}`) |
| | | return { total: Number(result.total) || 0, rows: result.rows || [] } |
| | | } |
| | | |
| | | const statusMap: Record<TestStatusCode, TestStatus> = { |
| | | WAITING: '待测试', RUNNING: '检测中', PAUSED: '暂停', RUNNING_ABNORMAL: '检测中(异常)', |
| | | COMPLETION_PENDING: '完成确认中', COMPLETED: '检测完成', TERMINATED: '已终止', |
| | |
| | | const menuGroups = [ |
| | | { title: '首页', icon: 'HomeFilled', path: '/dashboard' }, |
| | | { title: '测试管理', icon: 'Document', children: [ |
| | | { path: '/test-list', title: '测试列表' }, { path: '/result-query', title: '结果查询' }, { path: '/battery-group', title: '电池组管理' }, |
| | | { path: '/test-list', title: '测试列表' }, { path: '/battery-group', title: '电池组管理' }, |
| | | { path: '/test-type', title: '测试类型管理' }, { path: '/data-revision', title: '数据修订记录' }, |
| | | { path: '/exception', title: '异常管理' }, |
| | | ]}, |
| | |
| | | meta: { title: '测试列表' }, |
| | | }, |
| | | { |
| | | path: 'result-query', |
| | | name: 'result-query', |
| | | component: () => import('@/views/ResultQuery.vue'), |
| | | meta: { title: '结果查询' }, |
| | | }, |
| | | { |
| | | path: 'test-list/new', |
| | | name: 'test-create', |
| | | component: () => import('@/views/TestCreate.vue'), |
| New file |
| | |
| | | import { expect, test } from '@playwright/test' |
| | | |
| | | test('已删除的结果查询路径和未知路径统一回到工作台', async ({ page }) => { |
| | | await page.addInitScript(() => localStorage.setItem('battery_detection_auth_token', 'ticket20-test-token')) |
| | | |
| | | await page.goto('/result-query') |
| | | await expect(page).toHaveURL(/\/dashboard$/) |
| | | await expect(page.getByRole('button', { name: '结果查询', exact: true })).toHaveCount(0) |
| | | |
| | | await page.reload() |
| | | await expect(page).toHaveURL(/\/dashboard$/) |
| | | |
| | | await page.goto('/not-a-real-page') |
| | | await expect(page).toHaveURL(/\/dashboard$/) |
| | | }) |
| | | |
| | | test('未登录访问已删除路径不会保留返回结果查询的目标', async ({ page }) => { |
| | | await page.goto('/result-query') |
| | | |
| | | await expect(page).toHaveURL(/\/login(?:\?|$)/) |
| | | const redirect = new URL(page.url()).searchParams.get('redirect') |
| | | expect(redirect).not.toBe('/result-query') |
| | | }) |
| | | |
| | | test('测试列表仍可进入控制台数据列表', async ({ page }) => { |
| | | await page.addInitScript(() => localStorage.setItem('battery_detection_auth_token', 'ticket20-test-token')) |
| | | await page.route('**/system/test/list**', route => route.fulfill({ |
| | | status: 200, |
| | | contentType: 'application/json', |
| | | body: JSON.stringify({ |
| | | code: 200, |
| | | total: 1, |
| | | rows: [{ |
| | | testId: 77, |
| | | testName: 'Ticket20 控制台入口测试', |
| | | testTypeName: '循环测试', |
| | | principalName: '测试负责人', |
| | | testPurpose: '验证数据列表入口', |
| | | testStatus: 'COMPLETED', |
| | | receptionStatus: 'ENDED', |
| | | batteryNo: 'B-01', |
| | | createTime: '2026-08-31 09:00:00', |
| | | startedAtUtc: '2026-08-31T01:00:00Z', |
| | | endedAtUtc: '2026-08-31T02:00:00Z', |
| | | remark: '', |
| | | batteryCount: 1, |
| | | }], |
| | | }), |
| | | })) |
| | | await page.route('**/system/test/77/live-state', route => route.fulfill({ |
| | | status: 200, |
| | | contentType: 'application/json', |
| | | body: JSON.stringify({ code: 200, data: { testId: 77, testStatus: 'COMPLETED', receptionStatus: 'ENDED', sources: [], exceptions: [], integrityIssues: [] } }), |
| | | })) |
| | | await page.route('**/system/test/77/live', route => route.fulfill({ |
| | | status: 200, |
| | | contentType: 'text/event-stream', |
| | | body: 'event: heartbeat\ndata: {"at":"2026-08-31T02:00:00Z"}\n\n', |
| | | })) |
| | | await page.route('**/system/test/77', route => route.fulfill({ |
| | | status: 200, |
| | | contentType: 'application/json', |
| | | body: JSON.stringify({ |
| | | code: 200, |
| | | data: { |
| | | testId: 77, |
| | | testName: 'Ticket20 控制台入口测试', |
| | | testStatus: 'COMPLETED', |
| | | receptionStatus: 'ENDED', |
| | | batteries: [], |
| | | planSteps: [], |
| | | thresholds: [], |
| | | fieldSnapshots: [], |
| | | }, |
| | | }), |
| | | })) |
| | | |
| | | await page.goto('/test-list') |
| | | const row = page.locator('tbody tr').filter({ hasText: 'Ticket20 控制台入口测试' }) |
| | | await row.getByRole('button', { name: '控制台', exact: true }).click() |
| | | await expect(page).toHaveURL(/\/test-list\/77\/console$/) |
| | | |
| | | await page.getByRole('button', { name: '数据列表', exact: true }).click() |
| | | await expect(page.getByText('查询表格', { exact: true })).toBeVisible() |
| | | await expect(page.getByRole('button', { name: '结果查询', exact: true })).toHaveCount(0) |
| | | }) |