dataops-sdk 0.3.0__py3-none-any.whl
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.
Potentially problematic release.
This version of dataops-sdk might be problematic. Click here for more details.
- dataops_sdk/__init__.py +84 -0
- dataops_sdk/constants.py +6 -0
- dataops_sdk/exceptions.py +31 -0
- dataops_sdk/runner/__init__.py +46 -0
- dataops_sdk/runner/datasource_factory.py +83 -0
- dataops_sdk/runner/schemas/nacos/__init__.py +5 -0
- dataops_sdk/runner/schemas/nacos/config.py +40 -0
- dataops_sdk/runner/schemas/nacos/constants.py +235 -0
- dataops_sdk/runner/schemas/nacos/instance.py +103 -0
- dataops_sdk/runner/schemas/nacos/nacos_exception.py +44 -0
- dataops_sdk/runner/schemas/nacos/naming_param.py +62 -0
- dataops_sdk/runner/schemas/nacos/naming_request.py +84 -0
- dataops_sdk/runner/schemas/nacos/naming_response.py +50 -0
- dataops_sdk/runner/schemas/nacos/preserved_metadata_key.py +10 -0
- dataops_sdk/runner/schemas/nacos/service.py +119 -0
- dataops_sdk/runner/utils/__init__.py +42 -0
- dataops_sdk/runner/utils/common.py +209 -0
- dataops_sdk/runner/utils/dbConn_base.py +256 -0
- dataops_sdk/runner/utils/dbConn_sync.py +485 -0
- dataops_sdk/runner/utils/duckdb_manager.py +203 -0
- dataops_sdk/runner/utils/file_transfer_base.py +307 -0
- dataops_sdk/runner/utils/ftp_file_transfer.py +242 -0
- dataops_sdk/runner/utils/log.py +50 -0
- dataops_sdk/runner/utils/nacos.py +96 -0
- dataops_sdk/runner/utils/neo4j_sync.py +236 -0
- dataops_sdk/runner/utils/queue_base.py +224 -0
- dataops_sdk/runner/utils/queue_kafka.py +150 -0
- dataops_sdk/runner/utils/sftp_file_transfer.py +243 -0
- dataops_sdk/schemas/__init__.py +32 -0
- dataops_sdk/schemas/alarm.py +38 -0
- dataops_sdk/schemas/api.py +37 -0
- dataops_sdk/schemas/data_table.py +437 -0
- dataops_sdk/schemas/datasource.py +26 -0
- dataops_sdk/schemas/dict_.py +13 -0
- dataops_sdk/schemas/enums.py +120 -0
- dataops_sdk/schemas/group.py +40 -0
- dataops_sdk/schemas/hazard.py +151 -0
- dataops_sdk/schemas/meta.py +175 -0
- dataops_sdk/schemas/query.py +175 -0
- dataops_sdk/schemas/report.py +22 -0
- dataops_sdk/schemas/skill.py +70 -0
- dataops_sdk/schemas/table.py +65 -0
- dataops_sdk/schemas/user.py +52 -0
- dataops_sdk/schemas/widget.py +651 -0
- dataops_sdk/schemas/workflow.py +63 -0
- dataops_sdk/services/__init__.py +110 -0
- dataops_sdk/services/alarm.py +324 -0
- dataops_sdk/services/api.py +28 -0
- dataops_sdk/services/auth.py +120 -0
- dataops_sdk/services/data_table.py +485 -0
- dataops_sdk/services/dataset.py +127 -0
- dataops_sdk/services/datasource.py +57 -0
- dataops_sdk/services/dict_.py +69 -0
- dataops_sdk/services/hazard.py +260 -0
- dataops_sdk/services/meta.py +523 -0
- dataops_sdk/services/metrics.py +42 -0
- dataops_sdk/services/ref.py +66 -0
- dataops_sdk/services/report.py +36 -0
- dataops_sdk/services/skill.py +276 -0
- dataops_sdk/services/table.py +340 -0
- dataops_sdk/services/widget.py +143 -0
- dataops_sdk/services/workflow.py +102 -0
- dataops_sdk/session.py +292 -0
- dataops_sdk/tiptap/__init__.py +30 -0
- dataops_sdk/tiptap/builder.py +75 -0
- dataops_sdk/tiptap/constants.py +133 -0
- dataops_sdk/tiptap/markdown_parser.py +294 -0
- dataops_sdk/tiptap/models.py +43 -0
- dataops_sdk/tiptap/parse_utils.py +889 -0
- dataops_sdk/tiptap/render_utils.py +846 -0
- dataops_sdk/tiptap/renderers.py +51 -0
- dataops_sdk/tiptap/tool.py +629 -0
- dataops_sdk/utils/__init__.py +15 -0
- dataops_sdk/utils/common.py +211 -0
- dataops_sdk/utils/utils.py +120 -0
- dataops_sdk-0.3.0.dist-info/METADATA +25 -0
- dataops_sdk-0.3.0.dist-info/RECORD +79 -0
- dataops_sdk-0.3.0.dist-info/WHEEL +5 -0
- dataops_sdk-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from typing import Annotated, Any, Literal
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, model_validator
|
|
5
|
+
|
|
6
|
+
from .meta import Meta
|
|
7
|
+
|
|
8
|
+
# ============================================================
|
|
9
|
+
# 共享字段类型(所有卡片类型共用)
|
|
10
|
+
# ============================================================
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DimensionField(BaseModel):
|
|
14
|
+
"""维度字段"""
|
|
15
|
+
|
|
16
|
+
id: Annotated[str, Field(description="维度ID")]
|
|
17
|
+
name: Annotated[str, Field(description="字段名")]
|
|
18
|
+
title: Annotated[str, Field(description="显示标题")]
|
|
19
|
+
dbType: Annotated[str | None, Field(description="数据库类型")] = None
|
|
20
|
+
relId: Annotated[str | None, Field(description="关联ID")] = None
|
|
21
|
+
relType: Annotated[str | None, Field(description="关联类型")] = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MeasureField(BaseModel):
|
|
25
|
+
"""度量字段"""
|
|
26
|
+
|
|
27
|
+
id: Annotated[str, Field(description="度量ID")]
|
|
28
|
+
name: Annotated[str, Field(description="字段名")]
|
|
29
|
+
title: Annotated[str, Field(description="显示标题")]
|
|
30
|
+
dbType: Annotated[str | None, Field(description="数据库类型")] = None
|
|
31
|
+
relId: Annotated[str | None, Field(description="关联ID")] = None
|
|
32
|
+
relType: Annotated[str | None, Field(description="关联类型")] = None
|
|
33
|
+
aggregation: Annotated[
|
|
34
|
+
Literal["avg", "count", "distinct_count", "max", "min", "sum"] | None,
|
|
35
|
+
Field(description="聚合方式"),
|
|
36
|
+
] = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class FilterField(BaseModel):
|
|
40
|
+
"""过滤字段"""
|
|
41
|
+
|
|
42
|
+
id: Annotated[str, Field(description="过滤ID")]
|
|
43
|
+
name: Annotated[str, Field(description="字段名")]
|
|
44
|
+
title: Annotated[str, Field(description="显示标题")]
|
|
45
|
+
operator: Annotated[str | None, Field(description="操作符")] = None
|
|
46
|
+
value: Annotated[Any, Field(description="过滤值")] = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SortField(BaseModel):
|
|
50
|
+
"""排序字段"""
|
|
51
|
+
|
|
52
|
+
id: Annotated[str, Field(description="排序ID")]
|
|
53
|
+
relId: Annotated[str | None, Field(description="关联ID")] = None
|
|
54
|
+
relType: Annotated[Literal["dimension", "measure"] | None, Field(description="关联类型")] = None
|
|
55
|
+
title: Annotated[str | None, Field(description="显示标题")] = None
|
|
56
|
+
asc: Annotated[bool, Field(description="是否升序")] = True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ============================================================
|
|
60
|
+
# Chart 卡片 Schema (v1 + v2 统一)
|
|
61
|
+
# 前端 IdealChartView / IdealChartViewV2 共用
|
|
62
|
+
# 后端 subType="chart",数据 key 也叫 "chart"
|
|
63
|
+
# ============================================================
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ChartType(StrEnum):
|
|
67
|
+
"""图表子类型"""
|
|
68
|
+
|
|
69
|
+
LINE = "line"
|
|
70
|
+
BAR = "bar"
|
|
71
|
+
PIE = "pie"
|
|
72
|
+
DOUGHNUT = "doughnut"
|
|
73
|
+
RADAR = "radar"
|
|
74
|
+
SCATTER = "scatter"
|
|
75
|
+
FUNNEL = "funnel"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TextStyle(BaseModel):
|
|
79
|
+
"""文本样式(legend/xAxis/yAxis/label等使用)"""
|
|
80
|
+
|
|
81
|
+
fontSize: Annotated[int | None, Field(description="字体大小")] = None
|
|
82
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
83
|
+
fontWeight: Annotated[Literal["normal", "bold"] | None, Field(description="字重")] = None
|
|
84
|
+
fontStyle: Annotated[Literal["normal", "italic"] | None, Field(description="字体风格")] = None
|
|
85
|
+
textDecoration: Annotated[Literal["none", "underline"] | None, Field(description="装饰")] = None
|
|
86
|
+
textAlign: Annotated[Literal["left", "center", "right"] | None, Field(description="对齐")] = (
|
|
87
|
+
None
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class ChartAxis(BaseModel):
|
|
92
|
+
"""坐标轴配置"""
|
|
93
|
+
|
|
94
|
+
show: Annotated[bool, Field(description="是否显示")] = True
|
|
95
|
+
showLabel: Annotated[bool, Field(description="是否显示标签")] = True
|
|
96
|
+
labelRotate: Annotated[
|
|
97
|
+
Literal[0, 45, 90, -45, -90] | None, Field(description="标签旋转角度")
|
|
98
|
+
] = None
|
|
99
|
+
labelGap: Annotated[int | None, Field(description="标签间距")] = None
|
|
100
|
+
showAxisLine: Annotated[bool, Field(description="是否显示轴线")] = True
|
|
101
|
+
labelTextStyle: Annotated[TextStyle | None, Field(description="标签文本样式")] = None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class ChartLegend(BaseModel):
|
|
105
|
+
"""图例配置"""
|
|
106
|
+
|
|
107
|
+
show: Annotated[bool, Field(description="是否显示")] = True
|
|
108
|
+
position: Annotated[
|
|
109
|
+
Literal["top", "bottom", "left", "right"] | None, Field(description="位置")
|
|
110
|
+
] = None
|
|
111
|
+
textStyle: Annotated[TextStyle | None, Field(description="文本样式")] = None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class ChartLabel(BaseModel):
|
|
115
|
+
"""标签配置"""
|
|
116
|
+
|
|
117
|
+
show: Annotated[bool, Field(description="是否显示")] = True
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class ChartGrid(BaseModel):
|
|
121
|
+
"""网格配置"""
|
|
122
|
+
|
|
123
|
+
show: Annotated[bool, Field(description="是否显示")] = True
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ChartBackground(BaseModel):
|
|
127
|
+
"""背景配置"""
|
|
128
|
+
|
|
129
|
+
color: Annotated[
|
|
130
|
+
Literal["default", "#ffffff", "#f5f7fa", "#e8f4fd", "#1a1a2e", "#0d1b2a"] | str | None,
|
|
131
|
+
Field(description="背景色"),
|
|
132
|
+
] = "default"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ChartAxisTitle(BaseModel):
|
|
136
|
+
"""轴标题配置"""
|
|
137
|
+
|
|
138
|
+
xAxis: Annotated[TextStyle | None, Field(description="X轴标题")] = None
|
|
139
|
+
yAxis: Annotated[TextStyle | None, Field(description="Y轴标题")] = None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class LineSeriesConfig(BaseModel):
|
|
143
|
+
"""折线图系列配置"""
|
|
144
|
+
|
|
145
|
+
lineStyle: Annotated[TextStyle | None, Field(description="线条样式")] = None
|
|
146
|
+
itemStyle: Annotated[TextStyle | None, Field(description="数据项样式")] = None
|
|
147
|
+
symbol: Annotated[
|
|
148
|
+
Literal["circle", "rect", "triangle", "diamond", "pin", "arrow", "none"] | None,
|
|
149
|
+
Field(description="图标类型"),
|
|
150
|
+
] = "circle"
|
|
151
|
+
symbolSize: Annotated[int | None, Field(description="图标大小")] = None
|
|
152
|
+
yAxisIndex: Annotated[Literal[0, 1] | None, Field(description="Y轴索引")] = None
|
|
153
|
+
label: Annotated[TextStyle | None, Field(description="标签")] = None
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class BarSeriesConfig(BaseModel):
|
|
157
|
+
"""柱状图系列配置"""
|
|
158
|
+
|
|
159
|
+
borderStyle: Annotated[TextStyle | None, Field(description="边框样式")] = None
|
|
160
|
+
yAxisIndex: Annotated[Literal[0, 1] | None, Field(description="Y轴索引")] = None
|
|
161
|
+
label: Annotated[TextStyle | None, Field(description="标签")] = None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class PieLabel(BaseModel):
|
|
165
|
+
"""饼图标签配置"""
|
|
166
|
+
|
|
167
|
+
show: Annotated[bool, Field(description="是否显示")] = True
|
|
168
|
+
position: Annotated[
|
|
169
|
+
Literal["default", "outside", "inside", "center"] | None, Field(description="位置")
|
|
170
|
+
] = None
|
|
171
|
+
content: Annotated[
|
|
172
|
+
list[Literal["category", "value", "percent"]] | None, Field(description="显示内容")
|
|
173
|
+
] = None
|
|
174
|
+
textStyle: Annotated[TextStyle | None, Field(description="文本样式")] = None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class PieSeriesConfig(BaseModel):
|
|
178
|
+
"""饼图系列配置"""
|
|
179
|
+
|
|
180
|
+
borderColor: Annotated[str | None, Field(description="边框颜色")] = None
|
|
181
|
+
donutHole: Annotated[
|
|
182
|
+
Literal["0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%"] | None,
|
|
183
|
+
Field(description="环形挖空"),
|
|
184
|
+
] = "0%"
|
|
185
|
+
startAngle: Annotated[int | None, Field(description="起始角度")] = None
|
|
186
|
+
label: Annotated[PieLabel | None, Field(description="标签")] = None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class SectorConfig(BaseModel):
|
|
190
|
+
"""扇区配置"""
|
|
191
|
+
|
|
192
|
+
backgroundColor: Annotated[str | None, Field(description="背景色")] = None
|
|
193
|
+
borderColor: Annotated[str | None, Field(description="边框颜色")] = None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class ChartOptions(BaseModel):
|
|
197
|
+
"""完整图表选项"""
|
|
198
|
+
|
|
199
|
+
theme: Annotated[str | None, Field(description="主题")] = None
|
|
200
|
+
gradientFill: Annotated[bool | None, Field(description="渐变填充")] = None
|
|
201
|
+
legend: Annotated[ChartLegend | None, Field(description="图例")] = None
|
|
202
|
+
label: Annotated[ChartLabel | None, Field(description="标签")] = None
|
|
203
|
+
xAxis: Annotated[ChartAxis | None, Field(description="X轴")] = None
|
|
204
|
+
yAxis: Annotated[ChartAxis | None, Field(description="Y轴")] = None
|
|
205
|
+
grid: Annotated[ChartGrid | None, Field(description="网格")] = None
|
|
206
|
+
fontStyle: Annotated[TextStyle | None, Field(description="字体样式")] = None
|
|
207
|
+
background: Annotated[ChartBackground | None, Field(description="背景")] = None
|
|
208
|
+
titleStyle: Annotated[TextStyle | None, Field(description="标题样式")] = None
|
|
209
|
+
axisTitle: Annotated[ChartAxisTitle | None, Field(description="轴标题")] = None
|
|
210
|
+
series: Annotated[LineSeriesConfig | BarSeriesConfig | None, Field(description="系列配置")] = (
|
|
211
|
+
None
|
|
212
|
+
)
|
|
213
|
+
seriesList: Annotated[
|
|
214
|
+
list[LineSeriesConfig | BarSeriesConfig],
|
|
215
|
+
Field(description="系列列表", default_factory=list),
|
|
216
|
+
]
|
|
217
|
+
pieSeries: Annotated[PieSeriesConfig | None, Field(description="饼图系列")] = None
|
|
218
|
+
sectors: Annotated[list[SectorConfig], Field(description="扇区配置", default_factory=list)]
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class WidgetChartData(BaseModel):
|
|
222
|
+
"""图表卡片"""
|
|
223
|
+
|
|
224
|
+
type: Annotated[Literal["chart"], Field(description="卡片类型")] = "chart"
|
|
225
|
+
chartType: Annotated[ChartType, Field(description="图表类型")]
|
|
226
|
+
dimensions: Annotated[list[DimensionField], Field(description="维度列表", default_factory=list)]
|
|
227
|
+
measures: Annotated[list[MeasureField], Field(description="度量列表", default_factory=list)]
|
|
228
|
+
filters: Annotated[list[FilterField], Field(description="过滤条件", default_factory=list)]
|
|
229
|
+
sorts: Annotated[list[SortField], Field(description="排序列表", default_factory=list)]
|
|
230
|
+
pageSize: Annotated[int | None, Field(description="页面大小")] = 1000
|
|
231
|
+
options: Annotated[ChartOptions | None, Field(description="图表选项")] = None
|
|
232
|
+
datasource: Annotated[str, Field(description="数据源")]
|
|
233
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
234
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# ============================================================
|
|
238
|
+
# Metric 卡片 Schema
|
|
239
|
+
# ============================================================
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class MetricFontSizeType(StrEnum):
|
|
243
|
+
"""指标字体大小类型"""
|
|
244
|
+
|
|
245
|
+
PRESET = "preset"
|
|
246
|
+
CUSTOM = "custom"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class MetricTitleStyle(BaseModel):
|
|
250
|
+
"""指标标题样式"""
|
|
251
|
+
|
|
252
|
+
text: Annotated[str, Field(description="标题文本")] = "指标卡"
|
|
253
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
254
|
+
fontSize: Annotated[int | None, Field(description="字体大小")] = None
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class MetricValueStyle(BaseModel):
|
|
258
|
+
"""指标值样式"""
|
|
259
|
+
|
|
260
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
261
|
+
fontSize: Annotated[int | None, Field(description="字体大小")] = None
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class MetricBackground(BaseModel):
|
|
265
|
+
"""指标背景样式"""
|
|
266
|
+
|
|
267
|
+
color: Annotated[str | None, Field(description="背景色")] = None
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class MetricStyle(BaseModel):
|
|
271
|
+
"""指标样式配置"""
|
|
272
|
+
|
|
273
|
+
fontSizeType: Annotated[MetricFontSizeType | None, Field(description="字体大小类型")] = None
|
|
274
|
+
title: Annotated[MetricTitleStyle | None, Field(description="标题样式")] = None
|
|
275
|
+
value: Annotated[MetricValueStyle | None, Field(description="值样式")] = None
|
|
276
|
+
background: Annotated[MetricBackground | None, Field(description="背景样式")] = None
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class MetricFormatType(StrEnum):
|
|
280
|
+
"""指标数值格式类型"""
|
|
281
|
+
|
|
282
|
+
NUMBER = "number"
|
|
283
|
+
PERCENT = "percent"
|
|
284
|
+
THOUSAND = "thousand"
|
|
285
|
+
CUSTOM = "custom"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class MetricSuffixStyle(BaseModel):
|
|
289
|
+
"""指标后缀样式"""
|
|
290
|
+
|
|
291
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
292
|
+
fontSize: Annotated[int | None, Field(description="字体大小")] = None
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class MetricFormat(BaseModel):
|
|
296
|
+
"""指标数值格式配置"""
|
|
297
|
+
|
|
298
|
+
type: Annotated[MetricFormatType | None, Field(description="格式类型")] = None
|
|
299
|
+
precision: Annotated[Literal[0, 1, 2, 3, 4] | None, Field(description="精度")] = None
|
|
300
|
+
prefix: Annotated[str | None, Field(description="前缀")] = None
|
|
301
|
+
suffix: Annotated[str | None, Field(description="后缀")] = None
|
|
302
|
+
suffixStyle: Annotated[MetricSuffixStyle | None, Field(description="后缀样式")] = None
|
|
303
|
+
thousandSeparator: Annotated[bool | None, Field(description="千分位分隔符")] = None
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class WidgetMetricData(BaseModel):
|
|
307
|
+
"""指标卡片"""
|
|
308
|
+
|
|
309
|
+
type: Annotated[Literal["metric"], Field(description="卡片类型")] = "metric"
|
|
310
|
+
style: Annotated[MetricStyle | None, Field(description="样式配置")] = None
|
|
311
|
+
format: Annotated[MetricFormat | None, Field(description="格式配置")] = None
|
|
312
|
+
dimensions: Annotated[list[DimensionField], Field(description="维度列表", default_factory=list)]
|
|
313
|
+
measures: Annotated[list[MeasureField], Field(description="度量列表", default_factory=list)]
|
|
314
|
+
filters: Annotated[list[FilterField], Field(description="过滤条件", default_factory=list)]
|
|
315
|
+
datasource: Annotated[str, Field(description="数据源")]
|
|
316
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
317
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
# ============================================================
|
|
321
|
+
# Detail 卡片 Schema
|
|
322
|
+
# ============================================================
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class DetailDirection(StrEnum):
|
|
326
|
+
"""明细卡片方向"""
|
|
327
|
+
|
|
328
|
+
HORIZONTAL = "horizontal"
|
|
329
|
+
VERTICAL = "vertical"
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class DetailSize(StrEnum):
|
|
333
|
+
"""明细卡片尺寸"""
|
|
334
|
+
|
|
335
|
+
LARGE = "large"
|
|
336
|
+
DEFAULT = "default"
|
|
337
|
+
SMALL = "small"
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class DetailConfig(BaseModel):
|
|
341
|
+
"""明细卡片配置"""
|
|
342
|
+
|
|
343
|
+
title: Annotated[str | None, Field(description="标题")] = None
|
|
344
|
+
column: Annotated[int, Field(description="列数", ge=1, le=10)] = 2
|
|
345
|
+
border: Annotated[bool, Field(description="是否显示边框")] = True
|
|
346
|
+
direction: Annotated[DetailDirection, Field(description="方向")] = DetailDirection.HORIZONTAL
|
|
347
|
+
size: Annotated[DetailSize, Field(description="尺寸")] = DetailSize.DEFAULT
|
|
348
|
+
labelWidth: Annotated[str | None, Field(description="标签宽度")] = None
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
class WidgetDetailData(BaseModel):
|
|
352
|
+
"""明细卡片"""
|
|
353
|
+
|
|
354
|
+
type: Annotated[Literal["detail"], Field(description="卡片类型")] = "detail"
|
|
355
|
+
config: Annotated[DetailConfig, Field(description="配置")]
|
|
356
|
+
dimensions: Annotated[list[DimensionField], Field(description="维度列表", default_factory=list)]
|
|
357
|
+
measures: Annotated[list[MeasureField], Field(description="度量列表", default_factory=list)]
|
|
358
|
+
filters: Annotated[list[FilterField], Field(description="过滤条件", default_factory=list)]
|
|
359
|
+
datasource: Annotated[str, Field(description="数据源")]
|
|
360
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
361
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# ============================================================
|
|
365
|
+
# Topology 卡片 Schema
|
|
366
|
+
# ============================================================
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class TopologyNodeStyle(BaseModel):
|
|
370
|
+
"""拓扑节点样式"""
|
|
371
|
+
|
|
372
|
+
shape: Annotated[str | None, Field(description="形状")] = None
|
|
373
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
374
|
+
size: Annotated[str | None, Field(description="大小")] = None
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
class TopologyEdgeStyle(BaseModel):
|
|
378
|
+
"""拓扑边样式"""
|
|
379
|
+
|
|
380
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
381
|
+
lineStyle: Annotated[str | None, Field(description="线条样式")] = None
|
|
382
|
+
width: Annotated[int | None, Field(description="宽度")] = None
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
class WorkflowInputItem(BaseModel):
|
|
386
|
+
"""工作流输入参数"""
|
|
387
|
+
|
|
388
|
+
name: Annotated[str, Field(description="参数名")]
|
|
389
|
+
title: Annotated[str | None, Field(description="显示标题")] = None
|
|
390
|
+
type: Annotated[str, Field(description="参数类型")]
|
|
391
|
+
required: Annotated[bool, Field(description="是否必填")] = False
|
|
392
|
+
defaultValue: Annotated[Any, Field(description="默认值")] = None
|
|
393
|
+
description: Annotated[str | None, Field(description="描述")] = None
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
class WorkflowTreeNode(BaseModel):
|
|
397
|
+
"""工作流树节点"""
|
|
398
|
+
|
|
399
|
+
id: Annotated[str, Field(description="节点ID")]
|
|
400
|
+
label: Annotated[str, Field(description="显示标签")]
|
|
401
|
+
name: Annotated[str | None, Field(description="节点名称")] = None
|
|
402
|
+
type: Annotated[Literal["group", "workflow"], Field(description="节点类型")]
|
|
403
|
+
children: Annotated[list["WorkflowTreeNode"], Field(description="子节点", default_factory=list)]
|
|
404
|
+
code: Annotated[str | None, Field(description="编码")] = None
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class WorkflowConfig(BaseModel):
|
|
408
|
+
"""工作流配置"""
|
|
409
|
+
|
|
410
|
+
flowCode: Annotated[str | None, Field(description="流程编码")] = None
|
|
411
|
+
params: Annotated[dict[str, Any] | None, Field(description="流程参数")] = None
|
|
412
|
+
topologyStyle: Annotated[dict[str, Any] | None, Field(description="拓扑样式")] = None
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class WidgetTopologyData(BaseModel):
|
|
416
|
+
"""拓扑卡片"""
|
|
417
|
+
|
|
418
|
+
type: Annotated[Literal["topology"], Field(description="卡片类型")] = "topology"
|
|
419
|
+
layoutType: Annotated[str, Field(description="布局类型")] = "dagre"
|
|
420
|
+
nodeStyle: Annotated[TopologyNodeStyle | None, Field(description="节点样式")] = None
|
|
421
|
+
edgeStyle: Annotated[TopologyEdgeStyle | None, Field(description="边样式")] = None
|
|
422
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
423
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
424
|
+
workflowConfig: Annotated[WorkflowConfig | None, Field(description="工作流配置")] = None
|
|
425
|
+
inputItems: Annotated[
|
|
426
|
+
list[WorkflowInputItem], Field(description="输入项", default_factory=list)
|
|
427
|
+
]
|
|
428
|
+
treeData: Annotated[list[WorkflowTreeNode], Field(description="树形数据", default_factory=list)]
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
# ============================================================
|
|
432
|
+
# 旧版 Table 卡片 Schema(向后兼容)
|
|
433
|
+
# ============================================================
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
class WidgetDimension(BaseModel):
|
|
437
|
+
"""卡片表格维度"""
|
|
438
|
+
|
|
439
|
+
name: Annotated[str, Field(description="字段名")]
|
|
440
|
+
title: Annotated[str, Field(description="显示标题")]
|
|
441
|
+
nullable: Annotated[bool, Field(description="是否可空")]
|
|
442
|
+
dbType: Annotated[str, Field(description="数据库类型")]
|
|
443
|
+
length: Annotated[int, Field(description="长度")]
|
|
444
|
+
labelKey: Annotated[bool | None, Field(description="是否为标签字段")] = None
|
|
445
|
+
pk: Annotated[bool | None, Field(description="是否主键")] = None
|
|
446
|
+
relId: Annotated[str | None, Field(description="关联ID")] = None
|
|
447
|
+
relType: Annotated[str | None, Field(description="关联类型")] = None
|
|
448
|
+
id: Annotated[str, Field(description="维度ID")]
|
|
449
|
+
type: Annotated[str | None, Field(description="类型")] = None
|
|
450
|
+
remark: Annotated[str | None, Field(description="备注")] = None
|
|
451
|
+
format: Annotated["WidgetFormat | None", Field(description="格式化")] = None
|
|
452
|
+
link: Annotated["WidgetLink | None", Field(description="链接")] = None
|
|
453
|
+
cellStyle: Annotated["WidgetCellStyle | None", Field(description="单元格样式")] = None
|
|
454
|
+
typeExt: Annotated["WidgetTypeExt | None", Field(description="类型扩展")] = None
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class WidgetQuery(BaseModel):
|
|
458
|
+
"""卡片表格查询条件"""
|
|
459
|
+
|
|
460
|
+
id: Annotated[str, Field(description="查询条件ID")]
|
|
461
|
+
name: Annotated[str, Field(description="字段名")]
|
|
462
|
+
title: Annotated[str, Field(description="显示标题")]
|
|
463
|
+
dbType: Annotated[str, Field(description="数据库类型")]
|
|
464
|
+
plugin: Annotated["WidgetPlugin", Field(description="插件配置")]
|
|
465
|
+
condition: Annotated["WidgetCondition", Field(description="条件配置")]
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class WidgetFormat(BaseModel):
|
|
469
|
+
"""格式化配置"""
|
|
470
|
+
|
|
471
|
+
type: Annotated[str, Field(description="格式类型")]
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
class WidgetLink(BaseModel):
|
|
475
|
+
"""链接配置"""
|
|
476
|
+
|
|
477
|
+
type: Annotated[str, Field(description="链接类型")]
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
class WidgetCellStyle(BaseModel):
|
|
481
|
+
"""单元格样式"""
|
|
482
|
+
|
|
483
|
+
rules: Annotated[list, Field(description="样式规则")] = []
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
class WidgetPlugin(BaseModel):
|
|
487
|
+
"""插件配置"""
|
|
488
|
+
|
|
489
|
+
type: Annotated[str, Field(description="插件类型")]
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class WidgetCondition(BaseModel):
|
|
493
|
+
"""查询条件"""
|
|
494
|
+
|
|
495
|
+
expression: Annotated[str, Field(description="表达式")] = "eq"
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class WidgetTypeExt(BaseModel):
|
|
499
|
+
"""类型扩展"""
|
|
500
|
+
|
|
501
|
+
ref__table: Annotated["WidgetRefTable | None", Field(description="引用表")] = None
|
|
502
|
+
ref__valueField: Annotated["WidgetRefValueField | None", Field(description="引用值字段")] = None
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
class WidgetRefTable(BaseModel):
|
|
506
|
+
"""引用表"""
|
|
507
|
+
|
|
508
|
+
type: Annotated[str, Field(description="类型")] = "table"
|
|
509
|
+
code: Annotated[str | None, Field(description="编码")] = None
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
class WidgetRefValueField(BaseModel):
|
|
513
|
+
"""引用值字段"""
|
|
514
|
+
|
|
515
|
+
type: Annotated[str, Field(description="类型")] = "table"
|
|
516
|
+
code: Annotated[str | None, Field(description="编码")] = None
|
|
517
|
+
subtype: Annotated[str | None, Field(description="子类型")] = None
|
|
518
|
+
subcode: Annotated[str | None, Field(description="子编码")] = None
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
class WidgetTable(BaseModel):
|
|
522
|
+
"""卡片表格配置(兼容旧版)"""
|
|
523
|
+
|
|
524
|
+
type: Annotated[Literal["table"], Field(description="卡片类型")] = "table"
|
|
525
|
+
filters: Annotated[list, Field(description="过滤条件")] = []
|
|
526
|
+
datasource: Annotated[str, Field(description="数据源")]
|
|
527
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
528
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
529
|
+
dimensions: Annotated[list[WidgetDimension], Field(description="维度列表")] = []
|
|
530
|
+
querys: Annotated[list[WidgetQuery], Field(description="查询条件列表")] = []
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
# ============================================================
|
|
534
|
+
# GIS 卡片 Schema (v1)
|
|
535
|
+
# 前端 IdealGisView 共用
|
|
536
|
+
# 后端 subType="gis",数据 key 为 "gis"
|
|
537
|
+
# ============================================================
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
class GisLayer(BaseModel):
|
|
541
|
+
"""GIS 图层"""
|
|
542
|
+
|
|
543
|
+
id: Annotated[str, Field(description="图层ID")]
|
|
544
|
+
name: Annotated[str, Field(description="图层名称")]
|
|
545
|
+
color: Annotated[str | None, Field(description="颜色")] = None
|
|
546
|
+
layerType: Annotated[str | None, Field(description="图层类型")] = None
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
class WidgetGisData(BaseModel):
|
|
550
|
+
"""GIS 卡片"""
|
|
551
|
+
|
|
552
|
+
type: Annotated[Literal["gis"], Field(description="卡片类型")] = "gis"
|
|
553
|
+
mapToken: Annotated[str | None, Field(description="Mapbox Token")] = None
|
|
554
|
+
layers: Annotated[list[GisLayer], Field(description="图层列表", default_factory=list)]
|
|
555
|
+
datasource: Annotated[str, Field(description="数据源")]
|
|
556
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
557
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
# ============================================================
|
|
561
|
+
# AI 设计卡片 Schema (v1)
|
|
562
|
+
# 前端 IdealStatisticView 共用
|
|
563
|
+
# 后端 subType="statistic",数据 key 为 "statistic"
|
|
564
|
+
# ============================================================
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
class WidgetStatisticData(BaseModel):
|
|
568
|
+
"""AI 设计卡片"""
|
|
569
|
+
|
|
570
|
+
type: Annotated[Literal["statistic"], Field(description="卡片类型")] = "statistic"
|
|
571
|
+
cssText: Annotated[str | None, Field(description="自定义 CSS")] = None
|
|
572
|
+
datasource: Annotated[str, Field(description="数据源")]
|
|
573
|
+
metaType: Annotated[str, Field(description="元数据类型")]
|
|
574
|
+
metaName: Annotated[str, Field(description="元数据名称")]
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
# ============================================================
|
|
578
|
+
# 统一卡片数据联合类型(带 pydantic discriminator)
|
|
579
|
+
# ============================================================
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
# 所有卡片数据类型的联合(用于 pydantic discriminated union)
|
|
583
|
+
# pydantic 根据每个子类的 `type` 字段自动识别具体类型
|
|
584
|
+
WidgetData = Annotated[
|
|
585
|
+
WidgetChartData
|
|
586
|
+
| WidgetMetricData
|
|
587
|
+
| WidgetDetailData
|
|
588
|
+
| WidgetTopologyData
|
|
589
|
+
| WidgetTable
|
|
590
|
+
| WidgetGisData
|
|
591
|
+
| WidgetStatisticData,
|
|
592
|
+
Field(discriminator="type"),
|
|
593
|
+
]
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
class WidgetMetaData(BaseModel):
|
|
597
|
+
"""卡片元数据.
|
|
598
|
+
|
|
599
|
+
后端 rawData 结构: {"<subType>": {...}, "tenantId": ..., "code": ..., ...}
|
|
600
|
+
其中 subType 的值 (chart/metric/detail/topology/table/gis/statistic) 对应子类型 key 名称。
|
|
601
|
+
|
|
602
|
+
通过 model_validator 将 meta.data[subType] 路由到 widget_data 字段,
|
|
603
|
+
使 meta.data 成为 discriminated union 类型,方便 CLI 层做子类型分派渲染。
|
|
604
|
+
"""
|
|
605
|
+
|
|
606
|
+
widget_data: Annotated[
|
|
607
|
+
WidgetChartData
|
|
608
|
+
| WidgetMetricData
|
|
609
|
+
| WidgetDetailData
|
|
610
|
+
| WidgetTopologyData
|
|
611
|
+
| WidgetTable
|
|
612
|
+
| WidgetGisData
|
|
613
|
+
| WidgetStatisticData,
|
|
614
|
+
Field(discriminator="type", description="卡片子类型数据(按 subType 路由)"),
|
|
615
|
+
]
|
|
616
|
+
tenantId: Annotated[str, Field(description="租户ID")]
|
|
617
|
+
enterpriseCuid: Annotated[str, Field(description="企业CUID")]
|
|
618
|
+
name: Annotated[str, Field(description="名称")]
|
|
619
|
+
code: Annotated[str, Field(description="编码")]
|
|
620
|
+
title: Annotated[str, Field(description="标题")]
|
|
621
|
+
subType: Annotated[str | None, Field(description="子类型")] = None
|
|
622
|
+
groupCode: Annotated[str | None, Field(description="分组编码")] = None
|
|
623
|
+
|
|
624
|
+
@model_validator(mode="before")
|
|
625
|
+
@classmethod
|
|
626
|
+
def _route_subtype(cls, values: dict) -> dict:
|
|
627
|
+
"""根据 subType 将 meta.data[subType] 路由到 widget_data 字段."""
|
|
628
|
+
sub_type: str | None = values.get("subType")
|
|
629
|
+
data: dict = values.get("data") or {}
|
|
630
|
+
if sub_type and sub_type in data:
|
|
631
|
+
# 子类型数据在 meta.data[subType] 中
|
|
632
|
+
values["widget_data"] = data[sub_type]
|
|
633
|
+
elif not sub_type:
|
|
634
|
+
# 兜底:遍历所有已知子类型 key,找第一个匹配的
|
|
635
|
+
for key in (
|
|
636
|
+
"chart",
|
|
637
|
+
"metric",
|
|
638
|
+
"detail",
|
|
639
|
+
"topology",
|
|
640
|
+
"table",
|
|
641
|
+
"gis",
|
|
642
|
+
"statistic",
|
|
643
|
+
):
|
|
644
|
+
if key in data:
|
|
645
|
+
values["widget_data"] = data[key]
|
|
646
|
+
break
|
|
647
|
+
return values
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
class WidgetMeta(Meta[WidgetMetaData]):
|
|
651
|
+
"""卡片 Meta"""
|