openxiangda 2.34.3 → 2.44.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/FilePreviewPage.d.ts.map +1 -1
- package/dist/browser/FilePreviewPage.js +4 -2
- package/dist/browser/FilePreviewPage.js.map +1 -1
- package/dist/browser/ManagedCommand.d.ts +1 -0
- package/dist/browser/ManagedCommand.d.ts.map +1 -1
- package/dist/browser/ManagedCommand.js +1 -1
- package/dist/browser/ManagedCommand.js.map +1 -1
- package/dist/browser/Shell.d.ts.map +1 -1
- package/dist/browser/Shell.js +1 -1
- package/dist/browser/Shell.js.map +1 -1
- package/dist/browser/application.d.ts.map +1 -1
- package/dist/browser/application.js +5 -4
- package/dist/browser/application.js.map +1 -1
- package/dist/browser/components/administration/RoleMembershipManager.d.ts +7 -0
- package/dist/browser/components/administration/RoleMembershipManager.d.ts.map +1 -0
- package/dist/browser/components/administration/RoleMembershipManager.js +724 -0
- package/dist/browser/components/administration/RoleMembershipManager.js.map +1 -0
- package/dist/browser/components/administration/membership-batch-model.d.ts +17 -0
- package/dist/browser/components/administration/membership-batch-model.d.ts.map +1 -0
- package/dist/browser/components/administration/membership-batch-model.js +117 -0
- package/dist/browser/components/administration/membership-batch-model.js.map +1 -0
- package/dist/browser/components/platform-fields/AttachmentFileList.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/AttachmentFileList.js +2 -1
- package/dist/browser/components/platform-fields/AttachmentFileList.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileManagedFileField.d.ts +3 -1
- package/dist/browser/components/platform-fields/MobileManagedFileField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileManagedFileField.js +9 -5
- package/dist/browser/components/platform-fields/MobileManagedFileField.js.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.d.ts +3 -2
- package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.js +9 -9
- package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
- package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +14 -3
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +283 -75
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.d.ts +8 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.js +174 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.d.ts +3 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.js +75 -0
- package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.d.ts +14 -0
- package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.js +117 -0
- package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowDelegationManager.d.ts +14 -0
- package/dist/browser/components/workflow/WorkflowDelegationManager.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowDelegationManager.js +204 -0
- package/dist/browser/components/workflow/WorkflowDelegationManager.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowDiagram.d.ts +16 -0
- package/dist/browser/components/workflow/WorkflowDiagram.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowDiagram.js +110 -0
- package/dist/browser/components/workflow/WorkflowDiagram.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts +23 -0
- package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js +78 -0
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowNodeCard.d.ts +15 -0
- package/dist/browser/components/workflow/WorkflowNodeCard.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowNodeCard.js +16 -0
- package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts +13 -0
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +151 -0
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.d.ts +10 -0
- package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.js +59 -0
- package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskDraftPanel.d.ts +17 -0
- package/dist/browser/components/workflow/WorkflowTaskDraftPanel.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskDraftPanel.js +136 -0
- package/dist/browser/components/workflow/WorkflowTaskDraftPanel.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts +20 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.js +124 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +49 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.js +141 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -0
- package/dist/browser/components/workflow/workflow-flow-layout.d.ts +28 -0
- package/dist/browser/components/workflow/workflow-flow-layout.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-flow-layout.js +54 -0
- package/dist/browser/components/workflow/workflow-flow-layout.js.map +1 -0
- package/dist/browser/components/workflow/workflow-routing-draft.d.ts +4 -0
- package/dist/browser/components/workflow/workflow-routing-draft.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-routing-draft.js +9 -0
- package/dist/browser/components/workflow/workflow-routing-draft.js.map +1 -0
- package/dist/browser/durable-command.d.ts +9 -0
- package/dist/browser/durable-command.d.ts.map +1 -1
- package/dist/browser/durable-command.js +67 -13
- package/dist/browser/durable-command.js.map +1 -1
- package/dist/browser/navigation-guard.d.ts +3 -1
- package/dist/browser/navigation-guard.d.ts.map +1 -1
- package/dist/browser/navigation-guard.js +7 -3
- package/dist/browser/navigation-guard.js.map +1 -1
- package/dist/browser/platform-client.d.ts +76 -3
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +292 -47
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/record-detail.css +10 -0
- package/dist/browser/runtime-authorization-recovery.d.ts +7 -0
- package/dist/browser/runtime-authorization-recovery.d.ts.map +1 -0
- package/dist/browser/runtime-authorization-recovery.js +119 -0
- package/dist/browser/runtime-authorization-recovery.js.map +1 -0
- package/dist/browser/runtime.d.ts +2 -0
- package/dist/browser/runtime.d.ts.map +1 -1
- package/dist/browser/runtime.js +39 -13
- package/dist/browser/runtime.js.map +1 -1
- package/dist/browser/styles.css +155 -0
- package/dist/browser/workflow-task-command-recovery.d.ts +17 -0
- package/dist/browser/workflow-task-command-recovery.d.ts.map +1 -0
- package/dist/browser/workflow-task-command-recovery.js +50 -0
- package/dist/browser/workflow-task-command-recovery.js.map +1 -0
- package/dist/browser/workflow-task-file-upload.d.ts +18 -0
- package/dist/browser/workflow-task-file-upload.d.ts.map +1 -0
- package/dist/browser/workflow-task-file-upload.js +35 -0
- package/dist/browser/workflow-task-file-upload.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/core.d.ts +9 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +3 -0
- package/dist/core.js.map +1 -1
- package/dist/nest.d.ts +2 -2
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js.map +1 -1
- package/dist/react.d.ts +10 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +9 -1
- package/dist/react.js.map +1 -1
- package/documentation/administration.md +190 -0
- package/documentation/frontend.md +2 -0
- package/documentation/getting-started.md +7 -7
- package/documentation/managed-concurrency-frontend.md +9 -4
- package/documentation/managed-concurrency.md +10 -0
- package/documentation/manifest.json +7 -7
- package/documentation/workflow-events.md +237 -3
- package/package.json +26 -23
- package/releases/2.43.0.json +38 -0
- package/releases/2.44.0.json +36 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +4 -4
- package/skills/openxiangda-v2/references/administration.md +190 -0
- package/skills/openxiangda-v2/references/frontend.md +2 -0
- package/skills/openxiangda-v2/references/getting-started.md +7 -7
- package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +9 -4
- package/skills/openxiangda-v2/references/managed-concurrency.md +10 -0
- package/skills/openxiangda-v2/references/workflow-events.md +237 -3
- package/releases/2.0.0.json +0 -50
- package/releases/2.0.1.json +0 -39
- package/releases/2.1.0.json +0 -44
- package/releases/2.1.1.json +0 -48
- package/releases/2.10.0.json +0 -42
- package/releases/2.11.0.json +0 -41
- package/releases/2.12.0.json +0 -38
- package/releases/2.13.0.json +0 -41
- package/releases/2.13.1.json +0 -33
- package/releases/2.13.2.json +0 -31
- package/releases/2.14.0.json +0 -41
- package/releases/2.15.0.json +0 -40
- package/releases/2.16.0.json +0 -41
- package/releases/2.17.0.json +0 -39
- package/releases/2.17.1.json +0 -34
- package/releases/2.18.0.json +0 -37
- package/releases/2.18.1.json +0 -31
- package/releases/2.18.10.json +0 -29
- package/releases/2.18.2.json +0 -30
- package/releases/2.18.3.json +0 -30
- package/releases/2.18.9.json +0 -37
- package/releases/2.19.0.json +0 -38
- package/releases/2.2.0.json +0 -48
- package/releases/2.2.1.json +0 -35
- package/releases/2.2.2.json +0 -34
- package/releases/2.20.0.json +0 -36
- package/releases/2.20.1.json +0 -30
- package/releases/2.20.4.json +0 -30
- package/releases/2.21.0.json +0 -35
- package/releases/2.21.1.json +0 -36
- package/releases/2.21.2.json +0 -34
- package/releases/2.21.3.json +0 -31
- package/releases/2.21.4.json +0 -31
- package/releases/2.22.0.json +0 -35
- package/releases/2.22.1.json +0 -32
- package/releases/2.22.2.json +0 -35
- package/releases/2.22.3.json +0 -32
- package/releases/2.22.4.json +0 -33
- package/releases/2.22.5.json +0 -31
- package/releases/2.22.6.json +0 -29
- package/releases/2.22.7.json +0 -29
- package/releases/2.23.0.json +0 -34
- package/releases/2.24.0.json +0 -33
- package/releases/2.24.1.json +0 -33
- package/releases/2.24.2.json +0 -31
- package/releases/2.24.3.json +0 -33
- package/releases/2.25.0.json +0 -31
- package/releases/2.25.1.json +0 -33
- package/releases/2.25.2.json +0 -32
- package/releases/2.25.3.json +0 -32
- package/releases/2.26.0.json +0 -41
- package/releases/2.27.0.json +0 -38
- package/releases/2.28.0.json +0 -37
- package/releases/2.28.1.json +0 -34
- package/releases/2.29.0.json +0 -37
- package/releases/2.29.1.json +0 -34
- package/releases/2.29.2.json +0 -32
- package/releases/2.3.0.json +0 -37
- package/releases/2.30.0.json +0 -34
- package/releases/2.31.0.json +0 -39
- package/releases/2.31.1.json +0 -38
- package/releases/2.31.2.json +0 -34
- package/releases/2.31.3.json +0 -32
- package/releases/2.31.4.json +0 -33
- package/releases/2.31.5.json +0 -33
- package/releases/2.31.6.json +0 -29
- package/releases/2.31.7.json +0 -29
- package/releases/2.31.8.json +0 -33
- package/releases/2.31.9.json +0 -33
- package/releases/2.32.0.json +0 -38
- package/releases/2.33.0.json +0 -33
- package/releases/2.34.0.json +0 -38
- package/releases/2.34.1.json +0 -34
- package/releases/2.34.2.json +0 -36
- package/releases/2.34.3.json +0 -35
- package/releases/2.4.0.json +0 -37
- package/releases/2.4.1.json +0 -35
- package/releases/2.5.0.json +0 -37
- package/releases/2.6.0.json +0 -37
- package/releases/2.7.0.json +0 -37
- package/releases/2.7.1.json +0 -31
- package/releases/2.8.0.json +0 -32
- package/releases/2.8.1.json +0 -30
- package/releases/2.9.0.json +0 -33
- package/releases/2.9.1.json +0 -31
- package/releases/2.9.2.json +0 -33
- package/releases/2.9.3.json +0 -31
- package/releases/2.9.4.json +0 -37
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { applicationCode } from '../../runtime-meta';
|
|
3
3
|
import { readPendingWorkflowSubmission, writePendingWorkflowSubmission, clearPendingWorkflowSubmission, workflowSubmissionScope, submissionLocatorStorage, standardProcessWasRejected } from '../../workflow-submission-recovery';
|
|
4
|
+
import { readPendingWorkflowTaskCommand, writePendingWorkflowTaskCommand, clearPendingWorkflowTaskCommand, workflowTaskCommandScope, workflowCommandTokenDigest, workflowTaskCommandWasRejected } from '../../workflow-task-command-recovery';
|
|
5
|
+
import { WorkflowTaskForm, useWorkflowTaskForm } from './WorkflowTaskForm';
|
|
6
|
+
import { WorkflowPendingCommandGuard, WorkflowTaskCommandReceipt } from './WorkflowTaskCommandReceipt';
|
|
4
7
|
import { PresentationTime, usePresentationTimeZone } from '../../presentation-time';
|
|
5
8
|
import { ArrowLeftOutlined, ClockCircleOutlined, EllipsisOutlined, ReloadOutlined, CloseOutlined, ExpandOutlined, CompressOutlined, ExportOutlined, } from '@ant-design/icons';
|
|
6
9
|
import { Alert, App, Button, Card, Drawer, Empty, Form, Input, Modal, Result, Segmented, Select, Space, Spin, Table, Tabs, Tag, Tooltip, Typography, } from 'antd';
|
|
@@ -13,7 +16,7 @@ import { executeWorkflowOperation, executeWorkflowLaunchNamedOperation, loadWork
|
|
|
13
16
|
import { useWorkflowDefinition, } from '../../workflow-definitions';
|
|
14
17
|
import { useResourceDefinitions } from '../../resource-definitions';
|
|
15
18
|
import { selectedSurfaceFields } from '../resource/resource-field-selection';
|
|
16
|
-
import { useRuntime } from '../../runtime';
|
|
19
|
+
import { useRuntime, useOptionalRuntime } from '../../runtime';
|
|
17
20
|
import { SurfaceFieldValue, } from '../resource/SurfaceFields';
|
|
18
21
|
import { workflowContextScalarValue, processStatusReadRetryDelay, buildWorkflowNamedOperationInput, parseWorkflowNamedOperationResult, workflowLaunchContractJsonEqual, } from '../../workflow-launch';
|
|
19
22
|
import { normalizeFormValues, normalizeRecordForForm, } from '../platform-fields/field-form-codec';
|
|
@@ -39,13 +42,32 @@ export function shouldRefreshWorkflowSurface(kind, result) {
|
|
|
39
42
|
*/
|
|
40
43
|
export async function completeWorkflowCommand(kind, result, options) {
|
|
41
44
|
const refreshSurface = shouldRefreshWorkflowSurface(kind, result);
|
|
42
|
-
|
|
45
|
+
let nextSurface = null;
|
|
46
|
+
let refreshFailure;
|
|
47
|
+
try {
|
|
48
|
+
nextSurface = refreshSurface ? await options.refresh() : null;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
refreshFailure = error;
|
|
52
|
+
}
|
|
43
53
|
await options.onCommandCompleted?.(result);
|
|
44
54
|
if (nextSurface)
|
|
45
55
|
await options.onCompleted?.(nextSurface, result);
|
|
56
|
+
if (refreshFailure)
|
|
57
|
+
throw refreshFailure;
|
|
46
58
|
return nextSurface;
|
|
47
59
|
}
|
|
48
60
|
function errorMessage(error, fallback) {
|
|
61
|
+
const code = error?.code;
|
|
62
|
+
const taskPageMessages = {
|
|
63
|
+
WORKFLOW_TASK_FORM_REQUIRED: '请完成本页必填资料后再提交。',
|
|
64
|
+
WORKFLOW_TASK_FORM_REVISION_CONFLICT: '业务资料已被其他处理人更新。请刷新并核对,当前输入会保留。',
|
|
65
|
+
WORKFLOW_TASK_FORM_RECOMPUTATION_REQUIRED: '这些资料会影响已完成的计算,请退回到计算前的节点重新办理。',
|
|
66
|
+
WORKFLOW_TASK_FORM_FIELD_NOT_EDITABLE: '页面规则已变化,请刷新资料后重新确认。',
|
|
67
|
+
WORKFLOW_TASK_FORM_COMMAND_FORBIDDEN: '此操作不提交补填资料,请使用保存补填、同意或重新提交。',
|
|
68
|
+
};
|
|
69
|
+
if (code && taskPageMessages[code])
|
|
70
|
+
return taskPageMessages[code];
|
|
49
71
|
return error instanceof Error ? error.message : fallback;
|
|
50
72
|
}
|
|
51
73
|
function randomId(prefix) {
|
|
@@ -299,7 +321,8 @@ export function WorkflowTimelineSection({ timeline, }) {
|
|
|
299
321
|
return (_jsx(Card, { className: "oxa-workflow-timeline-card", title: "\u5BA1\u6279\u6D41\u7A0B", children: entries.length ? (_jsx("div", { className: "oxa-workflow-timeline", children: entries.map((item) => {
|
|
300
322
|
const operations = item.operations || [];
|
|
301
323
|
const visiblePeople = visibleWorkflowTimelinePeople(item, operations);
|
|
302
|
-
|
|
324
|
+
const businessStep = item.nodeKind === 'action' ? item.result.businessStep : undefined;
|
|
325
|
+
return (_jsxs("div", { className: timelineTone(item.status), children: [_jsx("span", { className: "oxa-workflow-timeline-dot", children: _jsx(WorkflowStatusIcon, { status: item.status }) }), _jsxs("div", { children: [_jsxs("div", { className: "oxa-workflow-timeline-title", children: [_jsx("strong", { children: item.title }), businessStep?.status === 'waiting' ? _jsx(Tag, { color: "processing", children: "\u7B49\u5F85\u4E1A\u52A1\u7ED3\u679C" }) : businessStep?.status === 'result_ready' ? _jsx(Tag, { color: "warning", children: "\u63A8\u8FDB\u53D7\u963B" }) : _jsx(StatusTag, { status: item.status })] }), businessStep?.status === 'result_ready' && _jsx(Typography.Text, { type: "secondary", children: "\u8BA1\u7B97\u7ED3\u679C\u5DF2\u6536\u5230\uFF0C\u540E\u7EED\u6D41\u8F6C\u7B49\u5F85\u4FEE\u590D\u3002" }), visiblePeople.length > 0 && (_jsx("div", { className: "oxa-workflow-timeline-assignees", children: visiblePeople.map((person, index) => (_jsxs("div", { children: [_jsx(PlatformAvatar, { avatarUrl: person.avatarUrl, size: 20 }), _jsxs("span", { children: [_jsx(Typography.Text, { children: person.displayName }), person.departmentDisplayName && (_jsx("small", { children: person.departmentDisplayName }))] })] }, `${person.userId || person.displayName}:${index}`))) })), operations.length > 0 && (_jsx("div", { className: "oxa-workflow-timeline-operations", children: operations.map((operation) => (_jsxs("div", { children: [_jsx(PlatformAvatar, { avatarUrl: operation.actor.avatarUrl, size: 20 }), _jsxs("span", { className: "oxa-workflow-operation-content", children: [_jsxs("span", { children: [_jsx(Typography.Text, { children: operation.actor.displayName }), _jsx("strong", { children: operation.operationLabel })] }), operation.reason && (_jsxs("span", { className: "oxa-workflow-operation-opinion", children: [_jsx(Typography.Text, { type: "secondary", children: "\u610F\u89C1" }), _jsx(Typography.Text, { children: operation.reason })] }))] })] }, operation.id))) })), item.terminalReason && !operations.some(operation => operation.reason) && (_jsxs(Typography.Text, { type: "secondary", children: ["\u539F\u56E0\uFF1A", item.terminalReason] })), item.primaryDisplayTime && (_jsx("time", { className: "oxa-workflow-primary-time", children: formatTime(item.primaryDisplayTime) }))] })] }, item.key));
|
|
303
326
|
}) })) : (_jsx(Empty, { description: "\u6682\u65E0\u6D41\u7A0B\u8F68\u8FF9", image: Empty.PRESENTED_IMAGE_SIMPLE })) }));
|
|
304
327
|
}
|
|
305
328
|
function WorkflowMemberPicker({ id, placeholder, value, onChange, multiple = false, variant }) {
|
|
@@ -360,18 +383,36 @@ function OperationDialog({ error, operation, submitting, variant, onCancel, onSu
|
|
|
360
383
|
if (!operation)
|
|
361
384
|
return null;
|
|
362
385
|
const ui = operation.uiSchema;
|
|
363
|
-
const formNode = (_jsxs(Form, { form: form, layout: "vertical", onFinish: onSubmit, children: [error && _jsx(Alert, { role: "alert", title: "\u5BA1\u6279\u5C1A\u672A\u5B8C\u6210", description: error, showIcon: true, type: "error" }), ui.confirmation?.description && (_jsx(Alert, { className: "oxa-workflow-operation-alert", description: ui.confirmation.description, showIcon: true, type: operation.emphasis === 'danger' ? 'warning' : 'info' })), _jsx(OperationFields, { operation: operation, variant: variant })] }));
|
|
386
|
+
const formNode = (_jsxs(Form, { form: form, layout: "vertical", onFinish: onSubmit, disabled: submitting, children: [error && _jsx(Alert, { role: "alert", title: "\u5BA1\u6279\u5C1A\u672A\u5B8C\u6210", description: error, showIcon: true, type: "error" }), ui.confirmation?.description && (_jsx(Alert, { className: "oxa-workflow-operation-alert", description: ui.confirmation.description, showIcon: true, type: operation.emphasis === 'danger' ? 'warning' : 'info' })), _jsx(OperationFields, { operation: operation, variant: variant })] }));
|
|
364
387
|
if (variant === 'mobile') {
|
|
365
388
|
return (_jsx(Drawer, { extra: _jsx(Button, { loading: submitting, onClick: () => form.submit(), type: "primary", children: ui.confirmText || `确认${operation.label}` }), rootClassName: "oxa-workflow-operation-drawer", styles: { body: { overflowY: 'auto', minHeight: 0 } }, keyboard: !submitting, mask: { closable: !submitting }, closable: !submitting, onClose: submitting ? undefined : onCancel, open: true, placement: "bottom", size: "min(640px, 92dvh)", title: operation.label, children: formNode }));
|
|
366
389
|
}
|
|
367
|
-
return (_jsx(Modal, { cancelText: "\u53D6\u6D88", confirmLoading: submitting, okText: ui.confirmText || `确认${operation.label}`, onCancel: onCancel, onOk: () => form.submit(), open: true, title: operation.label, children: formNode }));
|
|
390
|
+
return (_jsx(Modal, { cancelText: "\u53D6\u6D88", confirmLoading: submitting, cancelButtonProps: { disabled: submitting }, okText: ui.confirmText || `确认${operation.label}`, onCancel: onCancel, onOk: () => form.submit(), open: true, title: operation.label, keyboard: !submitting, mask: { closable: !submitting }, closable: !submitting, children: formNode }));
|
|
368
391
|
}
|
|
369
|
-
function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, }) {
|
|
392
|
+
function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pendingLocator, persistLocator, clearLocator, onBusyChange, settlement, confirmedReadPending, renderLayout, }) {
|
|
370
393
|
const { message } = App.useApp();
|
|
371
394
|
const [selectedState, setSelectedState] = useState(null);
|
|
372
395
|
const [moreOpen, setMoreOpen] = useState(false);
|
|
373
396
|
const [operationError, setOperationError] = useState('');
|
|
374
397
|
const [submitting, setSubmitting] = useState(false);
|
|
398
|
+
const [draftLocked, setDraftLocked] = useState(false);
|
|
399
|
+
const [fileLocked, setFileLocked] = useState(false);
|
|
400
|
+
const [refreshFailure, setRefreshFailure] = useState(null);
|
|
401
|
+
const [unknown, setUnknown] = useState(false);
|
|
402
|
+
const request = useRef(null);
|
|
403
|
+
const mounted = useRef(false);
|
|
404
|
+
const busyRef = useRef(false);
|
|
405
|
+
const taskForm = useWorkflowTaskForm(surface.taskForm);
|
|
406
|
+
useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
if (!settlement || request.current?.key !== settlement.key)
|
|
409
|
+
return;
|
|
410
|
+
if (settlement.result)
|
|
411
|
+
taskForm.committed(request.current.input.form, Number(settlement.result.dataRevision) || undefined);
|
|
412
|
+
request.current = null;
|
|
413
|
+
setUnknown(false);
|
|
414
|
+
setSelectedState(null);
|
|
415
|
+
}, [settlement]);
|
|
375
416
|
const operations = standardWorkflowOperations(surface);
|
|
376
417
|
const selected = selectedState?.surface === surface
|
|
377
418
|
? operations.find((operation) => operation.key === selectedState.operation.key &&
|
|
@@ -379,9 +420,9 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
379
420
|
selectedState.operationSignature) || null
|
|
380
421
|
: null;
|
|
381
422
|
useEffect(() => {
|
|
382
|
-
if (selectedState && !selected)
|
|
423
|
+
if (selectedState && !selected && !submitting && !unknown)
|
|
383
424
|
setSelectedState(null);
|
|
384
|
-
}, [selected, selectedState]);
|
|
425
|
+
}, [selected, selectedState, submitting, unknown]);
|
|
385
426
|
const selectOperation = (operation) => {
|
|
386
427
|
setOperationError('');
|
|
387
428
|
setSelectedState({
|
|
@@ -391,10 +432,12 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
391
432
|
});
|
|
392
433
|
};
|
|
393
434
|
const submit = async (values) => {
|
|
394
|
-
if (!selected ||
|
|
435
|
+
if (!selected || busyRef.current || draftLocked || fileLocked || taskForm.draftNeedsSave || pendingLocator || unknown || refreshFailure || confirmedReadPending)
|
|
395
436
|
return;
|
|
396
437
|
setOperationError('');
|
|
397
438
|
setSubmitting(true);
|
|
439
|
+
busyRef.current = true;
|
|
440
|
+
onBusyChange(true);
|
|
398
441
|
try {
|
|
399
442
|
if (selected.kind !== 'workflow_command') {
|
|
400
443
|
throw new Error('WORKFLOW_APP_ACTION_NOT_EXECUTABLE_IN_STANDARD_PANEL');
|
|
@@ -408,15 +451,22 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
408
451
|
await onRefresh();
|
|
409
452
|
throw new Error('WORKFLOW_COMMAND_SURFACE_EXPIRED');
|
|
410
453
|
}
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
454
|
+
const input = { ...values };
|
|
455
|
+
if (surface.taskForm && ['save_form', 'approve', 'resubmit'].includes(selected.key)) {
|
|
456
|
+
if (taskForm.stale)
|
|
457
|
+
throw new Error('业务资料已更新,请先核对最新资料');
|
|
458
|
+
input.form = await taskForm.build(selected.key !== 'save_form');
|
|
459
|
+
}
|
|
460
|
+
const key = randomId(`workflow:${selected.key}`);
|
|
461
|
+
if (surface.task?.id)
|
|
462
|
+
persistLocator({ taskId: String(surface.task.id), command: selected.key,
|
|
463
|
+
idempotencyKey: key, requestedAt: new Date().toISOString(), tokenDigest: await workflowCommandTokenDigest(commandToken) });
|
|
464
|
+
request.current = { surface, operation: selected, input: JSON.parse(JSON.stringify(input)), key };
|
|
415
465
|
}
|
|
416
466
|
catch (error) {
|
|
417
467
|
const hasFreshSurface = Boolean(error?.data?.freshSurface);
|
|
418
468
|
if (hasFreshSurface) {
|
|
419
|
-
await onRefresh();
|
|
469
|
+
await onRefresh().catch(() => undefined);
|
|
420
470
|
setSelectedState(null);
|
|
421
471
|
message.warning('内容已更新,请刷新后重试');
|
|
422
472
|
}
|
|
@@ -427,13 +477,112 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
427
477
|
setOperationError(failure);
|
|
428
478
|
message.error(failure);
|
|
429
479
|
}
|
|
480
|
+
setSubmitting(false);
|
|
481
|
+
busyRef.current = false;
|
|
482
|
+
onBusyChange(false);
|
|
483
|
+
return;
|
|
430
484
|
}
|
|
431
|
-
|
|
485
|
+
await sendRequest(false);
|
|
486
|
+
};
|
|
487
|
+
const sendRequest = async (recovering) => {
|
|
488
|
+
const wire = request.current;
|
|
489
|
+
if (!wire || (recovering && busyRef.current))
|
|
490
|
+
return;
|
|
491
|
+
setSubmitting(true);
|
|
492
|
+
busyRef.current = true;
|
|
493
|
+
onBusyChange(true);
|
|
494
|
+
setOperationError('');
|
|
495
|
+
let result;
|
|
496
|
+
try {
|
|
497
|
+
// Replay uses the exact token, input and key captured before the first write.
|
|
498
|
+
result = await executeWorkflowOperation(wire.surface, wire.operation, wire.input, { idempotencyKey: wire.key });
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
if (!mounted.current)
|
|
502
|
+
return;
|
|
503
|
+
const rejected = !recovering && workflowTaskCommandWasRejected(error);
|
|
504
|
+
if (rejected) {
|
|
505
|
+
clearLocator(wire.key);
|
|
506
|
+
request.current = null;
|
|
507
|
+
setSelectedState(null);
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
setUnknown(true);
|
|
511
|
+
setSelectedState(null);
|
|
512
|
+
}
|
|
513
|
+
const failure = errorMessage(error, '任务操作尚未完成');
|
|
514
|
+
setOperationError(failure);
|
|
515
|
+
if (rejected) {
|
|
516
|
+
message.error(failure);
|
|
517
|
+
// A definitive refusal permits a read, never an automatic new write.
|
|
518
|
+
// Keep this controller mounted so dirty inputs survive the fresh CAS.
|
|
519
|
+
try {
|
|
520
|
+
await onRefresh();
|
|
521
|
+
if (mounted.current)
|
|
522
|
+
setRefreshFailure(null);
|
|
523
|
+
}
|
|
524
|
+
catch (reason) {
|
|
525
|
+
if (mounted.current)
|
|
526
|
+
setRefreshFailure({ outcome: 'rejected', message: errorMessage(reason, '最新资料读取失败') });
|
|
527
|
+
}
|
|
528
|
+
}
|
|
432
529
|
setSubmitting(false);
|
|
530
|
+
busyRef.current = false;
|
|
531
|
+
onBusyChange(false);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
if (!mounted.current)
|
|
535
|
+
return;
|
|
536
|
+
clearLocator(wire.key);
|
|
537
|
+
request.current = null;
|
|
538
|
+
setUnknown(false);
|
|
539
|
+
setSelectedState(null);
|
|
540
|
+
taskForm.committed(wire.input.form, Number(result.dataRevision) || undefined);
|
|
541
|
+
onBusyChange(false);
|
|
542
|
+
message.success(`${wire.operation.label}已提交`);
|
|
543
|
+
// The write has succeeded. A callback or read failure can only affect refresh.
|
|
544
|
+
try {
|
|
545
|
+
await onCommandSuccess(result);
|
|
546
|
+
}
|
|
547
|
+
catch (error) {
|
|
548
|
+
if (mounted.current)
|
|
549
|
+
setRefreshFailure({ outcome: 'succeeded', message: errorMessage(error, '页面刷新失败') });
|
|
550
|
+
}
|
|
551
|
+
finally {
|
|
552
|
+
if (mounted.current) {
|
|
553
|
+
setSubmitting(false);
|
|
554
|
+
busyRef.current = false;
|
|
555
|
+
onBusyChange(false);
|
|
556
|
+
}
|
|
433
557
|
}
|
|
434
558
|
};
|
|
435
|
-
|
|
436
|
-
|
|
559
|
+
const refreshConfirmed = async () => {
|
|
560
|
+
if (busyRef.current)
|
|
561
|
+
return;
|
|
562
|
+
setSubmitting(true);
|
|
563
|
+
busyRef.current = true;
|
|
564
|
+
onBusyChange(true);
|
|
565
|
+
try {
|
|
566
|
+
await onRefresh();
|
|
567
|
+
if (mounted.current)
|
|
568
|
+
setRefreshFailure(null);
|
|
569
|
+
}
|
|
570
|
+
catch (error) {
|
|
571
|
+
if (mounted.current)
|
|
572
|
+
setRefreshFailure(current => ({ outcome: current?.outcome || 'rejected', message: errorMessage(error, '页面刷新失败') }));
|
|
573
|
+
}
|
|
574
|
+
finally {
|
|
575
|
+
if (mounted.current) {
|
|
576
|
+
setSubmitting(false);
|
|
577
|
+
busyRef.current = false;
|
|
578
|
+
onBusyChange(false);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
const commandLocked = submitting || unknown || Boolean(pendingLocator) || Boolean(refreshFailure) || confirmedReadPending;
|
|
583
|
+
const locked = commandLocked || draftLocked || fileLocked;
|
|
584
|
+
if (!operations.length && !surface.taskForm && !unknown && !refreshFailure)
|
|
585
|
+
return renderLayout({ content: null, actions: null });
|
|
437
586
|
const primary = operations
|
|
438
587
|
.filter((operation) => operation.placement === 'primary')
|
|
439
588
|
.sort((left, right) => {
|
|
@@ -443,10 +592,13 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
443
592
|
return (order[left.key] ?? 10) - (order[right.key] ?? 10);
|
|
444
593
|
});
|
|
445
594
|
const secondary = operations.filter((operation) => operation.placement !== 'primary');
|
|
446
|
-
|
|
595
|
+
const content = surface.taskForm || ((submitting || unknown) && !pendingLocator) || unknown || refreshFailure ? (_jsxs(_Fragment, { children: [surface.taskForm && _jsx(WorkflowTaskForm, { controller: taskForm, disabled: locked, variant: variant, taskId: surface.task?.id ? String(surface.task.id) : undefined, draftDisabled: commandLocked, onRefresh: onRefresh, onDraftBusyChange: busy => { setDraftLocked(busy); onBusyChange(busy || fileLocked || busyRef.current); }, onFileBusyChange: busy => { setFileLocked(busy); onBusyChange(busy || draftLocked || busyRef.current); }, resourceCode: surface.presentation.businessDetail.resourceCode || undefined, recordId: surface.presentation.businessDetail.recordId || undefined }), (submitting || unknown) && !pendingLocator && _jsx(WorkflowPendingCommandGuard, {}), unknown && _jsx(Alert, { type: "warning", showIcon: true, title: "\u4FDD\u7559\u4E86\u539F\u63D0\u4EA4\u8BF7\u6C42", description: operationError || '提交结果待确认,请重试原请求或查询原结果。', action: _jsx(Button, { disabled: submitting, loading: submitting, onClick: () => void sendRequest(true), children: "\u91CD\u8BD5\u539F\u8BF7\u6C42" }) }), refreshFailure && _jsx(Alert, { type: "warning", showIcon: true, title: refreshFailure.outcome === 'succeeded'
|
|
596
|
+
? '任务操作已成功,但资料刷新失败' : '本次未提交,最新资料读取失败', description: refreshFailure.message, action: _jsx(Button, { disabled: submitting, onClick: () => void refreshConfirmed(), children: "\u5237\u65B0\u8D44\u6599" }) })] })) : null;
|
|
597
|
+
const actions = (_jsxs(_Fragment, { children: [_jsxs("div", { className: `oxa-workflow-actions oxa-workflow-actions-${variant}`, children: [primary.map((operation) => (_jsx(Button, { danger: operation.emphasis === 'danger', disabled: locked || taskForm.stale || taskForm.draftNeedsSave || !operation.enabled, onClick: () => selectOperation(operation), title: operation.disabledReason, type: operation.emphasis === 'primary' ? 'primary' : 'default', children: operation.label }, operation.key))), secondary.length > 0 && (_jsx(Button, { className: "oxa-workflow-more-trigger", disabled: locked || taskForm.stale || taskForm.draftNeedsSave, icon: _jsx(EllipsisOutlined, {}), onClick: () => setMoreOpen((value) => !value), children: "\u66F4\u591A\u64CD\u4F5C" })), secondary.length > 0 && moreOpen && (_jsx("div", { className: "oxa-workflow-more-actions", children: secondary.map((operation) => (_jsx(Button, { disabled: locked || taskForm.stale || taskForm.draftNeedsSave || !operation.enabled, onClick: () => {
|
|
447
598
|
setMoreOpen(false);
|
|
448
599
|
selectOperation(operation);
|
|
449
600
|
}, type: "text", title: operation.disabledReason, children: operation.label }, operation.key))) }))] }), _jsx(OperationDialog, { error: operationError, onCancel: () => setSelectedState(null), onSubmit: (values) => void submit(values), operation: selected, submitting: submitting, variant: variant })] }));
|
|
601
|
+
return renderLayout({ content, actions });
|
|
450
602
|
}
|
|
451
603
|
/**
|
|
452
604
|
* Shared lifecycle for the embeddable task and instance operation panels.
|
|
@@ -456,13 +608,40 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
456
608
|
* idempotency, and state transitions; all operation controls continue to be
|
|
457
609
|
* rendered by WorkflowOperations above.
|
|
458
610
|
*/
|
|
459
|
-
function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: suppliedSurface, onSurfaceChange, onCompleted, onCommandCompleted, loadSurface, matchesSurface, missingIdentifierMessage, surfaceMismatchMessage, loadingLabel, loadErrorFallback, }) {
|
|
611
|
+
function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: suppliedSurface, onSurfaceChange, onCompleted, onCommandCompleted, loadSurface, matchesSurface, missingIdentifierMessage, surfaceMismatchMessage, loadingLabel, loadErrorFallback, renderLayout, }) {
|
|
460
612
|
const normalizedIdentifier = identifier.trim();
|
|
613
|
+
const runtime = useOptionalRuntime();
|
|
614
|
+
const { message } = App.useApp();
|
|
615
|
+
const locatorScope = surfaceKind === 'task' && runtime
|
|
616
|
+
? workflowTaskCommandScope(applicationCode(), runtime.identity.environment.id, runtime.identity.userId, normalizedIdentifier) : '';
|
|
617
|
+
const [locatorState, setLocatorState] = useState(() => ({ scope: locatorScope, value: locatorScope ? readPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope) : null }));
|
|
618
|
+
const [writing, setWriting] = useState(false);
|
|
619
|
+
const [settlement, setSettlement] = useState(null);
|
|
620
|
+
const [confirmedReadFailure, setConfirmedReadFailure] = useState(null);
|
|
621
|
+
const locator = locatorState.scope === locatorScope ? locatorState.value : null;
|
|
622
|
+
useEffect(() => {
|
|
623
|
+
setLocatorState({ scope: locatorScope, value: locatorScope ? readPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope) : null });
|
|
624
|
+
}, [locatorScope]);
|
|
625
|
+
const persistLocator = (value) => {
|
|
626
|
+
if (!locatorScope)
|
|
627
|
+
return;
|
|
628
|
+
if (!writePendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope, value))
|
|
629
|
+
message.warning('原请求已保留在当前页面,请在此确认提交结果。');
|
|
630
|
+
setLocatorState({ scope: locatorScope, value });
|
|
631
|
+
};
|
|
632
|
+
const clearLocator = (key) => {
|
|
633
|
+
if (locatorScope)
|
|
634
|
+
clearPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope, key);
|
|
635
|
+
setLocatorState(current => current.scope === locatorScope && current.value?.idempotencyKey === key
|
|
636
|
+
? { scope: locatorScope, value: null } : current);
|
|
637
|
+
};
|
|
461
638
|
const inputSurface = suppliedSurface || null;
|
|
462
639
|
const suppliedSurfaceMatches = matchesSurface(inputSurface, normalizedIdentifier);
|
|
463
640
|
const initialSurface = suppliedSurfaceMatches ? inputSurface : null;
|
|
464
641
|
const [surface, setSurface] = useState(initialSurface);
|
|
465
642
|
const [surfaceIdentifier, setSurfaceIdentifier] = useState(initialSurface ? normalizedIdentifier : null);
|
|
643
|
+
const displayedSurfaceRef = useRef(surface);
|
|
644
|
+
displayedSurfaceRef.current = surface;
|
|
466
645
|
const [acceptedInputSurface, setAcceptedInputSurface] = useState(initialSurface ? inputSurface : null);
|
|
467
646
|
const [loading, setLoading] = useState(!initialSurface);
|
|
468
647
|
const [loadingIdentifier, setLoadingIdentifier] = useState(initialSurface ? null : normalizedIdentifier);
|
|
@@ -514,8 +693,10 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
514
693
|
}
|
|
515
694
|
const requestInputSurface = currentInputSurfaceRef.current;
|
|
516
695
|
setAcceptedInputSurface(requestInputSurface);
|
|
517
|
-
|
|
518
|
-
|
|
696
|
+
if (!matchesSurface(displayedSurfaceRef.current, requestIdentifier)) {
|
|
697
|
+
setSurface(null);
|
|
698
|
+
setSurfaceIdentifier(null);
|
|
699
|
+
}
|
|
519
700
|
setLoading(true);
|
|
520
701
|
setLoadingIdentifier(requestIdentifier);
|
|
521
702
|
setErrorState(null);
|
|
@@ -530,7 +711,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
530
711
|
identifier: requestIdentifier,
|
|
531
712
|
message: surfaceMismatchMessage,
|
|
532
713
|
});
|
|
533
|
-
|
|
714
|
+
throw new Error(surfaceMismatchMessage);
|
|
534
715
|
}
|
|
535
716
|
setSurface(nextSurface);
|
|
536
717
|
setSurfaceIdentifier(requestIdentifier);
|
|
@@ -546,7 +727,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
546
727
|
message: errorMessage(reason, loadErrorFallback),
|
|
547
728
|
});
|
|
548
729
|
}
|
|
549
|
-
|
|
730
|
+
throw reason;
|
|
550
731
|
}
|
|
551
732
|
finally {
|
|
552
733
|
if (isCurrentRequest(sequence)) {
|
|
@@ -592,9 +773,11 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
592
773
|
requestSequence.current += 1;
|
|
593
774
|
};
|
|
594
775
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
776
|
+
if (!matchesSurface(displayedSurfaceRef.current, normalizedIdentifier)) {
|
|
777
|
+
setSurface(null);
|
|
778
|
+
setSurfaceIdentifier(null);
|
|
779
|
+
}
|
|
780
|
+
void refresh().catch(() => undefined);
|
|
598
781
|
return () => {
|
|
599
782
|
activeRef.current = false;
|
|
600
783
|
requestSequence.current += 1;
|
|
@@ -633,32 +816,40 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
633
816
|
setLoading(false);
|
|
634
817
|
setLoadingIdentifier(null);
|
|
635
818
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
819
|
+
try {
|
|
820
|
+
await completeWorkflowCommand(surfaceKind, result, {
|
|
821
|
+
refresh: async () => {
|
|
822
|
+
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
const nextSurface = await refresh();
|
|
826
|
+
return isCurrentGeneration(identifierAtStart, generationAtStart)
|
|
827
|
+
? nextSurface
|
|
828
|
+
: null;
|
|
829
|
+
},
|
|
830
|
+
onCommandCompleted: async (commandResult) => {
|
|
831
|
+
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
await onCommandCompletedRef.current?.(commandResult);
|
|
835
|
+
},
|
|
836
|
+
onCompleted: async (nextSurface, commandResult) => {
|
|
837
|
+
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const callback = onCompletedRef.current;
|
|
841
|
+
if (!callback)
|
|
842
|
+
return;
|
|
843
|
+
await callback(nextSurface, commandResult);
|
|
844
|
+
},
|
|
845
|
+
});
|
|
846
|
+
if (isCurrentGeneration(identifierAtStart, generationAtStart))
|
|
847
|
+
setConfirmedReadFailure(null);
|
|
848
|
+
}
|
|
849
|
+
catch (error) {
|
|
850
|
+
if (isCurrentGeneration(identifierAtStart, generationAtStart))
|
|
851
|
+
setConfirmedReadFailure({ result, message: errorMessage(error, '页面刷新失败') });
|
|
852
|
+
}
|
|
662
853
|
}, [
|
|
663
854
|
isCurrentGeneration,
|
|
664
855
|
normalizedIdentifier,
|
|
@@ -689,19 +880,36 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
689
880
|
loadingIdentifier === normalizedIdentifier ||
|
|
690
881
|
surfaceIdentifier !== normalizedIdentifier ||
|
|
691
882
|
!acceptedInput);
|
|
883
|
+
const receipt = locator && _jsx(WorkflowTaskCommandReceipt, { locator: locator, busy: writing, onSettled: async (result, text) => {
|
|
884
|
+
clearLocator(locator.idempotencyKey);
|
|
885
|
+
setSettlement({ key: locator.idempotencyKey, result });
|
|
886
|
+
message.info(text);
|
|
887
|
+
try {
|
|
888
|
+
if (result)
|
|
889
|
+
await completed(result);
|
|
890
|
+
else
|
|
891
|
+
await refreshCurrent();
|
|
892
|
+
}
|
|
893
|
+
catch (error) {
|
|
894
|
+
message.warning(result ? '原操作已成功,请刷新查看最新资料。' : errorMessage(error, '资料刷新失败'));
|
|
895
|
+
}
|
|
896
|
+
} }, locatorScope);
|
|
897
|
+
const confirmedWarning = confirmedReadFailure && _jsx(Alert, { showIcon: true, type: "warning", title: "\u4EFB\u52A1\u64CD\u4F5C\u5DF2\u6210\u529F\uFF0C\u4F46\u9875\u9762\u5237\u65B0\u5931\u8D25", description: confirmedReadFailure.message, action: _jsx(Button, { onClick: () => void completed(confirmedReadFailure.result), children: "\u5237\u65B0\u8D44\u6599" }) });
|
|
898
|
+
const layout = (parts) => renderLayout
|
|
899
|
+
? renderLayout({ ...parts, surface: renderSurface || undefined }) : _jsxs(_Fragment, { children: [parts.content, parts.actions] });
|
|
692
900
|
if (renderLoading) {
|
|
693
|
-
return (_jsx("div", { "aria-busy": "true", "aria-label": loadingLabel, className: `oxa-workflow-actions-loading oxa-workflow-actions-loading-${variant}`, children: _jsx(Spin, {}) }));
|
|
901
|
+
return layout({ actions: null, content: (_jsxs(_Fragment, { children: [receipt, confirmedWarning, _jsx("div", { "aria-busy": "true", "aria-label": loadingLabel, className: `oxa-workflow-actions-loading oxa-workflow-actions-loading-${variant}`, children: _jsx(Spin, {}) })] })) });
|
|
694
902
|
}
|
|
695
903
|
if (renderError && !renderSurface) {
|
|
696
|
-
return (_jsx(Alert, { action: _jsx(Button, { onClick: () => void refresh(), children: "\u91CD\u8BD5" }), description: renderError, showIcon: true, type: "error" }));
|
|
904
|
+
return layout({ actions: null, content: (_jsxs(_Fragment, { children: [receipt, confirmedWarning, _jsx(Alert, { action: _jsx(Button, { onClick: () => void refresh().catch(() => undefined), children: "\u91CD\u8BD5" }), description: renderError, showIcon: true, type: "error" })] })) });
|
|
697
905
|
}
|
|
698
906
|
if (!renderSurface)
|
|
699
|
-
return null;
|
|
700
|
-
return (_jsxs(_Fragment, { children: [renderError &&
|
|
907
|
+
return layout({ content: receipt || confirmedWarning ? _jsxs(_Fragment, { children: [receipt, confirmedWarning] }) : null, actions: null });
|
|
908
|
+
return (_jsx(WorkflowOperations, { onCommandSuccess: completed, onRefresh: refreshCurrent, surface: renderSurface, variant: variant, pendingLocator: locator, persistLocator: persistLocator, clearLocator: clearLocator, onBusyChange: setWriting, settlement: settlement, confirmedReadPending: Boolean(confirmedReadFailure), renderLayout: ({ content, actions }) => layout({ actions, content: receipt || confirmedWarning || renderError || content ? _jsxs(_Fragment, { children: [receipt, confirmedWarning, renderError && _jsx(Alert, { description: renderError, showIcon: true, type: "warning" }), content] }) : null }) }, `${normalizedIdentifier}:${locatorScope}:${runtime?.identityEpoch || 0}`));
|
|
701
909
|
}
|
|
702
910
|
/** Public, embeddable Workflow task operation surface. */
|
|
703
|
-
export function WorkflowTaskOperationsPanel({ taskId, variant = 'desktop', surface, onSurfaceChange, onCompleted, onCommandCompleted, }) {
|
|
704
|
-
return (_jsx(WorkflowOperationsPanel, { identifier: taskId, onCommandCompleted: onCommandCompleted, loadErrorFallback: "\u5BA1\u6279\u4EFB\u52A1\u52A0\u8F7D\u5931\u8D25", loadSurface: loadWorkflowTaskSurface, matchesSurface: workflowSurfaceMatchesTask, missingIdentifierMessage: "WORKFLOW_TASK_ID_REQUIRED", onCompleted: onCompleted, onSurfaceChange: onSurfaceChange, surface: surface, surfaceMismatchMessage: "WORKFLOW_TASK_SURFACE_TASK_MISMATCH", surfaceKind: "task", variant: variant, loadingLabel: "\u6B63\u5728\u52A0\u8F7D\u5BA1\u6279\u64CD\u4F5C" }));
|
|
911
|
+
export function WorkflowTaskOperationsPanel({ taskId, variant = 'desktop', surface, onSurfaceChange, onCompleted, onCommandCompleted, renderLayout, }) {
|
|
912
|
+
return (_jsx(WorkflowOperationsPanel, { identifier: taskId, onCommandCompleted: onCommandCompleted, renderLayout: renderLayout, loadErrorFallback: "\u5BA1\u6279\u4EFB\u52A1\u52A0\u8F7D\u5931\u8D25", loadSurface: loadWorkflowTaskSurface, matchesSurface: workflowSurfaceMatchesTask, missingIdentifierMessage: "WORKFLOW_TASK_ID_REQUIRED", onCompleted: onCompleted, onSurfaceChange: onSurfaceChange, surface: surface, surfaceMismatchMessage: "WORKFLOW_TASK_SURFACE_TASK_MISMATCH", surfaceKind: "task", variant: variant, loadingLabel: "\u6B63\u5728\u52A0\u8F7D\u5BA1\u6279\u64CD\u4F5C" }));
|
|
705
913
|
}
|
|
706
914
|
/** Public, embeddable Workflow instance operation surface. */
|
|
707
915
|
export function WorkflowInstanceOperationsPanel({ instanceId, variant = 'desktop', surface, onSurfaceChange, onCompleted, onCommandCompleted, }) {
|
|
@@ -717,7 +925,7 @@ export function WorkflowSummarySection({ surface }) {
|
|
|
717
925
|
};
|
|
718
926
|
return (_jsxs("div", { className: "oxa-workflow-summary-metadata", children: [_jsxs("span", { children: [_jsx(Typography.Text, { type: "secondary", children: "\u7533\u8BF7\u4EBA" }), _jsxs("span", { className: "oxa-workflow-applicant", children: [_jsx(PlatformAvatar, { avatarUrl: initiator.avatarUrl, size: 32 }), _jsxs("span", { children: [_jsx("strong", { children: initiator.displayName }), initiator.departmentDisplayName && (_jsx("small", { children: initiator.departmentDisplayName }))] })] })] }), _jsxs("span", { children: [_jsx(Typography.Text, { type: "secondary", children: "\u63D0\u4EA4\u65F6\u95F4" }), formatTime(summary.submittedAt)] }), summary.businessNumber && (_jsxs("span", { children: [_jsx(Typography.Text, { type: "secondary", children: "\u4E1A\u52A1\u7F16\u53F7" }), summary.businessNumber] }))] }));
|
|
719
927
|
}
|
|
720
|
-
function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations, variant, onClose, onEdit, drawer, drawerState, newPageHref, editing, busy, }) {
|
|
928
|
+
function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations, taskContent, variant, onClose, onEdit, drawer, drawerState, newPageHref, editing, busy, }) {
|
|
721
929
|
const navigate = useNavigate();
|
|
722
930
|
const timeZone = usePresentationTimeZone();
|
|
723
931
|
const [tab, setTab] = useState('application');
|
|
@@ -735,13 +943,13 @@ function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations
|
|
|
735
943
|
const loadAudit = useCallback(() => loadWorkflowDataAudit(instance.id), [instance.id]);
|
|
736
944
|
const back = onClose || (() => navigate(variant === 'mobile' ? '/m/work-center' : '/work-center'));
|
|
737
945
|
return _jsxs(RecordDetailFrame, { variant: variant, title: "\u7533\u8BF7\u8BE6\u60C5", heading: title, status: _jsx(StatusTag, { status: instance.status }), metadata: [summary.initiator?.displayName || summary.initiatorDisplayName, summary.initiator?.departmentDisplayName || summary.departmentDisplayName,
|
|
738
|
-
summary.submittedAt ? `${detailTime(summary.submittedAt, timeZone)} 创建` : ''].filter(Boolean).join(' · '), updatedAt: business.record.updated_at || instance.completedAt || instance.startedAt, onClose: back, onEdit: edit, editing: editing, busy: busy, drawer: drawer, drawerState: drawerState, newPageHref: newPageHref, footer: hasActions || edit ? _jsxs(_Fragment, { children: [operations, edit && _jsx(Button, { onClick: edit, children: "\u7F16\u8F91" })] }) : null, children: [warning && _jsx(Alert, { description: warning, showIcon: true, type: "warning" }), !workflowHasEnded(instance) && activeNode && _jsxs("div", { className: `oxa-workflow-current-node is-${bannerTone}`, role: "status", children: [_jsxs("span", { children: [_jsx(ClockCircleOutlined, {}), "\u5F53\u524D\u8282\u70B9\uFF1A", activeNode.title] }), people && _jsxs("span", { children: ["\u7B49\u5F85", people, "\u5904\u7406"] })] }), _jsx(Tabs, { activeKey: tab, onChange: setTab, items: [
|
|
946
|
+
summary.submittedAt ? `${detailTime(summary.submittedAt, timeZone)} 创建` : ''].filter(Boolean).join(' · '), updatedAt: business.record.updated_at || instance.completedAt || instance.startedAt, onClose: back, onEdit: edit, editing: editing, busy: busy, drawer: drawer, drawerState: drawerState, newPageHref: newPageHref, footer: operations || hasActions || edit ? _jsxs(_Fragment, { children: [operations, edit && _jsx(Button, { onClick: edit, children: "\u7F16\u8F91" })] }) : null, children: [warning && _jsx(Alert, { description: warning, showIcon: true, type: "warning" }), !workflowHasEnded(instance) && activeNode && _jsxs("div", { className: `oxa-workflow-current-node is-${bannerTone}`, role: "status", children: [_jsxs("span", { children: [_jsx(ClockCircleOutlined, {}), "\u5F53\u524D\u8282\u70B9\uFF1A", activeNode.title] }), people && _jsxs("span", { children: ["\u7B49\u5F85", people, "\u5904\u7406"] })] }), _jsx(Tabs, { activeKey: tab, onChange: setTab, items: [
|
|
739
947
|
{ key: 'application', label: '申请内容', children: _jsx(WorkflowBusinessDetailSections, { surface: surface, variant: variant }) },
|
|
740
948
|
{ key: 'history', label: '审批历史', children: _jsx(WorkflowTimelineSection, { timeline: timeline }) },
|
|
741
949
|
{ key: 'changes', label: '变更记录', children: tab === 'changes' && business.surface && business.resourceCode && business.recordId
|
|
742
950
|
? _jsx(RecordChangeHistory, { resourceCode: business.resourceCode, recordId: business.recordId, surface: business.surface, readable: () => true, loadPage: loadAudit })
|
|
743
951
|
: _jsx(Empty, { description: "\u6682\u65E0\u53D8\u66F4\u8BB0\u5F55" }) },
|
|
744
|
-
] })] });
|
|
952
|
+
] }), taskContent && _jsx("div", { className: "oxa-workflow-task-content", children: taskContent })] });
|
|
745
953
|
}
|
|
746
954
|
export function DesktopWorkflowDetailRenderer(props) {
|
|
747
955
|
return _jsx(StandardWorkflowDetailRenderer, { ...props, variant: "desktop" });
|
|
@@ -816,7 +1024,7 @@ export function useWorkflowDetail({ kind, id, resourceCode }) {
|
|
|
816
1024
|
refresh,
|
|
817
1025
|
};
|
|
818
1026
|
}
|
|
819
|
-
function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss, drawerState }) {
|
|
1027
|
+
function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss, drawerState, returnPath }) {
|
|
820
1028
|
const params = useParams();
|
|
821
1029
|
const id = recordId || String(kind === 'task' ? params.taskId || '' : kind === 'record' ? params.id || '' : params.instanceId || '');
|
|
822
1030
|
const navigate = useNavigate();
|
|
@@ -829,11 +1037,7 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
|
|
|
829
1037
|
const business = surface ? surfaceBusinessDetail(surface) : null;
|
|
830
1038
|
const detailPath = surface ? (variant === 'mobile' ? surface.detailNavigation.mobilePath : surface.detailNavigation.desktopPath) : '';
|
|
831
1039
|
const newPageHref = useHref(detailPath || '.');
|
|
832
|
-
const close = onDismiss || (() => navigate(detail ? variant === 'mobile' ? detail.navigationContext.mobileReturnPath : detail.navigationContext.desktopReturnPath : variant === 'mobile' ? '/m/work-center' : '/work-center'));
|
|
833
|
-
if (!surface || !detail || !instance)
|
|
834
|
-
return _jsx(RecordDetailFrame, { variant: variant, title: "\u7533\u8BF7\u8BE6\u60C5", drawer: Boolean(onDismiss), drawerState: drawerState, onClose: close, children: loading ? _jsx(Spin, {}) : _jsx(Result, { status: "error", title: "\u6D41\u7A0B\u8BE6\u60C5\u52A0\u8F7D\u5931\u8D25", subTitle: error || '流程不存在', extra: _jsx(Button, { onClick: () => void refresh(), children: "\u91CD\u8BD5" }) }) });
|
|
835
|
-
if (surface.detailNavigation.custom)
|
|
836
|
-
return _jsx(Navigate, { replace: true, to: detailPath });
|
|
1040
|
+
const close = onDismiss || (() => navigate(returnPath || (detail ? variant === 'mobile' ? detail.navigationContext.mobileReturnPath : detail.navigationContext.desktopReturnPath : variant === 'mobile' ? '/m/work-center' : '/work-center')));
|
|
837
1041
|
const onCommandCompleted = async (result) => {
|
|
838
1042
|
if (kind === 'task' && result.advanced === true) {
|
|
839
1043
|
const nextId = String(result.instanceId || '').trim();
|
|
@@ -845,18 +1049,22 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
|
|
|
845
1049
|
else
|
|
846
1050
|
await refresh();
|
|
847
1051
|
};
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1052
|
+
if (!surface || !detail || !instance)
|
|
1053
|
+
return _jsxs(RecordDetailFrame, { variant: variant, title: "\u7533\u8BF7\u8BE6\u60C5", drawer: Boolean(onDismiss), drawerState: drawerState, onClose: close, children: [kind === 'task' && readPendingWorkflowTaskCommand(submissionLocatorStorage(), workflowTaskCommandScope(applicationCode(), identity.environment.id, identity.userId, id)) &&
|
|
1054
|
+
_jsx(WorkflowTaskOperationsPanel, { taskId: id, variant: variant, onCommandCompleted: onCommandCompleted }), loading ? _jsx(Spin, {}) : _jsx(Result, { status: "error", title: "\u6D41\u7A0B\u8BE6\u60C5\u52A0\u8F7D\u5931\u8D25", subTitle: error || '流程不存在', extra: _jsx(Button, { onClick: () => void refresh(), children: "\u91CD\u8BD5" }) })] });
|
|
1055
|
+
if (surface.detailNavigation.custom)
|
|
1056
|
+
return _jsx(Navigate, { replace: true, to: detailPath });
|
|
1057
|
+
const renderDetail = (operations, taskContent, currentSurface = surface) => _jsx(StandardWorkflowDetailRenderer, { surface: currentSurface, timeline: timeline, warning: error, operations: operations, taskContent: taskContent, variant: variant, drawer: Boolean(onDismiss), drawerState: drawerState, newPageHref: newPageHref, onClose: editing ? () => { if (!editBusy)
|
|
852
1058
|
setEditing(false); } : close, busy: editBusy, editing: editing && business?.resourceCode && business.recordId ? _jsx(WorkflowRecordEditor, { resourceCode: business.resourceCode, recordId: business.recordId, variant: variant, presentation: "embedded", onBusyChange: setEditBusy, onDismiss: () => setEditing(false), onSaved: () => { setEditing(false); void refresh(); } }) : undefined, onEdit: workflowHasEnded(instance) && identity.isAppSuperAdmin && (business?.status === 'ready' || business?.status === 'stale') ? () => setEditing(true) : undefined });
|
|
1059
|
+
return task ? _jsx(WorkflowTaskOperationsPanel, { onCommandCompleted: onCommandCompleted, surface: surface, taskId: task.id, variant: variant, renderLayout: ({ content, actions, surface: currentSurface }) => renderDetail(actions, content, currentSurface) }, task.id)
|
|
1060
|
+
: renderDetail(_jsx(WorkflowInstanceOperationsPanel, { instanceId: instance.id, onCommandCompleted: onCommandCompleted, surface: surface, variant: variant }));
|
|
853
1061
|
}
|
|
854
1062
|
export function WorkflowRecordDetailPage({ variant = 'desktop', ...props }) { return _jsx(WorkflowDetailPage, { ...props, variant: variant, kind: "record" }); }
|
|
855
|
-
export function WorkflowTaskPage({ variant = 'desktop', }) {
|
|
856
|
-
return _jsx(WorkflowDetailPage, { kind: "task", variant: variant });
|
|
1063
|
+
export function WorkflowTaskPage({ variant = 'desktop', returnPath, }) {
|
|
1064
|
+
return _jsx(WorkflowDetailPage, { kind: "task", variant: variant, returnPath: returnPath });
|
|
857
1065
|
}
|
|
858
|
-
export function WorkflowInstancePage({ variant = 'desktop', }) {
|
|
859
|
-
return _jsx(WorkflowDetailPage, { kind: "instance", variant: variant });
|
|
1066
|
+
export function WorkflowInstancePage({ variant = 'desktop', returnPath, }) {
|
|
1067
|
+
return _jsx(WorkflowDetailPage, { kind: "instance", variant: variant, returnPath: returnPath });
|
|
860
1068
|
}
|
|
861
1069
|
const WORK_VIEWS = [
|
|
862
1070
|
{ value: 'created', label: '我创建的' }, { value: 'pending', label: '待我审批' },
|