waterHomeModel.test.mjs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import test from 'node:test'
  2. import assert from 'node:assert/strict'
  3. import {
  4. HOME_QUICK_ENTRIES,
  5. buildHomeWorkOrderQuery,
  6. normalizeFacilityTotal,
  7. normalizeHomeKpis,
  8. normalizeWorkOrderStatusStat,
  9. normalizeAlarmOverviewCards,
  10. normalizeAlarmTrend,
  11. normalizePieRatio,
  12. normalizeRealtimeAlarmRows,
  13. normalizeAbnormalTodoRows,
  14. normalizeDeviceSummary,
  15. normalizeWorkOrderRows,
  16. buildOverviewMapPoints
  17. } from '../src/utils/waterHomeModel.js'
  18. test('home work order scope is constrained to the water-supply type tree', () => {
  19. assert.deepEqual(buildHomeWorkOrderQuery(), {
  20. deviceTypeParentId: '1',
  21. pageNum: 1,
  22. pageSize: 5
  23. })
  24. assert.deepEqual(buildHomeWorkOrderQuery({ pageSize: 8 }), {
  25. deviceTypeParentId: '1',
  26. pageNum: 1,
  27. pageSize: 8
  28. })
  29. })
  30. test('facility total excludes the aggregated total row', () => {
  31. const rows = [
  32. { facilityType: 'source', totalCount: 3 },
  33. { facilityType: 'plant', totalCount: 2 },
  34. { facilityType: 'pipe', totalCount: 996 },
  35. { facilityType: 'total', totalCount: 1000 }
  36. ]
  37. assert.equal(normalizeFacilityTotal(rows), 1001)
  38. assert.equal(normalizeFacilityTotal(null), 0)
  39. assert.equal(normalizeFacilityTotal([]), 0)
  40. })
  41. test('home KPIs map api payloads to workbench cards', () => {
  42. const kpis = normalizeHomeKpis({
  43. facilityRows: [{ facilityType: 'pipe', totalCount: 996 }, { facilityType: 'total', totalCount: 1000 }],
  44. ledgerStats: { total: 15, online: 13 },
  45. alarmStats: { realtimeAlarmCount: 3 }
  46. })
  47. assert.deepEqual(kpis, [
  48. { key: 'facility', label: '设施总数', value: 996, unit: '处', tone: 'primary' },
  49. { key: 'device', label: '监测设备', value: 15, unit: '台', tone: 'primary' },
  50. { key: 'online', label: '在线设备', value: 13, unit: '台', tone: 'primary' },
  51. { key: 'alarm', label: '实时报警', value: 3, unit: '条', tone: 'danger' }
  52. ])
  53. })
  54. test('home KPIs keep realtime alarm card neutral when no alarm is active', () => {
  55. const alarm = normalizeHomeKpis({ alarmStats: { realtimeAlarmCount: 0 } }).find(item => item.key === 'alarm')
  56. assert.equal(alarm.tone, 'primary')
  57. })
  58. test('work order status statistic groups by authoritative status contract', () => {
  59. const stat = normalizeWorkOrderStatusStat({
  60. total: 10,
  61. counts: [
  62. { status: 0, count: 2 },
  63. { status: 1, count: 1 },
  64. { status: 3, count: 2 },
  65. { status: 4, count: 2 },
  66. { status: 5, count: 2 },
  67. { status: 7, count: 1 }
  68. ]
  69. })
  70. assert.equal(stat.total, 10)
  71. assert.equal(stat.pendingCount, 3)
  72. assert.equal(stat.processingCount, 2)
  73. assert.equal(stat.verifyingCount, 2)
  74. assert.equal(stat.finishedCount, 3)
  75. assert.equal(stat.byStatus.find(item => item.status === 6).count, 0)
  76. })
  77. test('alarm overview cards derive online rate and verifying orders', () => {
  78. const cards = normalizeAlarmOverviewCards({
  79. dashboard: { totalCount: 16, alarmingDeviceCount: 4 },
  80. deviceStats: { onlineRate: 86.666666 },
  81. workOrderStat: {
  82. counts: [{ status: 4, count: 3 }]
  83. }
  84. })
  85. assert.deepEqual(cards, [
  86. { key: 'alarmTotal', label: '报警总数', value: 16, unit: '条', tone: 'primary' },
  87. { key: 'alarmingDevice', label: '报警中设备', value: 4, unit: '台', tone: 'danger' },
  88. { key: 'verifyingOrder', label: '待验收工单', value: 3, unit: '单', tone: 'warning' },
  89. { key: 'onlineRate', label: '在线率', value: 86.7, unit: '%', tone: 'primary' }
  90. ])
  91. })
  92. test('alarm trend returns four level series with zero-filled missing days', () => {
  93. const trend = normalizeAlarmTrend([
  94. { date: '2026-09-15', level1Count: 1, level2Count: 2 },
  95. { date: '2026-09-16' }
  96. ])
  97. assert.deepEqual(trend.dates, ['2026-09-15', '2026-09-16'])
  98. assert.equal(trend.levels.length, 4)
  99. const level2 = trend.levels.find(item => item.name === '级2')
  100. assert.deepEqual(level2.data, [2, 0])
  101. assert.equal(normalizeAlarmTrend(null).levels.length, 4)
  102. })
  103. test('ratio pie drops empty values and caps the number of segments', () => {
  104. const items = [
  105. { name: ' ' },
  106. { name: '压力', count: '8' },
  107. { name: '流量', count: '5' },
  108. { name: '离线', count: '3' },
  109. { name: '低', count: 0 }
  110. ]
  111. assert.deepEqual(normalizePieRatio(items, '未分类', 3), [
  112. { name: '压力', count: 8 },
  113. { name: '流量', count: 5 },
  114. { name: '离线', count: 3 }
  115. ])
  116. assert.deepEqual(normalizePieRatio(undefined, '未分类'), [])
  117. })
  118. test('realtime alarm rows expose chinese friendly display fields', () => {
  119. const rows = normalizeRealtimeAlarmRows([
  120. { id: 'a1', deviceCode: 'CN-GS-202609020001', deviceName: '一号压力点', warningType: '压力过低', alarmLevel: 1, alarmTime: '2026-09-15 10:00:00', equipmentLocation: '城南' }
  121. ])
  122. assert.equal(rows.length, 1)
  123. assert.equal(rows[0].deviceName, '一号压力点')
  124. assert.equal(rows[0].alarmLevelText, '一级报警')
  125. assert.equal(rows[0].location, '城南')
  126. assert.equal(normalizeRealtimeAlarmRows([], 5).length, 0)
  127. })
  128. test('abnormal todo rows reuse the shared device normalization contract', () => {
  129. const rows = normalizeAbnormalTodoRows([{
  130. equipmentId: 'eq-1',
  131. equipmentCode: 'CN-GS-202609020002',
  132. equipmentName: '二号流量点',
  133. alarmStatus: 1,
  134. onlineStatus: 1,
  135. currentStatus: 1,
  136. alertLevel: 2,
  137. relatedWorkOrderNo: 'WO202609150001',
  138. relatedWorkOrderStatus: 3
  139. }], 1)
  140. assert.equal(rows.length, 1)
  141. assert.equal(rows[0].alarmStatusText, '报警')
  142. assert.equal(rows[0].onlineStatusText, '在线')
  143. assert.equal(rows[0].alarmLevelText, '二级报警')
  144. assert.equal(rows[0].relatedOrderNo, 'WO202609150001')
  145. assert.equal(rows[0].workOrderStatusText, '处理中')
  146. })
  147. test('device summary keeps key text fields for the workbench detail panel', () => {
  148. const summary = normalizeDeviceSummary({
  149. equipmentId: 'eq-9',
  150. equipmentCode: 'CB-GS-202609020003',
  151. equipmentName: '三号漏失点',
  152. equipmentLocation: '城北',
  153. district: '城北',
  154. alarmStatus: 0,
  155. onlineStatus: 0,
  156. currentStatus: 3,
  157. equipmentTypeName: '漏失在线监测仪'
  158. })
  159. assert.equal(summary.name, '三号漏失点')
  160. assert.equal(summary.alarmStatusText, '正常')
  161. assert.equal(summary.onlineStatusText, '离线')
  162. assert.equal(summary.currentStatusText, '维修')
  163. assert.equal(summary.abnormalReasonText, '设备维修中')
  164. assert.equal(summary.typeName, '漏失在线监测仪')
  165. })
  166. test('work order rows translate status and level codes to chinese', () => {
  167. const rows = normalizeWorkOrderRows([
  168. { orderId: 5, orderNo: 'WO202609150001', orderStatus: 4, orderLevel: 0, deviceCode: 'CN-GS-202609020001', createTime: '2026-09-15 10:00:00' }
  169. ], 5)
  170. assert.equal(rows[0].orderStatusText, '待验收')
  171. assert.equal(rows[0].orderStatusType, 'primary')
  172. assert.equal(rows[0].orderLevelText, '紧急')
  173. assert.equal(rows[0].orderLevelType, 'danger')
  174. })
  175. test('overview map points merge devices and alarms with alarm priority', () => {
  176. const points = buildOverviewMapPoints({
  177. devicePoints: [
  178. { equipmentId: 'eq-1', equipmentCode: 'CN-GS-202609020001', equipmentName: '一号点', longitude: 110.1, latitude: 28.1, alarmStatus: 0, onlineStatus: 1 },
  179. { equipmentId: 'eq-2', equipmentCode: 'CB-GS-202609020002', equipmentName: '二号点', longitude: 110.2, latitude: 28.2, alarmStatus: 1, onlineStatus: 1 }
  180. ],
  181. alarmRows: [
  182. { deviceCode: 'CN-GS-202609020001', deviceName: '一号点', longitude: 110.1, latitude: 28.1, warningType: '压力过低', alarmLevel: 1 }
  183. ]
  184. })
  185. assert.equal(points.length, 2)
  186. const one = points.find(item => item.deviceCode === 'CN-GS-202609020001')
  187. assert.equal(one.state, 'alarm')
  188. assert.equal(one.meta, '压力过低')
  189. const two = points.find(item => item.deviceCode === 'CB-GS-202609020002')
  190. assert.equal(two.state, 'alarm')
  191. assert.ok(points.every(item => Number.isFinite(item.mapX) && Number.isFinite(item.mapY)))
  192. assert.deepEqual(buildOverviewMapPoints({ devicePoints: [], alarmRows: [] }), [])
  193. })
  194. test('home quick entries cover the four workbench jumps', () => {
  195. assert.deepEqual(HOME_QUICK_ENTRIES.map(item => item.label), ['设备异常管理', '报警管理', '报警审核', '监测报警一张图'])
  196. assert.ok(HOME_QUICK_ENTRIES.every(item => item.suffix.startsWith('/')))
  197. })