@josephyan/qingflow-app-builder-mcp 1.1.26 → 1.1.27
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 +4 -3
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +24 -75
- package/skills/qingflow-app-builder/references/build-complete-system.md +185 -379
- package/skills/qingflow-app-builder/references/build-single-app.md +103 -495
- package/skills/qingflow-app-builder/references/create-app.md +15 -3
- package/skills/qingflow-app-builder/references/gotchas.md +6 -10
- package/skills/qingflow-app-builder/references/match-rules.md +18 -14
- package/skills/qingflow-app-builder/references/public-surface-sync.md +2 -2
- package/skills/qingflow-app-builder/references/tool-selection.md +9 -11
- package/src/qingflow_mcp/builder_facade/models.py +167 -71
- package/src/qingflow_mcp/builder_facade/service.py +612 -152
- package/src/qingflow_mcp/cli/commands/builder.py +3 -1
- package/src/qingflow_mcp/cli/main.py +8 -3
- package/src/qingflow_mcp/server_app_builder.py +9 -8
- package/src/qingflow_mcp/tools/ai_builder_tools.py +231 -180
- package/src/qingflow_mcp/version.py +2 -0
|
@@ -1,428 +1,234 @@
|
|
|
1
|
-
# Build Complete System
|
|
1
|
+
# Build Complete System
|
|
2
2
|
|
|
3
|
-
Use this when the user
|
|
3
|
+
Use this when the user asks for a system, app package, workspace module set, or several related apps/forms.
|
|
4
|
+
Do not compress several business objects into one app.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## Main Chain
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Phase 0 → Phase 1 → [Phase 2 → 3 → 4] per app → Phase 5 → Phase 6 → Phase 7
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
- Phase 1 (schema) must complete for **all apps** before Phase 2/3/4 begins — all `app_key` values must be known first
|
|
18
|
-
- Phase 5 (portal) runs after **all** Phase 4 views are created — `view_key` values must be available
|
|
19
|
-
- Phase 6 (data) runs after Phase 5 — fields and flows must be live before inserting records
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Phase 0 — Scan workspace packages
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{"tool_name": "package_list", "arguments": {"profile": "default"}}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
- **Package name already exists in workspace** → tell the user, wait for explicit confirmation before continuing
|
|
30
|
-
- **Package name not in workspace** → run `package_apply` immediately, no confirmation needed:
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
{
|
|
34
|
-
"tool_name": "package_apply",
|
|
35
|
-
"arguments": {
|
|
36
|
-
"profile": "default",
|
|
37
|
-
"package_name": "客户管理系统",
|
|
38
|
-
"create_if_missing": true
|
|
39
|
-
}
|
|
40
|
-
}
|
|
8
|
+
```text
|
|
9
|
+
package_apply
|
|
10
|
+
-> app_schema_apply(apps[] with fields, relations, form.sections)
|
|
11
|
+
-> app_views_apply(views[])
|
|
12
|
+
-> portal_apply(sections[] with inline QingBI chart)
|
|
13
|
+
-> workflow / associated resources only when requested or required
|
|
14
|
+
-> readback + publish/visibility summary
|
|
41
15
|
```
|
|
42
16
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
---
|
|
17
|
+
This is the only recommended chain for a new complete system. Do not split it into separate app creates, separate layout writes, or separate chart creation before portal.
|
|
46
18
|
|
|
47
|
-
##
|
|
19
|
+
## Required Shape
|
|
48
20
|
|
|
49
|
-
|
|
21
|
+
- Create or resolve the package with `package_apply` / `package_get`.
|
|
22
|
+
- Create all related apps in one `app_schema_apply(package_id=..., apps=[...])`.
|
|
23
|
+
- Every app item must include stable `client_key`, `app_name`, `icon`, `color`, `add_fields`, and exactly one readable `as_data_title: true`.
|
|
24
|
+
- Put form layout directly in `apps[].form.sections`. Do not make `app_layout_apply` a standard second step for new apps.
|
|
25
|
+
- Same-call relations must use `target_app_ref` pointing to another `apps[].client_key`.
|
|
26
|
+
- Use `target_app_key` only for an app that already exists and has been confirmed by readback.
|
|
27
|
+
- Do not create platform fields: `数据ID`, `编号`, `申请人`, `申请时间`, `创建人`, `创建时间`, `提交人`, `提交时间`, `更新时间`, `更新人`, `当前流程状态`, `当前处理人`, `当前处理节点`, `流程标题`.
|
|
50
28
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
**12–20 fields per app.** Distribute across types:
|
|
54
|
-
|
|
55
|
-
| Type | Count per app | Examples |
|
|
56
|
-
|------|--------------|---------|
|
|
57
|
-
| `text` / `long_text` | 2–3 | 名称、编号、描述 |
|
|
58
|
-
| `single_select` / `multi_select` | 2–4 | 状态、类型、优先级、阶段 |
|
|
59
|
-
| `date` / `datetime` | 1–2 | 开始日期、截止日期 |
|
|
60
|
-
| `number` / `amount` | 1–3 | 金额、数量、完成率 |
|
|
61
|
-
| `member` | 1–2 | 负责人、创建人 |
|
|
62
|
-
| `attachment` | 0–1 | 封面图或附件 |
|
|
63
|
-
| `relation` | 1–2 | 跨表关联字段 |
|
|
64
|
-
|
|
65
|
-
### Hard rules
|
|
66
|
-
|
|
67
|
-
- Exactly one top-level field per app must have `as_data_title: true`
|
|
68
|
-
- Every `relation` field must include both `display_field: {"name": "..."}` and `visible_fields: [{"name": "..."}]` — missing either causes `VALIDATION_ERROR` and the entire batch fails with `write_executed=false`; read the `message` field verbatim first before guessing at other causes
|
|
69
|
-
- Use `target_app_ref` to reference another app in the same batch by its `client_key`; do not create apps separately and patch relations later
|
|
70
|
-
- If part of the batch fails, only resubmit the failed apps by `row_number`; do not resubmit the entire batch
|
|
71
|
-
|
|
72
|
-
### Example (customer + opportunity system)
|
|
29
|
+
## Schema Payload Pattern
|
|
73
30
|
|
|
74
31
|
```json
|
|
75
32
|
{
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
{"
|
|
91
|
-
{"name": "客户状态", "type": "single_select", "options": ["潜在", "跟进中", "已签约", "流失"]},
|
|
92
|
-
{"name": "负责人", "type": "member"},
|
|
93
|
-
{"name": "联系人", "type": "text"},
|
|
94
|
-
{"name": "联系电话", "type": "phone"},
|
|
95
|
-
{"name": "所在地区", "type": "address"},
|
|
96
|
-
{"name": "首次合作日期", "type": "date"},
|
|
97
|
-
{"name": "累计合同金额", "type": "amount"},
|
|
98
|
-
{"name": "客户简介", "type": "long_text"},
|
|
99
|
-
{"name": "客户封面", "type": "attachment", "as_data_cover": true}
|
|
100
|
-
]
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"client_key": "opportunity",
|
|
104
|
-
"app_name": "商机",
|
|
105
|
-
"add_fields": [
|
|
106
|
-
{"name": "商机名称", "type": "text", "required": true, "as_data_title": true},
|
|
107
|
-
{"name": "关联客户", "type": "relation", "target_app_ref": "customer",
|
|
108
|
-
"display_field": {"name": "客户名称"}, "visible_fields": [{"name": "客户名称"}, {"name": "客户类型"}]},
|
|
109
|
-
{"name": "商机阶段", "type": "single_select", "options": ["初步接触", "需求确认", "方案报价", "商务谈判", "赢单", "输单"]},
|
|
110
|
-
{"name": "预计金额", "type": "amount"},
|
|
111
|
-
{"name": "赢单概率", "type": "number"},
|
|
112
|
-
{"name": "负责人", "type": "member"},
|
|
113
|
-
{"name": "预计成交日期", "type": "date"},
|
|
114
|
-
{"name": "商机来源", "type": "single_select", "options": ["官网", "转介绍", "市场活动", "电话开发", "其他"]},
|
|
115
|
-
{"name": "竞争对手", "type": "text"},
|
|
116
|
-
{"name": "跟进记录", "type": "long_text"},
|
|
117
|
-
{"name": "优先级", "type": "single_select", "options": ["高", "中", "低"]},
|
|
118
|
-
{"name": "创建日期", "type": "date"}
|
|
33
|
+
"package_id": 123,
|
|
34
|
+
"apps": [
|
|
35
|
+
{
|
|
36
|
+
"client_key": "customer",
|
|
37
|
+
"app_name": "客户",
|
|
38
|
+
"icon": "user-group",
|
|
39
|
+
"color": "blue",
|
|
40
|
+
"add_fields": [
|
|
41
|
+
{"name": "客户名称", "type": "text", "as_data_title": true},
|
|
42
|
+
{"name": "客户状态", "type": "select", "options": ["潜在", "跟进中", "已成交"]},
|
|
43
|
+
{"name": "负责人", "type": "member"}
|
|
44
|
+
],
|
|
45
|
+
"form": {
|
|
46
|
+
"sections": [
|
|
47
|
+
{"title": "基础信息", "rows": [["客户名称", "客户状态"], ["负责人"]]}
|
|
119
48
|
]
|
|
120
49
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
"mode": "merge",
|
|
143
|
-
"publish": true,
|
|
144
|
-
"sections": [
|
|
145
|
-
{
|
|
146
|
-
"title": "基础信息",
|
|
147
|
-
"rows": [
|
|
148
|
-
["客户名称", "客户编号"],
|
|
149
|
-
["客户类型", "行业"],
|
|
150
|
-
["客户状态", "负责人"]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"client_key": "opportunity",
|
|
53
|
+
"app_name": "商机",
|
|
54
|
+
"icon": "business-trend-up",
|
|
55
|
+
"color": "green",
|
|
56
|
+
"add_fields": [
|
|
57
|
+
{"name": "商机名称", "type": "text", "as_data_title": true},
|
|
58
|
+
{
|
|
59
|
+
"name": "关联客户",
|
|
60
|
+
"type": "relation",
|
|
61
|
+
"target_app_ref": "customer",
|
|
62
|
+
"display_field": {"name": "客户名称"},
|
|
63
|
+
"visible_fields": [{"name": "客户名称"}, {"name": "客户状态"}]
|
|
64
|
+
},
|
|
65
|
+
{"name": "商机阶段", "type": "select", "options": ["初步接触", "方案报价", "赢单", "输单"]},
|
|
66
|
+
{"name": "预计金额", "type": "amount"}
|
|
67
|
+
],
|
|
68
|
+
"form": {
|
|
69
|
+
"sections": [
|
|
70
|
+
{"title": "基础信息", "rows": [["商机名称", "关联客户"], ["商机阶段", "预计金额"]]}
|
|
151
71
|
]
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"title": "联系信息",
|
|
155
|
-
"rows": [
|
|
156
|
-
["联系人", "联系电话"],
|
|
157
|
-
["所在地区"]
|
|
158
|
-
]
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"title": "业务数据",
|
|
162
|
-
"rows": [
|
|
163
|
-
["首次合作日期", "累计合同金额"],
|
|
164
|
-
["客户简介"]
|
|
165
|
-
]
|
|
166
|
-
}
|
|
167
|
-
]
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
## Phase 3 — Per-app: Flow
|
|
175
|
-
|
|
176
|
-
> **Read first**: [update-flow.md](./update-flow.md) and [flow-actors-and-permissions.md](./flow-actors-and-permissions.md)
|
|
177
|
-
|
|
178
|
-
Run for each app. Search for an existing role first; create one if none fits.
|
|
179
|
-
|
|
180
|
-
```json
|
|
181
|
-
{"tool_name": "role_search", "arguments": {"profile": "default", "query": "审批"}}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
```json
|
|
185
|
-
{
|
|
186
|
-
"tool_name": "app_flow_apply",
|
|
187
|
-
"arguments": {
|
|
188
|
-
"profile": "default",
|
|
189
|
-
"app_key": "APP_KEY",
|
|
190
|
-
"preset": "basic_approval",
|
|
191
|
-
"publish": true,
|
|
192
|
-
"nodes": [
|
|
193
|
-
{
|
|
194
|
-
"id": "approve_1",
|
|
195
|
-
"type": "approve",
|
|
196
|
-
"name": "主管审批",
|
|
197
|
-
"assignees": {"role_names": ["部门主管"]},
|
|
198
|
-
"permissions": {"editable_fields": ["客户状态"]}
|
|
199
72
|
}
|
|
200
|
-
|
|
201
|
-
|
|
73
|
+
}
|
|
74
|
+
]
|
|
202
75
|
}
|
|
203
76
|
```
|
|
204
77
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
## Phase 4 — Per-app: Views (multiple types)
|
|
78
|
+
Agent-friendly field type aliases are allowed: `multiline -> long_text`, `select -> single_select`, `amount -> amount`. Readback may show canonical types; do not treat that as a mismatch.
|
|
208
79
|
|
|
209
|
-
|
|
80
|
+
## Views
|
|
210
81
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
| **card** | App has an `attachment` field with `as_data_cover: true` | Visual browsing; same `query_conditions` |
|
|
82
|
+
- Use one `app_views_apply(views=[...])` batch for same-app and cross-app views.
|
|
83
|
+
- Do not create platform default views named `全部数据`, `我的数据`, `我发起的`, `待办`, `已办`, or `抄送`.
|
|
84
|
+
- Use business-specific view names.
|
|
85
|
+
- If a view needs business actions, put them directly inside that view item with `action_buttons`.
|
|
86
|
+
- Keep `filters` and `query_conditions` separate:
|
|
87
|
+
- `filters`: fixed saved filters.
|
|
88
|
+
- `query_conditions`: frontend query panel fields.
|
|
219
89
|
|
|
220
90
|
```json
|
|
221
91
|
{
|
|
222
|
-
"
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
"query_conditions": {
|
|
233
|
-
"enabled": true,
|
|
234
|
-
"exact": false,
|
|
235
|
-
"hide_before_query": false,
|
|
236
|
-
"rows": [["客户名称", "客户类型"], ["客户状态", "负责人"]]
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
"name": "客户看板",
|
|
241
|
-
"type": "board",
|
|
242
|
-
"columns": ["客户名称", "客户类型", "负责人", "累计合同金额"],
|
|
243
|
-
"group_by": "客户状态",
|
|
244
|
-
"query_conditions": {
|
|
245
|
-
"enabled": true,
|
|
246
|
-
"exact": false,
|
|
247
|
-
"hide_before_query": false,
|
|
248
|
-
"rows": [["客户名称", "负责人"]]
|
|
249
|
-
}
|
|
92
|
+
"views": [
|
|
93
|
+
{
|
|
94
|
+
"operation": "upsert",
|
|
95
|
+
"app_key": "CUSTOMER_APP_KEY",
|
|
96
|
+
"name": "客户跟进视图",
|
|
97
|
+
"type": "table",
|
|
98
|
+
"columns": ["客户名称", "客户状态", "负责人"],
|
|
99
|
+
"query_conditions": {
|
|
100
|
+
"enabled": true,
|
|
101
|
+
"rows": [["客户名称", "客户状态"], ["负责人"]]
|
|
250
102
|
},
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"
|
|
257
|
-
"
|
|
258
|
-
|
|
259
|
-
|
|
103
|
+
"action_buttons": [
|
|
104
|
+
{
|
|
105
|
+
"text": "新建商机",
|
|
106
|
+
"action": "add_data",
|
|
107
|
+
"target_app_key": "OPPORTUNITY_APP_KEY",
|
|
108
|
+
"placement": "detail",
|
|
109
|
+
"field_mappings": [
|
|
110
|
+
{"source_field": "数据ID", "target_field": "关联客户"}
|
|
111
|
+
]
|
|
260
112
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
]
|
|
264
116
|
}
|
|
265
117
|
```
|
|
266
118
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
## Phase 5 — Charts + Portal
|
|
272
|
-
|
|
273
|
-
> **Read first**: [tool-selection.md — portal_apply section](./tool-selection.md)
|
|
119
|
+
## Portal
|
|
274
120
|
|
|
275
|
-
|
|
121
|
+
Use `portal_apply` only after apps and view keys are read back. QingBI charts for the portal are created inline in `sections[].chart`; do not pre-create charts as a separate standard step.
|
|
276
122
|
|
|
277
|
-
|
|
123
|
+
Portal layout rules:
|
|
278
124
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
y=0, rows=4: 九宫格业务入口 (cols=24)
|
|
289
|
-
y=4, rows=3: 指标1(x=0,cols=6) 指标2(x=6,cols=6) 指标3(x=12,cols=6) 指标4(x=18,cols=6)
|
|
290
|
-
y=7, rows=8: 可视化图1(x=0,cols=12) 可视化图2(x=12,cols=12)
|
|
291
|
-
y=15, rows=8: 可视化图3(x=0,cols=12) 可视化图4(x=12,cols=12)
|
|
292
|
-
y=23, rows=8: 数据视图 (cols=24)
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
Same-row rule: all components at the same `y` must have identical `rows` and `cols` summing to 24.
|
|
125
|
+
- PC grid has 24 columns.
|
|
126
|
+
- Components in the same row must share the same `y` and `rows`.
|
|
127
|
+
- Same-row `cols` should sum to 24.
|
|
128
|
+
- Recommended order: business entry -> metric cards -> BI charts -> concrete data views.
|
|
129
|
+
- Business entry `grid` must contain real `config.items[]`; never submit an empty grid container.
|
|
130
|
+
- Metric cards: `rows=5`.
|
|
131
|
+
- BI charts: `rows=7`.
|
|
132
|
+
- Data views: `rows=11`.
|
|
133
|
+
- Do not use platform default views such as `全部数据` / `我的数据` as main portal data views.
|
|
296
134
|
|
|
297
135
|
```json
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
"
|
|
302
|
-
"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
"
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
{
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
"position": {"pc": {"x": 0, "y": 15, "cols": 12, "rows": 8}, "mobile": {"x": 0, "y": 32, "cols": 6, "rows": 8}},
|
|
352
|
-
"chart_ref": {"app_key": "OPPORTUNITY_APP_KEY", "chart_id": "VISUAL_CHART_ID_3"}
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
"title": "合同金额趋势",
|
|
356
|
-
"source_type": "chart",
|
|
357
|
-
"position": {"pc": {"x": 12, "y": 15, "cols": 12, "rows": 8}, "mobile": {"x": 0, "y": 40, "cols": 6, "rows": 8}},
|
|
358
|
-
"chart_ref": {"app_key": "CONTRACT_APP_KEY", "chart_id": "VISUAL_CHART_ID_4"}
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
"title": "客户列表",
|
|
362
|
-
"source_type": "view",
|
|
363
|
-
"position": {"pc": {"x": 0, "y": 23, "cols": 24, "rows": 8}, "mobile": {"x": 0, "y": 48, "cols": 6, "rows": 8}},
|
|
364
|
-
"view_ref": {"app_key": "CUSTOMER_APP_KEY", "view_key": "CUSTOMER_TABLE_VIEW_KEY"}
|
|
365
|
-
}
|
|
366
|
-
]
|
|
136
|
+
[
|
|
137
|
+
{
|
|
138
|
+
"title": "业务入口",
|
|
139
|
+
"source_type": "grid",
|
|
140
|
+
"position": {
|
|
141
|
+
"pc": {"x": 0, "y": 0, "cols": 24, "rows": 4},
|
|
142
|
+
"mobile": {"x": 0, "y": 0, "cols": 6, "rows": 4}
|
|
143
|
+
},
|
|
144
|
+
"config": {
|
|
145
|
+
"items": [
|
|
146
|
+
{"type": 1, "jumpMode": 1, "linkAppKey": "CUSTOMER_APP_KEY", "linkFormType": 1, "title": "客户"},
|
|
147
|
+
{"type": 1, "jumpMode": 1, "linkAppKey": "OPPORTUNITY_APP_KEY", "linkFormType": 1, "title": "商机"}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"title": "客户总数",
|
|
153
|
+
"source_type": "chart",
|
|
154
|
+
"role": "metric",
|
|
155
|
+
"position": {
|
|
156
|
+
"pc": {"x": 0, "y": 4, "cols": 6, "rows": 5},
|
|
157
|
+
"mobile": {"x": 0, "y": 4, "cols": 6, "rows": 5}
|
|
158
|
+
},
|
|
159
|
+
"chart": {
|
|
160
|
+
"app_key": "CUSTOMER_APP_KEY",
|
|
161
|
+
"name": "客户总数",
|
|
162
|
+
"chart_type": "target",
|
|
163
|
+
"metric": "count(*)"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"title": "客户状态分布",
|
|
168
|
+
"source_type": "chart",
|
|
169
|
+
"position": {
|
|
170
|
+
"pc": {"x": 0, "y": 9, "cols": 8, "rows": 7},
|
|
171
|
+
"mobile": {"x": 0, "y": 9, "cols": 6, "rows": 7}
|
|
172
|
+
},
|
|
173
|
+
"chart": {
|
|
174
|
+
"app_key": "CUSTOMER_APP_KEY",
|
|
175
|
+
"name": "客户状态分布",
|
|
176
|
+
"chart_type": "bar",
|
|
177
|
+
"group_by": ["客户状态"],
|
|
178
|
+
"metric": "count(*)"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"title": "客户跟进视图",
|
|
183
|
+
"source_type": "view",
|
|
184
|
+
"position": {
|
|
185
|
+
"pc": {"x": 0, "y": 16, "cols": 12, "rows": 11},
|
|
186
|
+
"mobile": {"x": 0, "y": 16, "cols": 6, "rows": 11}
|
|
187
|
+
},
|
|
188
|
+
"view_ref": {"app_key": "CUSTOMER_APP_KEY", "view_key": "CUSTOMER_VIEW_KEY"}
|
|
367
189
|
}
|
|
368
|
-
|
|
190
|
+
]
|
|
369
191
|
```
|
|
370
192
|
|
|
371
|
-
|
|
193
|
+
## Optional Resources
|
|
372
194
|
|
|
373
|
-
|
|
195
|
+
Only add workflow or associated resources when the user asks for them or the business process cannot work without them.
|
|
374
196
|
|
|
375
|
-
|
|
197
|
+
- Workflow: use `app_flow_apply` after schema fields exist.
|
|
198
|
+
- Associated resources: use `app_associated_resources_apply` after target views/charts exist.
|
|
376
199
|
|
|
377
|
-
|
|
200
|
+
Do not create workflow just to make the system look complete.
|
|
378
201
|
|
|
379
|
-
|
|
202
|
+
## Recovery
|
|
380
203
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
204
|
+
- Timeout, `partial_success`, `write_executed=true`, `safe_to_retry=false`, or incomplete readback means write state is uncertain, not definitely failed.
|
|
205
|
+
- Next action is always readback: package -> app resolve -> fields/views/portal as needed.
|
|
206
|
+
- Retry only verified missing or incorrect slices.
|
|
207
|
+
- Do not create `V2`, `测试`, timestamp, or random-suffix apps to bypass conflicts.
|
|
208
|
+
|
|
209
|
+
## Final Summary
|
|
210
|
+
|
|
211
|
+
Before final response, write `tmp/qingflow_system_build_summary.json` and make the response match it:
|
|
384
212
|
|
|
385
213
|
```json
|
|
386
214
|
{
|
|
387
|
-
"
|
|
388
|
-
"
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
{"客户名称": "杭州云计算公司", "客户类型": "企业", "客户状态": "已签约", "负责人": "李四", "累计合同金额": 800000}
|
|
397
|
-
]
|
|
398
|
-
}
|
|
215
|
+
"package_id": 0,
|
|
216
|
+
"package_name": "",
|
|
217
|
+
"portal_dash_key": "",
|
|
218
|
+
"portal_live_status": "verified | unverified | not_created",
|
|
219
|
+
"front_end_visible": true,
|
|
220
|
+
"apps": [],
|
|
221
|
+
"warnings": [],
|
|
222
|
+
"partial_items": [],
|
|
223
|
+
"needs_followup": []
|
|
399
224
|
}
|
|
400
225
|
```
|
|
401
226
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
## Phase 7 — Publish verify
|
|
227
|
+
Final response must state:
|
|
407
228
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
229
|
+
```text
|
|
230
|
+
已完成:...
|
|
231
|
+
未完成/未验证:...
|
|
232
|
+
前端可见:是/否/未确认
|
|
233
|
+
需要继续修复:是/否;原因...
|
|
412
234
|
```
|
|
413
|
-
|
|
414
|
-
---
|
|
415
|
-
|
|
416
|
-
## Common failures
|
|
417
|
-
|
|
418
|
-
| Error | Phase | Fix |
|
|
419
|
-
|-------|-------|-----|
|
|
420
|
-
| `VALIDATION_ERROR` on relation field | 1 | Read `message` verbatim first. Add `display_field` + `visible_fields` to the failing relation field. |
|
|
421
|
-
| Partial app batch failure | 1 | Only resubmit failed apps by `row_number`. Do not resubmit the entire batch. |
|
|
422
|
-
| `UNKNOWN_LAYOUT_FIELD` | 2 | Re-read fields with `app_get_fields`. Field name in `rows` must match exactly. |
|
|
423
|
-
| `FLOW_ASSIGNEE_REQUIRED` | 3 | Run `role_search` first. Assign at least one role to every approve/fill node. |
|
|
424
|
-
| `FLOW_DEPENDENCY_MISSING` | 3 | Fix schema first, then retry flow. |
|
|
425
|
-
| View `partial_success` | 4 | Check `verification.view_query_conditions_verified`. Read `views_diff.failed`. |
|
|
426
|
-
| Portal height mismatch or blank space | 5 | All components at the same `y` must have identical `rows` and `cols` summing to 24. |
|
|
427
|
-
| `PORTAL_CHART_CARD_TOO_SMALL` | 5 | Indicator cards: `rows ≥ 3`. Visual charts: `rows ≥ 6`. |
|
|
428
|
-
| Relation field has no candidates on insert | 6 | The referenced app has no records yet. Insert that app's records first, then retry. |
|