@dazitech/cli 3.1.0 → 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 (65) 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 +318 -40
  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 +1 -1
  9. package/dist/docs/index.json +1 -13
  10. package/dist/docs/onto/dazi_script_sdk_reference.md +1 -1
  11. package/dist/docs/onto/dazi_script_seed_data_guide.md +1 -1
  12. package/dist/docs/onto/function-guide.md +6 -6
  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 -169
  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 +3 -2
  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 -242
  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 +12 -12
  17. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +14 -13
  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 +70 -15
  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 +4 -4
  27. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_category_mount.py +1 -1
  28. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +1 -1
  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 +2 -2
  60. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_category_mount.py +1 -1
  61. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +1 -1
  62. package/dist/prompts/index.json +1 -1
  63. package/dist/prompts/onto/planning-design.md +226 -104
  64. package/dist/prompts/onto/script-publish-run.md +8 -6
  65. package/package.json +1 -1
@@ -0,0 +1,53 @@
1
+ {
2
+ "version": "1.0",
3
+ "updatedAt": "2026-06-06",
4
+ "defaultReadOrder": [],
5
+ "examples": [
6
+ {
7
+ "id": "sales",
8
+ "dir": "销售示例",
9
+ "title": "产品销售分析",
10
+ "domain": [
11
+ "销售",
12
+ "订单",
13
+ "产品",
14
+ "渠道",
15
+ "SKU",
16
+ "客户"
17
+ ],
18
+ "planPrimary": "plans/规划示例_产品销售本体规划方案.md",
19
+ "featured": true
20
+ },
21
+ {
22
+ "id": "profit",
23
+ "dir": "利润示例",
24
+ "title": "利润 / GL 分析",
25
+ "domain": [
26
+ "利润",
27
+ "科目",
28
+ "预算",
29
+ "GL",
30
+ "成本中心",
31
+ "预实"
32
+ ],
33
+ "planPrimary": "plans/规划示例_利润分析本体方案.md",
34
+ "featured": true
35
+ },
36
+ {
37
+ "id": "equip-ops",
38
+ "dir": "设备运营",
39
+ "title": "化工设备运营分析",
40
+ "domain": [
41
+ "设备",
42
+ "OEE",
43
+ "停机",
44
+ "维保",
45
+ "能耗",
46
+ "工厂",
47
+ "运营"
48
+ ],
49
+ "planPrimary": "plans/化工设备运营分析本体方案.md",
50
+ "featured": true
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,29 @@
1
+ version: "1.0"
2
+ updatedAt: "2026-06-07"
3
+
4
+ # 规划 / 脚本阶段须至少阅读 defaultReadOrder 中一个完整示例(README + plans 主文档)
5
+ defaultReadOrder:
6
+ - 销售示例
7
+ - 设备运营
8
+
9
+ examples:
10
+ - id: sales
11
+ dir: 销售示例
12
+ title: 产品销售分析
13
+ domain: [销售, 订单, 产品, 渠道, SKU, 客户]
14
+ planPrimary: plans/规划示例_产品销售本体规划方案.md
15
+ featured: true
16
+
17
+ - id: profit
18
+ dir: 利润示例
19
+ title: 利润 / GL 分析
20
+ domain: [利润, 科目, 预算, GL, 成本中心, 预实]
21
+ planPrimary: plans/规划示例_利润分析本体方案.md
22
+ featured: true
23
+
24
+ - id: equip-ops
25
+ dir: 设备运营
26
+ title: 化工设备运营分析
27
+ domain: [设备, OEE, 停机, 维保, 能耗, 工厂, 运营]
28
+ planPrimary: plans/化工设备运营分析本体方案.md
29
+ featured: true
@@ -0,0 +1,23 @@
1
+ # 利润示例 · GL / 利润分析
2
+
3
+ ## 基本信息
4
+
5
+ | 字段 | 内容 |
6
+ | --- | --- |
7
+ | 数据空间 | 以示例脚本内 `space_id` 为准(复制后改 README) |
8
+ | 示例 ID | `profit`(见 `../index.yaml` / `index.json`) |
9
+
10
+ ## 目录
11
+
12
+ | 路径 | 说明 |
13
+ | --- | --- |
14
+ | [plans/规划示例_利润分析本体方案.md](./plans/规划示例_利润分析本体方案.md) | **规划正文** |
15
+ | `setup/` | `profit_ontology_init.py`、`profit_seed_data.py`、`profit_category_mount.py` |
16
+ | `functions/` | 7 个 `profit_fn_*.py`、`test_arguments/` |
17
+
18
+ ## 使用
19
+
20
+ - **规划阶段**:通读 `plans/*.md`;与 [销售示例](../销售示例/) 对照时写清差异说明
21
+ - **实施阶段**:init **不含** `apply_registry`;分类在 `profit_category_mount.py`(最后执行)
22
+
23
+ 规范指南:`资源/docs/onto/本体规划指南.md`
@@ -3,7 +3,6 @@
3
3
  # 用法:在 dazi-work 根目录执行 .\项目\DAZI_TEST\本体\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="profit.fn.get_summary"; file="profit.fn.get_summary.json"},
@@ -16,23 +15,25 @@ $functions = @(
16
15
  )
17
16
 
18
17
  Write-Host "获取函数列表..."
19
- $fnList = & dazi onto function list --space $spaceId 2>$null
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
20
21
 
21
22
  foreach ($fn in $functions) {
22
23
  $fnId = $fn.fn_id
23
24
  $fileName = $fn.file
24
25
  $jsonPath = "$PSScriptRoot/test_arguments/$fileName"
25
26
 
26
- $ofnId = $fnList | Where-Object { $_ -match $fnId } | ForEach-Object {
27
- if ($_ -match 'id:\s*(\S+)') { $matches[1] }
27
+ if (-not (Test-Path $jsonPath)) {
28
+ Write-Host "跳过 $fnId:找不到 $jsonPath"
29
+ continue
28
30
  }
29
-
30
- if ($ofnId) {
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 未找到,请先发布函数"
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
 
38
- Write-Host "完成"
39
+ Write-Host "完成"
@@ -5,7 +5,7 @@
5
5
  > **只读参照**:本文档供学习 GL 域规划**结构**与验收口径,**不得**整篇复制为本项目 `plans/` 充数。新建实现须在 `plans/` **独立撰写**,并含「与参照示例的差异说明」章节(见 [本体规划指南 · 任务模式](./本体规划指南.md#任务模式与反模式))。
6
6
 
7
7
  > 表/Cube/对象命名遵循 [本体命名规范](./本体命名规范_物理表Cube与对象.md)。
8
- > 工程模式参考:[规划示例_产品销售本体规划方案.md](./规划示例_产品销售本体规划方案.md)
8
+ > 工程模式参考:[销售示例 plans](../../销售示例/plans/规划示例_产品销售本体规划方案.md)
9
9
 
10
10
  **占位符**(复制到工作区 `plans/` 后替换为实际值):
11
11
 
@@ -76,7 +76,7 @@
76
76
 
77
77
  ### 3.0 时间维:dim_date(强制)
78
78
 
79
- 与销售域共用;字段定义见 [销售规划示例 §3.0](./规划示例_产品销售本体规划方案.md#30-时间维dim_date强制)。分录 **`date_key = toYYYYMMDD(posting_date)`**;预算行可用 **`toYYYYMMDD(toDate(concat(toString(fiscal_year), '-', lpad(toString(fiscal_period), 2, '0'), '-01')))`** 或 period 末代表日,规划须写清口径。
79
+ 与销售域共用;字段定义见 [销售示例 §3.0](../../销售示例/plans/规划示例_产品销售本体规划方案.md#30-时间维dim_date强制)。分录 **`date_key = toYYYYMMDD(posting_date)`**;预算行可用 **`toYYYYMMDD(toDate(concat(toString(fiscal_year), '-', lpad(toString(fiscal_period), 2, '0'), '-01')))`** 或 period 末代表日,规划须写清口径。
80
80
 
81
81
  ### 3.1 维度表:dim_account
82
82
 
@@ -534,7 +534,7 @@ s.tables.add_relationship(
534
534
  | 来源 | 用途 | 注意 |
535
535
  | ---- | ---- | ---- |
536
536
  | `资源/examples/onto/利润示例/` | 对照 API 写法或复制后按 **本实现 plans** 改造 | **禁止**无 plans 直接复制 init |
537
- | [规划示例:产品销售](./规划示例_产品销售本体规划方案.md) | 跨域工程模式只读对照 | 表结构与函数逻辑不同 |
537
+ | [销售示例](../../销售示例/plans/规划示例_产品销售本体规划方案.md) | 跨域工程模式只读对照 | 表结构与函数逻辑不同 |
538
538
 
539
539
  **seed 数据建议**:
540
540
 
@@ -670,7 +670,7 @@ s.tables.add_relationship(
670
670
  | ---- | ---- |
671
671
  | 本体命名规范 | [本体命名规范_物理表Cube与对象.md](./本体命名规范_物理表Cube与对象.md) |
672
672
  | 本体规划指南 | [本体规划指南.md](./本体规划指南.md) |
673
- | 规划示例(产品销售) | [规划示例_产品销售本体规划方案.md](./规划示例_产品销售本体规划方案.md) |
673
+ | 销售示例 | [规划示例_产品销售本体规划方案.md](../../销售示例/plans/规划示例_产品销售本体规划方案.md) |
674
674
  | **内置脚本示例** | `资源/examples/onto/利润示例/`(`dazi examples sync`;表名迁移中) |
675
675
  | 分类方案 | [本体分类规划与 SDK 扩展方案](./本体分类规划与SDK扩展方案.md) |
676
676
 
@@ -5,7 +5,7 @@ init → seed → 发布全部函数 → **本脚本**。
5
5
 
6
6
  放置:资源/examples/onto/利润示例/setup/profit_category_mount.py
7
7
  发布:dazi onto script publish <item-path>/setup/profit_category_mount.py --space <space-id> --type setup
8
- 规划对照:资源/docs/onto/规划示例_利润分析本体方案.md 附录 B
8
+ 规划对照:资源/examples/onto/利润示例/plans/规划示例_利润分析本体方案.md 附录 B
9
9
  """
10
10
 
11
11
  import json
@@ -11,7 +11,7 @@
11
11
 
12
12
  放置:资源/examples/onto/利润示例/setup/profit_ontology_init.py(复制到项目 ontos/<实现名>/setup/)
13
13
  发布:dazi onto script publish <item-path>/setup/profit_ontology_init.py --space <space-id> --type setup
14
- 规划对照:资源/docs/onto/规划示例_利润分析本体方案.md
14
+ 规划对照:资源/examples/onto/利润示例/plans/规划示例_利润分析本体方案.md
15
15
  """
16
16
 
17
17
  import json
@@ -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)