import test from 'node:test' import assert from 'node:assert/strict' import { HOME_QUICK_ENTRIES, buildHomeWorkOrderQuery, normalizeFacilityTotal, normalizeHomeKpis, normalizeWorkOrderStatusStat, normalizeAlarmOverviewCards, normalizeAlarmTrend, normalizePieRatio, normalizeRealtimeAlarmRows, realtimeAlarmJumpTarget, normalizeAbnormalTodoRows, normalizeDeviceSummary, normalizeWorkOrderRows, buildHomeGisOverview } from '../src/utils/waterHomeModel.js' test('home work order scope is constrained to the water-supply type tree', () => { assert.deepEqual(buildHomeWorkOrderQuery(), { deviceTypeParentId: '1', pageNum: 1, pageSize: 5 }) assert.deepEqual(buildHomeWorkOrderQuery({ pageSize: 8 }), { deviceTypeParentId: '1', pageNum: 1, pageSize: 8 }) }) test('facility total excludes the aggregated total row', () => { const rows = [ { facilityType: 'source', totalCount: 3 }, { facilityType: 'plant', totalCount: 2 }, { facilityType: 'pipe', totalCount: 996 }, { facilityType: 'total', totalCount: 1000 } ] assert.equal(normalizeFacilityTotal(rows), 1001) assert.equal(normalizeFacilityTotal(null), 0) assert.equal(normalizeFacilityTotal([]), 0) }) test('home KPIs map api payloads to workbench cards', () => { const kpis = normalizeHomeKpis({ facilityRows: [{ facilityType: 'pipe', totalCount: 996 }, { facilityType: 'total', totalCount: 1000 }], ledgerStats: { total: 15, online: 13 }, alarmStats: { realtimeAlarmCount: 3 } }) assert.deepEqual(kpis, [ { key: 'facility', label: '设施总数', value: 996, unit: '处', tone: 'primary' }, { key: 'device', label: '监测设备', value: 15, unit: '台', tone: 'primary' }, { key: 'online', label: '在线设备', value: 13, unit: '台', tone: 'primary' }, { key: 'alarm', label: '实时报警', value: 3, unit: '条', tone: 'danger' } ]) }) test('home KPIs keep realtime alarm card neutral when no alarm is active', () => { const alarm = normalizeHomeKpis({ alarmStats: { realtimeAlarmCount: 0 } }).find(item => item.key === 'alarm') assert.equal(alarm.tone, 'primary') }) test('work order status statistic groups by authoritative status contract', () => { const stat = normalizeWorkOrderStatusStat({ total: 10, counts: [ { status: 0, count: 2 }, { status: 1, count: 1 }, { status: 3, count: 2 }, { status: 4, count: 2 }, { status: 5, count: 2 }, { status: 7, count: 1 } ] }) assert.equal(stat.total, 10) assert.equal(stat.pendingCount, 3) assert.equal(stat.processingCount, 2) assert.equal(stat.verifyingCount, 2) assert.equal(stat.finishedCount, 3) assert.equal(stat.byStatus.find(item => item.status === 6).count, 0) }) test('alarm overview cards derive online rate and verifying orders', () => { const cards = normalizeAlarmOverviewCards({ dashboard: { totalCount: 16, alarmingDeviceCount: 4 }, deviceStats: { onlineRate: 86.666666 }, workOrderStat: { counts: [{ status: 4, count: 3 }] } }) assert.deepEqual(cards, [ { key: 'alarmTotal', label: '报警总数', value: 16, unit: '条', tone: 'primary' }, { key: 'alarmingDevice', label: '报警中设备', value: 4, unit: '台', tone: 'danger' }, { key: 'verifyingOrder', label: '待验收工单', value: 3, unit: '单', tone: 'warning' }, { key: 'onlineRate', label: '在线率', value: 86.7, unit: '%', tone: 'primary' } ]) }) test('alarm trend returns four level series with zero-filled missing days', () => { const trend = normalizeAlarmTrend([ { date: '2026-09-15', level1Count: 1, level2Count: 2 }, { date: '2026-09-16' } ]) assert.deepEqual(trend.dates, ['2026-09-15', '2026-09-16']) assert.equal(trend.levels.length, 4) const level2 = trend.levels.find(item => item.name === '级2') assert.deepEqual(level2.data, [2, 0]) assert.equal(normalizeAlarmTrend(null).levels.length, 4) }) test('ratio pie drops empty values and caps the number of segments', () => { const items = [ { name: ' ' }, { name: '压力', count: '8' }, { name: '流量', count: '5' }, { name: '离线', count: '3' }, { name: '低', count: 0 } ] assert.deepEqual(normalizePieRatio(items, '未分类', 3), [ { name: '压力', count: 8 }, { name: '流量', count: 5 }, { name: '离线', count: 3 } ]) assert.deepEqual(normalizePieRatio(undefined, '未分类'), []) }) test('realtime alarm rows expose chinese friendly display fields', () => { const rows = normalizeRealtimeAlarmRows([ { id: 'a1', deviceCode: 'CN-GS-202609020001', deviceName: '一号压力点', warningType: '压力过低', alarmLevel: 1, alarmTime: '2026-09-15 10:00:00', equipmentLocation: '城南', displayStatus: 1 } ]) assert.equal(rows.length, 1) assert.equal(rows[0].deviceName, '一号压力点') assert.equal(rows[0].alarmLevelText, '一级报警') assert.equal(rows[0].location, '城南') assert.equal(rows[0].displayStatusText, '待审核') assert.equal(rows[0].displayStatusType, 'warning') assert.equal(normalizeRealtimeAlarmRows([], 5).length, 0) }) test('realtime alarm rows drop released alarms and keep status for routing', () => { const rows = normalizeRealtimeAlarmRows([ { id: 'a-pending', deviceCode: 'CN-GS-202609020001', displayStatus: 1, alarmTime: '2026-09-15 10:00:00' }, { id: 'a-order', deviceCode: 'CN-GS-202609020002', displayStatus: 2, orderNo: 'WO202609151100001', alarmTime: '2026-09-15 09:00:00' }, { id: 'a-released', deviceCode: 'CN-GS-202609020003', displayStatus: 3, alarmTime: '2026-09-15 08:00:00' } ], 5) assert.deepEqual(rows.map(item => item.id), ['a-pending', 'a-order']) assert.equal(rows.find(item => item.id === 'a-order').displayStatusText, '已转工单') assert.equal(rows.find(item => item.id === 'a-order').orderNo, 'WO202609151100001') assert.equal(rows.find(item => item.id === 'a-pending').displayStatusType, 'warning') }) test('realtime alarm jumps split between audit and work order by display status', () => { assert.deepEqual(realtimeAlarmJumpTarget({ id: 'alarm-1', deviceCode: 'CN-GS-202609020001', displayStatus: 1 }), { path: '/monitorAlarm/audit', query: { alarmId: 'alarm-1', deviceCode: 'CN-GS-202609020001' } }) assert.deepEqual(realtimeAlarmJumpTarget({ id: 'alarm-2', deviceCode: 'CN-GS-202609020002', displayStatus: 2, orderNo: 'WO202609151100001' }), { path: '/device/maintain', query: { keyword: 'WO202609151100001' } }) // 已转工单但缺少工单号时回落到报警审核,避免无效跳转 const fallback = realtimeAlarmJumpTarget({ id: 'alarm-3', displayStatus: 2 }) assert.equal(fallback.path, '/monitorAlarm/audit') }) test('abnormal todo rows reuse the shared device normalization contract', () => { const rows = normalizeAbnormalTodoRows([{ equipmentId: 'eq-1', equipmentCode: 'CN-GS-202609020002', equipmentName: '二号流量点', alarmStatus: 1, onlineStatus: 1, currentStatus: 1, alertLevel: 2, relatedWorkOrderNo: 'WO202609150001', relatedWorkOrderStatus: 3 }], 1) assert.equal(rows.length, 1) assert.equal(rows[0].alarmStatusText, '报警') assert.equal(rows[0].onlineStatusText, '在线') assert.equal(rows[0].alarmLevelText, '二级报警') assert.equal(rows[0].relatedOrderNo, 'WO202609150001') assert.equal(rows[0].workOrderStatusText, '处理中') }) test('device summary keeps key text fields for the workbench detail panel', () => { const summary = normalizeDeviceSummary({ equipmentId: 'eq-9', equipmentCode: 'CB-GS-202609020003', equipmentName: '三号漏失点', equipmentLocation: '城北', district: '城北', alarmStatus: 0, onlineStatus: 0, currentStatus: 3, equipmentTypeName: '漏失在线监测仪' }) assert.equal(summary.name, '三号漏失点') assert.equal(summary.alarmStatusText, '正常') assert.equal(summary.onlineStatusText, '离线') assert.equal(summary.currentStatusText, '维修') assert.equal(summary.abnormalReasonText, '设备维修中') assert.equal(summary.typeName, '漏失在线监测仪') }) test('work order rows translate status and level codes to chinese', () => { const rows = normalizeWorkOrderRows([ { orderId: 5, orderNo: 'WO202609150001', orderStatus: 4, orderLevel: 0, deviceCode: 'CN-GS-202609020001', createTime: '2026-09-15 10:00:00' } ], 5) assert.equal(rows[0].orderStatusText, '待验收') assert.equal(rows[0].orderStatusType, 'primary') assert.equal(rows[0].orderLevelText, '紧急') assert.equal(rows[0].orderLevelType, 'danger') }) test('home GIS overview aggregates facilities, devices and alarms with alarm priority', () => { const overview = buildHomeGisOverview({ facilityPoints: [ { id: 'f-1', type: 'source', name: '一水源地', code: 'S-001', lng: 110.08, lat: 28.05 } ], facilityLines: [ { id: 'pipe-1', name: '城南主管', type: 'pipe', points: [{ lng: 110.1, lat: 28.1 }, { lng: 110.2, lat: 28.2 }] } ], devicePoints: [ { equipmentId: 'eq-1', equipmentCode: 'CN-GS-202609020001', equipmentName: '一号压力点', longitude: 110.1, latitude: 28.1, alarmStatus: 0, onlineStatus: 1, currentStatus: 0, equipmentTypeName: '压力计' } ], alarmPoints: [ { alarmId: 'alarm-1', deviceCode: 'CN-GS-202609020001', deviceName: '一号压力点', longitude: 110.1, latitude: 28.1, warningType: '压力过低', alarmLevel: 1 } ] }) assert.equal(overview.lines.length, 1) assert.equal(overview.lines[0].color, '#f1c40f') assert.equal(overview.lines[0].points.length, 2) assert.ok(overview.points.some(point => point.id === 'f-1' && point.statusKey === 'normal')) const device = overview.points.find(point => point.code === 'CN-GS-202609020001') assert.ok(device) assert.equal(device.statusKey, 'alarm') assert.equal(device.meta, '压力过低') assert.ok(overview.points.every(point => Number.isFinite(point.lng) && Number.isFinite(point.lat) && point.name && point.iconUrl)) const empty = buildHomeGisOverview({}) assert.deepEqual(empty, { points: [], lines: [] }) }) test('home quick entries cover the four workbench jumps', () => { assert.deepEqual(HOME_QUICK_ENTRIES.map(item => item.label), ['设备异常管理', '报警管理', '报警审核', '监测报警一张图']) assert.ok(HOME_QUICK_ENTRIES.every(item => item.suffix.startsWith('/'))) })