nayota-show-sdk 1.3.88 → 1.3.90
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 +1 -1
- package/utils/iot-module-specs.js +122 -1
- package/utils/iot-module-specs.test.js +95 -0
package/package.json
CHANGED
|
@@ -257,6 +257,40 @@ function normalizeHierarchyField(data = {}, field) {
|
|
|
257
257
|
return getNestedValue(data, `relationInfo.${field}`)
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
function normalizeHierarchyFloorPlanForWrite(data = {}) {
|
|
261
|
+
const relationInfo = data.relationInfo
|
|
262
|
+
const hasLegacyImage = hasOwn(relationInfo, 'image')
|
|
263
|
+
|
|
264
|
+
if (hasLegacyImage) {
|
|
265
|
+
const image = relationInfo.image
|
|
266
|
+
|
|
267
|
+
if (image == null) {
|
|
268
|
+
return null
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (typeof image !== 'object') {
|
|
272
|
+
return image
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const hasImagePath = Boolean(image.imagePath || image.url)
|
|
276
|
+
const hasDimensions = Number(image.width || 0) > 0 && Number(image.height || 0) > 0
|
|
277
|
+
const hasCorners = Array.isArray(image.corners) && image.corners.length > 0
|
|
278
|
+
const hasImageIdentity = Boolean(image.id)
|
|
279
|
+
|
|
280
|
+
if (!hasImagePath && !hasDimensions && !hasCorners && !hasImageIdentity) {
|
|
281
|
+
return null
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return image
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (hasOwn(data, 'floorPlan')) {
|
|
288
|
+
return data.floorPlan
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return undefined
|
|
292
|
+
}
|
|
293
|
+
|
|
260
294
|
function normalizeLegacyHierarchyRelationInfo(item = {}) {
|
|
261
295
|
const relationInfo = removeUndefinedFields({
|
|
262
296
|
...(item.relationInfo || {}),
|
|
@@ -314,7 +348,7 @@ function mapDepartsToIotBody(data = {}) {
|
|
|
314
348
|
latlng: normalizeHierarchyField(data, 'latlng'),
|
|
315
349
|
zooms: normalizeHierarchyField(data, 'zooms'),
|
|
316
350
|
powers: normalizeHierarchyField(data, 'powers'),
|
|
317
|
-
floorPlan: data
|
|
351
|
+
floorPlan: normalizeHierarchyFloorPlanForWrite(data),
|
|
318
352
|
metadata: Object.keys(metadata).length ? metadata : undefined
|
|
319
353
|
})
|
|
320
354
|
}
|
|
@@ -477,6 +511,90 @@ function normalizeLegacyValueStr(value, fallback = '') {
|
|
|
477
511
|
return ''
|
|
478
512
|
}
|
|
479
513
|
|
|
514
|
+
function normalizeLegacyEasyListPropTypeValue(value) {
|
|
515
|
+
if (value == null || value === '') {
|
|
516
|
+
return undefined
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const normalized = String(value).trim().replace(/[\s_-]/g, '').toLowerCase()
|
|
520
|
+
|
|
521
|
+
if (['operate', 'operation', 'control', 'controller', 'write', 'writable', 'readwrite', 'writeonly', 'rw', 'wr', 'w'].includes(normalized)) {
|
|
522
|
+
return 'Operate'
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (['check', 'monitor', 'sensor', 'read', 'readonly', 'ro', 'r'].includes(normalized)) {
|
|
526
|
+
return 'Check'
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (['控制', '控制器', '读写', '只写', '可写'].includes(normalized)) {
|
|
530
|
+
return 'Operate'
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (['监测', '监测器', '只读'].includes(normalized)) {
|
|
534
|
+
return 'Check'
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if ((normalized.includes('write') || normalized.includes('写')) && normalized !== 'readonly' && normalized !== '只读') {
|
|
538
|
+
return 'Operate'
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (normalized.includes('read') || normalized.includes('读') || normalized.includes('check')) {
|
|
542
|
+
return 'Check'
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return undefined
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function resolveLegacyEasyListPropType(source = {}, prop = {}) {
|
|
549
|
+
const explicitCandidates = [
|
|
550
|
+
source.propType,
|
|
551
|
+
source.type,
|
|
552
|
+
source.propertyType,
|
|
553
|
+
prop.propType,
|
|
554
|
+
prop.type,
|
|
555
|
+
prop.propertyType,
|
|
556
|
+
getNestedValue(source, 'metadata.propType'),
|
|
557
|
+
getNestedValue(prop, 'metadata.propType')
|
|
558
|
+
]
|
|
559
|
+
|
|
560
|
+
const explicitPropType = explicitCandidates
|
|
561
|
+
.map(normalizeLegacyEasyListPropTypeValue)
|
|
562
|
+
.find(Boolean)
|
|
563
|
+
|
|
564
|
+
if (explicitPropType) {
|
|
565
|
+
return explicitPropType
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const accessCandidates = [
|
|
569
|
+
source.access,
|
|
570
|
+
source.propertyAccess,
|
|
571
|
+
source.accessMode,
|
|
572
|
+
source.permission,
|
|
573
|
+
source.permissions,
|
|
574
|
+
source.accessPermission,
|
|
575
|
+
prop.access,
|
|
576
|
+
prop.propertyAccess,
|
|
577
|
+
prop.accessMode,
|
|
578
|
+
prop.permission,
|
|
579
|
+
prop.permissions,
|
|
580
|
+
prop.accessPermission,
|
|
581
|
+
getNestedValue(source, 'metadata.access'),
|
|
582
|
+
getNestedValue(source, 'metadata.propertyAccess'),
|
|
583
|
+
getNestedValue(source, 'typeProperty.access'),
|
|
584
|
+
getNestedValue(source, 'deviceProperty.access'),
|
|
585
|
+
getNestedValue(source, 'deviceTypeProperty.access'),
|
|
586
|
+
getNestedValue(prop, 'metadata.access'),
|
|
587
|
+
getNestedValue(prop, 'metadata.propertyAccess'),
|
|
588
|
+
getNestedValue(prop, 'typeProperty.access'),
|
|
589
|
+
getNestedValue(prop, 'deviceProperty.access'),
|
|
590
|
+
getNestedValue(prop, 'deviceTypeProperty.access')
|
|
591
|
+
]
|
|
592
|
+
|
|
593
|
+
return accessCandidates
|
|
594
|
+
.map(normalizeLegacyEasyListPropTypeValue)
|
|
595
|
+
.find(Boolean)
|
|
596
|
+
}
|
|
597
|
+
|
|
480
598
|
function normalizeLegacyPropLine(source = {}, prop = {}, row = {}) {
|
|
481
599
|
if (typeof source.line === 'boolean') {
|
|
482
600
|
return source.line
|
|
@@ -630,10 +748,12 @@ function normalizeLegacyEasyListProp(source = {}, row = {}) {
|
|
|
630
748
|
const isStatus = Boolean(source.isStatus)
|
|
631
749
|
const isNumber = Boolean(source.isNumber)
|
|
632
750
|
const isImport = Boolean(source.isImport || isMain || isStatus || isNumber)
|
|
751
|
+
const propType = resolveLegacyEasyListPropType(source, prop)
|
|
633
752
|
|
|
634
753
|
const legacyProp = removeUndefinedFields({
|
|
635
754
|
...prop,
|
|
636
755
|
_id: propId,
|
|
756
|
+
propType,
|
|
637
757
|
deviceId: prop.deviceId || source.deviceId || '',
|
|
638
758
|
key: prop.key || source.propertyKey,
|
|
639
759
|
name: prop.name || source.propName || source.name || source.code || source.propertyKey,
|
|
@@ -664,6 +784,7 @@ function normalizeLegacyEasyListProp(source = {}, row = {}) {
|
|
|
664
784
|
isMain,
|
|
665
785
|
isStatus,
|
|
666
786
|
isNumber,
|
|
787
|
+
propType,
|
|
667
788
|
line,
|
|
668
789
|
value,
|
|
669
790
|
valueStr,
|
|
@@ -233,6 +233,47 @@ describe('iotModuleSpecs departs hierarchy compatibility', () => {
|
|
|
233
233
|
expect(request.data.metadata).toEqual({ keep: 'value' })
|
|
234
234
|
})
|
|
235
235
|
|
|
236
|
+
test('clears official floorPlan when legacy relationInfo image is explicitly removed', () => {
|
|
237
|
+
const request = departs.updateOne.toRequest({
|
|
238
|
+
_id: 'e245a3f6-d2c7-4ce1-9e02-ba9bbb347ed7',
|
|
239
|
+
floorPlan: {
|
|
240
|
+
imagePath: 'stale.svg',
|
|
241
|
+
width: 100,
|
|
242
|
+
height: 80
|
|
243
|
+
},
|
|
244
|
+
relationInfo: {
|
|
245
|
+
image: null
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
expect(request.data.relationInfo).toEqual({
|
|
250
|
+
image: null
|
|
251
|
+
})
|
|
252
|
+
expect(request.data.floorPlan).toBeNull()
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
test('clears official floorPlan when legacy relationInfo image is emptied by old BMS editor', () => {
|
|
256
|
+
const request = departs.updateOne.toRequest({
|
|
257
|
+
_id: 'e245a3f6-d2c7-4ce1-9e02-ba9bbb347ed7',
|
|
258
|
+
floorPlan: {
|
|
259
|
+
imagePath: 'stale.svg',
|
|
260
|
+
width: 100,
|
|
261
|
+
height: 80
|
|
262
|
+
},
|
|
263
|
+
relationInfo: {
|
|
264
|
+
image: {
|
|
265
|
+
imagePath: '',
|
|
266
|
+
width: 0,
|
|
267
|
+
height: 0,
|
|
268
|
+
zIndex: 0,
|
|
269
|
+
corners: []
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
expect(request.data.floorPlan).toBeNull()
|
|
275
|
+
})
|
|
276
|
+
|
|
236
277
|
test('rebuilds legacy relationInfo from official hierarchy fields and ignores metadata fallbacks', () => {
|
|
237
278
|
const response = departs.list.fromResponse({
|
|
238
279
|
code: 0,
|
|
@@ -595,6 +636,60 @@ describe('iotModuleSpecs devices easyList legacy compatibility', () => {
|
|
|
595
636
|
})
|
|
596
637
|
)
|
|
597
638
|
})
|
|
639
|
+
|
|
640
|
+
test('maps writable access permissions to legacy BMS Operate props', () => {
|
|
641
|
+
const response = easyList.fromResponse({
|
|
642
|
+
code: 0,
|
|
643
|
+
data: {
|
|
644
|
+
total: 1,
|
|
645
|
+
rows: [
|
|
646
|
+
{
|
|
647
|
+
id: 'twin-1',
|
|
648
|
+
props: [
|
|
649
|
+
{
|
|
650
|
+
id: 'write-only-prop',
|
|
651
|
+
propertyKey: 'reset',
|
|
652
|
+
name: '复位',
|
|
653
|
+
access: 'write_only',
|
|
654
|
+
interval: '[["复位"],[1]]',
|
|
655
|
+
prop: {
|
|
656
|
+
id: 'device-prop-reset'
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
id: 'read-write-prop',
|
|
661
|
+
propertyKey: 'reply',
|
|
662
|
+
name: '回复',
|
|
663
|
+
propertyAccess: '读写',
|
|
664
|
+
interval: '[["确认"],[1]]',
|
|
665
|
+
prop: {
|
|
666
|
+
id: 'device-prop-reply'
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
id: 'read-only-prop',
|
|
671
|
+
propertyKey: 'version',
|
|
672
|
+
name: '版本',
|
|
673
|
+
access: 'read_only',
|
|
674
|
+
prop: {
|
|
675
|
+
id: 'device-prop-version'
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
]
|
|
679
|
+
}
|
|
680
|
+
]
|
|
681
|
+
}
|
|
682
|
+
})
|
|
683
|
+
|
|
684
|
+
const [writeOnlyProp, readWriteProp, readOnlyProp] = response.data.rows[0].props
|
|
685
|
+
|
|
686
|
+
expect(writeOnlyProp).toEqual(expect.objectContaining({ propType: 'Operate' }))
|
|
687
|
+
expect(writeOnlyProp.prop).toEqual(expect.objectContaining({ propType: 'Operate' }))
|
|
688
|
+
expect(readWriteProp).toEqual(expect.objectContaining({ propType: 'Operate' }))
|
|
689
|
+
expect(readWriteProp.prop).toEqual(expect.objectContaining({ propType: 'Operate' }))
|
|
690
|
+
expect(readOnlyProp).toEqual(expect.objectContaining({ propType: 'Check' }))
|
|
691
|
+
expect(readOnlyProp.prop).toEqual(expect.objectContaining({ propType: 'Check' }))
|
|
692
|
+
})
|
|
598
693
|
})
|
|
599
694
|
|
|
600
695
|
describe('iotModuleSpecs devices getPropHistoryData legacy compatibility', () => {
|