/** * 预警/报警**状态词表**(票 71 返工,维护者 2026-10-29 第 1 条反馈)。 * * ── 为什么必须分族,不能共用 ── * 维护者原话:「预警和报警状态是不一样的,不能完全通用(样式可以通用)」。 * 后端口径逐条核实过,两族是**两套互不相通的生命周期**: * * 预警(`WarningWorkflow` / `EarlyWarningStatusEnum`,六态,线性推进): * DRAFT 草稿 → PENDING 待接收 → RECEIVED 已接收 → PROCESSING 处置中 * → HANDLED 已处置 → CLOSED 已解除(**唯一终态**) * 后端注释原句:「已处置仍需核查,只有『已解除』才是终态」。 * * 报警(`alarm_data.alarm_status` 经后端归一,二态): * UNHANDLED 未处理 → HANDLED 已处理(处置手段是工单) * 见 `BusinessCockpitEventAdapter` / `CockpitOverviewWarningSettingsService`。 * * 共用一张表的实际后果(返工前就踩了): * · `PENDING` 在预警里是「待接收」,旧表却译成「待处理」—— 同一屏两种含义; * · 报警的 `UNHANDLED`/`HANDLED` 在旧表里**根本没有词条**,直接漏英文码上大屏; * · 预警的 RECEIVED/PROCESSING/CLOSED 同理漏码。 * * ── 共用的是**形状**,不是词条 ── * 两个族的词表都走同一个 `statusVocabulary()` 构造函数(同一套字段:label/tone/terminal/ * unhandled),所以「怎么画一个状态标签」只有一份实现;而「某个码是什么意思」各族自述。 * 认不出的机器状态显示「状态未知」;协议码仍保留在领域数据中,不编造正常状态。 */ /** 状态标签的语义色键(沿用 `statusTones.js` 的四档,不新造色)。 */ const TONE = { PENDING: 'lv2', ACTIVE: 'lv3', DONE: 'lv4', NEUTRAL: 'neutral' } /** * 列表状态徽标高亮色(维护者 2026-11-13 指定): * 待接收/已接收=黄、处置中=蓝、已处置=紫、已解除=绿。 * * 与语义色键 `tone` 分开:`tone` 服务标签点/图例的中性语义,已被其它面板消费; * 这里是「设备详情预警列表」的状态高亮口径,改它不动别处。紫色无既有语义色键, * 由 tokens.css 的 --status-handled 单源给出。 */ export const STATUS_DISPLAY_TONE = { WARNING: { PENDING: 'lv2', RECEIVED: 'lv2', PROCESSING: 'lv3', HANDLED: 'handled', CLOSED: 'lv4', }, ALARM: { UNHANDLED: 'lv2', HANDLED: 'lv4', }, } /** 某族某状态的高亮色键;认不出回中性(不猜成某个真实态的颜色)。 */ export function statusDisplayTone(family, status) { const key = String(family || '').trim().toUpperCase() const code = String(status || '').trim().toUpperCase() const table = STATUS_DISPLAY_TONE[key] return (table && table[code]) || 'neutral' } /** * 预警六态(`EarlyWarningStatusEnum`,码与中文名逐条照抄后端枚举)。 * * `terminal` 只标 **CLOSED**:HANDLED(已处置)仍需核查,不是终态 —— * 这是后端注释明写的口径,也是「处置数」与「已解除数」必须分开算的依据。 */ export const WARNING_STATUS = { DRAFT: { label: '草稿', tone: TONE.NEUTRAL, terminal: false, unhandled: true }, PENDING: { label: '待接收', tone: TONE.PENDING, terminal: false, unhandled: true }, RECEIVED: { label: '已接收', tone: TONE.ACTIVE, terminal: false, unhandled: false }, PROCESSING: { label: '处置中', tone: TONE.ACTIVE, terminal: false, unhandled: false }, HANDLED: { label: '已处置', tone: TONE.ACTIVE, terminal: false, unhandled: false }, CLOSED: { label: '已解除', tone: TONE.DONE, terminal: true, unhandled: false }, } /** 报警二态(后端归一后的取值)。 */ export const ALARM_STATUS = { UNHANDLED: { label: '未处理', tone: TONE.PENDING, terminal: false, unhandled: true }, HANDLED: { label: '已处理', tone: TONE.DONE, terminal: true, unhandled: false }, } /** 族 → 词表。认不出的族回空表(调用方据此只说原码,不冒充)。 */ const VOCABULARY_BY_FAMILY = { WARNING: WARNING_STATUS, ALARM: ALARM_STATUS, } /** * 某一族的**状态词表**(唯一入口;组件与卡片都不直接认码)。 * * @param {string} family `WARNING`/`ALARM`(大小写不敏感) * @returns {object} 码 → `{label, tone, terminal, unhandled}`;族认不出回空对象 */ export function statusVocabulary(family) { const key = String(family || '').trim().toUpperCase() // 返回浅拷贝:调用方只读,但也不该拿到能改到这张表内部的原对象。 return { ...(VOCABULARY_BY_FAMILY[key] || {}) } } /** * 该族里「已了结」的状态码集合(算**处置数**用)。 * * 预警只有 CLOSED;报警只有 HANDLED。用集合而不是单个字符串, * 是因为将来任一族加终态时改这一处即可,不用去改算法。 * @param {string} family * @returns {string[]} */ export function terminalStatuses(family) { return Object.entries(statusVocabulary(family)) .filter(([, meta]) => meta.terminal === true) .map(([code]) => code) } /** * 状态码 → 展示文本。 * * 三条判定顺序(与 `localizeCodeText` 同一条思路): * 1. 本族词表命中 → 中文; * 2. 已发布中文保留;未登记机器码显示「状态未知」;空字段留空,不造状态。 * * @param {string} family `WARNING`/`ALARM` * @param {string} status 后端状态码 */ export function statusText(family, status) { const code = typeof status === 'string' ? status.trim() : '' if (!code) return '' const vocabulary = statusVocabulary(family) const meta = Object.hasOwn(vocabulary, code.toUpperCase()) ? vocabulary[code.toUpperCase()] : null return meta ? meta.label : /\p{Script=Han}/u.test(code) && !/\p{Script=Latin}/u.test(code) ? code : '状态未知' } /** * 状态码 → 语义色键(标签必须带文字,色只是辅助 —— 票 06 的纪律)。 * 认不出的码走中性灰,**不猜**成「处理中」。 */ export function statusTone(family, status) { const code = typeof status === 'string' ? status.trim() : '' if (!code) return 'neutral' const meta = statusVocabulary(family)[code] return meta ? meta.tone : 'neutral' } /** 该状态是不是本族的「已了结」终态(算处置数用)。 */ export function isTerminalStatus(family, status) { const code = typeof status === 'string' ? status.trim() : '' return code !== '' && terminalStatuses(family).includes(code) } /** 该状态是不是本族的「还没人接手」(未处理/待接收一类)。 */ export function isUnhandledStatus(family, status) { const code = typeof status === 'string' ? status.trim() : '' if (!code) return false const meta = statusVocabulary(family)[code] return !!(meta && meta.unhandled === true) }