deviceStatus.js 4.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /**
  2. * 监测**设备**自身状态 → 视觉表现(票 44;决策票 07)。
  3. *
  4. * ── 为什么必须是**平行**于 `pointStatus.js` 的另一张表,而不是复用它 ──
  5. * 两张表的业务对象不同、状态来源也不同:
  6. * · `pointStatus.js` 表达**监测点聚合状态**(后端解析并发布,六个取值含 `EMPTY`「无设备」);
  7. * · 本表表达**监测设备自身状态**(五个取值,**没有 `EMPTY`** —— 那是点位聚合态专有)。
  8. * 早先 `detailFlow.js` 正拿点位那张表给设备配色配形(即"把设备猜成点位状态"在代码里已经发生),
  9. * 那是越界;本票把它改到本表(见 `domain/detailFlow.js` 的 `deviceStatusView`)。
  10. *
  11. * ── 三条纪律(与 `pointStatus.js` 同源,但取值集不同)──
  12. * 1. **前端不重算**:只接收后端 `deviceStatus` 字符串;认不出的落 `UNKNOWN`(「状态未发布」),
  13. * 宁可如实说不知道,**不猜成 NORMAL** —— 猜成正常是最危险的一种谎话。
  14. * 2. **颜色不是唯一线索**:每态同时有 `tone`(色键)+ `shape`(形状)+ `label`(文字)。
  15. * 色键**只写键名**,色值仍只在 `styles/tokens.css` 声明(票 06 的单一口径)。
  16. * 3. **色键可同、语义不混**:点位与设备可用同一组 `--lv1..--neutral` 调色板,
  17. * 但两表的键位含义各自成立,不得互相推导。
  18. *
  19. * 五态与中文标签照抄后端 `CockpitMonitoringPointDeviceCard.deviceStatus` 的取值
  20. * (`ALARM`/`WARNING`/`WORK_ORDER`/`NORMAL`/`OFFLINE`),不另造业务词汇。
  21. * 本票只交付**静态**色/形/文字;动效(扩散脉冲/闪烁/旋转环)归票 47。
  22. */
  23. import { SHAPES } from './pointStatus.js'
  24. /** 后端设备自身状态的五个取值(原样字符串,不改名、不缩写)。 */
  25. export const DEVICE_STATUS = {
  26. ALARM: 'ALARM',
  27. WARNING: 'WARNING',
  28. WORK_ORDER: 'WORK_ORDER',
  29. NORMAL: 'NORMAL',
  30. OFFLINE: 'OFFLINE',
  31. }
  32. /**
  33. * 设备状态视觉词表。
  34. *
  35. * 形状**复用** `pointStatus.js` 的 `SHAPES` 片段(同风格、同一份 SVG 来源,避免两套图形定义),
  36. * 但**键与语义在本表独立成立**:例如点位表的 `EMPTY`(无设备)在这里根本不存在。
  37. * `priority` 数值沿用后端给的状态优先级(1 最紧急),前端不自定序。
  38. */
  39. export const DEVICE_STATUS_VISUALS = {
  40. ALARM: { key: 'ALARM', tone: 'lv1', shape: 'triangle', label: '报警', priority: 1, effect: 'pulse' },
  41. WARNING: { key: 'WARNING', tone: 'lv2', shape: 'diamond', label: '预警', priority: 2, effect: 'blink' },
  42. WORK_ORDER: { key: 'WORK_ORDER', tone: 'lv3', shape: 'square', label: '工单处置', priority: 3, effect: 'spin' },
  43. NORMAL: { key: 'NORMAL', tone: 'lv4', shape: 'circle', label: '正常', priority: 4, effect: null },
  44. OFFLINE: { key: 'OFFLINE', tone: 'point-offline', shape: 'ring', label: '离线', priority: 5, effect: null },
  45. }
  46. /**
  47. * 认不出的设备状态:如实说「不知道」,**不落到任何一个真实状态上**(尤其不猜 NORMAL)。
  48. * `effect: null` —— 状态都不知道,**更不能给它编一个动效**(那会把"未知"画成"正在报警")。
  49. */
  50. export const DEVICE_UNKNOWN_VISUAL = { key: 'UNKNOWN', tone: 'point-unknown', shape: 'hollowDiamond', label: '状态未发布', priority: 6, effect: null }
  51. /** 设备状态字符串 → 视觉词条;认不出的一律 `DEVICE_UNKNOWN_VISUAL`。 */
  52. export function deviceVisualForStatus(status) {
  53. return DEVICE_STATUS_VISUALS[status] || DEVICE_UNKNOWN_VISUAL
  54. }
  55. /** 一条设备的视觉词条 → 地图标记要的形状名(引擎只认形状,不认业务状态)。 */
  56. export function deviceShapeOf(device) {
  57. return deviceVisualForStatus(device && device.status).shape
  58. }
  59. /**
  60. * 设备状态图例行(**独立于监测点摘要图例**,规格与票 09 的边界都要求分开)。
  61. *
  62. * `count` = 当前模式实际绘制的该状态设备数(由调用方给,本层只负责行与顺序)。
  63. * 0 不隐藏行(形状的含义要能查到)。
  64. * @param {object} [byStatus] `{ [visualKey]: count }`
  65. */
  66. export function deviceLegend(byStatus = {}) {
  67. const rows = [...Object.keys(DEVICE_STATUS_VISUALS).map((key) => DEVICE_STATUS_VISUALS[key]), DEVICE_UNKNOWN_VISUAL]
  68. return rows
  69. .sort((a, b) => a.priority - b.priority)
  70. .map((visual) => ({
  71. key: visual.key,
  72. tone: visual.tone,
  73. shape: visual.shape,
  74. label: visual.label,
  75. count: byStatus[visual.key] || 0,
  76. }))
  77. }
  78. /** 该形状名在本表(及其复用的 `SHAPES`)里是否存在;供静态守卫与降级判据用。 */
  79. export function isKnownDeviceShape(shape) {
  80. return Object.prototype.hasOwnProperty.call(SHAPES, shape)
  81. }