|
|
@@ -0,0 +1,43 @@
|
|
|
+import assert from 'node:assert/strict'
|
|
|
+import { deviceMetricKind, deviceMetricPath, toTypedMetricsPayload } from '../../../src/modules/cockpit/domain/deviceMetricSources.js'
|
|
|
+import { fetchEquipmentDetailAggregate } from '../../../src/modules/cockpit/services/detailApi.js'
|
|
|
+assert.equal(deviceMetricKind({ name: '测试流量计' }), 'flow')
|
|
|
+assert.equal(deviceMetricPath('flow', 'TEST-TCLLJ002215'), '/waterSupply/monitoring/flow/trend/TEST-TCLLJ002215')
|
|
|
+const typed = toTypedMetricsPayload({ data: [{ flow: 12.5, unit: 'm³/h', timestamp: '2026-10-19T10:00:00+08:00' }] }, 'D', 'flow')
|
|
|
+assert.equal(typed.metrics[0].value, 12.5)
|
|
|
+assert.equal(typed.metrics[0].unit, 'm³/h')
|
|
|
+const paths = []
|
|
|
+const options = {
|
|
|
+ config: { dataSource: 'real', api: { baseUrl: 'http://test.invalid/api/cockpit/v1' } },
|
|
|
+ fetchImpl: async (url) => {
|
|
|
+ paths.push(url)
|
|
|
+ if (url.endsWith('/detail-aggregate')) return new Response(JSON.stringify({ code: 200, data: {
|
|
|
+ deviceCode: 'TEST-TCLLJ002215', aggregateState: 'READY',
|
|
|
+ archive: { state: 'SUCCESS', data: { deviceCode: 'TEST-TCLLJ002215', deviceName: '测试流量计', deviceTypeName: '流量计' } },
|
|
|
+ metrics: { state: 'EMPTY', reason: 'NO_METRICS', data: null }, warnings: { state: 'SUCCESS', data: [] }, alarms: { state: 'SUCCESS', data: [] },
|
|
|
+ alarmWarningRelations: { state: 'SUCCESS', data: [] }, workOrders: { state: 'EMPTY', data: null }, timelines: { state: 'EMPTY', data: null }, latestImage: { state: 'EMPTY', data: null },
|
|
|
+ } }))
|
|
|
+ if (url.includes('/waterSupply/monitoring/flow/trend/')) return new Response(JSON.stringify({ code: 200, data: [{ flow: 12.5, unit: 'm³/h', timestamp: '2026-10-19T10:00:00+08:00' }] }))
|
|
|
+ throw new Error(`unexpected ${url}`)
|
|
|
+ },
|
|
|
+}
|
|
|
+const result = await fetchEquipmentDetailAggregate('TEST-TCLLJ002215', options)
|
|
|
+assert.equal(paths.length, 2)
|
|
|
+assert.equal(result.data.sections.metrics.data.metrics[0].value, 12.5)
|
|
|
+assert.equal(result.data.sections.metrics.data.metrics[0].unit, 'm³/h')
|
|
|
+assert.equal(deviceMetricKind({ type: 'FLOW_METER', name: '设备' }), 'flow')
|
|
|
+assert.equal(deviceMetricKind({ type: 'LEVEL_METER', name: '设备' }), '')
|
|
|
+const failedPaths = []
|
|
|
+const failed = await fetchEquipmentDetailAggregate('D-401', { config: options.config, fetchImpl: async (url) => {
|
|
|
+ failedPaths.push(url)
|
|
|
+ if (url.endsWith('/detail-aggregate')) return new Response(JSON.stringify({ code: 200, data: {
|
|
|
+ deviceCode: 'D-401', aggregateState: 'READY', archive: { state: 'SUCCESS', data: { deviceCode: 'D-401', deviceType: 'FLOW_METER', deviceName: '设备' } },
|
|
|
+ metrics: { state: 'EMPTY', reason: 'NO_METRICS', data: null }, warnings: { state: 'SUCCESS', data: [] }, alarms: { state: 'SUCCESS', data: [] },
|
|
|
+ alarmWarningRelations: { state: 'SUCCESS', data: [] }, workOrders: { state: 'EMPTY', data: null }, timelines: { state: 'EMPTY', data: null }, latestImage: { state: 'EMPTY', data: null },
|
|
|
+ } }))
|
|
|
+ return new Response(JSON.stringify({ code: 401, msg: 'unauthorized' }), { status: 401 })
|
|
|
+} })
|
|
|
+assert.equal(failedPaths.length, 2)
|
|
|
+assert.equal(failed.data.sections.metrics.state, 'unavailable')
|
|
|
+assert.equal(failed.data.sections.warnings.state, 'success')
|
|
|
+console.log('PASS 流量计按设备类型切专用指标源,通用EMPTY不覆盖专用读数')
|