openxiangda 1.0.76 → 1.0.78
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 -1
- package/lib/cli.js +320 -10
- package/openxiangda-skills/SKILL.md +11 -9
- package/openxiangda-skills/references/automation-v3.md +17 -1
- package/openxiangda-skills/references/connector-resources.md +4 -1
- package/openxiangda-skills/references/data-views.md +23 -9
- package/openxiangda-skills/references/pages/page-sdk.md +15 -0
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +88 -19
- package/openxiangda-skills/references/workflow-v3.md +17 -1
- package/openxiangda-skills/skills/openxiangda-app/SKILL.md +7 -5
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +7 -4
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +9 -9
- package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +2 -2
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +19 -16
- package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +4 -4
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +27 -8
- package/package.json +1 -1
- package/packages/sdk/dist/components/index.cjs +1120 -1098
- package/packages/sdk/dist/components/index.cjs.map +1 -1
- package/packages/sdk/dist/components/index.mjs +857 -841
- package/packages/sdk/dist/components/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/index.cjs +1031 -989
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +18 -1
- package/packages/sdk/dist/runtime/index.d.ts +18 -1
- package/packages/sdk/dist/runtime/index.mjs +788 -752
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/templates/openxiangda-react-spa/src/main.tsx +9 -1
- package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +8 -2
- package/templates/sy-lowcode-app-workspace/tsconfig.js-code-nodes.json +5 -1
|
@@ -254,6 +254,22 @@ Supported node types:
|
|
|
254
254
|
|
|
255
255
|
Use trusted Node JS_CODE nodes for AI/admin automation logic that runs after an automation trigger. Typical cases include scheduled data cleanup, date-field reminders, cross-form synchronization after submit/update/delete, workflow-completed follow-up writes, calling internal platform APIs, calling external HTTP services, and other backend-only orchestration.
|
|
256
256
|
|
|
257
|
+
For reusable backend logic that should be shared by pages, multiple automations, and workflows, prefer an App Function under `src/functions/<functionCode>/index.ts` plus `src/resources/functions/<functionCode>.json`. Automation graphs can call it with a `function_call` node:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"id": "call_summary",
|
|
262
|
+
"type": "function_call",
|
|
263
|
+
"data": {
|
|
264
|
+
"functionCode": "reservation_reminder_summary",
|
|
265
|
+
"input": { "scope": "today" },
|
|
266
|
+
"saveResponseTo": "summary"
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Use JS_CODE V2 when the script is local to one automation graph node.
|
|
272
|
+
|
|
257
273
|
```json
|
|
258
274
|
{
|
|
259
275
|
"id": "sync_customer",
|
|
@@ -275,7 +291,7 @@ Author source in `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.
|
|
|
275
291
|
|
|
276
292
|
The backend runs the snapshot in the trusted Node runtime, applies the node timeout (`30000` ms by default), stores execution logs, and writes the returned value to the node output and `variables.node_<nodeId>`. Scripts may use `export default async function (ctx) {}`, `module.exports = async (ctx) => {}`, `require`, `process`, `Buffer`, arbitrary HTTP, and `platform.api` for `/openxiangda-api/v1`.
|
|
277
293
|
|
|
278
|
-
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`.
|
|
294
|
+
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`. Prefer the higher-level resource helpers when available: `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryMany/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, `ctx.connector.call/invoke`, `ctx.notification.*`, and `ctx.platform.api.*`. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData`, `queryManyData`, `updateOneData`, `updateDataByFormInstanceId`, `updateManyData`, `createOneData`, `terminateProcess`, and `getAllParentDepartments`.
|
|
279
295
|
|
|
280
296
|
Code automation also exposes `ctx.logger.debug/info/warn/error(message, data?)`. AI-authored code should log input parsing, query conditions, external calls, writes, branch decisions, and caught errors. Logs are stored as full raw execution data by default. Use CLI diagnosis commands:
|
|
281
297
|
|
|
@@ -11,6 +11,7 @@ Common folders:
|
|
|
11
11
|
- `workflows`
|
|
12
12
|
- `automations`
|
|
13
13
|
- `data-views`
|
|
14
|
+
- `functions`
|
|
14
15
|
- `permissions/page-groups`
|
|
15
16
|
- `permissions/form-groups`
|
|
16
17
|
- `settings/forms`
|
|
@@ -28,7 +29,9 @@ Connector manifests use stable `code` values. The platform maps connector `code`
|
|
|
28
29
|
|
|
29
30
|
Notification manifests live under `src/resources/notifications/` and contain `templates` plus `typeConfigs`. See `notifications.md` before generating reminders or message templates.
|
|
30
31
|
|
|
31
|
-
Data view manifests live under `src/resources/data-views/` and define read-only materialized
|
|
32
|
+
Data view manifests live under `src/resources/data-views/` and define read-only joined or aggregate query resources. Use `storageMode: "materialized"` for refreshed lists/reports where lag is acceptable, and `storageMode: "live"` for bounded real-time query shapes. Use row views with `sdk.dataView.query` and aggregate views with `sdk.dataView.stats`. Before generating one, confirm freshness tolerance, query bounds, and indexes for materialized filters/sort fields/dimensions/date buckets. Do not use them for single-form CRUD, simple linkedForm selects, writes, write-back, or ad-hoc BI. See `data-views.md` before generating one.
|
|
33
|
+
|
|
34
|
+
App Function manifests live under `src/resources/functions/`, with source in `src/functions/<functionCode>/index.ts`. Use them for reusable server-side logic that pages, automations, and workflows can share through `sdk.function.invoke` or `function_call` nodes. App Functions expose controlled runtime helpers such as `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, and `ctx.platform.api`; they do not expose raw SQL or Redis in the current MVP. Use JS_CODE V2 only for node-local workflow/automation scripts.
|
|
32
35
|
|
|
33
36
|
```json
|
|
34
37
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Data View Resources
|
|
2
2
|
|
|
3
|
-
Data views are OpenXiangda-managed read-only PostgreSQL materialized views.
|
|
3
|
+
Data views are OpenXiangda-managed read-only query resources under `src/resources/data-views/`. They can run as PostgreSQL materialized views (`storageMode: "materialized"`, the default) or as live logical views (`storageMode: "live"`). Use them to publish repeated multi-form joins and predefined aggregate statistics as reusable app resources.
|
|
4
4
|
|
|
5
5
|
Use a data view when the app needs read-only joined data from multiple forms, such as:
|
|
6
6
|
|
|
@@ -10,13 +10,14 @@ Use a data view when the app needs read-only joined data from multiple forms, su
|
|
|
10
10
|
- Dashboard statistics such as monthly ticket count, order amount by customer, or task count by status.
|
|
11
11
|
- Reusable lookup or report data consumed by several pages or automations.
|
|
12
12
|
- Large list pages where repeated client-side cross-form joins would be slow or inconsistent.
|
|
13
|
+
- Real-time multi-form reads where the query shape is fixed and the source data volume is bounded (`storageMode: "live"`).
|
|
13
14
|
|
|
14
15
|
Do not use a data view for:
|
|
15
16
|
|
|
16
17
|
- Single-form CRUD. Use `sdk.form.advancedSearch`, form pages, or `DataManagementList`.
|
|
17
18
|
- Simple one-form dropdown options. Use `SelectField` with `optionSource.type: "linkedForm"`.
|
|
18
19
|
- Writes or write-back. Data views are read-only.
|
|
19
|
-
-
|
|
20
|
+
- Heavy real-time joins that cannot be paginated, indexed, filtered, or otherwise bounded.
|
|
20
21
|
- Raw SQL, incremental refresh, source-table trigger refresh, ad-hoc BI/pivot/window analysis, or write-heavy realtime dashboards.
|
|
21
22
|
|
|
22
23
|
## Authoring
|
|
@@ -25,8 +26,13 @@ Place manifests in `src/resources/data-views/*.json`. Use logical `formCode` val
|
|
|
25
26
|
|
|
26
27
|
Two view types are supported:
|
|
27
28
|
|
|
28
|
-
- `viewType: "row"` or omitted: row-level joined
|
|
29
|
-
- `viewType: "aggregate"`: grouped statistics
|
|
29
|
+
- `viewType: "row"` or omitted: row-level joined view using `select`.
|
|
30
|
+
- `viewType: "aggregate"`: grouped statistics view using `dimensions` and `measures`; query it with `stats`.
|
|
31
|
+
|
|
32
|
+
Two storage modes are supported:
|
|
33
|
+
|
|
34
|
+
- `storageMode: "materialized"` or omitted: create a PostgreSQL materialized view. Results may be stale until manual or scheduled refresh. Use `indexes` for common filters, sort fields, aggregate dimensions, and date buckets.
|
|
35
|
+
- `storageMode: "live"`: do not create a materialized view. Every query is compiled and executed against source forms in real time. `indexes` are ignored and refresh APIs do not apply. Use it only for bounded real-time query shapes.
|
|
30
36
|
|
|
31
37
|
Row view example:
|
|
32
38
|
|
|
@@ -34,6 +40,7 @@ Row view example:
|
|
|
34
40
|
{
|
|
35
41
|
"code": "ticket_with_customer",
|
|
36
42
|
"name": "Ticket With Customer",
|
|
43
|
+
"storageMode": "materialized",
|
|
37
44
|
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
38
45
|
"joins": [
|
|
39
46
|
{
|
|
@@ -74,6 +81,7 @@ Aggregate statistics example:
|
|
|
74
81
|
"code": "ticket_stats_by_customer",
|
|
75
82
|
"name": "Ticket Stats By Customer",
|
|
76
83
|
"viewType": "aggregate",
|
|
84
|
+
"storageMode": "materialized",
|
|
77
85
|
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
78
86
|
"joins": [
|
|
79
87
|
{
|
|
@@ -144,9 +152,11 @@ Filters:
|
|
|
144
152
|
|
|
145
153
|
Refresh:
|
|
146
154
|
|
|
155
|
+
- Refresh applies only to materialized data views.
|
|
147
156
|
- `manual` means refresh only when an administrator runs refresh or the resource is recreated.
|
|
148
157
|
- `scheduled` uses cron, for example `0 */10 * * * *`.
|
|
149
|
-
-
|
|
158
|
+
- Materialized query results may be stale. Show or inspect `lastRefreshedAt` when freshness matters.
|
|
159
|
+
- Live data views have no refresh state; `lastRefreshedAt` is `null` and refresh requests should be rejected.
|
|
150
160
|
- Do not choose a high-frequency schedule by default. Ask or infer how stale the data may be before setting `scheduled`.
|
|
151
161
|
|
|
152
162
|
Indexes:
|
|
@@ -159,11 +169,12 @@ Indexes:
|
|
|
159
169
|
|
|
160
170
|
## Performance And Freshness
|
|
161
171
|
|
|
162
|
-
|
|
172
|
+
Materialized data views move expensive joins and aggregations from page runtime to refresh time. Live data views keep results current by executing the same declared query shape on each request. Both modes reduce repeated page code complexity only when the view shape, data scope, and query bounds are chosen deliberately.
|
|
163
173
|
|
|
164
174
|
Before creating a data view, confirm these points:
|
|
165
175
|
|
|
166
176
|
- **Freshness tolerance**: ask whether users need near-real-time data, 10-30 minute freshness, hourly/daily reports, or manual snapshots.
|
|
177
|
+
- **Storage mode**: use `materialized` for read-heavy reports that tolerate refresh lag; use `live` for bounded real-time joins where source-table changes must appear immediately.
|
|
167
178
|
- **Query shape**: list the fields users will filter, sort, group, or drill down by. These should become output aliases and usually indexes.
|
|
168
179
|
- **Data scope**: if the business only needs active, recent, or in-scope records, put that rule in definition `where` so old/source-irrelevant rows are filtered before materialization.
|
|
169
180
|
- **Visible fields**: output only fields the page or permission rules need. Use hidden scope aliases for data permissions when needed, but do not build one huge catch-all view.
|
|
@@ -174,11 +185,12 @@ Refresh cadence guidance:
|
|
|
174
185
|
- Use `scheduled` every 10-30 minutes for normal dashboards, joined report lists, and recurring management views.
|
|
175
186
|
- Use hourly or daily schedules for leadership reports, historical statistics, and large aggregate views.
|
|
176
187
|
- Avoid intervals below 5 minutes unless the user explicitly confirms the time sensitivity and expected source-table volume. High-frequency refreshes can pressure both source tables and the materialized view.
|
|
177
|
-
- For strong real-time behavior after each form save,
|
|
188
|
+
- For strong real-time behavior after each form save, use `storageMode: "live"` only when the query is bounded. If the logic includes writes, side effects, raw platform orchestration, or expensive unbounded joins, use source-form queries, App Functions, or a different backend workflow instead.
|
|
178
189
|
|
|
179
190
|
Index guidance:
|
|
180
191
|
|
|
181
|
-
-
|
|
192
|
+
- For materialized mode, index only output aliases, not source references such as `customer.name`.
|
|
193
|
+
- Live data views ignore `indexes`; keep their runtime filters and page size conservative.
|
|
182
194
|
- For row views, index IDs used in drill-down (`ticketId`, `customerId`) and common filters/order fields (`statusValue`, `ownerId`, `createdAt`).
|
|
183
195
|
- For aggregate views, index the dimensions/time buckets used in runtime `filters`, `having` drill-downs, and `order` (`customerId`, `statusValue`, `createdMonth`).
|
|
184
196
|
- Keep compound indexes aligned with common query prefixes. For example, dashboard filters by customer then month should use `["customerId", "createdMonth"]`.
|
|
@@ -219,7 +231,7 @@ Diagnostic commands:
|
|
|
219
231
|
```bash
|
|
220
232
|
openxiangda data-view list --profile dev
|
|
221
233
|
openxiangda data-view status ticket_with_customer --profile dev
|
|
222
|
-
openxiangda data-view refresh ticket_with_customer --profile dev
|
|
234
|
+
openxiangda data-view refresh ticket_with_customer --profile dev # materialized only
|
|
223
235
|
openxiangda data-view query ticket_with_customer --profile dev --fields ticketId,customerName
|
|
224
236
|
openxiangda data-view query ticket_with_customer --profile dev --query-json query.json
|
|
225
237
|
openxiangda data-view stats ticket_stats_by_customer --profile dev --fields customerName,ticketCount
|
|
@@ -228,6 +240,8 @@ openxiangda data-view stats ticket_stats_by_customer --profile dev --query-json
|
|
|
228
240
|
|
|
229
241
|
## Runtime SDK
|
|
230
242
|
|
|
243
|
+
`sdk.dataView.query` and `sdk.dataView.stats` work for both materialized and live data views. Responses include `storageMode`; materialized responses may include `lastRefreshedAt`, while live responses return current data and `lastRefreshedAt: null`.
|
|
244
|
+
|
|
231
245
|
Direct query:
|
|
232
246
|
|
|
233
247
|
```ts
|
|
@@ -7,9 +7,11 @@ Guidelines:
|
|
|
7
7
|
- Do not hardcode `/openxiangda-api` calls inside end-user page components unless the page is explicitly an admin tool.
|
|
8
8
|
- Prefer SDK modules for form data, user context, permissions, and platform navigation.
|
|
9
9
|
- Use `sdk.dataView.query` for published read-only multi-form row data views. Use `sdk.dataView.stats` for aggregate data views declared with `viewType: "aggregate"`.
|
|
10
|
+
- Data views can be `storageMode: "materialized"` for refreshed report/list data or `storageMode: "live"` for bounded real-time joins. Page code calls the same SDK methods for both modes and should inspect `response.storageMode` / `response.lastRefreshedAt` when freshness is visible to users.
|
|
10
11
|
- Data view runtime queries can filter, sort, paginate, and select only output aliases.
|
|
11
12
|
- Keep data view page calls paginated and field-scoped. Runtime filters/order should use aliases that the data view indexes, especially for aggregate dimensions and date buckets.
|
|
12
13
|
- Use `sdk.dataSource.run()` with a page data source descriptor when the page config should own the data view code, default fields, or default filters.
|
|
14
|
+
- Use `sdk.function.invoke(code, { input })` for reusable backend business logic declared under `src/resources/functions/` and `src/functions/`. Do not implement multi-form orchestration, connector fan-out, notification orchestration, or permission-sensitive backend rules directly in a page component.
|
|
13
15
|
- Use `sdk.connector.invoke`, `sdk.connector.call("connector.api")`, or `sdk.connector.download` for external services. The SDK calls the platform runtime connector endpoint; it must not call third-party domains directly.
|
|
14
16
|
- Use `sdk.notification.sendByType` and `batchSendByType` for reusable business messages. Custom notification types must be declared in `src/resources/notifications/` and published with `openxiangda resource publish`.
|
|
15
17
|
- For the current user's department hierarchy, use `sdk.department.getCurrentUserParentDepartments()`; do not hardcode `GET /department/:id/parentDepartments` in page code.
|
|
@@ -87,6 +89,19 @@ const response = await sdk.dataSource.run("tickets", {
|
|
|
87
89
|
|
|
88
90
|
Data view filters, having, and fields use output aliases such as `customerName` or `ticketCount`, not source references such as `customer.name`. If the page only needs one form, prefer `sdk.form.advancedSearch`. If the page only needs a simple one-form dropdown, prefer linkedForm options.
|
|
89
91
|
|
|
92
|
+
App Function invocation:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const result = await sdk.function.invoke("reservation_reminder_summary", {
|
|
96
|
+
input: {
|
|
97
|
+
scope: "today",
|
|
98
|
+
keyword,
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Use App Functions when the logic must run server-side and be reusable by pages, automations, or workflows. Current runtime invocation requires the caller to have app automation management permission; ordinary page users should normally consume function-backed data through a permission-aware page or a narrower backend resource.
|
|
104
|
+
|
|
90
105
|
Logout and current-user role switching:
|
|
91
106
|
|
|
92
107
|
```ts
|
|
@@ -66,13 +66,15 @@ const data = await sdk.connector.call("crm.getCustomer", { body: { keyword } });
|
|
|
66
66
|
- 多表只读联表列表 / lookup / 报表明细:用行级 data view,页面调用 `sdk.dataView.query`。
|
|
67
67
|
- 固定口径统计 / 看板指标 / 图表数据源:用 `viewType: "aggregate"`,页面调用 `sdk.dataView.stats`。
|
|
68
68
|
- ECharts 或自定义 dashboard 只负责展示;统计口径稳定时,数据源优先沉淀成 aggregate data view。
|
|
69
|
-
-
|
|
70
|
-
-
|
|
69
|
+
- 默认 `storageMode: "materialized"`,适合读多写少和可接受刷新延迟的列表/报表;发布前为常用筛选、排序、维度和时间桶声明 `indexes`。
|
|
70
|
+
- `storageMode: "live"` 每次查询实时执行,适合强实时但数据量可控的固定复杂查询;live 模式忽略 `indexes` 且不能 refresh。
|
|
71
|
+
- 不用于单表 CRUD、简单 `linkedForm` 下拉、写回、无边界重查询或临时 BI 查询。
|
|
71
72
|
|
|
72
73
|
```json
|
|
73
74
|
{
|
|
74
75
|
"code": "ticket_with_customer",
|
|
75
76
|
"name": "Ticket With Customer",
|
|
77
|
+
"storageMode": "materialized",
|
|
76
78
|
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
77
79
|
"joins": [
|
|
78
80
|
{
|
|
@@ -137,7 +139,7 @@ const stats = await sdk.dataView.stats("ticket_stats_by_customer", {
|
|
|
137
139
|
});
|
|
138
140
|
```
|
|
139
141
|
|
|
140
|
-
性能要点:索引只能引用输出 alias;行级视图索引常用 filter/order 字段;聚合视图索引 dimensions/date buckets;`countDistinct` 和高基数维度刷新成本较高;低于 5 分钟的 scheduled refresh
|
|
142
|
+
性能要点:索引只能引用输出 alias;行级视图索引常用 filter/order 字段;聚合视图索引 dimensions/date buckets;`countDistinct` 和高基数维度刷新成本较高;低于 5 分钟的 scheduled refresh 需要用户明确确认时间敏感度。live 视图不刷新、不建索引,必须控制字段、过滤和分页。完整规则见 [`data-views.md`](data-views.md)。
|
|
141
143
|
|
|
142
144
|
## 3. Notification — `src/resources/notifications/<code>.json`
|
|
143
145
|
|
|
@@ -178,7 +180,69 @@ await sdk.notification.sendByType({
|
|
|
178
180
|
|
|
179
181
|
JS_CODE 调用:`ctx.notification.sendByType({ ... })`。允许的 channels:`inapp` / `email` / `dingding` / `wechat` / `thirdparty_todo`。完整规则见 [`notifications.md`](notifications.md)。
|
|
180
182
|
|
|
181
|
-
## 4.
|
|
183
|
+
## 4. App Function — `src/resources/functions/<functionCode>.json` + `src/functions/<functionCode>/index.ts`
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"code": "reservation_reminder_summary",
|
|
188
|
+
"name": "Reservation Reminder Summary",
|
|
189
|
+
"sourceFile": { "localPath": "src/functions/reservation_reminder_summary/index.ts" },
|
|
190
|
+
"runtimeMode": "trusted_node",
|
|
191
|
+
"timeout": 30000,
|
|
192
|
+
"resources": {
|
|
193
|
+
"forms": ["reservation_order"],
|
|
194
|
+
"dataViews": ["reservation_order_overview"],
|
|
195
|
+
"connectors": ["crm"]
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
// src/functions/reservation_reminder_summary/index.ts
|
|
202
|
+
export default async function reservationReminderSummary(ctx, input) {
|
|
203
|
+
const orders = await ctx.form.queryMany({
|
|
204
|
+
formCode: "reservation_order",
|
|
205
|
+
filters: [{ field: "status", operator: "=", value: "pending" }],
|
|
206
|
+
pageSize: 50,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const overview = await ctx.dataView.query("reservation_order_overview", {
|
|
210
|
+
pageSize: 20,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
pendingCount: orders.totalCount || orders.data?.length || 0,
|
|
215
|
+
overview: overview.data || [],
|
|
216
|
+
input,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
调用方式:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
const result = await sdk.function.invoke("reservation_reminder_summary", {
|
|
225
|
+
input: { scope: "today" },
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
自动化 / 流程图节点调用:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"id": "call_summary",
|
|
234
|
+
"type": "function_call",
|
|
235
|
+
"data": {
|
|
236
|
+
"functionCode": "reservation_reminder_summary",
|
|
237
|
+
"input": { "scope": "today" },
|
|
238
|
+
"saveResponseTo": "summary"
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
适用边界:可复用后端业务逻辑、跨页面/自动化/流程共享的查询编排、连接器调用、通知编排、受控平台 API 调用。当前 MVP 不暴露原始 SQL/Redis;运行时接口需要应用自动化管理权限,自动化/流程内部调用走服务端上下文。
|
|
244
|
+
|
|
245
|
+
## 5. Workflow — `src/resources/workflows/<code>/workflow.json`(manifest)+ `src/workflows/<code>/workflow.ts`(代码优先)
|
|
182
246
|
|
|
183
247
|
```jsonc
|
|
184
248
|
// src/resources/workflows/customer_approval/workflow.json
|
|
@@ -208,7 +272,7 @@ export default defineWorkflow({
|
|
|
208
272
|
|
|
209
273
|
CLI 编译为 `definition.v3.json` + `preview.json`,平台运行时仍走标准工作流引擎。完整规则见 [`workflow-v3.md`](workflow-v3.md)。
|
|
210
274
|
|
|
211
|
-
##
|
|
275
|
+
## 6. Automation — `src/resources/automations/<code>/{definition.code.json,preview.json}` + `src/automations/<code>/index.ts`
|
|
212
276
|
|
|
213
277
|
```jsonc
|
|
214
278
|
// src/resources/automations/notify_on_submit/definition.code.json
|
|
@@ -242,17 +306,18 @@ export default async function (ctx) {
|
|
|
242
306
|
|
|
243
307
|
`trigger_v2` 事件源:`form_data` / `form_field` / `workflow_task` / `workflow_process` / `mode: "scheduled"`(fixed_time / form_date_field)。完整规则见 [`automation-v3.md`](automation-v3.md)。
|
|
244
308
|
|
|
245
|
-
##
|
|
309
|
+
## 7. JS_CODE V2 — `src/js-code-nodes/<scriptCode>/index.ts`
|
|
310
|
+
|
|
311
|
+
JS_CODE V2 适合自动化/流程图里的节点级脚本。跨页面、跨自动化、需要一个稳定后端入口的可复用逻辑优先写 App Function,再用 `function_call` 节点或 `sdk.function.invoke` 调用。
|
|
246
312
|
|
|
247
313
|
```ts
|
|
248
314
|
export default async function (ctx) {
|
|
249
|
-
const { formData, operator,
|
|
250
|
-
const result = await
|
|
315
|
+
const { formData, operator, form, dataView, connector, notification, platform, utils, console } = ctx;
|
|
316
|
+
const result = await form.queryMany({
|
|
251
317
|
formCode: "customer",
|
|
252
|
-
|
|
253
|
-
searchCondition: [/* 查询条件 */],
|
|
318
|
+
filters: [/* 查询条件 */],
|
|
254
319
|
});
|
|
255
|
-
return { count: result.length };
|
|
320
|
+
return { count: result.totalCount || result.data?.length || 0 };
|
|
256
321
|
}
|
|
257
322
|
```
|
|
258
323
|
|
|
@@ -275,7 +340,9 @@ export default async function (ctx) {
|
|
|
275
340
|
|
|
276
341
|
构建:`pnpm build-js-code --script sync_customer`(先 `tsc` 再打包到 `dist/js-code-nodes/<code>/index.cjs`)。CLI validate/create/publish 时会上传快照、用 `{ bucketName, objectName, sha256 }` 替换 `sourceFile.localPath`。
|
|
277
342
|
|
|
278
|
-
|
|
343
|
+
`ctx.methods.*` 仍可用于兼容旧脚本;新脚本优先使用 `ctx.resources`、`ctx.form`、`ctx.dataView`、`ctx.connector`、`ctx.notification` 和 `ctx.platform.api`。
|
|
344
|
+
|
|
345
|
+
## 8. Role — `src/resources/roles/<code>.json`
|
|
279
346
|
|
|
280
347
|
```json
|
|
281
348
|
{
|
|
@@ -284,7 +351,7 @@ export default async function (ctx) {
|
|
|
284
351
|
}
|
|
285
352
|
```
|
|
286
353
|
|
|
287
|
-
##
|
|
354
|
+
## 9. Page Permission Group — `src/resources/permissions/page-groups/<code>.json`
|
|
288
355
|
|
|
289
356
|
```json
|
|
290
357
|
{
|
|
@@ -298,7 +365,7 @@ export default async function (ctx) {
|
|
|
298
365
|
|
|
299
366
|
`formCodes` / `pageCodes` / `menuCodes` 留空表示对匹配角色全部可见。
|
|
300
367
|
|
|
301
|
-
##
|
|
368
|
+
## 10. Form Permission Group — `src/resources/permissions/form-groups/<formCode>/<groupCode>.json`
|
|
302
369
|
|
|
303
370
|
```json
|
|
304
371
|
{
|
|
@@ -321,7 +388,7 @@ export default async function (ctx) {
|
|
|
321
388
|
}
|
|
322
389
|
```
|
|
323
390
|
|
|
324
|
-
##
|
|
391
|
+
## 11. Form Settings — `src/resources/settings/forms/<formCode>.json`
|
|
325
392
|
|
|
326
393
|
```json
|
|
327
394
|
{
|
|
@@ -339,7 +406,7 @@ export default async function (ctx) {
|
|
|
339
406
|
}
|
|
340
407
|
```
|
|
341
408
|
|
|
342
|
-
##
|
|
409
|
+
## 12. Menu — `src/resources/menus/<code>.json`
|
|
343
410
|
|
|
344
411
|
```json
|
|
345
412
|
{
|
|
@@ -359,16 +426,17 @@ export default async function (ctx) {
|
|
|
359
426
|
```text
|
|
360
427
|
需要展示数据?
|
|
361
428
|
├─ 单表 CRUD → 表单页 + DataManagementList(不要 data view)
|
|
362
|
-
├─ 多表只读联表 → src/resources/data-views
|
|
429
|
+
├─ 多表只读联表 → src/resources/data-views/(materialized 或 live)
|
|
363
430
|
├─ 表单字段下拉 → SelectField + optionSource.type: "linkedForm"(不要 data view)
|
|
364
431
|
└─ 大屏 / 报表 → 原生报表 → ECharts page
|
|
365
432
|
|
|
366
433
|
需要后端逻辑?
|
|
367
434
|
├─ 真有审批 → workflow(src/workflows/<code>/workflow.ts)
|
|
368
435
|
├─ 状态流转 → 表单 status 字段 + 状态机 + automation
|
|
436
|
+
├─ 可复用服务逻辑 → App Function(src/functions/<code>/index.ts + function_call / sdk.function.invoke)
|
|
369
437
|
├─ 提交/字段触发 → automation(trigger_v2 + src/automations/<code>/index.ts)
|
|
370
438
|
├─ 定时任务 → automation(mode: "scheduled")
|
|
371
|
-
└─
|
|
439
|
+
└─ 流程/自动化节点内脚本 → JS_CODE V2 trusted_node(src/js-code-nodes/<code>/index.ts)
|
|
372
440
|
|
|
373
441
|
需要外部数据?
|
|
374
442
|
├─ 第三方 HTTP → src/resources/connectors/ + sdk.connector.call
|
|
@@ -380,5 +448,6 @@ export default async function (ctx) {
|
|
|
380
448
|
- ❌ 把 `formUuid` / `pageId` 等平台 ID 写进 manifest。**用 code,CLI 自动解析。**
|
|
381
449
|
- ❌ 把 API key、token、密码写进 manifest。**用占位符,平台后台填真实值。**
|
|
382
450
|
- ❌ 同时在 manifest 与平台后台编辑同一个资源(漂移源)。**统一以 manifest 为单一来源**,需要看平台版本就 `resource pull`。
|
|
383
|
-
- ❌ 用 data view 代替 `linkedForm` 下拉、单表 CRUD 或写回。**data view
|
|
451
|
+
- ❌ 用 data view 代替 `linkedForm` 下拉、单表 CRUD 或写回。**data view 是只读;materialized 有刷新延迟,live 要控制查询边界。**
|
|
452
|
+
- ❌ 把跨页面/跨流程复用的后端逻辑都塞进 JS_CODE。**优先 App Function,JS_CODE 只做节点内脚本。**
|
|
384
453
|
- ❌ 在 page 源码里 hardcode `/api/notification-config/*` 或 `/connectors/actions/invoke`。**用 `sdk.notification` / `sdk.connector`。**
|
|
@@ -135,7 +135,23 @@ File snapshot:
|
|
|
135
135
|
|
|
136
136
|
AI-authored JS_CODE source must be TypeScript under `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.ts`. When validating or creating, the CLI runs `pnpm build-js-code --script <scriptCode>`, which runs TypeScript validation first, bundles to `dist/js-code-nodes/<scriptCode>/index.cjs`, uploads the bundle, and replaces `sourceFile.localPath` with immutable snapshot metadata. The backend verifies snapshot `sha256`, runs it in the trusted Node runtime, applies the node timeout (`30000` ms by default), stores execution logs, and writes the returned value to the node output and `variables.node_<nodeId>`.
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
For reusable backend logic that should be shared by pages, automations, and workflows, prefer an App Function under `src/functions/<functionCode>/index.ts` plus `src/resources/functions/<functionCode>.json`. Workflow graphs that support App Function nodes can call it with:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"id": "call_summary",
|
|
143
|
+
"type": "function_call",
|
|
144
|
+
"data": {
|
|
145
|
+
"functionCode": "reservation_reminder_summary",
|
|
146
|
+
"input": { "scope": "process" },
|
|
147
|
+
"saveResponseTo": "summary"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Use JS_CODE V2 when the script is local to one workflow node.
|
|
153
|
+
|
|
154
|
+
Scripts can export `export default async function (ctx) {}` or `module.exports = async (ctx) => {}`. The runtime exposes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.platform.api.*`, `ctx.utils`, `require`, `process`, and `Buffer`. Prefer `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryMany/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, and `ctx.connector.call/invoke` for platform-side work. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData/queryManyData/updateOneData/updateDataByFormInstanceId/updateManyData/createOneData/terminateProcess/getAllParentDepartments`.
|
|
139
155
|
|
|
140
156
|
Example `src/js-code-nodes/sync_customer/index.ts`:
|
|
141
157
|
|
|
@@ -99,7 +99,7 @@ openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
|
99
99
|
- Do not search platform apps or reuse similar app names unless the user explicitly asks to reuse an existing app or gives an `appType`.
|
|
100
100
|
- Store platform-specific IDs only in `.openxiangda/state.json`.
|
|
101
101
|
- Use logical local codes for forms, pages, workflows, automations, and menus.
|
|
102
|
-
- Before scaffolding a new business app, read
|
|
102
|
+
- Before scaffolding a new business app, read `references/best-practices.md` and pick an architecture from the initialized `examples/best-practices/` catalog. Do not generate a large single-file app page when a template pattern already covers the scenario.
|
|
103
103
|
- For Phase 6 React SPA apps, use `--runtime react-spa`. The generated app owns routing/layouts/menus with React Router and Tailwind CSS; platform permissions still come from backend runtime bootstrap and route checks.
|
|
104
104
|
- React SPA form publish is schema-only by default. Do not add OSS credentials or old embedded form bundles unless explicitly maintaining legacy compatibility with `--legacy-form-bundle`.
|
|
105
105
|
- When publishing after app edits, prefer targeted commands (`workspace publish --changed --dry-run`, then `--changed`, `--page`, `--form`, or `--only`). Do not publish all forms/pages just because one page changed.
|
|
@@ -107,10 +107,12 @@ openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
|
107
107
|
|
|
108
108
|
## Resource State
|
|
109
109
|
|
|
110
|
-
Read
|
|
110
|
+
Read `references/workspace-state.md` when changing `.openxiangda/state.json`.
|
|
111
111
|
|
|
112
|
-
Read
|
|
112
|
+
Read `references/openxiangda-api.md` when exact endpoint fields are needed.
|
|
113
113
|
|
|
114
|
-
Read
|
|
114
|
+
Read `references/resource-manifest-cheatsheet.md` before creating shared resources such as data views, connectors, notifications, App Functions, workflows, automations, permissions, settings, or menus.
|
|
115
115
|
|
|
116
|
-
Read
|
|
116
|
+
Read `references/architecture-patterns.md` to understand the overall app structure (how forms, pages, menus, workflows, and permissions compose into an app, and the recommended `src/forms` / `src/pages` layout) before scaffolding or restructuring an app workspace.
|
|
117
|
+
|
|
118
|
+
Read `references/best-practices.md` before implementing app-level patterns such as status lifecycles, role governance, PC/mobile portals, high-performance data management pages, workflow boundaries, and automation.
|
|
@@ -287,7 +287,10 @@ It is responsible for:
|
|
|
287
287
|
|
|
288
288
|
## References
|
|
289
289
|
|
|
290
|
-
-
|
|
291
|
-
-
|
|
292
|
-
-
|
|
293
|
-
-
|
|
290
|
+
- `references/openxiangda-api.md` — exact endpoint contracts.
|
|
291
|
+
- `references/workspace-state.md` — `.openxiangda/state.json` shape and profile-scoped resource maps.
|
|
292
|
+
- `references/resource-manifest-cheatsheet.md` — quick templates for connectors, data views, App Functions, workflows, automations, permissions, settings, and menus.
|
|
293
|
+
- `references/data-views.md` — materialized/live data view authoring, refresh behavior, permissions, indexes, and runtime SDK usage.
|
|
294
|
+
- `references/connector-resources.md` — engineering resource folders, connector usage, App Function boundary, and platform runtime calls.
|
|
295
|
+
- `references/architecture-patterns.md` — overall architecture of an OpenXiangda app workspace (CRUD data flow, page/form layering, recommended directory organization). Read this when you need to understand how forms, pages, workflows, and platform state fit together end-to-end.
|
|
296
|
+
- `references/best-practices.md` — initialized best-practice templates and rules for modular pages, status lifecycles, role governance, data isolation, query performance, and workflow boundaries.
|
|
@@ -110,12 +110,12 @@ Do not use `openxiangda form create` as the normal way to generate a user-facing
|
|
|
110
110
|
|
|
111
111
|
Read these references only when writing or reviewing schema:
|
|
112
112
|
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
113
|
+
- `references/forms/form-schema.md`
|
|
114
|
+
- `references/forms/component-registry.md`
|
|
115
|
+
- `references/forms/layout-and-rules.md`
|
|
116
|
+
- `references/platform-data-model.md` — how each field type is persisted (JSONB, `{label, value}` for option fields, attachment shape). Consult before designing schema or wiring values.
|
|
117
|
+
- `references/component-guide.md` — platform component first, `antd` / `antd-mobile` fallback, and native-control ban for AI-authored app code.
|
|
118
|
+
- `references/best-practices.md` — status lifecycle fields, ownership redundancy, role-governance fields, and the boundary between normal forms and workflow forms.
|
|
119
119
|
|
|
120
120
|
## Rules
|
|
121
121
|
|
|
@@ -133,13 +133,13 @@ Read these references only when writing or reviewing schema:
|
|
|
133
133
|
- Do not copy `formUuid` from dev to prod unless the target platform explicitly already uses that ID.
|
|
134
134
|
- Keep `schema.ts` and `page.tsx` as the source for fields/layout/rules and presentation; generated build output is not the source of truth.
|
|
135
135
|
- In `schema.ts`, import `defineFormSchema` from `openxiangda` and default-export the schema.
|
|
136
|
-
- Treat `schema.ts` as the field/component contract. Prefer platform field components listed in
|
|
136
|
+
- Treat `schema.ts` as the field/component contract. Prefer platform field components listed in `references/forms/component-registry.md`; do not replace them with raw JSX controls in `page.tsx`.
|
|
137
137
|
- Keep `page.tsx` presentation-only. It may customize layout, wrappers, sections, or routing, but should render a complete OpenXiangda standard form/runtime rather than assembling isolated raw controls.
|
|
138
138
|
- If a platform field is missing for a real business need, submit feedback with `openxiangda feedback submit --yes` and then use an `antd` / `antd-mobile` wrapper as a local workaround. Report the workaround and fingerprint to the user.
|
|
139
139
|
- Put validation on field-level `rules`; never generate old top-level validation arrays under `schema.rules`. Top-level `rules` is only for `FormEffect[]` with `when` and `then`.
|
|
140
|
-
- Always provide `options` for option components. `SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, and `CascadeSelectField` must not be emitted with `options` undefined. See
|
|
140
|
+
- Always provide `options` for option components. `SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, and `CascadeSelectField` must not be emitted with `options` undefined. See `references/component-guide.md` for the full list and `references/platform-data-model.md` for the `{label, value}` storage contract.
|
|
141
141
|
- Do not emit raw native form controls in app/workspace source. For basic entry use `TextField`, `TextAreaField`, `NumberField`, `DateField`, `SelectField`, `RadioField`, etc.; for platform-specific entry use `UserSelectField`, `DepartmentSelectField`, `AttachmentField`, `ImageField`, `EditorField`, `DigitalSignatureField`, and `LocationField`.
|
|
142
142
|
- Workflow form pages use the same workspace form structure plus workflow v3 configuration. In legacy workspaces, publish the form page bundle through workspace publish before treating it as complete. In React SPA workspaces, `workspace publish --form` syncs schema only, and the SPA default process pages render through `runtime deploy`.
|
|
143
143
|
- After editing one form, use `workspace publish --form <formCode>` or preview `--changed --dry-run`; do not run full workspace publish by default.
|
|
144
144
|
- Use `openxiangda form pull` or app snapshot before overwriting an existing form.
|
|
145
|
-
- Before assuming a value shape (e.g. dates, attachments, member fields, option fields), verify against
|
|
145
|
+
- Before assuming a value shape (e.g. dates, attachments, member fields, option fields), verify against `references/platform-data-model.md` instead of guessing.
|
|
@@ -59,6 +59,6 @@ Use logical local codes first. If a code is missing from `.openxiangda/state.jso
|
|
|
59
59
|
|
|
60
60
|
## References
|
|
61
61
|
|
|
62
|
-
-
|
|
63
|
-
-
|
|
62
|
+
- `references/platform-data-model.md` — how each field type is persisted on the platform (JSONB, `{label, value}` for option fields, attachment shape, etc.). Consult this when a snapshot value looks unexpected so you can tell broken data from normal storage format.
|
|
63
|
+
- `references/troubleshooting.md` — catalog of known failure modes (missing styles, `options` runtime errors, mismatched option labels, etc.). Cross-check inspection findings against this list before reporting an issue or proposing a fix.
|
|
64
64
|
|