import assert from 'node:assert/strict'; import test from 'node:test'; import type { MonitoringVehicle } from '../types'; import { defaultMileageDate, getRangePreset, normalizeRangeLabel } from './date-range'; import { formatAbsoluteTime, parseOneOsTime, vehicleStatisticTime } from './oneos-time'; import { buildExportMonitoringQuery, buildFullscreenMonitoringQuery, buildInitialMonitoringQuery, buildNextPageMonitoringQuery, type MonitoringQueryModel, } from './query-model'; import { vehicleSourceDisplay } from './source-display'; const baseVehicle: MonitoringVehicle = { plate: '粤A00001', vin: 'TESTVIN', dailyKm: 0, totalKm: 0, source: 'ONEOS', sourceProtocol: null, sourceCategory: null, dataTime: null, calculatedAt: null, updatedAt: null, isOnline: false, isDataSynced: false, customer: null, department: null, manager: null, rentStatus: null, entity: null, project: null, region: null, inventoryLocation: null, brand: null, targetNames: [], }; const queryModel: MonitoringQueryModel = { sortBy: 'statisticTime', sortOrder: 'asc', searchTerm: '粤A', department: '业务一部', customer: '客户甲', project: '项目甲', entity: '主体甲', rentStatus: '租赁', platePrefix: '粤A', targetNames: ['批次甲'], region: '广州', plates: ['粤A00001', '粤A00002'], mileageRange: { min: '10', max: '500' }, rangeStart: '2026-08-01', rangeEnd: '2026-08-12', brands: ['现代'], sourcePriority: ['instrument', 'gps'], }; test('monitoring date rolls over at 05:00 and presets retain existing ranges', () => { assert.equal(defaultMileageDate(new Date(2026, 7, 13, 4, 59)), '2026-08-12'); assert.equal(defaultMileageDate(new Date(2026, 7, 13, 5, 0)), '2026-08-13'); const now = new Date(2026, 7, 13, 12, 0); assert.deepEqual(getRangePreset('today', now), { start: '2026-08-13', end: '2026-08-13' }); assert.deepEqual(getRangePreset('yesterday', now), { start: '2026-08-12', end: '2026-08-12' }); assert.deepEqual(getRangePreset('thisWeek', now), { start: '2026-08-10', end: '2026-08-13' }); assert.deepEqual(getRangePreset('thisMonth', now), { start: '2026-08-01', end: '2026-08-13' }); assert.deepEqual(getRangePreset('last7', now), { start: '2026-08-07', end: '2026-08-13' }); assert.deepEqual(getRangePreset('last15', now), { start: '2026-07-30', end: '2026-08-13' }); assert.equal(normalizeRangeLabel('', ''), '最新数据'); assert.equal(normalizeRangeLabel('2026-08-12', '2026-08-12'), '2026-08-12'); assert.equal(normalizeRangeLabel('2026-08-01', '2026-08-12'), '2026-08-01 至 2026-08-12'); }); test('OneOS timestamps keep China Standard Time parsing and relative labels', () => { assert.equal( parseOneOsTime('2026-08-13 09:30:05'), Date.parse('2026-08-13T09:30:05+08:00'), ); assert.equal(parseOneOsTime('invalid'), null); assert.equal(formatAbsoluteTime('2026-08-13 09:30:05'), '2026/08/13 09:30:05'); const display = vehicleStatisticTime( { ...baseVehicle, dataTime: '2026-08-13 09:30:05', calculatedAt: '2026-08-13 09:30:06', updatedAt: '2026-08-13 09:30:07', isDataSynced: true, }, Date.parse('2026-08-13T09:31:05+08:00'), ); assert.deepEqual(display, { label: '1分钟前', title: [ '数据时间:2026/08/13 09:30:05', '计算时间:2026/08/13 09:30:06', '更新时间:2026/08/13 09:30:07', ].join('\n'), color: 'text-emerald-500', }); assert.deepEqual(vehicleStatisticTime({ ...baseVehicle, isDataSynced: true }, Date.now()), { label: '统计时间待接口', title: 'OneOS 当前未返回车辆级数据时间', color: 'text-amber-500', }); }); test('vehicle source display retains all source and missing-data states', () => { assert.deepEqual(vehicleSourceDisplay({ ...baseVehicle, sourceCategory: 'INSTRUMENT', sourceProtocol: 'MQTT', }), { label: '仪表数据', title: 'MQTT', className: 'bg-violet-50 text-violet-600', }); assert.equal(vehicleSourceDisplay({ ...baseVehicle, sourceCategory: 'GPS' }).title, 'JT808'); assert.equal(vehicleSourceDisplay({ ...baseVehicle, sourceCategory: 'MIXED' }).label, '仪表+GPS'); assert.equal(vehicleSourceDisplay({ ...baseVehicle, isDataSynced: true }).label, '来源待接口'); assert.equal(vehicleSourceDisplay(baseVehicle).label, '无数据'); }); test('four monitoring query builders preserve pagination and fullscreen differences', () => { const initial = buildInitialMonitoringQuery(queryModel, 50); assert.equal(initial.limit, 50); assert.equal(initial.page, 1); assert.equal(initial.project, '项目甲'); assert.equal(initial.entity, '主体甲'); assert.equal(initial.mileageMin, '10'); assert.equal(initial.mileageMax, '500'); assert.equal(initial.plate, '粤A00001,粤A00002'); const nextPage = buildNextPageMonitoringQuery(queryModel, 50, 3); assert.deepEqual(nextPage, { ...initial, page: 3 }); const exported = buildExportMonitoringQuery(queryModel); assert.deepEqual(exported, { ...initial, limit: 9999 }); const fullscreen = buildFullscreenMonitoringQuery(queryModel); assert.equal(fullscreen.limit, 9999); assert.equal(fullscreen.page, 1); assert.equal(fullscreen.customer, '客户甲'); assert.equal('project' in fullscreen, false); assert.equal('entity' in fullscreen, false); assert.equal('mileageMin' in fullscreen, false); assert.equal('mileageMax' in fullscreen, false); }); test('query model converts empty selections exactly as the existing requests do', () => { const query = buildInitialMonitoringQuery({ ...queryModel, searchTerm: '', department: 'All', customer: 'All', project: 'All', entity: 'All', rentStatus: 'All', platePrefix: 'All', targetNames: [], region: 'All', plates: [], mileageRange: { min: '', max: '' }, rangeStart: '', rangeEnd: '', brands: [], }, 50); assert.equal(query.search, undefined); assert.equal(query.dept, undefined); assert.equal(query.project, undefined); assert.equal(query.plate, undefined); assert.equal(query.mileageMin, undefined); assert.equal(query.startDate, undefined); assert.equal(query.brands, undefined); assert.deepEqual(query.sourcePriority, ['instrument', 'gps']); });