nayota-show-sdk 1.3.92 → 1.3.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/alarmRecord.js +135 -1
- package/api/alarmRecord.test.js +126 -0
- package/package.json +1 -1
package/api/alarmRecord.js
CHANGED
|
@@ -1,4 +1,138 @@
|
|
|
1
1
|
import requestAlarm from '../utils/alarm-request'
|
|
2
|
+
import { isV2 } from '../utils/version'
|
|
3
|
+
import { getOne as getDeviceClassOne } from './deviceClass'
|
|
4
|
+
|
|
5
|
+
function getLegacyRefId(value) {
|
|
6
|
+
if (value == null) return ''
|
|
7
|
+
|
|
8
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
9
|
+
return String(value)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (typeof value === 'object') {
|
|
13
|
+
if (value._id != null) return String(value._id)
|
|
14
|
+
if (value.id != null) return String(value.id)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return ''
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getLegacyRefName(value) {
|
|
21
|
+
if (!value || typeof value !== 'object') return ''
|
|
22
|
+
return value.name || value.deviceClassName || value.typeName || value.label || ''
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeLegacyDeviceClass(value, fallbackId = '') {
|
|
26
|
+
if (!value || typeof value !== 'object') return value
|
|
27
|
+
|
|
28
|
+
const id = getLegacyRefId(value) || fallbackId
|
|
29
|
+
return {
|
|
30
|
+
...value,
|
|
31
|
+
_id: value._id || id || undefined,
|
|
32
|
+
id: value.id || id || undefined,
|
|
33
|
+
name: getLegacyRefName(value) || undefined
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getAlarmRows(response) {
|
|
38
|
+
if (Array.isArray(response?.data?.rows)) return response.data.rows
|
|
39
|
+
if (Array.isArray(response?.rows)) return response.rows
|
|
40
|
+
return []
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function withAlarmRows(response, rows) {
|
|
44
|
+
if (Array.isArray(response?.data?.rows)) {
|
|
45
|
+
return {
|
|
46
|
+
...response,
|
|
47
|
+
data: {
|
|
48
|
+
...response.data,
|
|
49
|
+
rows
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (Array.isArray(response?.rows)) {
|
|
55
|
+
return {
|
|
56
|
+
...response,
|
|
57
|
+
rows
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return response
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function loadDeviceClassMap(ids = []) {
|
|
65
|
+
const uniqueIds = [...new Set(ids.filter(Boolean))]
|
|
66
|
+
const entries = await Promise.all(uniqueIds.map(async id => {
|
|
67
|
+
try {
|
|
68
|
+
const response = await getDeviceClassOne(id)
|
|
69
|
+
const item = response?.data
|
|
70
|
+
const normalized = normalizeLegacyDeviceClass(item, id)
|
|
71
|
+
return [id, normalized && getLegacyRefName(normalized) ? normalized : null]
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return [id, null]
|
|
74
|
+
}
|
|
75
|
+
}))
|
|
76
|
+
|
|
77
|
+
return new Map(entries.filter(([, item]) => item))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function normalizeV2AlarmRecordListResponse(response) {
|
|
81
|
+
if (!isV2()) return response
|
|
82
|
+
|
|
83
|
+
const rows = getAlarmRows(response)
|
|
84
|
+
if (!rows.length) return response
|
|
85
|
+
|
|
86
|
+
const rowsWithLocalDeviceClass = rows.map(row => {
|
|
87
|
+
const deviceClass = row?.deviceClass
|
|
88
|
+
const deviceDeviceClass = row?.device?.deviceClass
|
|
89
|
+
|
|
90
|
+
if (getLegacyRefName(deviceClass)) {
|
|
91
|
+
return {
|
|
92
|
+
...row,
|
|
93
|
+
deviceClass: normalizeLegacyDeviceClass(deviceClass)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (getLegacyRefName(deviceDeviceClass)) {
|
|
98
|
+
return {
|
|
99
|
+
...row,
|
|
100
|
+
deviceClass: normalizeLegacyDeviceClass(
|
|
101
|
+
deviceDeviceClass,
|
|
102
|
+
getLegacyRefId(deviceClass)
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return row
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const missingIds = rowsWithLocalDeviceClass
|
|
111
|
+
.filter(row => row?.deviceClass && !getLegacyRefName(row.deviceClass))
|
|
112
|
+
.map(row => getLegacyRefId(row.deviceClass))
|
|
113
|
+
|
|
114
|
+
if (!missingIds.length) {
|
|
115
|
+
return withAlarmRows(response, rowsWithLocalDeviceClass)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const deviceClassMap = await loadDeviceClassMap(missingIds)
|
|
119
|
+
if (!deviceClassMap.size) {
|
|
120
|
+
return withAlarmRows(response, rowsWithLocalDeviceClass)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return withAlarmRows(response, rowsWithLocalDeviceClass.map(row => {
|
|
124
|
+
if (!row?.deviceClass || getLegacyRefName(row.deviceClass)) return row
|
|
125
|
+
|
|
126
|
+
const id = getLegacyRefId(row.deviceClass)
|
|
127
|
+
const deviceClass = deviceClassMap.get(id)
|
|
128
|
+
if (!deviceClass) return row
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
...row,
|
|
132
|
+
deviceClass
|
|
133
|
+
}
|
|
134
|
+
}))
|
|
135
|
+
}
|
|
2
136
|
/**
|
|
3
137
|
* @file 报警记录api
|
|
4
138
|
* @module 报警记录接口
|
|
@@ -324,7 +458,7 @@ export function list(query) {
|
|
|
324
458
|
url: '/alarm-records',
|
|
325
459
|
method: 'get',
|
|
326
460
|
params: query
|
|
327
|
-
})
|
|
461
|
+
}).then(normalizeV2AlarmRecordListResponse)
|
|
328
462
|
}
|
|
329
463
|
|
|
330
464
|
/**
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
jest.mock('../utils', () => ({
|
|
2
|
+
requestShow: jest.fn(),
|
|
3
|
+
requestIot: jest.fn(),
|
|
4
|
+
requestForm: jest.fn()
|
|
5
|
+
}))
|
|
6
|
+
|
|
7
|
+
const urlcfg = require('../config/urlcfg').default
|
|
8
|
+
const { requestIot, requestShow } = require('../utils')
|
|
9
|
+
const { list } = require('./alarmRecord')
|
|
10
|
+
|
|
11
|
+
describe('alarmRecord api compatibility', () => {
|
|
12
|
+
const originalVersion = urlcfg.version
|
|
13
|
+
const originalIotServer = urlcfg.iotServer
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
urlcfg.version = originalVersion
|
|
17
|
+
urlcfg.iotServer = originalIotServer
|
|
18
|
+
jest.clearAllMocks()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('keeps v1 list response unchanged', async () => {
|
|
22
|
+
const response = {
|
|
23
|
+
code: 0,
|
|
24
|
+
data: {
|
|
25
|
+
rows: [
|
|
26
|
+
{
|
|
27
|
+
_id: 'alarm-1',
|
|
28
|
+
deviceClass: 'type-1'
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
urlcfg.version = 'v1'
|
|
34
|
+
requestShow.mockResolvedValue(response)
|
|
35
|
+
|
|
36
|
+
await expect(list({ limit: 1 })).resolves.toBe(response)
|
|
37
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
38
|
+
url: '/alarm-records',
|
|
39
|
+
method: 'get',
|
|
40
|
+
params: { limit: 1 }
|
|
41
|
+
})
|
|
42
|
+
expect(requestIot).not.toHaveBeenCalled()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('fills v2 alarm deviceClass name from digital twin type detail', async () => {
|
|
46
|
+
urlcfg.version = 'v2'
|
|
47
|
+
urlcfg.iotServer = '/iot-api'
|
|
48
|
+
requestIot.mockImplementation(config => {
|
|
49
|
+
if (config.url === '/alarm-records') {
|
|
50
|
+
return Promise.resolve({
|
|
51
|
+
code: 0,
|
|
52
|
+
data: {
|
|
53
|
+
total: 1,
|
|
54
|
+
rows: [
|
|
55
|
+
{
|
|
56
|
+
_id: 'alarm-1',
|
|
57
|
+
device: { name: '安消智能摄像头' },
|
|
58
|
+
deviceClass: 'type-1',
|
|
59
|
+
subType: '事件告警'
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (config.url === '/digital-twin-types/type-1') {
|
|
67
|
+
return Promise.resolve({
|
|
68
|
+
code: 0,
|
|
69
|
+
data: {
|
|
70
|
+
id: 'type-1',
|
|
71
|
+
name: '安消智能摄像头',
|
|
72
|
+
typeCode: 'CAMERA'
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return Promise.reject(new Error(`unexpected request: ${config.url}`))
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const response = await list({ limit: 1 })
|
|
81
|
+
|
|
82
|
+
expect(response.data.rows[0].deviceClass).toMatchObject({
|
|
83
|
+
_id: 'type-1',
|
|
84
|
+
id: 'type-1',
|
|
85
|
+
name: '安消智能摄像头',
|
|
86
|
+
code: 'CAMERA'
|
|
87
|
+
})
|
|
88
|
+
expect(requestIot).toHaveBeenCalledWith({
|
|
89
|
+
url: '/alarm-records',
|
|
90
|
+
method: 'get',
|
|
91
|
+
params: { limit: 1 }
|
|
92
|
+
})
|
|
93
|
+
expect(requestIot).toHaveBeenCalledWith({
|
|
94
|
+
url: '/digital-twin-types/type-1',
|
|
95
|
+
method: 'get'
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('does not request device class detail when v2 row already has name', async () => {
|
|
100
|
+
urlcfg.version = 'v2'
|
|
101
|
+
urlcfg.iotServer = '/iot-api'
|
|
102
|
+
requestIot.mockResolvedValue({
|
|
103
|
+
code: 0,
|
|
104
|
+
data: {
|
|
105
|
+
rows: [
|
|
106
|
+
{
|
|
107
|
+
_id: 'alarm-1',
|
|
108
|
+
deviceClass: {
|
|
109
|
+
_id: 'type-1',
|
|
110
|
+
name: '摄像头'
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
const response = await list({ limit: 1 })
|
|
118
|
+
|
|
119
|
+
expect(response.data.rows[0].deviceClass).toMatchObject({
|
|
120
|
+
_id: 'type-1',
|
|
121
|
+
id: 'type-1',
|
|
122
|
+
name: '摄像头'
|
|
123
|
+
})
|
|
124
|
+
expect(requestIot).toHaveBeenCalledTimes(1)
|
|
125
|
+
})
|
|
126
|
+
})
|