@qingflow-tech/qingflow-cli 1.1.50-beta.2 → 1.1.50-beta.4

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 (37) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/pyproject.toml +7 -2
  4. package/skills/qingflow-cli/SKILL.md +74 -0
  5. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md +3 -9
  6. package/skills/qingflow-cli/reference/builder/20-build-complete-system.md +1 -0
  7. package/skills/qingflow-cli/reference/builder/50-views.md +180 -191
  8. package/skills/qingflow-cli/reference/builder/README.md +1 -1
  9. package/skills/qingflow-cli/reference/builder/reference/app-delivery-sop.md +3 -3
  10. package/skills/qingflow-cli/reference/examples/README.md +1 -1
  11. package/skills/qingflow-cli/reference/examples/views/views_apply_v1alpha1.example.json +14 -0
  12. package/skills/qingflow-cli/reference/examples/views/views_upsert_table_minimal.example.json +30 -36
  13. package/src/qingflow_mcp/builder_facade/models.py +227 -17
  14. package/src/qingflow_mcp/builder_facade/schemas/views/manifest.json +42 -0
  15. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/complete.json +1245 -0
  16. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/button-config.json +53 -0
  17. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/data-permission.json +60 -0
  18. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/display.json +73 -0
  19. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/operation-permission.json +48 -0
  20. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/query-condition.json +47 -0
  21. package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/summary.json +319 -0
  22. package/src/qingflow_mcp/builder_facade/service.py +1460 -410
  23. package/src/qingflow_mcp/builder_facade/views_extract.py +592 -0
  24. package/src/qingflow_mcp/builder_facade/views_schema.py +400 -0
  25. package/src/qingflow_mcp/cli/commands/builder.py +72 -53
  26. package/src/qingflow_mcp/public_surface.py +3 -0
  27. package/src/qingflow_mcp/response_trim.py +11 -2
  28. package/src/qingflow_mcp/server_app_builder.py +32 -8
  29. package/src/qingflow_mcp/solution/compiler/view_compiler.py +2 -1
  30. package/src/qingflow_mcp/solution/executor.py +96 -8
  31. package/src/qingflow_mcp/solution/spec_models.py +1 -0
  32. package/src/qingflow_mcp/tools/ai_builder_tools.py +211 -393
  33. package/src/qingflow_mcp/tools/solution_tools.py +2 -0
  34. package/src/qingflow_mcp/tools/view_tools.py +0 -6
  35. package/src/qingflow_mcp/tools/view_writer.py +44 -0
  36. package/skills/qingflow-cli/reference/examples/views/views_batch_full.example.json +0 -159
  37. package/skills/qingflow-cli/reference/views_upsert_table_minimal.example.json +0 -42
@@ -1,38 +1,53 @@
1
1
  # Builder Views
2
2
 
3
- Read this when the task is about table/card/board/gantt views, fixed filters, query panels, view sorting, associated report/view display on a view, or repairing existing views.
3
+ Read this when the task is about table/card/board/gantt/hierarchy/calendar views, fixed filters, query panels, view sorting, view data permissions, associated report/view display on a view, or repairing existing views.
4
4
 
5
5
  ## Scope
6
6
 
7
- Responsible for: `builder views apply --views-file`, top-level `views[]`, `operation`, `columns`, `filters`, `query_conditions`, `action_buttons`, and view readback.
7
+ Responsible for: `builder views apply --app-key APP_KEY --view-file PATH` (the **only** creation entry), one view declaration, `columns`, `filters`, `query_conditions`, `action_buttons`, and view readback.
8
8
 
9
9
  Not responsible for: creating associated report resources or maintaining custom button bodies outside the view design. New business views must include `query_conditions`; ordinary business shortcut buttons are required and are declared only through `action_buttons` on the target view.
10
10
 
11
11
  ## Main chain
12
12
 
13
13
  ```text
14
- app get -> app get fields/views -> views apply with required query_conditions and list/detail action_buttons -> app get/views readback
14
+ app get -> app get fields/views -> views schema -> prepare one view -> views validate -> views apply -> app get/views readback
15
15
  ```
16
16
 
17
+ ## 版本与 schema(views v1alpha1)
18
+
19
+ 视图声明是**版本化契约**(`apiVersion: builder.qingflow.com/v1alpha1`)。`builder views apply` 是视图创建的**唯一入口**(旧命令式 `view_create` 已删除;不要再寻找或使用任何“直接创建视图”的命令/工具)。
20
+
21
+ - **两级 schema**:**summary**(最简版:类型/名称/数据展示内容 + `data_permission` 数据权限形状)与 **complete**(完整版:visibility 可见性授权、`filters`、`sort`、`query_conditions`、`action_buttons`/`buttons`、`associated_resources`、`card`/`gantt`/`hierarchy`/`calendar` 类型专属配置、`display`/`record`/`share`)。字段级定义逐字段带 `x-backend` 后端映射。
22
+ - **读 schema**:`qingflow --json builder views schema` 默认返回 `v1alpha1/summary.json`;需要完整可写配置时显式传 `--schema-kind complete`。MCP 对应 `app_views_schema`。
23
+ - **Schema-first 写入**:先用 `builder views schema --schema-version VERSION --schema-kind complete` 读取完整 schema;将相同版本显式传给 `validate --schema-version VERSION` 和 `apply --schema-version VERSION`。`validate` 也可从声明信封读取 `schema_version`,但推荐显式传版本;apply 的版本校验必须用 `--schema-version`。`validate` 接受一个直接视图声明对象,不接受 `upsert_view` 包装或批量 envelope。
24
+ - **说明字段**:视图 Schema 使用语义化的 `*Description` 自定义 key(如 `dataPermissionDescription`)承载说明,加载和引用展开时原样保留;读取说明的工具应识别这些 key。标准校验器忽略这些自定义字段,仍按 `type`、`enum`、`required` 等关键字校验;`default` 是标准注解,不会自动填值。`*Description` 不是提交视图声明时的业务字段。
25
+ - **离线校验**:`qingflow --json builder views validate --file PATH`(`-` 支持 stdin),不访问后端;返回 `ok`/`issues[]`(带 JSON pointer path)。
26
+ - **读 canonical 声明**:`qingflow --json builder views get --app-key APP --schema-version VERSION --schema-kind summary`,返回指定版本的 summary 声明数组(字段名反解);完整可写配置用 `--schema-kind complete` 并检查 `config_read_errors[].gaps`。
27
+ - **完整声明的提取边界**:`views get --schema-kind complete` 优先读取 `buttonConfigVO` 中的完整按钮绑定。公式过滤、无法解析的过滤规则或按钮 ID 会使该视图返回 `VIEW_NOT_EXTRACTABLE`(见 `details.config_read_errors[].gaps`),不会生成删减后的可写声明。修改这类视图的其他属性应使用局部 patch。更新现有视图时,已配置的系统字段原样保留,不补默认值、不重算序号;读接口生成的未配置占位对象不会写回,不会因此新增系统字段配置。
28
+ - **版本协商**:apply 显式传 `--schema-version v1alpha1` 时启用版本化校验:非法声明返回 `INVALID_SPEC` 且**不写**;响应信封回显 `schemaVersion`。apply 不传时行为与旧版一致(别名宽容,零破坏)。
29
+ - **公开视图类型**:summary 与 complete 均支持 `table`、`card`、`board`、`gantt`、`hierarchy`、`calendar`。层级视图须提供 `hierarchy: {title_que_id, children_que_id}`;日历视图须提供 `calendar: {title_que_id, date_que_id}`,可选 `color_que_id`。日历 `date_que_id` 可引用表单日期字段,也可用系统字段 `2`(申请时间)或 `3`(更新时间)。
30
+ - **complete 档配置速览**:`data_permission`(`{type: config|custom, scope: all|oneself|dept|subordinate|custom}`;`scope=custom` 的规则明细写 `filters`);`sort`(`[{que_id, ascending}]`,空数组=恢复默认排序);`hierarchy`(可选 `root_filter`);`card`/`gantt`/`calendar`/`display`/`record`/`share` 配置组。
31
+
17
32
  ## Update existing views
18
33
 
19
- - Prefer `views[].operation="patch"` for small changes to an existing view.
34
+ - Prefer `--patch-views-file` for small changes to an existing view.
20
35
  - Use raw `view_key` from `app_get.views[].view_key`; do not use record-data `custom:<view_key>` prefixes.
21
- - Do not send a partial `upsert` object to update a complex existing view; use `operation="patch"` with `set`.
36
+ - Do not send a partial `--view-file` object to update a complex existing view; use `--patch-views-file` with `set`.
22
37
  - Verify filters, query conditions, and associated resources separately before reporting success.
23
38
 
24
39
  ## Detailed contract notes
25
40
 
26
- 稳定命令:**`qingflow builder views apply --views-file`**(别名 **`qingflow build views apply`**)。编写前已结合 **builder 契约**与实现要点整理;**标准 `views[]` 文件**见 **[views_upsert_table_minimal.example.json](../examples/views/views_upsert_table_minimal.example.json)**(与门户/报表 **`.example.json`** 同风格,已包含必需的查询面板、列表快捷按钮和详情快捷按钮)。
41
+ 稳定命令:**`qingflow builder views apply --app-key APP_KEY --view-file PATH`**(别名 **`qingflow build views apply`**)。`--view-file` 是一个直接的 JSON 对象,只声明一个新建或完整更新的视图。
27
42
 
28
43
  > **权限**:视图**新建**走后端 `createViewgraphConfig`,需要同时满足 **视图管理 / ViewManagementAuth**(`beingViewManageStatus`)和 **数据管理 / DataManageAuth**;视图**更新/删除**只走 **ViewManagementAuth**。未开启高级应用权限时 `beingViewManageStatus` 等价回落到 **DataManageAuth**。失败时常见 **40002 / 40161 / 编辑锁**,参见主技能与 **ADMIN** 速查。
29
44
 
30
- > **默认系统视图**:`全部数据`、`我的数据`、`我发起的`、`待办`、`已办`、`抄送` 等由轻流自带,**不要新建同名业务视图**。新建视图必须用业务名,例如 `项目台账视图`、`客户跟进视图`、`逾期任务看板`。如果确实要调整默认系统视图,只能从 `app get views` 取已存在的 raw **`view_key`** 后用 `views[].operation="patch"` 更新。
45
+ > **默认系统视图**:`全部数据`、`我的数据`、`我发起的`、`待办`、`已办`、`抄送` 等由轻流自带,**不要新建同名业务视图**。新建视图必须用业务名,例如 `项目台账视图`、`客户跟进视图`、`逾期任务看板`。如果确实要调整默认系统视图,只能从 `app get views` 取已存在的 raw **`view_key`** 后通过 `--patch-views-file` 更新。
31
46
 
32
47
  > **契约**(权威键名、枚举、`execution_notes`、示例):
33
48
  > `qingflow --json builder contract --tool-name app_views_apply`
34
49
  > (`--tool-name` 为契约索引,用于拉取 **`allowed_keys` / 别名 / 示例**。)
35
- > 契约示例若带 `"profile"`,不要复制到 `--views-file`;CLI 指定 profile 用根级 `qingflow --profile …`。
50
+ > 契约示例若带 `"profile"` 或 `"app_key"`,不要复制到 `--view-file`;CLI 分别用根级 `qingflow --profile …` 和 `--app-key` 指定。
36
51
 
37
52
  ---
38
53
 
@@ -42,10 +57,11 @@ app get -> app get fields/views -> views apply with required query_conditions an
42
57
  |------|------|-----|
43
58
  | ① 读应用地图 | 先看 compact views/charts/buttons/associated resources | `qingflow --json builder app get --app-key <APP_KEY>` |
44
59
  | ② 读字段/视图 | 确认 **`columns`** / `query_conditions.rows` 可用字段、核对 **`view_key`** | `qingflow --json builder app get --app-key <APP_KEY> fields` / `qingflow --json builder app get --app-key <APP_KEY> views` |
45
- | ③ 准备补丁 JSON | 写入一个 **`{"views":[...]}`** 文件,每个 view item 自带 `operation` 和 `app_key` | — |
46
- | ④ 应用视图补丁 | 执行 apply | `qingflow builder views apply …`(写入命令自动 JSON,默认直接 stdout;需要留档时用 `tee`) |
47
- | ⑤ 配置查询面板和快捷按钮 | 新建业务视图必须写 `query_conditions` 和 `action_buttons`,按钮同时覆盖 `list` 和 `detail` 位置 | `builder views apply` |
48
- | ⑥ 需要上线时 | 发布侧校验 | `qingflow builder publish verify --app-key …` |
60
+ | ③ 读取 schema | 固定版本;按需求读取 summary 或 complete | `qingflow --json builder views schema --schema-version v1alpha1 --schema-kind complete` |
61
+ | ④ 准备并校验声明 | 新建或完整更新写一个视图对象;先离线校验;局部修改写单项 patch | `qingflow --json builder views validate --file PATH --schema-version v1alpha1` |
62
+ | ⑤ 应用视图操作 | 将同一版本传给 apply;一次只提交一个视图操作 | `qingflow builder views apply --app-key … --view-file PATH --schema-version v1alpha1` |
63
+ | ⑥ 配置查询面板和快捷按钮 | 新建业务视图必须写 `query_conditions` 和 `action_buttons`,按钮同时覆盖 `list` 和 `detail` 位置 | `builder views apply` |
64
+ | ⑦ 需要上线时 | 发布侧校验 | `qingflow builder publish verify --app-key …` |
49
65
 
50
66
  **说明**:`views apply` 的 **`--publish`** 对应契约里的 **`publish`**;新建业务视图必须包含 `query_conditions` 和 `action_buttons` 并使用 `publish=true`,因为底层按钮写入会自动发布。只有删除、纯维护补丁、或用户明确要求的只读/归档视图,才允许不带按钮;只读/归档视图仍应配置 `query_conditions`。
51
67
 
@@ -55,14 +71,17 @@ app get -> app get fields/views -> views apply with required query_conditions an
55
71
 
56
72
  ```bash
57
73
  qingflow builder views apply \
58
- --views-file PATH \
74
+ --app-key APP_KEY \
75
+ --view-file PATH \
59
76
  [--publish | --no-publish]
60
77
  ```
61
78
 
62
- - **`--views-file`**:推荐唯一主入口。文件为 **JSON 对象**,形如 `{"views":[...]}`;同一批可混合创建、局部修改、删除,可混合同 app / 跨 app 视图。
63
- - 每个 `views[]` 项必须写 **`app_key`**;`operation` 为 **`upsert`** / **`patch`** / **`remove`**。
64
- - CLI 内部按 view job 并发写入,上限 20,结果按输入顺序返回。
65
- - 兼容旧入口 **`--app-key + --upsert-views-file / --patch-views-file / --remove-views-file`**,但不作为智能体主写法。
79
+ - **`--view-file`**:单个 JSON 对象,用于新建或完整更新一个视图;命令每次只接受一个。
80
+ - **`--patch-views-file`**:JSON 数组,用于已有视图的局部更新;每次最多传一项,包含 `view_key` 或唯一 `name`,以及 `set`/`unset`。
81
+ - **`--remove-views-file`**:JSON 数组,用于删除一个视图;每次最多传一个 raw `view_key` 或唯一名称。
82
+ - 每次调用只能选择一种写入模式:`--view-file`、`--patch-views-file`、`--remove-views-file` 三者不能混用;每次只处理一个应用中的一个视图操作。
83
+ - **不支持批量创建**:不要传 `upsert_views`、`views`、`apps` 等批量声明,也不要在 patch/remove 文件中放多项;多个视图须逐个调用 `builder views apply`,每次单独读回确认。
84
+ - **`--app-key`**:每次视图写入必须指定一个应用;CLI 不提供跨应用或同次多视图写入。
66
85
  - 输出默认直接给 stdout,前端可直接读取;需要留档时用 `qingflow builder views apply … | tee tmp/builder_views_apply.json`。
67
86
 
68
87
  ---
@@ -71,10 +90,10 @@ qingflow builder views apply \
71
90
 
72
91
  | 文件 | 用途 |
73
92
  |------|------|
74
- | [views_upsert_table_minimal.example.json](../examples/views/views_upsert_table_minimal.example.json) | **新建 table 视图**标准 **`views[]` 文件**:`operation` + `app_key` + `name` + `type` + **`columns`** + 必需的 `query_conditions` + 必需的 `action_buttons`(含 `list` 与 `detail`) |
75
- | [views_batch_full.example.json](../examples/views/views_batch_full.example.json) | 批量能力示例:同批 `upsert` / `patch` / `remove`,table / board / gantt,固定筛选、查询面板、视图内按钮和可见性 |
93
+ | [views_upsert_table_minimal.example.json](../examples/views/views_upsert_table_minimal.example.json) | 单视图表格示例,可直接作为 `--view-file` |
94
+ | [views_apply_v1alpha1.example.json](../examples/views/views_apply_v1alpha1.example.json) | 版本化单视图字段示例;作为 `--view-file` 使用时加 `--schema-version v1alpha1` |
76
95
 
77
- 复制到具体应用前务必替换文件内 **`app_key`** 和 **`columns`**;**`name`** 重名时会更新已有同名视图而非新建(见 **§4**)。
96
+ 复制到具体应用前替换 **`columns`**;应用由命令的 **`--app-key`** 指定。**`name`** 重名时会更新已有同名视图而非新建(见 **§4**)。
78
97
 
79
98
  ---
80
99
 
@@ -84,12 +103,11 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
84
103
 
85
104
  | 键 | 说明 |
86
105
  |----|------|
87
- | **`views`** | 必填数组;每项是一个 view job |
88
- | **`views[].operation`** | `upsert` / `patch` / `remove`;省略时按字段推断,但推荐显式写 |
89
- | **`views[].app_key`** | 必填;允许同批混合同 app / 跨 app |
90
- | **`views[].name` / `view_key`** | 创建用 `name`;更新/删除优先用 raw `view_key` |
91
- | **`views[].query_conditions`** | 新建业务视图必填;配置前端查询面板字段布局 |
92
- | **`views[].set` / `unset`** | `operation="patch"` 时使用 |
106
+ | **`app_key`** | 命令的必填参数,定位单个应用 |
107
+ | **`upsert_view`** | 来自 `--view-file` 的一个对象;创建用 `name`,完整更新优先带 raw `view_key` |
108
+ | **`upsert_view.query_conditions`** | 新建业务视图必填;配置前端查询面板字段布局 |
109
+ | **`patch_views`** | 来自 `--patch-views-file` 的数组;每次最多一项,使用 `view_key`/`name` 和 `set`/`unset` |
110
+ | **`remove_views`** | 来自 `--remove-views-file` 的数组;每次最多一项,使用 raw `view_key` 或唯一名称 |
93
111
 
94
112
  **别名**(契约 `aliases` 节选):**`fields` / `column_names` → `columns`**;**`view_key` / `viewKey`**;**`tableView`→`table`**、**`kanban`→`board`** 等;**`filter_rules`→`filters`**;**`startField`→`start_field`** 等。
95
113
 
@@ -99,15 +117,15 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
99
117
 
100
118
  服务逻辑概要:
101
119
 
102
- - **`operation="remove"`**:优先传 raw **`view_key`**;也可传唯一视图显示名 `name`,显示名重名则 **`AMBIGUOUS_VIEW`**。
103
- - **`operation="upsert"`**:
120
+ - **`remove_views`**:优先传 raw **`view_key`**;也可传唯一视图显示名 `name`,显示名重名则 **`AMBIGUOUS_VIEW`**。
121
+ - **`upsert_view`**:
104
122
  - 若提供 **`view_key`**:对该视图做 **更新**(含类型变更等,仍受后端约束)。
105
123
  - 未提供 **`view_key`**:若 **`name` 唯一** 匹配已有视图 → **更新**;否则 → **创建**。
106
- - **`operation="patch"`**:对已有视图做局部参数替换;必须有 `view_key` 或唯一 `name`,并写 `set` / `unset`。
124
+ - **`patch_views`**:对已有视图做局部参数替换;必须有 `view_key` 或唯一 `name`,并写 `set` / `unset`。
107
125
 
108
- 响应中的 **`verification.by_view[].status`** 会出现 **`created` / `updated`** 等;**`views_diff`** 汇总创建/更新/失败名单。
126
+ 响应中的 **`verification.view.status`** 会出现 **`created` / `updated`** 等;**`view_result`** 给出本次唯一视图操作结果,**`views_diff`** 仅保留兼容摘要。
109
127
 
110
- **`partial_success`**:部分视图成功、部分失败时整体仍可能带成功信封,务必读 **`failed`** 与 **`execution_notes`**。
128
+ **`partial_success`**:单个视图写入已执行,但读回或附属配置校验未完全通过;务必读 **`view_result`**、**`warnings`** 与 **`verification`**。
111
129
 
112
130
  **系统默认名禁止新建**:未提供 `view_key` 的 `upsert` 不要使用 `全部数据`、`我的数据`、`我发起的`、`待办`、`已办`、`抄送` 这类默认系统视图名。它们不是业务视图模板,而是平台默认对象;新业务视图用具体业务名。
113
131
 
@@ -115,16 +133,18 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
115
133
 
116
134
  ## 5. `type` 与各类型必填
117
135
 
118
- 契约 **`view.type`**:**`table`** | **`card`** | **`board`** | **`gantt`**。
136
+ 契约 **`view.type`**:**`table`** | **`card`** | **`board`** | **`gantt`** | **`hierarchy`** | **`calendar`**。
119
137
 
120
138
  | `type` | 列/字段要点 | 类型专属键 |
121
139
  |--------|----------------|------------|
122
- | **`table`** | **`columns`**(业务字段 **显示名**,须能在 **`app get fields`** 里找到) | — |
140
+ | **`table`** | **`columns`**(业务字段 **queId**,或已有系统字段 **queId**) | — |
123
141
  | **`card`** | 同 table | — |
124
142
  | **`board`**(看板) | 列;且须 **`group_by`**(分组字段名) | **`group_by`** |
125
143
  | **`gantt`** | 列;须 **`start_field`**、**`end_field`**(通常为日期类字段名) | 可选 **`title_field`** |
144
+ | **`hierarchy`** | 层级标题字段和父子关系字段 | `hierarchy.title_que_id`、`hierarchy.children_que_id`;可选 `hierarchy.root_filter` |
145
+ | **`calendar`** | 标题字段和日期字段 | `calendar.title_que_id`、`calendar.date_que_id`;可选 `calendar.color_que_id` |
126
146
 
127
- 实现侧校验:对 **table/card**,若声明了 **`columns`**,在 **过滤系统列**后须 **至少保留一个**真实应用字段,否则报错——**不能**只用系统列名凑一列(系统列集合见 **[reference/app-delivery-sop.md](./reference/app-delivery-sop.md)**)。
147
+ 实现侧校验:对 **table/card**,`columns` 至少包含一列;已知系统字段在读取已有视图时原样透传,不要求出现在表单业务字段索引中。未知系统字段仍会报告覆盖缺口。
128
148
 
129
149
  ---
130
150
 
@@ -136,9 +156,9 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
136
156
 
137
157
  | 目标场景 | 写到哪里 | 推荐写法 | 不要这样做 |
138
158
  | --- | --- | --- | --- |
139
- | 视图打开时固定筛选数据 | `filters` | `{"field_name":"状态","operator":"eq","value":"进行中"}` | 不要写 `judgeType` / `judgeValues`;不要把它放进 `query_conditions` |
159
+ | 视图打开时固定筛选数据 | `filters` | `{"que_id":101,"operator":"eq","value":"进行中"}` | 不要写 `judgeType` / `judgeValues`;不要把它放进 `query_conditions` |
140
160
  | 前端查询面板显示哪些字段 | `query_conditions.rows` | `[["客户名称", "负责人"], ["创建时间"]]` | 不要写筛选值;不要把它当 OR 条件 |
141
- | 按钮显示条件 | `action_buttons[].visible_when` | `{"field_name":"状态","operator":"eq","value":"已完工"}` | 不要手写后端判断符 |
161
+ | 按钮显示条件 | `action_buttons[].visible_when` | `{"que_id":101,"operator":"eq","value":"已完工"}` | 不要手写后端判断符 |
142
162
  | 当前记录创建下游记录时传值 | `field_mappings` | `{"source_field":"数据ID","target_field":"关联工单"}` | 不要放在 `header` 按钮;`header` 没有当前记录上下文 |
143
163
  | 关联视图/关联报表按当前记录过滤 | `associated-resource apply.match_mappings` | `{"target_field":"关联客户","operator":"eq","source_field":"数据ID"}` | 不要用 `filters` 或 `query_conditions` 代替 |
144
164
  | 关联视图/关联报表静态筛选 | `match_mappings` | `{"target_field":"状态","operator":"eq","value":"有效"}` | 不要混用 raw `match_rules` |
@@ -147,17 +167,17 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
147
167
 
148
168
  ### 6.1 `filters`
149
169
 
150
- - 项形状:**`field_name`**、**`operator`**、**`values`**(或契约允许的 **`value`** 别名)。
170
+ - 项形状:**`que_id`**、**`operator`**、**`values`**(或契约允许的 **`value`** 别名)。
151
171
  - **`operator`**:统一公共语义,推荐 `eq` / `neq` / `in` / `contains` / `gte` / `lte` / `is_empty` / `not_empty`;兼容 `equal` / `equals` / `=` / `!=` / `any_of` / `one_of` / `empty` 等别名(以契约为准)。
152
172
  - **`in` 等多值**:传 **列表**;**`value`** 为列表时可作别名。
153
173
  - **`value` 按字段类型写**:文本/数字/日期直接写业务值;单选/多选/是否优先写选项文本,也支持 option id;成员/部门/关联记录固定筛选优先写唯一 id 或 `{id,value}`。完整规则见 **[reference/match-rules.md](./reference/match-rules.md)**。
154
174
  - **语义**:固定筛选条件,打开视图即生效。不要把前端查询栏字段写进 `filters`。
155
- - **写入 / 读回语义**:智能体始终写 `field_name + operator + value/values`;CLI 内部自动转换目标协议,读回也会还原成 `operator/value` 语义。不要手写或解释后端判断符。
175
+ - **写入 / 读回语义**:智能体始终写 `que_id + operator + value/values`;CLI 内部自动转换目标协议,读回也会还原成 `operator/value` 语义。不要手写或解释后端判断符。
156
176
 
157
177
  示例:
158
178
 
159
179
  ```json
160
- {"field_name": "状态", "operator": "eq", "value": "进行中"}
180
+ {"que_id": 101, "operator": "eq", "value": "进行中"}
161
181
  ```
162
182
 
163
183
  ### 6.2 `query_conditions`
@@ -176,44 +196,38 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
176
196
 
177
197
  ```json
178
198
  {
179
- "views": [
199
+ "name": "客户查询视图",
200
+ "type": "table",
201
+ "columns": [101, 102, 103, 104],
202
+ "filters": [
203
+ {"que_id": 103, "operator": "eq", "value": "有效"}
204
+ ],
205
+ "query_conditions": {
206
+ "enabled": true,
207
+ "exact": false,
208
+ "hide_before_query": false,
209
+ "rows": [["客户名称", "负责人"], ["创建时间"]]
210
+ },
211
+ "action_buttons": [
180
212
  {
181
- "operation": "upsert",
182
- "app_key": "APP_KEY",
183
- "name": "客户查询视图",
184
- "type": "table",
185
- "columns": ["客户名称", "负责人", "客户状态", "创建时间"],
186
- "filters": [
187
- {"field_name": "客户状态", "operator": "eq", "value": "有效"}
213
+ "text": "行内创建跟进",
214
+ "action": "add_data",
215
+ "target_app_key": "FOLLOWUP_APP_KEY",
216
+ "field_mappings": [
217
+ {"source_field": "数据ID", "target_field": "关联客户"}
188
218
  ],
189
- "query_conditions": {
190
- "enabled": true,
191
- "exact": false,
192
- "hide_before_query": false,
193
- "rows": [["客户名称", "负责人"], ["创建时间"]]
194
- },
195
- "action_buttons": [
196
- {
197
- "text": "行内创建跟进",
198
- "action": "add_data",
199
- "target_app_key": "FOLLOWUP_APP_KEY",
200
- "field_mappings": [
201
- {"source_field": "数据ID", "target_field": "关联客户"}
202
- ],
203
- "default_values": {"跟进状态": "待跟进"},
204
- "placement": "list"
205
- },
206
- {
207
- "text": "详情创建跟进",
208
- "action": "add_data",
209
- "target_app_key": "FOLLOWUP_APP_KEY",
210
- "field_mappings": [
211
- {"source_field": "数据ID", "target_field": "关联客户"}
212
- ],
213
- "default_values": {"跟进状态": "待跟进"},
214
- "placement": "detail"
215
- }
216
- ]
219
+ "default_values": {"跟进状态": "待跟进"},
220
+ "placement": "list"
221
+ },
222
+ {
223
+ "text": "详情创建跟进",
224
+ "action": "add_data",
225
+ "target_app_key": "FOLLOWUP_APP_KEY",
226
+ "field_mappings": [
227
+ {"source_field": "数据ID", "target_field": "关联客户"}
228
+ ],
229
+ "default_values": {"跟进状态": "待跟进"},
230
+ "placement": "detail"
217
231
  }
218
232
  ]
219
233
  }
@@ -236,47 +250,41 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
236
250
 
237
251
  ```json
238
252
  {
239
- "views": [
253
+ "name": "生产工单执行视图",
254
+ "type": "table",
255
+ "columns": ["工单编号", "产品", "状态", "负责人"],
256
+ "filters": [
257
+ {"que_id": 101, "operator": "in", "values": ["生产中", "已完工"]}
258
+ ],
259
+ "query_conditions": {
260
+ "enabled": true,
261
+ "exact": false,
262
+ "hide_before_query": false,
263
+ "rows": [["工单编号", "状态"], ["负责人"]]
264
+ },
265
+ "action_buttons": [
240
266
  {
241
- "operation": "upsert",
242
- "app_key": "APP_KEY",
243
- "name": "生产工单执行视图",
244
- "type": "table",
245
- "columns": ["工单编号", "产品", "状态", "负责人"],
246
- "filters": [
247
- {"field_name": "状态", "operator": "in", "values": ["生产中", "已完工"]}
267
+ "text": "行内创建质检单",
268
+ "action": "add_data",
269
+ "target_app_key": "QUALITY_APP",
270
+ "field_mappings": [
271
+ {"source_field": "数据ID", "target_field": "关联工单"}
248
272
  ],
249
- "query_conditions": {
250
- "enabled": true,
251
- "exact": false,
252
- "hide_before_query": false,
253
- "rows": [["工单编号", "状态"], ["负责人"]]
254
- },
255
- "action_buttons": [
256
- {
257
- "text": "行内创建质检单",
258
- "action": "add_data",
259
- "target_app_key": "QUALITY_APP",
260
- "field_mappings": [
261
- {"source_field": "数据ID", "target_field": "关联工单"}
262
- ],
263
- "default_values": {"处理状态": "待处理"},
264
- "placement": "list",
265
- "visible_when": [
266
- {"field_name": "状态", "operator": "eq", "value": "已完工"}
267
- ]
268
- },
269
- {
270
- "text": "详情创建返工单",
271
- "action": "add_data",
272
- "target_app_key": "REWORK_APP",
273
- "field_mappings": [
274
- {"source_field": "数据ID", "target_field": "关联工单"}
275
- ],
276
- "default_values": {"返工状态": "待处理"},
277
- "placement": "detail"
278
- }
273
+ "default_values": {"处理状态": "待处理"},
274
+ "placement": "list",
275
+ "visible_when": [
276
+ {"que_id": 101, "operator": "eq", "value": "已完工"}
279
277
  ]
278
+ },
279
+ {
280
+ "text": "详情创建返工单",
281
+ "action": "add_data",
282
+ "target_app_key": "REWORK_APP",
283
+ "field_mappings": [
284
+ {"source_field": "数据ID", "target_field": "关联工单"}
285
+ ],
286
+ "default_values": {"返工状态": "待处理"},
287
+ "placement": "detail"
280
288
  }
281
289
  ]
282
290
  }
@@ -286,8 +294,6 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
286
294
 
287
295
  ```json
288
296
  {
289
- "operation": "patch",
290
- "app_key": "APP_KEY",
291
297
  "view_key": "RAW_VIEW_KEY",
292
298
  "set": {
293
299
  "action_buttons": [
@@ -325,7 +331,7 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
325
331
  - `publish=false` + `action_buttons` 会被阻断为 `VIEW_ACTION_BUTTONS_REQUIRE_PUBLISH`。
326
332
  - 视图内按钮写智能体语义:`action: "add_data"` 或 `action: "link"`。不要手写底层触发名。
327
333
  - 响应里同时看 `verification.views_verified`、`verification.action_buttons_verified`、`verification.view_button_bindings_verified`。
328
- - 按钮失败但视图成功时是 `partial_success`;先按 `suggested_next_call` 重试失败视图的 `views[]` patch。 如果回读里目标视图已有 `CUSTOM` 按钮、文本/位置/触发类型正确,不要重建视图或重复创建按钮。
334
+ - 按钮失败但视图成功时是 `partial_success`;先按 `suggested_next_call` 用 `patch_views` 重试失败视图。 如果回读里目标视图已有 `CUSTOM` 按钮、文本/位置/触发类型正确,不要重建视图或重复创建按钮。
329
335
 
330
336
  `default_values` 是写入**目标应用新增表单**的静态默认值,必须按目标应用 schema 写:
331
337
 
@@ -333,7 +339,7 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
333
339
  - 单选/多选字段的默认值必须来自目标字段 `options` 的**原始文本或 option id**;不要用业务近义词。例如 schema 选项是 `每月`、`中`,就不要写 `月检`、`普通`。
334
340
  - 成员/部门/关联字段默认值按 record insert 的写法处理;不确定候选或目标记录时,先只写 `field_mappings`,不要编造 `default_values`。
335
341
  - `field_mappings[].target_field` 和 `default_values` 的 key 都是**目标应用字段名**,不是当前视图字段名。
336
- - CLI 会在按钮写入前校验默认值;非法值会返回 `CUSTOM_BUTTON_DEFAULT_VALUE_UNSUPPORTED`。这时视图可能已经创建成功,只需要用 `views[].operation="patch"` + raw `view_key` 修正 `action_buttons.default_values`,不要重建视图或应用。
342
+ - CLI 会在按钮写入前校验默认值;非法值会返回 `CUSTOM_BUTTON_DEFAULT_VALUE_UNSUPPORTED`。这时视图可能已经创建成功,只需要用 `patch_views` + raw `view_key` 修正 `action_buttons.default_values`,不要重建视图或应用。
337
343
 
338
344
  正确示例:
339
345
 
@@ -386,10 +392,10 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
386
392
 
387
393
  ## 7. 删除视图
388
394
 
389
- - 主路径使用 `views[].operation="remove"`;元素必须带 `app_key`,优先带 raw **`view_key`**,也可以带唯一视图显示名。
395
+ - 主路径使用 `--remove-views-file`;元素是 raw **`view_key`** 或唯一视图显示名,应用通过 `--app-key` 指定。
390
396
  - 优先用 **`view_key`** 删除;显示名重名会导致 **`AMBIGUOUS_VIEW`**,需先在 **`app get views`** 里确认。
391
397
  - DELETE 发出后,工具会用单个 **`view_key`** 回读验证,而不是再读全量视图列表判断删除结果。
392
- - 删除结果看 **`verification.by_view[].delete_executed`**、**`readback_status`**、**`safe_to_retry_delete`**:
398
+ - 删除结果看 **`verification.view.delete_executed`**、**`readback_status`**、**`safe_to_retry_delete`**:
393
399
  - **`readback_status=deleted`**:删除已验证。
394
400
  - **`readback_status=unavailable`** 或 **`still_exists`**:删除请求已发出但回读未完全确认,**不要盲目重复删除**;稍后用 `builder app get views` 或对应视图详情确认。
395
401
 
@@ -401,21 +407,15 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
401
407
 
402
408
  ```json
403
409
  {
404
- "views": [
405
- {
406
- "operation": "upsert",
407
- "app_key": "APP_KEY",
408
- "name": "项目台账视图",
409
- "type": "table",
410
- "columns": ["项目名称"],
411
- "visibility": {
412
- "mode": "workspace",
413
- "selectors": {},
414
- "external_mode": "not",
415
- "external_selectors": {}
416
- }
417
- }
418
- ]
410
+ "name": "项目台账视图",
411
+ "type": "table",
412
+ "columns": [101],
413
+ "visibility": {
414
+ "mode": "workspace",
415
+ "selectors": {},
416
+ "external_mode": "not",
417
+ "external_selectors": {}
418
+ }
419
419
  }
420
420
  ```
421
421
 
@@ -423,70 +423,58 @@ CLI 将参数与文件内容拼装为服务层载荷,**顶层键**如下:
423
423
 
424
424
  ```json
425
425
  {
426
- "views": [
426
+ "name": "项目甘特图",
427
+ "type": "gantt",
428
+ "columns": [101, 102, 103],
429
+ "start_que_id": 102,
430
+ "end_que_id": 103,
431
+ "title_que_id": 101,
432
+ "filters": [
427
433
  {
428
- "operation": "upsert",
429
- "app_key": "APP_KEY",
430
- "name": "项目甘特图",
431
- "type": "gantt",
432
- "columns": ["项目名称", "开始日期", "结束日期"],
433
- "start_field": "开始日期",
434
- "end_field": "结束日期",
435
- "title_field": "项目名称",
436
- "filters": [
437
- {
438
- "field_name": "状态",
439
- "operator": "eq",
440
- "value": "进行中"
441
- }
442
- ]
434
+ "que_id": 101,
435
+ "operator": "eq",
436
+ "value": "进行中"
443
437
  }
444
438
  ]
445
439
  }
446
440
  ```
447
441
 
448
- **Table + 筛选 + 查询条件 + 快捷按钮(完整 views-file)**:
442
+ **Table + 筛选 + 查询条件 + 快捷按钮(单条 `--view-file`)**:
449
443
 
450
444
  ```json
451
445
  {
452
- "views": [
446
+ "name": "客户查询视图",
447
+ "type": "table",
448
+ "columns": [101, 102, 103, 104],
449
+ "filters": [
450
+ {"que_id": 103, "operator": "eq", "value": "有效"}
451
+ ],
452
+ "query_conditions": {
453
+ "enabled": true,
454
+ "exact": false,
455
+ "hide_before_query": false,
456
+ "rows": [["客户名称", "负责人"], ["创建时间"]]
457
+ },
458
+ "action_buttons": [
453
459
  {
454
- "operation": "upsert",
455
- "app_key": "APP_KEY",
456
- "name": "客户查询视图",
457
- "type": "table",
458
- "columns": ["客户名称", "负责人", "客户状态", "创建时间"],
459
- "filters": [
460
- {"field_name": "客户状态", "operator": "eq", "value": "有效"}
460
+ "text": "行内创建跟进",
461
+ "action": "add_data",
462
+ "target_app_key": "FOLLOWUP_APP_KEY",
463
+ "field_mappings": [
464
+ {"source_field": "数据ID", "target_field": "关联客户"}
461
465
  ],
462
- "query_conditions": {
463
- "enabled": true,
464
- "exact": false,
465
- "hide_before_query": false,
466
- "rows": [["客户名称", "负责人"], ["创建时间"]]
467
- },
468
- "action_buttons": [
469
- {
470
- "text": "行内创建跟进",
471
- "action": "add_data",
472
- "target_app_key": "FOLLOWUP_APP_KEY",
473
- "field_mappings": [
474
- {"source_field": "数据ID", "target_field": "关联客户"}
475
- ],
476
- "default_values": {"跟进状态": "待跟进"},
477
- "placement": "list"
478
- },
479
- {
480
- "text": "详情创建跟进",
481
- "action": "add_data",
482
- "target_app_key": "FOLLOWUP_APP_KEY",
483
- "field_mappings": [
484
- {"source_field": "数据ID", "target_field": "关联客户"}
485
- ],
486
- "default_values": {"跟进状态": "待跟进"},
487
- "placement": "detail"
488
- }
489
- ]
466
+ "default_values": {"跟进状态": "待跟进"},
467
+ "placement": "list"
468
+ },
469
+ {
470
+ "text": "详情创建跟进",
471
+ "action": "add_data",
472
+ "target_app_key": "FOLLOWUP_APP_KEY",
473
+ "field_mappings": [
474
+ {"source_field": "数据ID", "target_field": "关联客户"}
475
+ ],
476
+ "default_values": {"跟进状态": "待跟进"},
477
+ "placement": "detail"
490
478
  }
491
479
  ]
492
480
  }
@@ -508,11 +496,12 @@ qingflow --json builder app get --app-key ead8ims5i401 views
508
496
 
509
497
  ```bash
510
498
  qingflow builder views apply \
499
+ --app-key ead8ims5i401 \
511
500
  --publish \
512
- --views-file ./reference/examples/views/views_upsert_table_minimal.example.json
501
+ --view-file ./view.json
513
502
  ```
514
503
 
515
- **结果摘要**(示例视图名 **`示例业务操作视图_CLI模板`**):`status: success`,`verification.by_view[0].status: created`,返回 **`view_key`**(如 **`ecdk22v65c02`**),并验证 `query_conditions` 与 `action_buttons`。
504
+ **结果摘要**(示例视图名 **`示例业务操作视图_CLI模板`**):`status: success`,`verification.view.status: created`,返回 **`view_key`**(如 **`ecdk22v65c02`**),并验证 `query_conditions` 与 `action_buttons`。
516
505
 
517
506
  ---
518
507
 
@@ -524,7 +513,7 @@ qingflow builder views apply \
524
513
  | 重名视图 / 删错 | **`app get views`**;更新时带 **`view_key`** |
525
514
  | 过滤器未生效疑虑 | 看响应 **`verification.view_filters_verified`**;必要时再 **`app get views`** |
526
515
  | 查询条件未生效疑虑 | 看响应 **`verification.view_query_conditions_verified`**;不要把 `query_conditions` 当 `filters` |
527
- | 后端 **40038 / Object not exist** | 先读失败项 **`details.per_view_results[].details.field_level_diagnostics`** 与 **`recommended_minimal_retry`**。不要删除字段、不要重建应用;先按最小列重试,再逐步加非关键列/筛选。 |
516
+ | 后端 **40038 / Object not exist** | 先读失败项 **`details.view_result.details.field_level_diagnostics`** 与 **`recommended_minimal_retry`**。不要删除字段、不要重建应用;先按最小列重试,再逐步加非关键列/筛选。 |
528
517
  | 按钮/关联资源配置 | 常规业务按钮随视图写 **`action_buttons`**;关联视图/报表走 **`builder associated-resource apply`** |
529
518
  | 部分失败 | 读 **`views_diff.failed`** 与契约 **execution_notes** 中 **partial_success** |
530
519
  | 权限/锁 | 同 [publish verify](./99-publish-verify.md) 与 [app delivery reference](./reference/app-delivery-sop.md) |
@@ -533,7 +522,7 @@ qingflow builder views apply \
533
522
 
534
523
  ## 11. 交叉引用
535
524
 
536
- - [views_upsert_table_minimal.example.json](../examples/views/views_upsert_table_minimal.example.json)(**table** 视图最小 **`views[]`**)
525
+ - [views_upsert_table_minimal.example.json](../examples/views/views_upsert_table_minimal.example.json)(单视图示例,可直接作为 `--view-file` 使用)
537
526
  - [SKILL.md](../../SKILL.md):builder 直接输出、鉴权顺序。
538
527
  - [99-publish-verify.md](./99-publish-verify.md):发布与回读。
539
528
  - [reference/app-delivery-sop.md](./reference/app-delivery-sop.md):系统列与历史交付细节。
@@ -38,7 +38,7 @@ Rules:
38
38
  - Portal chart sections use one `chart` field: `{"chart_id":"..."}` to reuse an existing QingBI chart, or `{"app_key":"...","name":"...","chart_type":"...",...}` to create/update the needed chart inline.
39
39
  - Buttons are part of the view design: declare them in the target view with `action_buttons`.
40
40
  - Update instructions live inside the resource document. Do not use `update-*` as a separate main route.
41
- - Batch read, batch write, and patch are resource-specific variants, not separate workflows.
41
+ - Batch read, batch write, and patch are resource-specific variants, not separate workflows. View writes are single-operation: `builder views apply` handles one view per call; consult [50-views.md](./50-views.md) before preparing multiple view changes.
42
42
 
43
43
  ## File responsibilities
44
44
 
@@ -41,7 +41,7 @@
41
41
  这些不是独立流程,而是读、写、改三个动作的多资源形态:
42
42
 
43
43
  - **批量读**:读多个应用时优先用 `--app-keys`,例如 `builder app get --app-keys a,b fields`、`builder app get --app-keys a,b views`、`builder button get --app-keys a,b`、`builder associated-resource get --app-keys a,b`、`builder publish verify --app-keys a,b`。读结果同时看成功项和 `errors[]`,不要因单个应用失败否定全批。
44
- - **批量写**:视图、按钮、关联资源和报表按各自资源契约使用对应的批量文件;应用表单不走 `apps-file`,而是每个应用独立提交完整 AppForm 声明。
44
+ - **批量写**:仅在资源契约明确支持时使用批量文件;视图例外,`builder views apply` 每次只提交一个视图的一种操作,不支持多视图批量创建或把 upsert/patch/remove 混在一次调用中。应用表单不走 `apps-file`,而是每个应用独立提交完整 AppForm 声明。
45
45
  - **局部改**:只改已存在资源的少量参数时用对应 patch 文件;`patch_*` 内只写目标定位字段和 `set/unset`,不要用不完整 `upsert_*` 伪装局部更新。
46
46
 
47
47
  ---
@@ -374,14 +374,14 @@ qingflow builder flow apply \
374
374
 
375
375
  后端很多保存接口仍是整份配置保存,但新版 CLI/MCP 对外提供 **public partial patch**:
376
376
 
377
- - 已有视图:`builder views apply --views-file`,其中对应项写 `operation: "patch"`
377
+ - 已有视图:`builder views apply --app-key APP_KEY --patch-views-file PATH`,文件只放一项,写 `view_key`/`name` 与 `set`/`unset`
378
378
  - 已有按钮:`builder button apply --patch-buttons-file`
379
379
  - 已有关联资源:`builder associated-resource apply --patch-resources-file`
380
380
  - 已有报表:`builder charts apply --patch-file`
381
381
  - 已有流程节点:`builder flow apply --patch-nodes-file`
382
382
  - 已有门户组件:`builder portal apply --patch-sections-file`
383
383
 
384
- 局部更新的语义是:你只写要替换的参数,工具内部读取当前配置、补齐后端必填字段,再整份保存。每个 patch 项直接使用对象真实定位字段 + `set` / 可选 `unset`,不要写字面量 `selector` key。示例:`{"operation":"patch","app_key":"APP_KEY","view_key":"VIEW_KEY","set":{"query_conditions":{...}}}`、`{"button_id": 1001, "set": {"button_text": "新名称"}}`、`{"associated_item_id": 123, "set": {"match_mappings": [...]}}`、`{"chart_id": 456, "set": {"name": "新报表名"}}`、`{"id": "node_1", "set": {"name": "主管审批"}}`、`{"chart": {"chart_key": "xxx"}, "set": {"rows": 7}}`。
384
+ 局部更新的语义是:你只写要替换的参数,工具内部读取当前配置、补齐后端必填字段,再整份保存。每个 patch 项直接使用对象真实定位字段 + `set` / 可选 `unset`,不要写字面量 `selector` key。示例:`{"view_key":"VIEW_KEY","set":{"query_conditions":{...}}}`、`{"button_id": 1001, "set": {"button_text": "新名称"}}`、`{"associated_item_id": 123, "set": {"match_mappings": [...]}}`、`{"chart_id": 456, "set": {"name": "新报表名"}}`、`{"id": "node_1", "set": {"name": "主管审批"}}`、`{"chart": {"chart_key": "xxx"}, "set": {"rows": 7}}`。
385
385
 
386
386
  `upsert_*` 用于创建或提供完整目标配置;不要只给 `name/type/query_conditions` 这类局部片段然后期待后端自动合并。
387
387