@josephyan/qingflow-cli 1.0.11 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/npm/bin/qingflow.mjs +40 -2
- package/npm/lib/runtime.mjs +386 -15
- package/npm/scripts/postinstall.mjs +7 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-cli/SKILL.md +440 -0
- package/skills/qingflow-cli/manifest.yaml +10 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_ADMIN_CHEATSHEET.md +94 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md +485 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md +237 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_MATCH_RULES.md +137 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_PORTAL_WORKFLOW.md +263 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md +304 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_WORKSPACE_ICONS.md +41 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md +139 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_EXPLORATION_REPORT.md +84 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_FIELD_DATA_TYPES.md +129 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_MEMBER_CHEATSHEET.md +195 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md +159 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md +20 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_IMPORT_WORKFLOW.md +176 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md +163 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_SCHEMA_APPLY_FIELD_TYPES_AND_SCENARIOS.md +107 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md +151 -0
- package/skills/qingflow-cli/reference/_batch_schema_complex.json +18 -0
- package/skills/qingflow-cli/reference/_batch_schema_scalar.json +17 -0
- package/skills/qingflow-cli/reference/charts_remove.example.json +1 -0
- package/skills/qingflow-cli/reference/charts_reorder.example.json +1 -0
- package/skills/qingflow-cli/reference/charts_upsert_bar.example.json +8 -0
- package/skills/qingflow-cli/reference/charts_upsert_dashboard_starter.example.json +37 -0
- package/skills/qingflow-cli/reference/charts_upsert_minimal.example.json +13 -0
- package/skills/qingflow-cli/reference/portal_sections_all_types.example.json +131 -0
- package/skills/qingflow-cli/reference/portal_sections_five_types.example.json +126 -0
- package/skills/qingflow-cli/reference/portal_sections_standard_workbench.example.json +128 -0
- package/skills/qingflow-cli/reference/schema_add_fields_minimal.example.json +7 -0
- package/skills/qingflow-cli/reference/schema_apply_add_fields_all_types.json +78 -0
- package/skills/qingflow-cli/reference/views_upsert_table_minimal.example.json +7 -0
- package/skills/qingflow-cli/scripts/builder-package-from-app-list.py +140 -0
- package/skills/qingflow-cli/scripts/find-app-by-keyword.py +132 -0
- package/skills/qingflow-cli/scripts/validate_qingflow_output_files.py +87 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/models.py +532 -48
- package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
- package/src/qingflow_mcp/cli/commands/app.py +3 -16
- package/src/qingflow_mcp/cli/commands/builder.py +354 -56
- package/src/qingflow_mcp/cli/commands/record.py +89 -2
- package/src/qingflow_mcp/cli/formatters.py +32 -1
- package/src/qingflow_mcp/cli/main.py +245 -3
- package/src/qingflow_mcp/public_surface.py +11 -8
- package/src/qingflow_mcp/response_trim.py +143 -14
- package/src/qingflow_mcp/server.py +15 -12
- package/src/qingflow_mcp/server_app_builder.py +108 -30
- package/src/qingflow_mcp/server_app_user.py +17 -18
- package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
- package/src/qingflow_mcp/solution/executor.py +3 -133
- package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
- package/src/qingflow_mcp/tools/app_tools.py +53 -8
- package/src/qingflow_mcp/tools/package_tools.py +16 -2
- package/src/qingflow_mcp/tools/record_tools.py +2095 -176
- package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
- package/src/qingflow_mcp/tools/solution_tools.py +30 -2
- package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
- package/src/qingflow_mcp/version.py +110 -0
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Builder 报表(QingBI)创建与变更 SOP:`qingflow builder charts apply`
|
|
2
|
+
|
|
3
|
+
稳定命令:**`qingflow builder charts apply`**(子命令 **`builder charts apply`**;**`qingflow build charts apply`** 等价)。
|
|
4
|
+
|
|
5
|
+
实现要点:`builder_facade/models.py`(**`ChartUpsertPatch`**、**`ChartPartialPatch`**、**`ChartApplyRequest`**、**`ChartFilterRulePatch`**)、`builder_facade/service.py`(**`chart_apply`** / **`_build_public_chart_config_payload`**)、`cli/commands/builder.py`(**`--upsert-file`** / **`--patch-file`** / **`--remove-chart-ids-file`** / **`--reorder-chart-ids-file`**)。已对应用 **`ead8ims5i401`** 与工时测试应用实跑:**新建/更新 `target`、常规图表、`summary` / `gauge` / `scatter` / `dualaxes`,按 `chart_id` 更新(改名 + `visibility`)、仅 `reorder`**。
|
|
6
|
+
|
|
7
|
+
> **权限**:**`data_manage`**(与其它搭建写一致,`chart_apply` 内 **`_guard_app_permission`**)。
|
|
8
|
+
|
|
9
|
+
> **读取链路**:`builder chart get` / `chart_get` 读取基础信息时优先走前端同源的 **`/qingbi/charts/qflow/baseinfo/{chartId}`** 可见性链路;仅当该 qflow 路由明确不存在/不适用时才退回 BI 管理详情 **`/qingbi/charts/baseinfo/{chartId}`**。配置详情 **`/qingbi/charts/{chartId}/configs`** 仍可能需要 **`CHART_SEE`**,不可用时会尝试从 qflow 数据接口返回的 embedded config 降级。不要把中间 **`CHART_SEE` / 40002** 直接当成“用户看不到报表”。
|
|
10
|
+
|
|
11
|
+
> **契约**:`qingflow --json builder contract --tool-name app_charts_apply`
|
|
12
|
+
> (`--tool-name` 为契约索引。)
|
|
13
|
+
|
|
14
|
+
> **与「应用发布」的关系**:契约 **execution_notes** 写明 **`app_charts_apply` 为 immediate-live,不走 `app_publish`**。改报表不等价于 **`builder publish verify`**。
|
|
15
|
+
|
|
16
|
+
> **能力边界**:`builder charts apply` 只创建/更新 **应用源 QingBI 报表**(生成 `dataSourceType=qingflow`)。**数据集 BI 报表不在此工具创建/编辑**;先在 QingBI 中创建数据集报表,再用 **`builder associated-resource apply`** 以 `report_source: "dataset"` 关联到轻流应用。
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. CLI 形态
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
qingflow --json builder charts apply \
|
|
24
|
+
--app-key "<APP_KEY>" \
|
|
25
|
+
[--upsert-file UPSERT_JSON] \
|
|
26
|
+
[--patch-file PATCH_JSON] \
|
|
27
|
+
[--remove-chart-ids-file REMOVE_JSON] \
|
|
28
|
+
[--reorder-chart-ids-file REORDER_JSON] \
|
|
29
|
+
> tmp/builder_charts_apply.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- 四个文件参数均可省略,但 **`ChartApplyRequest`** 要求 **至少一项非空**(**upsert** / **patch** / **remove** / **reorder**),否则校验报错。
|
|
33
|
+
- 各文件均为 **JSON 数组**(与 `load_list_arg` 一致)。
|
|
34
|
+
- 大 JSON 必须 **落盘**,见主技能 **builder** 行。
|
|
35
|
+
- 完整系统里一次要创建很多报表时,主路径按应用或主题分批提交,推荐每批 **4-8 个 `upsert_charts`**。超过 8 个时 CLI 会在写入前返回 `CHART_UPSERT_BATCH_TOO_LARGE`,并给出 `details.suggested_batch_payloads[]`;直接逐个执行这些 payload,不要提交原始大数组。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. 推荐顺序(读 → 写 → 核对)
|
|
40
|
+
|
|
41
|
+
| 步骤 | 动作 | CLI |
|
|
42
|
+
|------|------|-----|
|
|
43
|
+
| ① 解析应用 | 确认 **`app_key`** | **`builder app resolve --app-key …`** |
|
|
44
|
+
| ② 读报表字段 | 取 **`chart_fields[]`** 中的 **显示名**、**`field_id`**(如 **`field_数字`**)或 **`bi_field_id`**,供 `group_by` / `metric` / `where` 用;可直接复制 **`chart_fields[].chart_apply_examples`** 作为 apply 片段 | **`builder app get --app-key … fields`** |
|
|
45
|
+
| ③ 读现有报表 | 已有 **`chart_id`**、重名风险 | 先看 **`builder app get --app-key …`** 的 compact `charts`;不足时再用 **`builder app get --app-key … charts`** |
|
|
46
|
+
| ④ 应用变更 | upsert / remove / reorder | **`builder charts apply …`** |
|
|
47
|
+
| ⑤ 再读列表 | 确认顺序与条目 | 再次 **`builder app get --app-key …`**;需要完整报表清单时再下钻 `builder app get charts` |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. `upsert_charts[]` 形状(**`ChartUpsertPatch`**)
|
|
52
|
+
|
|
53
|
+
| 键 | 说明 |
|
|
54
|
+
|----|------|
|
|
55
|
+
| **`name`** | 必填;新建时即图表名;**更新**时可改名。 |
|
|
56
|
+
| **`chart_type`** | 以 `qingflow --json builder contract --tool-name app_charts_apply` 的 `$.contract.allowed_values["chart.chart_type"]` 为准;当前公开面已覆盖 QingBI 常用类型,如 **`target` / `indicator` / `summary` / `pie` / `bar` / `columnar` / `line` / `table` / `detail` / `area` / `stacked_area` / `funnel` / `waterfall` / `gauge` / `heatmap` / `histogram` / `treemap` / `radar` / `stacked_bar` / `stacked_column` / `scatter` / `ring` / `rose` / `dualaxes` / `map`** 等;最终仍以 contract 为准。 |
|
|
57
|
+
| **`chart_id`** | 可选。**有则按 id 命中更新**;无则 **按 `name` 精确匹配**:0 个 → **创建**;多个 → **歧义报错**(须带 **`chart_id`**)。 |
|
|
58
|
+
| **`metric`** / **`metrics`** | **主推语义指标写法**:`"count(*)"`、`"sum(金额)"`、`"avg(工时)"`、`"max(评分)"`、`"min(耗时)"`,也支持对象 `{"op":"sum","field":"金额"}`。字段必须来自 **`chart_fields[]`**。 |
|
|
59
|
+
| **`group_by`** | **主推维度写法**:字段显示名、`field_id` 或 `bi_field_id` 数组,例如 `["使用状态"]`。 |
|
|
60
|
+
| **`where`** / **`filters`** | 统一固定筛选写法:**`field`/`field_name`**(可用 **`chart_fields[].title`** / **`field_id`** / **`bi_field_id`**)+ **`op`/`operator`** + **`value`/`values`** → 写入配置 **`beforeAggregationFilterMatrix`**。 |
|
|
61
|
+
| **`dimension_field_ids`** / **`indicator_field_ids`** | 兼容/高级写法;旧 payload 可继续用,但智能体主路径优先写 `group_by` + `metric(s)`。 |
|
|
62
|
+
| **`visibility`** | 可选;编译为 QingBI **`visibleAuth`**;**仅更新 visibility** 时不重算其它授权结构(见契约)。**更新**时 **省略** 可保留原可见性。 |
|
|
63
|
+
| **`config`** | 透传高级键:`aggregate`、`beforeAggregationFilterMatrix`、`afterAggregationFilterMatrix`、`chartStyleConfigs`、`displayLimitConfig`、`rawDataConfigDTO`、`query_condition_field_ids` 等;未列键会 **merge 进根**(实现 **`_build_public_chart_config_payload`**)。主路径不要手写 `selectedMetrics` / `xMetrics` / `leftMetrics`。 |
|
|
64
|
+
| **`question_config`** / **`user_config`** | 可选;分别 POST **`/chart/{id}/question/config`** 与 **`/user/config`**。 |
|
|
65
|
+
|
|
66
|
+
**配置是否重算**:若已存在图表且本次 **未显式**改 **`metric(s)` / `group_by` / `where` / `dimension_field_ids` / `indicator_field_ids` / `filters` / `config`**(Pydantic **`model_fields_set`**),实现可 **跳过** **`qingbi_report_update_config`**;**新建**总会写配置。
|
|
67
|
+
|
|
68
|
+
**报表筛选 operator**:推荐使用 `eq` / `neq` / `in` / `contains` / `gte` / `lte` / `is_empty` / `not_empty`;兼容 `equal` / `equals` / `=` / `!=` / `any_of` / `one_of` / `empty` 等别名。CLI 会自动转成 QingBI 字符串判断符(如 `equal`、`anyMatch`、`isNull`)和 BI 前端需要的 `judgeValue` 文本值;单选/多选筛选入参可传选项文本或 option id,CLI 会按 QingBI 路径转成文本。智能体不要手写 `judgeType`、`judgeValue`、`beforeAggregationFilterMatrix`。
|
|
69
|
+
|
|
70
|
+
**读回语义**:`builder chart get` / `chart_get` 会返回语义化 `group_by`、`metrics`、`filters`;`config.*` 仅作为 raw 诊断,不作为智能体更新主输入。
|
|
71
|
+
|
|
72
|
+
示例:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{"field_name": "使用状态", "operator": "eq", "value": "正常"}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3.1 推荐语义写法
|
|
79
|
+
|
|
80
|
+
指标卡:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{"name": "正常设备数", "chart_type": "target", "metric": "count(*)", "where": [{"field": "使用状态", "op": "eq", "value": "正常"}]}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
字段聚合:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{"name": "维修费用总额", "chart_type": "target", "metric": "sum(维修费用)"}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
分组图表:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{"name": "设备状态分布", "chart_type": "bar", "group_by": ["使用状态"], "metric": "count(*)"}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
双轴图:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{"name": "预算执行对比", "chart_type": "dualaxes", "group_by": ["月份"], "left_metric": "sum(预算金额)", "right_metric": "sum(实际金额)"}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
字段发现返回的 `chart_fields[].chart_apply_examples` 会给出同样语义的可复制片段:
|
|
105
|
+
|
|
106
|
+
- `count_by_field`:按该字段分组计数,适合 bar/columnar/pie 类分布图。
|
|
107
|
+
- `filtered_count`:按该字段固定筛选后计数,适合 target/indicator 指标卡。
|
|
108
|
+
- `sum_metric`:仅数值字段提供,适合金额/数量/工时等合计指标卡。
|
|
109
|
+
|
|
110
|
+
拿到片段后只改 `name`、`chart_type` 和筛选值即可,不要改写成 `indicator_field_ids` / `config.aggregate` / `selectedMetrics`。
|
|
111
|
+
|
|
112
|
+
### 3.2 BI 类型与后端字段映射
|
|
113
|
+
|
|
114
|
+
CLI 对外推荐使用 **`group_by` + `metric(s)`**;旧的 **`dimension_field_ids`** 和 **`indicator_field_ids`** 仍兼容。字段来源必须是 **`app_get_fields.chart_fields`** 的 QingBI datasource 字段。部分 QingBI 类型后端字段槽位不同,CLI 会自动转换:
|
|
115
|
+
|
|
116
|
+
| `chart_type` | 后端要求 | CLI 处理 |
|
|
117
|
+
|--------------|----------|----------|
|
|
118
|
+
| **`summary`** | `xDimensions` / `yDimensions` + `selectedMetrics` | `rows` 写入 `xDimensions`,`columns` 写入 `yDimensions`,`metrics` 写入 `selectedMetrics`。 |
|
|
119
|
+
| **`scatter`** | `selectedDimensions` + 单个 `xMetrics` + 单个 `yMetrics` | `x_metric` / `y_metric` 分别写入 X/Y;也兼容 `metrics` 前两个。 |
|
|
120
|
+
| **`dualaxes`** | `selectedDimensions` + `leftMetrics` / `rightMetrics` | `left_metric` / `right_metric` 分别写入左/右轴;也兼容 `metrics` 前两个。 |
|
|
121
|
+
| **`gauge`** | 无维度,且必须有两个不重复指标 | `value_metric` / `target_metric` 为主;只给一个真实指标时,第二指标自动补 **`数据总量`**。 |
|
|
122
|
+
| **`histogram`** | 最多 1 个维度,且必须 1 个普通数值指标 | 不能省略指标,不能使用默认 **`数据总量`** / count,不能使用文本字段或聚合公式字段;推荐 `metric: "sum(数值字段)"` 或 `metric: "avg(数值字段)"`。 |
|
|
123
|
+
| **`heatmap`** | 2 个维度 + 1 个指标 | 不满足时 CLI 会提前返回 `diagnostics`,不要等后端裸 810xx。 |
|
|
124
|
+
| **`waterfall` / `map`** | 1 个维度 + 1 个指标 | `map` 的维度应选位置/地区含义字段。 |
|
|
125
|
+
| **`treemap`** | 1-2 个维度 + 1 个指标 | 维度过少/过多都会被前置校验。 |
|
|
126
|
+
|
|
127
|
+
这些转换用于避免“报表配置未完成”。若用户显式在 `config` 中提供 `xDimensions`、`xMetrics`、`leftMetrics` 等高级字段,应以 contract 与后端校验为准。
|
|
128
|
+
|
|
129
|
+
低频报表失败时优先看 **`chart_results[].diagnostics`**:
|
|
130
|
+
|
|
131
|
+
- **`81002`** 通常会翻译为 `WRONG_METRIC_COUNT_OR_TYPE`,代表指标数量或指标类型不满足当前图表。
|
|
132
|
+
- **`81005`** 通常会翻译为 `CHART_FIELD_ID_REPEAT`,代表某个维度/指标槽位里出现重复 `fieldId`。
|
|
133
|
+
- `diagnostics.next_action` 是下一步修复建议;不要只把裸后端码返回给用户。
|
|
134
|
+
|
|
135
|
+
### 3.3 应用源报表 vs 数据集报表
|
|
136
|
+
|
|
137
|
+
- **应用源 BI 报表**:使用 `builder charts apply` 创建/更新,配置里保持 `dataSourceType=qingflow`。
|
|
138
|
+
- **数据集 BI 报表**:当前 CLI 不创建、不编辑;只能在已有报表基础上,用 `builder associated-resource apply` 关联到应用,传 `report_source: "dataset"`。
|
|
139
|
+
- 不要把 dataset 报表的 `chart_id` 交给 `builder charts apply --patch-file` 更新;工具会拒绝,避免误写应用源配置。
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 3.4 已有报表局部更新:`patch_charts`
|
|
144
|
+
|
|
145
|
+
`patch_charts` 用于已有报表的小参数替换,工具会读当前 base/config、合并 `set/unset`,再按后端要求保存整份配置。
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
[
|
|
149
|
+
{
|
|
150
|
+
"chart_id": "CHART_ID",
|
|
151
|
+
"set": {
|
|
152
|
+
"name": "本月工时总览",
|
|
153
|
+
"visibility": {"mode": "workspace"}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
- patch 项直接用真实定位字段 `chart_id` + `set` / 可选 `unset`,不要写字面量 `selector` key。
|
|
160
|
+
- 改名称、可见性、筛选、单个 config 片段时优先用 `patch_charts`。
|
|
161
|
+
- 新建或提供完整目标配置才用 `upsert_charts`。
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 4. 创建流程(实现摘要)
|
|
166
|
+
|
|
167
|
+
1. **读** 应用表单 **`fields`** + QingBI datasource **`chart_fields`**;报表维度/指标/筛选/查询条件字段以 **`chart_fields`** 为权威,表单字段只用于补充显示名/类型。
|
|
168
|
+
2. **无 `chart_id` 且无名或名未命中**:**`qingbi_report_create`**(临时 **`chartId`** 形如 **`mcp_<hex>`**),再以 **`chartName`/`chartType`** 做 **读回确认**,得到 **最终 `chart_id`**。
|
|
169
|
+
3. **有名唯一命中** 或 **`chart_id` 命中**:必要时 **`qingbi_report_update_base`**(改名、类型、**`visibleAuth`**)。
|
|
170
|
+
4. **新建或 config 有变**:**`qingbi_report_update_config`**(**`_build_public_chart_config_payload`**);特殊 BI 类型会按上文转换后端字段。
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 5. **remove** / **reorder**
|
|
175
|
+
|
|
176
|
+
- **`--remove-chart-ids-file`**:字符串 id 数组 → **`qingbi_report_delete`**。
|
|
177
|
+
- 删除成功后工具会用单个 **`chart_id`** 回读验证是否已不存在;**纯删除不会再读全量报表列表**。若返回 **`readback_status: unavailable`** 或 **`still_exists`**,表示删除请求已发出但回读未确认,**不要盲目重复删除**,可稍后用 **`builder chart get --chart-id …`** 确认。
|
|
178
|
+
- **`--reorder-chart-ids-file`**:期望的 **展示顺序前缀**;实现会 **反转** 后调 **`qingbi_report_reorder`**;验证时要求列表 **`chart_list_source == "sorted"`** 且前缀与请求一致。
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 6. 响应与排障
|
|
183
|
+
|
|
184
|
+
| 字段 | 含义 |
|
|
185
|
+
|------|------|
|
|
186
|
+
| **`chart_results[]`** | 每项 **`status`**: **`created`** / **`updated`** / **`removed`** / **`failed`**。 |
|
|
187
|
+
| **`verification.charts_verified`** | 新建/更新/排序通过报表清单回读验证;删除通过单个 **`chart_id`** 回读验证。 |
|
|
188
|
+
| **`partial_success` / `CHART_APPLY_PARTIAL`** | 部分 **`upsert/remove`** 失败。若同时 `write_executed=true` / `write_may_have_succeeded=true`,先读回报表列表,不要整批重试。 |
|
|
189
|
+
| **`CHART_READBACK_PENDING`** | 变更已提交但列表读回未完成。 |
|
|
190
|
+
| **`CHART_DELETE_READBACK_PENDING`** | 删除请求已完成,但单个 **`chart_id`** 回读未确认已删除。 |
|
|
191
|
+
| **`CHART_UPSERT_BATCH_TOO_LARGE`** | 一次 upsert 图表数超过 8;CLI 写前阻断,`write_executed=false`,按 `details.suggested_batch_payloads[]` 分批执行。 |
|
|
192
|
+
| **`chart_results[].readback_status`** | 删除结果专用:**`deleted`** / **`still_exists`** / **`unavailable`**。只要 **`delete_executed=true`**,**`safe_to_retry_delete=false`**,不要直接重复删除。 |
|
|
193
|
+
|
|
194
|
+
常见问题:**重名**须 **`chart_id`**;**`chart_id` 不存在**;报表字段必须来自 **`app get fields.chart_fields`**,**record schema 可见** 或 **普通表单 fields 可见** 不等于 QingBI 可用;系统字段如 **申请人/申请时间/编号** 只有出现在 **`chart_fields`** 时才可用于报表;字段标题重复时用 **`bi_field_id`** 或 **`field_queId`** 精确指定;**子表等**类型是否可做维度/指标以后端为准。
|
|
195
|
+
|
|
196
|
+
`CHART_APPLY_PARTIAL` 恢复规则:
|
|
197
|
+
|
|
198
|
+
- 先看 `details.failed_chart_names`、`details.failed_delete_chart_ids` 和 `details.readback_first`。
|
|
199
|
+
- 若 `details.readback_first=true`,先 `builder app get --app-key <APP_KEY> charts` 或 `chart get` 确认哪些报表已经存在/已更新。
|
|
200
|
+
- 只重试 `details.suggested_retry_payload` 里的失败项;不要重放原始 `upsert_charts` 全量数组。
|
|
201
|
+
- 如果失败项已经在读回中存在但配置未确认,按失败项名称或 `chart_id` 做一次最小 patch。
|
|
202
|
+
|
|
203
|
+
`CHART_UPSERT_BATCH_TOO_LARGE` 处理规则:
|
|
204
|
+
|
|
205
|
+
- 这是写前阻断,不是后端失败;`write_executed=false`,可以安全按建议重试。
|
|
206
|
+
- 直接复制执行 `details.suggested_batch_payloads[]`,每次只跑一个 payload。
|
|
207
|
+
- 不要改报表名称、不要拆成单个图表反复试、不要重放原始大数组。
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 7. 示例文件(可复制)
|
|
212
|
+
|
|
213
|
+
- **目标图(契约极简)**:[charts_upsert_minimal.example.json](./charts_upsert_minimal.example.json)
|
|
214
|
+
- **柱状(须替换 `field_id`)**:[charts_upsert_bar.example.json](./charts_upsert_bar.example.json)
|
|
215
|
+
- **重排**:[charts_reorder.example.json](./charts_reorder.example.json)
|
|
216
|
+
- **删除**:[charts_remove.example.json](./charts_remove.example.json)
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 8. 本环境实测(`ead8ims5i401`)
|
|
221
|
+
|
|
222
|
+
| 操作 | 载荷要点 | 结果 |
|
|
223
|
+
|------|-----------|------|
|
|
224
|
+
| 新建 **bar** | **`group_by`: [`状态`]**,**`metric`: `sum(金额)`** | **`chart_id`: `mcp_3a35981aff4f4f57`**,`status: created`,**`verified: true`** |
|
|
225
|
+
| **更新** | 同上 id,**`name`** 改为 **`CLI图表探针_柱状_已改名`**,补 **`visibility`** workspace | **`status: updated`**,**`verified: true`** |
|
|
226
|
+
| **reorder** | **`[mcp_3a35981aff4f4f57, mcp_fb104267c5c249ca]`** | **`success`**,**`chart_order_verified: true`** |
|
|
227
|
+
|
|
228
|
+
(环境中另有早期探针 **`mcp_fb104267c5c249ca`(target)**,供门户 **`chart_ref`** 使用。)
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 9. 交叉引用
|
|
233
|
+
|
|
234
|
+
- [SKILL.md](../SKILL.md)
|
|
235
|
+
- [QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md](./QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md)
|
|
236
|
+
- [QINGFLOW_CLI_BUILDER_PORTAL_WORKFLOW.md](./QINGFLOW_CLI_BUILDER_PORTAL_WORKFLOW.md)(**`chart_ref`**)
|
|
237
|
+
- [QINGFLOW_CLI_FIELD_DATA_TYPES.md](./QINGFLOW_CLI_FIELD_DATA_TYPES.md)(成员侧 **`kind`** 与搭建 **`type`** 对照理解业务)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Builder 字段匹配规则:按钮传参与关联视图/报表筛选
|
|
2
|
+
|
|
3
|
+
本文只适用于 **Builder 侧 MatchRule**:
|
|
4
|
+
|
|
5
|
+
- `builder button apply` 的新增数据按钮传参
|
|
6
|
+
- `builder associated-resource apply` 的关联视图 / 关联报表筛选条件
|
|
7
|
+
|
|
8
|
+
它不是 `record_access` 分析筛选 DSL,也不是普通视图 `filters`。
|
|
9
|
+
|
|
10
|
+
统一语义:
|
|
11
|
+
|
|
12
|
+
- 固定筛选用 `field_name + operator + value/values`,例如视图 `filters`、报表 `filters`。
|
|
13
|
+
- 当前记录上下文匹配用 `target_field + operator + source_field/value`,例如关联资源 `match_mappings`、新增数据按钮传参。
|
|
14
|
+
- 不要直接写 `judgeType`、`judgeValues`、`matchRules`;CLI 会按目标协议自动编译。
|
|
15
|
+
- 单选 / 多选 / 布尔这类选项值,入参可写选项文本或 option id;视图 / 按钮 / 工作流路径会编译成 Qingflow 需要的 id + details,QingBI 报表路径会编译成 BI 前端需要的文本 `judgeValue`。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. 默认写法
|
|
20
|
+
|
|
21
|
+
优先使用语义化映射,不手写后端 raw `que_relation` / `match_rules`。
|
|
22
|
+
|
|
23
|
+
### 1.1 新增数据按钮
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
[
|
|
27
|
+
{
|
|
28
|
+
"client_key": "add_worklog",
|
|
29
|
+
"button_text": "快捷添加工时",
|
|
30
|
+
"trigger_action": "addData",
|
|
31
|
+
"trigger_add_data_config": {
|
|
32
|
+
"target_app_key": "WORKLOG_APP",
|
|
33
|
+
"field_mappings": [
|
|
34
|
+
{"source_field": "数据ID", "target_field": "关联员工"},
|
|
35
|
+
{"source_field": "员工名称", "target_field": "员工姓名"}
|
|
36
|
+
],
|
|
37
|
+
"default_values": {
|
|
38
|
+
"状态": "待提交"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`field_mappings` 表示从当前记录动态带值;`default_values` 只表示静态默认值。
|
|
46
|
+
|
|
47
|
+
### 1.2 关联视图 / 报表
|
|
48
|
+
|
|
49
|
+
跨应用关联必须显式传 `target_app_key`。若关联的是当前应用自己的视图或报表,可以省略 `target_app_key`,CLI 会默认使用命令里的 `--app-key`。
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
"client_key": "employee_worklogs",
|
|
55
|
+
"graph_type": "view",
|
|
56
|
+
"target_app_key": "WORKLOG_APP",
|
|
57
|
+
"view_key": "WORKLOG_VIEW",
|
|
58
|
+
"match_mappings": [
|
|
59
|
+
{"target_field": "关联员工", "source_field": "数据ID"},
|
|
60
|
+
{"target_field": "状态", "value": "待提交"}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
动态条件用 `source_field`;静态条件用 `value`。
|
|
67
|
+
|
|
68
|
+
`operator` 推荐使用 `eq` / `neq` / `in` / `contains` / `gte` / `lte` / `is_empty` / `not_empty`;兼容 `equal` / `equals` / `=` / `!=` / `any_of` / `one_of` / `empty` 等别名。`field_name` / `field` 可作为 `target_field` 别名;静态单值可写 `value`,也兼容单元素 `values`。
|
|
69
|
+
|
|
70
|
+
示例:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{"target_field": "客户ID", "operator": "eq", "source_field": "数据ID"}
|
|
74
|
+
{"target_field": "状态", "operator": "eq", "value": "有效"}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 2. 系统字段
|
|
80
|
+
|
|
81
|
+
系统字段可以参与匹配:
|
|
82
|
+
|
|
83
|
+
| 写法 | field_id | 含义 |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `数据ID` / `row_record_id` / `apply_id` / `_id` | `-17` | 当前记录真实 record/apply ID |
|
|
86
|
+
| `编号` / `数据编号` / `record_number` | `0` | 前端可见数据编号,可能是自定义编号 |
|
|
87
|
+
|
|
88
|
+
也可以显式写:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{"source_field": {"field_id": -17}, "target_field": "关联员工"}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
注意:`数据ID` 和 `编号` 不是同一个东西。要把当前记录填入目标引用字段时,用 `数据ID`。
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 3. 类型兼容规则
|
|
99
|
+
|
|
100
|
+
| 目标 / 源字段类型 | 可匹配对象 |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| 引用字段 | 同目标应用的引用字段,或当前源应用记录的 `数据ID(-17)` |
|
|
103
|
+
| `数据ID(-17)` | 指向当前源应用的目标引用字段;也可匹配 ID 兼容的文本/数字字段 |
|
|
104
|
+
| `编号(0)` | 文本、长文本、数字、金额、编号类字段 |
|
|
105
|
+
| 成员字段 | 成员字段 |
|
|
106
|
+
| 部门字段 | 部门字段 |
|
|
107
|
+
| 单选 / 多选 / 布尔 | 选项类字段或静态选项值 |
|
|
108
|
+
| 日期 / 日期时间 | 日期类字段互通 |
|
|
109
|
+
| 文本 / 长文本 / 电话 / 邮箱 | 文本类字段互通 |
|
|
110
|
+
| 数字 / 金额 | 数值类字段互通 |
|
|
111
|
+
|
|
112
|
+
附件、子表、代码块、Q-Linker、地址字段默认不作为匹配字段。
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 4. 常见错误处理
|
|
117
|
+
|
|
118
|
+
| 错误场景 | 下一步 |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| 字段不存在 | 重新 `builder app get --app-key APP_KEY fields` / `builder app get --app-key APP_KEY`,用准确字段标题或 `field_id` |
|
|
121
|
+
| 类型不兼容 | 按上表换兼容的源字段 / 目标字段 |
|
|
122
|
+
| 引用来源不一致 | 目标引用字段指向了别的应用;换成指向当前源应用的引用字段 |
|
|
123
|
+
| 同时传 semantic 与 raw | 同一项里只能二选一:`field_mappings/match_mappings` 或 raw `que_relation/match_rules` |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 5. 关联资源 ID 口径
|
|
128
|
+
|
|
129
|
+
`associated_item_id` 是应用级关联资源池里的 `form_asos_chart.id`,最终口径来自:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
qingflow --json builder app get --app-key APP_KEY
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
或同等 `app_get.associated_resources[].associated_item_id`。
|
|
136
|
+
|
|
137
|
+
它不是 `chart_id`、`chart_key`、`view_key`。但新版 `builder associated-resource apply` 在部分入口可接受 `chart_id` / `chart_key` / `view_key` 作为 selector,并自动解析成后端需要的 `associated_item_id`;写 view config 或排障时仍以读回的 `associated_item_id` 为准。
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Builder 门户创建与变更 SOP:`qingflow builder portal`
|
|
2
|
+
|
|
3
|
+
搭建侧稳定入口:**`qingflow builder portal`**:`list` / `get` / **`apply`** / **`delete`**(与根命令 **`qingflow portal`** 的「成员可读列表/详情」不同,见 **[QINGFLOW_CLI_EXPLORATION_REPORT.md](./QINGFLOW_CLI_EXPLORATION_REPORT.md) §4.6**)。
|
|
4
|
+
|
|
5
|
+
实现要点来自 CLI 打包内的 `builder_facade/models.py`(`PortalApplyRequest`、`PortalSectionPatch`)、`builder_facade/service.py`(`portal_apply` / `portal_delete`)、`cli/commands/builder.py`。已对 **`package_id=2030703`**、应用 **`ead8ims5i401`** **实跑**:**新建**(`--no-publish`)、**`--publish` 更新**(网关 **503** 恢复后已重试成功)、**五类区块可稳定落库**;**`filter`(`type:6`)经 CLI 直传未落库** 见 **§3.4 / §8**。另已对测试包 **`1414907`** 实跑 **`portal delete`**:临时门户 **`etcivtmv5402`** 删除后回读 **`readback_status=deleted`**。
|
|
6
|
+
|
|
7
|
+
> **权限**:**更新**需 **`edit_portal`**;**新建**按后端 `DashCtrl.createDash` 链路只预检目标包 **`add_app`**,不额外要求包 **`edit_app`**。失败时参见主技能与 **ADMIN** 速查。
|
|
8
|
+
|
|
9
|
+
> **契约**:`qingflow --json builder contract --tool-name portal_apply`;删除契约:`qingflow --json builder contract --tool-name portal_delete`
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. 读:`list` → `get`
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
qingflow --json builder portal list > tmp/builder_portal_list.json
|
|
17
|
+
|
|
18
|
+
qingflow --json builder portal get --dash-key "<DASH_KEY>" > tmp/builder_portal_get.json
|
|
19
|
+
qingflow --json builder portal get --dash-key "<DASH_KEY>" --no-being-draft
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- **`list`** 可能带 **`PORTAL_PERMISSION_READ_UNAVAILABLE`**,**`verified: false`** 仍可能有可用 **`items[]`**。
|
|
23
|
+
- **`get`**:**`--dash-key`** 必填;默认 **`--being-draft`** 为草稿。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. 写:`apply` 两种模式(互斥)
|
|
28
|
+
|
|
29
|
+
**不可同时**出现 **`--dash-key`** 与 **`--package-id`**。
|
|
30
|
+
|
|
31
|
+
| 模式 | 必备参数 | 含义 |
|
|
32
|
+
|------|----------|------|
|
|
33
|
+
| **新建** | **`--package-id`** + **`--dash-name`** | **`--sections-file` 须非空**。 |
|
|
34
|
+
| **更新** | **`--dash-key`** | 不要带 **`package_id`**。 |
|
|
35
|
+
|
|
36
|
+
| 参数 | 说明 |
|
|
37
|
+
|------|------|
|
|
38
|
+
| **`--publish` / `--no-publish`** | 默认 **`--publish`**。仅 **`--no-publish`** 时不会调用发布接口;契约说明 **`publish=false` 不宣称线上已变**。 |
|
|
39
|
+
| **`--payload-file`** | 完整门户 JSON 对象;**标准字段写 `dash_name`**。新版 CLI 兼容 **`name -> dash_name`**、单页 **`pages[0].components -> sections`**,但 agent 默认不要依赖兼容别名。 |
|
|
40
|
+
| **`--sections-file`** | JSON **数组**;**全量替换**。省略时仅改基础信息,且 **`hide_copyright` / `dash_global_config` / `config`** 不能单独提交(**`PORTAL_SECTIONS_REQUIRED`**)。 |
|
|
41
|
+
| **`--layout-preset`** | 可选:**`auto` / `dashboard_2col` / `dashboard_3col`**。当区块未显式写 **`position`** 时由工具生成大屏布局。 |
|
|
42
|
+
| **`--visibility-file`** | 与 **`--auth-file`** 不能同时用。 |
|
|
43
|
+
| **`--icon`** / **`--color`** | 新建门户必须显式传合法的非 `template` 图标和颜色;候选用 `qingflow --json builder icon catalog`。编辑已有门户时省略则保留现状。 |
|
|
44
|
+
| **`--hide-copyright`** / **`--dash-global-config-file`** / **`--config-file`** | 见契约;部分键 **依赖与 `sections` 同批提交**。 |
|
|
45
|
+
|
|
46
|
+
**图标规则**:CLI 不按门户名自动猜图标;智能体需要自行选择业务贴合的 `icon + color`。读回结果里的 `icon_config` 可直接用于前端资源卡片展示。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 3. `sections[]`:六类组件与回读 `type`
|
|
51
|
+
|
|
52
|
+
### 3.1 公共键
|
|
53
|
+
|
|
54
|
+
- **`title`**(必填)、**`source_type`**(必填,小写)、可选 **`position`**(**`pc`/`mobile`** 各 **`x,y,cols,rows`**;省略则由**实现自动排布**)。
|
|
55
|
+
- **`config`**、**`dash_style_config`**:按类型 Optional。默认只写 snake_case 规范键。
|
|
56
|
+
|
|
57
|
+
### 3.1.0 Payload 字段口径
|
|
58
|
+
|
|
59
|
+
推荐完整 payload 直接使用 CLI 标准键:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"dash_name": "产品研发数据大屏",
|
|
64
|
+
"package_id": 1414909,
|
|
65
|
+
"layout_preset": "dashboard_2col",
|
|
66
|
+
"pages": [
|
|
67
|
+
{
|
|
68
|
+
"title": "研发总览",
|
|
69
|
+
"components": [
|
|
70
|
+
{
|
|
71
|
+
"title": "部门分布",
|
|
72
|
+
"source_type": "chart",
|
|
73
|
+
"chart_ref": {"app_key": "APP_KEY", "chart_id": "CHART_ID"}
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`name` 只是兼容别名;如果遇到旧版 CLI 报 **`name Extra inputs are not permitted`**,不要反复重试,改成 **`dash_name`** 或升级 CLI。
|
|
82
|
+
|
|
83
|
+
### 3.1.1 布局硬规则:PC 24 栅格,mobile 6 栅格
|
|
84
|
+
|
|
85
|
+
**门户 PC 端不是 12 栅格,而是 24 栅格。**如果把两列写成 **`x=0/6, cols=6`**,所有组件只会占左半屏,工具会返回 **`PORTAL_LAYOUT_HALF_WIDTH`**。
|
|
86
|
+
|
|
87
|
+
推荐:
|
|
88
|
+
|
|
89
|
+
| 场景 | PC 写法 |
|
|
90
|
+
|------|---------|
|
|
91
|
+
| 不确定布局 | **省略 `position`**,或传 **`--layout-preset auto`** |
|
|
92
|
+
| 两列可视化图表 | **`x=0/12, cols=12`**,图表 **`rows >= 7`** |
|
|
93
|
+
| 三列可视化图表 | **`x=0/8/16, cols=8`**,图表 **`rows >= 7`** |
|
|
94
|
+
| 四个指标卡 | **`x=0/6/12/18, cols=6, rows=5`** |
|
|
95
|
+
| 具体数据视图 / 明细表 | 优先 **`cols=12`** 或 **`cols=24`**,视图 **`rows >= 11`** |
|
|
96
|
+
|
|
97
|
+
mobile 写法固定按 **6 栅格**:通常 **`x=0, cols=6`**。如果只写了 PC position,CLI 会自动补 mobile position,并返回 **`PORTAL_MOBILE_POSITION_MISSING`** 提醒。
|
|
98
|
+
|
|
99
|
+
图表卡片过小时会返回 **`PORTAL_CHART_CARD_TOO_SMALL`**;指标卡按 **`pc.cols >= 6, pc.rows >= 5`** 校验,普通可视化图表按 **`pc.cols >= 8, pc.rows >= 7`** 校验。指标区图表建议写 `role: "metric"`;此时必须引用 `target` / `indicator` 图表,否则返回 **`PORTAL_METRIC_SECTION_CHART_TYPE_MISMATCH`**,应先用 `app_charts_apply` 创建缺失指标卡再组门户。标准工作台数量也会进入 `layout_diagnostics.standard_template_counts`:指标卡推荐 4-6 个、BI 图表 2-3 个、业务视图 1-2 个,超出或不足会返回 `PORTAL_STANDARD_*_COUNT_OUT_OF_RANGE`。
|
|
100
|
+
|
|
101
|
+
### 3.1.2 推荐门户模板:业务工作台
|
|
102
|
+
|
|
103
|
+
默认按 **业务入口 → 核心指标 → BI 可视化 → 业务视图** 搭建。门户首屏应直接呈现可用工作台,不要做营销页、说明页或大面积装饰区。
|
|
104
|
+
|
|
105
|
+
| 区域 | 推荐组件 | PC 布局 | 要点 |
|
|
106
|
+
|------|----------|---------|------|
|
|
107
|
+
| 顶部业务入口 | **`grid`** + 可选 **待办 `task`** | `grid x=0,y=0,cols=12,rows=4`;待办 `x=12,y=0,cols=12,rows=4` | `grid` 放 2-6 个核心业务入口;待办用于当前用户任务概览。当前公开 `portal apply --sections-file` 暂未支持 `source_type=task`,不要伪造;见下方边界说明。 |
|
|
108
|
+
| 核心指标 | **`chart`** 指标卡 + `role: "metric"` | 4 张:`x=0/6/12/18,y=4,cols=6,rows=5` | 指标卡推荐高度 **5**。24 栅格下单卡最小 `cols=6`,所以一行 4 张最稳;如果要 5 个指标,拆成两行。 |
|
|
109
|
+
| BI 可视化 | **`chart`** 图表 | 3 张:`x=0/8/16,y=9,cols=8,rows=7`;或 2 张:`x=0/12,cols=12,rows=7` | 可视化图表推荐高度 **7**,一行 2-3 个,1-2 行。 |
|
|
110
|
+
| 业务数据视图 | **`view`** | `x=0/12,y=16,cols=12,rows=11`;或单表 `cols=24,rows=11` | 数据视图推荐高度 **11**,一行 1-2 个,1-2 行。只挂业务视图,不要创建或引用默认的 **全部数据 / 我的数据** 当主门户视图。 |
|
|
111
|
+
|
|
112
|
+
mobile 固定按 **6 栅格** 从上到下堆叠:通常所有组件 `x=0, cols=6`,`y` 按 PC 顺序递增。若顶部同时有 `grid + task`,mobile 建议先业务入口 `y=0,rows=4`,再待办 `y=4,rows=4`,核心指标从 `y=8` 开始;若当前公开 CLI 只能写 `grid`,核心指标可从 `y=4` 开始。
|
|
113
|
+
|
|
114
|
+
**当前工具边界**:
|
|
115
|
+
|
|
116
|
+
- 公开 `sections-file` 稳定支持:**`grid` / `chart` / `view` / `text` / `link`**;`filter` 仍按 **§3.4** 的 raw `filterConfig` 边界处理,不作为主路径。
|
|
117
|
+
- **待办 `task` / 常用 `favorite`** 是前端/后端 raw 组件形状,不在当前公开 `source_type` 合约里。智能体不要在 `sections-file` 中写 `source_type: "task"`;只有工具后续显式支持 `task`,或维护者走 raw 门户写入链路时,才使用待办槽位。
|
|
118
|
+
- 推荐门户的可直接 apply 示例见 **[portal_sections_standard_workbench.example.json](./portal_sections_standard_workbench.example.json)**。该示例使用当前公开 CLI 可稳定写入的组件,顶部先用一个业务入口 `grid` 占满 24 栅格;如果工具已支持待办组件,再把顶部拆成 `grid cols=12 + task cols=12`。
|
|
119
|
+
- `grid` 必须写 **`config.items[]`**;只写 `gridTitle` / `beingShowTitle` 会生成空入口容器,工具会返回 **`PORTAL_GRID_ITEMS_EMPTY`**。
|
|
120
|
+
|
|
121
|
+
**待办组件 raw 形状参考**(仅用于工具实现对齐,当前不要作为 `--sections-file` 输入):
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"type": 8,
|
|
126
|
+
"position": {
|
|
127
|
+
"pc": {"x": 12, "y": 0, "cols": 12, "rows": 4},
|
|
128
|
+
"mobile": {"x": 0, "y": 4, "cols": 6, "rows": 4}
|
|
129
|
+
},
|
|
130
|
+
"taskConfig": {
|
|
131
|
+
"beingShowTitle": true,
|
|
132
|
+
"componentTaskTitle": "待办",
|
|
133
|
+
"beingShowHint": true,
|
|
134
|
+
"componentTaskHint": "及时处理待办,可以有效提升流程效率",
|
|
135
|
+
"dashTaskConfigList": [
|
|
136
|
+
{"type": 1, "title": "all.taskTodo", "beingCheck": true, "ordinal": 0},
|
|
137
|
+
{"type": 2, "title": "all.taskTimeout", "beingCheck": true, "ordinal": 1},
|
|
138
|
+
{"type": 3, "title": "all.taskUpcomingTimeout", "beingCheck": true, "ordinal": 2},
|
|
139
|
+
{"type": 4, "title": "all.taskRemind", "beingCheck": true, "ordinal": 3}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 3.2 `source_type` ↔ 回读 `components[].type`(搭建侧)
|
|
146
|
+
|
|
147
|
+
| `source_type` | 回读 `type`(数字) | 搭建侧含义 |
|
|
148
|
+
|---------------|---------------------|------------|
|
|
149
|
+
| **`chart`** | **9** | QingBI 图表块 |
|
|
150
|
+
| **`view`** | **10** | 应用视图块 |
|
|
151
|
+
| **`grid`** | **2** | 九宫格 |
|
|
152
|
+
| **`filter`** | **6** | 筛选条 |
|
|
153
|
+
| **`text`** | **5** | 富文本说明 |
|
|
154
|
+
| **`link`** | **4** | 外链 |
|
|
155
|
+
|
|
156
|
+
CLI 校验(`PortalSectionPatch`):**chart** 须 **`chart_ref`**;**view** 须 **`view_ref`**;**text** 须 **`text`**;**link** 须 **`url`**。**grid** / **filter** 无额外 ref,**`config` 形状由后端接受为准**。
|
|
157
|
+
|
|
158
|
+
### 3.3 **`chart`**:几乎总须 **`builder charts apply` 先建报表**
|
|
159
|
+
|
|
160
|
+
- `portal` 只做 **`chart_ref` 解析**(`app_key` + **`chart_id`** 优先,否则 **唯一 `chart_name`**)。
|
|
161
|
+
- 若 **`builder app get charts`** 为空,先 **`builder charts apply --app-key … --upsert-file`** 创建(契约 **minimal_example** 如 **`target` + `indicator_field_ids: []`**),从响应 **`chart_results[].chart_id`** 取 id 再写 **`chart_ref`**.
|
|
162
|
+
|
|
163
|
+
### 3.4 **`filter`**:`config` **整包**即接口里的 **`filterConfig`**
|
|
164
|
+
|
|
165
|
+
实现:组件为 **`{"type": 6, "filterConfig": deepcopy(section.config)}`**。
|
|
166
|
+
|
|
167
|
+
- **理论上**与 solution 编译器一致:外层 **`{"filterConfig": [ … ], "graphList": [ … ]}`**;**`graphList`** 常含 **`graphType`**(如 **`CHART`**)、**`graphKey`** 或 **`graphRef`(`entity_id` / `chart_id`)** 等。
|
|
168
|
+
- **本环境 CLI 直写实测(多次 `--publish`)**:在已验证 **chart / view / grid / text / link** 均可落库的前提下,**`source_type: filter` 始终未出现在 `draft_result.components` 中**;尝试过:**空数组**、**仅 `graphList` + QingBI `chart_id`**、**`graphKey` 为门户 `dashChartId`**、**`chart` 排在 **`filter` 前**、**仅 2 块(chart+filter)** 等,回读仍 **只有 chart(`count: 1`)** 或 **五类缺 `type: 6`**。
|
|
169
|
+
**结论**:当前宜 **在搭建界面创建筛选条**,再 **`builder portal get` 反抓** 原始 `filterConfig` 形状;或向后端确认 **POST `/dash/{dashKey}`** 对 **`type: 6`** 的必填字段。**自动化不要默认认为 `filter` 已写入。**
|
|
170
|
+
- portal `filter` 组件仍按 raw `filterConfig` 处理,不纳入视图 / 报表 / 关联资源的统一筛选 DSL 主链路。
|
|
171
|
+
|
|
172
|
+
### 3.5 **`grid` / `text` / `link` / `view`**
|
|
173
|
+
|
|
174
|
+
- **grid**:**`config`** 并入 **`gridConfig`**;业务入口必须写 **`config.items[]`**。应用入口项推荐 `{ "type": 1, "jumpMode": 1, "linkAppKey": "APP_KEY", "linkFormType": 1, "title": "入口名" }`。空 `config` 或空 `items` 只会生成空入口容器,并触发 **`PORTAL_GRID_ITEMS_EMPTY`**。
|
|
175
|
+
- **text** / **link**:**`text`** / **`url`** 必填。
|
|
176
|
+
- **view**:**`view_ref`**;**`view_key`** 来自 **`builder app get views`**。
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 4. 前置数据
|
|
181
|
+
|
|
182
|
+
| 目的 | 命令 |
|
|
183
|
+
|------|------|
|
|
184
|
+
| **`package_id`** | **`builder app resolve --app-key …`** → **`package_ids`** |
|
|
185
|
+
| **`view_key`** | **`builder app get --app-key … views`** |
|
|
186
|
+
| **`chart_id`** | **`builder app get charts`** 或 **`charts apply` 创建** |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 5. 新建最小例(`--no-publish`)
|
|
191
|
+
|
|
192
|
+
见上文 **§2** 与 **`visibility`** 最小对象;**`sections`** 可先用 **单块 `view`**。成功后拿 **`dash_key`** 再 **更新 / 发布**。
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 6. 更新与替换语义
|
|
197
|
+
|
|
198
|
+
- **`--dash-key`** + **`--sections-file`**:**列表即全量**;没写进去的区块会被拿掉。
|
|
199
|
+
- 仅改 **可见性 / 图标 / 分组**:**不传 `--sections-file`**,且不要单独带 **§2** 所列「仅在有 sections 时允许」的键。
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 7. 删除:`delete`
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
qingflow --json builder portal delete --dash-key "<DASH_KEY>" > tmp/builder_portal_delete.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
- **只按 `dash_key` 删除一个门户**;先用 `builder portal list/get` 确认目标,不要按名称猜。
|
|
210
|
+
- 返回成功时重点看:**`delete_executed`**、**`readback_status`**、**`safe_to_retry_delete`**、`summary.removed`。
|
|
211
|
+
- **`delete_executed=true` + `readback_status=deleted`**:删除已执行且回读确认不存在。
|
|
212
|
+
- **`delete_executed=true` + `readback_status=unavailable|still_exists`**:DELETE 已发出,但回读不可确认或短时间仍存在;**不要盲目重复删除**,稍后用 `builder portal get/list` 确认。
|
|
213
|
+
- DELETE 本身失败时才按 `status=failed` / `error_code` 处理。
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 8. **发布**(`--publish`)
|
|
218
|
+
|
|
219
|
+
- **默认会发布**:未显式 **`--no-publish`** 即 **`publish: true`**;公开入口仍是 **`portal_apply`**,发布动作由工具内部执行并回读 **`being_draft=false`**。
|
|
220
|
+
- **已发布线索**:成功路径上 **`published: true`**;**`live_result.publishStatus`** 常见 **`2`** 表示已发布(以你环境枚举为准)。
|
|
221
|
+
- **`partial_success` + `PORTAL_READBACK_PENDING`**:草稿/线上 **组件数量或元数据** 与「本次期望」不一致时会出现;**`PORTAL_*_VERIFICATION_INCOMPLETE`** 警告。应 **`builder portal get --dash-key …`**(草稿与 **`--no-being-draft` 线上**)**肉眼核对**区块是否齐全,而不是仅信 **`verified: true`**。
|
|
222
|
+
- **网关 503**:**与 CLI 无关**;环境恢复后重试 **`portal get` / `portal apply`**。(本轮在网关恢复后 **`portal apply` 已成功**。)
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 9. 本环境实测摘要
|
|
227
|
+
|
|
228
|
+
| 步骤 | 命令要点 | 结果 |
|
|
229
|
+
|------|-----------|------|
|
|
230
|
+
| 新建门户 | `--package-id 2030703`、`--dash-name "CLI门户探针_可删"`、`--no-publish`、单 **view** | **`dash_key`: `ecdcell64s02`** |
|
|
231
|
+
| 补报表 | **`builder charts apply`**,`name: 门户探针_目标图`,**`target`** | **`chart_id`: `mcp_fb104267c5c249ca`** |
|
|
232
|
+
| 503 后重试 | **`--dash-key ecdcell64s02`、`--publish`** + 含 **filter** 的六类 **`sections-file`** | **`published: true`**;**`filter` 仍不落库** → **`partial_success`**,**`components expected 6, got 5`**(与 **§3.4** 一致) |
|
|
233
|
+
| **filter 专项** | 仅 **chart + filter** 两块的多种 **`graphList`/`graphRef`/`dashChartId`/`filterGroupConfig`** 组合 | **回读恒为 1 块(仅 `type: 9`)** |
|
|
234
|
+
| **稳定可复现** | **`--publish`** + **[portal_sections_five_types.example.json](./portal_sections_five_types.example.json)**(**grid / text / link / view / chart**) | **`status: success`**,**`types: [2,4,5,9,10]`**,**`published: true`** |
|
|
235
|
+
| 删除门户 | `builder portal delete --dash-key etcivtmv5402` | **`status: success`**,**`delete_executed: true`**,**`readback_status: deleted`**,**`summary.removed: 1`** |
|
|
236
|
+
|
|
237
|
+
**推荐工作台模板示例**:[portal_sections_standard_workbench.example.json](./portal_sections_standard_workbench.example.json)
|
|
238
|
+
|
|
239
|
+
**含 `filter` 的六类示例(`filter` 是否落库视环境/后端而定)**:[portal_sections_all_types.example.json](./portal_sections_all_types.example.json)
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 10. 排障
|
|
244
|
+
|
|
245
|
+
| 现象 | 处理 |
|
|
246
|
+
|------|------|
|
|
247
|
+
| `portal apply accepts exactly one selector mode` | **`dash-key`** vs **`package-id`** 二选一。 |
|
|
248
|
+
| `PORTAL_READBACK_PENDING` / **`components expected N, got M`** | **`portal get`** 数组件;若多写了 **`filter`** 而回读少一块,见 **§3.4**(**CLI 写 filter 可能整体不生效**);也可能是 **异步回读**,可再 **`get`** 一次。 |
|
|
249
|
+
| **`published: true` 但 `verified: false`** | 读 **§7**;用 **`get` 草稿+线上**对照。 |
|
|
250
|
+
| **503** | 网关/运维;稍后重试。 |
|
|
251
|
+
| 缺 **chart** | **[QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md](./QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md)**:`builder charts apply`;或换有报表的应用。 |
|
|
252
|
+
| **VISIBILITY_CONFLICT** | 只用 **`--visibility-file`**。 |
|
|
253
|
+
| `delete_executed=true` 但 `readback_status=unavailable|still_exists` | DELETE 已发出,回读未确认;不要重复删除,稍后 `builder portal get/list` 复核。 |
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 11. 交叉引用
|
|
258
|
+
|
|
259
|
+
- [SKILL.md](../SKILL.md)
|
|
260
|
+
- [QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md](./QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md)
|
|
261
|
+
- [QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md](./QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md)
|
|
262
|
+
- [QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md](./QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md)
|
|
263
|
+
- [QINGFLOW_CLI_EXPLORATION_REPORT.md](./QINGFLOW_CLI_EXPLORATION_REPORT.md)
|