@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,552 @@
1
+ """化工设备运营分析演示数据灌入 — space_cate_test01
2
+
3
+ 前置:先执行 equip_ops_ontology_init.py 建表;dim_date 由空间其他域提供或已存在。
4
+ 幂等:fact_equipment_daily_ops 已有数据则跳过。
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/设备运营/setup/equip_ops_seed_data.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/setup/equip_ops_seed_data.py --space space_cate_test01 --type data
8
+ """
9
+
10
+ import json
11
+ import random
12
+ from datetime import date, datetime, timedelta
13
+
14
+ _SEED_DT = datetime(2025, 1, 1, 0, 0, 0)
15
+ _PLAN_VERSION = "2026月度计划"
16
+ _WEEKLY_MINUTES = 7 * 1440 # 每周一行,日历时间按 7 天计
17
+
18
+
19
+ def _date_key(d):
20
+ return int(d.strftime("%Y%m%d"))
21
+
22
+
23
+ def main():
24
+ space_id = "space_cate_test01"
25
+ s = space.get(space_id)
26
+
27
+ output.print("=== 化工设备运营分析演示数据灌入 ===")
28
+
29
+ try:
30
+ n = int(s.sql.query_one("SELECT count() FROM fact_equipment_daily_ops") or 0)
31
+ except Exception:
32
+ n = 0
33
+ if n > 0:
34
+ output.print(f"fact_equipment_daily_ops 已有 {n} 行,跳过灌数")
35
+ output.print("__JSON_SUMMARY__" + json.dumps({"ok": True, "skipped": True, "rows": n}, ensure_ascii=True))
36
+ return
37
+
38
+ random.seed(8806)
39
+
40
+ # 1. 厂区
41
+ plants = [
42
+ {
43
+ "plant_id": "PL001",
44
+ "plant_code": "PL001",
45
+ "plant_name": "乙烯装置区",
46
+ "company_code": "PD-CHEM",
47
+ "plant_type": "烯烃",
48
+ "location": "华东炼化基地A区",
49
+ "design_capacity": 800000.0,
50
+ "capacity_unit": "吨/年",
51
+ "status": "运行",
52
+ },
53
+ {
54
+ "plant_id": "PL002",
55
+ "plant_code": "PL002",
56
+ "plant_name": "芳烃装置区",
57
+ "company_code": "PD-CHEM",
58
+ "plant_type": "芳烃",
59
+ "location": "华东炼化基地B区",
60
+ "design_capacity": 600000.0,
61
+ "capacity_unit": "吨/年",
62
+ "status": "运行",
63
+ },
64
+ ]
65
+ for p in plants:
66
+ p["created_at"] = _SEED_DT
67
+
68
+ # 2. 工艺单元(4 个)
69
+ units = [
70
+ {
71
+ "unit_id": "PU001",
72
+ "unit_code": "PU001",
73
+ "unit_name": "裂解炉区",
74
+ "plant_id": "PL001",
75
+ "plant_name": "乙烯装置区",
76
+ "unit_type": "反应",
77
+ "criticality": "A",
78
+ "status": "运行",
79
+ },
80
+ {
81
+ "unit_id": "PU002",
82
+ "unit_code": "PU002",
83
+ "unit_name": "分离精馏区",
84
+ "plant_id": "PL001",
85
+ "plant_name": "乙烯装置区",
86
+ "unit_type": "分离",
87
+ "criticality": "A",
88
+ "status": "运行",
89
+ },
90
+ {
91
+ "unit_id": "PU003",
92
+ "unit_code": "PU003",
93
+ "unit_name": "芳烃反应区",
94
+ "plant_id": "PL002",
95
+ "plant_name": "芳烃装置区",
96
+ "unit_type": "反应",
97
+ "criticality": "A",
98
+ "status": "运行",
99
+ },
100
+ {
101
+ "unit_id": "PU004",
102
+ "unit_code": "PU004",
103
+ "unit_name": "芳烃精馏区",
104
+ "plant_id": "PL002",
105
+ "plant_name": "芳烃装置区",
106
+ "unit_type": "分离",
107
+ "criticality": "B",
108
+ "status": "运行",
109
+ },
110
+ ]
111
+ for u in units:
112
+ u["created_at"] = _SEED_DT
113
+
114
+ # 3. 设备类型树
115
+ equip_types = [
116
+ {"equip_type_id": "ET_DYN", "equip_type_code": "DYN", "equip_type_name": "动设备", "category": "动设备", "parent_type_id": "", "type_level": 1, "is_leaf": False, "status": "启用"},
117
+ {"equip_type_id": "ET_STA", "equip_type_code": "STA", "equip_type_name": "静设备", "category": "静设备", "parent_type_id": "", "type_level": 1, "is_leaf": False, "status": "启用"},
118
+ {"equip_type_id": "ET_PUMP", "equip_type_code": "PUMP", "equip_type_name": "泵", "category": "动设备", "parent_type_id": "ET_DYN", "type_level": 2, "is_leaf": True, "status": "启用"},
119
+ {"equip_type_id": "ET_COMP", "equip_type_code": "COMP", "equip_type_name": "压缩机", "category": "动设备", "parent_type_id": "ET_DYN", "type_level": 2, "is_leaf": True, "status": "启用"},
120
+ {"equip_type_id": "ET_REACT", "equip_type_code": "REACT", "equip_type_name": "反应釜", "category": "静设备", "parent_type_id": "ET_STA", "type_level": 2, "is_leaf": True, "status": "启用"},
121
+ {"equip_type_id": "ET_TOWER", "equip_type_code": "TOWER", "equip_type_name": "塔器", "category": "静设备", "parent_type_id": "ET_STA", "type_level": 2, "is_leaf": True, "status": "启用"},
122
+ ]
123
+ for et in equip_types:
124
+ et["created_at"] = _SEED_DT
125
+ type_map = {et["equip_type_id"]: et for et in equip_types}
126
+
127
+ # 4. 设备(8 台)
128
+ equipment = [
129
+ {
130
+ "equipment_id": "EQ001",
131
+ "equipment_code": "P-101A",
132
+ "equipment_name": "裂解进料泵A",
133
+ "equip_type_id": "ET_PUMP",
134
+ "plant_id": "PL001",
135
+ "unit_id": "PU001",
136
+ "manufacturer": "大连深蓝",
137
+ "model": "OH2-200",
138
+ "install_date": date(2018, 6, 15),
139
+ "design_capacity": 120.0,
140
+ "capacity_unit": "m³/h",
141
+ "criticality": "A",
142
+ "production_mode": "连续",
143
+ "status": "运行",
144
+ "ideal_cycle_rate": 0.083,
145
+ "output_unit": "吨",
146
+ "energy_base": 850.0,
147
+ },
148
+ {
149
+ "equipment_id": "EQ002",
150
+ "equipment_code": "C-201B",
151
+ "equipment_name": "裂解气压缩机B",
152
+ "equip_type_id": "ET_COMP",
153
+ "plant_id": "PL001",
154
+ "unit_id": "PU001",
155
+ "manufacturer": "沈阳鼓风机",
156
+ "model": "MCL403",
157
+ "install_date": date(2017, 3, 20),
158
+ "design_capacity": 50000.0,
159
+ "capacity_unit": "Nm³/h",
160
+ "criticality": "A",
161
+ "production_mode": "连续",
162
+ "status": "运行",
163
+ "ideal_cycle_rate": 34.7,
164
+ "output_unit": "吨",
165
+ "energy_base": 12000.0,
166
+ },
167
+ {
168
+ "equipment_id": "EQ003",
169
+ "equipment_code": "T-401",
170
+ "equipment_name": "乙烯精馏塔",
171
+ "equip_type_id": "ET_TOWER",
172
+ "plant_id": "PL001",
173
+ "unit_id": "PU002",
174
+ "manufacturer": "兰石重装",
175
+ "model": "T-1200",
176
+ "install_date": date(2018, 9, 1),
177
+ "design_capacity": 80.0,
178
+ "capacity_unit": "t/h",
179
+ "criticality": "A",
180
+ "production_mode": "连续",
181
+ "status": "运行",
182
+ "ideal_cycle_rate": 1.33,
183
+ "output_unit": "吨",
184
+ "energy_base": 3200.0,
185
+ },
186
+ {
187
+ "equipment_id": "EQ004",
188
+ "equipment_code": "P-102B",
189
+ "equipment_name": "回流泵B",
190
+ "equip_type_id": "ET_PUMP",
191
+ "plant_id": "PL001",
192
+ "unit_id": "PU002",
193
+ "manufacturer": "大连深蓝",
194
+ "model": "BB2-150",
195
+ "install_date": date(2019, 1, 10),
196
+ "design_capacity": 90.0,
197
+ "capacity_unit": "m³/h",
198
+ "criticality": "B",
199
+ "production_mode": "连续",
200
+ "status": "运行",
201
+ "ideal_cycle_rate": 0.062,
202
+ "output_unit": "吨",
203
+ "energy_base": 620.0,
204
+ },
205
+ {
206
+ "equipment_id": "EQ005",
207
+ "equipment_code": "R-301",
208
+ "equipment_name": "芳烃反应釜",
209
+ "equip_type_id": "ET_REACT",
210
+ "plant_id": "PL002",
211
+ "unit_id": "PU003",
212
+ "manufacturer": "张化机",
213
+ "model": "R-5000",
214
+ "install_date": date(2019, 5, 8),
215
+ "design_capacity": 45.0,
216
+ "capacity_unit": "t/h",
217
+ "criticality": "A",
218
+ "production_mode": "连续",
219
+ "status": "运行",
220
+ "ideal_cycle_rate": 0.75,
221
+ "output_unit": "吨",
222
+ "energy_base": 4500.0,
223
+ },
224
+ {
225
+ "equipment_id": "EQ006",
226
+ "equipment_code": "C-202A",
227
+ "equipment_name": "循环氢压缩机A",
228
+ "equip_type_id": "ET_COMP",
229
+ "plant_id": "PL002",
230
+ "unit_id": "PU003",
231
+ "manufacturer": "沈阳鼓风机",
232
+ "model": "MCL303",
233
+ "install_date": date(2018, 11, 22),
234
+ "design_capacity": 35000.0,
235
+ "capacity_unit": "Nm³/h",
236
+ "criticality": "A",
237
+ "production_mode": "连续",
238
+ "status": "运行",
239
+ "ideal_cycle_rate": 24.3,
240
+ "output_unit": "吨",
241
+ "energy_base": 9800.0,
242
+ },
243
+ {
244
+ "equipment_id": "EQ007",
245
+ "equipment_code": "T-402",
246
+ "equipment_name": "二甲苯精馏塔",
247
+ "equip_type_id": "ET_TOWER",
248
+ "plant_id": "PL002",
249
+ "unit_id": "PU004",
250
+ "manufacturer": "兰石重装",
251
+ "model": "T-900",
252
+ "install_date": date(2020, 2, 14),
253
+ "design_capacity": 55.0,
254
+ "capacity_unit": "t/h",
255
+ "criticality": "B",
256
+ "production_mode": "连续",
257
+ "status": "运行",
258
+ "ideal_cycle_rate": 0.92,
259
+ "output_unit": "吨",
260
+ "energy_base": 2800.0,
261
+ },
262
+ {
263
+ "equipment_id": "EQ008",
264
+ "equipment_code": "P-103A",
265
+ "equipment_name": "芳烃输送泵A",
266
+ "equip_type_id": "ET_PUMP",
267
+ "plant_id": "PL002",
268
+ "unit_id": "PU004",
269
+ "manufacturer": "大连深蓝",
270
+ "model": "OH2-180",
271
+ "install_date": date(2020, 8, 5),
272
+ "design_capacity": 100.0,
273
+ "capacity_unit": "m³/h",
274
+ "criticality": "B",
275
+ "production_mode": "连续",
276
+ "status": "运行",
277
+ "ideal_cycle_rate": 0.069,
278
+ "output_unit": "吨",
279
+ "energy_base": 720.0,
280
+ },
281
+ ]
282
+ plant_map = {p["plant_id"]: p for p in plants}
283
+ unit_map = {u["unit_id"]: u for u in units}
284
+ for eq in equipment:
285
+ et = type_map[eq["equip_type_id"]]
286
+ pl = plant_map[eq["plant_id"]]
287
+ un = unit_map[eq["unit_id"]]
288
+ eq["equip_type_name"] = et["equip_type_name"]
289
+ eq["category"] = et["category"]
290
+ eq["plant_name"] = pl["plant_name"]
291
+ eq["unit_name"] = un["unit_name"]
292
+ eq["created_at"] = _SEED_DT
293
+
294
+ eq_map = {e["equipment_id"]: e for e in equipment}
295
+
296
+ # 5. 停机原因码表
297
+ reasons = [
298
+ {"reason_id": "DR_PLAN", "reason_code": "PLAN", "reason_name": "计划检修", "reason_category": "计划检修", "is_planned": 1, "parent_reason_id": "", "status": "启用"},
299
+ {"reason_id": "DR_MECH", "reason_code": "MECH", "reason_name": "机械故障", "reason_category": "机械", "is_planned": 0, "parent_reason_id": "", "status": "启用"},
300
+ {"reason_id": "DR_MECH_SEAL", "reason_code": "MECH-SEAL", "reason_name": "密封泄漏", "reason_category": "机械", "is_planned": 0, "parent_reason_id": "DR_MECH", "status": "启用"},
301
+ {"reason_id": "DR_MECH_BEAR", "reason_code": "MECH-BEAR", "reason_name": "轴承损坏", "reason_category": "机械", "is_planned": 0, "parent_reason_id": "DR_MECH", "status": "启用"},
302
+ {"reason_id": "DR_ELEC", "reason_code": "ELEC", "reason_name": "电气故障", "reason_category": "电气", "is_planned": 0, "parent_reason_id": "", "status": "启用"},
303
+ {"reason_id": "DR_INST", "reason_code": "INST", "reason_name": "仪表故障", "reason_category": "仪表", "is_planned": 0, "parent_reason_id": "", "status": "启用"},
304
+ {"reason_id": "DR_PROC", "reason_code": "PROC", "reason_name": "工艺异常", "reason_category": "工艺", "is_planned": 0, "parent_reason_id": "", "status": "启用"},
305
+ {"reason_id": "DR_EXT", "reason_code": "EXT", "reason_name": "外部因素", "reason_category": "外部", "is_planned": 0, "parent_reason_id": "", "status": "启用"},
306
+ ]
307
+ for r in reasons:
308
+ r["created_at"] = _SEED_DT
309
+ reason_map = {r["reason_id"]: r for r in reasons}
310
+
311
+ # 灌入维表
312
+ s.sql.insert_rows("dim_plant", plants)
313
+ output.print(f"OK dim_plant {len(plants)} 条")
314
+ s.sql.insert_rows("dim_process_unit", units)
315
+ output.print(f"OK dim_process_unit {len(units)} 条")
316
+ s.sql.insert_rows("dim_equipment_type", equip_types)
317
+ output.print(f"OK dim_equipment_type {len(equip_types)} 条")
318
+
319
+ equip_rows = [{k: v for k, v in eq.items() if k not in ("ideal_cycle_rate", "output_unit", "energy_base")} for eq in equipment]
320
+ s.sql.insert_rows("dim_equipment", equip_rows)
321
+ output.print(f"OK dim_equipment {len(equip_rows)} 条")
322
+ s.sql.insert_rows("dim_downtime_reason", reasons)
323
+ output.print(f"OK dim_downtime_reason {len(reasons)} 条")
324
+
325
+ # 6. 设备周运行汇总(2025-01-01 ~ 2026-06-30,每周每设备 1 行)
326
+ ops_rows = []
327
+ ops_seq = 1
328
+ start = date(2025, 1, 1)
329
+ end = date(2026, 6, 30)
330
+ week_start = start
331
+
332
+ while week_start <= end:
333
+ week_end = min(week_start + timedelta(days=6), end)
334
+ dk = _date_key(week_start)
335
+
336
+ for eq in equipment:
337
+ avail_target = random.uniform(0.82, 0.96)
338
+ perf_target = random.uniform(0.88, 0.98)
339
+ qual_target = random.uniform(0.97, 0.995)
340
+
341
+ planned_dt = round(_WEEKLY_MINUTES * random.uniform(0.02, 0.08), 1)
342
+ sched_runtime = _WEEKLY_MINUTES - planned_dt
343
+ unplanned_dt = round(sched_runtime * (1 - avail_target) * random.uniform(0.5, 1.2), 1)
344
+ unplanned_dt = min(unplanned_dt, sched_runtime * 0.25)
345
+ runtime = round(sched_runtime - unplanned_dt, 1)
346
+ idle = round(max(_WEEKLY_MINUTES - planned_dt - unplanned_dt - runtime, 0), 1)
347
+
348
+ ideal_rate = eq["ideal_cycle_rate"]
349
+ actual_out = round(runtime * ideal_rate * perf_target * random.uniform(0.92, 1.05), 2)
350
+ qualified_out = round(actual_out * qual_target, 2)
351
+ planned_out = round(sched_runtime * ideal_rate * random.uniform(0.95, 1.02), 2)
352
+ energy = round(eq["energy_base"] * (runtime / _WEEKLY_MINUTES) * random.uniform(0.9, 1.1), 2)
353
+
354
+ ops_rows.append({
355
+ "ops_id": f"OPS{week_start.strftime('%Y%m%d')}{ops_seq:04d}{eq['equipment_id']}",
356
+ "date_key": dk,
357
+ "calendar_date": week_start,
358
+ "equipment_id": eq["equipment_id"],
359
+ "equipment_code": eq["equipment_code"],
360
+ "equipment_name": eq["equipment_name"],
361
+ "plant_id": eq["plant_id"],
362
+ "plant_name": eq["plant_name"],
363
+ "unit_id": eq["unit_id"],
364
+ "unit_name": eq["unit_name"],
365
+ "equip_type_id": eq["equip_type_id"],
366
+ "category": eq["category"],
367
+ "calendar_minutes": float(_WEEKLY_MINUTES),
368
+ "planned_downtime_min": planned_dt,
369
+ "unplanned_downtime_min": unplanned_dt,
370
+ "runtime_min": runtime,
371
+ "idle_min": idle,
372
+ "planned_output_qty": planned_out,
373
+ "actual_output_qty": actual_out,
374
+ "qualified_output_qty": qualified_out,
375
+ "output_unit": eq["output_unit"],
376
+ "ideal_cycle_rate": ideal_rate,
377
+ "energy_consumption": energy,
378
+ "energy_unit": "kWh",
379
+ "shift_code": "全天",
380
+ "data_source": "MES",
381
+ "created_at": datetime.combine(week_start, datetime.min.time()),
382
+ })
383
+ ops_seq += 1
384
+
385
+ week_start += timedelta(days=7)
386
+
387
+ ops_inserted = s.sql.insert_rows("fact_equipment_daily_ops", ops_rows)
388
+ output.print(f"OK fact_equipment_daily_ops 插入 {ops_inserted} 行")
389
+
390
+ # 7. 停机事件(24 条)
391
+ downtime_templates = [
392
+ ("EQ001", "DR_MECH_SEAL", "机动", "高", "进料泵机械密封泄漏,切换备用泵"),
393
+ ("EQ002", "DR_MECH_BEAR", "机动", "高", "压缩机推力轴承温度超限停机检查"),
394
+ ("EQ002", "DR_PLAN", "机动", "中", "压缩机年度大修"),
395
+ ("EQ003", "DR_PROC", "生产", "高", "塔顶温度波动,降负荷运行后恢复"),
396
+ ("EQ003", "DR_INST", "仪表", "中", "塔釜液位仪表故障导致联锁"),
397
+ ("EQ004", "DR_MECH", "机动", "低", "回流泵振动偏大,紧固后恢复"),
398
+ ("EQ004", "DR_ELEC", "电气", "中", "电机保护动作,检查接线"),
399
+ ("EQ005", "DR_PROC", "生产", "高", "反应器催化剂活性下降,计划降负荷"),
400
+ ("EQ005", "DR_PLAN", "机动", "中", "反应釜计划停车更换催化剂"),
401
+ ("EQ006", "DR_MECH", "机动", "高", "循环氢压缩机喘振保护停机"),
402
+ ("EQ006", "DR_ELEC", "电气", "中", "变频器故障"),
403
+ ("EQ007", "DR_INST", "仪表", "低", "塔顶压力变送器漂移"),
404
+ ("EQ007", "DR_EXT", "生产", "中", "上游来料中断导致降负荷"),
405
+ ("EQ008", "DR_MECH_BEAR", "机动", "中", "输送泵轴承异响更换"),
406
+ ("EQ001", "DR_PLAN", "机动", "中", "泵体计划保养"),
407
+ ("EQ002", "DR_INST", "仪表", "低", "振动探头校验"),
408
+ ("EQ003", "DR_PLAN", "机动", "高", "精馏塔计划停车检修"),
409
+ ("EQ005", "DR_MECH", "机动", "中", "搅拌器密封更换"),
410
+ ("EQ006", "DR_PLAN", "机动", "高", "压缩机计划检修"),
411
+ ("EQ001", "DR_ELEC", "电气", "低", "软启动器参数复位"),
412
+ ("EQ004", "DR_PLAN", "机动", "中", "回流泵计划保养"),
413
+ ("EQ008", "DR_PROC", "生产", "低", "输送量不足工艺调整"),
414
+ ("EQ006", "DR_EXT", "生产", "中", "电网波动引起停机"),
415
+ ("EQ007", "DR_MECH", "机动", "中", "再沸器管束泄漏排查"),
416
+ ]
417
+
418
+ downtime_rows = []
419
+ base_dt = datetime(2025, 2, 10, 8, 0, 0)
420
+ for idx, (eq_id, reason_id, dept, impact, desc) in enumerate(downtime_templates):
421
+ eq = eq_map[eq_id]
422
+ reason = reason_map[reason_id]
423
+ start_dt = base_dt + timedelta(days=idx * 18, hours=random.randint(0, 8))
424
+ duration = random.uniform(60, 480) if reason["is_planned"] == 0 else random.uniform(240, 1440)
425
+ end_dt = start_dt + timedelta(minutes=duration)
426
+ event_date = start_dt.date()
427
+
428
+ downtime_rows.append({
429
+ "event_id": f"DT{idx + 1:04d}",
430
+ "date_key": _date_key(event_date),
431
+ "equipment_id": eq_id,
432
+ "equipment_code": eq["equipment_code"],
433
+ "equipment_name": eq["equipment_name"],
434
+ "plant_id": eq["plant_id"],
435
+ "unit_id": eq["unit_id"],
436
+ "reason_id": reason_id,
437
+ "reason_code": reason["reason_code"],
438
+ "reason_name": reason["reason_name"],
439
+ "reason_category": reason["reason_category"],
440
+ "is_planned": reason["is_planned"],
441
+ "start_time": start_dt,
442
+ "end_time": end_dt,
443
+ "duration_min": round(duration, 1),
444
+ "impact_level": impact,
445
+ "responsible_dept": dept,
446
+ "description": desc,
447
+ "created_at": start_dt,
448
+ })
449
+
450
+ dt_inserted = s.sql.insert_rows("fact_downtime_event", downtime_rows)
451
+ output.print(f"OK fact_downtime_event 插入 {dt_inserted} 行")
452
+
453
+ # 8. 维保记录(16 条)
454
+ maint_templates = [
455
+ ("EQ001", "预防", "完成", 1, 8, 7.5, 12000, 11500),
456
+ ("EQ002", "预测", "完成", 1, 24, 22, 85000, 82000),
457
+ ("EQ002", "大修", "完成", 1, 72, 68, 320000, 305000),
458
+ ("EQ003", "预防", "完成", 0, 16, 18, 45000, 48000),
459
+ ("EQ003", "故障维修", "完成", 1, 12, 10, 28000, 26500),
460
+ ("EQ004", "预防", "完成", 1, 6, 5.5, 8000, 7800),
461
+ ("EQ005", "预测", "完成", 1, 20, 19, 65000, 63000),
462
+ ("EQ005", "大修", "进行中", 0, 48, 0, 180000, 0),
463
+ ("EQ006", "预防", "完成", 1, 18, 17, 55000, 54000),
464
+ ("EQ006", "故障维修", "完成", 1, 10, 12, 35000, 38000),
465
+ ("EQ007", "预防", "逾期", 0, 8, 0, 12000, 0),
466
+ ("EQ007", "预防", "计划", 0, 8, 0, 12000, 0),
467
+ ("EQ008", "预防", "完成", 1, 6, 6, 9000, 9200),
468
+ ("EQ001", "故障维修", "完成", 1, 4, 3.5, 6000, 5800),
469
+ ("EQ004", "预测", "完成", 1, 10, 9, 15000, 14500),
470
+ ("EQ008", "故障维修", "完成", 0, 5, 6, 7500, 8200),
471
+ ]
472
+
473
+ maint_rows = []
474
+ maint_base = date(2025, 3, 1)
475
+ for idx, (eq_id, mtype, status, on_sched, plan_h, act_h, plan_c, act_c) in enumerate(maint_templates):
476
+ eq = eq_map[eq_id]
477
+ plan_d = maint_base + timedelta(days=idx * 25)
478
+ actual_d = plan_d + timedelta(days=random.randint(-2, 3)) if status in ("完成", "逾期") and act_h > 0 else None
479
+ if status == "逾期":
480
+ actual_d = None
481
+ dk = _date_key(actual_d or plan_d)
482
+
483
+ maint_rows.append({
484
+ "maint_id": f"MR{idx + 1:04d}",
485
+ "date_key": dk,
486
+ "equipment_id": eq_id,
487
+ "equipment_code": eq["equipment_code"],
488
+ "plant_id": eq["plant_id"],
489
+ "unit_id": eq["unit_id"],
490
+ "maint_type": mtype,
491
+ "plan_date": plan_d,
492
+ "actual_date": actual_d,
493
+ "plan_hours": float(plan_h),
494
+ "actual_hours": float(act_h),
495
+ "plan_cost": float(plan_c),
496
+ "actual_cost": float(act_c),
497
+ "status": status,
498
+ "is_on_schedule": on_sched,
499
+ "vendor": "机动科自营" if mtype != "大修" else "外委-石化检修",
500
+ "description": f"{eq['equipment_name']}{mtype}作业",
501
+ "created_at": datetime.combine(plan_d, datetime.min.time()),
502
+ })
503
+
504
+ maint_inserted = s.sql.insert_rows("fact_maintenance_record", maint_rows)
505
+ output.print(f"OK fact_maintenance_record 插入 {maint_inserted} 行")
506
+
507
+ # 9. 2026 年 6 月运行计划
508
+ plan_rows = []
509
+ plan_month_start = date(2026, 6, 1)
510
+ dk_june = _date_key(plan_month_start)
511
+ month_runtime = 30 * 1440 * 0.92
512
+
513
+ for idx, eq in enumerate(equipment):
514
+ planned_rt = round(month_runtime * random.uniform(0.88, 0.95), 1)
515
+ planned_out = round(planned_rt * eq["ideal_cycle_rate"] * random.uniform(0.94, 1.0), 2)
516
+ planned_energy = round(eq["energy_base"] * 30 * random.uniform(0.9, 1.05), 2)
517
+ plan_rows.append({
518
+ "plan_id": f"PLN202606{idx + 1:03d}",
519
+ "date_key": dk_june,
520
+ "equipment_id": eq["equipment_id"],
521
+ "equipment_code": eq["equipment_code"],
522
+ "plant_id": eq["plant_id"],
523
+ "unit_id": eq["unit_id"],
524
+ "plan_version": _PLAN_VERSION,
525
+ "fiscal_year": 2026,
526
+ "fiscal_month": 6,
527
+ "planned_runtime_min": planned_rt,
528
+ "planned_output_qty": planned_out,
529
+ "planned_energy": planned_energy,
530
+ "output_unit": eq["output_unit"],
531
+ "status": "已发布",
532
+ "created_at": datetime(2026, 5, 25, 0, 0, 0),
533
+ })
534
+
535
+ plan_inserted = s.sql.insert_rows("fact_equipment_plan", plan_rows)
536
+ output.print(f"OK fact_equipment_plan 插入 {plan_inserted} 行")
537
+
538
+ summary = {
539
+ "ok": True,
540
+ "space_id": space_id,
541
+ "plants": len(plants),
542
+ "units": len(units),
543
+ "equip_types": len(equip_types),
544
+ "equipment": len(equipment),
545
+ "reasons": len(reasons),
546
+ "ops_inserted": ops_inserted,
547
+ "downtime_inserted": dt_inserted,
548
+ "maint_inserted": maint_inserted,
549
+ "plan_inserted": plan_inserted,
550
+ }
551
+ output.success("灌数完成")
552
+ output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))
@@ -0,0 +1,23 @@
1
+ # 销售示例 · 产品销售分析
2
+
3
+ ## 基本信息
4
+
5
+ | 字段 | 内容 |
6
+ | --- | --- |
7
+ | 数据空间 | 以示例脚本内 `space_id` 为准(复制后改 README) |
8
+ | 示例 ID | `sales`(见 `../index.yaml` / `index.json`) |
9
+
10
+ ## 目录
11
+
12
+ | 路径 | 说明 |
13
+ | --- | --- |
14
+ | [plans/规划示例_产品销售本体规划方案.md](./plans/规划示例_产品销售本体规划方案.md) | **规划正文**(表/Cube/对象/函数/附录 B) |
15
+ | `setup/` | `sales_ontology_init.py`、`sales_seed_data.py`、`sales_category_mount.py` |
16
+ | `functions/` | 7 个 `sales_fn_*.py`、`test_arguments/`、`save_test_arguments.ps1` |
17
+
18
+ ## 使用
19
+
20
+ - **规划阶段**:通读 `plans/*.md` 学结构;在本项目 `plans/` **独立撰写** + 差异说明
21
+ - **实施阶段**:`plans/` 定稿后对照 `setup/`、`functions/` API 写法或复制改造
22
+
23
+ 规范指南:`资源/docs/onto/本体规划指南.md`
@@ -1,9 +1,8 @@
1
1
  # save_test_arguments.ps1
2
2
  # 批量保存各函数的 test_arguments
3
- # 用法:在 dazi-work 根目录执行 .\项目\DAZI_TEST\本体\ontos\销售本体示例\functions\save_test_arguments.ps1
3
+ # 用法:在 dazi-work 根目录执行 .\项目\<业务>\本体\ontos\<实现>\functions\save_test_arguments.ps1
4
4
 
5
5
  $spaceId = "space__misc_01"
6
- $itemPath = "项目/DAZI_TEST/本体/ontos/销售本体示例/functions"
7
6
 
8
7
  $functions = @(
9
8
  @{fn_id="sales.fn.get_summary"; file="sales.fn.get_summary.json"},
@@ -15,23 +14,25 @@ $functions = @(
15
14
  @{fn_id="sales.fn.channel_mix"; file="sales.fn.channel_mix.json"}
16
15
  )
17
16
 
18
- # 先获取 function list 获取 ofn_xxx 内部 id
19
17
  Write-Host "获取函数列表..."
20
- $fnList = & dazi onto function list --space $spaceId --output json 2>$null | ConvertFrom-Json
18
+ $fnListRaw = & dazi onto function list --space $spaceId --json 2>&1
19
+ $jsonLines = ($fnListRaw | Where-Object { $_ -notmatch '__JSON_SUMMARY__' }) -join "`n"
20
+ $fnList = $jsonLines | ConvertFrom-Json
21
21
 
22
22
  foreach ($fn in $functions) {
23
23
  $fnId = $fn.fn_id
24
24
  $fileName = $fn.file
25
25
  $jsonPath = "$PSScriptRoot/test_arguments/$fileName"
26
26
 
27
- # 查找 ofn_xxx 内部 id
28
- $fnInfo = $fnList | Where-Object { $_.function_id -eq $fnId }
29
- if ($fnInfo) {
30
- $ofnId = $fnInfo.id
31
- Write-Host "保存 $fnId (ofnId=$ofnId)..."
32
- & dazi onto function save-test-arguments $ofnId --space $spaceId --arguments-json-file $jsonPath
33
- } else {
34
- Write-Host "函数 $fnId 未找到,请先发布函数"
27
+ if (-not (Test-Path $jsonPath)) {
28
+ Write-Host "跳过 $fnId:找不到 $jsonPath"
29
+ continue
30
+ }
31
+
32
+ Write-Host "保存 $fnId ..."
33
+ & dazi onto function save-test-arguments --function-id $fnId --space $spaceId --arguments-json-file $jsonPath
34
+ if ($LASTEXITCODE -ne 0) {
35
+ Write-Host " ✗ 保存失败" -ForegroundColor Red
35
36
  }
36
37
  }
37
38