@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.
- package/README.md +1 -1
- package/dist/clis/dazi-app.js +2 -2
- package/dist/clis/dazi-flow.js +2 -2
- package/dist/clis/dazi-onto.js +324 -41
- package/dist/clis/dazi.js +407 -185
- package/dist/docs/flow/flow-project-guide.md +1 -1
- package/dist/docs/guides/cli-reference.md +16 -3
- package/dist/docs/guides/troubleshooting.md +3 -3
- package/dist/docs/index.json +3 -15
- package/dist/docs/onto/dazi_script_sdk_reference.md +246 -244
- package/dist/docs/onto/dazi_script_seed_data_guide.md +1 -1
- package/dist/docs/onto/function-guide.md +123 -123
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/index.json +222 -6
- package/dist/examples/onto/README.md +34 -36
- package/dist/examples/onto/_templates/onto_preflight.ps1 +84 -0
- package/dist/examples/onto/index.json +53 -0
- package/dist/examples/onto/index.yaml +29 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/README.md +23 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/save_test_arguments.ps1 +12 -11
- 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
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_category_mount.py +85 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +3 -66
- package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/README.md +24 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/functions/save_test_arguments.ps1 +42 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/setup/equip_ops_category_mount.py +106 -0
- package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/setup/equip_ops_ontology_init.py +1077 -0
- package/dist/examples/onto//350/256/276/345/244/207/350/277/220/350/220/245/setup/equip_ops_seed_data.py +552 -0
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/README.md +23 -0
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +13 -12
- 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
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_category_mount.py +82 -0
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +3 -54
- package/dist/prompts/index.json +8 -1
- package/dist/prompts/onto/function-design.md +73 -73
- package/dist/prompts/onto/planning-design.md +226 -0
- package/dist/prompts/onto/script-publish-run.md +231 -208
- package/package.json +1 -1
- 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,24 @@
|
|
|
1
|
+
# 设备运营 · 化工设备运营分析
|
|
2
|
+
|
|
3
|
+
## 基本信息
|
|
4
|
+
|
|
5
|
+
| 字段 | 内容 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| 数据空间 | 分类测试01 |
|
|
8
|
+
| 数据空间 ID | `space_cate_test01` |
|
|
9
|
+
| 示例 ID | `equip-ops`(见 `../index.yaml` / `index.json`) |
|
|
10
|
+
|
|
11
|
+
## 目录
|
|
12
|
+
|
|
13
|
+
| 路径 | 说明 |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| [plans/化工设备运营分析本体方案.md](./plans/化工设备运营分析本体方案.md) | **规划正文**(OEE、停机等) |
|
|
16
|
+
| `setup/` | `equip_ops_ontology_init.py`、`equip_ops_seed_data.py`、`equip_ops_category_mount.py` |
|
|
17
|
+
| `functions/` | 11 个 `equip_ops_fn_*.py`、`test_arguments/` |
|
|
18
|
+
|
|
19
|
+
## 使用
|
|
20
|
+
|
|
21
|
+
- **规划阶段**:推荐阅读(含 Cube + 冗余字段策略 + 11 函数清单)
|
|
22
|
+
- **实施阶段**:init 不含 `apply_registry`;见 `equip_ops_category_mount.py`
|
|
23
|
+
|
|
24
|
+
规范指南:`资源/docs/onto/本体规划指南.md`
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""可用率与停机结构分析 equip_ops.fn.availability_analysis
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, plant_id(可选)
|
|
4
|
+
返回:planned_downtime_hours, unplanned_downtime_hours, runtime_hours, availability, load_rate
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_availability_analysis.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.availability_analysis
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
TEST_ARGUMENTS = {
|
|
12
|
+
"v": 1,
|
|
13
|
+
"arguments": {"start_date": "2025-01-01", "end_date": "2026-06-30"},
|
|
14
|
+
"object_type_code": "EquipmentAnalysis",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _build_ops_where(start_date, end_date, plant_id=None):
|
|
19
|
+
clauses = []
|
|
20
|
+
if start_date and end_date:
|
|
21
|
+
clauses.append(f"calendar_date >= '{start_date}' AND calendar_date <= '{end_date}'")
|
|
22
|
+
if plant_id:
|
|
23
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
24
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _ontology_fn_body(p):
|
|
28
|
+
params = dict(p.get_params() or {})
|
|
29
|
+
start_date = params.get("start_date", "")
|
|
30
|
+
end_date = params.get("end_date", "")
|
|
31
|
+
plant_id = params.get("plant_id") or None
|
|
32
|
+
where_clause = _build_ops_where(start_date, end_date, plant_id)
|
|
33
|
+
|
|
34
|
+
sql = f"""
|
|
35
|
+
SELECT
|
|
36
|
+
sum(planned_downtime_min) AS sum_planned_downtime_min,
|
|
37
|
+
sum(unplanned_downtime_min) AS sum_unplanned_downtime_min,
|
|
38
|
+
sum(runtime_min) AS sum_runtime_min,
|
|
39
|
+
sum(calendar_minutes - planned_downtime_min) AS sum_available_min
|
|
40
|
+
FROM fact_equipment_daily_ops
|
|
41
|
+
{where_clause}
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
rows = p.sql.query(sql)
|
|
45
|
+
row = rows[0] if rows else {}
|
|
46
|
+
|
|
47
|
+
sum_runtime = float(row.get("sum_runtime_min") or 0)
|
|
48
|
+
sum_available = float(row.get("sum_available_min") or 0)
|
|
49
|
+
availability = sum_runtime / sum_available if sum_available > 0 else 0.0
|
|
50
|
+
load_rate = availability
|
|
51
|
+
|
|
52
|
+
data = [{
|
|
53
|
+
"planned_downtime_hours": round(float(row.get("sum_planned_downtime_min") or 0) / 60.0, 2),
|
|
54
|
+
"unplanned_downtime_hours": round(
|
|
55
|
+
float(row.get("sum_unplanned_downtime_min") or 0) / 60.0, 2
|
|
56
|
+
),
|
|
57
|
+
"runtime_hours": round(sum_runtime / 60.0, 2),
|
|
58
|
+
"availability": round(availability, 4),
|
|
59
|
+
"load_rate": round(load_rate, 4),
|
|
60
|
+
}]
|
|
61
|
+
|
|
62
|
+
return p.function_result(
|
|
63
|
+
columns=[
|
|
64
|
+
"planned_downtime_hours", "unplanned_downtime_hours",
|
|
65
|
+
"runtime_hours", "availability", "load_rate",
|
|
66
|
+
],
|
|
67
|
+
data=data,
|
|
68
|
+
row_count=1,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main():
|
|
73
|
+
s = space.get(ctx.space_id or "")
|
|
74
|
+
_Ports = type(
|
|
75
|
+
"_Ports",
|
|
76
|
+
(),
|
|
77
|
+
{
|
|
78
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
79
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
p = _Ports()
|
|
83
|
+
p.sql = s.sql
|
|
84
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""停机原因结构分析 equip_ops.fn.downtime_breakdown
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, reason_level=2, plant_id(可选)
|
|
4
|
+
JOIN dim_downtime_reason,返回 reason_code, reason_name, reason_category,
|
|
5
|
+
is_planned, downtime_hours, event_count, share_pct
|
|
6
|
+
|
|
7
|
+
发布:
|
|
8
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_downtime_breakdown.py \
|
|
9
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.downtime_breakdown
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
TEST_ARGUMENTS = {
|
|
13
|
+
"v": 1,
|
|
14
|
+
"arguments": {
|
|
15
|
+
"start_date": "2025-01-01",
|
|
16
|
+
"end_date": "2026-06-30",
|
|
17
|
+
"reason_level": 2,
|
|
18
|
+
},
|
|
19
|
+
"object_type_code": "EquipmentAnalysis",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _build_where(start_date, end_date, plant_id=None):
|
|
24
|
+
clauses = []
|
|
25
|
+
if start_date and end_date:
|
|
26
|
+
clauses.append(
|
|
27
|
+
f"e.start_time >= '{start_date} 00:00:00' AND e.start_time <= '{end_date} 23:59:59'"
|
|
28
|
+
)
|
|
29
|
+
if plant_id:
|
|
30
|
+
clauses.append(f"e.plant_id = '{plant_id}'")
|
|
31
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _ontology_fn_body(p):
|
|
35
|
+
params = dict(p.get_params() or {})
|
|
36
|
+
start_date = params.get("start_date", "")
|
|
37
|
+
end_date = params.get("end_date", "")
|
|
38
|
+
reason_level = int(params.get("reason_level", 2) or 2)
|
|
39
|
+
plant_id = params.get("plant_id") or None
|
|
40
|
+
where_clause = _build_where(start_date, end_date, plant_id)
|
|
41
|
+
|
|
42
|
+
if reason_level <= 1:
|
|
43
|
+
group_cols = "dr.reason_category"
|
|
44
|
+
select_cols = """
|
|
45
|
+
dr.reason_category AS reason_code,
|
|
46
|
+
dr.reason_category AS reason_name,
|
|
47
|
+
dr.reason_category AS reason_category,
|
|
48
|
+
max(dr.is_planned) AS is_planned
|
|
49
|
+
"""
|
|
50
|
+
else:
|
|
51
|
+
group_cols = "dr.reason_code, dr.reason_name, dr.reason_category, dr.is_planned"
|
|
52
|
+
select_cols = """
|
|
53
|
+
dr.reason_code AS reason_code,
|
|
54
|
+
dr.reason_name AS reason_name,
|
|
55
|
+
dr.reason_category AS reason_category,
|
|
56
|
+
dr.is_planned AS is_planned
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
sql = f"""
|
|
60
|
+
SELECT
|
|
61
|
+
{select_cols},
|
|
62
|
+
sum(e.duration_min) AS downtime_min,
|
|
63
|
+
count() AS event_count
|
|
64
|
+
FROM fact_downtime_event AS e
|
|
65
|
+
INNER JOIN dim_downtime_reason AS dr ON e.reason_id = dr.reason_id
|
|
66
|
+
{where_clause}
|
|
67
|
+
GROUP BY {group_cols}
|
|
68
|
+
ORDER BY downtime_min DESC
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
result = p.sql.query(sql)
|
|
72
|
+
if not result:
|
|
73
|
+
return p.function_result(
|
|
74
|
+
columns=[
|
|
75
|
+
"reason_code", "reason_name", "reason_category",
|
|
76
|
+
"is_planned", "downtime_hours", "event_count", "share_pct",
|
|
77
|
+
],
|
|
78
|
+
data=[],
|
|
79
|
+
row_count=0,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
total_min = sum(float(r.get("downtime_min") or 0) for r in result)
|
|
83
|
+
data = []
|
|
84
|
+
for row in result:
|
|
85
|
+
downtime_min = float(row.get("downtime_min") or 0)
|
|
86
|
+
share_pct = downtime_min / total_min if total_min > 0 else 0.0
|
|
87
|
+
data.append({
|
|
88
|
+
"reason_code": str(row.get("reason_code") or ""),
|
|
89
|
+
"reason_name": str(row.get("reason_name") or ""),
|
|
90
|
+
"reason_category": str(row.get("reason_category") or ""),
|
|
91
|
+
"is_planned": int(row.get("is_planned") or 0),
|
|
92
|
+
"downtime_hours": round(downtime_min / 60.0, 2),
|
|
93
|
+
"event_count": int(row.get("event_count") or 0),
|
|
94
|
+
"share_pct": round(share_pct, 4),
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return p.function_result(
|
|
98
|
+
columns=[
|
|
99
|
+
"reason_code", "reason_name", "reason_category",
|
|
100
|
+
"is_planned", "downtime_hours", "event_count", "share_pct",
|
|
101
|
+
],
|
|
102
|
+
data=data,
|
|
103
|
+
row_count=len(data),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main():
|
|
108
|
+
s = space.get(ctx.space_id or "")
|
|
109
|
+
_Ports = type(
|
|
110
|
+
"_Ports",
|
|
111
|
+
(),
|
|
112
|
+
{
|
|
113
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
114
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
p = _Ports()
|
|
118
|
+
p.sql = s.sql
|
|
119
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""能耗强度分析 equip_ops.fn.energy_intensity
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, group_by=plant|unit|equipment, plant_id(可选)
|
|
4
|
+
返回:group_id, group_name, energy_total, output_qty, energy_per_output
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_energy_intensity.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.energy_intensity
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
TEST_ARGUMENTS = {
|
|
12
|
+
"v": 1,
|
|
13
|
+
"arguments": {
|
|
14
|
+
"start_date": "2025-01-01",
|
|
15
|
+
"end_date": "2026-06-30",
|
|
16
|
+
"group_by": "plant",
|
|
17
|
+
},
|
|
18
|
+
"object_type_code": "EquipmentAnalysis",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_GROUP_BY_MAP = {
|
|
22
|
+
"plant": ("plant_id", "any(plant_name)"),
|
|
23
|
+
"unit": ("unit_id", "any(unit_name)"),
|
|
24
|
+
"equipment": ("equipment_id", "any(equipment_name)"),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _build_ops_where(start_date, end_date, plant_id=None):
|
|
29
|
+
clauses = []
|
|
30
|
+
if start_date and end_date:
|
|
31
|
+
clauses.append(f"calendar_date >= '{start_date}' AND calendar_date <= '{end_date}'")
|
|
32
|
+
if plant_id:
|
|
33
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
34
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _ontology_fn_body(p):
|
|
38
|
+
params = dict(p.get_params() or {})
|
|
39
|
+
start_date = params.get("start_date", "")
|
|
40
|
+
end_date = params.get("end_date", "")
|
|
41
|
+
group_by = params.get("group_by", "plant")
|
|
42
|
+
plant_id = params.get("plant_id") or None
|
|
43
|
+
group_id_col, group_name_expr = _GROUP_BY_MAP.get(group_by, _GROUP_BY_MAP["plant"])
|
|
44
|
+
where_clause = _build_ops_where(start_date, end_date, plant_id)
|
|
45
|
+
|
|
46
|
+
sql = f"""
|
|
47
|
+
SELECT
|
|
48
|
+
{group_id_col} AS group_id,
|
|
49
|
+
{group_name_expr} AS group_name,
|
|
50
|
+
sum(energy_consumption) AS energy_total,
|
|
51
|
+
sum(actual_output_qty) AS output_qty
|
|
52
|
+
FROM fact_equipment_daily_ops
|
|
53
|
+
{where_clause}
|
|
54
|
+
GROUP BY {group_id_col}
|
|
55
|
+
ORDER BY energy_total DESC
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
result = p.sql.query(sql)
|
|
59
|
+
if not result:
|
|
60
|
+
return p.function_result(
|
|
61
|
+
columns=["group_id", "group_name", "energy_total", "output_qty", "energy_per_output"],
|
|
62
|
+
data=[],
|
|
63
|
+
row_count=0,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
data = []
|
|
67
|
+
for row in result:
|
|
68
|
+
energy_total = float(row.get("energy_total") or 0)
|
|
69
|
+
output_qty = float(row.get("output_qty") or 0)
|
|
70
|
+
energy_per_output = energy_total / output_qty if output_qty > 0 else 0.0
|
|
71
|
+
data.append({
|
|
72
|
+
"group_id": str(row.get("group_id") or ""),
|
|
73
|
+
"group_name": str(row.get("group_name") or ""),
|
|
74
|
+
"energy_total": round(energy_total, 2),
|
|
75
|
+
"output_qty": round(output_qty, 2),
|
|
76
|
+
"energy_per_output": round(energy_per_output, 4),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
return p.function_result(
|
|
80
|
+
columns=["group_id", "group_name", "energy_total", "output_qty", "energy_per_output"],
|
|
81
|
+
data=data,
|
|
82
|
+
row_count=len(data),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main():
|
|
87
|
+
s = space.get(ctx.space_id or "")
|
|
88
|
+
_Ports = type(
|
|
89
|
+
"_Ports",
|
|
90
|
+
(),
|
|
91
|
+
{
|
|
92
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
93
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
p = _Ports()
|
|
97
|
+
p.sql = s.sql
|
|
98
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""设备运营总览 equip_ops.fn.get_summary
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, plant_id(可选)
|
|
4
|
+
返回:equipment_count, avg_availability, avg_oee, total_runtime_hours,
|
|
5
|
+
total_unplanned_downtime_hours, total_output_qty, total_energy,
|
|
6
|
+
energy_per_output, downtime_event_count
|
|
7
|
+
|
|
8
|
+
发布:
|
|
9
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_get_summary.py \
|
|
10
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.get_summary
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
TEST_ARGUMENTS = {
|
|
14
|
+
"v": 1,
|
|
15
|
+
"arguments": {"start_date": "2025-01-01", "end_date": "2026-06-30"},
|
|
16
|
+
"object_type_code": "EquipmentAnalysis",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _build_ops_where(start_date, end_date, plant_id=None):
|
|
21
|
+
clauses = []
|
|
22
|
+
if start_date and end_date:
|
|
23
|
+
clauses.append(f"calendar_date >= '{start_date}' AND calendar_date <= '{end_date}'")
|
|
24
|
+
if plant_id:
|
|
25
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
26
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _build_downtime_where(start_date, end_date, plant_id=None):
|
|
30
|
+
clauses = []
|
|
31
|
+
if start_date and end_date:
|
|
32
|
+
clauses.append(
|
|
33
|
+
f"toDate(start_time) >= '{start_date}' AND toDate(start_time) <= '{end_date}'"
|
|
34
|
+
)
|
|
35
|
+
if plant_id:
|
|
36
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
37
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _calc_oee_from_sums(row):
|
|
41
|
+
sum_runtime = float(row.get("sum_runtime_min") or 0)
|
|
42
|
+
sum_available = float(row.get("sum_available_min") or 0)
|
|
43
|
+
sum_actual = float(row.get("sum_actual_output") or 0)
|
|
44
|
+
sum_qualified = float(row.get("sum_qualified_output") or 0)
|
|
45
|
+
sum_theoretical = float(row.get("sum_theoretical_output") or 0)
|
|
46
|
+
availability = sum_runtime / sum_available if sum_available > 0 else 0.0
|
|
47
|
+
quality = sum_qualified / sum_actual if sum_actual > 0 else 0.0
|
|
48
|
+
performance = sum_actual / sum_theoretical if sum_theoretical > 0 else 0.0
|
|
49
|
+
oee = availability * performance * quality
|
|
50
|
+
return round(availability, 4), round(oee, 4)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _ontology_fn_body(p):
|
|
54
|
+
params = dict(p.get_params() or {})
|
|
55
|
+
start_date = params.get("start_date", "")
|
|
56
|
+
end_date = params.get("end_date", "")
|
|
57
|
+
plant_id = params.get("plant_id") or None
|
|
58
|
+
where_clause = _build_ops_where(start_date, end_date, plant_id)
|
|
59
|
+
|
|
60
|
+
sql = f"""
|
|
61
|
+
SELECT
|
|
62
|
+
uniq(equipment_id) AS equipment_count,
|
|
63
|
+
sum(runtime_min) AS sum_runtime_min,
|
|
64
|
+
sum(calendar_minutes - planned_downtime_min) AS sum_available_min,
|
|
65
|
+
sum(actual_output_qty) AS sum_actual_output,
|
|
66
|
+
sum(qualified_output_qty) AS sum_qualified_output,
|
|
67
|
+
sumIf(runtime_min * ideal_cycle_rate, runtime_min > 0) AS sum_theoretical_output,
|
|
68
|
+
sum(unplanned_downtime_min) AS sum_unplanned_downtime_min,
|
|
69
|
+
sum(energy_consumption) AS sum_energy
|
|
70
|
+
FROM fact_equipment_daily_ops
|
|
71
|
+
{where_clause}
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
rows = p.sql.query(sql)
|
|
75
|
+
row = rows[0] if rows else {}
|
|
76
|
+
avg_availability, avg_oee = _calc_oee_from_sums(row)
|
|
77
|
+
|
|
78
|
+
sum_runtime = float(row.get("sum_runtime_min") or 0)
|
|
79
|
+
sum_actual = float(row.get("sum_actual_output") or 0)
|
|
80
|
+
sum_energy = float(row.get("sum_energy") or 0)
|
|
81
|
+
energy_per_output = sum_energy / sum_actual if sum_actual > 0 else 0.0
|
|
82
|
+
|
|
83
|
+
dt_where = _build_downtime_where(start_date, end_date, plant_id)
|
|
84
|
+
dt_sql = f"SELECT count() AS event_count FROM fact_downtime_event {dt_where}"
|
|
85
|
+
dt_rows = p.sql.query(dt_sql)
|
|
86
|
+
downtime_event_count = int((dt_rows[0] if dt_rows else {}).get("event_count") or 0)
|
|
87
|
+
|
|
88
|
+
data = [{
|
|
89
|
+
"equipment_count": int(row.get("equipment_count") or 0),
|
|
90
|
+
"avg_availability": avg_availability,
|
|
91
|
+
"avg_oee": avg_oee,
|
|
92
|
+
"total_runtime_hours": round(sum_runtime / 60.0, 2),
|
|
93
|
+
"total_unplanned_downtime_hours": round(
|
|
94
|
+
float(row.get("sum_unplanned_downtime_min") or 0) / 60.0, 2
|
|
95
|
+
),
|
|
96
|
+
"total_output_qty": round(sum_actual, 2),
|
|
97
|
+
"total_energy": round(sum_energy, 2),
|
|
98
|
+
"energy_per_output": round(energy_per_output, 4),
|
|
99
|
+
"downtime_event_count": downtime_event_count,
|
|
100
|
+
}]
|
|
101
|
+
|
|
102
|
+
return p.function_result(
|
|
103
|
+
columns=[
|
|
104
|
+
"equipment_count", "avg_availability", "avg_oee", "total_runtime_hours",
|
|
105
|
+
"total_unplanned_downtime_hours", "total_output_qty", "total_energy",
|
|
106
|
+
"energy_per_output", "downtime_event_count",
|
|
107
|
+
],
|
|
108
|
+
data=data,
|
|
109
|
+
row_count=1,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def main():
|
|
114
|
+
s = space.get(ctx.space_id or "")
|
|
115
|
+
_Ports = type(
|
|
116
|
+
"_Ports",
|
|
117
|
+
(),
|
|
118
|
+
{
|
|
119
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
120
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
p = _Ports()
|
|
124
|
+
p.sql = s.sql
|
|
125
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""维保达成分析 equip_ops.fn.maintenance_compliance
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, plant_id(可选)
|
|
4
|
+
返回:schedule_rate, total_maint, on_schedule_count, overdue_count, total_cost
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_maintenance_compliance.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.maintenance_compliance
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
TEST_ARGUMENTS = {
|
|
12
|
+
"v": 1,
|
|
13
|
+
"arguments": {"start_date": "2025-01-01", "end_date": "2026-06-30"},
|
|
14
|
+
"object_type_code": "EquipmentAnalysis",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _build_where(start_date, end_date, plant_id=None):
|
|
19
|
+
clauses = []
|
|
20
|
+
if start_date and end_date:
|
|
21
|
+
clauses.append(f"plan_date >= '{start_date}' AND plan_date <= '{end_date}'")
|
|
22
|
+
if plant_id:
|
|
23
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
24
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _ontology_fn_body(p):
|
|
28
|
+
params = dict(p.get_params() or {})
|
|
29
|
+
start_date = params.get("start_date", "")
|
|
30
|
+
end_date = params.get("end_date", "")
|
|
31
|
+
plant_id = params.get("plant_id") or None
|
|
32
|
+
where_clause = _build_where(start_date, end_date, plant_id)
|
|
33
|
+
|
|
34
|
+
sql = f"""
|
|
35
|
+
SELECT
|
|
36
|
+
count() AS total_maint,
|
|
37
|
+
sum(is_on_schedule) AS on_schedule_count,
|
|
38
|
+
countIf(status = '逾期') AS overdue_count,
|
|
39
|
+
sum(actual_cost) AS total_cost
|
|
40
|
+
FROM fact_maintenance_record
|
|
41
|
+
{where_clause}
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
rows = p.sql.query(sql)
|
|
45
|
+
row = rows[0] if rows else {}
|
|
46
|
+
total_maint = int(row.get("total_maint") or 0)
|
|
47
|
+
on_schedule_count = int(row.get("on_schedule_count") or 0)
|
|
48
|
+
schedule_rate = on_schedule_count / total_maint if total_maint > 0 else 0.0
|
|
49
|
+
|
|
50
|
+
data = [{
|
|
51
|
+
"schedule_rate": round(schedule_rate, 4),
|
|
52
|
+
"total_maint": total_maint,
|
|
53
|
+
"on_schedule_count": on_schedule_count,
|
|
54
|
+
"overdue_count": int(row.get("overdue_count") or 0),
|
|
55
|
+
"total_cost": round(float(row.get("total_cost") or 0), 2),
|
|
56
|
+
}]
|
|
57
|
+
|
|
58
|
+
return p.function_result(
|
|
59
|
+
columns=["schedule_rate", "total_maint", "on_schedule_count", "overdue_count", "total_cost"],
|
|
60
|
+
data=data,
|
|
61
|
+
row_count=1,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def main():
|
|
66
|
+
s = space.get(ctx.space_id or "")
|
|
67
|
+
_Ports = type(
|
|
68
|
+
"_Ports",
|
|
69
|
+
(),
|
|
70
|
+
{
|
|
71
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
72
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
p = _Ports()
|
|
76
|
+
p.sql = s.sql
|
|
77
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""环比分析 equip_ops.fn.mom_analysis
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, metric=oee|availability|output, unit_id(可选)
|
|
4
|
+
对比上一同等长度期间,返回 current / previous / mom
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_mom_analysis.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.mom_analysis
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from datetime import datetime, timedelta
|
|
12
|
+
|
|
13
|
+
TEST_ARGUMENTS = {
|
|
14
|
+
"v": 1,
|
|
15
|
+
"arguments": {
|
|
16
|
+
"start_date": "2025-01-01",
|
|
17
|
+
"end_date": "2026-06-30",
|
|
18
|
+
"metric": "availability",
|
|
19
|
+
},
|
|
20
|
+
"object_type_code": "EquipmentAnalysis",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _build_ops_where(start_date, end_date, unit_id=None):
|
|
25
|
+
clauses = []
|
|
26
|
+
if start_date and end_date:
|
|
27
|
+
clauses.append(f"calendar_date >= '{start_date}' AND calendar_date <= '{end_date}'")
|
|
28
|
+
if unit_id:
|
|
29
|
+
clauses.append(f"unit_id = '{unit_id}'")
|
|
30
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _query_period_metrics(p, start_date, end_date, unit_id):
|
|
34
|
+
where_clause = _build_ops_where(start_date, end_date, unit_id)
|
|
35
|
+
sql = f"""
|
|
36
|
+
SELECT
|
|
37
|
+
sum(runtime_min) AS sum_runtime_min,
|
|
38
|
+
sum(calendar_minutes - planned_downtime_min) AS sum_available_min,
|
|
39
|
+
sum(actual_output_qty) AS sum_actual_output,
|
|
40
|
+
sum(qualified_output_qty) AS sum_qualified_output,
|
|
41
|
+
sumIf(runtime_min * ideal_cycle_rate, runtime_min > 0) AS sum_theoretical_output
|
|
42
|
+
FROM fact_equipment_daily_ops
|
|
43
|
+
{where_clause}
|
|
44
|
+
"""
|
|
45
|
+
rows = p.sql.query(sql)
|
|
46
|
+
row = rows[0] if rows else {}
|
|
47
|
+
sum_runtime = float(row.get("sum_runtime_min") or 0)
|
|
48
|
+
sum_available = float(row.get("sum_available_min") or 0)
|
|
49
|
+
sum_actual = float(row.get("sum_actual_output") or 0)
|
|
50
|
+
sum_qualified = float(row.get("sum_qualified_output") or 0)
|
|
51
|
+
sum_theoretical = float(row.get("sum_theoretical_output") or 0)
|
|
52
|
+
availability = sum_runtime / sum_available if sum_available > 0 else 0.0
|
|
53
|
+
quality = sum_qualified / sum_actual if sum_actual > 0 else 0.0
|
|
54
|
+
performance = sum_actual / sum_theoretical if sum_theoretical > 0 else 0.0
|
|
55
|
+
oee = availability * performance * quality
|
|
56
|
+
return {
|
|
57
|
+
"oee": round(oee, 4),
|
|
58
|
+
"availability": round(availability, 4),
|
|
59
|
+
"output": round(sum_actual, 2),
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _calc_mom(current, previous):
|
|
64
|
+
if previous == 0:
|
|
65
|
+
return 0.0 if current == 0 else None
|
|
66
|
+
return round((current - previous) / previous, 4)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _ontology_fn_body(p):
|
|
70
|
+
params = dict(p.get_params() or {})
|
|
71
|
+
start_date = params.get("start_date") or "2025-01-01"
|
|
72
|
+
end_date = params.get("end_date") or "2026-06-30"
|
|
73
|
+
metric = params.get("metric", "oee")
|
|
74
|
+
unit_id = params.get("unit_id") or None
|
|
75
|
+
|
|
76
|
+
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
|
77
|
+
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
|
78
|
+
period_days = (end_dt - start_dt).days + 1
|
|
79
|
+
prev_end_dt = start_dt - timedelta(days=1)
|
|
80
|
+
prev_start_dt = prev_end_dt - timedelta(days=period_days - 1)
|
|
81
|
+
prev_start = prev_start_dt.strftime("%Y-%m-%d")
|
|
82
|
+
prev_end = prev_end_dt.strftime("%Y-%m-%d")
|
|
83
|
+
|
|
84
|
+
current_metrics = _query_period_metrics(p, start_date, end_date, unit_id)
|
|
85
|
+
previous_metrics = _query_period_metrics(p, prev_start, prev_end, unit_id)
|
|
86
|
+
|
|
87
|
+
current_value = current_metrics.get(metric, 0)
|
|
88
|
+
previous_value = previous_metrics.get(metric, 0)
|
|
89
|
+
mom = _calc_mom(current_value, previous_value)
|
|
90
|
+
|
|
91
|
+
result = {
|
|
92
|
+
"metric": metric,
|
|
93
|
+
"period": f"{start_date} ~ {end_date}",
|
|
94
|
+
"previous_period": f"{prev_start} ~ {prev_end}",
|
|
95
|
+
"current": current_value,
|
|
96
|
+
"previous": previous_value,
|
|
97
|
+
"mom": mom,
|
|
98
|
+
}
|
|
99
|
+
return p.function_result(
|
|
100
|
+
columns=["metric", "period", "previous_period", "current", "previous", "mom"],
|
|
101
|
+
data=[result],
|
|
102
|
+
row_count=1,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def main():
|
|
107
|
+
s = space.get(ctx.space_id or "")
|
|
108
|
+
_Ports = type(
|
|
109
|
+
"_Ports",
|
|
110
|
+
(),
|
|
111
|
+
{
|
|
112
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
113
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
p = _Ports()
|
|
117
|
+
p.sql = s.sql
|
|
118
|
+
return _ontology_fn_body(p)
|