data-ops-cli 0.5.1__tar.gz → 0.5.2__tar.gz

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 (40) hide show
  1. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/PKG-INFO +1 -1
  2. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/data_ops_cli.egg-info/PKG-INFO +1 -1
  3. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/data_ops_cli.egg-info/SOURCES.txt +0 -2
  4. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/__init__.py +1 -1
  5. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/__init__.py +1 -1
  6. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/factory.py +1 -5
  7. data_ops_cli-0.5.1/src/dataops_cli/cli/alarm.py +0 -721
  8. data_ops_cli-0.5.1/src/dataops_cli/cli/hazard.py +0 -406
  9. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/README.md +0 -0
  10. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/pyproject.toml +0 -0
  11. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/setup.cfg +0 -0
  12. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/data_ops_cli.egg-info/dependency_links.txt +0 -0
  13. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/data_ops_cli.egg-info/entry_points.txt +0 -0
  14. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/data_ops_cli.egg-info/requires.txt +0 -0
  15. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/data_ops_cli.egg-info/top_level.txt +0 -0
  16. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/_compat.py +0 -0
  17. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/api.py +0 -0
  18. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/auth.py +0 -0
  19. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/data_table.py +0 -0
  20. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/dataset.py +0 -0
  21. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/datasource.py +0 -0
  22. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/dict_.py +0 -0
  23. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/kb.py +0 -0
  24. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/metrics.py +0 -0
  25. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/ontology.py +0 -0
  26. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/ref.py +0 -0
  27. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/report.py +0 -0
  28. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/skill.py +0 -0
  29. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/table.py +0 -0
  30. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/tag.py +0 -0
  31. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/utils.py +0 -0
  32. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/widget.py +0 -0
  33. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/cli/workflow.py +0 -0
  34. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/exceptions.py +0 -0
  35. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/runner.py +0 -0
  36. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/schems.py +0 -0
  37. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/sdk.py +0 -0
  38. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/session.py +0 -0
  39. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/src/dataops_cli/utils.py +0 -0
  40. {data_ops_cli-0.5.1 → data_ops_cli-0.5.2}/tests/test_table_relation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-ops-cli
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Command-line wrapper around dataops_sdk for the DataOps platform.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-ops-cli
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Command-line wrapper around dataops_sdk for the DataOps platform.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -15,7 +15,6 @@ src/dataops_cli/sdk.py
15
15
  src/dataops_cli/session.py
16
16
  src/dataops_cli/utils.py
17
17
  src/dataops_cli/cli/__init__.py
18
- src/dataops_cli/cli/alarm.py
19
18
  src/dataops_cli/cli/api.py
20
19
  src/dataops_cli/cli/auth.py
21
20
  src/dataops_cli/cli/data_table.py
@@ -23,7 +22,6 @@ src/dataops_cli/cli/dataset.py
23
22
  src/dataops_cli/cli/datasource.py
24
23
  src/dataops_cli/cli/dict_.py
25
24
  src/dataops_cli/cli/factory.py
26
- src/dataops_cli/cli/hazard.py
27
25
  src/dataops_cli/cli/kb.py
28
26
  src/dataops_cli/cli/metrics.py
29
27
  src/dataops_cli/cli/ontology.py
@@ -14,4 +14,4 @@ groups command modules under :mod:`dataops_cli.cli` and re-exports the package
14
14
  removed in ``dataops_cli`` 1.0.
15
15
  """
16
16
 
17
- __version__ = "0.5.1"
17
+ __version__ = "0.5.2"
@@ -1,6 +1,6 @@
1
1
  """data-ops-cli 的 Typer 命令组集合.
2
2
 
3
- 本包聚合所有 CLI 子命令模块(alarm、api、auth 等),由 ``factory.create_app``
3
+ 本包聚合所有 CLI 子命令模块(api、auth 等),由 ``factory.create_app``
4
4
  统一注册为 Typer 应用并通过 ``dataops_cli.cli.app`` 暴露。
5
5
  """
6
6
 
@@ -39,20 +39,18 @@ def main(
39
39
  def create_app():
40
40
  """组装并返回 data-ops-cli 的顶层 Typer 应用。
41
41
 
42
- 负责集中导入各业务子命令模块(alarm、api、auth 等),将其 Typer 子命令组
42
+ 负责集中导入各业务子命令模块(api、auth 等),将其 Typer 子命令组
43
43
  注册到根应用上,并绑定 ``--version`` 回调。
44
44
 
45
45
  Returns:
46
46
  已注册所有子命令组的 ``typer.Typer`` 应用实例。
47
47
  """
48
- from dataops_cli.cli.alarm import alarm_typer
49
48
  from dataops_cli.cli.api import api_typer
50
49
  from dataops_cli.cli.auth import auth_typer
51
50
  from dataops_cli.cli.data_table import data_table_typer
52
51
  from dataops_cli.cli.dataset import dataset_typer
53
52
  from dataops_cli.cli.datasource import datasource_typer
54
53
  from dataops_cli.cli.dict_ import dict_typer
55
- from dataops_cli.cli.hazard import hazard_typer
56
54
  from dataops_cli.cli.kb import kb_typer
57
55
  from dataops_cli.cli.metrics import metrics_typer
58
56
  from dataops_cli.cli.ontology import ontology_typer
@@ -71,7 +69,6 @@ def create_app():
71
69
  )
72
70
  app.add_typer(auth_typer)
73
71
  app.add_typer(api_typer)
74
- app.add_typer(alarm_typer)
75
72
  app.add_typer(datasource_typer)
76
73
  app.add_typer(dataset_typer)
77
74
  app.add_typer(table_typer)
@@ -84,7 +81,6 @@ def create_app():
84
81
  app.add_typer(data_table_typer)
85
82
  app.add_typer(widget_typer)
86
83
  app.add_typer(dict_typer)
87
- app.add_typer(hazard_typer)
88
84
  app.add_typer(kb_typer)
89
85
  app.add_typer(tag_typer)
90
86
 
@@ -1,721 +0,0 @@
1
- """告警管理模块.
2
-
3
- 提供告警规则的查询与配置能力,覆盖后端 /alarm/rule/* 接口。
4
-
5
- - 服务层函数 (service_*):纯 Python 接口,返回原始数据
6
- - CLI 命令:基于服务层的薄包装,负责格式化输出
7
- """
8
-
9
- import json
10
- from typing import Annotated, Any
11
-
12
- import typer
13
- from dataops_sdk.exceptions import DataOpsError
14
- from dataops_sdk.services.alarm import (
15
- service_count_alarm_action,
16
- service_count_alarm_rule_matches,
17
- service_count_alarm_rules,
18
- service_count_alarm_specs,
19
- service_find_alarm_table_data,
20
- service_find_meta_by_codes,
21
- service_get_alarm_action_detail,
22
- service_get_alarm_builtin_function_detail,
23
- service_get_alarm_preprocess_detail,
24
- service_get_alarm_rule_detail,
25
- service_get_alarm_rule_enums,
26
- service_get_alarm_rule_type_detail,
27
- service_get_alarm_spec_detail,
28
- service_get_alarm_table_columns,
29
- service_get_rel_table_columns,
30
- service_list_alarm_action,
31
- service_list_alarm_builtin_functions,
32
- service_list_alarm_preprocess,
33
- service_list_alarm_rule_matches,
34
- service_list_alarm_rules,
35
- service_list_alarm_specs,
36
- )
37
- from pydantic_core import to_json
38
- from rich.console import Console
39
- from rich.table import Table
40
-
41
- from dataops_cli.cli.utils import print_list
42
-
43
- # ---------------------------------------------------------------------------
44
- # CLI 命令(薄包装,负责输出渲染)
45
- # ---------------------------------------------------------------------------
46
-
47
- alarm_typer = typer.Typer(name="alarm", help="告警规则配置", no_args_is_help=True)
48
- alarm_rule_typer = typer.Typer(name="rule", help="告警规则命令", no_args_is_help=True)
49
- alarm_rule_type_typer = typer.Typer(name="type", help="告警规则类型命令", no_args_is_help=True)
50
- alarm_spec_typer = typer.Typer(name="spec", help="告警专业命令", no_args_is_help=True)
51
- alarm_action_typer = typer.Typer(name="action", help="告警动作命令", no_args_is_help=True)
52
- alarm_preprocess_typer = typer.Typer(name="preprocess", help="预处理脚本命令", no_args_is_help=True)
53
- alarm_builtin_function_typer = typer.Typer(
54
- name="builtin-function", help="内置函数命令", no_args_is_help=True
55
- )
56
- rule_match_typer = typer.Typer(name="match", help="规则匹配命令", no_args_is_help=True)
57
- alarm_typer.add_typer(alarm_rule_typer, no_args_is_help=True)
58
- alarm_typer.add_typer(alarm_spec_typer, no_args_is_help=True)
59
- alarm_rule_typer.add_typer(alarm_rule_type_typer, no_args_is_help=True)
60
- alarm_rule_typer.add_typer(rule_match_typer, no_args_is_help=True)
61
- alarm_typer.add_typer(alarm_action_typer, no_args_is_help=True)
62
- alarm_typer.add_typer(alarm_preprocess_typer, no_args_is_help=True)
63
- alarm_typer.add_typer(alarm_builtin_function_typer, no_args_is_help=True)
64
-
65
-
66
- def _safe_str(value: Any) -> str:
67
- if value is None:
68
- return ""
69
- if isinstance(value, (dict, list)):
70
- return to_json(value).decode("utf-8")
71
- return str(value)
72
-
73
-
74
- def _extract_column_list(data: Any) -> list:
75
- """从响应中提取列数组。
76
-
77
- 后端返回可能是:
78
- - list[...] 直接列表
79
- - dict {"columns": [...], "indexes": [...]} 嵌套结构
80
- - None / 其他 空
81
- """
82
- if isinstance(data, list):
83
- return data
84
- if isinstance(data, dict):
85
- columns = data.get("columns")
86
- if isinstance(columns, list):
87
- return columns
88
- return []
89
-
90
-
91
- def _print_column_list(data: Any) -> None:
92
- """统一渲染列数组(list[dict] → 平面表;其他 → JSON)."""
93
- columns = _extract_column_list(data)
94
- if not columns:
95
- print("(空)")
96
- return
97
- if isinstance(columns[0], dict):
98
- headers = list(columns[0].keys())
99
- rows = [[_safe_str(c.get(h)) for h in headers] for c in columns]
100
- print_list(headers, rows)
101
- else:
102
- print(to_json(columns).decode("utf-8"))
103
-
104
-
105
- def _print_alarm_detail(detail: Any, title: str, simplify: bool = False) -> None:
106
- """渲染告警详情的主体、data 和参数。"""
107
- console = Console(no_color=True)
108
- meta = detail.meta
109
- basic_table = Table("字段", "值", title=title, show_header=False)
110
- for field in ("code", "title", "type", "remark", "createUser", "lastModifyTime"):
111
- value = getattr(meta, field, None)
112
- if value is not None:
113
- basic_table.add_row(field, _safe_str(value))
114
- console.print(basic_table)
115
-
116
- data = meta.data or {}
117
- if hasattr(data, "model_dump"):
118
- data = data.model_dump(mode="json")
119
- if isinstance(data, dict):
120
- data_table = Table("data 字段", "值", title="详情数据", show_header=False)
121
- for key, value in data.items():
122
- if simplify and key.lower() in {"script", "scriptcontent", "script_content"}:
123
- continue
124
- data_table.add_row(str(key), _safe_str(value))
125
- if data_table.row_count:
126
- console.print(data_table)
127
-
128
- if detail.params:
129
- params_table = Table("参数", "值", title="Meta 参数", show_header=False)
130
- for key, value in detail.params.items():
131
- params_table.add_row(str(key), _safe_str(value))
132
- console.print(params_table)
133
-
134
-
135
- def _handle_alarm_detail(detail_service, code: str, title: str, simplify: bool) -> None:
136
- """统一处理详情 service 的错误和终端输出。"""
137
- try:
138
- detail = detail_service(code)
139
- except DataOpsError as e:
140
- typer.echo(f"错误: {e.message}")
141
- raise typer.Exit(code=1) from None
142
- _print_alarm_detail(detail, title, simplify)
143
-
144
-
145
- @alarm_preprocess_typer.command("list", help="查询预处理脚本")
146
- def list_alarm_preprocess(
147
- spec_type: Annotated[
148
- list[str] | None, typer.Option("--spec-type", help="关联专业编码,可重复传入")
149
- ] = None,
150
- enabled: Annotated[
151
- list[str] | None, typer.Option("--enabled", help="启用状态值 1/0,可重复传入")
152
- ] = None,
153
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
154
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
155
- query: Annotated[str | None, typer.Option("-q", "--query", help="脚本名称关键词")] = None,
156
- ) -> None:
157
- """查询预处理脚本列表。"""
158
- try:
159
- rows = service_list_alarm_preprocess(
160
- page_num,
161
- page_size,
162
- query,
163
- spec_type or [],
164
- enabled or [],
165
- )
166
- except DataOpsError as e:
167
- typer.echo(f"错误: {e.message}")
168
- raise typer.Exit(code=1) from None
169
-
170
- if not rows:
171
- print("未查询到预处理脚本")
172
- return
173
- print_list(
174
- ["脚本编码", "脚本名称", "关联专业", "脚本说明", "启用状态", "创建人", "创建时间"],
175
- [
176
- [
177
- row.CODE,
178
- row.TITLE,
179
- row.N_SPEC_TYPE,
180
- row.DESCRIPTION,
181
- row.IS_ENABLED,
182
- row.CREATE_USER,
183
- row.CREATE_TIME,
184
- ]
185
- for row in rows
186
- ],
187
- )
188
-
189
-
190
- @alarm_preprocess_typer.command("detail", no_args_is_help=True)
191
- def get_alarm_preprocess_detail(
192
- code: Annotated[str, typer.Argument(help="预处理脚本编码")],
193
- simplify: Annotated[bool, typer.Option("-s", "--simplify", help="隐藏脚本正文")] = False,
194
- ) -> None:
195
- """按编码查询预处理脚本详情。"""
196
- _handle_alarm_detail(
197
- service_get_alarm_preprocess_detail,
198
- code,
199
- "预处理脚本详情",
200
- simplify,
201
- )
202
-
203
-
204
- @alarm_builtin_function_typer.command("list", help="查询内置函数")
205
- def list_alarm_builtin_functions(
206
- enabled: Annotated[
207
- list[str] | None, typer.Option("--enabled", help="启用状态值 1/0,可重复传入")
208
- ] = None,
209
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
210
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
211
- query: Annotated[str | None, typer.Option("-q", "--query", help="函数名称关键词")] = None,
212
- ) -> None:
213
- """查询内置函数列表。"""
214
- try:
215
- rows = service_list_alarm_builtin_functions(page_num, page_size, query, enabled or [])
216
- except DataOpsError as e:
217
- typer.echo(f"错误: {e.message}")
218
- raise typer.Exit(code=1) from None
219
-
220
- if not rows:
221
- print("未查询到内置函数")
222
- return
223
- print_list(
224
- ["函数编码", "函数名称", "类全路径", "备注", "启用状态", "创建人", "创建时间"],
225
- [
226
- [
227
- row.CODE,
228
- row.TITLE,
229
- row.CLAZZ,
230
- row.REMARK,
231
- row.IS_ENABLED,
232
- row.CREATE_USER,
233
- row.CREATE_TIME,
234
- ]
235
- for row in rows
236
- ],
237
- )
238
-
239
-
240
- @alarm_builtin_function_typer.command("detail", no_args_is_help=True)
241
- def get_alarm_builtin_function_detail(
242
- code: Annotated[str, typer.Argument(help="内置函数编码")],
243
- simplify: Annotated[bool, typer.Option("-s", "--simplify", help="隐藏函数脚本")] = False,
244
- ) -> None:
245
- """按编码查询内置函数详情。"""
246
- _handle_alarm_detail(
247
- service_get_alarm_builtin_function_detail,
248
- code,
249
- "内置函数详情",
250
- simplify,
251
- )
252
-
253
-
254
- @rule_match_typer.command("count", help="查询告警匹配规则数量")
255
- def count_alarm_rules_match(
256
- spec: Annotated[list[str], typer.Option(help="专业值", default_factory=list)],
257
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
258
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
259
- ):
260
- """查询告警匹配规则数量。
261
-
262
- 按专业、关键字与启用状态进行过滤,返回匹配规则的总数。
263
-
264
- Args:
265
- spec: 专业值列表,多个值会同时参与匹配。
266
- query: 可选关键字,用于模糊搜索。
267
- enabled: 可选启用状态过滤;为 ``True`` / ``False`` 时严格匹配。
268
-
269
- Examples:
270
- >>> data-ops-cli alarm rule match count --spec MY_SPEC
271
- """
272
- try:
273
- total = service_count_alarm_rule_matches(query, enabled, spec)
274
- except DataOpsError as e:
275
- typer.echo(f"错误: {e.message}")
276
- raise typer.Exit(code=1) from None
277
- print(total)
278
-
279
-
280
- @rule_match_typer.command("list", help="查询告警匹配规则")
281
- def list_alarm_rules_match(
282
- spec: Annotated[list[str], typer.Option(help="专业值", default_factory=list)],
283
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
284
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
285
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
286
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
287
- ):
288
- """查询告警匹配规则列表。
289
-
290
- 按专业、关键字与启用状态过滤告警匹配规则,并以平面表格形式输出。
291
-
292
- Args:
293
- spec: 专业值列表,多个值同时参与匹配。
294
- page: 页码(从 0 开始)。
295
- size: 每页条数。
296
- query: 可选关键字。
297
- enabled: 可选启用状态过滤。
298
-
299
- Examples:
300
- >>> data-ops-cli alarm rule match list --spec MY_SPEC --page 0 --size 20
301
- """
302
- try:
303
- group_nodes = service_list_alarm_rule_matches(page_num, page_size, query, enabled, spec)
304
- except DataOpsError as e:
305
- typer.echo(f"错误: {e.message}")
306
- raise typer.Exit(code=1) from None
307
-
308
- if not group_nodes:
309
- print("未查询到匹配告警规则")
310
- return
311
- print_list(
312
- [
313
- "告警匹配规则名称",
314
- "规则类型(值)",
315
- "启用状态",
316
- "所属区域",
317
- "专业类型(值)",
318
- "创建人",
319
- "更新时间",
320
- ],
321
- [
322
- [
323
- column.TITLE,
324
- f"{column.N_RULE_TYPE}({column.RULE_TYPE})",
325
- column.N_IS_ENABLED,
326
- column.AREA,
327
- f"{column.N_SPEC_TYPE}({column.SPEC_TYPE})",
328
- column.CREATE_USER,
329
- column.LAST_MODIFY_TIME,
330
- ]
331
- for column in group_nodes
332
- ],
333
- )
334
-
335
-
336
- @alarm_rule_typer.command("list", help="查询告警匹配规则")
337
- def list_alarm_rules(
338
- spec: Annotated[list[str], typer.Option(help="专业值", default_factory=list)],
339
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
340
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
341
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
342
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
343
- ) -> None:
344
- """查询告警匹配规则列表。
345
-
346
- 这是前端 ``pages/alarm/rule`` 对应的 canonical 命令;旧的
347
- ``alarm rule match list`` 仍保留作为兼容入口。
348
- """
349
- list_alarm_rules_match(spec, page_num, page_size, query, enabled)
350
-
351
-
352
- @alarm_rule_typer.command("detail", no_args_is_help=True)
353
- def get_alarm_rule_detail(
354
- code: Annotated[str, typer.Argument(help="告警匹配规则编码")],
355
- simplify: Annotated[bool, typer.Option("-s", "--simplify", help="简化详情输出")] = False,
356
- ) -> None:
357
- """按编码查询告警匹配规则基础详情。"""
358
- _handle_alarm_detail(service_get_alarm_rule_detail, code, "告警匹配规则详情", simplify)
359
-
360
-
361
- @alarm_rule_typer.command("count", help="兼容查询告警规则类型数量")
362
- def count_alarm_rules_compat(
363
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
364
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
365
- ) -> None:
366
- """兼容保留的原规则类型数量命令。
367
-
368
- 规则类型的 canonical 列表命令是 ``alarm rule type list``;匹配规则数量
369
- 仍使用 ``alarm rule match count``。
370
- """
371
- try:
372
- total = service_count_alarm_rules(query, enabled)
373
- except DataOpsError as e:
374
- typer.echo(f"错误: {e.message}")
375
- raise typer.Exit(code=1) from None
376
- print(total)
377
-
378
-
379
- @alarm_spec_typer.command("list", help="查询告警专业")
380
- def list_alarm_specs(
381
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
382
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
383
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
384
- active: Annotated[bool | None, typer.Option(help="启用状态")] = None,
385
- ):
386
- """查询告警专业列表。
387
-
388
- 按关键字与启用状态过滤告警专业(spec),输出标题、值、行业等基础字段。
389
-
390
- Args:
391
- page: 页码(从 0 开始)。
392
- size: 每页条数。
393
- query: 可选关键字。
394
- active: 可选启用状态过滤。
395
-
396
- Examples:
397
- >>> data-ops-cli alarm spec list -q "网元"
398
- """
399
- group_nodes = service_list_alarm_specs(page_num, page_size, query, active)
400
-
401
- print_list(
402
- ["专业名称", "值", "行业", "启用状态", "创建人", "更新时间"],
403
- [
404
- [
405
- column.TITLE,
406
- column.CODE,
407
- column.N_INDUSTRY,
408
- column.N_IS_ENABLED,
409
- column.CREATE_USER,
410
- column.LAST_MODIFY_TIME,
411
- ]
412
- for column in group_nodes
413
- ],
414
- )
415
-
416
-
417
- @alarm_spec_typer.command("detail", no_args_is_help=True)
418
- def get_alarm_spec_detail(
419
- code: Annotated[str, typer.Argument(help="告警专业编码")],
420
- simplify: Annotated[bool, typer.Option("-s", "--simplify", help="简化详情输出")] = False,
421
- ) -> None:
422
- """按编码查询告警专业详情。"""
423
- _handle_alarm_detail(service_get_alarm_spec_detail, code, "告警专业详情", simplify)
424
-
425
-
426
- @alarm_spec_typer.command("count", help="查询告警专业数量")
427
- def count_alarm_specs(
428
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
429
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
430
- ):
431
- """查询告警专业的总数。
432
-
433
- Args:
434
- query: 可选关键字。
435
- enabled: 可选启用状态过滤。
436
-
437
- Examples:
438
- >>> data-ops-cli alarm spec count
439
- """
440
- total = service_count_alarm_specs(query, enabled)
441
- print(total)
442
-
443
-
444
- @alarm_rule_type_typer.command("list", help="查询告警规则类型")
445
- def list_alarm_rule_types(
446
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
447
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
448
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
449
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
450
- ):
451
- """查询告警规则类型列表。
452
-
453
- 按关键字与启用状态过滤告警规则,并以平面表格输出名称、值与启用状态。
454
-
455
- Args:
456
- page: 页码(从 0 开始)。
457
- size: 每页条数。
458
- query: 可选关键字。
459
- enabled: 可选启用状态过滤。
460
-
461
- Examples:
462
- >>> data-ops-cli alarm rule type list -q "电压"
463
- """
464
- group_nodes = service_list_alarm_rules(page_num, page_size, query, enabled)
465
-
466
- print_list(
467
- ["规则名称", "值", "启用状态", "创建人", "更新时间"],
468
- [
469
- [
470
- column.TITLE,
471
- column.CODE,
472
- column.N_IS_ENABLED,
473
- column.CREATE_USER,
474
- column.LAST_MODIFY_TIME,
475
- ]
476
- for column in group_nodes
477
- ],
478
- )
479
-
480
-
481
- @alarm_rule_type_typer.command("detail", no_args_is_help=True)
482
- def get_alarm_rule_type_detail(
483
- code: Annotated[str, typer.Argument(help="告警规则类型编码")],
484
- simplify: Annotated[bool, typer.Option("-s", "--simplify", help="简化详情输出")] = False,
485
- ) -> None:
486
- """按编码查询告警规则类型详情。"""
487
- _handle_alarm_detail(service_get_alarm_rule_type_detail, code, "告警规则类型详情", simplify)
488
-
489
-
490
- @alarm_rule_type_typer.command("count", help="查询告警规则类型数量")
491
- def count_alarm_rule_types(
492
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
493
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
494
- ):
495
- """查询告警规则的总数。
496
-
497
- Args:
498
- query: 可选关键字。
499
- enabled: 可选启用状态过滤。
500
-
501
- Examples:
502
- >>> data-ops-cli alarm rule type count
503
- """
504
- total = service_count_alarm_rules(query, enabled)
505
- print(total)
506
-
507
-
508
- @alarm_action_typer.command("list", help="查询告警动作")
509
- def list_alarm_actions(
510
- rule: Annotated[list[str], typer.Option(help="专业值", default_factory=list)],
511
- page_num: Annotated[int, typer.Option("-n", "--page-num", "--page", help="页码")] = 0,
512
- page_size: Annotated[int, typer.Option("-s", "--page-size", "--size", help="每页大小")] = 20,
513
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
514
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
515
- ):
516
- """查询告警动作列表。
517
-
518
- 按所属规则、关键字与启用状态过滤告警动作,并以平面表格输出。
519
-
520
- Args:
521
- rule: 所属规则编码列表。
522
- page: 页码(从 0 开始)。
523
- size: 每页条数。
524
- query: 可选关键字。
525
- enabled: 可选启用状态过滤。
526
-
527
- Examples:
528
- >>> data-ops-cli alarm action list --rule MY_RULE
529
- """
530
- try:
531
- group_nodes = service_list_alarm_action(page_num, page_size, query, enabled, rule)
532
- except DataOpsError as e:
533
- typer.echo(f"错误: {e.message}")
534
- raise typer.Exit(code=1) from None
535
-
536
- if not group_nodes:
537
- print("未查询到匹配告警动作")
538
- return
539
- print_list(
540
- [
541
- "动作名称",
542
- "值",
543
- "规则类型(值)",
544
- "启用状态",
545
- "创建人",
546
- "更新时间",
547
- ],
548
- [
549
- [
550
- column.TITLE,
551
- column.CODE,
552
- f"{column.N_RULE_TYPE}({column.RULE_TYPE})",
553
- column.N_IS_ENABLED,
554
- column.CREATE_USER,
555
- column.LAST_MODIFY_TIME,
556
- ]
557
- for column in group_nodes
558
- ],
559
- )
560
-
561
-
562
- @alarm_action_typer.command("detail", no_args_is_help=True)
563
- def get_alarm_action_detail(
564
- code: Annotated[str, typer.Argument(help="告警动作编码")],
565
- simplify: Annotated[bool, typer.Option("-s", "--simplify", help="简化详情输出")] = False,
566
- ) -> None:
567
- """按编码查询告警处置动作详情。"""
568
- _handle_alarm_detail(service_get_alarm_action_detail, code, "告警处置动作详情", simplify)
569
-
570
-
571
- @alarm_action_typer.command("count", help="查询告警动作数量")
572
- def count_alarm_actions(
573
- rule: Annotated[list[str], typer.Option(help="专业值", default_factory=list)],
574
- query: Annotated[str | None, typer.Option("-q", "--query", help="搜索关键字")] = None,
575
- enabled: Annotated[bool | None, typer.Option(help="启用状态")] = None,
576
- ):
577
- """查询告警动作的总数。
578
-
579
- Args:
580
- rule: 所属规则编码列表。
581
- query: 可选关键字。
582
- enabled: 可选启用状态过滤。
583
-
584
- Examples:
585
- >>> data-ops-cli alarm action count --rule MY_RULE
586
- """
587
- try:
588
- total = service_count_alarm_action(query, enabled, rule)
589
- except DataOpsError as e:
590
- typer.echo(f"错误: {e.message}")
591
- raise typer.Exit(code=1) from None
592
- print(total)
593
-
594
-
595
- @alarm_rule_typer.command("enums")
596
- def get_alarm_rule_enums() -> None:
597
- """获取告警规则枚举配置。
598
-
599
- 后端返回 ``dict`` 时以两列 ``key/value`` 表渲染;其他结构以 JSON 形式输出。
600
-
601
- Examples:
602
- >>> data-ops-cli alarm rule enums
603
- """
604
- try:
605
- data = service_get_alarm_rule_enums()
606
- except DataOpsError as e:
607
- typer.echo(f"错误: {e.message}")
608
- raise typer.Exit(code=1) from None
609
-
610
- if not data:
611
- print("(空)")
612
- return
613
-
614
- if isinstance(data, dict):
615
- table = Table("key", "value", show_header=False)
616
- for k, v in data.items():
617
- table.add_row(k, _safe_str(v))
618
- console = Console(no_color=True)
619
- console.print(table)
620
- else:
621
- print(to_json(data).decode("utf-8"))
622
-
623
-
624
- @alarm_rule_typer.command("find-meta-by-codes", no_args_is_help=True)
625
- def find_meta_by_codes(
626
- codes: Annotated[list[str], typer.Argument(help="告警规则编码列表")],
627
- ) -> None:
628
- """根据告警规则编码批量查询关联元数据。
629
-
630
- 以 JSON 格式输出查询结果,便于人工检视或管道后续处理。
631
-
632
- Args:
633
- codes: 告警规则编码列表。
634
-
635
- Examples:
636
- >>> data-ops-cli alarm rule find-meta-by-codes code1 code2
637
- """
638
- try:
639
- data = service_find_meta_by_codes(list(codes))
640
- except DataOpsError as e:
641
- typer.echo(f"错误: {e.message}")
642
- raise typer.Exit(code=1) from None
643
-
644
- print(to_json(data).decode("utf-8"))
645
-
646
-
647
- @alarm_rule_typer.command("alarm-columns", no_args_is_help=True)
648
- def get_alarm_table_columns(
649
- spec_type: Annotated[str, typer.Argument(help="告警规格类型")],
650
- ) -> None:
651
- """获取指定 specType 对应的告警表列定义。
652
-
653
- Args:
654
- spec_type: 告警规格类型编码。
655
-
656
- Examples:
657
- >>> data-ops-cli alarm rule alarm-columns MY_SPEC_TYPE
658
- """
659
- try:
660
- columns = service_get_alarm_table_columns(spec_type)
661
- except DataOpsError as e:
662
- typer.echo(f"错误: {e.message}")
663
- raise typer.Exit(code=1) from None
664
-
665
- _print_column_list(columns)
666
-
667
-
668
- @alarm_rule_typer.command("rel-columns", no_args_is_help=True)
669
- def get_rel_table_columns(
670
- code: Annotated[str, typer.Argument(help="告警规则编码")],
671
- ) -> None:
672
- """获取指定告警规则关联表的列定义。
673
-
674
- Args:
675
- code: 告警规则编码。
676
-
677
- Examples:
678
- >>> data-ops-cli alarm rule rel-columns rule_code_001
679
- """
680
- try:
681
- columns = service_get_rel_table_columns(code)
682
- except DataOpsError as e:
683
- typer.echo(f"错误: {e.message}")
684
- raise typer.Exit(code=1) from None
685
-
686
- _print_column_list(columns)
687
-
688
-
689
- @alarm_rule_typer.command("data", no_args_is_help=True)
690
- def find_alarm_table_data(
691
- code: Annotated[str, typer.Option(help="告警规则编码")],
692
- query: Annotated[
693
- str | None,
694
- typer.Option(help="查询条件 JSON 字符串"),
695
- ] = None,
696
- ) -> None:
697
- """查询指定数据源中告警表的实际数据(由告警规则写入的记录,非实时告警)。
698
-
699
- ``--query`` 接收 JSON 字符串并解析为 dict 后透传给 SDK。
700
-
701
- Args:
702
- code: 告警规则编码。
703
- query: 可选 JSON 字符串,表示查询条件。
704
-
705
- Examples:
706
- >>> data-ops-cli alarm rule data --code rule_code_001
707
- >>> data-ops-cli alarm rule data --code rule_code_001 --query '{"date":"2026-07-16"}'
708
- """
709
- try:
710
- query_dict = json.loads(query) if query else None
711
- except json.JSONDecodeError as e:
712
- typer.echo(f"错误: --query 不是合法 JSON: {e}")
713
- raise typer.Exit(code=1) from None
714
-
715
- try:
716
- data = service_find_alarm_table_data(code, query_dict)
717
- except DataOpsError as e:
718
- typer.echo(f"错误: {e.message}")
719
- raise typer.Exit(code=1) from None
720
-
721
- print(to_json(data).decode("utf-8"))
@@ -1,406 +0,0 @@
1
- """隐患管理命令组.
2
-
3
- - 服务层函数 (service_*):纯 Python 接口,返回原始数据
4
- - CLI 命令:基于服务层的薄包装,负责格式化输出
5
-
6
- 后端接口(位于 data-ops-guard 服务):
7
-
8
- - /hazard/task/trigger/{code}
9
- - /hazard/task/logs/{taskCode}
10
- - /hazard/task/log/records/{taskId}
11
- - /hazard/record/list
12
- - /hazard/record/his/list
13
- - /hazard/record/dispatch/callback
14
- - /hazard/record/his/clear
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- import json
20
- from datetime import datetime
21
- from typing import Annotated, Any
22
-
23
- import typer
24
- from dataops_sdk.exceptions import DataOpsError
25
- from dataops_sdk.schemas.query import PageParam, SqlQueryParam
26
- from dataops_sdk.services import (
27
- service_clear_hazard_history_records,
28
- service_dispatch_hazard_callback,
29
- service_get_hazard_task_log_records,
30
- service_get_hazard_task_logs,
31
- service_list_hazard_history_records,
32
- service_list_hazard_records,
33
- service_trigger_hazard_task,
34
- )
35
- from pydantic_core import to_json
36
- from rich.console import Console
37
- from rich.table import Table
38
-
39
- from dataops_cli.cli.utils import print_list
40
-
41
- # ---------------------------------------------------------------------------
42
- # CLI 命令(薄包装,负责输出渲染)
43
- # ---------------------------------------------------------------------------
44
-
45
- hazard_typer = typer.Typer(name="hazard", help="隐患相关命令", no_args_is_help=True)
46
- hazard_task_typer = typer.Typer(name="task", help="隐患任务命令", no_args_is_help=True)
47
- hazard_record_typer = typer.Typer(name="record", help="隐患记录命令", no_args_is_help=True)
48
- hazard_typer.add_typer(hazard_task_typer)
49
- hazard_typer.add_typer(hazard_record_typer)
50
-
51
- console = Console(no_color=True)
52
-
53
-
54
- # ---------------------------------------------------------------------------
55
- # 公共工具
56
- # ---------------------------------------------------------------------------
57
-
58
-
59
- def _parse_query_json(query: str | None) -> SqlQueryParam | None:
60
- """把 ``--query`` JSON 字符串解析为 SqlQueryParam。
61
-
62
- Args:
63
- query: JSON 字符串;为空时直接返回 ``None``。
64
- """
65
- if not query:
66
- return None
67
- try:
68
- data = json.loads(query)
69
- except json.JSONDecodeError as e:
70
- typer.echo(f"错误: --query 不是合法 JSON: {e}")
71
- raise typer.Exit(code=2) from None
72
- if not isinstance(data, dict):
73
- typer.echo("错误: --query 必须是 JSON 对象")
74
- raise typer.Exit(code=2) from None
75
- return SqlQueryParam.model_validate(data)
76
-
77
-
78
- def _make_page_param(page: int, size: int) -> PageParam:
79
- return PageParam(start=page * size, limit=size)
80
-
81
-
82
- def _print_dict_list(items: list[dict], columns: list[str] | None = None) -> None:
83
- """以 Rich 表格打印字典列表.
84
-
85
- Args:
86
- items: 记录列表.
87
- columns: 指定展示的列;为空时使用首条记录的全部 keys.
88
- """
89
- if not items:
90
- console.print("(空)")
91
- return
92
- headers = columns or list(items[0].keys())
93
- table = Table(*headers, show_header=True, header_style="bold")
94
- for item in items:
95
- row: list[Any] = []
96
- for h in headers:
97
- v = item.get(h)
98
- if v is None:
99
- row.append("")
100
- elif isinstance(v, (dict, list)):
101
- row.append(to_json(v).decode("utf-8"))
102
- else:
103
- row.append(str(v))
104
- table.add_row(*row)
105
- console.print(table)
106
-
107
-
108
- # ---------------------------------------------------------------------------
109
- # 隐患任务子命令
110
- # ---------------------------------------------------------------------------
111
-
112
-
113
- @hazard_task_typer.command("trigger", no_args_is_help=True)
114
- def trigger_hazard_task(
115
- code: Annotated[str, typer.Argument(help="隐患任务编码")],
116
- trigger_time: Annotated[
117
- str | None,
118
- typer.Option(
119
- "--trigger-time",
120
- help="ISO 时间字符串(如 2026-07-23T10:00:00);缺省为立即触发",
121
- ),
122
- ] = None,
123
- sync: Annotated[
124
- bool,
125
- typer.Option("--sync", help="同步执行(默认通过 Job 模板异步执行)"),
126
- ] = False,
127
- ) -> None:
128
- """触发指定编码的隐患任务。
129
-
130
- Args:
131
- code: 隐患任务编码。
132
- trigger_time: 可选 ISO 时间字符串,缺省时立即触发。
133
- sync: 是否同步执行;默认通过 Job 模板异步执行。
134
-
135
- Examples:
136
- >>> data-ops-cli hazard task trigger task_hazard_001
137
- >>> data-ops-cli hazard task trigger task_hazard_001 --sync
138
- >>> data-ops-cli hazard task trigger task_hazard_001 \
139
- ... --trigger-time 2026-07-23T10:00:00
140
- """
141
- parsed_time: datetime | None = None
142
- if trigger_time:
143
- try:
144
- parsed_time = datetime.fromisoformat(trigger_time)
145
- except ValueError as e:
146
- typer.echo(f"错误: --trigger-time 不是合法 ISO 时间: {e}")
147
- raise typer.Exit(code=2) from None
148
-
149
- try:
150
- ok = service_trigger_hazard_task(code, trigger_time=parsed_time, sync=sync)
151
- except DataOpsError as e:
152
- typer.echo(f"错误: {e.message}")
153
- raise typer.Exit(code=1) from None
154
-
155
- if ok:
156
- console.print(f"已触发: {code}")
157
- else:
158
- typer.echo(f"触发失败: {code}")
159
- raise typer.Exit(code=1) from None
160
-
161
-
162
- @hazard_task_typer.command("logs", no_args_is_help=True)
163
- def get_hazard_task_logs(
164
- task_code: Annotated[str, typer.Argument(help="隐患任务编码")],
165
- page_num: Annotated[int, typer.Option("-n", "--page-num", help="页码")] = 0,
166
- page_size: Annotated[int, typer.Option("-s", "--page-size", help="每页大小")] = 20,
167
- count: Annotated[bool, typer.Option("--count", help="只返回记录数")] = False,
168
- ) -> None:
169
- """获取隐患任务日志列表(按 ``START_TIME DESC`` 排序)。
170
-
171
- Args:
172
- task_code: 隐患任务编码。
173
- page: 页码(从 0 开始)。
174
- size: 每页条数。
175
- count: 是否只返回记录数。
176
-
177
- Examples:
178
- >>> data-ops-cli hazard task logs task_hazard_001
179
- >>> data-ops-cli hazard task logs task_hazard_001 --page-num 0 --page-size 50
180
- >>> data-ops-cli hazard task logs task_hazard_001 --count
181
- """
182
- try:
183
- page_param = _make_page_param(page_num, page_size)
184
- result = service_get_hazard_task_logs(task_code, page_param=page_param, count=count)
185
- except DataOpsError as e:
186
- typer.echo(f"错误: {e.message}")
187
- raise typer.Exit(code=1) from None
188
-
189
- if count:
190
- console.print(f"记录数: {result}")
191
- return
192
- _print_dict_list(result)
193
-
194
-
195
- @hazard_task_typer.command("log-records", no_args_is_help=True)
196
- def get_hazard_task_log_records(
197
- task_id: Annotated[str, typer.Argument(help="隐患任务实例 ID")],
198
- page_num: Annotated[int, typer.Option("-n", "--page-num", help="页码")] = 0,
199
- page_size: Annotated[int, typer.Option("-s", "--page-size", help="每页大小")] = 20,
200
- count: Annotated[bool, typer.Option("--count", help="只返回记录数")] = False,
201
- ) -> None:
202
- """获取隐患任务结果记录(按 ``CREATE_TIME DESC`` 排序)。
203
-
204
- Args:
205
- task_id: 隐患任务实例 ID。
206
- page: 页码(从 0 开始)。
207
- size: 每页条数。
208
- count: 是否只返回记录数。
209
-
210
- Examples:
211
- >>> data-ops-cli hazard task log-records run_001
212
- """
213
- try:
214
- page_param = _make_page_param(page_num, page_size)
215
- result = service_get_hazard_task_log_records(task_id, page_param=page_param, count=count)
216
- except DataOpsError as e:
217
- typer.echo(f"错误: {e.message}")
218
- raise typer.Exit(code=1) from None
219
-
220
- if count:
221
- console.print(f"记录数: {result}")
222
- return
223
- _print_dict_list(result)
224
-
225
-
226
- # ---------------------------------------------------------------------------
227
- # 隐患记录子命令
228
- # ---------------------------------------------------------------------------
229
-
230
-
231
- @hazard_record_typer.command("list", no_args_is_help=True)
232
- def list_hazard_records(
233
- page_num: Annotated[int, typer.Option("-n", "--page-num", help="页码")] = 0,
234
- page_size: Annotated[int, typer.Option("-s", "--page-size", help="每页大小")] = 20,
235
- query: Annotated[
236
- str | None,
237
- typer.Option(
238
- "--query",
239
- "-q",
240
- help='SqlQueryParam JSON,如 \'{"conditionList":[{"name":"STATUS","value":1,"alias":"T0"}]}\'',
241
- ),
242
- ] = None,
243
- count: Annotated[bool, typer.Option("--count", help="只返回记录数")] = False,
244
- ) -> None:
245
- """列出活动隐患记录。
246
-
247
- Args:
248
- page: 页码(从 0 开始)。
249
- size: 每页条数。
250
- query: SqlQueryParam JSON。
251
- count: 是否只返回记录数。
252
-
253
- Examples:
254
- >>> data-ops-cli hazard record list
255
- >>> data-ops-cli hazard record list -q '{"conditionList":[{"name":"STATUS","value":1,"alias":"T0"}]}'
256
- >>> data-ops-cli hazard record list --count
257
- """
258
- try:
259
- query_param = _parse_query_json(query)
260
- page_param = _make_page_param(page_num, page_size)
261
- result = service_list_hazard_records(
262
- page_param=page_param,
263
- query_param=query_param,
264
- count=count,
265
- )
266
- except DataOpsError as e:
267
- typer.echo(f"错误: {e.message}")
268
- raise typer.Exit(code=1) from None
269
-
270
- if count:
271
- console.print(f"记录数: {result}")
272
- return
273
- _print_dict_list(result)
274
-
275
-
276
- @hazard_record_typer.command("his-list", no_args_is_help=True)
277
- def list_hazard_history_records(
278
- page_num: Annotated[int, typer.Option("-n", "--page-num", help="页码")] = 0,
279
- page_size: Annotated[int, typer.Option("-s", "--page-size", help="每页大小")] = 20,
280
- query: Annotated[
281
- str | None,
282
- typer.Option("--query", "-q", help="SqlQueryParam JSON"),
283
- ] = None,
284
- count: Annotated[bool, typer.Option("--count", help="只返回记录数")] = False,
285
- ) -> None:
286
- """列出归档隐患记录。
287
-
288
- Args:
289
- page: 页码(从 0 开始)。
290
- size: 每页条数。
291
- query: SqlQueryParam JSON。
292
- count: 是否只返回记录数。
293
-
294
- Examples:
295
- >>> data-ops-cli hazard record his-list
296
- >>> data-ops-cli hazard record his-list --count
297
- """
298
- try:
299
- query_param = _parse_query_json(query)
300
- page_param = _make_page_param(page_num, page_size)
301
- result = service_list_hazard_history_records(
302
- page_param=page_param,
303
- query_param=query_param,
304
- count=count,
305
- )
306
- except DataOpsError as e:
307
- typer.echo(f"错误: {e.message}")
308
- raise typer.Exit(code=1) from None
309
-
310
- if count:
311
- console.print(f"记录数: {result}")
312
- return
313
- _print_dict_list(result)
314
-
315
-
316
- @hazard_record_typer.command("dispatch-callback", no_args_is_help=True)
317
- def dispatch_callback(
318
- cuid: Annotated[str, typer.Option("--cuid", help="隐患记录 ID")],
319
- order_no: Annotated[str, typer.Option("--order-no", help="外部工单号")],
320
- dispatch_status: Annotated[
321
- int,
322
- typer.Option("--status", help="派遣状态码(业务自行约定,如 1=成功/2=失败)"),
323
- ],
324
- ) -> None:
325
- """外部工单系统回写隐患派遣结果。
326
-
327
- Args:
328
- cuid: 隐患记录 ID。
329
- order_no: 外部工单号。
330
- dispatch_status: 派遣状态码。
331
-
332
- Examples:
333
- >>> data-ops-cli hazard record dispatch-callback \
334
- ... --cuid rec-123 --order-no WT-2026-001 --status 1
335
- """
336
- try:
337
- ok = service_dispatch_hazard_callback(cuid, order_no, dispatch_status)
338
- except DataOpsError as e:
339
- typer.echo(f"错误: {e.message}")
340
- raise typer.Exit(code=1) from None
341
-
342
- if ok:
343
- console.print(f"回调成功: cuid={cuid} orderNo={order_no} status={dispatch_status}")
344
- else:
345
- typer.echo("回调失败: 活动隐患不存在")
346
- raise typer.Exit(code=1) from None
347
-
348
-
349
- @hazard_record_typer.command("his-clear", no_args_is_help=True)
350
- def clear_hazard_history_records(
351
- cuid: Annotated[str, typer.Option("--cuid", help="归档隐患记录 ID")],
352
- clear_notify_status: Annotated[
353
- int | None,
354
- typer.Option("--notify-status", help="清除通知状态码"),
355
- ] = None,
356
- ) -> None:
357
- """清理指定归档隐患记录。
358
-
359
- Args:
360
- cuid: 归档隐患记录 ID。
361
- clear_notify_status: 可选清除通知状态码。
362
-
363
- Examples:
364
- >>> data-ops-cli hazard record his-clear --cuid rec-archived-001
365
- >>> data-ops-cli hazard record his-clear --cuid rec-archived-001 --notify-status 1
366
- """
367
- try:
368
- ok = service_clear_hazard_history_records(
369
- cuid,
370
- clear_notify_status=clear_notify_status,
371
- )
372
- except DataOpsError as e:
373
- typer.echo(f"错误: {e.message}")
374
- raise typer.Exit(code=1) from None
375
-
376
- if ok:
377
- console.print(f"已清除: {cuid}")
378
- else:
379
- typer.echo("清除失败: 归档隐患记录不存在")
380
- raise typer.Exit(code=1) from None
381
-
382
-
383
- # 兼容旧版 CLI(已弃用,保留直至 1.0)
384
- __all__ = ["hazard_typer"]
385
-
386
-
387
- # 旧接口(已弃用)的 stub,避免破坏外部 import
388
- def _safe_str(value: Any) -> str:
389
- if value is None:
390
- return ""
391
- if isinstance(value, (dict, list)):
392
- return to_json(value).decode("utf-8")
393
- return str(value)
394
-
395
-
396
- # 兼容旧版 ``print_list`` 风格的快速打印
397
- def _legacy_print_dict_list(items: list) -> None:
398
- if not items:
399
- print("(空)")
400
- return
401
- if isinstance(items[0], dict):
402
- headers = list(items[0].keys())
403
- rows = [[_safe_str(item.get(h)) for h in headers] for item in items]
404
- print_list(headers, rows)
405
- else:
406
- print(to_json(items).decode("utf-8"))
File without changes
File without changes