t116-facility-overlay.mjs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import assert from 'node:assert/strict'
  2. import { test } from 'node:test'
  3. import { planMarker } from '../src/modules/cockpit/domain/markerPlan.js'
  4. import { mountMarkerOverlay, syncMarkerOverlay, unmountMarkerOverlay } from '../src/modules/cockpit/services/markerOverlay.js'
  5. import { markerTestDocument } from './helpers/marker-dom.mjs'
  6. const tones = { lv1: '#ff3b52', lv2: '#ffb020', lv3: '#01abea', lv4: '#27d17a', neutral: '#5680b0' }
  7. const facility = (status, id = '1') => ({
  8. key: `facility-point|WATER_PLANT|${id}`, kind: 'facility-point', code: 'WP001',
  9. name: '水厂', type: 'WATER_PLANT', entityId: id, detailCategory: 'WATER_PLANT', clickable: true,
  10. status, longitude: 110.38, latitude: 28.43,
  11. })
  12. const planOf = (row) => planMarker({ kind: row.kind, status: row.status, facilityType: row.type, industry: row.industry, tone: row.tone })
  13. function mount(t) {
  14. const previous = globalThis.document
  15. const document = markerTestDocument()
  16. globalThis.document = document
  17. assert.equal(mountMarkerOverlay(document.host), true)
  18. t.after(() => {
  19. unmountMarkerOverlay()
  20. if (previous === undefined) delete globalThis.document
  21. else globalThis.document = previous
  22. })
  23. return {
  24. document,
  25. sync: (rows, effectOf, extra = {}) => syncMarkerOverlay({
  26. facilities: rows, facilityPlanOf: planOf, planOf, tones,
  27. facilityEffectOf: effectOf, projectToWindow: () => ({ x: 100, y: 200 }), ...extra,
  28. }),
  29. node: (row) => document.host.nodes().find((node) => node.dataset.markerOverlayKey === row.key),
  30. }
  31. }
  32. test('正常设施不能被错误或过期的门控键挂上报警环', (t) => {
  33. const scene = mount(t)
  34. const row = { ...facility('0'), tone: 'lv1' }
  35. scene.sync([row], () => 'pulse')
  36. assert.equal(scene.node(row).dataset.markerRing, 'no')
  37. assert.equal(scene.node(row).dataset.markerEffect, undefined)
  38. })
  39. test('同一设施在超限降级与恢复时更新已有环的大小和透明度', (t) => {
  40. const scene = mount(t)
  41. const row = facility('2')
  42. scene.sync([row], () => 'pulse')
  43. assert.equal(scene.node(row).dataset.markerEffectConverged, 'no')
  44. scene.sync([row], () => 'pulse', { converge: { peak: 0.6, alpha: 0.5 } })
  45. const degraded = scene.node(row)
  46. assert.equal(degraded.dataset.markerEffectConverged, 'yes')
  47. assert.equal(degraded.dataset.markerEffectAlpha, '0.5')
  48. const ringHost = degraded.children.find((node) => node.className.includes('marker-overlay-fx--'))
  49. assert.equal(ringHost.style.opacity, '0.5')
  50. assert.equal(ringHost.style.transform, 'scale(0.6)')
  51. scene.sync([row], () => 'pulse', { converge: null })
  52. assert.equal(scene.node(row).dataset.markerEffectConverged, 'no')
  53. assert.equal(scene.node(row).dataset.markerEffectAlpha, '1')
  54. })
  55. test('设施报警、预警、维修与同态设备的实际环节点和动画配置一致', (t) => {
  56. const scene = mount(t)
  57. for (const [status, deviceStatus, effect, layers, period, color, glow] of [
  58. ['1', 'WORK_ORDER', 'spin', 1, '18000ms', '#01abea', 0],
  59. ['2', 'ALARM', 'pulse', 4, '1800ms', '#ff3b52', 1],
  60. ['WARNING', 'WARNING', 'blink', 3, '1400ms', '#ffb020', 0],
  61. ]) {
  62. const row = facility(status)
  63. scene.sync([row], () => effect, {
  64. devices: [{ code: 'd1', status: deviceStatus, industry: 'WATER_SUPPLY', x: 100, y: 200 }],
  65. deviceEffectOf: () => effect,
  66. })
  67. const node = scene.node(row)
  68. const device = scene.document.host.nodes().find((item) => item.dataset.markerOverlayKey === 'device|d1')
  69. assert.equal(node.dataset.markerTone, color)
  70. for (const key of ['markerEffect', 'markerEffectLayers', 'markerEffectAlpha', 'markerEffectConverged', 'markerDrawWidth']) {
  71. assert.equal(node.dataset[key], device.dataset[key])
  72. }
  73. const rings = node.children[0].children.filter((item) => item.className === 'marker-overlay-fx-ring')
  74. assert.equal(rings.length, layers)
  75. assert.equal(rings[0].style.animationDuration, period)
  76. assert.equal(rings[0].style.animationName, effect === 'spin' ? 'markerFxSpin' : `markerFxRing--${effect}--0`)
  77. assert.equal(node.children[0].children.filter((item) => item.className === 'marker-overlay-fx-glow').length, glow)
  78. }
  79. })
  80. test('特效开关与设施状态切换不遗留旧环,编码重复的设施按主键独立更新', (t) => {
  81. const scene = mount(t)
  82. const left = facility('1', 'A')
  83. const right = facility('2', 'B')
  84. const effects = (row) => row.key === left.key ? 'spin' : 'pulse'
  85. scene.sync([left, right], effects)
  86. assert.equal(scene.node(left).dataset.markerEffect, 'spin')
  87. assert.equal(scene.node(right).dataset.markerEffect, 'pulse')
  88. scene.sync([left, right], () => '')
  89. assert.equal(scene.node(left).dataset.markerRing, 'no')
  90. assert.equal(scene.node(right).dataset.markerEffect, undefined)
  91. scene.sync([left, right], effects)
  92. assert.equal(scene.node(left).dataset.markerEffect, 'spin')
  93. scene.sync([{ ...left, status: '0' }, right], effects)
  94. assert.equal(scene.node(left).dataset.markerRing, 'no')
  95. assert.equal(scene.node(right).dataset.markerRing, 'yes')
  96. scene.sync([], effects)
  97. assert.equal(scene.node(left).style.display, 'none')
  98. assert.equal(scene.node(right).style.display, 'none')
  99. })
  100. test('跨图层降级与恢复同时更新设备和监测点已有节点', (t) => {
  101. const scene = mount(t)
  102. const extra = {
  103. devices: [{ code: 'd2', status: 'ALARM', x: 100, y: 200 }],
  104. deviceEffectOf: () => 'pulse',
  105. markers: [{ kind: 'monitoring-point', code: 'MP1', status: 'ALARM', tone: 'lv1', longitude: 110.38, latitude: 28.43 }],
  106. effectOf: () => 'pulse',
  107. }
  108. scene.sync([], () => '', extra)
  109. scene.sync([], () => '', { ...extra, converge: { peak: 0.6, alpha: 0.5 } })
  110. for (const key of ['device|d2', 'monitoring-point|MP1']) {
  111. const node = scene.document.host.nodes().find((item) => item.dataset.markerOverlayKey === key)
  112. assert.equal(node.dataset.markerEffectConverged, 'yes')
  113. assert.equal(node.dataset.markerEffectAlpha, '0.5')
  114. }
  115. scene.sync([], () => '', extra)
  116. for (const key of ['device|d2', 'monitoring-point|MP1']) {
  117. const node = scene.document.host.nodes().find((item) => item.dataset.markerOverlayKey === key)
  118. assert.equal(node.dataset.markerEffectConverged, 'no')
  119. assert.equal(node.dataset.markerEffectAlpha, '1')
  120. }
  121. })