@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,126 @@
|
|
|
1
|
+
"""OEE 分解分析 equip_ops.fn.oee_analysis
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, equipment_id(可选), group_by=plant|unit|equipment|equip_type
|
|
4
|
+
返回:group_id, group_name, availability, performance, quality, oee, runtime_hours, output_qty
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_oee_analysis.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.oee_analysis
|
|
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
|
+
"equip_type": ("equip_type_id", "any(category)"),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _build_ops_where(start_date, end_date, plant_id=None, equipment_id=None):
|
|
30
|
+
clauses = []
|
|
31
|
+
if start_date and end_date:
|
|
32
|
+
clauses.append(f"calendar_date >= '{start_date}' AND calendar_date <= '{end_date}'")
|
|
33
|
+
if plant_id:
|
|
34
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
35
|
+
if equipment_id:
|
|
36
|
+
clauses.append(f"equipment_id = '{equipment_id}'")
|
|
37
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _calc_oee_metrics(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 {
|
|
51
|
+
"availability": round(availability, 4),
|
|
52
|
+
"performance": round(performance, 4),
|
|
53
|
+
"quality": round(quality, 4),
|
|
54
|
+
"oee": round(oee, 4),
|
|
55
|
+
"runtime_hours": round(sum_runtime / 60.0, 2),
|
|
56
|
+
"output_qty": round(sum_actual, 2),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _ontology_fn_body(p):
|
|
61
|
+
params = dict(p.get_params() or {})
|
|
62
|
+
start_date = params.get("start_date", "")
|
|
63
|
+
end_date = params.get("end_date", "")
|
|
64
|
+
equipment_id = params.get("equipment_id") or None
|
|
65
|
+
group_by = params.get("group_by", "plant")
|
|
66
|
+
group_id_col, group_name_expr = _GROUP_BY_MAP.get(group_by, _GROUP_BY_MAP["plant"])
|
|
67
|
+
where_clause = _build_ops_where(start_date, end_date, equipment_id=equipment_id)
|
|
68
|
+
|
|
69
|
+
sql = f"""
|
|
70
|
+
SELECT
|
|
71
|
+
{group_id_col} AS group_id,
|
|
72
|
+
{group_name_expr} AS group_name,
|
|
73
|
+
sum(runtime_min) AS sum_runtime_min,
|
|
74
|
+
sum(calendar_minutes - planned_downtime_min) AS sum_available_min,
|
|
75
|
+
sum(actual_output_qty) AS sum_actual_output,
|
|
76
|
+
sum(qualified_output_qty) AS sum_qualified_output,
|
|
77
|
+
sumIf(runtime_min * ideal_cycle_rate, runtime_min > 0) AS sum_theoretical_output
|
|
78
|
+
FROM fact_equipment_daily_ops
|
|
79
|
+
{where_clause}
|
|
80
|
+
GROUP BY {group_id_col}
|
|
81
|
+
ORDER BY group_id
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
result = p.sql.query(sql)
|
|
85
|
+
if not result:
|
|
86
|
+
return p.function_result(
|
|
87
|
+
columns=[
|
|
88
|
+
"group_id", "group_name", "availability", "performance",
|
|
89
|
+
"quality", "oee", "runtime_hours", "output_qty",
|
|
90
|
+
],
|
|
91
|
+
data=[],
|
|
92
|
+
row_count=0,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
data = []
|
|
96
|
+
for row in result:
|
|
97
|
+
metrics = _calc_oee_metrics(row)
|
|
98
|
+
data.append({
|
|
99
|
+
"group_id": str(row.get("group_id") or ""),
|
|
100
|
+
"group_name": str(row.get("group_name") or ""),
|
|
101
|
+
**metrics,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return p.function_result(
|
|
105
|
+
columns=[
|
|
106
|
+
"group_id", "group_name", "availability", "performance",
|
|
107
|
+
"quality", "oee", "runtime_hours", "output_qty",
|
|
108
|
+
],
|
|
109
|
+
data=data,
|
|
110
|
+
row_count=len(data),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def main():
|
|
115
|
+
s = space.get(ctx.space_id or "")
|
|
116
|
+
_Ports = type(
|
|
117
|
+
"_Ports",
|
|
118
|
+
(),
|
|
119
|
+
{
|
|
120
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
121
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
p = _Ports()
|
|
125
|
+
p.sql = s.sql
|
|
126
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""运行计划对比 equip_ops.fn.plan_vs_actual
|
|
2
|
+
|
|
3
|
+
参数:fiscal_year, fiscal_month, plan_version, plant_id(可选)
|
|
4
|
+
JOIN fact_equipment_plan 与 fact_equipment_daily_ops
|
|
5
|
+
返回:planned vs actual runtime/output/energy, execution_rate
|
|
6
|
+
|
|
7
|
+
发布:
|
|
8
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_plan_vs_actual.py \
|
|
9
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.plan_vs_actual
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
TEST_ARGUMENTS = {
|
|
13
|
+
"v": 1,
|
|
14
|
+
"arguments": {
|
|
15
|
+
"fiscal_year": 2026,
|
|
16
|
+
"fiscal_month": 6,
|
|
17
|
+
"plan_version": "2026月度计划",
|
|
18
|
+
},
|
|
19
|
+
"object_type_code": "PlanAnalysis",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _ontology_fn_body(p):
|
|
24
|
+
params = dict(p.get_params() or {})
|
|
25
|
+
fiscal_year = int(params.get("fiscal_year", 2026))
|
|
26
|
+
fiscal_month = int(params.get("fiscal_month", 1))
|
|
27
|
+
plan_version = params.get("plan_version", "2026月度计划")
|
|
28
|
+
plant_id = params.get("plant_id") or None
|
|
29
|
+
|
|
30
|
+
plant_cond = "" if not plant_id else f"AND p.plant_id = '{plant_id}'"
|
|
31
|
+
|
|
32
|
+
sql = f"""
|
|
33
|
+
SELECT
|
|
34
|
+
sum(p.planned_runtime_min) AS planned_runtime_min,
|
|
35
|
+
sum(p.planned_output_qty) AS planned_output_qty,
|
|
36
|
+
sum(p.planned_energy) AS planned_energy,
|
|
37
|
+
sum(o.runtime_min) AS actual_runtime_min,
|
|
38
|
+
sum(o.actual_output_qty) AS actual_output_qty,
|
|
39
|
+
sum(o.energy_consumption) AS actual_energy
|
|
40
|
+
FROM fact_equipment_plan AS p
|
|
41
|
+
LEFT JOIN fact_equipment_daily_ops AS o
|
|
42
|
+
ON p.equipment_id = o.equipment_id AND p.date_key = o.date_key
|
|
43
|
+
WHERE p.fiscal_year = {fiscal_year}
|
|
44
|
+
AND p.fiscal_month = {fiscal_month}
|
|
45
|
+
AND p.plan_version = '{plan_version}'
|
|
46
|
+
{plant_cond}
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
rows = p.sql.query(sql)
|
|
50
|
+
row = rows[0] if rows else {}
|
|
51
|
+
|
|
52
|
+
planned_runtime = float(row.get("planned_runtime_min") or 0)
|
|
53
|
+
planned_output = float(row.get("planned_output_qty") or 0)
|
|
54
|
+
planned_energy = float(row.get("planned_energy") or 0)
|
|
55
|
+
actual_runtime = float(row.get("actual_runtime_min") or 0)
|
|
56
|
+
actual_output = float(row.get("actual_output_qty") or 0)
|
|
57
|
+
actual_energy = float(row.get("actual_energy") or 0)
|
|
58
|
+
|
|
59
|
+
runtime_rate = actual_runtime / planned_runtime if planned_runtime > 0 else 0.0
|
|
60
|
+
output_rate = actual_output / planned_output if planned_output > 0 else 0.0
|
|
61
|
+
energy_rate = actual_energy / planned_energy if planned_energy > 0 else 0.0
|
|
62
|
+
execution_rate = (runtime_rate + output_rate + energy_rate) / 3.0
|
|
63
|
+
|
|
64
|
+
data = [{
|
|
65
|
+
"fiscal_year": fiscal_year,
|
|
66
|
+
"fiscal_month": fiscal_month,
|
|
67
|
+
"plan_version": plan_version,
|
|
68
|
+
"planned_runtime_hours": round(planned_runtime / 60.0, 2),
|
|
69
|
+
"actual_runtime_hours": round(actual_runtime / 60.0, 2),
|
|
70
|
+
"runtime_execution_rate": round(runtime_rate, 4),
|
|
71
|
+
"planned_output_qty": round(planned_output, 2),
|
|
72
|
+
"actual_output_qty": round(actual_output, 2),
|
|
73
|
+
"output_execution_rate": round(output_rate, 4),
|
|
74
|
+
"planned_energy": round(planned_energy, 2),
|
|
75
|
+
"actual_energy": round(actual_energy, 2),
|
|
76
|
+
"energy_execution_rate": round(energy_rate, 4),
|
|
77
|
+
"execution_rate": round(execution_rate, 4),
|
|
78
|
+
}]
|
|
79
|
+
|
|
80
|
+
return p.function_result(
|
|
81
|
+
columns=[
|
|
82
|
+
"fiscal_year", "fiscal_month", "plan_version",
|
|
83
|
+
"planned_runtime_hours", "actual_runtime_hours", "runtime_execution_rate",
|
|
84
|
+
"planned_output_qty", "actual_output_qty", "output_execution_rate",
|
|
85
|
+
"planned_energy", "actual_energy", "energy_execution_rate",
|
|
86
|
+
"execution_rate",
|
|
87
|
+
],
|
|
88
|
+
data=data,
|
|
89
|
+
row_count=1,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def main():
|
|
94
|
+
s = space.get(ctx.space_id or "")
|
|
95
|
+
_Ports = type(
|
|
96
|
+
"_Ports",
|
|
97
|
+
(),
|
|
98
|
+
{
|
|
99
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
100
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
p = _Ports()
|
|
104
|
+
p.sql = s.sql
|
|
105
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""故障 TOP 设备 equip_ops.fn.top_fault_equipment
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, limit=10, plant_id(可选)
|
|
4
|
+
按非计划停机时长 TOP 设备
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_top_fault_equipment.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.top_fault_equipment
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
TEST_ARGUMENTS = {
|
|
12
|
+
"v": 1,
|
|
13
|
+
"arguments": {
|
|
14
|
+
"start_date": "2025-01-01",
|
|
15
|
+
"end_date": "2026-06-30",
|
|
16
|
+
"limit": 10,
|
|
17
|
+
},
|
|
18
|
+
"object_type_code": "EquipmentAnalysis",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _build_where(start_date, end_date, plant_id=None):
|
|
23
|
+
clauses = ["e.is_planned = 0"]
|
|
24
|
+
if start_date and end_date:
|
|
25
|
+
clauses.append(
|
|
26
|
+
f"e.start_time >= '{start_date} 00:00:00' AND e.start_time <= '{end_date} 23:59:59'"
|
|
27
|
+
)
|
|
28
|
+
if plant_id:
|
|
29
|
+
clauses.append(f"e.plant_id = '{plant_id}'")
|
|
30
|
+
return "WHERE " + " AND ".join(clauses)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _ontology_fn_body(p):
|
|
34
|
+
params = dict(p.get_params() or {})
|
|
35
|
+
start_date = params.get("start_date", "")
|
|
36
|
+
end_date = params.get("end_date", "")
|
|
37
|
+
limit = int(params.get("limit", 10) or 10)
|
|
38
|
+
plant_id = params.get("plant_id") or None
|
|
39
|
+
where_clause = _build_where(start_date, end_date, plant_id)
|
|
40
|
+
|
|
41
|
+
sql = f"""
|
|
42
|
+
SELECT
|
|
43
|
+
e.equipment_id,
|
|
44
|
+
any(e.equipment_code) AS equipment_code,
|
|
45
|
+
any(e.equipment_name) AS equipment_name,
|
|
46
|
+
any(eq.plant_name) AS plant_name,
|
|
47
|
+
any(eq.unit_name) AS unit_name,
|
|
48
|
+
sum(e.duration_min) AS downtime_min,
|
|
49
|
+
count() AS event_count
|
|
50
|
+
FROM fact_downtime_event AS e
|
|
51
|
+
LEFT JOIN dim_equipment AS eq ON e.equipment_id = eq.equipment_id
|
|
52
|
+
{where_clause}
|
|
53
|
+
GROUP BY e.equipment_id
|
|
54
|
+
ORDER BY downtime_min DESC
|
|
55
|
+
LIMIT {limit}
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
result = p.sql.query(sql)
|
|
59
|
+
if not result:
|
|
60
|
+
return p.function_result(
|
|
61
|
+
columns=[
|
|
62
|
+
"rank", "equipment_id", "equipment_code", "equipment_name",
|
|
63
|
+
"plant_name", "unit_name", "downtime_hours", "event_count",
|
|
64
|
+
],
|
|
65
|
+
data=[],
|
|
66
|
+
row_count=0,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
data = []
|
|
70
|
+
for rank, row in enumerate(result, start=1):
|
|
71
|
+
data.append({
|
|
72
|
+
"rank": rank,
|
|
73
|
+
"equipment_id": str(row.get("equipment_id") or ""),
|
|
74
|
+
"equipment_code": str(row.get("equipment_code") or ""),
|
|
75
|
+
"equipment_name": str(row.get("equipment_name") or ""),
|
|
76
|
+
"plant_name": str(row.get("plant_name") or ""),
|
|
77
|
+
"unit_name": str(row.get("unit_name") or ""),
|
|
78
|
+
"downtime_hours": round(float(row.get("downtime_min") or 0) / 60.0, 2),
|
|
79
|
+
"event_count": int(row.get("event_count") or 0),
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return p.function_result(
|
|
83
|
+
columns=[
|
|
84
|
+
"rank", "equipment_id", "equipment_code", "equipment_name",
|
|
85
|
+
"plant_name", "unit_name", "downtime_hours", "event_count",
|
|
86
|
+
],
|
|
87
|
+
data=data,
|
|
88
|
+
row_count=len(data),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def main():
|
|
93
|
+
s = space.get(ctx.space_id or "")
|
|
94
|
+
_Ports = type(
|
|
95
|
+
"_Ports",
|
|
96
|
+
(),
|
|
97
|
+
{
|
|
98
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
99
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
p = _Ports()
|
|
103
|
+
p.sql = s.sql
|
|
104
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""工艺单元对标 equip_ops.fn.unit_comparison
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, metric=oee|availability|output, plant_id(可选)
|
|
4
|
+
按工艺单元对标排名
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_unit_comparison.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.unit_comparison
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
TEST_ARGUMENTS = {
|
|
12
|
+
"v": 1,
|
|
13
|
+
"arguments": {
|
|
14
|
+
"start_date": "2025-01-01",
|
|
15
|
+
"end_date": "2026-06-30",
|
|
16
|
+
"metric": "oee",
|
|
17
|
+
},
|
|
18
|
+
"object_type_code": "EquipmentAnalysis",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _build_ops_where(start_date, end_date, plant_id=None):
|
|
23
|
+
clauses = []
|
|
24
|
+
if start_date and end_date:
|
|
25
|
+
clauses.append(f"calendar_date >= '{start_date}' AND calendar_date <= '{end_date}'")
|
|
26
|
+
if plant_id:
|
|
27
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
28
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _calc_metric(row, metric):
|
|
32
|
+
sum_runtime = float(row.get("sum_runtime_min") or 0)
|
|
33
|
+
sum_available = float(row.get("sum_available_min") or 0)
|
|
34
|
+
sum_actual = float(row.get("sum_actual_output") or 0)
|
|
35
|
+
sum_qualified = float(row.get("sum_qualified_output") or 0)
|
|
36
|
+
sum_theoretical = float(row.get("sum_theoretical_output") or 0)
|
|
37
|
+
availability = sum_runtime / sum_available if sum_available > 0 else 0.0
|
|
38
|
+
quality = sum_qualified / sum_actual if sum_actual > 0 else 0.0
|
|
39
|
+
performance = sum_actual / sum_theoretical if sum_theoretical > 0 else 0.0
|
|
40
|
+
oee = availability * performance * quality
|
|
41
|
+
if metric == "availability":
|
|
42
|
+
return round(availability, 4)
|
|
43
|
+
if metric == "output":
|
|
44
|
+
return round(sum_actual, 2)
|
|
45
|
+
return round(oee, 4)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _ontology_fn_body(p):
|
|
49
|
+
params = dict(p.get_params() or {})
|
|
50
|
+
start_date = params.get("start_date", "")
|
|
51
|
+
end_date = params.get("end_date", "")
|
|
52
|
+
metric = params.get("metric", "oee")
|
|
53
|
+
plant_id = params.get("plant_id") or None
|
|
54
|
+
where_clause = _build_ops_where(start_date, end_date, plant_id)
|
|
55
|
+
|
|
56
|
+
sql = f"""
|
|
57
|
+
SELECT
|
|
58
|
+
unit_id,
|
|
59
|
+
any(unit_name) AS unit_name,
|
|
60
|
+
any(plant_name) AS plant_name,
|
|
61
|
+
sum(runtime_min) AS sum_runtime_min,
|
|
62
|
+
sum(calendar_minutes - planned_downtime_min) AS sum_available_min,
|
|
63
|
+
sum(actual_output_qty) AS sum_actual_output,
|
|
64
|
+
sum(qualified_output_qty) AS sum_qualified_output,
|
|
65
|
+
sumIf(runtime_min * ideal_cycle_rate, runtime_min > 0) AS sum_theoretical_output
|
|
66
|
+
FROM fact_equipment_daily_ops
|
|
67
|
+
{where_clause}
|
|
68
|
+
GROUP BY unit_id
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
result = p.sql.query(sql)
|
|
72
|
+
if not result:
|
|
73
|
+
return p.function_result(
|
|
74
|
+
columns=["rank", "unit_id", "unit_name", "plant_name", "metric", "metric_value"],
|
|
75
|
+
data=[],
|
|
76
|
+
row_count=0,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
scored = []
|
|
80
|
+
for row in result:
|
|
81
|
+
scored.append({
|
|
82
|
+
"unit_id": str(row.get("unit_id") or ""),
|
|
83
|
+
"unit_name": str(row.get("unit_name") or ""),
|
|
84
|
+
"plant_name": str(row.get("plant_name") or ""),
|
|
85
|
+
"metric_value": _calc_metric(row, metric),
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
scored.sort(key=lambda x: x["metric_value"], reverse=True)
|
|
89
|
+
|
|
90
|
+
data = []
|
|
91
|
+
for rank, item in enumerate(scored, start=1):
|
|
92
|
+
data.append({
|
|
93
|
+
"rank": rank,
|
|
94
|
+
"unit_id": item["unit_id"],
|
|
95
|
+
"unit_name": item["unit_name"],
|
|
96
|
+
"plant_name": item["plant_name"],
|
|
97
|
+
"metric": metric,
|
|
98
|
+
"metric_value": item["metric_value"],
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return p.function_result(
|
|
102
|
+
columns=["rank", "unit_id", "unit_name", "plant_name", "metric", "metric_value"],
|
|
103
|
+
data=data,
|
|
104
|
+
row_count=len(data),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def main():
|
|
109
|
+
s = space.get(ctx.space_id or "")
|
|
110
|
+
_Ports = type(
|
|
111
|
+
"_Ports",
|
|
112
|
+
(),
|
|
113
|
+
{
|
|
114
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
115
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
p = _Ports()
|
|
119
|
+
p.sql = s.sql
|
|
120
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""同比分析 equip_ops.fn.yoy_analysis
|
|
2
|
+
|
|
3
|
+
参数:start_date, end_date, metric=oee|availability|output, plant_id(可选)
|
|
4
|
+
返回:current / previous / yoy 对比
|
|
5
|
+
|
|
6
|
+
发布:
|
|
7
|
+
dazi onto script publish 项目/DAZI_TEST/本体/ontos/设备运营/functions/equip_ops_fn_yoy_analysis.py \
|
|
8
|
+
--space space_cate_test01 --register-function-id equip_ops.fn.yoy_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": "oee",
|
|
19
|
+
},
|
|
20
|
+
"object_type_code": "EquipmentAnalysis",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _build_ops_where(start_date, end_date, plant_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 plant_id:
|
|
29
|
+
clauses.append(f"plant_id = '{plant_id}'")
|
|
30
|
+
return ("WHERE " + " AND ".join(clauses)) if clauses else ""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _query_period_metrics(p, start_date, end_date, plant_id):
|
|
34
|
+
where_clause = _build_ops_where(start_date, end_date, plant_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_yoy(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
|
+
plant_id = params.get("plant_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
|
+
prev_start = (start_dt - timedelta(days=365)).strftime("%Y-%m-%d")
|
|
79
|
+
prev_end = (end_dt - timedelta(days=365)).strftime("%Y-%m-%d")
|
|
80
|
+
|
|
81
|
+
current_metrics = _query_period_metrics(p, start_date, end_date, plant_id)
|
|
82
|
+
previous_metrics = _query_period_metrics(p, prev_start, prev_end, plant_id)
|
|
83
|
+
|
|
84
|
+
current_value = current_metrics.get(metric, 0)
|
|
85
|
+
previous_value = previous_metrics.get(metric, 0)
|
|
86
|
+
yoy = _calc_yoy(current_value, previous_value)
|
|
87
|
+
|
|
88
|
+
result = {
|
|
89
|
+
"metric": metric,
|
|
90
|
+
"period": f"{start_date} ~ {end_date}",
|
|
91
|
+
"previous_period": f"{prev_start} ~ {prev_end}",
|
|
92
|
+
"current": current_value,
|
|
93
|
+
"previous": previous_value,
|
|
94
|
+
"yoy": yoy,
|
|
95
|
+
}
|
|
96
|
+
return p.function_result(
|
|
97
|
+
columns=["metric", "period", "previous_period", "current", "previous", "yoy"],
|
|
98
|
+
data=[result],
|
|
99
|
+
row_count=1,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def main():
|
|
104
|
+
s = space.get(ctx.space_id or "")
|
|
105
|
+
_Ports = type(
|
|
106
|
+
"_Ports",
|
|
107
|
+
(),
|
|
108
|
+
{
|
|
109
|
+
"get_params": lambda self: dict(ctx.params or {}),
|
|
110
|
+
"function_result": lambda self, **kw: onto.function_result(**kw),
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
p = _Ports()
|
|
114
|
+
p.sql = s.sql
|
|
115
|
+
return _ontology_fn_body(p)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 批量保存各函数的 test_arguments
|
|
2
|
+
# 用法:在 dazi-work 根目录执行 .\项目\DAZI_TEST\本体\ontos\设备运营\functions\save_test_arguments.ps1
|
|
3
|
+
|
|
4
|
+
$spaceId = "space_cate_test01"
|
|
5
|
+
|
|
6
|
+
$functions = @(
|
|
7
|
+
@{ fn_id = "equip_ops.fn.get_summary"; file = "equip_ops.fn.get_summary.json" },
|
|
8
|
+
@{ fn_id = "equip_ops.fn.oee_analysis"; file = "equip_ops.fn.oee_analysis.json" },
|
|
9
|
+
@{ fn_id = "equip_ops.fn.availability_analysis"; file = "equip_ops.fn.availability_analysis.json" },
|
|
10
|
+
@{ fn_id = "equip_ops.fn.downtime_breakdown"; file = "equip_ops.fn.downtime_breakdown.json" },
|
|
11
|
+
@{ fn_id = "equip_ops.fn.yoy_analysis"; file = "equip_ops.fn.yoy_analysis.json" },
|
|
12
|
+
@{ fn_id = "equip_ops.fn.mom_analysis"; file = "equip_ops.fn.mom_analysis.json" },
|
|
13
|
+
@{ fn_id = "equip_ops.fn.top_fault_equipment"; file = "equip_ops.fn.top_fault_equipment.json" },
|
|
14
|
+
@{ fn_id = "equip_ops.fn.maintenance_compliance"; file = "equip_ops.fn.maintenance_compliance.json" },
|
|
15
|
+
@{ fn_id = "equip_ops.fn.energy_intensity"; file = "equip_ops.fn.energy_intensity.json" },
|
|
16
|
+
@{ fn_id = "equip_ops.fn.plan_vs_actual"; file = "equip_ops.fn.plan_vs_actual.json" },
|
|
17
|
+
@{ fn_id = "equip_ops.fn.unit_comparison"; file = "equip_ops.fn.unit_comparison.json" }
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
Write-Host "获取函数列表..."
|
|
21
|
+
$raw = (dazi onto function list --space $spaceId 2>&1) -join "`n"
|
|
22
|
+
$idx = $raw.IndexOf('__JSON_SUMMARY__')
|
|
23
|
+
if ($idx -lt 0) {
|
|
24
|
+
Write-Host "无法解析 function list 输出"
|
|
25
|
+
exit 1
|
|
26
|
+
}
|
|
27
|
+
$fnList = ($raw.Substring($idx + 16) | ConvertFrom-Json).data.functions
|
|
28
|
+
|
|
29
|
+
foreach ($fn in $functions) {
|
|
30
|
+
$fnId = $fn.fn_id
|
|
31
|
+
$jsonPath = Join-Path $PSScriptRoot "test_arguments/$($fn.file)"
|
|
32
|
+
$fnInfo = $fnList | Where-Object { $_.function_id -eq $fnId }
|
|
33
|
+
if ($fnInfo) {
|
|
34
|
+
$ofnId = $fnInfo.id
|
|
35
|
+
Write-Host "保存 $fnId (ofnId=$ofnId)..."
|
|
36
|
+
& dazi onto function save-test-arguments $ofnId --space $spaceId --arguments-json-file $jsonPath
|
|
37
|
+
} else {
|
|
38
|
+
Write-Host "函数 $fnId 未找到,请先 publish"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Write-Host "完成"
|