@dazitech/cli 3.0.9 → 3.1.1

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/dist/clis/dazi-app.js +2 -2
  3. package/dist/clis/dazi-flow.js +2 -2
  4. package/dist/clis/dazi-onto.js +324 -41
  5. package/dist/clis/dazi.js +407 -185
  6. package/dist/docs/flow/flow-project-guide.md +1 -1
  7. package/dist/docs/guides/cli-reference.md +16 -3
  8. package/dist/docs/guides/troubleshooting.md +3 -3
  9. package/dist/docs/index.json +3 -15
  10. package/dist/docs/onto/dazi_script_sdk_reference.md +246 -244
  11. package/dist/docs/onto/dazi_script_seed_data_guide.md +1 -1
  12. package/dist/docs/onto/function-guide.md +123 -123
  13. package/dist/docs/onto//346/234/254/344/275/223/345/210/206/347/261/273/350/247/204/345/210/222/344/270/216SDK/346/211/251/345/261/225/346/226/271/346/241/210.md +169 -168
  14. package/dist/docs/onto//346/234/254/344/275/223/345/221/275/345/220/215/350/247/204/350/214/203_/347/211/251/347/220/206/350/241/250Cube/344/270/216/345/257/271/350/261/241.md +403 -402
  15. package/dist/docs/onto//346/234/254/344/275/223/345/274/200/345/217/221/344/274/230/345/214/226/346/200/273/347/273/223.md +257 -0
  16. package/dist/docs/onto//346/234/254/344/275/223/350/204/232/346/234/254/347/274/226/345/206/231/346/214/207/345/215/227.md +339 -311
  17. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +305 -281
  18. package/dist/docs/onto//350/204/232/346/234/254/350/277/220/350/241/214/345/270/270/350/247/201/351/224/231/350/257/257/345/244/204/347/220/206.md +297 -0
  19. package/dist/examples/index.json +222 -6
  20. package/dist/examples/onto/README.md +34 -36
  21. package/dist/examples/onto/_templates/onto_preflight.ps1 +84 -0
  22. package/dist/examples/onto/index.json +53 -0
  23. package/dist/examples/onto/index.yaml +29 -0
  24. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/README.md +23 -0
  25. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/save_test_arguments.ps1 +12 -11
  26. package/dist/{docs/onto → examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/plans}//350/247/204/345/210/222/347/244/272/344/276/213_/345/210/251/346/266/246/345/210/206/346/236/220/346/234/254/344/275/223/346/226/271/346/241/210.md +37 -35
  27. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_category_mount.py +85 -0
  28. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +3 -66
  29. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/README.md +24 -0
  30. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_availability_analysis.py +84 -0
  31. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_downtime_breakdown.py +119 -0
  32. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_energy_intensity.py +98 -0
  33. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_get_summary.py +125 -0
  34. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_maintenance_compliance.py +77 -0
  35. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_mom_analysis.py +118 -0
  36. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_oee_analysis.py +126 -0
  37. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_plan_vs_actual.py +105 -0
  38. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_top_fault_equipment.py +104 -0
  39. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_unit_comparison.py +120 -0
  40. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/equip_ops_fn_yoy_analysis.py +115 -0
  41. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/save_test_arguments.ps1 +42 -0
  42. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.availability_analysis.json +7 -0
  43. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.downtime_breakdown.json +8 -0
  44. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.energy_intensity.json +8 -0
  45. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.get_summary.json +7 -0
  46. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.maintenance_compliance.json +7 -0
  47. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.mom_analysis.json +8 -0
  48. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.oee_analysis.json +8 -0
  49. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.plan_vs_actual.json +8 -0
  50. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.top_fault_equipment.json +8 -0
  51. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.unit_comparison.json +8 -0
  52. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/test_arguments/equip_ops.fn.yoy_analysis.json +8 -0
  53. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/plans//345/214/226/345/267/245/350/256/276/345/244/207/350/277/220/350/220/245/345/210/206/346/236/220/346/234/254/344/275/223/346/226/271/346/241/210.md +735 -0
  54. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/setup/equip_ops_category_mount.py +106 -0
  55. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/setup/equip_ops_ontology_init.py +1077 -0
  56. package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/setup/equip_ops_seed_data.py +552 -0
  57. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/README.md +23 -0
  58. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +13 -12
  59. package/dist/{docs/onto → examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/plans}//350/247/204/345/210/222/347/244/272/344/276/213_/344/272/247/345/223/201/351/224/200/345/224/256/346/234/254/344/275/223/350/247/204/345/210/222/346/226/271/346/241/210.md +34 -34
  60. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_category_mount.py +82 -0
  61. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +3 -54
  62. package/dist/prompts/index.json +8 -1
  63. package/dist/prompts/onto/function-design.md +73 -73
  64. package/dist/prompts/onto/planning-design.md +226 -0
  65. package/dist/prompts/onto/script-publish-run.md +231 -208
  66. package/package.json +1 -1
  67. package/dist/docs/onto//350/204/232/346/234/254/350/277/220/350/241/214/347/272/240/351/224/231_/345/225/206/345/212/241/346/210/220/346/234/254/346/226/271/346/241/210/345/274/200/345/217/221/350/277/207/347/250/213.md +0 -213
@@ -0,0 +1,1077 @@
1
+ """化工设备运营分析本体初始化脚本 — space_cate_test01
2
+
3
+ 初始化内容:
4
+ 1. 创建物理表(5 维 + 4 事实,不含 dim_date)
5
+ 2. 注册表到空间(含 display_name / description)
6
+ 3. 注册表间关系(16 条,含 4 条 fact→dim_date)
7
+ 4. 注册 Cube(7 个)及派生度量
8
+ 5. 定义对象类型(10 种)、绑定数据源、属性、链接(16 种)
9
+ 6. 同步指标引用
10
+ 7. 输出 JSON summary
11
+
12
+ 不含 apply_registry(分类在 equip_ops_category_mount.py)。
13
+
14
+ 放置:项目/DAZI_TEST/本体/ontos/设备运营/setup/equip_ops_ontology_init.py
15
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/setup/equip_ops_ontology_init.py --space space_cate_test01 --type setup
16
+ 规划对照:项目/DAZI_TEST/本体/ontos/设备运营/plans/化工设备运营分析本体方案.md
17
+ """
18
+
19
+ import json
20
+
21
+ # 与规划文档 §2 对齐:display_name=侧栏显示名,description=业务说明
22
+ TABLE_REGISTRY = {
23
+ "dim_plant": {
24
+ "display_name": "厂区维表",
25
+ "description": "化工生产厂区或大型装置区主数据",
26
+ "columns": [
27
+ {"name": "plant_id", "display_name": "厂区 ID", "description": "主键"},
28
+ {"name": "plant_code", "display_name": "厂区编码"},
29
+ {"name": "plant_name", "display_name": "厂区名称"},
30
+ {"name": "company_code", "display_name": "公司代码"},
31
+ {"name": "plant_type", "display_name": "装置类型", "description": "炼油/烯烃/芳烃/精细化工"},
32
+ {"name": "location", "display_name": "地理位置"},
33
+ {"name": "design_capacity", "display_name": "设计产能"},
34
+ {"name": "capacity_unit", "display_name": "产能单位"},
35
+ {"name": "status", "display_name": "状态", "description": "运行/检修/停产"},
36
+ {"name": "created_at", "display_name": "创建时间"},
37
+ ],
38
+ },
39
+ "dim_process_unit": {
40
+ "display_name": "工艺单元维表",
41
+ "description": "装置内工艺单元(蒸馏、反应、压缩等工段)",
42
+ "columns": [
43
+ {"name": "unit_id", "display_name": "单元 ID", "description": "主键"},
44
+ {"name": "unit_code", "display_name": "单元编码"},
45
+ {"name": "unit_name", "display_name": "单元名称"},
46
+ {"name": "plant_id", "display_name": "所属厂区", "description": "关联 dim_plant"},
47
+ {"name": "plant_name", "display_name": "厂区名称", "description": "冗余"},
48
+ {"name": "unit_type", "display_name": "单元类型", "description": "反应/分离/换热/公用工程"},
49
+ {"name": "criticality", "display_name": "关键等级", "description": "A/B/C"},
50
+ {"name": "status", "display_name": "状态"},
51
+ {"name": "created_at", "display_name": "创建时间"},
52
+ ],
53
+ },
54
+ "dim_equipment_type": {
55
+ "display_name": "设备类型维表",
56
+ "description": "设备分类主数据(泵、压缩机、反应釜、塔器等)",
57
+ "columns": [
58
+ {"name": "equip_type_id", "display_name": "类型 ID", "description": "主键"},
59
+ {"name": "equip_type_code", "display_name": "类型编码"},
60
+ {"name": "equip_type_name", "display_name": "类型名称"},
61
+ {"name": "category", "display_name": "大类", "description": "动设备/静设备/仪表/电气"},
62
+ {"name": "parent_type_id", "display_name": "上级类型", "description": "自关联"},
63
+ {"name": "type_level", "display_name": "层级"},
64
+ {"name": "is_leaf", "display_name": "末级"},
65
+ {"name": "status", "display_name": "状态"},
66
+ {"name": "created_at", "display_name": "创建时间"},
67
+ ],
68
+ },
69
+ "dim_equipment": {
70
+ "display_name": "设备主数据",
71
+ "description": "单台设备台账;OEE 与停机分析的核心维度",
72
+ "columns": [
73
+ {"name": "equipment_id", "display_name": "设备 ID", "description": "主键"},
74
+ {"name": "equipment_code", "display_name": "设备位号", "description": "如 P-101A"},
75
+ {"name": "equipment_name", "display_name": "设备名称"},
76
+ {"name": "equip_type_id", "display_name": "设备类型", "description": "关联 dim_equipment_type"},
77
+ {"name": "equip_type_name", "display_name": "类型名称", "description": "冗余"},
78
+ {"name": "category", "display_name": "设备大类", "description": "冗余"},
79
+ {"name": "plant_id", "display_name": "所属厂区", "description": "关联 dim_plant"},
80
+ {"name": "plant_name", "display_name": "厂区名称", "description": "冗余"},
81
+ {"name": "unit_id", "display_name": "所属单元", "description": "关联 dim_process_unit"},
82
+ {"name": "unit_name", "display_name": "单元名称", "description": "冗余"},
83
+ {"name": "manufacturer", "display_name": "制造商"},
84
+ {"name": "model", "display_name": "型号"},
85
+ {"name": "install_date", "display_name": "投运日期"},
86
+ {"name": "design_capacity", "display_name": "设计能力"},
87
+ {"name": "capacity_unit", "display_name": "能力单位", "description": "t/h、m³/h 等"},
88
+ {"name": "criticality", "display_name": "关键等级", "description": "A/B/C"},
89
+ {"name": "production_mode", "display_name": "生产模式", "description": "连续/间歇"},
90
+ {"name": "status", "display_name": "状态", "description": "运行/备用/检修/报废"},
91
+ {"name": "created_at", "display_name": "创建时间"},
92
+ ],
93
+ },
94
+ "dim_downtime_reason": {
95
+ "display_name": "停机原因维表",
96
+ "description": "停机/故障原因码表",
97
+ "columns": [
98
+ {"name": "reason_id", "display_name": "原因 ID", "description": "主键"},
99
+ {"name": "reason_code", "display_name": "原因编码"},
100
+ {"name": "reason_name", "display_name": "原因名称"},
101
+ {"name": "reason_category", "display_name": "原因大类", "description": "机械/电气/仪表/工艺/计划检修/外部"},
102
+ {"name": "is_planned", "display_name": "是否计划停机", "description": "0/1"},
103
+ {"name": "parent_reason_id", "display_name": "上级原因", "description": "自关联"},
104
+ {"name": "status", "display_name": "状态"},
105
+ {"name": "created_at", "display_name": "创建时间"},
106
+ ],
107
+ },
108
+ "fact_equipment_daily_ops": {
109
+ "display_name": "设备日运行汇总",
110
+ "description": "每台设备每日运行 KPI 汇总;OEE 计算主源",
111
+ "columns": [
112
+ {"name": "ops_id", "display_name": "汇总 ID", "description": "主键"},
113
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date,YYYYMMDD"},
114
+ {"name": "calendar_date", "display_name": "统计日期"},
115
+ {"name": "equipment_id", "display_name": "设备 ID", "description": "关联 dim_equipment"},
116
+ {"name": "equipment_code", "display_name": "设备位号", "description": "冗余"},
117
+ {"name": "equipment_name", "display_name": "设备名称", "description": "冗余"},
118
+ {"name": "plant_id", "display_name": "厂区 ID", "description": "冗余"},
119
+ {"name": "plant_name", "display_name": "厂区名称", "description": "冗余"},
120
+ {"name": "unit_id", "display_name": "单元 ID", "description": "冗余"},
121
+ {"name": "unit_name", "display_name": "单元名称", "description": "冗余"},
122
+ {"name": "equip_type_id", "display_name": "设备类型", "description": "冗余"},
123
+ {"name": "category", "display_name": "设备大类", "description": "冗余"},
124
+ {"name": "calendar_minutes", "display_name": "日历时间", "description": "分钟"},
125
+ {"name": "planned_downtime_min", "display_name": "计划停机", "description": "分钟"},
126
+ {"name": "unplanned_downtime_min", "display_name": "非计划停机", "description": "分钟"},
127
+ {"name": "runtime_min", "display_name": "运行时间", "description": "分钟"},
128
+ {"name": "idle_min", "display_name": "待机时间", "description": "分钟"},
129
+ {"name": "planned_output_qty", "display_name": "计划产量"},
130
+ {"name": "actual_output_qty", "display_name": "实际产量"},
131
+ {"name": "qualified_output_qty", "display_name": "合格产量"},
132
+ {"name": "output_unit", "display_name": "产量单位"},
133
+ {"name": "ideal_cycle_rate", "display_name": "理想节拍", "description": "单位/分钟"},
134
+ {"name": "energy_consumption", "display_name": "能耗", "description": "kWh 或 GJ"},
135
+ {"name": "energy_unit", "display_name": "能耗单位"},
136
+ {"name": "shift_code", "display_name": "班次", "description": "早/中/晚/全天"},
137
+ {"name": "data_source", "display_name": "数据来源", "description": "DCS/MES/手工"},
138
+ {"name": "created_at", "display_name": "创建时间"},
139
+ ],
140
+ },
141
+ "fact_downtime_event": {
142
+ "display_name": "停机事件明细",
143
+ "description": "单次停机/故障事件流水",
144
+ "columns": [
145
+ {"name": "event_id", "display_name": "事件 ID", "description": "主键"},
146
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date(事件开始日)"},
147
+ {"name": "equipment_id", "display_name": "设备 ID", "description": "关联 dim_equipment"},
148
+ {"name": "equipment_code", "display_name": "设备位号", "description": "冗余"},
149
+ {"name": "equipment_name", "display_name": "设备名称", "description": "冗余"},
150
+ {"name": "plant_id", "display_name": "厂区 ID", "description": "冗余"},
151
+ {"name": "unit_id", "display_name": "单元 ID", "description": "冗余"},
152
+ {"name": "reason_id", "display_name": "停机原因", "description": "关联 dim_downtime_reason"},
153
+ {"name": "reason_code", "display_name": "原因编码", "description": "冗余"},
154
+ {"name": "reason_name", "display_name": "原因名称", "description": "冗余"},
155
+ {"name": "reason_category", "display_name": "原因大类", "description": "冗余"},
156
+ {"name": "is_planned", "display_name": "是否计划停机", "description": "0/1"},
157
+ {"name": "start_time", "display_name": "开始时间"},
158
+ {"name": "end_time", "display_name": "结束时间"},
159
+ {"name": "duration_min", "display_name": "停机时长", "description": "分钟"},
160
+ {"name": "impact_level", "display_name": "影响等级", "description": "高/中/低"},
161
+ {"name": "responsible_dept", "display_name": "责任部门", "description": "机动/电气/仪表/生产"},
162
+ {"name": "description", "display_name": "事件描述"},
163
+ {"name": "created_at", "display_name": "创建时间"},
164
+ ],
165
+ },
166
+ "fact_maintenance_record": {
167
+ "display_name": "维保记录",
168
+ "description": "计划与实际维保作业记录",
169
+ "columns": [
170
+ {"name": "maint_id", "display_name": "维保 ID", "description": "主键"},
171
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date(计划或完成日)"},
172
+ {"name": "equipment_id", "display_name": "设备 ID", "description": "关联 dim_equipment"},
173
+ {"name": "equipment_code", "display_name": "设备位号", "description": "冗余"},
174
+ {"name": "plant_id", "display_name": "厂区 ID", "description": "冗余"},
175
+ {"name": "unit_id", "display_name": "单元 ID", "description": "冗余"},
176
+ {"name": "maint_type", "display_name": "维保类型", "description": "预防/预测/故障维修/大修"},
177
+ {"name": "plan_date", "display_name": "计划日期"},
178
+ {"name": "actual_date", "display_name": "实际完成日期", "description": "可空"},
179
+ {"name": "plan_hours", "display_name": "计划工时"},
180
+ {"name": "actual_hours", "display_name": "实际工时"},
181
+ {"name": "plan_cost", "display_name": "计划费用"},
182
+ {"name": "actual_cost", "display_name": "实际费用"},
183
+ {"name": "status", "display_name": "状态", "description": "计划/进行中/完成/逾期"},
184
+ {"name": "is_on_schedule", "display_name": "是否按期", "description": "1=按期完成"},
185
+ {"name": "vendor", "display_name": "维保单位"},
186
+ {"name": "description", "display_name": "作业内容"},
187
+ {"name": "created_at", "display_name": "创建时间"},
188
+ ],
189
+ },
190
+ "fact_equipment_plan": {
191
+ "display_name": "设备运行计划",
192
+ "description": "计划运行时间/产量,用于计划 vs 实际对比",
193
+ "columns": [
194
+ {"name": "plan_id", "display_name": "计划 ID", "description": "主键"},
195
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date"},
196
+ {"name": "equipment_id", "display_name": "设备 ID", "description": "关联 dim_equipment"},
197
+ {"name": "equipment_code", "display_name": "设备位号", "description": "冗余"},
198
+ {"name": "plant_id", "display_name": "厂区 ID", "description": "冗余"},
199
+ {"name": "unit_id", "display_name": "单元 ID", "description": "冗余"},
200
+ {"name": "plan_version", "display_name": "计划版本", "description": "如 2026月度计划"},
201
+ {"name": "fiscal_year", "display_name": "计划年度"},
202
+ {"name": "fiscal_month", "display_name": "计划月份", "description": "1-12"},
203
+ {"name": "planned_runtime_min", "display_name": "计划运行时间", "description": "分钟"},
204
+ {"name": "planned_output_qty", "display_name": "计划产量"},
205
+ {"name": "planned_energy", "display_name": "计划能耗"},
206
+ {"name": "output_unit", "display_name": "产量单位"},
207
+ {"name": "status", "display_name": "状态", "description": "草稿/已发布"},
208
+ {"name": "created_at", "display_name": "创建时间"},
209
+ ],
210
+ },
211
+ }
212
+
213
+
214
+ def main():
215
+ space_id = "space_cate_test01"
216
+ s = space.get(space_id)
217
+
218
+ output.print("=== 化工设备运营分析本体初始化 ===")
219
+ output.print(f"空间: {space_id}")
220
+
221
+ # 1. 创建物理表
222
+ output.print("\n[1/8] 创建物理表...")
223
+
224
+ s.sql.execute("""
225
+ CREATE TABLE IF NOT EXISTS dim_plant (
226
+ plant_id String,
227
+ plant_code String,
228
+ plant_name String,
229
+ company_code String,
230
+ plant_type String,
231
+ location String,
232
+ design_capacity Float64,
233
+ capacity_unit String,
234
+ status String,
235
+ created_at DateTime DEFAULT now()
236
+ ) ENGINE = MergeTree()
237
+ ORDER BY (plant_code)
238
+ """)
239
+ output.print("OK dim_plant")
240
+
241
+ s.sql.execute("""
242
+ CREATE TABLE IF NOT EXISTS dim_process_unit (
243
+ unit_id String,
244
+ unit_code String,
245
+ unit_name String,
246
+ plant_id String,
247
+ plant_name String,
248
+ unit_type String,
249
+ criticality String,
250
+ status String,
251
+ created_at DateTime DEFAULT now()
252
+ ) ENGINE = MergeTree()
253
+ ORDER BY (plant_id, unit_code)
254
+ """)
255
+ output.print("OK dim_process_unit")
256
+
257
+ s.sql.execute("""
258
+ CREATE TABLE IF NOT EXISTS dim_equipment_type (
259
+ equip_type_id String,
260
+ equip_type_code String,
261
+ equip_type_name String,
262
+ category String,
263
+ parent_type_id String,
264
+ type_level Int32,
265
+ is_leaf Boolean,
266
+ status String,
267
+ created_at DateTime DEFAULT now()
268
+ ) ENGINE = MergeTree()
269
+ ORDER BY (equip_type_code)
270
+ """)
271
+ output.print("OK dim_equipment_type")
272
+
273
+ s.sql.execute("""
274
+ CREATE TABLE IF NOT EXISTS dim_equipment (
275
+ equipment_id String,
276
+ equipment_code String,
277
+ equipment_name String,
278
+ equip_type_id String,
279
+ equip_type_name String,
280
+ category String,
281
+ plant_id String,
282
+ plant_name String,
283
+ unit_id String,
284
+ unit_name String,
285
+ manufacturer String,
286
+ model String,
287
+ install_date Date,
288
+ design_capacity Float64,
289
+ capacity_unit String,
290
+ criticality String,
291
+ production_mode String,
292
+ status String,
293
+ created_at DateTime DEFAULT now()
294
+ ) ENGINE = MergeTree()
295
+ ORDER BY (plant_id, unit_id, equipment_code)
296
+ """)
297
+ output.print("OK dim_equipment")
298
+
299
+ s.sql.execute("""
300
+ CREATE TABLE IF NOT EXISTS dim_downtime_reason (
301
+ reason_id String,
302
+ reason_code String,
303
+ reason_name String,
304
+ reason_category String,
305
+ is_planned UInt8,
306
+ parent_reason_id String,
307
+ status String,
308
+ created_at DateTime DEFAULT now()
309
+ ) ENGINE = MergeTree()
310
+ ORDER BY (reason_code)
311
+ """)
312
+ output.print("OK dim_downtime_reason")
313
+
314
+ s.sql.execute("""
315
+ CREATE TABLE IF NOT EXISTS fact_equipment_daily_ops (
316
+ ops_id String,
317
+ date_key Int32,
318
+ calendar_date Date,
319
+ equipment_id String,
320
+ equipment_code String,
321
+ equipment_name String,
322
+ plant_id String,
323
+ plant_name String,
324
+ unit_id String,
325
+ unit_name String,
326
+ equip_type_id String,
327
+ category String,
328
+ calendar_minutes Float64,
329
+ planned_downtime_min Float64,
330
+ unplanned_downtime_min Float64,
331
+ runtime_min Float64,
332
+ idle_min Float64,
333
+ planned_output_qty Float64,
334
+ actual_output_qty Float64,
335
+ qualified_output_qty Float64,
336
+ output_unit String,
337
+ ideal_cycle_rate Float64,
338
+ energy_consumption Float64,
339
+ energy_unit String,
340
+ shift_code String,
341
+ data_source String,
342
+ created_at DateTime DEFAULT now()
343
+ ) ENGINE = MergeTree()
344
+ ORDER BY (date_key, equipment_id, shift_code)
345
+ """)
346
+ output.print("OK fact_equipment_daily_ops")
347
+
348
+ s.sql.execute("""
349
+ CREATE TABLE IF NOT EXISTS fact_downtime_event (
350
+ event_id String,
351
+ date_key Int32,
352
+ equipment_id String,
353
+ equipment_code String,
354
+ equipment_name String,
355
+ plant_id String,
356
+ unit_id String,
357
+ reason_id String,
358
+ reason_code String,
359
+ reason_name String,
360
+ reason_category String,
361
+ is_planned UInt8,
362
+ start_time DateTime,
363
+ end_time DateTime,
364
+ duration_min Float64,
365
+ impact_level String,
366
+ responsible_dept String,
367
+ description String,
368
+ created_at DateTime DEFAULT now()
369
+ ) ENGINE = MergeTree()
370
+ ORDER BY (date_key, equipment_id, start_time)
371
+ """)
372
+ output.print("OK fact_downtime_event")
373
+
374
+ s.sql.execute("""
375
+ CREATE TABLE IF NOT EXISTS fact_maintenance_record (
376
+ maint_id String,
377
+ date_key Int32,
378
+ equipment_id String,
379
+ equipment_code String,
380
+ plant_id String,
381
+ unit_id String,
382
+ maint_type String,
383
+ plan_date Date,
384
+ actual_date Nullable(Date),
385
+ plan_hours Float64,
386
+ actual_hours Float64,
387
+ plan_cost Float64,
388
+ actual_cost Float64,
389
+ status String,
390
+ is_on_schedule UInt8,
391
+ vendor String,
392
+ description String,
393
+ created_at DateTime DEFAULT now()
394
+ ) ENGINE = MergeTree()
395
+ ORDER BY (date_key, equipment_id, maint_id)
396
+ """)
397
+ output.print("OK fact_maintenance_record")
398
+
399
+ s.sql.execute("""
400
+ CREATE TABLE IF NOT EXISTS fact_equipment_plan (
401
+ plan_id String,
402
+ date_key Int32,
403
+ equipment_id String,
404
+ equipment_code String,
405
+ plant_id String,
406
+ unit_id String,
407
+ plan_version String,
408
+ fiscal_year Int32,
409
+ fiscal_month Int32,
410
+ planned_runtime_min Float64,
411
+ planned_output_qty Float64,
412
+ planned_energy Float64,
413
+ output_unit String,
414
+ status String,
415
+ created_at DateTime DEFAULT now()
416
+ ) ENGINE = MergeTree()
417
+ ORDER BY (fiscal_year, fiscal_month, equipment_id, plan_id)
418
+ """)
419
+ output.print("OK fact_equipment_plan")
420
+
421
+ # 2. 注册表(含 display_name / description)
422
+ output.print("\n[2/8] 注册表到空间...")
423
+
424
+ for tbl_name, meta in TABLE_REGISTRY.items():
425
+ s.tables.register_with_meta(
426
+ table_name=tbl_name,
427
+ display_name=meta["display_name"],
428
+ description=meta.get("description"),
429
+ columns=meta["columns"],
430
+ force_column_meta=True,
431
+ )
432
+ output.print(f"OK {tbl_name} ({meta['display_name']})")
433
+
434
+ # 3. 注册表间关系(16 条,规划 §三)
435
+ output.print("\n[3/8] 注册表间关系...")
436
+
437
+ table_relationships = [
438
+ {
439
+ "from_table": "fact_equipment_daily_ops",
440
+ "to_table": "dim_date",
441
+ "join_sql": "fact_equipment_daily_ops.date_key = dim_date.date_key",
442
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
443
+ "relationship_type": "many_to_one",
444
+ "description": "日运行→日历",
445
+ },
446
+ {
447
+ "from_table": "fact_downtime_event",
448
+ "to_table": "dim_date",
449
+ "join_sql": "fact_downtime_event.date_key = dim_date.date_key",
450
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
451
+ "relationship_type": "many_to_one",
452
+ "description": "停机→日历",
453
+ },
454
+ {
455
+ "from_table": "fact_maintenance_record",
456
+ "to_table": "dim_date",
457
+ "join_sql": "fact_maintenance_record.date_key = dim_date.date_key",
458
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
459
+ "relationship_type": "many_to_one",
460
+ "description": "维保→日历",
461
+ },
462
+ {
463
+ "from_table": "fact_equipment_plan",
464
+ "to_table": "dim_date",
465
+ "join_sql": "fact_equipment_plan.date_key = dim_date.date_key",
466
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
467
+ "relationship_type": "many_to_one",
468
+ "description": "计划→日历",
469
+ },
470
+ {
471
+ "from_table": "dim_process_unit",
472
+ "to_table": "dim_plant",
473
+ "join_sql": "dim_process_unit.plant_id = dim_plant.plant_id",
474
+ "join_keys": [{"from": "plant_id", "to": "plant_id"}],
475
+ "relationship_type": "many_to_one",
476
+ "description": "单元→厂区",
477
+ },
478
+ {
479
+ "from_table": "dim_equipment",
480
+ "to_table": "dim_equipment_type",
481
+ "join_sql": "dim_equipment.equip_type_id = dim_equipment_type.equip_type_id",
482
+ "join_keys": [{"from": "equip_type_id", "to": "equip_type_id"}],
483
+ "relationship_type": "many_to_one",
484
+ "description": "设备→类型",
485
+ },
486
+ {
487
+ "from_table": "dim_equipment",
488
+ "to_table": "dim_plant",
489
+ "join_sql": "dim_equipment.plant_id = dim_plant.plant_id",
490
+ "join_keys": [{"from": "plant_id", "to": "plant_id"}],
491
+ "relationship_type": "many_to_one",
492
+ "description": "设备→厂区",
493
+ },
494
+ {
495
+ "from_table": "dim_equipment",
496
+ "to_table": "dim_process_unit",
497
+ "join_sql": "dim_equipment.unit_id = dim_process_unit.unit_id",
498
+ "join_keys": [{"from": "unit_id", "to": "unit_id"}],
499
+ "relationship_type": "many_to_one",
500
+ "description": "设备→单元",
501
+ },
502
+ {
503
+ "from_table": "fact_equipment_daily_ops",
504
+ "to_table": "dim_equipment",
505
+ "join_sql": "fact_equipment_daily_ops.equipment_id = dim_equipment.equipment_id",
506
+ "join_keys": [{"from": "equipment_id", "to": "equipment_id"}],
507
+ "relationship_type": "many_to_one",
508
+ "description": "日运行→设备",
509
+ },
510
+ {
511
+ "from_table": "fact_downtime_event",
512
+ "to_table": "dim_equipment",
513
+ "join_sql": "fact_downtime_event.equipment_id = dim_equipment.equipment_id",
514
+ "join_keys": [{"from": "equipment_id", "to": "equipment_id"}],
515
+ "relationship_type": "many_to_one",
516
+ "description": "停机→设备",
517
+ },
518
+ {
519
+ "from_table": "fact_downtime_event",
520
+ "to_table": "dim_downtime_reason",
521
+ "join_sql": "fact_downtime_event.reason_id = dim_downtime_reason.reason_id",
522
+ "join_keys": [{"from": "reason_id", "to": "reason_id"}],
523
+ "relationship_type": "many_to_one",
524
+ "description": "停机→原因",
525
+ },
526
+ {
527
+ "from_table": "fact_maintenance_record",
528
+ "to_table": "dim_equipment",
529
+ "join_sql": "fact_maintenance_record.equipment_id = dim_equipment.equipment_id",
530
+ "join_keys": [{"from": "equipment_id", "to": "equipment_id"}],
531
+ "relationship_type": "many_to_one",
532
+ "description": "维保→设备",
533
+ },
534
+ {
535
+ "from_table": "fact_equipment_plan",
536
+ "to_table": "dim_equipment",
537
+ "join_sql": "fact_equipment_plan.equipment_id = dim_equipment.equipment_id",
538
+ "join_keys": [{"from": "equipment_id", "to": "equipment_id"}],
539
+ "relationship_type": "many_to_one",
540
+ "description": "计划→设备",
541
+ },
542
+ {
543
+ "from_table": "dim_equipment_type",
544
+ "to_table": "dim_equipment_type",
545
+ "join_sql": "dim_equipment_type.parent_type_id = dim_equipment_type.equip_type_id",
546
+ "join_keys": [{"from": "parent_type_id", "to": "equip_type_id"}],
547
+ "relationship_type": "many_to_one",
548
+ "description": "类型上级(树形)",
549
+ },
550
+ {
551
+ "from_table": "dim_downtime_reason",
552
+ "to_table": "dim_downtime_reason",
553
+ "join_sql": "dim_downtime_reason.parent_reason_id = dim_downtime_reason.reason_id",
554
+ "join_keys": [{"from": "parent_reason_id", "to": "reason_id"}],
555
+ "relationship_type": "many_to_one",
556
+ "description": "原因上级(树形)",
557
+ },
558
+ {
559
+ "from_table": "fact_equipment_plan",
560
+ "to_table": "fact_equipment_daily_ops",
561
+ "join_sql": "fact_equipment_plan.equipment_id = fact_equipment_daily_ops.equipment_id AND fact_equipment_plan.date_key = fact_equipment_daily_ops.date_key",
562
+ "join_keys": [
563
+ {"from": "equipment_id", "to": "equipment_id"},
564
+ {"from": "date_key", "to": "date_key"},
565
+ ],
566
+ "relationship_type": "many_to_one",
567
+ "description": "计划对比实际(逻辑关联)",
568
+ },
569
+ ]
570
+ for rel in table_relationships:
571
+ s.tables.add_relationship(**rel)
572
+ output.print(f"OK {rel['from_table']} -> {rel['to_table']}")
573
+
574
+ # 4. 注册 Cube
575
+ output.print("\n[4/8] 注册 Cube...")
576
+
577
+ ops = "fact_equipment_daily_ops"
578
+ downtime = "fact_downtime_event"
579
+ maint = "fact_maintenance_record"
580
+ plan = "fact_equipment_plan"
581
+
582
+ ops_measures = [
583
+ {"name": "calendar_minutes_total", "col": "calendar_minutes", "agg": "sum", "title": "日历时间合计"},
584
+ {"name": "planned_downtime_total", "col": "planned_downtime_min", "agg": "sum", "title": "计划停机合计"},
585
+ {"name": "unplanned_downtime_total", "col": "unplanned_downtime_min", "agg": "sum", "title": "非计划停机合计"},
586
+ {"name": "runtime_total", "col": "runtime_min", "agg": "sum", "title": "运行时间合计"},
587
+ {"name": "actual_output_total", "col": "actual_output_qty", "agg": "sum", "title": "实际产量"},
588
+ {"name": "qualified_output_total", "col": "qualified_output_qty", "agg": "sum", "title": "合格产量"},
589
+ {"name": "energy_total", "col": "energy_consumption", "agg": "sum", "title": "能耗合计"},
590
+ {"name": "ideal_cycle_rate_avg", "col": "ideal_cycle_rate", "agg": "avg", "title": "理想节拍均值"},
591
+ {"name": "ops_days", "col": "ops_id", "agg": "count", "title": "汇总行数"},
592
+ ]
593
+
594
+ ops_dims = [
595
+ {"name": "ops_id", "col": "ops_id", "type": "string", "title": "汇总ID"},
596
+ {"name": "date_key", "col": "date_key", "type": "int", "title": "日期键"},
597
+ {"name": "calendar_date", "col": "calendar_date", "type": "date", "title": "统计日期"},
598
+ {"name": "equipment_id", "col": "equipment_id", "type": "string", "title": "设备ID"},
599
+ {"name": "equipment_code", "col": "equipment_code", "type": "string", "title": "设备位号"},
600
+ {"name": "equipment_name", "col": "equipment_name", "type": "string", "title": "设备名称"},
601
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
602
+ {"name": "plant_name", "col": "plant_name", "type": "string", "title": "厂区名称"},
603
+ {"name": "unit_id", "col": "unit_id", "type": "string", "title": "单元ID"},
604
+ {"name": "unit_name", "col": "unit_name", "type": "string", "title": "单元名称"},
605
+ {"name": "equip_type_id", "col": "equip_type_id", "type": "string", "title": "设备类型ID"},
606
+ {"name": "category", "col": "category", "type": "string", "title": "设备大类"},
607
+ {"name": "shift_code", "col": "shift_code", "type": "string", "title": "班次"},
608
+ ]
609
+
610
+ oee_derived = [
611
+ {
612
+ "name": "availability",
613
+ "title": "可用率",
614
+ "expression": "if((OperationCube.calendar_minutes_total - OperationCube.planned_downtime_total) > 0, OperationCube.runtime_total / (OperationCube.calendar_minutes_total - OperationCube.planned_downtime_total), 0)",
615
+ "description": "运行时间 / 计划运行时间",
616
+ },
617
+ {
618
+ "name": "performance",
619
+ "title": "性能率",
620
+ "expression": "if(OperationCube.runtime_total > 0 and OperationCube.ideal_cycle_rate_avg > 0, (OperationCube.actual_output_total / OperationCube.runtime_total) / OperationCube.ideal_cycle_rate_avg, 0)",
621
+ "description": "实际节拍 / 理想节拍",
622
+ },
623
+ {
624
+ "name": "quality",
625
+ "title": "质量率",
626
+ "expression": "if(OperationCube.actual_output_total > 0, OperationCube.qualified_output_total / OperationCube.actual_output_total, 0)",
627
+ "description": "合格产量 / 实际产量",
628
+ },
629
+ {
630
+ "name": "oee",
631
+ "title": "综合效率",
632
+ "expression": "OperationCube.availability * OperationCube.performance * OperationCube.quality",
633
+ "description": "可用率 × 性能率 × 质量率",
634
+ },
635
+ {
636
+ "name": "load_rate",
637
+ "title": "负荷率",
638
+ "expression": "if((OperationCube.calendar_minutes_total - OperationCube.planned_downtime_total) > 0, OperationCube.runtime_total / (OperationCube.calendar_minutes_total - OperationCube.planned_downtime_total), 0)",
639
+ "description": "运行时间 / 计划运行时间",
640
+ },
641
+ {
642
+ "name": "energy_per_output",
643
+ "title": "单位产量能耗",
644
+ "expression": "if(OperationCube.actual_output_total > 0, OperationCube.energy_total / OperationCube.actual_output_total, 0)",
645
+ "description": "能耗 / 实际产量",
646
+ },
647
+ ]
648
+
649
+ subject_oee_derived = lambda cube: [
650
+ {
651
+ "name": "availability",
652
+ "title": "可用率",
653
+ "expression": f"if(({cube}.calendar_minutes_total - {cube}.planned_downtime_total) > 0, {cube}.runtime_total / ({cube}.calendar_minutes_total - {cube}.planned_downtime_total), 0)",
654
+ "description": "可用率",
655
+ },
656
+ {
657
+ "name": "performance",
658
+ "title": "性能率",
659
+ "expression": f"if({cube}.runtime_total > 0 and {cube}.ideal_cycle_rate_avg > 0, ({cube}.actual_output_total / {cube}.runtime_total) / {cube}.ideal_cycle_rate_avg, 0)",
660
+ "description": "性能率",
661
+ },
662
+ {
663
+ "name": "quality",
664
+ "title": "质量率",
665
+ "expression": f"if({cube}.actual_output_total > 0, {cube}.qualified_output_total / {cube}.actual_output_total, 0)",
666
+ "description": "质量率",
667
+ },
668
+ {
669
+ "name": "oee",
670
+ "title": "综合效率",
671
+ "expression": f"{cube}.availability * {cube}.performance * {cube}.quality",
672
+ "description": "OEE",
673
+ },
674
+ {
675
+ "name": "energy_per_output",
676
+ "title": "单位产量能耗",
677
+ "expression": f"if({cube}.actual_output_total > 0, {cube}.energy_total / {cube}.actual_output_total, 0)",
678
+ "description": "单位产量能耗",
679
+ },
680
+ ]
681
+
682
+ # OperationCube
683
+ s.register_cube(
684
+ name="OperationCube",
685
+ table=ops,
686
+ title="日运行主Cube",
687
+ measures=ops_measures,
688
+ dimensions=ops_dims,
689
+ )
690
+ output.print("OK OperationCube")
691
+
692
+ # EquipmentCube
693
+ s.register_cube(
694
+ name="EquipmentCube",
695
+ table=ops,
696
+ title="设备运营Cube",
697
+ measures=[
698
+ {"name": "calendar_minutes_total", "col": "calendar_minutes", "agg": "sum", "title": "日历时间合计"},
699
+ {"name": "planned_downtime_total", "col": "planned_downtime_min", "agg": "sum", "title": "计划停机合计"},
700
+ {"name": "runtime_total", "col": "runtime_min", "agg": "sum", "title": "运行时间合计"},
701
+ {"name": "unplanned_downtime_total", "col": "unplanned_downtime_min", "agg": "sum", "title": "非计划停机合计"},
702
+ {"name": "actual_output_total", "col": "actual_output_qty", "agg": "sum", "title": "实际产量"},
703
+ {"name": "qualified_output_total", "col": "qualified_output_qty", "agg": "sum", "title": "合格产量"},
704
+ {"name": "energy_total", "col": "energy_consumption", "agg": "sum", "title": "能耗合计"},
705
+ {"name": "ideal_cycle_rate_avg", "col": "ideal_cycle_rate", "agg": "avg", "title": "理想节拍均值"},
706
+ {"name": "ops_days", "col": "ops_id", "agg": "count", "title": "汇总行数"},
707
+ ],
708
+ dimensions=[
709
+ {"name": "equipment_id", "col": "equipment_id", "type": "string", "title": "设备ID"},
710
+ {"name": "equipment_code", "col": "equipment_code", "type": "string", "title": "设备位号"},
711
+ {"name": "equipment_name", "col": "equipment_name", "type": "string", "title": "设备名称"},
712
+ {"name": "equip_type_id", "col": "equip_type_id", "type": "string", "title": "设备类型ID"},
713
+ {"name": "category", "col": "category", "type": "string", "title": "设备大类"},
714
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
715
+ {"name": "plant_name", "col": "plant_name", "type": "string", "title": "厂区名称"},
716
+ {"name": "unit_id", "col": "unit_id", "type": "string", "title": "单元ID"},
717
+ {"name": "unit_name", "col": "unit_name", "type": "string", "title": "单元名称"},
718
+ {"name": "criticality", "col": "equipment_id", "type": "string", "title": "关键等级"},
719
+ {"name": "production_mode", "col": "equipment_id", "type": "string", "title": "生产模式"},
720
+ ],
721
+ )
722
+ output.print("OK EquipmentCube")
723
+
724
+ # PlantCube
725
+ s.register_cube(
726
+ name="PlantCube",
727
+ table=ops,
728
+ title="厂区运营Cube",
729
+ measures=[
730
+ {"name": "calendar_minutes_total", "col": "calendar_minutes", "agg": "sum", "title": "日历时间合计"},
731
+ {"name": "planned_downtime_total", "col": "planned_downtime_min", "agg": "sum", "title": "计划停机合计"},
732
+ {"name": "runtime_total", "col": "runtime_min", "agg": "sum", "title": "运行时间合计"},
733
+ {"name": "unplanned_downtime_total", "col": "unplanned_downtime_min", "agg": "sum", "title": "非计划停机合计"},
734
+ {"name": "actual_output_total", "col": "actual_output_qty", "agg": "sum", "title": "实际产量"},
735
+ {"name": "qualified_output_total", "col": "qualified_output_qty", "agg": "sum", "title": "合格产量"},
736
+ {"name": "energy_total", "col": "energy_consumption", "agg": "sum", "title": "能耗合计"},
737
+ {"name": "ideal_cycle_rate_avg", "col": "ideal_cycle_rate", "agg": "avg", "title": "理想节拍均值"},
738
+ ],
739
+ dimensions=[
740
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
741
+ {"name": "plant_name", "col": "plant_name", "type": "string", "title": "厂区名称"},
742
+ ],
743
+ )
744
+ output.print("OK PlantCube")
745
+
746
+ # ProcessUnitCube
747
+ s.register_cube(
748
+ name="ProcessUnitCube",
749
+ table=ops,
750
+ title="工艺单元运营Cube",
751
+ measures=[
752
+ {"name": "calendar_minutes_total", "col": "calendar_minutes", "agg": "sum", "title": "日历时间合计"},
753
+ {"name": "planned_downtime_total", "col": "planned_downtime_min", "agg": "sum", "title": "计划停机合计"},
754
+ {"name": "runtime_total", "col": "runtime_min", "agg": "sum", "title": "运行时间合计"},
755
+ {"name": "unplanned_downtime_total", "col": "unplanned_downtime_min", "agg": "sum", "title": "非计划停机合计"},
756
+ {"name": "actual_output_total", "col": "actual_output_qty", "agg": "sum", "title": "实际产量"},
757
+ {"name": "qualified_output_total", "col": "qualified_output_qty", "agg": "sum", "title": "合格产量"},
758
+ {"name": "energy_total", "col": "energy_consumption", "agg": "sum", "title": "能耗合计"},
759
+ {"name": "ideal_cycle_rate_avg", "col": "ideal_cycle_rate", "agg": "avg", "title": "理想节拍均值"},
760
+ ],
761
+ dimensions=[
762
+ {"name": "unit_id", "col": "unit_id", "type": "string", "title": "单元ID"},
763
+ {"name": "unit_name", "col": "unit_name", "type": "string", "title": "单元名称"},
764
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
765
+ {"name": "plant_name", "col": "plant_name", "type": "string", "title": "厂区名称"},
766
+ ],
767
+ )
768
+ output.print("OK ProcessUnitCube")
769
+
770
+ # DowntimeCube
771
+ s.register_cube(
772
+ name="DowntimeCube",
773
+ table=downtime,
774
+ title="停机事件Cube",
775
+ measures=[
776
+ {"name": "downtime_minutes", "col": "duration_min", "agg": "sum", "title": "停机时长"},
777
+ {"name": "event_count", "col": "event_id", "agg": "count", "title": "事件次数"},
778
+ ],
779
+ dimensions=[
780
+ {"name": "event_id", "col": "event_id", "type": "string", "title": "事件ID"},
781
+ {"name": "date_key", "col": "date_key", "type": "int", "title": "日期键"},
782
+ {"name": "equipment_id", "col": "equipment_id", "type": "string", "title": "设备ID"},
783
+ {"name": "equipment_code", "col": "equipment_code", "type": "string", "title": "设备位号"},
784
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
785
+ {"name": "unit_id", "col": "unit_id", "type": "string", "title": "单元ID"},
786
+ {"name": "reason_id", "col": "reason_id", "type": "string", "title": "原因ID"},
787
+ {"name": "reason_code", "col": "reason_code", "type": "string", "title": "原因编码"},
788
+ {"name": "reason_name", "col": "reason_name", "type": "string", "title": "原因名称"},
789
+ {"name": "reason_category", "col": "reason_category", "type": "string", "title": "原因大类"},
790
+ {"name": "is_planned", "col": "is_planned", "type": "int", "title": "是否计划停机"},
791
+ {"name": "responsible_dept", "col": "responsible_dept", "type": "string", "title": "责任部门"},
792
+ ],
793
+ )
794
+ output.print("OK DowntimeCube")
795
+
796
+ # MaintenanceCube
797
+ s.register_cube(
798
+ name="MaintenanceCube",
799
+ table=maint,
800
+ title="维保记录Cube",
801
+ measures=[
802
+ {"name": "plan_hours", "col": "plan_hours", "agg": "sum", "title": "计划工时"},
803
+ {"name": "actual_hours", "col": "actual_hours", "agg": "sum", "title": "实际工时"},
804
+ {"name": "plan_cost", "col": "plan_cost", "agg": "sum", "title": "计划费用"},
805
+ {"name": "actual_cost", "col": "actual_cost", "agg": "sum", "title": "实际费用"},
806
+ {"name": "maint_count", "col": "maint_id", "agg": "count", "title": "维保次数"},
807
+ {"name": "on_schedule_count", "col": "is_on_schedule", "agg": "sum", "title": "按期完成次数"},
808
+ ],
809
+ dimensions=[
810
+ {"name": "maint_id", "col": "maint_id", "type": "string", "title": "维保ID"},
811
+ {"name": "date_key", "col": "date_key", "type": "int", "title": "日期键"},
812
+ {"name": "equipment_id", "col": "equipment_id", "type": "string", "title": "设备ID"},
813
+ {"name": "equipment_code", "col": "equipment_code", "type": "string", "title": "设备位号"},
814
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
815
+ {"name": "unit_id", "col": "unit_id", "type": "string", "title": "单元ID"},
816
+ {"name": "maint_type", "col": "maint_type", "type": "string", "title": "维保类型"},
817
+ {"name": "status", "col": "status", "type": "string", "title": "状态"},
818
+ ],
819
+ )
820
+ output.print("OK MaintenanceCube")
821
+
822
+ # PlanVsActualCube
823
+ s.register_cube(
824
+ name="PlanVsActualCube",
825
+ table=plan,
826
+ title="计划对比Cube",
827
+ measures=[
828
+ {"name": "planned_runtime_min", "col": "planned_runtime_min", "agg": "sum", "title": "计划运行时间"},
829
+ {"name": "planned_output_qty", "col": "planned_output_qty", "agg": "sum", "title": "计划产量"},
830
+ {"name": "planned_energy", "col": "planned_energy", "agg": "sum", "title": "计划能耗"},
831
+ {"name": "plan_count", "col": "plan_id", "agg": "count", "title": "计划行数"},
832
+ ],
833
+ dimensions=[
834
+ {"name": "plan_id", "col": "plan_id", "type": "string", "title": "计划ID"},
835
+ {"name": "date_key", "col": "date_key", "type": "int", "title": "日期键"},
836
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "计划年度"},
837
+ {"name": "fiscal_month", "col": "fiscal_month", "type": "int", "title": "计划月份"},
838
+ {"name": "equipment_id", "col": "equipment_id", "type": "string", "title": "设备ID"},
839
+ {"name": "equipment_code", "col": "equipment_code", "type": "string", "title": "设备位号"},
840
+ {"name": "plant_id", "col": "plant_id", "type": "string", "title": "厂区ID"},
841
+ {"name": "unit_id", "col": "unit_id", "type": "string", "title": "单元ID"},
842
+ {"name": "plan_version", "col": "plan_version", "type": "string", "title": "计划版本"},
843
+ ],
844
+ )
845
+ output.print("OK PlanVsActualCube")
846
+
847
+ # 派生度量
848
+ output.print("\n[4b/8] 配置派生度量...")
849
+ s.upsert_derived_measures("OperationCube", oee_derived)
850
+ output.print("OK OperationCube 派生度量")
851
+
852
+ for cube_name in ("EquipmentCube", "PlantCube", "ProcessUnitCube"):
853
+ derived = subject_oee_derived(cube_name)
854
+ if cube_name == "ProcessUnitCube":
855
+ derived.append({
856
+ "name": "load_rate",
857
+ "title": "负荷率",
858
+ "expression": f"if(({cube_name}.calendar_minutes_total - {cube_name}.planned_downtime_total) > 0, {cube_name}.runtime_total / ({cube_name}.calendar_minutes_total - {cube_name}.planned_downtime_total), 0)",
859
+ "description": "负荷率",
860
+ })
861
+ s.upsert_derived_measures(cube_name, derived)
862
+ output.print(f"OK {cube_name} 派生度量")
863
+
864
+ s.upsert_derived_measures(
865
+ "DowntimeCube",
866
+ [
867
+ {
868
+ "name": "avg_downtime",
869
+ "title": "平均停机时长",
870
+ "expression": "if(DowntimeCube.event_count > 0, DowntimeCube.downtime_minutes / DowntimeCube.event_count, 0)",
871
+ "description": "停机时长 / 事件次数",
872
+ },
873
+ ],
874
+ )
875
+ output.print("OK DowntimeCube 派生度量")
876
+
877
+ s.upsert_derived_measures(
878
+ "MaintenanceCube",
879
+ [
880
+ {
881
+ "name": "schedule_rate",
882
+ "title": "维保达成率",
883
+ "expression": "if(MaintenanceCube.maint_count > 0, MaintenanceCube.on_schedule_count / MaintenanceCube.maint_count, 0)",
884
+ "description": "按期完成 / 维保次数",
885
+ },
886
+ {
887
+ "name": "cost_variance",
888
+ "title": "费用偏差",
889
+ "expression": "MaintenanceCube.actual_cost - MaintenanceCube.plan_cost",
890
+ "description": "实际费用 - 计划费用",
891
+ },
892
+ ],
893
+ )
894
+ output.print("OK MaintenanceCube 派生度量")
895
+
896
+ # 5. 定义对象类型(10 种,规划 §5.1)
897
+ output.print("\n[5/8] 定义对象类型...")
898
+
899
+ s.onto.define_object_type(
900
+ code="Plant",
901
+ name="厂区/装置区",
902
+ description="化工生产厂区或大型装置区",
903
+ category_347="主数据",
904
+ )
905
+ s.onto.bind_source("Plant", "dazi_cube", config={"cube": "PlantCube"})
906
+ output.print("OK Plant")
907
+
908
+ s.onto.define_object_type(
909
+ code="ProcessUnit",
910
+ name="工艺单元",
911
+ description="装置内工艺单元",
912
+ category_347="主数据",
913
+ )
914
+ s.onto.bind_source("ProcessUnit", "dazi_cube", config={"cube": "ProcessUnitCube"})
915
+ output.print("OK ProcessUnit")
916
+
917
+ s.onto.define_object_type(
918
+ code="EquipmentType",
919
+ name="设备类型",
920
+ description="设备分类主数据",
921
+ category_347="主数据",
922
+ )
923
+ output.print("OK EquipmentType(无 bind_source)")
924
+
925
+ s.onto.define_object_type(
926
+ code="Equipment",
927
+ name="设备",
928
+ description="单台设备台账",
929
+ category_347="主数据",
930
+ )
931
+ s.onto.bind_source("Equipment", "dazi_cube", config={"cube": "EquipmentCube"})
932
+ output.print("OK Equipment")
933
+
934
+ s.onto.define_object_type(
935
+ code="DowntimeReason",
936
+ name="停机原因",
937
+ description="停机/故障原因码表",
938
+ category_347="参考",
939
+ )
940
+ output.print("OK DowntimeReason(无 bind_source)")
941
+
942
+ s.onto.define_object_type(
943
+ code="OperationSnapshot",
944
+ name="日运行汇总",
945
+ description="设备日运行 KPI 汇总",
946
+ category_347="事务",
947
+ )
948
+ s.onto.bind_source("OperationSnapshot", "dazi_cube", config={"cube": "OperationCube"})
949
+ output.print("OK OperationSnapshot")
950
+
951
+ s.onto.define_object_type(
952
+ code="DowntimeEvent",
953
+ name="停机事件",
954
+ description="单次停机/故障事件",
955
+ category_347="事务",
956
+ )
957
+ s.onto.bind_source("DowntimeEvent", "dazi_cube", config={"cube": "DowntimeCube"})
958
+ output.print("OK DowntimeEvent")
959
+
960
+ s.onto.define_object_type(
961
+ code="MaintenanceRecord",
962
+ name="维保记录",
963
+ description="计划与实际维保作业",
964
+ category_347="事务",
965
+ )
966
+ s.onto.bind_source("MaintenanceRecord", "dazi_cube", config={"cube": "MaintenanceCube"})
967
+ output.print("OK MaintenanceRecord")
968
+
969
+ s.onto.define_object_type(
970
+ code="EquipmentAnalysis",
971
+ name="设备运营分析",
972
+ description="多维度设备运营指标聚合",
973
+ category_347="分析",
974
+ )
975
+ s.onto.bind_source("EquipmentAnalysis", "dazi_cube", config={"cube": "OperationCube"})
976
+ output.print("OK EquipmentAnalysis")
977
+
978
+ s.onto.define_object_type(
979
+ code="PlanAnalysis",
980
+ name="计划对比分析",
981
+ description="运行计划 vs 实际对比",
982
+ category_347="分析",
983
+ )
984
+ s.onto.bind_source("PlanAnalysis", "dazi_cube", config={"cube": "PlanVsActualCube"})
985
+ output.print("OK PlanAnalysis")
986
+
987
+ # 6. 定义属性(主要对象各 3-5 个,规划 §5.2)
988
+ output.print("\n[6/8] 定义对象属性...")
989
+
990
+ s.onto.define_property("Plant", "id", "厂区 ID", semantic_role="dimension", qualified_name="PlantCube.plant_id")
991
+ s.onto.define_property("Plant", "name", "厂区名称", semantic_role="dimension", qualified_name="PlantCube.plant_name")
992
+ s.onto.define_property("Plant", "availability", "可用率", semantic_role="measure", qualified_name="PlantCube.availability")
993
+ s.onto.define_property("Plant", "oee", "装置 OEE", semantic_role="measure", qualified_name="PlantCube.oee")
994
+ s.onto.define_property("Plant", "energy_per_output", "单位产量能耗", semantic_role="measure", qualified_name="PlantCube.energy_per_output")
995
+
996
+ s.onto.define_property("ProcessUnit", "id", "单元 ID", semantic_role="dimension", qualified_name="ProcessUnitCube.unit_id")
997
+ s.onto.define_property("ProcessUnit", "name", "单元名称", semantic_role="dimension", qualified_name="ProcessUnitCube.unit_name")
998
+ s.onto.define_property("ProcessUnit", "availability", "可用率", semantic_role="measure", qualified_name="ProcessUnitCube.availability")
999
+ s.onto.define_property("ProcessUnit", "oee", "单元 OEE", semantic_role="measure", qualified_name="ProcessUnitCube.oee")
1000
+ s.onto.define_property("ProcessUnit", "load_rate", "负荷率", semantic_role="measure", qualified_name="ProcessUnitCube.load_rate")
1001
+
1002
+ # EquipmentType / DowntimeReason 无 bind_source,跳过 define_property(平台要求 measure/dimension 须绑定 Cube)
1003
+
1004
+ s.onto.define_property("Equipment", "id", "设备 ID", semantic_role="dimension", qualified_name="EquipmentCube.equipment_id")
1005
+ s.onto.define_property("Equipment", "code", "设备位号", semantic_role="dimension", qualified_name="EquipmentCube.equipment_code")
1006
+ s.onto.define_property("Equipment", "name", "设备名称", semantic_role="dimension", qualified_name="EquipmentCube.equipment_name")
1007
+ s.onto.define_property("Equipment", "runtime", "运行时间", semantic_role="measure", qualified_name="EquipmentCube.runtime_total")
1008
+ s.onto.define_property("Equipment", "availability", "可用率", semantic_role="measure", qualified_name="EquipmentCube.availability")
1009
+ s.onto.define_property("Equipment", "oee", "综合效率", semantic_role="measure", qualified_name="EquipmentCube.oee")
1010
+
1011
+ s.onto.define_property("OperationSnapshot", "date", "统计日期", semantic_role="dimension", qualified_name="OperationCube.calendar_date")
1012
+ s.onto.define_property("OperationSnapshot", "runtime", "运行时间", semantic_role="measure", qualified_name="OperationCube.runtime_total")
1013
+ s.onto.define_property("OperationSnapshot", "availability", "可用率", semantic_role="measure", qualified_name="OperationCube.availability")
1014
+ s.onto.define_property("OperationSnapshot", "oee", "OEE", semantic_role="measure", qualified_name="OperationCube.oee")
1015
+
1016
+ s.onto.define_property("DowntimeEvent", "id", "事件 ID", semantic_role="dimension", qualified_name="DowntimeCube.event_id")
1017
+ s.onto.define_property("DowntimeEvent", "duration", "停机时长", semantic_role="measure", qualified_name="DowntimeCube.downtime_minutes")
1018
+ s.onto.define_property("DowntimeEvent", "reason", "原因名称", semantic_role="dimension", qualified_name="DowntimeCube.reason_name")
1019
+ s.onto.define_property("DowntimeEvent", "is_planned", "是否计划", semantic_role="dimension", qualified_name="DowntimeCube.is_planned")
1020
+
1021
+ s.onto.define_property("MaintenanceRecord", "id", "维保 ID", semantic_role="dimension", qualified_name="MaintenanceCube.maint_id")
1022
+ s.onto.define_property("MaintenanceRecord", "plan_hours", "计划工时", semantic_role="measure", qualified_name="MaintenanceCube.plan_hours")
1023
+ s.onto.define_property("MaintenanceRecord", "actual_hours", "实际工时", semantic_role="measure", qualified_name="MaintenanceCube.actual_hours")
1024
+ s.onto.define_property("MaintenanceRecord", "schedule_rate", "达成率", semantic_role="measure", qualified_name="MaintenanceCube.schedule_rate")
1025
+
1026
+ s.onto.define_property("EquipmentAnalysis", "oee", "平均 OEE", semantic_role="measure", qualified_name="OperationCube.oee")
1027
+ s.onto.define_property("EquipmentAnalysis", "availability", "平均可用率", semantic_role="measure", qualified_name="OperationCube.availability")
1028
+ s.onto.define_property("EquipmentAnalysis", "runtime", "总运行时间", semantic_role="measure", qualified_name="OperationCube.runtime_total")
1029
+ s.onto.define_property("EquipmentAnalysis", "energy_per_output", "单位产量能耗", semantic_role="measure", qualified_name="OperationCube.energy_per_output")
1030
+
1031
+ s.onto.define_property("PlanAnalysis", "planned_output", "计划产量", semantic_role="measure", qualified_name="PlanVsActualCube.planned_output_qty")
1032
+ s.onto.define_property("PlanAnalysis", "planned_runtime", "计划运行时间", semantic_role="measure", qualified_name="PlanVsActualCube.planned_runtime_min")
1033
+ s.onto.define_property("PlanAnalysis", "plan_version", "计划版本", semantic_role="dimension", qualified_name="PlanVsActualCube.plan_version")
1034
+
1035
+ output.print("OK 属性定义完成")
1036
+
1037
+ # 7. 定义链接类型(16 种,规划 §5.3)
1038
+ output.print("\n[7/8] 定义链接类型...")
1039
+
1040
+ s.onto.define_link_type(code="unit_belongs_plant", name="单元归属厂区", from_object_type_code="ProcessUnit", to_object_type_code="Plant", category_347="归属关系")
1041
+ s.onto.define_link_type(code="equipment_belongs_plant", name="设备归属厂区", from_object_type_code="Equipment", to_object_type_code="Plant", category_347="归属关系")
1042
+ s.onto.define_link_type(code="equipment_belongs_unit", name="设备归属单元", from_object_type_code="Equipment", to_object_type_code="ProcessUnit", category_347="归属关系")
1043
+ s.onto.define_link_type(code="equipment_has_type", name="设备属于类型", from_object_type_code="Equipment", to_object_type_code="EquipmentType", category_347="归属关系")
1044
+ s.onto.define_link_type(code="snapshot_for_equipment", name="日运行归属设备", from_object_type_code="OperationSnapshot", to_object_type_code="Equipment", category_347="归属关系")
1045
+ s.onto.define_link_type(code="downtime_on_equipment", name="停机发生于设备", from_object_type_code="DowntimeEvent", to_object_type_code="Equipment", category_347="归属关系")
1046
+ s.onto.define_link_type(code="downtime_has_reason", name="停机对应原因", from_object_type_code="DowntimeEvent", to_object_type_code="DowntimeReason", category_347="归属关系")
1047
+ s.onto.define_link_type(code="maint_for_equipment", name="维保针对设备", from_object_type_code="MaintenanceRecord", to_object_type_code="Equipment", category_347="归属关系")
1048
+
1049
+ s.onto.define_link_type(code="equip_type_has_parent", name="类型上级", from_object_type_code="EquipmentType", to_object_type_code="EquipmentType", category_347="层级关系")
1050
+ s.onto.define_link_type(code="reason_has_parent", name="原因上级", from_object_type_code="DowntimeReason", to_object_type_code="DowntimeReason", category_347="层级关系")
1051
+
1052
+ s.onto.define_link_type(code="plan_compared_to_actual", name="计划对比实际", from_object_type_code="PlanAnalysis", to_object_type_code="EquipmentAnalysis", category_347="对比关系")
1053
+
1054
+ s.onto.define_link_type(code="analysis_by_equipment", name="分析归因设备", from_object_type_code="EquipmentAnalysis", to_object_type_code="Equipment", category_347="分析归因")
1055
+ s.onto.define_link_type(code="analysis_by_plant", name="分析归因厂区", from_object_type_code="EquipmentAnalysis", to_object_type_code="Plant", category_347="分析归因")
1056
+ s.onto.define_link_type(code="analysis_by_unit", name="分析归因单元", from_object_type_code="EquipmentAnalysis", to_object_type_code="ProcessUnit", category_347="分析归因")
1057
+ s.onto.define_link_type(code="analysis_by_downtime", name="分析归因停机", from_object_type_code="EquipmentAnalysis", to_object_type_code="DowntimeEvent", category_347="分析归因")
1058
+ s.onto.define_link_type(code="analysis_by_maintenance", name="分析归因维保", from_object_type_code="EquipmentAnalysis", to_object_type_code="MaintenanceRecord", category_347="分析归因")
1059
+
1060
+ output.print("OK 链接定义完成")
1061
+
1062
+ # 8. 同步指标引用 + 输出摘要
1063
+ output.print("\n[8/8] 同步指标引用...")
1064
+ s.sync_metric_refs()
1065
+ output.print("OK sync_metric_refs")
1066
+
1067
+ summary = {
1068
+ "ok": True,
1069
+ "space_id": space_id,
1070
+ "tables": len(TABLE_REGISTRY),
1071
+ "relationships": len(table_relationships),
1072
+ "cubes": 7,
1073
+ "objects": 10,
1074
+ "links": 16,
1075
+ }
1076
+ output.success("化工设备运营分析本体初始化完成")
1077
+ output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))