openxiangda 1.0.106 → 1.0.108
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 +1 -1
- package/lib/cli.js +59 -6
- package/lib/design-gates.js +42 -2
- package/openxiangda-skills/references/notifications.md +8 -0
- package/openxiangda-skills/references/openxiangda-api.md +16 -1
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +1 -1
- package/openxiangda-skills/references/workflow-v3.md +35 -0
- package/package.json +1 -1
- package/packages/sdk/dist/workflow/index.cjs +262 -26
- package/packages/sdk/dist/workflow/index.cjs.map +1 -1
- package/packages/sdk/dist/workflow/index.d.mts +177 -1
- package/packages/sdk/dist/workflow/index.d.ts +177 -1
- package/packages/sdk/dist/workflow/index.mjs +262 -26
- package/packages/sdk/dist/workflow/index.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ openxiangda public-access grant-check public_register --form-code registration_f
|
|
|
105
105
|
openxiangda auth-config methods --json
|
|
106
106
|
openxiangda function invoke submit_public_registration --body-json '{"input":{}}'
|
|
107
107
|
openxiangda connector invoke sms.sendCode --body-json '{"body":{"phone":"13800000000"}}'
|
|
108
|
-
openxiangda notification preview public_register_notice --body-json '{"
|
|
108
|
+
openxiangda notification preview public_register_notice --body-json '{"payload":{"title":"测试"}}'
|
|
109
109
|
openxiangda permission audit --json
|
|
110
110
|
```
|
|
111
111
|
|
package/lib/cli.js
CHANGED
|
@@ -2856,7 +2856,12 @@ async function notification(args) {
|
|
|
2856
2856
|
const { subcommand, rest } = parseSubcommandArgs(args);
|
|
2857
2857
|
const { flags, positional } = parseArgs(rest);
|
|
2858
2858
|
if (wantsSubcommandHelp(subcommand, flags)) {
|
|
2859
|
-
print(
|
|
2859
|
+
print([
|
|
2860
|
+
'用法: openxiangda notification template-list|template-get|template-upsert|template-delete|type-list|type-get|type-upsert|type-delete|preview|send|batch-send',
|
|
2861
|
+
' preview <templateCode> --body-json \'{"payload":{"title":"测试"}}\'',
|
|
2862
|
+
' send <notificationType> --body-json \'{"recipientId":"USER_ID","payload":{"title":"测试"}}\' --force',
|
|
2863
|
+
' batch-send <notificationType> --body-json \'{"recipients":[{"recipientId":"USER_ID","payload":{}}]}\' --force',
|
|
2864
|
+
].join('\n'));
|
|
2860
2865
|
return;
|
|
2861
2866
|
}
|
|
2862
2867
|
const config = loadConfig();
|
|
@@ -2955,13 +2960,20 @@ async function notification(args) {
|
|
|
2955
2960
|
fail(`openxiangda notification ${subcommand} 是发送动作,必须加 --force`);
|
|
2956
2961
|
}
|
|
2957
2962
|
const code = positional[0] || flags.code;
|
|
2958
|
-
const body =
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2963
|
+
const body = normalizeNotificationActionBody(
|
|
2964
|
+
subcommand,
|
|
2965
|
+
code,
|
|
2966
|
+
readDirectJsonBody(flags, `notification ${subcommand}`, { optional: true })
|
|
2967
|
+
);
|
|
2968
|
+
const actionPath =
|
|
2969
|
+
subcommand === 'preview'
|
|
2970
|
+
? 'templates/preview'
|
|
2971
|
+
: subcommand === 'batch-send'
|
|
2972
|
+
? 'batch-send-by-type'
|
|
2973
|
+
: 'send-by-type';
|
|
2962
2974
|
return runDirectRequest(config, target, flags, {
|
|
2963
2975
|
method: 'POST',
|
|
2964
|
-
path: `${appPrefix}/${
|
|
2976
|
+
path: `${appPrefix}/${actionPath}`,
|
|
2965
2977
|
body,
|
|
2966
2978
|
strictEnvelope: true,
|
|
2967
2979
|
});
|
|
@@ -4587,6 +4599,47 @@ function extractNotificationTypeConfigBody(bound, body) {
|
|
|
4587
4599
|
};
|
|
4588
4600
|
}
|
|
4589
4601
|
|
|
4602
|
+
function normalizeNotificationActionBody(subcommand, code, rawBody = {}) {
|
|
4603
|
+
const body = { ...(rawBody || {}) };
|
|
4604
|
+
if (body.variables && !body.payload) {
|
|
4605
|
+
body.payload = body.variables;
|
|
4606
|
+
}
|
|
4607
|
+
delete body.variables;
|
|
4608
|
+
|
|
4609
|
+
if (subcommand === 'preview') {
|
|
4610
|
+
if (code && !body.templateCode && !body.templateId && !body.code) {
|
|
4611
|
+
body.templateCode = code;
|
|
4612
|
+
}
|
|
4613
|
+
return body;
|
|
4614
|
+
}
|
|
4615
|
+
|
|
4616
|
+
if (code && !body.notificationType) {
|
|
4617
|
+
body.notificationType = code;
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4620
|
+
if (subcommand === 'send') {
|
|
4621
|
+
if (!body.recipientId && Array.isArray(body.recipientIds) && body.recipientIds.length === 1) {
|
|
4622
|
+
body.recipientId = body.recipientIds[0];
|
|
4623
|
+
}
|
|
4624
|
+
delete body.recipientIds;
|
|
4625
|
+
return body;
|
|
4626
|
+
}
|
|
4627
|
+
|
|
4628
|
+
if (subcommand === 'batch-send') {
|
|
4629
|
+
if (!body.recipients && Array.isArray(body.recipientIds)) {
|
|
4630
|
+
body.recipients = body.recipientIds.map(recipientId => ({
|
|
4631
|
+
recipientId,
|
|
4632
|
+
payload: body.payload || {},
|
|
4633
|
+
...(body.channels ? { channels: body.channels } : {}),
|
|
4634
|
+
}));
|
|
4635
|
+
}
|
|
4636
|
+
delete body.recipientIds;
|
|
4637
|
+
return body;
|
|
4638
|
+
}
|
|
4639
|
+
|
|
4640
|
+
return body;
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4590
4643
|
function buildPublicGrantChecks(bound, grants, flags = {}) {
|
|
4591
4644
|
const checks = [];
|
|
4592
4645
|
const formTargets = [
|
package/lib/design-gates.js
CHANGED
|
@@ -482,7 +482,27 @@ const RESOURCE_EXPLAINS = {
|
|
|
482
482
|
},
|
|
483
483
|
commands: [
|
|
484
484
|
'openxiangda notification template-upsert --json-file src/resources/notifications/reservation_reminder.json',
|
|
485
|
-
'openxiangda notification preview reservation_reminder --body-json \'{"
|
|
485
|
+
'openxiangda notification preview reservation_reminder --body-json \'{"payload":{"title":"测试"}}\'',
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
workflow: {
|
|
489
|
+
dir: 'src/resources/workflows/*.json + src/workflows/<code>/workflow.ts',
|
|
490
|
+
minimalManifest: {
|
|
491
|
+
code: 'expense_approval',
|
|
492
|
+
name: '费用审批',
|
|
493
|
+
formCode: 'expense_request',
|
|
494
|
+
workflowFile: '../../workflows/expense_approval/workflow.ts',
|
|
495
|
+
definitionFile: '../../generated/workflows/expense_approval/definition.v3.json',
|
|
496
|
+
previewFile: '../../generated/workflows/expense_approval/preview.json',
|
|
497
|
+
publish: true,
|
|
498
|
+
enable: true,
|
|
499
|
+
},
|
|
500
|
+
commands: [
|
|
501
|
+
'openxiangda workflow compile src/workflows/expense_approval/workflow.ts --check',
|
|
502
|
+
'openxiangda workflow compile src/workflows/expense_approval/workflow.ts --out-definition src/generated/workflows/expense_approval/definition.v3.json --out-preview src/generated/workflows/expense_approval/preview.json',
|
|
503
|
+
'openxiangda resource validate workflow',
|
|
504
|
+
'openxiangda resource plan workflow',
|
|
505
|
+
'openxiangda resource publish',
|
|
486
506
|
],
|
|
487
507
|
},
|
|
488
508
|
'data-view': {
|
|
@@ -513,7 +533,27 @@ const RESOURCE_EXPLAINS = {
|
|
|
513
533
|
};
|
|
514
534
|
|
|
515
535
|
function getResourceExplain(type) {
|
|
516
|
-
const
|
|
536
|
+
const rawKey = String(type || 'route')
|
|
537
|
+
.trim()
|
|
538
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
539
|
+
.replace(/[_\s]+/g, '-')
|
|
540
|
+
.toLowerCase();
|
|
541
|
+
const aliases = {
|
|
542
|
+
routes: 'route',
|
|
543
|
+
notifications: 'notification',
|
|
544
|
+
workflows: 'workflow',
|
|
545
|
+
dataview: 'data-view',
|
|
546
|
+
dataviews: 'data-view',
|
|
547
|
+
'data-views': 'data-view',
|
|
548
|
+
publicaccess: 'public-access',
|
|
549
|
+
publicaccesspolicy: 'public-access',
|
|
550
|
+
publicaccesspolicies: 'public-access',
|
|
551
|
+
auth: 'auth-config',
|
|
552
|
+
authconfigs: 'auth-config',
|
|
553
|
+
functions: 'function',
|
|
554
|
+
connectors: 'connector',
|
|
555
|
+
};
|
|
556
|
+
const key = aliases[rawKey] || rawKey;
|
|
517
557
|
return RESOURCE_EXPLAINS[key];
|
|
518
558
|
}
|
|
519
559
|
|
|
@@ -61,6 +61,14 @@ await sdk.notification.sendByType({
|
|
|
61
61
|
});
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
CLI smoke tests:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
openxiangda notification preview reservation_reminder --body-json '{"payload":{"title":"测试"}}'
|
|
68
|
+
openxiangda notification send reservation_reminder --body-json '{"recipientId":"USER_ID","payload":{"title":"测试"}}' --force
|
|
69
|
+
openxiangda notification batch-send reservation_reminder --body-json '{"recipients":[{"recipientId":"USER_ID","payload":{"title":"测试"}}]}' --force
|
|
70
|
+
```
|
|
71
|
+
|
|
64
72
|
Automation or workflow JS_CODE:
|
|
65
73
|
|
|
66
74
|
```ts
|
|
@@ -334,6 +334,21 @@ Requires Bearer token. Sends a notification in the current app scope.
|
|
|
334
334
|
|
|
335
335
|
Requires Bearer token. Sends one notification type to multiple recipients.
|
|
336
336
|
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"notificationType": "reservation_reminder",
|
|
340
|
+
"recipients": [
|
|
341
|
+
{
|
|
342
|
+
"recipientId": "user-id",
|
|
343
|
+
"payload": {
|
|
344
|
+
"title": "预约提醒"
|
|
345
|
+
},
|
|
346
|
+
"channels": ["inapp"]
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
337
352
|
### GET `/apps/:appType/notifications/templates`
|
|
338
353
|
|
|
339
354
|
Requires Bearer token. Lists app/form notification templates.
|
|
@@ -344,7 +359,7 @@ Requires app admin permission. Upserts an app/form notification template by code
|
|
|
344
359
|
|
|
345
360
|
### POST `/apps/:appType/notifications/templates/preview`
|
|
346
361
|
|
|
347
|
-
Requires Bearer token. Body uses `templateCode` or `templateId` plus `payload`.
|
|
362
|
+
Requires Bearer token. Body uses `templateCode` or `templateId` plus `payload`. The CLI command is `openxiangda notification preview <templateCode> --body-json '{"payload":{...}}'`.
|
|
348
363
|
|
|
349
364
|
### GET `/apps/:appType/notifications/type-configs`
|
|
350
365
|
|
|
@@ -47,7 +47,7 @@ openxiangda connector invoke sms.sendCode --body-json '{"body":{"phone":"1380000
|
|
|
47
47
|
|
|
48
48
|
openxiangda notification template-upsert --json-file src/resources/notifications/register.json
|
|
49
49
|
openxiangda notification type-upsert --json-file src/resources/notifications/register.json
|
|
50
|
-
openxiangda notification preview public_register_notice --body-json '{"
|
|
50
|
+
openxiangda notification preview public_register_notice --body-json '{"payload":{"title":"测试"}}'
|
|
51
51
|
|
|
52
52
|
openxiangda data-view upsert --json-file src/resources/data-views/public_lookup.json
|
|
53
53
|
openxiangda menu update public_register --json-file src/resources/menus/public_register.json --write-manifest
|
|
@@ -44,6 +44,41 @@ export default defineWorkflow({
|
|
|
44
44
|
});
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
For compact AI-authored drafts, `flow.define` is also exported. It accepts
|
|
48
|
+
declarative node and edge helpers, then compiles to the same v3 JSON:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { flow } from "openxiangda/workflow";
|
|
52
|
+
|
|
53
|
+
export default flow.define({
|
|
54
|
+
name: "费用审批",
|
|
55
|
+
formUuid: "FORM_UUID",
|
|
56
|
+
nodes: [
|
|
57
|
+
flow.start("start"),
|
|
58
|
+
flow.approval("manager_approval", {
|
|
59
|
+
label: "主管审批",
|
|
60
|
+
assignees: [flow.assignee.initiator()],
|
|
61
|
+
actions: [
|
|
62
|
+
flow.action.approve("通过"),
|
|
63
|
+
flow.action.returnToInitiator(),
|
|
64
|
+
flow.action.transfer(),
|
|
65
|
+
],
|
|
66
|
+
fieldPermissions: { amount: "readonly" },
|
|
67
|
+
}),
|
|
68
|
+
flow.functionCall("sync_budget", {
|
|
69
|
+
functionName: "sync_budget",
|
|
70
|
+
input: { amount: "${amount}" },
|
|
71
|
+
}),
|
|
72
|
+
flow.end("end"),
|
|
73
|
+
],
|
|
74
|
+
edges: [
|
|
75
|
+
flow.connect("start", "manager_approval"),
|
|
76
|
+
flow.connect("manager_approval", "sync_budget"),
|
|
77
|
+
flow.connect("sync_budget", "end"),
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
47
82
|
Resource manifest:
|
|
48
83
|
|
|
49
84
|
```json
|
package/package.json
CHANGED
|
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var workflow_exports = {};
|
|
22
22
|
__export(workflow_exports, {
|
|
23
23
|
WorkflowBuilder: () => WorkflowBuilder,
|
|
24
|
-
defineWorkflow: () => defineWorkflow
|
|
24
|
+
defineWorkflow: () => defineWorkflow,
|
|
25
|
+
flow: () => flow
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(workflow_exports);
|
|
27
28
|
function sanitizeId(value) {
|
|
@@ -37,6 +38,30 @@ function normalizeAction(action, label, extra = {}) {
|
|
|
37
38
|
...extra
|
|
38
39
|
};
|
|
39
40
|
}
|
|
41
|
+
var workflowActions = {
|
|
42
|
+
approve: (label = "\u540C\u610F", extra = {}) => normalizeAction("agree", label, extra),
|
|
43
|
+
reject: (label = "\u62D2\u7EDD", extra = {}) => normalizeAction("rejected", label, extra),
|
|
44
|
+
transfer: (label = "\u8F6C\u4EA4", extra = {}) => normalizeAction("transfer", label, {
|
|
45
|
+
remark: { popUp: true, required: false },
|
|
46
|
+
...extra
|
|
47
|
+
}),
|
|
48
|
+
return: (label = "\u9000\u56DE", extra = {}) => normalizeAction("return", label, {
|
|
49
|
+
remark: { popUp: true, required: false },
|
|
50
|
+
...extra
|
|
51
|
+
}),
|
|
52
|
+
returnToInitiator: (label = "\u9000\u56DE\u53D1\u8D77\u4EBA", extra = {}) => normalizeAction("return", label, {
|
|
53
|
+
remark: { popUp: true, required: false },
|
|
54
|
+
returnTarget: "initiator",
|
|
55
|
+
returnScope: "initiator",
|
|
56
|
+
...extra
|
|
57
|
+
}),
|
|
58
|
+
save: (label = "\u6682\u5B58", extra = {}) => normalizeAction("save", label, extra),
|
|
59
|
+
withdraw: (label = "\u64A4\u56DE", extra = {}) => normalizeAction("withdraw", label, extra),
|
|
60
|
+
resubmit: (label = "\u91CD\u65B0\u63D0\u4EA4", extra = {}) => normalizeAction("resubmit", label, extra),
|
|
61
|
+
callback: (label = "\u89E6\u53D1\u56DE\u8C03", extra = {}) => normalizeAction("callback", label, extra),
|
|
62
|
+
retryException: (label = "\u91CD\u8BD5\u5F02\u5E38", extra = {}) => normalizeAction("retryException", label, extra),
|
|
63
|
+
adminTransfer: (label = "\u7BA1\u7406\u5458\u8F6C\u4EA4", extra = {}) => normalizeAction("adminTransfer", label, extra)
|
|
64
|
+
};
|
|
40
65
|
function normalizeReturnConfig(value) {
|
|
41
66
|
if (value === false) return { enabled: false };
|
|
42
67
|
if (value === true || value === void 0) {
|
|
@@ -49,6 +74,111 @@ function normalizeReturnConfig(value) {
|
|
|
49
74
|
...value
|
|
50
75
|
};
|
|
51
76
|
}
|
|
77
|
+
function findInitiatorReturnAction(actions) {
|
|
78
|
+
return actions.find(
|
|
79
|
+
(action) => action?.action === "return" && (action.returnTarget === "initiator" || action.returnScope === "initiator")
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function inferReturnConfigFromActions(actions, explicitReturnConfig) {
|
|
83
|
+
const initiatorReturnAction = findInitiatorReturnAction(actions);
|
|
84
|
+
if (!initiatorReturnAction) return explicitReturnConfig;
|
|
85
|
+
const base = explicitReturnConfig || normalizeReturnConfig({
|
|
86
|
+
scopeType: "previous_all",
|
|
87
|
+
resubmitMode: initiatorReturnAction.resubmitMode || "replay"
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
...base,
|
|
91
|
+
allowOriginatorReturn: true
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function normalizeFieldBehavior(value) {
|
|
95
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
96
|
+
if (["normal", "edit", "editable", "write", "writable"].includes(normalized)) return "NORMAL";
|
|
97
|
+
if (["readonly", "read", "view", "visible"].includes(normalized)) return "READONLY";
|
|
98
|
+
if (["hidden", "hide", "invisible"].includes(normalized)) return "HIDDEN";
|
|
99
|
+
return String(value || "READONLY").toUpperCase();
|
|
100
|
+
}
|
|
101
|
+
function normalizeFieldPermissions(value) {
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
return value.map((item) => {
|
|
104
|
+
if (!item || typeof item !== "object") return item;
|
|
105
|
+
return {
|
|
106
|
+
...item,
|
|
107
|
+
fieldId: item.fieldId || item.field || item.id,
|
|
108
|
+
fieldBehavior: normalizeFieldBehavior(item.fieldBehavior || item.behavior || item.permission)
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (value && typeof value === "object") {
|
|
113
|
+
return Object.entries(value).map(([fieldId, fieldBehavior]) => ({
|
|
114
|
+
fieldId,
|
|
115
|
+
fieldBehavior: normalizeFieldBehavior(fieldBehavior)
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
function createDeclarativeNode(type, id, data = {}) {
|
|
121
|
+
return {
|
|
122
|
+
__openxiangdaWorkflowNode: true,
|
|
123
|
+
id: sanitizeId(id),
|
|
124
|
+
type,
|
|
125
|
+
data
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function createDeclarativeEdge(source, target, data = {}) {
|
|
129
|
+
return {
|
|
130
|
+
__openxiangdaWorkflowEdge: true,
|
|
131
|
+
source,
|
|
132
|
+
target,
|
|
133
|
+
data
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function isDeclarativeInput(input) {
|
|
137
|
+
return input && Array.isArray(input.nodes);
|
|
138
|
+
}
|
|
139
|
+
function isWorkflowNodeDescriptor(value) {
|
|
140
|
+
return Boolean(value?.__openxiangdaWorkflowNode);
|
|
141
|
+
}
|
|
142
|
+
function normalizeAssignee(value) {
|
|
143
|
+
if (typeof value === "string") {
|
|
144
|
+
return { type: value === "originator" ? "originator" : "user", id: value, name: value };
|
|
145
|
+
}
|
|
146
|
+
return value || {};
|
|
147
|
+
}
|
|
148
|
+
function normalizeApprovalData(data = {}) {
|
|
149
|
+
const normalized = { ...data };
|
|
150
|
+
const assignees = Array.isArray(data.assignees) ? data.assignees.map(normalizeAssignee) : void 0;
|
|
151
|
+
if (assignees && !normalized.approverType) {
|
|
152
|
+
const supervisor = assignees.find((item) => item.type === "department_supervisor");
|
|
153
|
+
const initiatorSelect = assignees.find((item) => item.type === "initiator_select");
|
|
154
|
+
const roleAssignees = assignees.filter((item) => item.type === "role");
|
|
155
|
+
const userAssignees = assignees.filter((item) => item.type === "user" || item.type === "originator");
|
|
156
|
+
if (supervisor) {
|
|
157
|
+
normalized.approverType = "ext_target_approval_department_supervisor";
|
|
158
|
+
normalized.supervisorConfig = {
|
|
159
|
+
level: supervisor.level || 1,
|
|
160
|
+
fallbackToAncestorSupervisor: supervisor.fallbackToAncestorSupervisor !== false,
|
|
161
|
+
...normalized.supervisorConfig || {}
|
|
162
|
+
};
|
|
163
|
+
normalized.approvals = normalized.approvals || [];
|
|
164
|
+
normalized.approvalNames = normalized.approvalNames || [];
|
|
165
|
+
} else if (initiatorSelect) {
|
|
166
|
+
normalized.approverType = "ext_target_approval_initiator_select";
|
|
167
|
+
normalized.initiatorSelectScope = initiatorSelect.scope || initiatorSelect.initiatorSelectScope || "all";
|
|
168
|
+
normalized.approvals = normalized.approvals || (Array.isArray(initiatorSelect.approvals) ? initiatorSelect.approvals : roleAssignees.map((item) => item.id).filter(Boolean));
|
|
169
|
+
normalized.approvalNames = normalized.approvalNames || (Array.isArray(initiatorSelect.approvalNames) ? initiatorSelect.approvalNames : roleAssignees.map((item) => item.name || item.id).filter(Boolean));
|
|
170
|
+
} else if (roleAssignees.length > 0 && userAssignees.length === 0) {
|
|
171
|
+
normalized.approverType = "ext_target_approval_role";
|
|
172
|
+
normalized.approvals = normalized.approvals || roleAssignees.map((item) => item.id).filter(Boolean);
|
|
173
|
+
normalized.approvalNames = normalized.approvalNames || roleAssignees.map((item) => item.name || item.id).filter(Boolean);
|
|
174
|
+
} else {
|
|
175
|
+
normalized.approverType = "ext_target_approval";
|
|
176
|
+
normalized.approvals = normalized.approvals || userAssignees.map((item) => item.type === "originator" ? "originator" : item.id).filter(Boolean);
|
|
177
|
+
normalized.approvalNames = normalized.approvalNames || userAssignees.map((item) => item.name || (item.type === "originator" ? "\u53D1\u8D77\u4EBA" : item.id)).filter(Boolean);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return normalized;
|
|
181
|
+
}
|
|
52
182
|
var WorkflowBuilder = class {
|
|
53
183
|
constructor(meta = {}) {
|
|
54
184
|
this.meta = meta;
|
|
@@ -56,19 +186,7 @@ var WorkflowBuilder = class {
|
|
|
56
186
|
this.edges = [];
|
|
57
187
|
this.flowConfig = {};
|
|
58
188
|
this.globalSettings = {};
|
|
59
|
-
this.action =
|
|
60
|
-
approve: (label = "\u540C\u610F", extra = {}) => normalizeAction("agree", label, extra),
|
|
61
|
-
reject: (label = "\u62D2\u7EDD", extra = {}) => normalizeAction("rejected", label, extra),
|
|
62
|
-
transfer: (label = "\u8F6C\u4EA4", extra = {}) => normalizeAction("transfer", label, {
|
|
63
|
-
remark: { popUp: true, required: false },
|
|
64
|
-
...extra
|
|
65
|
-
}),
|
|
66
|
-
return: (label = "\u9000\u56DE", extra = {}) => normalizeAction("return", label, {
|
|
67
|
-
remark: { popUp: true, required: false },
|
|
68
|
-
...extra
|
|
69
|
-
}),
|
|
70
|
-
save: (label = "\u6682\u5B58", extra = {}) => normalizeAction("save", label, extra)
|
|
71
|
-
};
|
|
189
|
+
this.action = workflowActions;
|
|
72
190
|
this.data = {
|
|
73
191
|
retrieveSingle: (id, data) => this.node("data_retrieve_single", id, {
|
|
74
192
|
type: "data_retrieve_single",
|
|
@@ -107,21 +225,23 @@ var WorkflowBuilder = class {
|
|
|
107
225
|
return this.node("end", id, { label: "\u7ED3\u675F\u8282\u70B9", ...data });
|
|
108
226
|
}
|
|
109
227
|
approval(id, data) {
|
|
110
|
-
const
|
|
228
|
+
const approvalData = normalizeApprovalData(data);
|
|
229
|
+
const actions = approvalData.buttons || approvalData.actions || [
|
|
111
230
|
this.action.approve(),
|
|
112
231
|
this.action.reject()
|
|
113
232
|
];
|
|
114
|
-
const returnConfig =
|
|
233
|
+
const returnConfig = approvalData.returnConfig !== void 0 ? normalizeReturnConfig(approvalData.returnConfig) : approvalData.returnPolicy !== void 0 ? normalizeReturnConfig(approvalData.returnPolicy) : void 0;
|
|
234
|
+
const inferredReturnConfig = inferReturnConfigFromActions(actions, returnConfig);
|
|
115
235
|
return this.node("approval", id, {
|
|
116
|
-
label:
|
|
117
|
-
value:
|
|
118
|
-
approverType:
|
|
119
|
-
approvals:
|
|
120
|
-
approvalNames:
|
|
121
|
-
multiApprove:
|
|
122
|
-
...
|
|
236
|
+
label: approvalData.label || "\u5BA1\u6279",
|
|
237
|
+
value: approvalData.value || "",
|
|
238
|
+
approverType: approvalData.approverType || "ext_target_approval",
|
|
239
|
+
approvals: approvalData.approvals || [],
|
|
240
|
+
approvalNames: approvalData.approvalNames || [],
|
|
241
|
+
multiApprove: approvalData.multiApprove || "or",
|
|
242
|
+
...approvalData,
|
|
123
243
|
actions,
|
|
124
|
-
...
|
|
244
|
+
...inferredReturnConfig ? { returnConfig: inferredReturnConfig } : {}
|
|
125
245
|
});
|
|
126
246
|
}
|
|
127
247
|
copy(id, data) {
|
|
@@ -302,8 +422,9 @@ var WorkflowBuilder = class {
|
|
|
302
422
|
data,
|
|
303
423
|
position: createPosition(this.nodes.length)
|
|
304
424
|
});
|
|
305
|
-
|
|
306
|
-
|
|
425
|
+
const fieldPermissions = normalizeFieldPermissions(data.fieldPermissions);
|
|
426
|
+
if (fieldPermissions) {
|
|
427
|
+
this.flowConfig[nodeId] = fieldPermissions;
|
|
307
428
|
}
|
|
308
429
|
return nodeId;
|
|
309
430
|
}
|
|
@@ -369,4 +490,119 @@ function defineWorkflow(input) {
|
|
|
369
490
|
}
|
|
370
491
|
};
|
|
371
492
|
}
|
|
493
|
+
function addDeclarativeNode(builder, node) {
|
|
494
|
+
if (!isWorkflowNodeDescriptor(node)) {
|
|
495
|
+
throw new Error("workflow declarative nodes must be created by flow.* helpers");
|
|
496
|
+
}
|
|
497
|
+
switch (node.type) {
|
|
498
|
+
case "start":
|
|
499
|
+
builder.start(node.id, node.data);
|
|
500
|
+
return;
|
|
501
|
+
case "end":
|
|
502
|
+
builder.end(node.id, node.data);
|
|
503
|
+
return;
|
|
504
|
+
case "approval":
|
|
505
|
+
builder.approval(node.id, node.data);
|
|
506
|
+
return;
|
|
507
|
+
case "copy":
|
|
508
|
+
builder.copy(node.id, node.data);
|
|
509
|
+
return;
|
|
510
|
+
case "js_code":
|
|
511
|
+
builder.jsCode(node.id, node.data);
|
|
512
|
+
return;
|
|
513
|
+
case "function_call":
|
|
514
|
+
builder.functionCall(node.id, node.data);
|
|
515
|
+
return;
|
|
516
|
+
case "callback_wait":
|
|
517
|
+
builder.callbackWait(node.id, node.data);
|
|
518
|
+
return;
|
|
519
|
+
case "connector_call":
|
|
520
|
+
builder.connectorCall(node.id, node.data);
|
|
521
|
+
return;
|
|
522
|
+
case "work_notification":
|
|
523
|
+
builder.workNotification(node.id, node.data);
|
|
524
|
+
return;
|
|
525
|
+
case "condition_branch":
|
|
526
|
+
builder.condition(node.id, node.data);
|
|
527
|
+
return;
|
|
528
|
+
case "branch": {
|
|
529
|
+
builder.branch(node.id, node.data);
|
|
530
|
+
const branches = Array.isArray(node.data?.branches) ? node.data.branches : [];
|
|
531
|
+
branches.forEach((branch, index) => {
|
|
532
|
+
const conditionId = sanitizeId(`${node.id}_${branch.id || index + 1}`);
|
|
533
|
+
builder.condition(conditionId, {
|
|
534
|
+
label: branch.label || (branch.else || branch.isElse ? "\u5176\u4ED6\u60C5\u51B5" : `\u6761\u4EF6 ${index + 1}`),
|
|
535
|
+
condition: branch.condition || {
|
|
536
|
+
ruleType: "group",
|
|
537
|
+
condition: "AND",
|
|
538
|
+
rules: []
|
|
539
|
+
},
|
|
540
|
+
isElse: branch.else === true || branch.isElse === true,
|
|
541
|
+
priority: String(index + 1)
|
|
542
|
+
});
|
|
543
|
+
builder.edge(node.id, conditionId, {
|
|
544
|
+
id: `edge_${node.id}_${conditionId}`,
|
|
545
|
+
label: branch.label
|
|
546
|
+
});
|
|
547
|
+
if (branch.next) {
|
|
548
|
+
builder.edge(conditionId, sanitizeId(branch.next), {
|
|
549
|
+
id: `edge_${conditionId}_${sanitizeId(branch.next)}`,
|
|
550
|
+
label: branch.label
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
default:
|
|
557
|
+
builder.node(node.type, node.id, node.data);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function defineDeclarativeWorkflow(input) {
|
|
561
|
+
return {
|
|
562
|
+
__openxiangdaWorkflow: true,
|
|
563
|
+
compile() {
|
|
564
|
+
const builder = new WorkflowBuilder(input);
|
|
565
|
+
input.nodes.forEach((node) => addDeclarativeNode(builder, node));
|
|
566
|
+
(input.edges || []).forEach((edge) => {
|
|
567
|
+
builder.edge(edge.source, edge.target, edge.data || {});
|
|
568
|
+
});
|
|
569
|
+
return builder.compile();
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
var flow = {
|
|
574
|
+
define(input) {
|
|
575
|
+
if (isDeclarativeInput(input)) {
|
|
576
|
+
return defineDeclarativeWorkflow(input);
|
|
577
|
+
}
|
|
578
|
+
return defineWorkflow(input);
|
|
579
|
+
},
|
|
580
|
+
action: workflowActions,
|
|
581
|
+
assignee: {
|
|
582
|
+
user: (id, name) => ({ type: "user", id, name: name || id }),
|
|
583
|
+
initiator: () => ({ type: "originator", id: "originator", name: "\u53D1\u8D77\u4EBA" }),
|
|
584
|
+
role: (id, name) => ({ type: "role", id, name: name || id }),
|
|
585
|
+
departmentSupervisor: (level = 1, extra = {}) => ({ type: "department_supervisor", level, ...extra }),
|
|
586
|
+
initiatorSelect: (scope = "all", extra = {}) => ({ type: "initiator_select", scope, ...extra })
|
|
587
|
+
},
|
|
588
|
+
start: (id = "start", data = {}) => createDeclarativeNode("start", id, data),
|
|
589
|
+
end: (id = "end", data = {}) => createDeclarativeNode("end", id, data),
|
|
590
|
+
approval: (id, data = {}) => createDeclarativeNode("approval", id, data),
|
|
591
|
+
copy: (id, data = {}) => createDeclarativeNode("copy", id, data),
|
|
592
|
+
jsCode: (id, data = {}) => createDeclarativeNode("js_code", id, data),
|
|
593
|
+
functionCall: (id, data = {}) => createDeclarativeNode("function_call", id, data),
|
|
594
|
+
callbackWait: (id, data = {}) => createDeclarativeNode("callback_wait", id, data),
|
|
595
|
+
connectorCall: (id, data = {}) => createDeclarativeNode("connector_call", id, data),
|
|
596
|
+
workNotification: (id, data = {}) => createDeclarativeNode("work_notification", id, data),
|
|
597
|
+
notification: (id, data = {}) => createDeclarativeNode("work_notification", id, data),
|
|
598
|
+
condition: (id, data = {}) => createDeclarativeNode("condition_branch", id, data),
|
|
599
|
+
branch: (id, data = {}) => createDeclarativeNode("branch", id, data),
|
|
600
|
+
data: {
|
|
601
|
+
retrieveSingle: (id, data = {}) => createDeclarativeNode("data_retrieve_single", id, data),
|
|
602
|
+
retrieveBatch: (id, data = {}) => createDeclarativeNode("data_retrieve_batch", id, data),
|
|
603
|
+
create: (id, data = {}) => createDeclarativeNode("data_create", id, data),
|
|
604
|
+
update: (id, data = {}) => createDeclarativeNode("data_update", id, data)
|
|
605
|
+
},
|
|
606
|
+
connect: createDeclarativeEdge
|
|
607
|
+
};
|
|
372
608
|
//# sourceMappingURL=index.cjs.map
|