openxiangda 2.67.4 → 2.68.0
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/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowConditionEditor.d.ts +3 -1
- package/dist/browser/components/workflow/WorkflowConditionEditor.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowConditionEditor.js +10 -7
- package/dist/browser/components/workflow/WorkflowConditionEditor.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowConditionalAssignmentEditor.d.ts +11 -0
- package/dist/browser/components/workflow/WorkflowConditionalAssignmentEditor.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowConditionalAssignmentEditor.js +35 -0
- package/dist/browser/components/workflow/WorkflowConditionalAssignmentEditor.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowDesigner.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowDesigner.js +159 -35
- package/dist/browser/components/workflow/WorkflowDesigner.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowDesignerAssistant.d.ts +2 -1
- package/dist/browser/components/workflow/WorkflowDesignerAssistant.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowDesignerAssistant.js +50 -13
- package/dist/browser/components/workflow/WorkflowDesignerAssistant.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowDraftHandlingEditor.d.ts +3 -1
- package/dist/browser/components/workflow/WorkflowDraftHandlingEditor.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowDraftHandlingEditor.js +3 -2
- package/dist/browser/components/workflow/WorkflowDraftHandlingEditor.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts +7 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +70 -13
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowPeopleSourceEditor.d.ts +5 -1
- package/dist/browser/components/workflow/WorkflowPeopleSourceEditor.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowPeopleSourceEditor.js +17 -8
- package/dist/browser/components/workflow/WorkflowPeopleSourceEditor.js.map +1 -1
- package/dist/browser/components/workflow/workflow-designer-authority.d.ts +10 -0
- package/dist/browser/components/workflow/workflow-designer-authority.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-designer-authority.js +23 -0
- package/dist/browser/components/workflow/workflow-designer-authority.js.map +1 -0
- package/dist/browser/platform-client.d.ts +4 -1
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +20 -9
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/styles.css +11 -0
- package/documentation/administration.md +21 -1
- package/documentation/development.md +8 -0
- package/documentation/getting-started.md +22 -7
- package/documentation/manifest.json +7 -7
- package/documentation/reference/mcp.md +2 -2
- package/documentation/upgrading.md +25 -0
- package/documentation/workflow-events.md +11 -0
- package/package.json +29 -23
- package/releases/2.68.0.json +40 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +4 -4
- package/skills/openxiangda-v2/references/administration.md +21 -1
- package/skills/openxiangda-v2/references/development.md +8 -0
- package/skills/openxiangda-v2/references/getting-started.md +22 -7
- package/skills/openxiangda-v2/references/mcp.md +2 -2
- package/skills/openxiangda-v2/references/upgrading.md +25 -0
- package/skills/openxiangda-v2/references/workflow-events.md +11 -0
- package/releases/2.67.3.json +0 -39
- package/releases/2.67.4.json +0 -34
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { workflowDesignerAllowedActions, isWorkflowDesignerAuthorityLoss, isWorkflowDesignerAuthorityBusy } from './workflow-designer-authority';
|
|
3
|
+
import { workflowAssignmentLeaves, workflowAuthoringCatalog, workflowCanvasBindingKey, createWorkflowHumanNode, pruneWorkflowCanvasBindings, validateWorkflowBusinessSteps } from 'openxiangda-contracts/browser';
|
|
3
4
|
import { WorkflowBusinessStepEditor } from './WorkflowBusinessStepEditor';
|
|
4
5
|
import { WorkflowParallelConfigurationEditor } from './WorkflowParallelConfigurationEditor.js';
|
|
5
6
|
import { WorkflowReminderEditor } from './WorkflowReminderEditor.js';
|
|
@@ -9,7 +10,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
9
10
|
import { Alert, App, Button, Checkbox, Collapse, Drawer, Input, Modal, Popconfirm, Radio, Segmented, Select, Skeleton, Space, Spin, Table, Tag, Tooltip } from 'antd';
|
|
10
11
|
import { ArrowLeftOutlined, CheckCircleOutlined, CloseOutlined, HistoryOutlined, MenuFoldOutlined, MenuUnfoldOutlined, RedoOutlined, RobotOutlined, SafetyOutlined, UndoOutlined, UserOutlined, FormOutlined, CodeOutlined, CopyOutlined, BranchesOutlined, BellOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
|
11
12
|
import { workflowReturnTargets, formatWorkflowSupervisorChain, isWorkflowPlatformNotify, WORKFLOW_PLATFORM_NOTIFY_HANDLER, WORKFLOW_PLATFORM_NOTIFY_INPUT_SCHEMA, WORKFLOW_PLATFORM_NOTIFY_OUTPUT_SCHEMA, editWorkflowDesignerDefinition, projectWorkflowGraph, validateWorkflowDesignerDocument, workflowDesignerVariables } from 'openxiangda-contracts/browser';
|
|
12
|
-
import { OpenXiangdaPlatformRequestError,
|
|
13
|
+
import { OpenXiangdaPlatformRequestError, loadWorkflowDesignerRead, loadWorkflowDesignerOriginalOutcome, loadWorkflowNodeConfigurations, loadApplicationAdministrationContext, saveWorkflowDesignerDraft, previewWorkflowDesignerPublication, publishWorkflowDesigner, loadWorkflowDesignerPublication, listWorkflowDesignerPublications, restoreWorkflowDesignerVersion, controlWorkflowDesignerPublication, searchWorkflowDesignerHoldCandidates } from '../../platform-client';
|
|
13
14
|
import { createBrowserUuid } from '../../uuid';
|
|
14
15
|
import { WorkflowDiagram } from './WorkflowDiagram';
|
|
15
16
|
import { workflowDesignerDisplayGraph, workflowDesignerOutlineRows, workflowDesignerStartId } from './workflow-designer-presentation';
|
|
@@ -27,6 +28,18 @@ const same = (left, right) => JSON.stringify(canonical(left)) === JSON.stringify
|
|
|
27
28
|
/** Canonical authoring. The graph is a projection; coordinates never become executable state. */
|
|
28
29
|
export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onStateChange, onBack }) {
|
|
29
30
|
const { message } = App.useApp();
|
|
31
|
+
const [authorityActions, setAuthorityActions] = useState([]);
|
|
32
|
+
const [publishedOnly, setPublishedOnly] = useState();
|
|
33
|
+
const [authorityNotice, setAuthorityNotice] = useState('');
|
|
34
|
+
const [retainedPrompt, setRetainedPrompt] = useState('');
|
|
35
|
+
const [retainedInput, setRetainedInput] = useState();
|
|
36
|
+
const [retainedNodeInput, setRetainedNodeInput] = useState();
|
|
37
|
+
const definiteBusy = useRef(new Set());
|
|
38
|
+
const checkedOutcomes = useRef(new Set());
|
|
39
|
+
const authorityStopped = useRef(false);
|
|
40
|
+
const canEdit = authorityActions.includes('draft.edit');
|
|
41
|
+
const canPublish = authorityActions.includes('publication.publish');
|
|
42
|
+
const canHandle = authorityActions.includes('handling.configure');
|
|
30
43
|
const [draft, setDraft] = useState();
|
|
31
44
|
const [definition, setDefinition] = useState();
|
|
32
45
|
const [stepInputInvalid, setStepInputInvalid] = useState(false);
|
|
@@ -75,24 +88,46 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
75
88
|
const [holdReason, setHoldReason] = useState('');
|
|
76
89
|
const [acknowledge, setAcknowledge] = useState(false);
|
|
77
90
|
const [receipt, setReceipt] = useState();
|
|
91
|
+
const heldExternalOperation = useRef(undefined);
|
|
78
92
|
const frozenSave = useRef(undefined);
|
|
79
93
|
const frozenPublish = useRef(undefined);
|
|
94
|
+
const frozenAuxOperation = useRef(undefined);
|
|
80
95
|
const frozenAux = useRef(undefined);
|
|
81
96
|
const alive = useRef(true);
|
|
97
|
+
const acceptRead = (value, nativeSuperAdmin) => {
|
|
98
|
+
const allowed = workflowDesignerAllowedActions(value, nativeSuperAdmin);
|
|
99
|
+
setAuthorityActions(allowed.actions);
|
|
100
|
+
setAuthorityNotice(allowed.legacy && !nativeSuperAdmin ? '当前平台版本尚不支持细粒度流程管理,已切换为只读。' : '');
|
|
101
|
+
if (!allowed.actions.length)
|
|
102
|
+
throw new Error('当前账号没有可用的流程查看权限');
|
|
103
|
+
if ('view' in value && value.view === 'published') {
|
|
104
|
+
setPublishedOnly(value);
|
|
105
|
+
setDraft(undefined);
|
|
106
|
+
setDefinition(value.definition);
|
|
107
|
+
setBinding(value.binding);
|
|
108
|
+
setPublishedView(false);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const next = value;
|
|
112
|
+
setPublishedOnly(undefined);
|
|
113
|
+
setDraft(next);
|
|
114
|
+
setDefinition(next.definition);
|
|
115
|
+
setBinding(next.binding);
|
|
116
|
+
}
|
|
117
|
+
setSelected(value.definition.startAt);
|
|
118
|
+
setHistory([]);
|
|
119
|
+
setFuture([]);
|
|
120
|
+
};
|
|
82
121
|
const load = useCallback(async () => {
|
|
83
|
-
const [value, configuration, context] = await Promise.all([
|
|
122
|
+
const [value, configuration, context] = await Promise.all([loadWorkflowDesignerRead(workflowCode), loadWorkflowNodeConfigurations(workflowCode), loadApplicationAdministrationContext()]);
|
|
84
123
|
if (context.headRevision == null)
|
|
85
124
|
throw new Error('当前应用没有可用的办理配置版本');
|
|
86
125
|
if (!alive.current)
|
|
87
126
|
return;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
setBinding(value.binding);
|
|
127
|
+
acceptRead(value, context.authorization === 'application_super_admin');
|
|
128
|
+
authorityStopped.current = false;
|
|
91
129
|
setConfigurations(configuration);
|
|
92
130
|
setNativeHeadRevision(context.headRevision);
|
|
93
|
-
setSelected(value.definition.startAt);
|
|
94
|
-
setHistory([]);
|
|
95
|
-
setFuture([]);
|
|
96
131
|
setError(undefined);
|
|
97
132
|
}, [workflowCode]);
|
|
98
133
|
useEffect(() => { alive.current = true; void load().catch(error => setError(String(error.message))); return () => { alive.current = false; }; }, [load]);
|
|
@@ -103,12 +138,13 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
103
138
|
setConfigurations(configuration);
|
|
104
139
|
setNativeHeadRevision(context.headRevision);
|
|
105
140
|
};
|
|
106
|
-
const dirty = !!draft && !!definition && (!same(draft.definition, definition) || !same(draft.binding, binding) || stepInputInvalid || reminderDirty);
|
|
107
|
-
|
|
108
|
-
useEffect(() => {
|
|
141
|
+
const dirty = !!retainedInput || !!retainedNodeInput || !!retainedPrompt || !!draft && !!definition && (!same(draft.definition, definition) || !same(draft.binding, binding) || stepInputInvalid || reminderDirty);
|
|
142
|
+
const unknown = !!heldExternalOperation.current || [frozenSave.current?.operationId, frozenPublish.current?.operationId, frozenAuxOperation.current].some(operation => !!operation && !definiteBusy.current.has(operation)) || assistantState.unknown || liveState.unknown;
|
|
143
|
+
useEffect(() => { onDirtyChange?.(dirty || liveState.dirty || unknown); onStateChange?.({ dirty: dirty || liveState.dirty, busy: busy || assistantState.busy || liveState.busy, unknown }); }, [dirty, busy, unknown, assistantState, liveState, onDirtyChange, onStateChange]);
|
|
144
|
+
useEffect(() => { const guard = (event) => { if (dirty || unknown || busy) {
|
|
109
145
|
event.preventDefault();
|
|
110
146
|
event.returnValue = '';
|
|
111
|
-
} }; addEventListener('beforeunload', guard); return () => removeEventListener('beforeunload', guard); }, [dirty,
|
|
147
|
+
} }; addEventListener('beforeunload', guard); return () => removeEventListener('beforeunload', guard); }, [dirty, unknown, busy]);
|
|
112
148
|
useEffect(() => {
|
|
113
149
|
if (!receipt || receipt.status !== 'running' || publication)
|
|
114
150
|
return;
|
|
@@ -126,7 +162,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
126
162
|
const outlineNodes = useMemo(() => displayGraph ? workflowDesignerOutlineRows(displayGraph) : [], [displayGraph]);
|
|
127
163
|
useEffect(() => { if (shown && selected !== workflowDesignerStartId && !shown.nodes[selected])
|
|
128
164
|
setSelected(shown.startAt); }, [shown, selected]);
|
|
129
|
-
const catalog = useMemo(() => draft?.capabilities || (draft ? workflowAuthoringCatalog(draft.publishedDefinition, draft.publishedBinding) : undefined), [draft]);
|
|
165
|
+
const catalog = useMemo(() => canEdit ? draft?.capabilities || (draft ? workflowAuthoringCatalog(draft.publishedDefinition, draft.publishedBinding) : undefined) : { appVersionId: '', digest: '', taskPages: {}, steps: [], peopleSources: {} }, [draft, canEdit]);
|
|
130
166
|
const variables = useMemo(() => definition ? workflowDesignerVariables(definition) : [], [definition]);
|
|
131
167
|
const errors = useMemo(() => definition ? [...validateWorkflowDesignerDocument(definition), ...validateWorkflowBusinessSteps(definition), ...Object.values(definition.nodes).flatMap(node => {
|
|
132
168
|
if (!('binding' in node))
|
|
@@ -136,7 +172,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
136
172
|
})] : [], [definition, binding]);
|
|
137
173
|
const node = shown?.nodes[selected];
|
|
138
174
|
const liveNode = configurations?.nodes.find(item => item.nodeId === selected);
|
|
139
|
-
const disabled = busy || assistantState.busy || assistantState.unknown || publishedView || !!frozenSave.current || !!frozenPublish.current || !!frozenAux.current;
|
|
175
|
+
const disabled = !canEdit || authorityStopped.current || busy || assistantState.busy || assistantState.unknown || publishedView || !!frozenSave.current || !!frozenPublish.current || !!frozenAux.current;
|
|
140
176
|
const mutate = (next, nextBinding = binding) => {
|
|
141
177
|
if (!definition || !binding || !nextBinding || disabled)
|
|
142
178
|
return;
|
|
@@ -153,8 +189,55 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
153
189
|
};
|
|
154
190
|
const patch = (patch) => { if (definition && node)
|
|
155
191
|
mutate(editWorkflowDesignerDefinition(definition, { type: 'node', nodeId: node.id, patch })); };
|
|
192
|
+
const loseAuthority = async (failure, assistantOperation, assistantPrompt, nodeInput) => {
|
|
193
|
+
if (!isWorkflowDesignerAuthorityLoss(failure))
|
|
194
|
+
return false;
|
|
195
|
+
if (nodeInput)
|
|
196
|
+
setRetainedNodeInput(nodeInput);
|
|
197
|
+
if (assistantPrompt)
|
|
198
|
+
setRetainedPrompt(assistantPrompt);
|
|
199
|
+
if (assistantOperation)
|
|
200
|
+
heldExternalOperation.current = assistantOperation;
|
|
201
|
+
authorityStopped.current = true;
|
|
202
|
+
setAuthorityActions([]);
|
|
203
|
+
if (definition && binding && draft && (!same(draft.definition, definition) || !same(draft.binding, binding)))
|
|
204
|
+
setRetainedInput(structuredClone({ definition, binding }));
|
|
205
|
+
setAssistantOpen(false);
|
|
206
|
+
setPublication(false);
|
|
207
|
+
const operation = assistantOperation || frozenSave.current?.operationId || frozenPublish.current?.operationId || frozenAuxOperation.current;
|
|
208
|
+
let notice = '流程管理权限已改变,当前输入已保留且尚未保存。';
|
|
209
|
+
if (operation && !checkedOutcomes.current.has(operation)) {
|
|
210
|
+
checkedOutcomes.current.add(operation);
|
|
211
|
+
try {
|
|
212
|
+
const result = await loadWorkflowDesignerOriginalOutcome(workflowCode, operation);
|
|
213
|
+
notice = result.state === 'committed' ? '原操作已提交;权限已改变,当前输入保留供核对。' : result.state === 'not_committed' ? '原操作未提交,当前输入已保留且尚未保存。' : '原操作结果仍待确认,请联系应用管理员核对。';
|
|
214
|
+
if (result.state !== 'undetermined') {
|
|
215
|
+
heldExternalOperation.current = undefined;
|
|
216
|
+
frozenSave.current = undefined;
|
|
217
|
+
frozenPublish.current = undefined;
|
|
218
|
+
frozenAux.current = undefined;
|
|
219
|
+
frozenAuxOperation.current = undefined;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
notice = '原操作结果暂时无法确认,请联系应用管理员核对。当前输入已保留。';
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const value = await loadWorkflowDesignerRead(workflowCode);
|
|
228
|
+
acceptRead(value, false);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
setDraft(undefined);
|
|
232
|
+
setPublishedOnly(undefined);
|
|
233
|
+
}
|
|
234
|
+
setAssistantState({ busy: false, unknown: false });
|
|
235
|
+
setAuthorityNotice(notice);
|
|
236
|
+
setError(notice);
|
|
237
|
+
return true;
|
|
238
|
+
};
|
|
156
239
|
const save = async (quiet = false) => {
|
|
157
|
-
if (!draft || !definition)
|
|
240
|
+
if (!canEdit || authorityStopped.current || !draft || !definition)
|
|
158
241
|
return undefined;
|
|
159
242
|
if (reminderDirty && !frozenSave.current) {
|
|
160
243
|
message.warning('请先确定或取消办理提醒的修改。');
|
|
@@ -167,6 +250,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
167
250
|
setBusy(true);
|
|
168
251
|
try {
|
|
169
252
|
frozenSave.current ||= { expectedRevision: draft.revision, expectedHeadRevision: draft.baseHeadRevision, operationId: createBrowserUuid(), definition, binding: binding };
|
|
253
|
+
definiteBusy.current.delete(frozenSave.current.operationId);
|
|
170
254
|
const saved = await saveWorkflowDesignerDraft(workflowCode, frozenSave.current);
|
|
171
255
|
frozenSave.current = undefined;
|
|
172
256
|
setDraft(saved);
|
|
@@ -178,6 +262,14 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
178
262
|
return saved;
|
|
179
263
|
}
|
|
180
264
|
catch (error) {
|
|
265
|
+
if (await loseAuthority(error))
|
|
266
|
+
return undefined;
|
|
267
|
+
if (isWorkflowDesignerAuthorityBusy(error)) {
|
|
268
|
+
if (frozenSave.current)
|
|
269
|
+
definiteBusy.current.add(frozenSave.current.operationId);
|
|
270
|
+
setError('权限正在变更,本次未写入;请稍后重试原保存请求。');
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
181
273
|
if (refused(error))
|
|
182
274
|
frozenSave.current = undefined;
|
|
183
275
|
setError(`${String(error.message)}${refused(error) ? '。修改已保留,可修正后再次保存。' : '。结果待确认,请重试原保存请求。'}`);
|
|
@@ -190,7 +282,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
190
282
|
const autosave = useRef(save);
|
|
191
283
|
autosave.current = save;
|
|
192
284
|
useEffect(() => {
|
|
193
|
-
if (!dirty || !definition || stepInputInvalid || reminderDirty || busy || publishedView || frozenSave.current || frozenPublish.current || frozenAux.current || attemptedAutosave.current === JSON.stringify({ definition, binding }))
|
|
285
|
+
if (!canEdit || authorityStopped.current || !dirty || !definition || stepInputInvalid || reminderDirty || busy || publishedView || frozenSave.current || frozenPublish.current || frozenAux.current || attemptedAutosave.current === JSON.stringify({ definition, binding }))
|
|
194
286
|
return;
|
|
195
287
|
let timer;
|
|
196
288
|
const persist = () => {
|
|
@@ -203,7 +295,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
203
295
|
};
|
|
204
296
|
timer = setTimeout(persist, 900);
|
|
205
297
|
return () => clearTimeout(timer);
|
|
206
|
-
}, [dirty, definition, binding, busy, publishedView, stepInputInvalid, reminderDirty]);
|
|
298
|
+
}, [dirty, definition, binding, busy, publishedView, stepInputInvalid, reminderDirty, canEdit]);
|
|
207
299
|
const inspectorReady = () => {
|
|
208
300
|
if (stepInputInvalid) {
|
|
209
301
|
message.warning('业务步骤固定值不是有效 JSON,请先修正,或切换此输入来源以放弃该值。');
|
|
@@ -272,9 +364,9 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
272
364
|
next();
|
|
273
365
|
};
|
|
274
366
|
const goBack = () => {
|
|
275
|
-
if (!inspectorReady())
|
|
367
|
+
if (unknown || busy || assistantState.busy || liveState.busy || !inspectorReady())
|
|
276
368
|
return;
|
|
277
|
-
const next = () => { if (dirty) {
|
|
369
|
+
const next = () => { if (dirty && canEdit && !authorityStopped.current) {
|
|
278
370
|
void save(true).then(saved => { if (saved) {
|
|
279
371
|
if (onBack)
|
|
280
372
|
onBack();
|
|
@@ -299,7 +391,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
299
391
|
};
|
|
300
392
|
const holds = () => holdIds.length || holdNodeIds.length ? [{ instanceIds: holdIds, nodeIds: holdNodeIds, reason: holdReason.trim() }] : [];
|
|
301
393
|
const check = async (value = draft, selectedHolds = holds()) => {
|
|
302
|
-
if (!value)
|
|
394
|
+
if (!canPublish || authorityStopped.current || !value)
|
|
303
395
|
return;
|
|
304
396
|
setBusy(true);
|
|
305
397
|
setPreview(undefined);
|
|
@@ -317,6 +409,8 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
317
409
|
}
|
|
318
410
|
};
|
|
319
411
|
const openPublication = async () => {
|
|
412
|
+
if (!canPublish || authorityStopped.current)
|
|
413
|
+
return;
|
|
320
414
|
const saved = dirty || frozenSave.current ? await save() : draft;
|
|
321
415
|
if (!saved)
|
|
322
416
|
return;
|
|
@@ -331,11 +425,12 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
331
425
|
await check(saved, []);
|
|
332
426
|
};
|
|
333
427
|
const publish = async () => {
|
|
334
|
-
if (!draft || !reason.trim() || scope === 'running_and_new' && (holdIds.length || holdNodeIds.length) && !holdReason.trim())
|
|
428
|
+
if (!canPublish || authorityStopped.current || !draft || !reason.trim() || scope === 'running_and_new' && (holdIds.length || holdNodeIds.length) && !holdReason.trim())
|
|
335
429
|
return;
|
|
336
430
|
setBusy(true);
|
|
337
431
|
try {
|
|
338
432
|
frozenPublish.current ||= { expectedRevision: draft.revision, expectedHeadRevision: draft.baseHeadRevision, operationId: createBrowserUuid(), reason: reason.trim(), scope, holds: scope === 'running_and_new' ? holds() : [], acknowledgeExceptions: acknowledge };
|
|
433
|
+
definiteBusy.current.delete(frozenPublish.current.operationId);
|
|
339
434
|
const result = await publishWorkflowDesigner(workflowCode, frozenPublish.current);
|
|
340
435
|
frozenPublish.current = undefined;
|
|
341
436
|
setReceipt(result);
|
|
@@ -345,6 +440,14 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
345
440
|
message.success('流程版本已发布并启用');
|
|
346
441
|
}
|
|
347
442
|
catch (error) {
|
|
443
|
+
if (await loseAuthority(error))
|
|
444
|
+
return;
|
|
445
|
+
if (isWorkflowDesignerAuthorityBusy(error)) {
|
|
446
|
+
if (frozenPublish.current)
|
|
447
|
+
definiteBusy.current.add(frozenPublish.current.operationId);
|
|
448
|
+
setError('权限正在变更,本次未写入;请稍后重试原发布请求。');
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
348
451
|
if (refused(error))
|
|
349
452
|
frozenPublish.current = undefined;
|
|
350
453
|
setError(`${String(error.message)}${refused(error) ? '。草稿已保留。' : '。结果待确认,重试将使用原发布请求。'}`);
|
|
@@ -378,17 +481,30 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
378
481
|
}
|
|
379
482
|
};
|
|
380
483
|
const retryAux = async () => {
|
|
381
|
-
if (!frozenAux.current)
|
|
484
|
+
if (authorityStopped.current || !frozenAux.current)
|
|
382
485
|
return;
|
|
383
486
|
setBusy(true);
|
|
384
487
|
try {
|
|
488
|
+
if (frozenAuxOperation.current)
|
|
489
|
+
definiteBusy.current.delete(frozenAuxOperation.current);
|
|
385
490
|
await frozenAux.current();
|
|
386
491
|
frozenAux.current = undefined;
|
|
492
|
+
frozenAuxOperation.current = undefined;
|
|
387
493
|
setError(undefined);
|
|
388
494
|
}
|
|
389
495
|
catch (error) {
|
|
390
|
-
if (
|
|
496
|
+
if (await loseAuthority(error))
|
|
497
|
+
return;
|
|
498
|
+
if (isWorkflowDesignerAuthorityBusy(error)) {
|
|
499
|
+
if (frozenAuxOperation.current)
|
|
500
|
+
definiteBusy.current.add(frozenAuxOperation.current);
|
|
501
|
+
setError('权限正在变更,本次未写入;请稍后重试原操作。');
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (refused(error)) {
|
|
391
505
|
frozenAux.current = undefined;
|
|
506
|
+
frozenAuxOperation.current = undefined;
|
|
507
|
+
}
|
|
392
508
|
setError(`${String(error.message)}${refused(error) ? '。输入已保留。' : '。结果待确认,请重试原操作。'}`);
|
|
393
509
|
}
|
|
394
510
|
finally {
|
|
@@ -396,9 +512,10 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
396
512
|
}
|
|
397
513
|
};
|
|
398
514
|
const restore = async (version) => {
|
|
399
|
-
if (!draft || frozenAux.current)
|
|
515
|
+
if (!canEdit || authorityStopped.current || !draft || frozenAux.current)
|
|
400
516
|
return;
|
|
401
517
|
const input = { version, expectedRevision: draft.revision, expectedHeadRevision: draft.baseHeadRevision, operationId: createBrowserUuid() };
|
|
518
|
+
frozenAuxOperation.current = input.operationId;
|
|
402
519
|
frozenAux.current = async () => {
|
|
403
520
|
const restored = await restoreWorkflowDesignerVersion(workflowCode, input);
|
|
404
521
|
setDraft(restored);
|
|
@@ -412,10 +529,11 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
412
529
|
await retryAux();
|
|
413
530
|
};
|
|
414
531
|
const control = async (action) => {
|
|
415
|
-
if (!receipt || !draft || frozenAux.current)
|
|
532
|
+
if (!canPublish || authorityStopped.current || !receipt || !draft || frozenAux.current)
|
|
416
533
|
return;
|
|
417
534
|
const publicationId = receipt.publicationId;
|
|
418
535
|
const input = { expectedHeadRevision: draft.baseHeadRevision, operationId: createBrowserUuid(), action, reason: action === 'pause' ? '管理员暂停更新' : action === 'retry_failed' ? '管理员重试更新失败的申请' : '管理员继续更新' };
|
|
536
|
+
frozenAuxOperation.current = input.operationId;
|
|
419
537
|
frozenAux.current = async () => { setReceipt(await controlWorkflowDesignerPublication(workflowCode, publicationId, input)); };
|
|
420
538
|
await retryAux();
|
|
421
539
|
};
|
|
@@ -428,10 +546,11 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
428
546
|
}
|
|
429
547
|
};
|
|
430
548
|
const releaseHolds = async () => {
|
|
431
|
-
if (!receipt || !draft || !releaseIds.length || !releaseReason.trim() || frozenAux.current)
|
|
549
|
+
if (!canPublish || authorityStopped.current || !receipt || !draft || !releaseIds.length || !releaseReason.trim() || frozenAux.current)
|
|
432
550
|
return;
|
|
433
551
|
const publicationId = receipt.publicationId;
|
|
434
552
|
const input = { expectedHeadRevision: draft.baseHeadRevision, operationId: createBrowserUuid(), action: 'release_holds', instanceIds: releaseIds, reason: releaseReason.trim() };
|
|
553
|
+
frozenAuxOperation.current = input.operationId;
|
|
435
554
|
frozenAux.current = async () => { setReceipt(await controlWorkflowDesignerPublication(workflowCode, publicationId, input)); setReleaseIds([]); setReleaseReason(''); };
|
|
436
555
|
await retryAux();
|
|
437
556
|
};
|
|
@@ -514,6 +633,11 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
514
633
|
setError(String(error.message));
|
|
515
634
|
}
|
|
516
635
|
};
|
|
636
|
+
const retained = _jsxs(_Fragment, { children: [retainedPrompt && _jsx(Alert, { type: "warning", title: "\u4FDD\u7559\u7684\u52A9\u624B\u8F93\u5165", description: retainedPrompt, action: _jsx(Button, { onClick: () => setRetainedPrompt(''), children: "\u653E\u5F03\u52A9\u624B\u8F93\u5165" }) }), retainedInput && _jsxs("details", { open: true, children: [_jsx("summary", { children: "\u67E5\u770B\u4FDD\u7559\u7684\u672A\u4FDD\u5B58\u8F93\u5165" }), _jsx(WorkflowDiagram, { graph: projectWorkflowGraph(retainedInput.definition, 'draft'), selectedNodeId: retainedInput.definition.startAt, onSelectNode: () => { } }), _jsx(Input.TextArea, { "aria-label": "\u4FDD\u7559\u7684\u6D41\u7A0B\u4E0E\u4EBA\u5458\u89C4\u5219", readOnly: true, rows: 8, value: JSON.stringify(retainedInput, null, 2) }), _jsx(Button, { onClick: () => setRetainedInput(undefined), children: "\u653E\u5F03\u4FDD\u7559\u8F93\u5165" })] }), retainedNodeInput && _jsx(Alert, { type: "warning", title: `保留的办理设置:${retainedNodeInput.nodeId}`, description: _jsx(Input.TextArea, { "aria-label": "\u4FDD\u7559\u7684\u529E\u7406\u8BBE\u7F6E\u8F93\u5165", readOnly: true, rows: 8, value: JSON.stringify(retainedNodeInput.values, null, 2) }), action: _jsx(Button, { onClick: () => setRetainedNodeInput(undefined), children: "\u653E\u5F03\u529E\u7406\u8BBE\u7F6E\u8F93\u5165" }) })] });
|
|
637
|
+
if (publishedOnly && configurations && nativeHeadRevision != null)
|
|
638
|
+
return _jsxs("section", { className: "oxa-workflow-designer", children: [_jsxs(Space, { wrap: true, children: [_jsx(Button, { onClick: goBack, children: "\u8FD4\u56DE" }), _jsx("h2", { children: publishedOnly.definition.title }), _jsxs(Tag, { children: ["\u5DF2\u53D1\u5E03 v", publishedOnly.definitionVersion] }), _jsx(Button, { onClick: () => void showVersions(), children: "\u7248\u672C\u8BB0\u5F55" })] }), authorityNotice && _jsx(Alert, { type: "warning", title: authorityNotice }), retained, _jsx(WorkflowDiagram, { graph: projectWorkflowGraph(publishedOnly.definition, 'draft'), selectedNodeId: selected, onSelectNode: selectNode }), liveNode && _jsx(WorkflowNodeConfigurationEditor, { workflowCode: workflowCode, node: liveNode, principals: configurations.principals, conditionalAssignment: configurations.conditionalAssignment, expectedHeadRevision: nativeHeadRevision, presentation: "inline", readOnly: !canHandle || authorityStopped.current, onClose: () => setSelected(''), onStateChange: handlingStateChanged, onLeaveGuardChange: handlingGuardChanged, onAuthorityLoss: loseAuthority, onSaved: () => void refreshHandling().catch(failure => setError(String(failure.message))) }, liveNode.nodeId), _jsx(Drawer, { open: versionsOpen, title: "\u6D41\u7A0B\u7248\u672C\u8BB0\u5F55", onClose: () => setVersionsOpen(false), children: _jsx(Table, { rowKey: "publicationId", dataSource: versions, pagination: { pageSize: 10 }, columns: [{ title: '版本', dataIndex: 'definitionVersion' }, { title: '说明', dataIndex: 'reason' }] }) }), error && _jsx(Alert, { type: "error", title: error })] });
|
|
639
|
+
if (authorityStopped.current && !draft && !publishedOnly)
|
|
640
|
+
return _jsxs("section", { children: [_jsx(Alert, { type: "warning", title: authorityNotice || error }), retained, _jsx(Button, { onClick: goBack, children: "\u8FD4\u56DE" })] });
|
|
517
641
|
if (!draft || !definition || !graph || nativeHeadRevision == null)
|
|
518
642
|
return error ? _jsx(Alert, { type: "error", title: "\u6D41\u7A0B\u8BBE\u8BA1\u672A\u80FD\u8F7D\u5165", description: error, action: _jsx(Button, { onClick: () => void load().catch(error => setError(String(error.message))), children: "\u91CD\u65B0\u8F7D\u5165" }) }) : _jsx(Skeleton, { active: true });
|
|
519
643
|
const targets = Object.values(definition.nodes).filter(item => item.id !== selected).map(item => ({ value: item.id, label: item.title || item.id }));
|
|
@@ -526,8 +650,8 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
526
650
|
return [item.nodeId, `${mode}${mode ? ' · ' : ''}${source}`];
|
|
527
651
|
}));
|
|
528
652
|
const human = node?.kind === 'approval' || node?.kind === 'handle';
|
|
529
|
-
const panel = _jsxs("div", { className: "oxa-workflow-designer-inspector", children: [_jsxs("header", { children: [_jsx("span", { className: `oxa-designer-inspector-icon kind-${node?.kind || 'start'}`, children: _jsx(NodeIcon, {}) }), _jsx("h2", { children: node?.title || '流程发起' }), _jsx(Tag, { children: isWorkflowPlatformNotify(node) ? '通知节点' : kinds[node?.kind || ''] || '发起' }), _jsx(Button, { type: "text", icon: _jsx(CloseOutlined, {}), "aria-label": "\u5173\u95ED\u8282\u70B9\u8BBE\u7F6E", onClick: closeInspector })] }), node ? _jsxs(_Fragment, { children: [_jsx("div", { hidden: human && structureKeys.includes('return'), children: liveNode && configurations && ['approval', 'handle', 'cc'].includes(node.kind) ? _jsx(WorkflowNodeConfigurationEditor, { workflowCode: workflowCode, node: liveNode, principals: configurations.principals, expectedHeadRevision: nativeHeadRevision, presentation: "inline", readOnly:
|
|
530
|
-
return; mutate({ ...definition, nodes: { ...definition.nodes, [node.id]: { ...node, ...(entry.provider === 'supervisor_chain' &&
|
|
653
|
+
const panel = _jsxs("div", { className: "oxa-workflow-designer-inspector", children: [_jsxs("header", { children: [_jsx("span", { className: `oxa-designer-inspector-icon kind-${node?.kind || 'start'}`, children: _jsx(NodeIcon, {}) }), _jsx("h2", { children: node?.title || '流程发起' }), _jsx(Tag, { children: isWorkflowPlatformNotify(node) ? '通知节点' : kinds[node?.kind || ''] || '发起' }), _jsx(Button, { type: "text", icon: _jsx(CloseOutlined, {}), "aria-label": "\u5173\u95ED\u8282\u70B9\u8BBE\u7F6E", onClick: closeInspector })] }), node ? _jsxs(_Fragment, { children: [_jsx("div", { hidden: human && structureKeys.includes('return'), children: liveNode && configurations && ['approval', 'handle', 'cc'].includes(node.kind) ? _jsx(WorkflowNodeConfigurationEditor, { workflowCode: workflowCode, node: liveNode, principals: configurations.principals, conditionalAssignment: configurations.conditionalAssignment, expectedHeadRevision: nativeHeadRevision, presentation: "inline", readOnly: !canHandle || authorityStopped.current, compact: !detailInspector && !narrow, onExpand: () => { setDetailInspector(true); setOutline(false); }, onClose: closeInspector, onStateChange: handlingStateChanged, onLeaveGuardChange: handlingGuardChanged, onAuthorityLoss: loseAuthority, returnSummary: human && (node.returnPolicy?.targets || node.returnTargets || []).length ? _jsxs("div", { children: [_jsx(Tag, { color: "gold", children: "\u968F\u8349\u7A3F\u53D1\u5E03" }), _jsx("div", { children: (node.returnPolicy?.targets || (node.returnTargets || []).map(nodeId => ({ nodeId, defaultRoute: 'replay' }))).map(target => _jsxs("p", { children: [definition.nodes[target.nodeId]?.title || '退回目标', " \u00B7 ", target.defaultRoute === 'resume' ? '重新提交后直接回到本节点' : '重新提交后重新按流程流转'] }, target.nodeId)) }), _jsx(Button, { type: "link", size: "small", onClick: () => setStructureKeys(['return']), children: "\u7F16\u8F91\u9000\u56DE\u8BBE\u7F6E" })] }) : undefined, onSaved: () => { void refreshHandling().catch(failure => setError(`办理设置已保存,重新读取失败:${String(failure.message)}`)); } }, `${liveNode.nodeId}:${liveNode.configuration.revision}`) : draft.publishedDefinition.nodes[node.id] && ['approval', 'handle', 'cc'].includes(node.kind) ? _jsx(Alert, { type: "warning", showIcon: true, title: "\u5DF2\u53D1\u5E03\u8282\u70B9\u7684\u529E\u7406\u8BBE\u7F6E\u672A\u80FD\u8F7D\u5165", description: "\u6B64\u8282\u70B9\u4E0D\u662F\u65B0\u589E\u8349\u7A3F\u8282\u70B9\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u914D\u7F6E\u540E\u4FEE\u6539\u3002", action: _jsx(Button, { onClick: () => void refreshHandling().catch(failure => setError(String(failure.message))), children: "\u91CD\u65B0\u8BFB\u53D6\u529E\u7406\u8BBE\u7F6E" }) }) : ['approval', 'handle', 'cc'].includes(node.kind) && _jsx(WorkflowDraftHandlingEditor, { node: node, baseline: node, bindingOptions: Object.keys(draft.publishedBinding.bindings).map(value => ({ value, label: value })), conditionalContext: catalog?.conditionalAssignments ? { definition, nodeId: node.id, standardProviders: ['fixed_users', 'app_role'], releasedSources: Object.fromEntries(Object.entries(catalog.peopleSources).flatMap(([key, source]) => workflowAssignmentLeaves(source).map((leaf, index) => [`${key}/${index}`, leaf]))) } : undefined, binding: binding?.bindings['binding' in node ? node.binding : ''], sources: catalog.peopleSources, principals: configurations?.principals || { users: [], roles: [] }, disabled: disabled, onBindingChange: entry => { if (!('binding' in node) || !binding)
|
|
654
|
+
return; mutate({ ...definition, nodes: { ...definition.nodes, [node.id]: { ...node, ...((entry.provider === 'conditional' ? [...entry.cases.map(rule => rule.assignee), entry.otherwise] : [entry]).some(leaf => leaf.provider === 'supervisor_chain' && leaf.continuous !== false) ? { mode: 'sequence' } : {}) } } }, { ...binding, bindings: { ...binding.bindings, [node.binding]: entry } }); }, onChange: patch }) }), node.kind === 'action' && !isWorkflowPlatformNotify(node) && catalog && _jsx(WorkflowBusinessStepEditor, { node: node, catalog: catalog, variables: variables, disabled: disabled, onValidityChange: setStepInputInvalid, onChange: patch, onAssistant: () => { setAssistantContext(`当前步骤:${node.title}(${node.handler.code} v${node.handler.version})。需要新增业务能力时,请提出源代码与发布契约的改造方案,不要假设新能力已经发布。`); setAssistantOpen(true); setInspector(true); } }, `${node.id}:${node.handler.code}`), node.kind === 'parallel' && _jsx(WorkflowParallelConfigurationEditor, { node: node, selectedBranch: node.branches[(graph.edges.find(edge => edge.id === selectedEdge && edge.from === node.id)?.priority || 0) - 1]?.id, variables: variables, disabled: disabled, onChange: value => patch({ branches: value.branches }), onRemove: branchId => mutate(editWorkflowDesignerDefinition(definition, { type: 'remove_parallel_branch', nodeId: node.id, branchId })) }, node.id), node.kind === 'join' && _jsx(Alert, { type: "info", showIcon: true, title: "\u672C\u6B21\u8FDB\u5165\u7684\u5168\u90E8\u5206\u652F\u5B8C\u6210\u540E\u7EE7\u7EED", description: "\u6C47\u5408\u70B9\u4E0E\u5E76\u884C\u5206\u652F\u6210\u5BF9\u7EF4\u62A4\u3002\u82E5\u8981\u5220\u9664\u6574\u4E2A\u5E76\u884C\u533A\u57DF\uFF0C\u8BF7\u5728\u5E76\u884C\u8282\u70B9\u8BBE\u7F6E\u4E2D\u64CD\u4F5C\u3002" }), node.kind === 'condition' && _jsx(WorkflowConditionConfigurationEditor, { node: node, variables: variables, targets: targets, selectedBranch: graph.edges.find(edge => edge.id === selectedEdge && edge.from === node.id && edge.kind === 'branch')?.priority ? graph.edges.find(edge => edge.id === selectedEdge).priority - 1 : undefined, disabled: disabled, onChange: value => patch({ branches: value.branches, otherwise: value.otherwise }) }, node.id), human && structureKeys.includes('return') && _jsxs(_Fragment, { children: [_jsx(Button, { type: "link", className: "oxa-designer-return-back", icon: _jsx(ArrowLeftOutlined, {}), onClick: () => setStructureKeys([]), children: "\u8FD4\u56DE\u8282\u70B9\u914D\u7F6E" }), _jsx(WorkflowReturnPolicyEditor, { definition: definition, node: node, disabled: disabled, onChange: returnPolicy => patch({ returnPolicy, returnTargets: returnPolicy.targets.map(target => target.nodeId) }) })] }), _jsxs("section", { className: "oxa-designer-draft-band", hidden: human && structureKeys.includes('return'), children: [_jsx("h3", { children: "\u6D41\u7A0B\u7ED3\u6784 \u00B7 \u968F\u8349\u7A3F\u53D1\u5E03" }), _jsx(Collapse, { ghost: true, activeKey: structureKeys, onChange: keys => setStructureKeys(Array.isArray(keys) ? keys : [keys]), items: [
|
|
531
655
|
{ key: 'name', label: '节点名称', extra: _jsx("span", { children: node.title || '未命名节点' }), children: _jsxs("label", { children: ["\u8282\u70B9\u540D\u79F0", _jsx(Input, { disabled: disabled, value: node.title || '', onChange: event => patch({ title: event.target.value }) })] }) },
|
|
532
656
|
...(human ? [{ key: 'return', label: '退回设置', extra: _jsx("span", { children: (node.returnPolicy?.targets || node.returnTargets || []).length ? `可退回 ${(node.returnPolicy?.targets || node.returnTargets || []).length} 个节点` : '未配置退回目标' }), children: null }] : []),
|
|
533
657
|
...(['approval', 'handle', 'correction'].includes(node.kind) ? [{ key: 'reminder', label: '办理提醒', extra: _jsx("span", { children: 'reminders' in node && node.reminders ? `${node.reminders.afterSeconds >= 3600 ? `${node.reminders.afterSeconds / 3600} 小时` : `${node.reminders.afterSeconds / 60} 分钟`}后提醒` : '未设置提醒' }), children: _jsx(_Fragment, { children: ['approval', 'handle', 'correction'].includes(node.kind) && _jsx(WorkflowReminderEditor, { rule: 'reminders' in node ? node.reminders : undefined, disabled: disabled, onDirtyChange: setReminderDirty, onChange: reminders => patch({ reminders }) }, node.id) }) }] : []),
|
|
@@ -548,7 +672,7 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
548
672
|
const messages = { WORKFLOW_DESIGNER_CYCLE: '后续路径形成循环', WORKFLOW_DESIGNER_TARGET_MISSING: '后续节点不存在', WORKFLOW_DESIGNER_UNREACHABLE: '尚未连接到流程', WORKFLOW_DESIGNER_CONDITION_TYPE: '条件变量与比较值类型不一致', WORKFLOW_DESIGNER_VARIABLE_UNKNOWN: '条件变量来源无法确认', WORKFLOW_DESIGNER_CONDITION_BOOLEAN: '条件需要产生满足或不满足的判断', WORKFLOW_DESIGNER_BRANCH_LIMIT: '条件分支数量超出限制' };
|
|
549
673
|
return `${title}:${messages[code || ''] || '配置需要调整'}`;
|
|
550
674
|
};
|
|
551
|
-
return _jsxs("section", { className: "oxa-workflow-designer", "aria-label": "\u6D41\u7A0B\u8BBE\u8BA1\u5668", children: [_jsxs("header", { className: "oxa-designer-toolbar", children: [_jsxs("div", { className: "oxa-designer-toolbar-identity", children: [_jsx(Tooltip, { title: "\u8FD4\u56DE\u6D41\u7A0B\u56FE", children: _jsx(Button, { icon: _jsx(ArrowLeftOutlined, {}), "aria-label": "\u8FD4\u56DE\u6D41\u7A0B\u56FE", disabled: busy ||
|
|
675
|
+
return _jsxs("section", { className: "oxa-workflow-designer", "aria-label": "\u6D41\u7A0B\u8BBE\u8BA1\u5668", children: [_jsxs("header", { className: "oxa-designer-toolbar", children: [_jsxs("div", { className: "oxa-designer-toolbar-identity", children: [_jsx(Tooltip, { title: "\u8FD4\u56DE\u6D41\u7A0B\u56FE", children: _jsx(Button, { icon: _jsx(ArrowLeftOutlined, {}), "aria-label": "\u8FD4\u56DE\u6D41\u7A0B\u56FE", disabled: busy || unknown || assistantState.busy || liveState.busy, onClick: goBack }) }), _jsx("span", { className: "oxa-designer-toolbar-label", children: "\u6D41\u7A0B\u8BBE\u8BA1" }), _jsx("strong", { children: definition.title }), _jsx(Tag, { color: "blue", children: draft.environmentKey === 'production' ? '正式环境' : '测试环境' }), _jsx(Segmented, { "aria-label": "\u6D41\u7A0B\u8BBE\u8BA1\u67E5\u770B\u7248\u672C", value: publishedView ? 'published' : 'draft', onChange: switchVersion, options: [{ value: 'published', label: `已发布 v${draft.definitionVersion}` }, { value: 'draft', label: '草稿' }] }), _jsx("span", { className: "oxa-designer-save-state", children: busy && frozenSave.current ? '正在保存…' : dirty ? errors.length ? '修改待检查' : '草稿未保存' : `${draft.updatedAt ? '草稿已自动保存' : '草稿与已发布版本一致'}${draft.updatedAt ? ` ${new Date(draft.updatedAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}` : ''}` }), (frozenSave.current || dirty && error) && _jsx(Button, { type: "link", disabled: !canEdit || authorityStopped.current || busy, onClick: () => void save(), children: frozenSave.current ? '重试原保存请求' : '重试保存' })] }), _jsxs(Space, { size: 8, className: "oxa-designer-toolbar-actions", children: [_jsx(Tooltip, { title: "\u64A4\u9500", children: _jsx(Button, { icon: _jsx(UndoOutlined, {}), "aria-label": "\u64A4\u9500", disabled: disabled || stepInputInvalid || reminderDirty || !history.length, onClick: () => { const previous = history.at(-1); if (previous) {
|
|
552
676
|
setFuture(current => [...current, { definition, binding: binding }]);
|
|
553
677
|
setHistory(current => current.slice(0, -1));
|
|
554
678
|
setDefinition(previous.definition);
|
|
@@ -561,14 +685,14 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
561
685
|
} }, children: "\u91CD\u505A" }) }), _jsx(Button, { icon: _jsx(SafetyOutlined, {}), onClick: () => setChecksOpen(true), children: "\u7ED3\u6784\u68C0\u67E5" }), _jsx(Button, { icon: _jsx(HistoryOutlined, {}), onClick: () => void showVersions(), children: "\u7248\u672C\u8BB0\u5F55" }), _jsx(Button, { icon: _jsx(RobotOutlined, {}), disabled: disabled || liveState.busy || liveState.unknown, onClick: () => { const open = () => void openAssistant(); if (leaveHandling.current)
|
|
562
686
|
leaveHandling.current(open);
|
|
563
687
|
else
|
|
564
|
-
open(); }, children: "AI \u52A9\u624B" }), _jsx(Button, { type: "primary", disabled:
|
|
688
|
+
open(); }, children: "AI \u52A9\u624B" }), _jsx(Button, { type: "primary", disabled: !canPublish || authorityStopped.current || busy || publishedView || !!frozenSave.current || !!frozenPublish.current || !!frozenAux.current || stepInputInvalid || reminderDirty || errors.length > 0 || liveState.dirty || liveState.busy || liveState.unknown, onClick: () => void openPublication(), children: "\u53D1\u5E03\u5E76\u542F\u7528" })] })] }), error && _jsx(Alert, { type: "error", title: error, action: frozenSave.current ? _jsx(Button, { onClick: () => void save(), children: "\u91CD\u8BD5\u4FDD\u5B58" }) : frozenAux.current ? _jsx(Button, { onClick: () => void retryAux(), children: "\u91CD\u8BD5\u539F\u64CD\u4F5C" }) : undefined }), authorityNotice && _jsx(Alert, { type: "warning", title: authorityNotice }), retained, receipt && _jsxs(_Fragment, { children: [_jsx(Alert, { type: receipt.counts.failed || receipt.counts.excepted ? 'warning' : 'success', title: `已发布 v${receipt.definitionVersion} · ${receipt.status === 'running' ? '正在更新进行中的申请' : '更新处理结束'}`, description: Object.entries(receipt.counts).map(([key, count]) => `${outcomeLabels[key] || key} ${count}`).join(' · '), action: _jsxs(Space, { children: [receipt.status === 'running' && _jsx(Button, { disabled: busy, onClick: () => void control('pause'), children: "\u6682\u505C\u66F4\u65B0" }), receipt.status === 'paused' && _jsx(Button, { disabled: busy, onClick: () => void control('resume'), children: "\u7EE7\u7EED\u66F4\u65B0" }), !!receipt.counts.failed && _jsx(Button, { disabled: busy, onClick: () => void control('retry_failed'), children: "\u91CD\u8BD5\u5931\u8D25\u7684\u7533\u8BF7" })] }) }), receipt.items?.length ? _jsxs("details", { children: [_jsx("summary", { children: "\u67E5\u770B\u7533\u8BF7\u66F4\u65B0\u8BB0\u5F55" }), _jsx(Table, { size: "small", rowKey: "instanceId", dataSource: receipt.items, pagination: { pageSize: 5 }, columns: [{ title: '申请', dataIndex: 'business_key' }, { title: '结果', render: (_, item) => outcomeLabels[item.outcome] || item.outcome }, { title: '原因', dataIndex: 'reason' }] }), receipt.items.some(item => item.outcome === 'held') && _jsxs("div", { style: { padding: 12 }, children: [_jsxs("label", { children: ["\u89E3\u9664\u539F\u7248\u672C\u4FDD\u7559", _jsx(Select, { mode: "multiple", style: { width: '100%' }, value: releaseIds, disabled: busy || !!frozenAux.current, options: receipt.items.filter(item => item.outcome === 'held').map(item => ({ value: item.instanceId, label: item.business_key })), onChange: setReleaseIds })] }), _jsx(Input, { "aria-label": "\u89E3\u9664\u4FDD\u7559\u8BF4\u660E", maxLength: 1000, value: releaseReason, disabled: busy || !!frozenAux.current, onChange: event => setReleaseReason(event.target.value), placeholder: "\u8BF4\u660E\u4E3A\u4EC0\u4E48\u5C06\u8FD9\u4E9B\u7533\u8BF7\u66F4\u65B0\u5230\u5F53\u524D\u7248\u672C" }), _jsx(Button, { disabled: busy || !!frozenAux.current || !releaseIds.length || !releaseReason.trim(), onClick: () => void releaseHolds(), children: "\u89E3\u9664\u4FDD\u7559\u5E76\u66F4\u65B0" })] })] }) : null] }), _jsxs("div", { className: `oxa-designer-workspace ${outline ? '' : 'without-outline'} ${inspector ? '' : 'without-inspector'} ${detailInspector ? 'detail-inspector' : ''}`, children: [_jsxs("aside", { className: "oxa-designer-outline", "aria-label": "\u6D41\u7A0B\u5927\u7EB2", children: [_jsxs("div", { className: "oxa-designer-outline-heading", children: [outline && _jsx("strong", { children: "\u6D41\u7A0B\u5927\u7EB2" }), _jsx(Button, { type: "text", icon: outline ? _jsx(MenuFoldOutlined, {}) : _jsx(MenuUnfoldOutlined, {}), "aria-label": outline ? '收起流程大纲' : '展开流程大纲', onClick: () => { const toggle = () => { if (!outline)
|
|
565
689
|
setDetailInspector(false); setOutline(value => !value); }; if (!outline && leaveHandling.current)
|
|
566
690
|
leaveHandling.current(toggle);
|
|
567
691
|
else
|
|
568
692
|
toggle(); } })] }), outline && _jsx(Input.Search, { size: "small", "aria-label": "\u641C\u7D22\u6D41\u7A0B\u8282\u70B9", placeholder: "\u641C\u7D22\u8282\u70B9", value: outlineKeyword, allowClear: true, onChange: event => setOutlineKeyword(event.target.value) }), _jsx("nav", { children: outlineNodes.filter(item => !outlineKeyword || item.title.includes(outlineKeyword)).map(item => {
|
|
569
693
|
const Icon = item.presentation === 'notification' ? BellOutlined : typeIcons[item.kind] || CodeOutlined;
|
|
570
694
|
return _jsx(Tooltip, { title: !outline ? item.title : undefined, placement: "right", children: _jsxs("button", { type: "button", className: `kind-${item.kind}`, "aria-label": item.title, "aria-pressed": item.edgeId ? selectedEdge === item.edgeId : selected === item.nodeId, style: outline && item.depth ? { paddingLeft: 14 + item.depth * 16 } : undefined, onClick: () => item.edgeId ? selectEdge(item.edgeId) : selectNode(item.nodeId), children: [_jsx(Icon, {}), outline && _jsx("span", { children: item.title })] }) }, item.id);
|
|
571
|
-
}) }), outline && _jsxs("footer", { children: [_jsx("strong", { children: "\u68C0\u67E5\u7ED3\u679C" }), _jsxs("button", { type: "button", onClick: () => setChecksOpen(true), children: [_jsx(CheckCircleOutlined, {}), " ", errors.length ? `发现 ${errors.length} 项问题` : '未发现问题'] })] })] }), _jsxs("main", { children: [_jsxs("div", { className: "oxa-designer-banner", children: [publishedView ? `正在查看已发布 v${draft.definitionVersion}` : '正在编辑草稿', " \u00B7 \u53D1\u5E03\u5E76\u542F\u7528\u65F6\u53EF\u66F4\u65B0\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7"] }), _jsx(WorkflowDiagram, { graph: displayGraph, summaries: summaries, selectedNodeId: selected, selectedEdgeId: selectedEdge, onSelectEdge: selectEdge, onSelectNode: selectNode, presentation: "designer", insertionOptions: [{ value: 'approval', label: '审批', kind: 'approval' }, { value: 'handle', label: '办理', kind: 'handle' }, { value: 'cc', label: '抄送', kind: 'cc' }, ...(variables.length ? [{ value: 'condition', label: '条件分支', kind: 'condition' }] : []), { value: 'parallel', label: '并行分支', kind: 'parallel' }, { value: 'action', label: '业务步骤', kind: 'action' }, { value: 'platform_notify', label: '发送通知', kind: 'notification' }], onInsertEdge: disabled || stepInputInvalid || reminderDirty ? undefined : (value, chosenTemplate) => { const open = () => { if (chosenTemplate) {
|
|
695
|
+
}) }), outline && _jsxs("footer", { children: [_jsx("strong", { children: "\u68C0\u67E5\u7ED3\u679C" }), _jsxs("button", { type: "button", onClick: () => setChecksOpen(true), children: [_jsx(CheckCircleOutlined, {}), " ", errors.length ? `发现 ${errors.length} 项问题` : '未发现问题'] })] })] }), _jsxs("main", { children: [_jsxs("div", { className: "oxa-designer-banner", children: [publishedView ? `正在查看已发布 v${draft.definitionVersion}` : canEdit ? '正在编辑草稿' : '正在审阅草稿', " \u00B7 \u53D1\u5E03\u5E76\u542F\u7528\u65F6\u53EF\u66F4\u65B0\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7"] }), _jsx(WorkflowDiagram, { graph: displayGraph, summaries: summaries, selectedNodeId: selected, selectedEdgeId: selectedEdge, onSelectEdge: selectEdge, onSelectNode: selectNode, presentation: "designer", insertionOptions: [{ value: 'approval', label: '审批', kind: 'approval' }, { value: 'handle', label: '办理', kind: 'handle' }, { value: 'cc', label: '抄送', kind: 'cc' }, ...(variables.length ? [{ value: 'condition', label: '条件分支', kind: 'condition' }] : []), { value: 'parallel', label: '并行分支', kind: 'parallel' }, { value: 'action', label: '业务步骤', kind: 'action' }, { value: 'platform_notify', label: '发送通知', kind: 'notification' }], onInsertEdge: disabled || stepInputInvalid || reminderDirty ? undefined : (value, chosenTemplate) => { const open = () => { if (chosenTemplate) {
|
|
572
696
|
const title = chosenTemplate === 'parallel' ? '并行分支' : chosenTemplate === 'condition' ? '条件分支' : chosenTemplate === 'platform_notify' ? '发送通知' : kinds[chosenTemplate] || draft.publishedDefinition.nodes[chosenTemplate]?.title || '新增节点';
|
|
573
697
|
insertNode(chosenTemplate, title, value);
|
|
574
698
|
}
|
|
@@ -579,8 +703,8 @@ export function WorkflowDesigner({ workflowCode, onPublished, onDirtyChange, onS
|
|
|
579
703
|
} }; if (leaveHandling.current)
|
|
580
704
|
leaveHandling.current(open);
|
|
581
705
|
else
|
|
582
|
-
open(); } }), !inspector && _jsx(Button, { className: "oxa-designer-show-inspector", onClick: () => setInspector(true), children: "\u8282\u70B9\u8BBE\u7F6E" }), _jsxs(Button, { className: "oxa-designer-mobile-inspector", onClick: () => setInspector(true), children: ["\u7F16\u8F91 ", node?.title || '节点'] })] }), inspector && narrow && _jsx("button", { type: "button", className: "oxa-designer-inspector-backdrop", "aria-label": "\u5173\u95ED\u8282\u70B9\u8BBE\u7F6E", onClick: closeInspector }), _jsxs("aside", { style: { display: inspector ? undefined : 'none' }, ref: inspectorElement, className: "oxa-designer-desktop-inspector", role: narrow ? 'dialog' : undefined, "aria-modal": narrow ? true : undefined, "aria-label": assistantOpen ? 'AI 助手' : '节点设置', children: [_jsx("div", { hidden: assistantOpen, children: panel }), _jsx(WorkflowDesignerAssistant, { presentation: "panel", workflowCode: workflowCode, draft: draft, context: assistantContext, open: assistantOpen, canApply: !dirty && !busy && !liveState.dirty && !liveState.busy && !liveState.unknown && !frozenSave.current && !frozenPublish.current && !frozenAux.current, onClose: () => setAssistantOpen(false), onApplied: value => { setPublishedView(false); setDraft(value); setDefinition(value.definition); setBinding(value.binding); setHistory(current => { const snapshots = [...current, { definition, binding: binding }].slice(-25); while (snapshots.length > 1 && snapshots.reduce((bytes, item) => bytes + JSON.stringify(item).length, 0) > 4 * 1024 * 1024)
|
|
583
|
-
snapshots.shift(); return snapshots; }); setFuture([]); setError(undefined); }, onStateChange: setAssistantState })] })] }), _jsx(Drawer, { open: checksOpen, title: "\u6D41\u7A0B\u7ED3\u6784\u68C0\u67E5", width: 440, onClose: () => setChecksOpen(false), children: _jsx(Alert, { showIcon: true, type: errors.length ? 'warning' : 'success', title: errors.length ? `发现 ${errors.length} 项待修正的问题` : '未发现结构问题', description: errors.length ? errors.map(diagnostic).join(';') : '节点与流转路径已通过结构校验。发布时还会检查当前应用的人员规则、页面和业务步骤。' }) }), _jsxs(Modal, { open: !!insert, title: "\u65B0\u589E\u8282\u70B9", onCancel: () => setInsert(undefined), onOk: () => insertNode(), okText: "\u6DFB\u52A0", okButtonProps: { disabled: !nodeTitle.trim() || !template }, children: [_jsx("p", { children: "\u65B0\u589E\u7A7A\u767D\u8282\u70B9\u540E\u81EA\u884C\u914D\u7F6E\u4EBA\u5458\u3001\u6309\u94AE\u548C\u63D0\u9192\u3002\u4E1A\u52A1\u6B65\u9AA4\u4F7F\u7528\u5E94\u7528\u5DF2\u53D1\u5E03\u7684\u80FD\u529B\u3002" }), _jsxs("label", { children: ["\u8282\u70B9\u7C7B\u578B", _jsx(Select, { style: { width: '100%' }, value: template, onChange: setTemplate, options: [{ value: 'approval', label: '审批(空白)' }, { value: 'handle', label: '办理(空白)' }, { value: 'cc', label: '抄送(空白)' }, { value: 'action', label: '已发布业务步骤' }, { value: 'parallel', label: '并行分支' }, { value: 'platform_notify', label: '发送通知' }, ...(variables.length ? [{ value: 'condition', label: '条件分支' }] : []), ...Object.values(draft.publishedDefinition.nodes).filter(node => ['approval', 'handle', 'cc', 'action'].includes(node.kind)).map(node => ({ value: node.id, label: `复制已有配置 · ${node.title}` }))] })] }), _jsxs("label", { children: ["\u8282\u70B9\u540D\u79F0", _jsx(Input, { value: nodeTitle, onChange: event => setNodeTitle(event.target.value) })] })] }), _jsx(Drawer, { open: versionsOpen, title: "\u6D41\u7A0B\u7248\u672C\u8BB0\u5F55", width: 620, onClose: () => setVersionsOpen(false), children: _jsx(Table, { loading: busy, rowKey: "publicationId", dataSource: versions, pagination: { pageSize: 10 }, columns: [{ title: '版本', render: (_, item) => `v${item.definitionVersion}` }, { title: '说明', dataIndex: 'reason' }, { title: '发布时间', dataIndex: 'createdAt', render: value => new Date(value).toLocaleString() }, { title: '操作', render: (_, item) => _jsx(Popconfirm, { title: "\u5C06\u8BE5\u7248\u672C\u6062\u590D\u5230\u5171\u4EAB\u8349\u7A3F\uFF1F", description: "\u5F53\u524D\u8349\u7A3F\u5C06\u88AB\u66FF\u6362\uFF1B\u53D1\u5E03\u540E\u624D\u4F1A\u751F\u6548\u3002", onConfirm: () => void restore(item.definitionVersion), children: _jsx(Button, { disabled: busy || dirty || liveState.dirty || liveState.busy || liveState.unknown || !!frozenSave.current || !!frozenPublish.current || !!frozenAux.current, children: "\u6062\u590D\u5230\u8349\u7A3F" }) }) }] }) }), _jsxs(Modal, { open: publication, title: "\u53D1\u5E03\u5E76\u542F\u7528", width: 648, className: "oxa-designer-publish-modal", cancelText: "\u7EE7\u7EED\u7F16\u8F91", onCancel: () => { if (!frozenPublish.current)
|
|
584
|
-
setPublication(false); }, onOk: () => void publish(), confirmLoading: busy, okText: frozenPublish.current ? '重试原发布请求' : '发布并启用', okButtonProps: { disabled: !reason.trim() || scope === 'running_and_new' && (holdIds.length > 0 || holdNodeIds.length > 0) && !holdReason.trim() || !preview || preview.truncated || scope === 'running_and_new' && !!preview.counts.excepted && !acknowledge }, children: [_jsxs("p", { children: ["\u5C06\u5F53\u524D\u8349\u7A3F\u53D1\u5E03\u5230", draft.environmentKey === 'production' ? '正式环境' : '测试环境', "\u3002\u68C0\u67E5\u901A\u8FC7\u540E\u7ACB\u5373\u751F\u6548\u3002"] }), _jsxs(Spin, { spinning: busy, children: [_jsxs("div", { className: "oxa-designer-publish-checks", children: [_jsx(CheckCircleOutlined, {}), _jsx("span", { children: preview ? '流程与应用能力检查已完成' : '正在检查流程与应用能力' })] }), _jsxs("fieldset", { disabled: busy || !!frozenPublish.current, children: [_jsx("h3", { children: "\u751F\u6548\u8303\u56F4" }), _jsxs(Radio.Group, { value: scope, disabled: busy || !!frozenPublish.current, onChange: event => setScope(event.target.value), className: "oxa-designer-publish-scope", children: [_jsxs(Radio, { value: "running_and_new", children: [_jsxs("strong", { children: ["\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7\u548C\u65B0\u53D1\u8D77\u7684\u7533\u8BF7\u90FD\u4F7F\u7528\u65B0\u7248\u672C", _jsx(Tag, { color: "blue", children: "\u9ED8\u8BA4" })] }), _jsx("small", { children: "\u5DF2\u8FDB\u5165\u7684\u4EFB\u52A1\u4FDD\u7559\u539F\u6709\u4EBA\u9009\u3001\u6309\u94AE\u548C\u9875\u9762\uFF0C\u540E\u7EED\u6D41\u8F6C\u4F7F\u7528\u65B0\u7248\u672C\u3002" })] }), _jsxs(Radio, { value: "new_only", children: [_jsx("strong", { children: "\u4EC5\u65B0\u53D1\u8D77\u7684\u7533\u8BF7\u4F7F\u7528\u65B0\u7248\u672C" }), _jsx("small", { children: "\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7\u7EE7\u7EED\u6309\u539F\u7248\u672C\u529E\u7406\u3002" })] })] }), scope === 'running_and_new' && _jsxs("details", { className: "oxa-designer-publish-holds", children: [_jsxs("summary", { children: ["\u6307\u5B9A\u4FDD\u7559\u5728\u539F\u7248\u672C\u7684\u7533\u8BF7", (holdIds.length > 0 || holdNodeIds.length > 0) && _jsx(Tag, { children: "\u5DF2\u6307\u5B9A" })] }), _jsxs("label", { children: ["\u4FDD\u7559\u539F\u7248\u672C\u7684\u7533\u8BF7", _jsx(Select, { mode: "multiple", showSearch: true, filterOption: false, onSearch: keyword => void searchHolds(keyword), disabled: busy || !!frozenPublish.current, value: holdIds, onChange: value => { setHoldIds(value); setPreview(undefined); }, options: holdCandidates.map(item => ({ value: item.instanceId, label: `${item.businessKey} · ${item.nodeTitle}` })) })] }), _jsxs("label", { children: ["\u4FDD\u7559\u5F53\u524D\u505C\u5728\u8FD9\u4E9B\u8282\u70B9\u7684\u7533\u8BF7", _jsx(Select, { mode: "multiple", disabled: busy || !!frozenPublish.current, value: holdNodeIds, options: Object.values(definition.nodes).filter(node => ['approval', 'handle', 'correction', 'action'].includes(node.kind)).map(node => ({ value: node.id, label: node.title || '流程节点' })), onChange: value => { setHoldNodeIds(value); setPreview(undefined); } })] }), (holdIds.length > 0 || holdNodeIds.length > 0) && _jsxs("label", { children: ["\u4FDD\u7559\u539F\u56E0", _jsx(Input, { disabled: busy || !!frozenPublish.current, value: holdReason, maxLength: 1000, onChange: event => setHoldReason(event.target.value) })] }), _jsx(Button, { disabled: busy || !!frozenPublish.current, onClick: () => void check(), children: "\u91CD\u65B0\u68C0\u67E5\u5F71\u54CD" })] }), preview && scope === 'running_and_new' && _jsxs(_Fragment, { children: [_jsx("h3", { children: "\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7" }), _jsx("dl", { className: "oxa-designer-publish-counts", children: Object.entries(preview.counts).map(([key, count]) => _jsxs("div", { className: `outcome-${key}`, children: [_jsx("dt", { children: outcomeLabels[key] || key }), _jsx("dd", { children: count })] }, key)) }), preview.items.some(item => item.outcome !== 'eligible') && _jsxs("details", { className: "oxa-designer-publish-exceptions", children: [_jsx("summary", { children: "\u67E5\u770B\u9700\u5355\u72EC\u5904\u7406\u7684\u7533\u8BF7" }), _jsx(Table, { size: "small", rowKey: "instanceId", dataSource: preview.items.filter(item => item.outcome !== 'eligible'), pagination: { pageSize: 5 }, columns: [{ title: '申请', dataIndex: 'businessKey' }, { title: '处理', render: (_, item) => outcomeLabels[item.outcome] }, { title: '原因', dataIndex: 'reason' }] })] }), !!preview.counts.excepted && _jsx(Checkbox, { disabled: !!frozenPublish.current || busy, checked: acknowledge, onChange: event => setAcknowledge(event.target.checked), children: "\u6211\u5DF2\u4E86\u89E3\u4E0D\u80FD\u66F4\u65B0\u7684\u7533\u8BF7\u5C06\u4FDD\u7559\u539F\u7248\u672C\uFF0C\u5E76\u5728\u66F4\u65B0\u8BB0\u5F55\u4E2D\u5355\u72EC\u5217\u51FA\u3002" })] }), scope === 'new_only' && _jsx("p", { children: "\u65B0\u53D1\u8D77\u7684\u7533\u8BF7\u4F7F\u7528\u6B64\u7248\u672C\uFF0C\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7\u4FDD\u6301\u5F53\u524D\u7248\u672C\u3002" }), _jsxs("label", { className: "oxa-designer-publish-reason", children: ["\u7248\u672C\u8BF4\u660E", _jsx(Input, { "aria-label": "\u6D41\u7A0B\u7248\u672C\u8BF4\u660E", disabled: busy || !!frozenPublish.current, value: reason, maxLength: 1000, onChange: event => setReason(event.target.value), placeholder: "\u8BF4\u660E\u672C\u6B21\u6D41\u7A0B\u7684\u8C03\u6574" })] })] })] })] })] });
|
|
706
|
+
open(); } }), !inspector && _jsx(Button, { className: "oxa-designer-show-inspector", onClick: () => setInspector(true), children: "\u8282\u70B9\u8BBE\u7F6E" }), _jsxs(Button, { className: "oxa-designer-mobile-inspector", onClick: () => setInspector(true), children: ["\u7F16\u8F91 ", node?.title || '节点'] })] }), inspector && narrow && _jsx("button", { type: "button", className: "oxa-designer-inspector-backdrop", "aria-label": "\u5173\u95ED\u8282\u70B9\u8BBE\u7F6E", onClick: closeInspector }), _jsxs("aside", { style: { display: inspector ? undefined : 'none' }, ref: inspectorElement, className: "oxa-designer-desktop-inspector", role: narrow ? 'dialog' : undefined, "aria-modal": narrow ? true : undefined, "aria-label": assistantOpen ? 'AI 助手' : '节点设置', children: [_jsx("div", { hidden: assistantOpen, children: panel }), _jsx(WorkflowDesignerAssistant, { presentation: "panel", workflowCode: workflowCode, draft: draft, context: assistantContext, open: assistantOpen && canEdit, canApply: canEdit && !authorityStopped.current && !dirty && !busy && !liveState.dirty && !liveState.busy && !liveState.unknown && !frozenSave.current && !frozenPublish.current && !frozenAux.current, onClose: () => setAssistantOpen(false), onApplied: value => { setPublishedView(false); setDraft(value); setDefinition(value.definition); setBinding(value.binding); setHistory(current => { const snapshots = [...current, { definition, binding: binding }].slice(-25); while (snapshots.length > 1 && snapshots.reduce((bytes, item) => bytes + JSON.stringify(item).length, 0) > 4 * 1024 * 1024)
|
|
707
|
+
snapshots.shift(); return snapshots; }); setFuture([]); setError(undefined); }, onStateChange: setAssistantState, onAuthorityLoss: loseAuthority })] })] }), _jsx(Drawer, { open: checksOpen, title: "\u6D41\u7A0B\u7ED3\u6784\u68C0\u67E5", width: 440, onClose: () => setChecksOpen(false), children: _jsx(Alert, { showIcon: true, type: errors.length ? 'warning' : 'success', title: errors.length ? `发现 ${errors.length} 项待修正的问题` : '未发现结构问题', description: errors.length ? errors.map(diagnostic).join(';') : '节点与流转路径已通过结构校验。发布时还会检查当前应用的人员规则、页面和业务步骤。' }) }), _jsxs(Modal, { open: !!insert, title: "\u65B0\u589E\u8282\u70B9", onCancel: () => setInsert(undefined), onOk: () => insertNode(), okText: "\u6DFB\u52A0", okButtonProps: { disabled: !nodeTitle.trim() || !template }, children: [_jsx("p", { children: "\u65B0\u589E\u7A7A\u767D\u8282\u70B9\u540E\u81EA\u884C\u914D\u7F6E\u4EBA\u5458\u3001\u6309\u94AE\u548C\u63D0\u9192\u3002\u4E1A\u52A1\u6B65\u9AA4\u4F7F\u7528\u5E94\u7528\u5DF2\u53D1\u5E03\u7684\u80FD\u529B\u3002" }), _jsxs("label", { children: ["\u8282\u70B9\u7C7B\u578B", _jsx(Select, { style: { width: '100%' }, value: template, onChange: setTemplate, options: [{ value: 'approval', label: '审批(空白)' }, { value: 'handle', label: '办理(空白)' }, { value: 'cc', label: '抄送(空白)' }, { value: 'action', label: '已发布业务步骤' }, { value: 'parallel', label: '并行分支' }, { value: 'platform_notify', label: '发送通知' }, ...(variables.length ? [{ value: 'condition', label: '条件分支' }] : []), ...Object.values(draft.publishedDefinition.nodes).filter(node => ['approval', 'handle', 'cc', 'action'].includes(node.kind)).map(node => ({ value: node.id, label: `复制已有配置 · ${node.title}` }))] })] }), _jsxs("label", { children: ["\u8282\u70B9\u540D\u79F0", _jsx(Input, { value: nodeTitle, onChange: event => setNodeTitle(event.target.value) })] })] }), _jsx(Drawer, { open: versionsOpen, title: "\u6D41\u7A0B\u7248\u672C\u8BB0\u5F55", width: 620, onClose: () => setVersionsOpen(false), children: _jsx(Table, { loading: busy, rowKey: "publicationId", dataSource: versions, pagination: { pageSize: 10 }, columns: [{ title: '版本', render: (_, item) => `v${item.definitionVersion}` }, { title: '说明', dataIndex: 'reason' }, { title: '发布时间', dataIndex: 'createdAt', render: value => new Date(value).toLocaleString() }, { title: '操作', render: (_, item) => _jsx(Popconfirm, { title: "\u5C06\u8BE5\u7248\u672C\u6062\u590D\u5230\u5171\u4EAB\u8349\u7A3F\uFF1F", description: "\u5F53\u524D\u8349\u7A3F\u5C06\u88AB\u66FF\u6362\uFF1B\u53D1\u5E03\u540E\u624D\u4F1A\u751F\u6548\u3002", onConfirm: () => void restore(item.definitionVersion), children: _jsx(Button, { disabled: !canEdit || authorityStopped.current || busy || dirty || liveState.dirty || liveState.busy || liveState.unknown || !!frozenSave.current || !!frozenPublish.current || !!frozenAux.current, children: "\u6062\u590D\u5230\u8349\u7A3F" }) }) }] }) }), _jsxs(Modal, { open: publication, title: "\u53D1\u5E03\u5E76\u542F\u7528", width: 648, className: "oxa-designer-publish-modal", cancelText: "\u7EE7\u7EED\u7F16\u8F91", onCancel: () => { if (!frozenPublish.current)
|
|
708
|
+
setPublication(false); }, onOk: () => void publish(), confirmLoading: busy, okText: frozenPublish.current ? '重试原发布请求' : '发布并启用', okButtonProps: { disabled: !canPublish || authorityStopped.current || !reason.trim() || scope === 'running_and_new' && (holdIds.length > 0 || holdNodeIds.length > 0) && !holdReason.trim() || !preview || preview.truncated || scope === 'running_and_new' && !!preview.counts.excepted && !acknowledge }, children: [_jsxs("p", { children: ["\u5C06\u5F53\u524D\u8349\u7A3F\u53D1\u5E03\u5230", draft.environmentKey === 'production' ? '正式环境' : '测试环境', "\u3002\u68C0\u67E5\u901A\u8FC7\u540E\u7ACB\u5373\u751F\u6548\u3002"] }), _jsxs(Spin, { spinning: busy, children: [_jsxs("div", { className: "oxa-designer-publish-checks", children: [_jsx(CheckCircleOutlined, {}), _jsx("span", { children: preview ? '流程与应用能力检查已完成' : '正在检查流程与应用能力' })] }), _jsxs("fieldset", { disabled: busy || !!frozenPublish.current, children: [_jsx("h3", { children: "\u751F\u6548\u8303\u56F4" }), _jsxs(Radio.Group, { value: scope, disabled: busy || !!frozenPublish.current, onChange: event => setScope(event.target.value), className: "oxa-designer-publish-scope", children: [_jsxs(Radio, { value: "running_and_new", children: [_jsxs("strong", { children: ["\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7\u548C\u65B0\u53D1\u8D77\u7684\u7533\u8BF7\u90FD\u4F7F\u7528\u65B0\u7248\u672C", _jsx(Tag, { color: "blue", children: "\u9ED8\u8BA4" })] }), _jsx("small", { children: "\u5DF2\u8FDB\u5165\u7684\u4EFB\u52A1\u4FDD\u7559\u539F\u6709\u4EBA\u9009\u3001\u6309\u94AE\u548C\u9875\u9762\uFF0C\u540E\u7EED\u6D41\u8F6C\u4F7F\u7528\u65B0\u7248\u672C\u3002" })] }), _jsxs(Radio, { value: "new_only", children: [_jsx("strong", { children: "\u4EC5\u65B0\u53D1\u8D77\u7684\u7533\u8BF7\u4F7F\u7528\u65B0\u7248\u672C" }), _jsx("small", { children: "\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7\u7EE7\u7EED\u6309\u539F\u7248\u672C\u529E\u7406\u3002" })] })] }), scope === 'running_and_new' && _jsxs("details", { className: "oxa-designer-publish-holds", children: [_jsxs("summary", { children: ["\u6307\u5B9A\u4FDD\u7559\u5728\u539F\u7248\u672C\u7684\u7533\u8BF7", (holdIds.length > 0 || holdNodeIds.length > 0) && _jsx(Tag, { children: "\u5DF2\u6307\u5B9A" })] }), _jsxs("label", { children: ["\u4FDD\u7559\u539F\u7248\u672C\u7684\u7533\u8BF7", _jsx(Select, { mode: "multiple", showSearch: true, filterOption: false, onSearch: keyword => void searchHolds(keyword), disabled: busy || !!frozenPublish.current, value: holdIds, onChange: value => { setHoldIds(value); setPreview(undefined); }, options: holdCandidates.map(item => ({ value: item.instanceId, label: `${item.businessKey} · ${item.nodeTitle}` })) })] }), _jsxs("label", { children: ["\u4FDD\u7559\u5F53\u524D\u505C\u5728\u8FD9\u4E9B\u8282\u70B9\u7684\u7533\u8BF7", _jsx(Select, { mode: "multiple", disabled: busy || !!frozenPublish.current, value: holdNodeIds, options: Object.values(definition.nodes).filter(node => ['approval', 'handle', 'correction', 'action'].includes(node.kind)).map(node => ({ value: node.id, label: node.title || '流程节点' })), onChange: value => { setHoldNodeIds(value); setPreview(undefined); } })] }), (holdIds.length > 0 || holdNodeIds.length > 0) && _jsxs("label", { children: ["\u4FDD\u7559\u539F\u56E0", _jsx(Input, { disabled: busy || !!frozenPublish.current, value: holdReason, maxLength: 1000, onChange: event => setHoldReason(event.target.value) })] }), _jsx(Button, { disabled: busy || !!frozenPublish.current, onClick: () => void check(), children: "\u91CD\u65B0\u68C0\u67E5\u5F71\u54CD" })] }), preview && scope === 'running_and_new' && _jsxs(_Fragment, { children: [_jsx("h3", { children: "\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7" }), _jsx("dl", { className: "oxa-designer-publish-counts", children: Object.entries(preview.counts).map(([key, count]) => _jsxs("div", { className: `outcome-${key}`, children: [_jsx("dt", { children: outcomeLabels[key] || key }), _jsx("dd", { children: count })] }, key)) }), preview.items.some(item => item.outcome !== 'eligible') && _jsxs("details", { className: "oxa-designer-publish-exceptions", children: [_jsx("summary", { children: "\u67E5\u770B\u9700\u5355\u72EC\u5904\u7406\u7684\u7533\u8BF7" }), _jsx(Table, { size: "small", rowKey: "instanceId", dataSource: preview.items.filter(item => item.outcome !== 'eligible'), pagination: { pageSize: 5 }, columns: [{ title: '申请', dataIndex: 'businessKey' }, { title: '处理', render: (_, item) => outcomeLabels[item.outcome] }, { title: '原因', dataIndex: 'reason' }] })] }), !!preview.counts.excepted && _jsx(Checkbox, { disabled: !!frozenPublish.current || busy, checked: acknowledge, onChange: event => setAcknowledge(event.target.checked), children: "\u6211\u5DF2\u4E86\u89E3\u4E0D\u80FD\u66F4\u65B0\u7684\u7533\u8BF7\u5C06\u4FDD\u7559\u539F\u7248\u672C\uFF0C\u5E76\u5728\u66F4\u65B0\u8BB0\u5F55\u4E2D\u5355\u72EC\u5217\u51FA\u3002" })] }), scope === 'new_only' && _jsx("p", { children: "\u65B0\u53D1\u8D77\u7684\u7533\u8BF7\u4F7F\u7528\u6B64\u7248\u672C\uFF0C\u8FDB\u884C\u4E2D\u7684\u7533\u8BF7\u4FDD\u6301\u5F53\u524D\u7248\u672C\u3002" }), _jsxs("label", { className: "oxa-designer-publish-reason", children: ["\u7248\u672C\u8BF4\u660E", _jsx(Input, { "aria-label": "\u6D41\u7A0B\u7248\u672C\u8BF4\u660E", disabled: busy || !!frozenPublish.current, value: reason, maxLength: 1000, onChange: event => setReason(event.target.value), placeholder: "\u8BF4\u660E\u672C\u6B21\u6D41\u7A0B\u7684\u8C03\u6574" })] })] })] })] })] });
|
|
585
709
|
}
|
|
586
710
|
//# sourceMappingURL=WorkflowDesigner.js.map
|