openxiangda 1.0.131 → 1.0.133
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 +46 -1
- package/lib/cli.js +390 -82
- package/openxiangda-skills/SKILL.md +7 -5
- package/openxiangda-skills/references/connector-resources.md +1 -1
- package/openxiangda-skills/references/notifications.md +86 -0
- package/openxiangda-skills/references/openxiangda-api.md +149 -0
- package/openxiangda-skills/references/pages/page-sdk.md +37 -0
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +16 -1
- package/openxiangda-skills/references/workflow-v3.md +1 -1
- package/package.json +1 -1
- package/packages/sdk/dist/components/index.cjs +3 -3
- package/packages/sdk/dist/components/index.cjs.map +1 -1
- package/packages/sdk/dist/components/index.mjs +3 -3
- package/packages/sdk/dist/components/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/index.cjs +203 -30
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +1 -1
- package/packages/sdk/dist/runtime/index.d.ts +1 -1
- package/packages/sdk/dist/runtime/index.mjs +203 -30
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +200 -27
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.d.mts +226 -3
- package/packages/sdk/dist/runtime/react.d.ts +226 -3
- package/packages/sdk/dist/runtime/react.mjs +200 -27
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
- package/packages/sdk/src/build-source/scripts/sync-schema.mjs +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda
|
|
3
|
-
description: "Use OpenXiangda for any private low-code platform or sy-lowcode-app-workspace work: architecture design, app creation, forms, pages, resources, workflows, automations, JS_CODE, permissions, data views, connectors, notifications, publishing, deployment, diagnosis, feedback, profile/login state, and CLI commands. Trigger on OpenXiangda, 享搭, 私有化低代码, 低代码平台, .openxiangda/state.json, app-workspace.config.ts, or openxiangda CLI usage."
|
|
3
|
+
description: "Use OpenXiangda for any private low-code platform or sy-lowcode-app-workspace work: architecture design, app creation, forms, pages, resources, workflows, automations, JS_CODE, permissions, organization/account management, data views, connectors, notifications, publishing, deployment, diagnosis, feedback, profile/login state, and CLI commands. Trigger on OpenXiangda, 享搭, 私有化低代码, 低代码平台, .openxiangda/state.json, app-workspace.config.ts, or openxiangda CLI usage."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda
|
|
@@ -30,6 +30,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
|
|
|
30
30
|
| App Function / function_call / 可复用后端逻辑 | `openxiangda-workflow-automation` | declare `src/resources/functions/<code>.json` + `src/functions/<code>/index.ts` |
|
|
31
31
|
| 应用登录 / Auth SDK / 手机号验证码 / CAS / 钉钉免登 | `openxiangda-architecture-design` + `openxiangda-page` | design security gate first, then declare `src/resources/auth/<code>.json` and use `createAuthClient` / `LoginPage` |
|
|
32
32
|
| 角色 / 权限组 / 字段权限 / 数据范围 | `openxiangda-permission-settings` | `openxiangda permission ...` / `openxiangda settings ...` |
|
|
33
|
+
| 平台部门 / 平台账号 / 重置密码 / 组织账号管理 | `openxiangda-architecture-design` + `openxiangda-page` | check `openxiangda organization capabilities --json`; use `sdk.organization` / `ctx.organization` only after `app:organization:manage` is granted |
|
|
33
34
|
| 外部人员无需登录访问 / 公开报名 / 公开查询 / public page | `openxiangda-architecture-design` + `openxiangda-permission-settings` + `openxiangda-page` | 先确认公开范围、外部角色、ticket、grants;再声明 `routes` + `public-access`,并用 `OpenXiangdaProvider` + `OpenXiangdaPageProvider` + `PublicAccessGate` |
|
|
34
35
|
| 看应用结构 / 快照 / 对比 / 诊断 / 排查 / 报错 | `openxiangda-inspect` | `openxiangda app snapshot <APP_XXX> --profile <name> --json` |
|
|
35
36
|
| 登录 / 切换平台 / profile / token / whoami | `openxiangda-core` | `openxiangda env --profile <name>` / `openxiangda auth status` |
|
|
@@ -48,7 +49,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
|
|
|
48
49
|
- ✅ For app login/auth requirements, run the auth security gate before coding: enabled methods, registration policy, identity matching keys, provider boundary, default roles, rate limits, audit fields, and third-party ownership must be confirmed.
|
|
49
50
|
- ✅ For public/no-login access requirements, run the public access design gate before coding: public routes, external role codes, guest vs ticket, form/dataView/function/connector grants, backend permission groups, and visible loading/error fallback states must be confirmed. New React SPA apps use `/view/:appType/public/*`, `src/resources/routes/`, `src/resources/public-access/`, and `PublicAccessGate`; route children that use Page SDK hooks must be inside `OpenXiangdaProvider` + `OpenXiangdaPageProvider`.
|
|
50
51
|
- ✅ Public/no-login validation must inspect the JSON envelope, not only HTTP status. HTTP 200 with `code: "PUBLIC_GRANT_DENIED"` is a denied request; success requires `code` `200`, `"200"`, or compatible `0`, and no `success: false`.
|
|
51
|
-
- ✅ Use first-class resource CLI commands for discovery, diagnosis, and small live fixes: `route`, `public-access`, `auth-config`, `function`, `connector`, `notification`, `data-view`, `menu`, and `permission`. For multi-resource formal development, still prefer `src/resources/**` + `openxiangda resource validate|plan|publish`. If a direct CLI write is intentionally used, add `--write-manifest` when the repository should stay the source of truth.
|
|
52
|
+
- ✅ Use first-class resource CLI commands for discovery, diagnosis, and small live fixes: `route`, `public-access`, `auth-config`, `function`, `connector`, `notification`, `organization`, `data-view`, `menu`, and `permission`. For multi-resource formal development, still prefer `src/resources/**` + `openxiangda resource validate|plan|publish`. If a direct CLI write is intentionally used, add `--write-manifest` when the repository should stay the source of truth.
|
|
52
53
|
- ✅ For form-entry UX, pick components in this order: OpenXiangda platform form components → `antd` / `antd-mobile` wrappers → custom component only when neither exists.
|
|
53
54
|
- ✅ In React SPA apps, keep imports on public package entrypoints such as `openxiangda`, `openxiangda/runtime`, and `openxiangda/runtime/react`. The default template already groups large vendor chunks; if a bundle is too large, use route-level lazy loading and Vite `manualChunks`, not `openxiangda/packages/sdk/dist/...` internal paths.
|
|
54
55
|
- ✅ For image thumbnails or lightweight previews, use `imageCompression` on `ImageField` or `AttachmentField`. Keep the original `url` for the source file and use `thumbUrl` / `previewUrl` / `variants` for smaller images.
|
|
@@ -154,7 +155,8 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
154
155
|
- Put engineering-managed resources in `src/resources/` and use `openxiangda resource validate|plan|publish|pull`. `workspace publish` publishes workspace forms/pages first, then runs non-destructive resource upsert. Only pass `--prune` when the user explicitly wants local manifests to delete platform-side extras.
|
|
155
156
|
- For repeated read-only multi-form queries or predefined dashboard metrics, create a data view manifest in `src/resources/data-views/`. Use `storageMode: "materialized"` for refreshed lists/reports that tolerate delay; use `storageMode: "live"` for bounded real-time joins where source changes must appear immediately. Use row views plus `sdk.dataView.query` for joined lists/lookups; use `viewType: "aggregate"` plus `sdk.dataView.stats` for count/sum/avg/min/max statistics. Add `indexes` only for materialized views. Do not use data views for single-form CRUD, simple linkedForm selects, writes, write-back, unbounded realtime joins, or ad-hoc BI. Read `references/data-views.md` before designing one.
|
|
156
157
|
- For external APIs, create a connector manifest in `src/resources/connectors/` and call it from pages through `sdk.connector`; never put third-party API keys in page source.
|
|
157
|
-
- For reusable backend logic shared by pages, automations, and workflows, create an App Function in `src/resources/functions/<functionCode>.json` plus `src/functions/<functionCode>/index.ts`. Call it from pages with `sdk.function.invoke`, from automation/workflow graphs with `function_call`, or from the runtime endpoint when the caller has app automation management permission. Current App Function MVP exposes controlled helpers such as `ctx.resources`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, and `ctx.platform.api`; it does not expose raw SQL or Redis. Runtime functions also receive trusted role context on `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, and `ctx.permissions`; use these for server-side business authorization. Do not trust role codes sent in page input for sensitive actions. App Function form writes are trusted backend writes governed by declared `resources.forms` and function invocation authorization; do not grant normal users raw submit permission to internal forms just to let `ctx.form.createOne/updateOne/updateById` run.
|
|
158
|
+
- For reusable backend logic shared by pages, automations, and workflows, create an App Function in `src/resources/functions/<functionCode>.json` plus `src/functions/<functionCode>/index.ts`. Call it from pages with `sdk.function.invoke`, from automation/workflow graphs with `function_call`, or from the runtime endpoint when the caller has app automation management permission. Current App Function MVP exposes controlled helpers such as `ctx.resources`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, and `ctx.platform.api`; it does not expose raw SQL or Redis. Runtime functions also receive trusted role context on `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, and `ctx.permissions`; use these for server-side business authorization. Do not trust role codes sent in page input for sensitive actions. App Function form writes are trusted backend writes governed by declared `resources.forms` and function invocation authorization; do not grant normal users raw submit permission to internal forms just to let `ctx.form.createOne/updateOne/updateById` run.
|
|
159
|
+
- For app-managed platform departments/accounts, use `sdk.organization.departments.*`, `sdk.organization.accounts.*`, `ctx.organization.departments.*`, or `ctx.organization.accounts.*`. The real current user/audit actor must hold `app:organization:manage` on the app; runtime service principals do not bypass this permission. Do not call legacy `/user` or `/department` write endpoints from apps. Do not include `password` in account updates; reset target accounts with `resetPassword`, and change the current user's password with `changeMyPassword({ oldPassword, newPassword })`.
|
|
158
160
|
- For application login, declare auth resources in `src/resources/auth/<code>.json` and publish them with `openxiangda resource publish`. App Function auth providers may validate external credentials and return only an identity assertion; they must never issue tokens, set cookies, or write platform user/binding tables directly. The platform auth service decides create/bind/reject and issues tokens.
|
|
159
161
|
- For external/no-login pages in React SPA apps, declare `src/resources/routes/<code>.json` and `src/resources/public-access/<code>.json`, put the page under `/view/:appType/public/*`, and use `PublicAccessGate` or `createPublicAccessClient`. The route tree must also include `OpenXiangdaPageProvider` inside `OpenXiangdaProvider` before any `usePageSdk()` / `usePageContext()` / `useDataSource()` call; otherwise pages throw `usePageSdkStore 必须在 PageProvider 内使用`. Always provide `fallback` and `errorFallback` for public routes so slow networks, missing tickets, or expired tickets do not render blank pages. Public guest access to forms, dataViews, functions, and connectors is denied unless policy `grants` explicitly names the resource; backend permission groups still apply.
|
|
160
162
|
- When verifying public access, parse the response body and reject string business errors such as `PUBLIC_GRANT_DENIED` even if the HTTP status is 200. Do not use `response.ok` alone as the success condition.
|
|
@@ -194,7 +196,7 @@ Load these references on demand instead of memorizing them. Subskills cite the s
|
|
|
194
196
|
|
|
195
197
|
Core CLI / state:
|
|
196
198
|
|
|
197
|
-
- `references/openxiangda-api.md` — `/openxiangda-api/v1` request and response fields.
|
|
199
|
+
- `references/openxiangda-api.md` — `/openxiangda-api/v1` request and response fields, including app-scoped organization APIs.
|
|
198
200
|
- `references/architecture-design.md` — OpenXiangda architecture design gate, anti-pattern rejection, question gates, final design template, and black-box demo scenario.
|
|
199
201
|
- `references/workspace-state.md` — `.openxiangda/state.json` shape and profile isolation rules.
|
|
200
202
|
- `references/connector-resources.md` — `src/resources` manifests, connector schema, App Function boundary, and platform runtime calls.
|
|
@@ -212,7 +214,7 @@ Form authoring:
|
|
|
212
214
|
Page authoring:
|
|
213
215
|
|
|
214
216
|
- `references/pages/workspace-structure.md` — `src/pages/<pageCode>/` layout and config.
|
|
215
|
-
- `references/pages/page-sdk.md` — `openxiangda/runtime` data, connector, data view, notification, and App Function APIs.
|
|
217
|
+
- `references/pages/page-sdk.md` — `openxiangda/runtime` data, connector, data view, notification, organization, and App Function APIs.
|
|
216
218
|
- `references/pages/publish-flow.md` — workspace publish steps for code pages.
|
|
217
219
|
|
|
218
220
|
Workflow / automation / permissions:
|
|
@@ -32,7 +32,7 @@ Notification manifests live under `src/resources/notifications/` and contain `te
|
|
|
32
32
|
|
|
33
33
|
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.
|
|
34
34
|
|
|
35
|
-
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.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, and `ctx.platform.api`; they do not expose raw SQL or Redis in the current MVP. Runtime page invocations also expose trusted role context on `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, and `ctx.permissions`; use that context for server-side authorization, and never trust page-submitted role codes for sensitive actions. App Function form writes are trusted backend writes governed by declared `resources.forms` and function invocation authorization, not by direct page-user submit access to the target form. Use JS_CODE V2 only for node-local workflow/automation scripts.
|
|
35
|
+
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.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, and `ctx.platform.api`; they do not expose raw SQL or Redis in the current MVP. Runtime page invocations also expose trusted role context on `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, and `ctx.permissions`; use that context for server-side authorization, and never trust page-submitted role codes for sensitive actions. App Function form writes are trusted backend writes governed by declared `resources.forms` and function invocation authorization, not by direct page-user submit access to the target form. App Function organization writes require `app:organization:manage` on the real operator/audit actor. Use JS_CODE V2 only for node-local workflow/automation scripts.
|
|
36
36
|
|
|
37
37
|
Auth manifests live under `src/resources/auth/`. Use them to enable app-level login methods and bind phone-code/CAS/custom providers to App Functions. Auth provider functions are called only by the platform auth flow. They validate external credentials and return identity assertions such as `phone`, `email`, `externalId`, or `unionId`; they must not issue tokens, set cookies, or mutate platform user/binding tables.
|
|
38
38
|
|
|
@@ -45,6 +45,62 @@ Allowed channels: `inapp`, `email`, `dingding`, `wechat`, `thirdparty_todo`.
|
|
|
45
45
|
|
|
46
46
|
Do not include `token`, `secret`, `password`, `authorization`, `auth`, `credential`, or `headers` fields. Platform admins configure channel credentials outside resources.
|
|
47
47
|
|
|
48
|
+
## DingTalk Cards
|
|
49
|
+
|
|
50
|
+
DingTalk notifications prefer cards by default when the tenant has a default card template configured. Application resources should not include `appKey`, `appSecret`, or `agentId`; only override non-secret card settings when the app owns a custom DingTalk card.
|
|
51
|
+
|
|
52
|
+
Standard card example:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"channelsConfig": {
|
|
57
|
+
"dingding": {
|
|
58
|
+
"enabled": true,
|
|
59
|
+
"content": "{{title}}",
|
|
60
|
+
"config": {
|
|
61
|
+
"deliveryMode": "card_preferred",
|
|
62
|
+
"fallbackToWorkNotice": true,
|
|
63
|
+
"card": {
|
|
64
|
+
"mode": "standard",
|
|
65
|
+
"cardTemplateId": "${DINGTALK_CARD_TEMPLATE_ID}",
|
|
66
|
+
"title": "{{title}}",
|
|
67
|
+
"summary": "{{content}}",
|
|
68
|
+
"jumpUrl": "{{detailUrl}}",
|
|
69
|
+
"fieldConfigs": [
|
|
70
|
+
{ "fieldId": "ticketNo", "label": "工单号", "order": 1, "required": false }
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Delivery modes:
|
|
80
|
+
|
|
81
|
+
- `card_preferred`: send a DingTalk card first, then fallback to a work notification if card delivery fails.
|
|
82
|
+
- `card_only`: card failure is a send failure.
|
|
83
|
+
- `work_notice_only`: send only a DingTalk work notification.
|
|
84
|
+
|
|
85
|
+
Custom cards use the variables defined in the DingTalk developer console:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"deliveryMode": "card_only",
|
|
90
|
+
"card": {
|
|
91
|
+
"mode": "custom",
|
|
92
|
+
"cardTemplateId": "${DINGTALK_TICKET_CARD_ID}",
|
|
93
|
+
"paramMap": {
|
|
94
|
+
"title": "{{title}}",
|
|
95
|
+
"ticketNo": "{{ticketNo}}",
|
|
96
|
+
"status": "{{status}}"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Standard card payload variables include `title`, `lastMessage`, `content`, `contentList`, `jumpUrl`, `createTime`, `status`, `operator`, `currentUser`, `formData.current`, `workflowData`, `variables`, and `app`. General notifications do not show approval buttons by default.
|
|
103
|
+
|
|
48
104
|
## Runtime Calls
|
|
49
105
|
|
|
50
106
|
Code pages:
|
|
@@ -61,6 +117,27 @@ await sdk.notification.sendByType({
|
|
|
61
117
|
});
|
|
62
118
|
```
|
|
63
119
|
|
|
120
|
+
DingTalk-specific helpers are available when the caller wants to inspect or force the DingTalk channel:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const capabilities = await sdk.notification.capabilities();
|
|
124
|
+
|
|
125
|
+
const preview = await sdk.notification.previewDingTalk({
|
|
126
|
+
notificationType: "reservation_reminder",
|
|
127
|
+
payload: {
|
|
128
|
+
title: "预约提醒",
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await sdk.notification.sendDingTalk({
|
|
133
|
+
notificationType: "reservation_reminder",
|
|
134
|
+
recipientId: userId,
|
|
135
|
+
payload: {
|
|
136
|
+
title: "预约提醒",
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
64
141
|
User-facing in-app message centers should read the platform inbox instead of
|
|
65
142
|
creating app-specific message/log forms:
|
|
66
143
|
|
|
@@ -86,6 +163,10 @@ CLI smoke tests:
|
|
|
86
163
|
|
|
87
164
|
```bash
|
|
88
165
|
openxiangda notification preview reservation_reminder --body-json '{"payload":{"title":"测试"}}'
|
|
166
|
+
openxiangda notification capabilities --json
|
|
167
|
+
openxiangda notification dingding-preview reservation_reminder --body-json '{"payload":{"title":"测试"}}'
|
|
168
|
+
openxiangda notification dingding-preview --template-code reservation_reminder --body-json '{"payload":{"title":"测试"}}'
|
|
169
|
+
openxiangda notification dingding-send reservation_reminder --body-json '{"recipientId":"USER_ID","payload":{"title":"测试"}}' --force
|
|
89
170
|
openxiangda notification send reservation_reminder --body-json '{"recipientId":"USER_ID","payload":{"title":"测试"}}' --force
|
|
90
171
|
openxiangda notification batch-send reservation_reminder --body-json '{"recipients":[{"recipientId":"USER_ID","payload":{"title":"测试"}}]}' --force
|
|
91
172
|
```
|
|
@@ -103,6 +184,11 @@ export default async function notify(ctx) {
|
|
|
103
184
|
startTime: ctx.formData.current.start_time,
|
|
104
185
|
},
|
|
105
186
|
});
|
|
187
|
+
|
|
188
|
+
await ctx.notification.previewDingTalk({
|
|
189
|
+
notificationType: "reservation_reminder",
|
|
190
|
+
payload: { title: "预约提醒" },
|
|
191
|
+
});
|
|
106
192
|
}
|
|
107
193
|
```
|
|
108
194
|
|
|
@@ -318,6 +318,7 @@ Requires Bearer token. Updates menu sorting and parent relationships in batch.
|
|
|
318
318
|
### POST `/apps/:appType/notifications/send-by-type`
|
|
319
319
|
|
|
320
320
|
Requires Bearer token. Sends a notification in the current app scope.
|
|
321
|
+
Each returned message can include `deliveryMeta` with provider message id, outTrackId, card template id, fallback usage, and provider error summary.
|
|
321
322
|
|
|
322
323
|
```json
|
|
323
324
|
{
|
|
@@ -360,6 +361,45 @@ Requires app admin permission. Upserts an app/form notification template by code
|
|
|
360
361
|
### POST `/apps/:appType/notifications/templates/preview`
|
|
361
362
|
|
|
362
363
|
Requires Bearer token. Body uses `templateCode` or `templateId` plus `payload`. The CLI command is `openxiangda notification preview <templateCode> --body-json '{"payload":{...}}'`.
|
|
364
|
+
If DingTalk is enabled, the response includes `dingding.cardPreview` with `resolvedCardTemplateId`, `cardParamMap`, `outTrackId`, `workNoticeContent`, `missingVariables`, and `warnings`.
|
|
365
|
+
|
|
366
|
+
### GET `/apps/:appType/notifications/dingtalk/capabilities`
|
|
367
|
+
|
|
368
|
+
Requires Bearer token. Returns whether the tenant DingTalk channel is enabled, whether app credentials/agent/default card template are configured, and supported delivery/card modes.
|
|
369
|
+
|
|
370
|
+
### POST `/apps/:appType/notifications/dingtalk/preview`
|
|
371
|
+
|
|
372
|
+
Requires Bearer token. Body can use a notification binding:
|
|
373
|
+
|
|
374
|
+
```json
|
|
375
|
+
{
|
|
376
|
+
"notificationType": "reservation_reminder",
|
|
377
|
+
"payload": {
|
|
378
|
+
"title": "预约提醒"
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
or a direct DingTalk config:
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
{
|
|
387
|
+
"config": {
|
|
388
|
+
"deliveryMode": "card_preferred",
|
|
389
|
+
"card": {
|
|
390
|
+
"mode": "standard",
|
|
391
|
+
"title": "{{title}}"
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
"payload": {
|
|
395
|
+
"title": "预约提醒"
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### POST `/apps/:appType/notifications/dingtalk/send`
|
|
401
|
+
|
|
402
|
+
Requires Bearer token. Sends the resolved `notificationType` through the DingTalk channel only. The CLI command is `openxiangda notification dingding-send <notificationType> --body-json '{"recipientId":"USER_ID","payload":{"title":"测试"}}' --force`.
|
|
363
403
|
|
|
364
404
|
### GET `/apps/:appType/notifications/type-configs`
|
|
365
405
|
|
|
@@ -373,6 +413,115 @@ Requires Bearer token. Resolves the active binding by notification type and opti
|
|
|
373
413
|
|
|
374
414
|
Requires app admin permission. Upserts a binding with `templateCode` or `templateId`.
|
|
375
415
|
|
|
416
|
+
## Organization
|
|
417
|
+
|
|
418
|
+
Organization APIs are app-scoped and require `app:organization:manage` on the target app. Platform admins pass through the same permission service. Runtime service principals are not accepted by themselves: trusted runtime calls must carry a real audit actor, and permission is checked against that user.
|
|
419
|
+
|
|
420
|
+
Use these endpoints for OpenXiangda app-managed platform departments and accounts. Do not use legacy `/user` or `/department` write endpoints for new app organization management.
|
|
421
|
+
|
|
422
|
+
### GET `/apps/:appType/organization/capabilities`
|
|
423
|
+
|
|
424
|
+
Requires Bearer token. Returns whether the current actor can manage organization data for the app, the permission code, and supported operations.
|
|
425
|
+
|
|
426
|
+
CLI:
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
openxiangda organization capabilities --json
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### GET `/apps/:appType/organization/departments`
|
|
433
|
+
|
|
434
|
+
Requires `app:organization:manage`. Lists platform departments in the current tenant.
|
|
435
|
+
|
|
436
|
+
### GET `/apps/:appType/organization/departments/:departmentId`
|
|
437
|
+
|
|
438
|
+
Requires `app:organization:manage`. Returns one platform department.
|
|
439
|
+
|
|
440
|
+
### POST `/apps/:appType/organization/departments`
|
|
441
|
+
|
|
442
|
+
Requires `app:organization:manage`. Creates a platform department and runs existing org cache invalidation.
|
|
443
|
+
|
|
444
|
+
```json
|
|
445
|
+
{
|
|
446
|
+
"name": "销售部",
|
|
447
|
+
"parentId": "optional-parent-id",
|
|
448
|
+
"externalId": "optional-external-id",
|
|
449
|
+
"corpId": "optional-corp-id",
|
|
450
|
+
"visibilityScope": "public",
|
|
451
|
+
"memberViewScope": "self_and_children",
|
|
452
|
+
"supervisorUserIds": ["user-1"]
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
CLI:
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
openxiangda organization department-create --body-json '{"name":"销售部"}' --force
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### POST `/apps/:appType/organization/departments/:departmentId`
|
|
463
|
+
|
|
464
|
+
Requires `app:organization:manage`. Updates department metadata, visibility/member scopes, and supervisors.
|
|
465
|
+
|
|
466
|
+
### GET `/apps/:appType/organization/accounts`
|
|
467
|
+
|
|
468
|
+
Requires `app:organization:manage`. Lists tenant platform accounts. Supports `ids`, `departmentIds`, `keyword`, `name`, `username`, `phone`, `email`, `jobNumber`, `page`, and `pageSize`.
|
|
469
|
+
|
|
470
|
+
### GET `/apps/:appType/organization/accounts/:userId`
|
|
471
|
+
|
|
472
|
+
Requires `app:organization:manage`. Returns one platform account. Password, login failure counters, and lock fields are removed from the response.
|
|
473
|
+
|
|
474
|
+
### POST `/apps/:appType/organization/accounts`
|
|
475
|
+
|
|
476
|
+
Requires `app:organization:manage`. Creates a platform account.
|
|
477
|
+
|
|
478
|
+
```json
|
|
479
|
+
{
|
|
480
|
+
"id": "optional-user-id",
|
|
481
|
+
"username": "alice",
|
|
482
|
+
"password": "initial-password",
|
|
483
|
+
"name": "Alice",
|
|
484
|
+
"phone": "13800000000",
|
|
485
|
+
"email": "alice@example.com",
|
|
486
|
+
"jobNumber": "E001",
|
|
487
|
+
"departmentIds": ["dept-1"],
|
|
488
|
+
"affiliatedDepartmentId": "dept-1",
|
|
489
|
+
"validFrom": "2026-07-01T00:00:00.000Z",
|
|
490
|
+
"validTo": null
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### POST `/apps/:appType/organization/accounts/:userId`
|
|
495
|
+
|
|
496
|
+
Requires `app:organization:manage`. Updates account fields except password. If `password` is present, the request is rejected; use the dedicated password endpoint.
|
|
497
|
+
|
|
498
|
+
### POST `/apps/:appType/organization/accounts/:userId/password/reset`
|
|
499
|
+
|
|
500
|
+
Requires `app:organization:manage`. Resets the target account password, writes the existing sha512 password hash, and clears `failedLoginAttempts`, `lockUntil`, and `lockReason`.
|
|
501
|
+
|
|
502
|
+
```json
|
|
503
|
+
{
|
|
504
|
+
"newPassword": "new-password"
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
CLI:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
openxiangda organization account-reset-password user-1 --body-json '{"newPassword":"new-password"}' --force
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### POST `/apps/:appType/organization/accounts/me/password/change`
|
|
515
|
+
|
|
516
|
+
Requires `app:organization:manage` for the current real user. Validates `oldPassword` before changing the current user's password.
|
|
517
|
+
|
|
518
|
+
```json
|
|
519
|
+
{
|
|
520
|
+
"oldPassword": "old-password",
|
|
521
|
+
"newPassword": "new-password"
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
376
525
|
### GET `/apps/:appType/workflows`
|
|
377
526
|
|
|
378
527
|
Requires Bearer token. Lists workflow definitions in the app. Supports `formUuid`, `isPublished`, `page`, and `pageSize` query parameters.
|
|
@@ -16,6 +16,7 @@ Guidelines:
|
|
|
16
16
|
- 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.
|
|
17
17
|
- 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.
|
|
18
18
|
- 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`.
|
|
19
|
+
- Use `sdk.organization.departments.*` and `sdk.organization.accounts.*` only for admin-style app pages that intentionally manage platform departments/accounts. The current user needs `app:organization:manage` on the app. Do not call legacy `/user` or `/department` write endpoints from pages.
|
|
19
20
|
- Use `sdk.workCenter.listItems({ boxType })` and `sdk.workCenter.getStats()` for current-user work center lists and counts. `boxType` is one of `todo`, `done`, `cc`, or `initiated`. This is the end-user task/handled/cc/initiated surface; do not build todo pages by reading workflow operation logs, automation logs, or raw process-task tables.
|
|
20
21
|
- Use `createAuthClient` from `openxiangda/runtime` or `LoginPage` / `useAuth` from `openxiangda/runtime/react` for application login pages. Auth provider App Functions return identity assertions only; platform auth owns create/bind/reject/token decisions.
|
|
21
22
|
- Use `PublicAccessGate` from `openxiangda/runtime/react` or `createPublicAccessClient` from `openxiangda/runtime` for React SPA public pages under `/view/:appType/public/*`. Do not append old `?publicAccess=guest` links in new apps.
|
|
@@ -113,6 +114,42 @@ same value is also available as `ctx.input` for compatibility.
|
|
|
113
114
|
|
|
114
115
|
Use App Functions when the logic must run server-side and be reusable by pages, automations, or workflows. Runtime invocation requires app automation management permission by default. To let ordinary app users call a function from a page, declare the allowed current app roles in `definitionJson.runtimeInvoke.roleCodes`; keep sensitive admin-only functions without broad grants. Inside the function, authorize sensitive actions with trusted runtime context such as `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, or `ctx.permissions`; do not trust role codes sent in the page input. When the function writes forms with `ctx.form.createOne/updateOne/updateById`, treat the write as a trusted backend operation over declared `resources.forms`; do not open direct submit permission on internal forms just for that page action.
|
|
115
116
|
|
|
117
|
+
Organization management:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const capabilities = await sdk.organization.capabilities()
|
|
121
|
+
if (!capabilities.result?.canManage) {
|
|
122
|
+
throw new Error("当前用户缺少组织账号管理权限")
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await sdk.organization.departments.create({
|
|
126
|
+
name: "销售部",
|
|
127
|
+
parentId: rootDepartmentId,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const accounts = await sdk.organization.accounts.list({
|
|
131
|
+
keyword,
|
|
132
|
+
departmentIds: [rootDepartmentId],
|
|
133
|
+
page: 1,
|
|
134
|
+
pageSize: 20,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
await sdk.organization.accounts.create({
|
|
138
|
+
username: "alice",
|
|
139
|
+
password: initialPassword,
|
|
140
|
+
name: "Alice",
|
|
141
|
+
jobNumber: "E001",
|
|
142
|
+
departmentIds: [rootDepartmentId],
|
|
143
|
+
affiliatedDepartmentId: rootDepartmentId,
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
await sdk.organization.accounts.resetPassword("alice", {
|
|
147
|
+
newPassword,
|
|
148
|
+
})
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Use `ctx.organization.departments.*` and `ctx.organization.accounts.*` inside App Functions or trusted JS nodes for the same capability. Runtime service principals must resolve a real operator/audit actor; permission is checked against that user, not against the runtime service account. Keep password changes on dedicated endpoints: update account metadata with `update`, reset another user's password with `resetPassword`, and change the current user's password with `changeMyPassword({ oldPassword, newPassword })`.
|
|
152
|
+
|
|
116
153
|
Work center:
|
|
117
154
|
|
|
118
155
|
```ts
|
|
@@ -423,7 +423,20 @@ const stats = await sdk.dataView.stats("ticket_stats_by_customer", {
|
|
|
423
423
|
"variables": ["title", "instrumentName", "startTime"],
|
|
424
424
|
"channelsConfig": {
|
|
425
425
|
"inapp": { "enabled": true, "content": "{{instrumentName}} 将于 {{startTime}} 开始" },
|
|
426
|
-
"dingding": {
|
|
426
|
+
"dingding": {
|
|
427
|
+
"enabled": true,
|
|
428
|
+
"content": "{{title}}",
|
|
429
|
+
"config": {
|
|
430
|
+
"deliveryMode": "card_preferred",
|
|
431
|
+
"fallbackToWorkNotice": true,
|
|
432
|
+
"card": {
|
|
433
|
+
"mode": "standard",
|
|
434
|
+
"title": "{{title}}",
|
|
435
|
+
"summary": "{{instrumentName}} 将于 {{startTime}} 开始",
|
|
436
|
+
"jumpUrl": "{{detailUrl}}"
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
427
440
|
}
|
|
428
441
|
}
|
|
429
442
|
],
|
|
@@ -450,6 +463,8 @@ await sdk.notification.sendByType({
|
|
|
450
463
|
|
|
451
464
|
JS_CODE 调用:`ctx.notification.sendByType({ ... })`。允许的 channels:`inapp` / `email` / `dingding` / `wechat` / `thirdparty_todo`。完整规则见 [`notifications.md`](notifications.md)。
|
|
452
465
|
|
|
466
|
+
钉钉卡片预览/发送:`sdk.notification.previewDingTalk({ notificationType, payload })`、`sdk.notification.sendDingTalk({ notificationType, recipientId, payload })`;CLI 为 `openxiangda notification dingding-preview` 和 `openxiangda notification dingding-send --force`。
|
|
467
|
+
|
|
453
468
|
## 4. App Function — `src/resources/functions/<functionCode>.json` + `src/functions/<functionCode>/index.ts`
|
|
454
469
|
|
|
455
470
|
```json
|
|
@@ -389,7 +389,7 @@ For reusable backend logic that should be shared by pages, automations, and work
|
|
|
389
389
|
|
|
390
390
|
Use JS_CODE V2 when the script is local to one workflow node.
|
|
391
391
|
|
|
392
|
-
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.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, and `ctx.connector.call/invoke` for platform-side work. App Function and trusted-node form writes are backend operations over declared resources, not direct page-user submit access; keep internal forms closed to raw user submission unless the business requires it. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData/queryManyData/getDataByFormInstanceId/updateOneData/updateDataByFormInstanceId/updateManyData/createOneData/terminateProcess/getAllParentDepartments`.
|
|
392
|
+
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.organization`, `ctx.platform.api.*`, `ctx.utils`, `require`, `process`, and `Buffer`. Prefer `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, and `ctx.connector.call/invoke` for platform-side work. Use `ctx.organization.departments.*` and `ctx.organization.accounts.*` only for intentional organization-management flows; the real operator/audit actor must hold `app:organization:manage`. App Function and trusted-node form writes are backend operations over declared resources, not direct page-user submit access; keep internal forms closed to raw user submission unless the business requires it. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData/queryManyData/getDataByFormInstanceId/updateOneData/updateDataByFormInstanceId/updateManyData/createOneData/terminateProcess/getAllParentDepartments`.
|
|
393
393
|
|
|
394
394
|
Example `src/js-code-nodes/sync_customer/index.ts`:
|
|
395
395
|
|
package/package.json
CHANGED
|
@@ -12259,7 +12259,7 @@ async function handleApproval(request, params) {
|
|
|
12259
12259
|
async function withdrawProcess(request, params) {
|
|
12260
12260
|
const response = await request({
|
|
12261
12261
|
url: `/workflow/instance/${params.instanceId}/withdraw`,
|
|
12262
|
-
method: "
|
|
12262
|
+
method: "post",
|
|
12263
12263
|
data: { reason: params.reason }
|
|
12264
12264
|
});
|
|
12265
12265
|
return unwrapRuntimeResponse(response);
|
|
@@ -12267,7 +12267,7 @@ async function withdrawProcess(request, params) {
|
|
|
12267
12267
|
async function transferTask(request, params) {
|
|
12268
12268
|
const response = await request({
|
|
12269
12269
|
url: `/workflow/task/${params.taskId}/transfer`,
|
|
12270
|
-
method: "
|
|
12270
|
+
method: "post",
|
|
12271
12271
|
data: { newAssignee: params.newAssignee, reason: params.reason }
|
|
12272
12272
|
});
|
|
12273
12273
|
return unwrapRuntimeResponse(response);
|
|
@@ -12275,7 +12275,7 @@ async function transferTask(request, params) {
|
|
|
12275
12275
|
async function returnTask(request, params) {
|
|
12276
12276
|
const response = await request({
|
|
12277
12277
|
url: `/workflow/task/${params.taskId}/return`,
|
|
12278
|
-
method: "
|
|
12278
|
+
method: "post",
|
|
12279
12279
|
data: { targetNodeId: params.targetNodeId, reason: params.reason }
|
|
12280
12280
|
});
|
|
12281
12281
|
return unwrapRuntimeResponse(response);
|