| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- # -*- coding: utf-8 -*-
- """本体码表 — 枚举层的**单一正本** (2026-08-31)。
- ## 为什么有这个文件
- 英文版返工三轮的根因不在渲染层, 在这里: `schema.py` 原先把枚举定义成中文字面量
- (`FM_CLASSES={'磨损',...}` / `FACETS={'因侧执行链',...}`), 于是**校验闸强制所有生成器写中文** —
- 中文不是"漏译", 是被约束系统要求写进去的。产物端再怎么翻译都是治标, 且翻译自由文本必然产出
- "Verification 状态机" / "scroll 元Data" 这类混杂串 (2026-08-31 实测, 已作废)。
- ## 分层 (docs/本体数据标准.md)
- | 层 | 存什么 | 语言 |
- |---|---|---|
- | 标识层 id/key | `mechanism/WTG29/lub_starvation` | 英文 snake_case, **永不翻译** |
- | 枚举层 | `wear` / `cause_actuation` / `L2_reversible` | **英文码**, 显示时查 LABELS |
- | 数值层 | 3.07, "2026-07" | 无语言 |
- | 文本层 | name / note / decision 正文 | `_zh` + `_en` **双写**, 不靠词表替换 |
- **枚举与文本的分界是硬的**: 有限集合 ⇒ 码化(机器判, 一劳永逸);
- 自由文本 ⇒ 双写(人或模型写一次固化)。把自由文本当枚举翻译, 就是那三轮返工。
- ## 兼容
- `normalize(field, value)` 把历史中文值映射回码。**只读方向兼容, 不反向写** —
- 存量 7178 个对象保持原样(中文版在用, 不动), 新写入一律走码。
- """
- # ── 枚举码表: code → (zh, en) ──────────────────────────────────────────
- # 新增枚举值必须同时给 zh 与 en; 缺一不许进表 (缺了就会在渲染时回落成另一语言 = 残留复发)
- LABELS = {
- 'fm_class': { # ISO 14224 风格失效分类
- 'wear': ('磨损', 'Wear'),
- 'fatigue': ('疲劳', 'Fatigue'),
- 'lubrication_failure': ('润滑失效', 'Lubrication failure'),
- 'corrosion': ('腐蚀', 'Corrosion'),
- 'overheating': ('过热', 'Overheating'),
- 'fastener_failure': ('松动/紧固失效', 'Loosening / fastener failure'),
- 'contamination': ('污染/异物', 'Contamination / foreign object'),
- 'electrical_failure': ('电气失效', 'Electrical failure'),
- 'control_software': ('控制/软件', 'Control / software'),
- 'seal_failure': ('密封失效', 'Seal failure'),
- 'structural_damage': ('结构损伤', 'Structural damage'),
- 'measurement_failure': ('测量链失效', 'Measurement chain failure'),
- 'hydraulic_pneumatic': ('液压/气动失效', 'Hydraulic / pneumatic failure'),
- 'undetermined': ('未定', 'Undetermined'),
- },
- 'facet': { # 观测面 (C3: 源数按面去重, 非按证据条数)
- 'cause_actuation': ('因侧执行链', 'Cause side — actuation chain'),
- 'effect_temperature': ('果侧温度', 'Effect side — temperature'),
- 'effect_vib_steady': ('果侧振动稳态', 'Effect side — vibration, steady state'),
- 'effect_vib_transient':('果侧振动瞬态', 'Effect side — vibration, transient'),
- 'effect_oil': ('果侧油液', 'Effect side — oil'),
- 'effect_electrical': ('果侧电气', 'Effect side — electrical'),
- 'external_record': ('外部记录', 'External record'),
- 'measurement_chain': ('测量链面', 'Measurement chain'),
- 'structural': ('结构面', 'Structural'),
- 'performance': ('性能面', 'Performance'),
- },
- 'crosscheck': { # C4: 禁把"不可判"写成阴性
- 'supports': ('支持', 'Supports'),
- 'excludes': ('排除', 'Excludes'),
- 'indeterminate': ('不可判', 'Indeterminate'),
- },
- 'reversibility': { # C6: 可逆性三级
- 'L1_read_only': ('L1只读', 'L1 read-only'),
- 'L2_reversible': ('L2可逆写', 'L2 reversible write'),
- 'L3_approval': ('L3待批', 'L3 pending approval'),
- },
- 'review_tier': { # SOP §6.1 RV-1 审级
- 'lite': ('lite 单独立审', 'Lite — single independent review'),
- 'dual_model': ('双模审', 'Dual-model review'),
- 'advci_pr': ('AdvCI-PR', 'AdvCI-PR'),
- 'user_ruling': ('用户裁', 'User ruling'),
- 'field_exec': ('现场执行', 'Field execution'),
- },
- 'closure_type': { # C16 (2026-09-07, Claude 裁/用户授权 "你来定"): Verdict 归宿类 (章程铁律 1 出生带归宿; E3 四类 + E10 两格); 码 = 章程原词
- '现场验证单': ('现场验证单', 'Field verification order'),
- '补数据': ('补数据', 'Acquire data'),
- '下轮Measure': ('下轮Measure', 'Next Measure round'),
- '被后续替代': ('被后续替代', 'Superseded by later claim'),
- '已闭环/不适用': ('已闭环/不适用', 'Closed / not applicable'),
- '已有裁决/处置中': ('已有裁决/处置中', 'Already ruled / in progress'),
- },
- 'decision_status': { # C16: Decision 生命周期 (机器提议 → 人裁 → 关闭/替代)
- 'proposed': ('提议 (机器)', 'Proposed (machine)'),
- 'proposed_pending_human': ('提议待人裁', 'Proposed, pending human ruling'),
- 'decided': ('已裁', 'Decided'),
- 'closed': ('已关闭', 'Closed'),
- 'superseded': ('已被替代', 'Superseded'),
- },
- 'decision_kind': { # C16: Release 层 Decision 子类 (E9/E10)
- 'closure_proposal': ('归宿提议', 'Closure proposal'),
- 'closure_migrated': ('归宿迁移', 'Closure migrated'),
- 'screening_policy': ('普查策略', 'Screening policy'),
- },
- 'detection_method': { # C15 检出方式 — 这次故障是怎么被发现的
- # ★为什么必须有这一张表: 它是检出率/误报率/监测面有效性的**唯一直接来源**。
- # 没有它, "高速轴点蚀在振动上不可见、靠内窥镜发现" 这类结论只能靠翻台账原文
- # 事后对拍去得到 — 既贵又不可复现。
- # ★故意做短 (10 个)。现场在塔上填表, 选项超过十个就会开始乱选。
- 'scada_alarm': ('SCADA 报警', 'SCADA alarm'),
- 'cms_vibration': ('CMS 振动', 'CMS vibration'),
- 'temp_trend': ('温度趋势', 'Temperature trend'),
- 'oil_lab': ('油液化验', 'Oil laboratory analysis'),
- 'routine_check': ('例行巡检', 'Routine inspection'),
- 'borescope': ('内窥镜', 'Borescope'),
- 'incidental': ('修他件时发现', 'Found while servicing something else'),
- 'sensory': ('外观/异响', 'Visual or audible'),
- 'owner_report': ('业主指出', 'Reported by the owner'),
- # ★"不确定"必须是一个**值**而不是留空。留空分不出"没查出来"(真实诊断结论,
- # 该进检出率分母) 与"忘了填"(数据质量问题, 该剔除) — 混在一起检出率永远算不准,
- # 而检出率正是这整套体系最终要产出的那个数。
- 'unknown': ('不确定', 'Not determined'),
- },
- 'task_kind': { # C10 检修任务类型
- 'preventive': ('预防性', 'Preventive'),
- 'corrective': ('抢修', 'Corrective / breakdown'),
- 'inspection': ('检查', 'Inspection'),
- 'rectify': ('整改', 'Rectification'),
- },
- 'part': { # 部件码 (台账部位名 → 码; 标识层用它拼 id)
- 'bolt': ('螺栓', 'Bolt'),
- 'yaw_brake_pad': ('偏航刹车片', 'Yaw brake pad'),
- 'brake_pad': ('刹车片', 'Brake pad'),
- 'yaw_motor': ('偏航电机', 'Yaw motor'),
- 'yaw_inverter': ('偏航变频器', 'Yaw inverter'),
- 'main_breaker': ('主断路器', 'Main circuit breaker'),
- 'slip_ring': ('滑环', 'Slip ring'),
- 'electrical_slip_ring': ('电气滑环', 'Electrical slip ring'),
- 'capacitor': ('电容', 'Capacitor'),
- 'power_module': ('电源模块', 'Power module'),
- 'stic_processor': ('STIC处理器', 'STIC processor'),
- 'cooling_fan': ('散热风扇', 'Cooling fan'),
- 'fan': ('风扇', 'Fan'),
- 'oil_pipe': ('油管', 'Oil pipe'),
- 'anemometer': ('风速仪', 'Anemometer'),
- 'igbt': ('IGBT', 'IGBT'),
- # 2025-2026 工单接入后新出现的部件 (闸拦下来才补的, 不是预先猜的)
- 'generator_lube_pump': ('发电机润滑泵', 'Generator lubrication pump'),
- 'motor': ('电机', 'Motor'),
- },
- 'maturity_dim': { # 运维成熟度四维 (docs/运维可靠性方法论.md)
- 'evidence_completeness': ('证据完整', 'Evidence completeness'),
- 'closure_verification': ('闭环验证', 'Closure verification'),
- 'recurrence_control': ('复发控制', 'Recurrence control'),
- 'commonality_identification': ('共性识别', 'Commonality identification'),
- },
- 'maturity_stage': { # 成熟度五级阶梯
- 'reactive': ('1 被动抢修', '1 — Reactive'),
- 'planned': ('2 计划维修', '2 — Planned'),
- 'condition': ('3 状态维修', '3 — Condition-based'),
- 'predictive': ('4 预测维修', '4 — Predictive'),
- 'reliability':('5 可靠性驱动', '5 — Reliability-driven'),
- },
- # ★grade 是**结论级别** (这条结论有多硬), 不是设备状态 (机器多健康)。
- # 设备状态的英文按 ISO 17359 / ISO 20816 走, 见 src/windscada/ui_en.py 的说明;
- # 两者混用会让"预警"这类词在两种语境下指不同的东西。
- 'grade': { # SOP §0.2 结论六枚举
- 'established': ('定论', 'Established'),
- 'early_warning': ('准定论·预警', 'Near-established — early warning'),
- 'candidate': ('候选', 'Candidate'),
- 'reference': ('参考', 'Reference'),
- 'insufficient': ('INSUFFICIENT', 'Insufficient evidence'),
- 'withdrawn': ('撤回', 'Withdrawn'),
- },
- # ★2026-08-31 增: count 的计数单位。
- # 为什么必须码化 —— C12 早就强制"带 count 必须声明 count_basis", 但**只查有没有,
- # 不查填了什么**。结果是这个字段被填成"手边最近的那个词": 实测 5 条 finding 里 3 条错标
- # (35 台/37 台被标成 work_orders, 59 个长停事件被标成 work_sessions)。
- # **一个必填但不校验取值的字段, 等于没设防** —— 它给了"已声明口径"的假象,
- # 而 C12 存在的全部意义就是防"同一事实两个数"。
- 'count_basis': {
- 'work_orders': ('工单条数', 'work orders'),
- 'work_sessions': ('作业次数', 'work sessions'),
- 'turbines': ('机组台数', 'turbines'),
- 'events': ('事件数', 'events'),
- 'records': ('记录条数', 'records'),
- 'samples': ('样本数', 'samples'),
- 'documents': ('文档份数', 'documents'),
- },
- }
- # ── 历史中文值 → 码 (只读兼容; 存量对象不改写) ────────────────────────
- _ALIAS = {(f, zh): c for f, m in LABELS.items() for c, (zh, _en) in m.items()}
- _ALIAS.update({
- ('review_tier', 'lite'): 'lite', # 原枚举里本就是英文的两个
- ('review_tier', 'AdvCI-PR'): 'advci_pr',
- ('grade', 'INSUFFICIENT'): 'insufficient',
- ('grade', '准定论'): 'early_warning',
- ('grade', '预警'): 'early_warning',
- # 历史截短写法 (旧 ingest 存进库的是 '处理器', 判据实际输出 'STIC处理器')
- ('part', '处理器'): 'stic_processor',
- })
- CODES = {f: set(m) for f, m in LABELS.items()}
- def normalize(field, value):
- """历史中文值 → 码; 已是码则原样返回; 无法映射返回 None (响亮, 不静默塞回原值)。"""
- if value is None:
- return None
- if field in CODES and value in CODES[field]:
- return value
- hit = _ALIAS.get((field, value))
- if hit:
- return hit
- # ★2026-08-31 增三档归一。存量值实测有三类"其实能映射但差一点"的:
- # ① 尾随/前导空格 ('IGBT ' ×10) ② 大小写 ('stic'/'STIC' ×6)
- # ③ 码前缀简写 ('L1' → 'L1_read_only' ×26, 可逆性三档)
- # 这三类不是新语义, 是**同一个值的书写变体**; 不归一就白白落进"无法映射",
- # 让英文投影退回中文。归一只做这三档, 不做模糊匹配 —— 模糊匹配会静默塞错码。
- v = str(value).strip()
- if v != value:
- hit = normalize(field, v)
- if hit:
- return hit
- if field in CODES:
- low = v.lower()
- for c in CODES[field]:
- if c.lower() == low:
- return c
- if '_' in c and c.split('_', 1)[0].lower() == low: # L1 → L1_read_only
- return c
- for c, (zh, _en) in LABELS.get(field, {}).items():
- if zh.strip().lower() == low:
- return c
- return None
- def label(field, code, lang='zh'):
- """码 → 显示文本。**查不到不回落到另一语言** —— 回落会让缺口永远不被发现,
- 正是英文版残留三轮没被逮住的机制 (docs/本体数据标准.md §4)。"""
- m = LABELS.get(field, {}).get(code)
- if not m:
- return f'[{field}:{code}]'
- return m[0] if lang == 'zh' else m[1]
- def text(props, key, lang='zh'):
- """文本层取值: 优先 `key_zh`/`key_en`, 回落裸 `key`(存量对象)。
- 英文侧取不到 `_en` 时返回 `[translation pending]` 而非中文原文 —— 同上, 缺口必须可见。"""
- v = props.get(f'{key}_{lang}')
- if v:
- return v
- bare = props.get(key)
- if lang == 'zh':
- return bare
- return '[translation pending]' if bare else None
|