nayota-show-sdk 1.3.67 → 1.3.69

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nayota-show-sdk",
3
- "version": "1.3.67",
3
+ "version": "1.3.69",
4
4
  "description": "nayota-show-server rest-api",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -2,6 +2,17 @@ function isPlainObject(value) {
2
2
  return Object.prototype.toString.call(value) === '[object Object]'
3
3
  }
4
4
 
5
+ function stripResourceIdPrefix(value) {
6
+ if (value == null) {
7
+ return value
8
+ }
9
+
10
+ const normalized = String(value)
11
+ const match = normalized.match(/^[a-z][a-z0-9-]*:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i)
12
+
13
+ return match ? match[1] : normalized
14
+ }
15
+
5
16
  export function removeUndefinedFields(value) {
6
17
  if (!isPlainObject(value)) {
7
18
  return value
@@ -35,7 +46,7 @@ export function getLegacyId(value) {
35
46
  }
36
47
 
37
48
  if (typeof value === 'string' || typeof value === 'number') {
38
- return String(value)
49
+ return stripResourceIdPrefix(value)
39
50
  }
40
51
 
41
52
  if (Array.isArray(value)) {
@@ -44,10 +55,10 @@ export function getLegacyId(value) {
44
55
 
45
56
  if (typeof value === 'object') {
46
57
  if (value._id != null) {
47
- return String(value._id)
58
+ return stripResourceIdPrefix(value._id)
48
59
  }
49
60
  if (value.id != null) {
50
- return String(value.id)
61
+ return stripResourceIdPrefix(value.id)
51
62
  }
52
63
  }
53
64
 
@@ -89,6 +100,14 @@ export function withLegacyId(value) {
89
100
  return acc
90
101
  }, {})
91
102
 
103
+ if (next.id != null) {
104
+ next.id = stripResourceIdPrefix(next.id)
105
+ }
106
+
107
+ if (next._id != null) {
108
+ next._id = stripResourceIdPrefix(next._id)
109
+ }
110
+
92
111
  if (next.id != null && next._id == null) {
93
112
  next._id = next.id
94
113
  }
@@ -297,6 +297,71 @@ function mapDeviceEasyListRequest(data = {}) {
297
297
  })
298
298
  }
299
299
 
300
+ function hasOwn(value, key) {
301
+ return Object.prototype.hasOwnProperty.call(value || {}, key)
302
+ }
303
+
304
+ function getLegacyUiRelationId(relation = {}) {
305
+ if (relation.uiId != null) {
306
+ return getLegacyId(relation.uiId)
307
+ }
308
+
309
+ if (relation.ui != null) {
310
+ return getLegacyId(relation.ui)
311
+ }
312
+
313
+ if (relation.id != null || relation._id != null) {
314
+ return getLegacyId(relation)
315
+ }
316
+
317
+ return ''
318
+ }
319
+
320
+ function normalizeLegacyUiRelation(relation = {}, fallbackType = 'ba_card') {
321
+ const source = relation.ui && typeof relation.ui === 'object'
322
+ ? relation.ui
323
+ : relation
324
+ const uiId = getLegacyUiRelationId(relation)
325
+
326
+ if (!uiId) {
327
+ return null
328
+ }
329
+
330
+ return removeUndefinedFields({
331
+ uiId,
332
+ uiName: relation.uiName || source.name,
333
+ uiCode: relation.uiCode || source.code,
334
+ type: relation.type || source.type || fallbackType,
335
+ props: relation.props,
336
+ attrs: Array.isArray(relation.attrs) ? relation.attrs : []
337
+ })
338
+ }
339
+
340
+ function resolveDigitalTwinTypeUiRelation(data = {}) {
341
+ if (hasOwn(data, 'uiId')) {
342
+ return data.uiId == null ? null : normalizeLegacyUiRelation({ uiId: data.uiId, ui: data.ui })
343
+ }
344
+
345
+ if (data.ui) {
346
+ return normalizeLegacyUiRelation(data.ui)
347
+ }
348
+
349
+ const relations = Array.isArray(data.uis) ? data.uis : []
350
+ return relations.find(item => item && item.type === 'ba_card') ||
351
+ relations.find(item => item && item.type === 'component') ||
352
+ relations[0] ||
353
+ null
354
+ }
355
+
356
+ function getDigitalTwinTypeUiId(data = {}) {
357
+ if (hasOwn(data, 'uiId')) {
358
+ return data.uiId == null ? null : getLegacyId(data.uiId)
359
+ }
360
+
361
+ const relation = resolveDigitalTwinTypeUiRelation(data)
362
+ return relation ? getLegacyUiRelationId(relation) : undefined
363
+ }
364
+
300
365
  function mapDeviceClassToIotQuery(query = {}) {
301
366
  return removeUndefinedFields({
302
367
  ...omitKeys(query, ['_id', 'code', 'sort']),
@@ -309,6 +374,8 @@ function mapDeviceClassToIotQuery(query = {}) {
309
374
  }
310
375
 
311
376
  function mapDeviceClassToIotBody(data = {}) {
377
+ const twinUiRelation = resolveDigitalTwinTypeUiRelation(data)
378
+ const uiId = getDigitalTwinTypeUiId(data)
312
379
  const metadata = mergeMetadata(data.metadata, {
313
380
  display: mergeMetadata(getNestedValue(data, 'metadata.display'), {
314
381
  icon: data.icon
@@ -316,6 +383,7 @@ function mapDeviceClassToIotBody(data = {}) {
316
383
  bms: mergeMetadata(getNestedValue(data, 'metadata.bms'), {
317
384
  deviceUI: data.deviceUI,
318
385
  uis: data.uis,
386
+ twinUi: twinUiRelation ? normalizeLegacyUiRelation(twinUiRelation) : undefined,
319
387
  paramType: data.paramType,
320
388
  departTag: data.departTag,
321
389
  isSimulation: data.isSimulation,
@@ -329,6 +397,8 @@ function mapDeviceClassToIotBody(data = {}) {
329
397
  '_id',
330
398
  'id',
331
399
  'code',
400
+ 'ui',
401
+ 'uiId',
332
402
  'deviceUI',
333
403
  'uis',
334
404
  'paramType',
@@ -338,6 +408,7 @@ function mapDeviceClassToIotBody(data = {}) {
338
408
  'icon'
339
409
  ]),
340
410
  typeCode: data.typeCode || data.code || fallbackCode(data.name || data._id, 'TYPE'),
411
+ uiId,
341
412
  metadata: Object.keys(metadata).length ? metadata : undefined
342
413
  })
343
414
  }
@@ -347,12 +418,22 @@ function mapIotDeviceClassToLegacy(item = {}) {
347
418
  const metadata = getMetadata(entity.metadata)
348
419
  const bms = getMetadata(metadata.bms)
349
420
  const display = getMetadata(metadata.display)
421
+ const twinUiRelation = normalizeLegacyUiRelation({
422
+ uiId: entity.uiId,
423
+ ui: entity.ui,
424
+ type: entity.ui && entity.ui.type
425
+ })
426
+ const bmsUis = Array.isArray(bms.uis) ? bms.uis : undefined
427
+ const uis = bmsUis && bmsUis.length
428
+ ? bmsUis
429
+ : twinUiRelation ? [twinUiRelation] : entity.uis
350
430
 
351
431
  return removeUndefinedFields({
352
432
  ...entity,
353
433
  code: entity.typeCode || entity.code,
354
434
  deviceUI: bms.deviceUI || entity.deviceUI,
355
- uis: bms.uis || entity.uis,
435
+ uis,
436
+ uiCode: entity.uiCode || twinUiRelation?.uiCode,
356
437
  paramType: bms.paramType || entity.paramType,
357
438
  departTag: bms.departTag || entity.departTag,
358
439
  isSimulation: bms.isSimulation != null ? bms.isSimulation : entity.isSimulation,
@@ -0,0 +1,95 @@
1
+ const { iotModuleSpecs } = require('./iot-module-specs')
2
+
3
+ describe('iotModuleSpecs deviceClass UI compatibility', () => {
4
+ const deviceClass = iotModuleSpecs.deviceClass.operations
5
+
6
+ test('maps legacy ba_card relation to digital twin type uiId', () => {
7
+ const request = deviceClass.updateOne.toRequest({
8
+ _id: 'type-1',
9
+ name: '照明',
10
+ code: 'LIGHT',
11
+ deviceUI: 'legacy-device-ui-1',
12
+ uis: [
13
+ {
14
+ uiId: 'legacy-device-ui-1',
15
+ uiName: '旧展示设备UI',
16
+ uiCode: 'LegacyDeviceUi',
17
+ type: 'device_ui',
18
+ attrs: []
19
+ },
20
+ {
21
+ uiId: 'card-ui-1',
22
+ uiName: '照明卡片',
23
+ uiCode: 'NaLightingCard',
24
+ type: 'ba_card',
25
+ attrs: [{ name: '名称' }]
26
+ }
27
+ ]
28
+ })
29
+
30
+ expect(request.url).toBe('/digital-twin-types/type-1')
31
+ expect(request.method).toBe('patch')
32
+ expect(request.data.uiId).toBe('card-ui-1')
33
+ expect(request.data.metadata.bms.deviceUI).toBe('legacy-device-ui-1')
34
+ expect(request.data.metadata.bms.twinUi).toEqual({
35
+ uiId: 'card-ui-1',
36
+ uiName: '照明卡片',
37
+ uiCode: 'NaLightingCard',
38
+ type: 'ba_card',
39
+ attrs: [{ name: '名称' }]
40
+ })
41
+ })
42
+
43
+ test('does not treat legacy deviceUI as digital twin type uiId', () => {
44
+ const request = deviceClass.create.toRequest({
45
+ name: '空调',
46
+ code: 'AIR',
47
+ deviceUI: 'legacy-device-ui-2'
48
+ })
49
+
50
+ expect(request.data.uiId).toBeUndefined()
51
+ expect(request.data.metadata.bms.deviceUI).toBe('legacy-device-ui-2')
52
+ })
53
+
54
+ test('expands digital twin type ui relation back to legacy uis', () => {
55
+ const response = deviceClass.list.fromResponse({
56
+ code: 0,
57
+ data: {
58
+ total: 1,
59
+ items: [
60
+ {
61
+ id: 'type-1',
62
+ typeCode: 'LIGHT',
63
+ name: '照明',
64
+ uiId: 'card-ui-1',
65
+ ui: {
66
+ id: 'card-ui-1',
67
+ name: '照明卡片',
68
+ code: 'NaLightingCard',
69
+ type: 'ba_card'
70
+ },
71
+ metadata: {
72
+ bms: {
73
+ deviceUI: 'legacy-device-ui-1'
74
+ }
75
+ }
76
+ }
77
+ ]
78
+ }
79
+ })
80
+
81
+ expect(response.data.rows[0]._id).toBe('type-1')
82
+ expect(response.data.rows[0].code).toBe('LIGHT')
83
+ expect(response.data.rows[0].deviceUI).toBe('legacy-device-ui-1')
84
+ expect(response.data.rows[0].uiCode).toBe('NaLightingCard')
85
+ expect(response.data.rows[0].uis).toEqual([
86
+ {
87
+ uiId: 'card-ui-1',
88
+ uiName: '照明卡片',
89
+ uiCode: 'NaLightingCard',
90
+ type: 'ba_card',
91
+ attrs: []
92
+ }
93
+ ])
94
+ })
95
+ })