openxiangda 2.35.3 → 2.48.2
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/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/JsonField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/JsonField.js +6 -1
- package/dist/browser/components/platform-fields/JsonField.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 +15 -6
- package/dist/browser/components/platform-fields/MobileManagedFileField.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.d.ts +2 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.js +3 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.js.map +1 -1
- package/dist/browser/components/platform-fields/RichTextField.d.ts +3 -2
- package/dist/browser/components/platform-fields/RichTextField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/RichTextField.js +96 -44
- package/dist/browser/components/platform-fields/RichTextField.js.map +1 -1
- package/dist/browser/components/platform-fields/SignatureField.d.ts +5 -4
- package/dist/browser/components/platform-fields/SignatureField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/SignatureField.js +69 -16
- package/dist/browser/components/platform-fields/SignatureField.js.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.d.ts +18 -2
- package/dist/browser/components/platform-fields/SubtableField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.js +146 -57
- package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
- package/dist/browser/components/platform-fields/subtable-pagination.d.ts +20 -0
- package/dist/browser/components/platform-fields/subtable-pagination.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/subtable-pagination.js +39 -0
- package/dist/browser/components/platform-fields/subtable-pagination.js.map +1 -0
- package/dist/browser/components/platform-fields/subtable-value.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/subtable-value.js +2 -1
- package/dist/browser/components/platform-fields/subtable-value.js.map +1 -1
- package/dist/browser/components/platform-fields/surface-field-validation.d.ts +31 -0
- package/dist/browser/components/platform-fields/surface-field-validation.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/surface-field-validation.js +36 -0
- package/dist/browser/components/platform-fields/surface-field-validation.js.map +1 -0
- package/dist/browser/components/resource/SurfaceFields.d.ts +4 -3
- package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.js +46 -72
- package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
- package/dist/browser/components/resource/resource-form-operations.d.ts.map +1 -1
- package/dist/browser/components/resource/resource-form-operations.js +5 -1
- package/dist/browser/components/resource/resource-form-operations.js.map +1 -1
- package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +8 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +305 -80
- 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.map +1 -1
- package/dist/browser/components/workflow/WorkflowDiagram.js +14 -1
- package/dist/browser/components/workflow/WorkflowDiagram.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js +27 -8
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeCard.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeCard.js +5 -2
- package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +6 -5
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
- 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 +22 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.js +164 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +53 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.js +175 -0
- package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -0
- package/dist/browser/components/workflow/standard-process-values.d.ts +10 -0
- package/dist/browser/components/workflow/standard-process-values.d.ts.map +1 -0
- package/dist/browser/components/workflow/standard-process-values.js +25 -0
- package/dist/browser/components/workflow/standard-process-values.js.map +1 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.d.ts +19 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.js +28 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.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/components/workflow/workflow-task-field-codec.d.ts +4 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.js +9 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.js.map +1 -0
- package/dist/browser/components/workflow/workflow-task-subtable.d.ts +7 -0
- package/dist/browser/components/workflow/workflow-task-subtable.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-task-subtable.js +58 -0
- package/dist/browser/components/workflow/workflow-task-subtable.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/mobile-fields.css +4 -0
- 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 +67 -3
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +135 -5
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/record-detail.css +14 -2
- package/dist/browser/runtime.d.ts +2 -0
- package/dist/browser/runtime.d.ts.map +1 -1
- package/dist/browser/runtime.js +5 -1
- package/dist/browser/runtime.js.map +1 -1
- package/dist/browser/styles.css +92 -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 +36 -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 +5 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +1 -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 +8 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -1
- package/dist/react.js.map +1 -1
- package/documentation/administration.md +128 -1
- package/documentation/field-components.md +1 -1
- package/documentation/frontend.md +2 -0
- package/documentation/getting-started.md +7 -7
- package/documentation/managed-concurrency-frontend.md +9 -4
- package/documentation/manifest.json +7 -7
- package/documentation/workflow-events.md +303 -3
- package/package.json +21 -37
- package/releases/2.48.1.json +30 -0
- package/releases/2.48.2.json +29 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +4 -4
- package/skills/openxiangda-v2/references/administration.md +128 -1
- package/skills/openxiangda-v2/references/field-components.md +1 -1
- 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/workflow-events.md +303 -3
- package/dist/browser/components/platform-fields/MobileRichTextField.d.ts +0 -4
- package/dist/browser/components/platform-fields/MobileRichTextField.d.ts.map +0 -1
- package/dist/browser/components/platform-fields/MobileRichTextField.js +0 -38
- package/dist/browser/components/platform-fields/MobileRichTextField.js.map +0 -1
- package/releases/2.35.0.json +0 -42
- package/releases/2.35.1.json +0 -43
- package/releases/2.35.2.json +0 -45
- package/releases/2.35.3.json +0 -46
|
@@ -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';
|
|
@@ -22,6 +25,9 @@ import { RecordChangeHistory } from '../resource/RecordChangeHistory';
|
|
|
22
25
|
import { ResourceFormContent } from '../resource/ResourceFormFrame';
|
|
23
26
|
import { WorkflowRecordEditor } from './WorkflowRecordEditor';
|
|
24
27
|
import { PlatformAvatar } from '../PlatformAvatar';
|
|
28
|
+
import { SubtableField } from '../platform-fields/SubtableField';
|
|
29
|
+
import { standardProcessFormValues } from './standard-process-values';
|
|
30
|
+
import { fieldWritable } from '../resource/resource-page-helpers';
|
|
25
31
|
/**
|
|
26
32
|
* An advanced task command has completed the current task and may have
|
|
27
33
|
* created a new task. Reading the old task Surface in that case is expected
|
|
@@ -39,13 +45,32 @@ export function shouldRefreshWorkflowSurface(kind, result) {
|
|
|
39
45
|
*/
|
|
40
46
|
export async function completeWorkflowCommand(kind, result, options) {
|
|
41
47
|
const refreshSurface = shouldRefreshWorkflowSurface(kind, result);
|
|
42
|
-
|
|
48
|
+
let nextSurface = null;
|
|
49
|
+
let refreshFailure;
|
|
50
|
+
try {
|
|
51
|
+
nextSurface = refreshSurface ? await options.refresh() : null;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
refreshFailure = error;
|
|
55
|
+
}
|
|
43
56
|
await options.onCommandCompleted?.(result);
|
|
44
57
|
if (nextSurface)
|
|
45
58
|
await options.onCompleted?.(nextSurface, result);
|
|
59
|
+
if (refreshFailure)
|
|
60
|
+
throw refreshFailure;
|
|
46
61
|
return nextSurface;
|
|
47
62
|
}
|
|
48
63
|
function errorMessage(error, fallback) {
|
|
64
|
+
const code = error?.code;
|
|
65
|
+
const taskPageMessages = {
|
|
66
|
+
WORKFLOW_TASK_FORM_REQUIRED: '请完成本页必填资料后再提交。',
|
|
67
|
+
WORKFLOW_TASK_FORM_REVISION_CONFLICT: '业务资料已被其他处理人更新。请刷新并核对,当前输入会保留。',
|
|
68
|
+
WORKFLOW_TASK_FORM_RECOMPUTATION_REQUIRED: '这些资料会影响已完成的计算,请退回到计算前的节点重新办理。',
|
|
69
|
+
WORKFLOW_TASK_FORM_FIELD_NOT_EDITABLE: '页面规则已变化,请刷新资料后重新确认。',
|
|
70
|
+
WORKFLOW_TASK_FORM_COMMAND_FORBIDDEN: '此操作不提交补填资料,请使用保存补填、同意或重新提交。',
|
|
71
|
+
};
|
|
72
|
+
if (code && taskPageMessages[code])
|
|
73
|
+
return taskPageMessages[code];
|
|
49
74
|
return error instanceof Error ? error.message : fallback;
|
|
50
75
|
}
|
|
51
76
|
function randomId(prefix) {
|
|
@@ -128,11 +153,6 @@ function workflowOperationSignature(operation) {
|
|
|
128
153
|
}
|
|
129
154
|
const WORKFLOW_APP_ACTION_DISABLED_REASON = '应用动作由应用页面负责';
|
|
130
155
|
function standardWorkflowOperations(surface) {
|
|
131
|
-
if (!surface.commandToken ||
|
|
132
|
-
!surface.commandTokenExpiresAt ||
|
|
133
|
-
new Date(surface.commandTokenExpiresAt).getTime() <= Date.now()) {
|
|
134
|
-
return [];
|
|
135
|
-
}
|
|
136
156
|
return surface.operations
|
|
137
157
|
.filter((operation) => operation.visible)
|
|
138
158
|
.map((operation) => {
|
|
@@ -299,7 +319,8 @@ export function WorkflowTimelineSection({ timeline, }) {
|
|
|
299
319
|
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
320
|
const operations = item.operations || [];
|
|
301
321
|
const visiblePeople = visibleWorkflowTimelinePeople(item, operations);
|
|
302
|
-
|
|
322
|
+
const businessStep = item.nodeKind === 'action' ? item.result.businessStep : undefined;
|
|
323
|
+
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
324
|
}) })) : (_jsx(Empty, { description: "\u6682\u65E0\u6D41\u7A0B\u8F68\u8FF9", image: Empty.PRESENTED_IMAGE_SIMPLE })) }));
|
|
304
325
|
}
|
|
305
326
|
function WorkflowMemberPicker({ id, placeholder, value, onChange, multiple = false, variant }) {
|
|
@@ -360,28 +381,63 @@ function OperationDialog({ error, operation, submitting, variant, onCancel, onSu
|
|
|
360
381
|
if (!operation)
|
|
361
382
|
return null;
|
|
362
383
|
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 })] }));
|
|
384
|
+
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
385
|
if (variant === 'mobile') {
|
|
365
386
|
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
387
|
}
|
|
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 }));
|
|
388
|
+
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
389
|
}
|
|
369
|
-
function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, }) {
|
|
390
|
+
function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pendingLocator, persistLocator, clearLocator, onBusyChange, settlement, confirmedReadPending, renderLayout, }) {
|
|
370
391
|
const { message } = App.useApp();
|
|
371
392
|
const [selectedState, setSelectedState] = useState(null);
|
|
372
393
|
const [moreOpen, setMoreOpen] = useState(false);
|
|
373
394
|
const [operationError, setOperationError] = useState('');
|
|
374
395
|
const [submitting, setSubmitting] = useState(false);
|
|
396
|
+
const [draftLocked, setDraftLocked] = useState(false);
|
|
397
|
+
const [fileLocked, setFileLocked] = useState(false);
|
|
398
|
+
const [refreshFailure, setRefreshFailure] = useState(null);
|
|
399
|
+
const [unknown, setUnknown] = useState(false);
|
|
400
|
+
const request = useRef(null);
|
|
401
|
+
const mounted = useRef(false);
|
|
402
|
+
const busyRef = useRef(false);
|
|
403
|
+
const taskForm = useWorkflowTaskForm(surface.taskForm);
|
|
404
|
+
useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
|
|
405
|
+
useEffect(() => {
|
|
406
|
+
if (!settlement || request.current?.key !== settlement.key)
|
|
407
|
+
return;
|
|
408
|
+
if (settlement.result)
|
|
409
|
+
taskForm.committed(request.current.input.form, Number(settlement.result.dataRevision) || undefined);
|
|
410
|
+
request.current = null;
|
|
411
|
+
setUnknown(false);
|
|
412
|
+
setSelectedState(null);
|
|
413
|
+
}, [settlement]);
|
|
375
414
|
const operations = standardWorkflowOperations(surface);
|
|
376
|
-
const
|
|
415
|
+
const [, setCommandClock] = useState(0);
|
|
416
|
+
const commandExpiresAt = Date.parse(surface.commandTokenExpiresAt || '');
|
|
417
|
+
const commandNeedsRefresh = operations.some(operation => operation.kind === 'workflow_command') &&
|
|
418
|
+
(!surface.commandToken || !Number.isFinite(commandExpiresAt) || commandExpiresAt <= Date.now());
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
if (!surface.commandToken || !Number.isFinite(commandExpiresAt) || commandExpiresAt <= Date.now())
|
|
421
|
+
return;
|
|
422
|
+
let timer;
|
|
423
|
+
const tick = () => {
|
|
424
|
+
setCommandClock(value => value + 1);
|
|
425
|
+
const remaining = commandExpiresAt - Date.now();
|
|
426
|
+
if (remaining > 0)
|
|
427
|
+
timer = setTimeout(tick, Math.min(remaining, 2_147_483_647));
|
|
428
|
+
};
|
|
429
|
+
timer = setTimeout(tick, Math.min(commandExpiresAt - Date.now(), 2_147_483_647));
|
|
430
|
+
return () => clearTimeout(timer);
|
|
431
|
+
}, [surface.commandToken, commandExpiresAt]);
|
|
432
|
+
const selected = !commandNeedsRefresh && selectedState?.surface === surface
|
|
377
433
|
? operations.find((operation) => operation.key === selectedState.operation.key &&
|
|
378
434
|
workflowOperationSignature(operation) ===
|
|
379
435
|
selectedState.operationSignature) || null
|
|
380
436
|
: null;
|
|
381
437
|
useEffect(() => {
|
|
382
|
-
if (selectedState && !selected)
|
|
438
|
+
if (selectedState && !selected && !submitting && !unknown)
|
|
383
439
|
setSelectedState(null);
|
|
384
|
-
}, [selected, selectedState]);
|
|
440
|
+
}, [selected, selectedState, submitting, unknown]);
|
|
385
441
|
const selectOperation = (operation) => {
|
|
386
442
|
setOperationError('');
|
|
387
443
|
setSelectedState({
|
|
@@ -391,10 +447,12 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
391
447
|
});
|
|
392
448
|
};
|
|
393
449
|
const submit = async (values) => {
|
|
394
|
-
if (!selected ||
|
|
450
|
+
if (!selected || busyRef.current || draftLocked || fileLocked || taskForm.draftNeedsSave || pendingLocator || unknown || refreshFailure || confirmedReadPending)
|
|
395
451
|
return;
|
|
396
452
|
setOperationError('');
|
|
397
453
|
setSubmitting(true);
|
|
454
|
+
busyRef.current = true;
|
|
455
|
+
onBusyChange(true);
|
|
398
456
|
try {
|
|
399
457
|
if (selected.kind !== 'workflow_command') {
|
|
400
458
|
throw new Error('WORKFLOW_APP_ACTION_NOT_EXECUTABLE_IN_STANDARD_PANEL');
|
|
@@ -404,19 +462,26 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
404
462
|
await onRefresh();
|
|
405
463
|
throw new Error('WORKFLOW_FRESH_COMMAND_TOKEN_REQUIRED');
|
|
406
464
|
}
|
|
407
|
-
if (
|
|
465
|
+
if (!Number.isFinite(commandExpiresAt) || commandExpiresAt <= Date.now()) {
|
|
408
466
|
await onRefresh();
|
|
409
|
-
throw new Error('
|
|
467
|
+
throw new Error('操作已刷新,请保留当前输入并重新确认。');
|
|
410
468
|
}
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
469
|
+
const input = { ...values };
|
|
470
|
+
if (surface.taskForm && ['save_form', 'approve', 'resubmit'].includes(selected.key)) {
|
|
471
|
+
if (taskForm.stale)
|
|
472
|
+
throw new Error('业务资料已更新,请先核对最新资料');
|
|
473
|
+
input.form = await taskForm.build(selected.key !== 'save_form');
|
|
474
|
+
}
|
|
475
|
+
const key = randomId(`workflow:${selected.key}`);
|
|
476
|
+
if (surface.task?.id)
|
|
477
|
+
persistLocator({ taskId: String(surface.task.id), command: selected.key,
|
|
478
|
+
idempotencyKey: key, requestedAt: new Date().toISOString(), tokenDigest: await workflowCommandTokenDigest(commandToken) });
|
|
479
|
+
request.current = { surface, operation: selected, input: JSON.parse(JSON.stringify(input)), key };
|
|
415
480
|
}
|
|
416
481
|
catch (error) {
|
|
417
482
|
const hasFreshSurface = Boolean(error?.data?.freshSurface);
|
|
418
483
|
if (hasFreshSurface) {
|
|
419
|
-
await onRefresh();
|
|
484
|
+
await onRefresh().catch(() => undefined);
|
|
420
485
|
setSelectedState(null);
|
|
421
486
|
message.warning('内容已更新,请刷新后重试');
|
|
422
487
|
}
|
|
@@ -427,26 +492,128 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
427
492
|
setOperationError(failure);
|
|
428
493
|
message.error(failure);
|
|
429
494
|
}
|
|
495
|
+
setSubmitting(false);
|
|
496
|
+
busyRef.current = false;
|
|
497
|
+
onBusyChange(false);
|
|
498
|
+
return;
|
|
430
499
|
}
|
|
431
|
-
|
|
500
|
+
await sendRequest(false);
|
|
501
|
+
};
|
|
502
|
+
const sendRequest = async (recovering) => {
|
|
503
|
+
const wire = request.current;
|
|
504
|
+
if (!wire || (recovering && busyRef.current))
|
|
505
|
+
return;
|
|
506
|
+
setSubmitting(true);
|
|
507
|
+
busyRef.current = true;
|
|
508
|
+
onBusyChange(true);
|
|
509
|
+
setOperationError('');
|
|
510
|
+
let result;
|
|
511
|
+
try {
|
|
512
|
+
// Replay uses the exact token, input and key captured before the first write.
|
|
513
|
+
result = await executeWorkflowOperation(wire.surface, wire.operation, wire.input, { idempotencyKey: wire.key });
|
|
514
|
+
}
|
|
515
|
+
catch (error) {
|
|
516
|
+
if (!mounted.current)
|
|
517
|
+
return;
|
|
518
|
+
const rejected = !recovering && workflowTaskCommandWasRejected(error);
|
|
519
|
+
if (rejected) {
|
|
520
|
+
clearLocator(wire.key);
|
|
521
|
+
request.current = null;
|
|
522
|
+
setSelectedState(null);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
setUnknown(true);
|
|
526
|
+
setSelectedState(null);
|
|
527
|
+
}
|
|
528
|
+
const failure = errorMessage(error, '任务操作尚未完成');
|
|
529
|
+
setOperationError(failure);
|
|
530
|
+
if (rejected) {
|
|
531
|
+
message.error(failure);
|
|
532
|
+
// A definitive refusal permits a read, never an automatic new write.
|
|
533
|
+
// Keep this controller mounted so dirty inputs survive the fresh CAS.
|
|
534
|
+
try {
|
|
535
|
+
await onRefresh();
|
|
536
|
+
if (mounted.current)
|
|
537
|
+
setRefreshFailure(null);
|
|
538
|
+
}
|
|
539
|
+
catch (reason) {
|
|
540
|
+
if (mounted.current)
|
|
541
|
+
setRefreshFailure({ outcome: 'rejected', message: errorMessage(reason, '最新资料读取失败') });
|
|
542
|
+
}
|
|
543
|
+
}
|
|
432
544
|
setSubmitting(false);
|
|
545
|
+
busyRef.current = false;
|
|
546
|
+
onBusyChange(false);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (!mounted.current)
|
|
550
|
+
return;
|
|
551
|
+
clearLocator(wire.key);
|
|
552
|
+
request.current = null;
|
|
553
|
+
setUnknown(false);
|
|
554
|
+
setSelectedState(null);
|
|
555
|
+
taskForm.committed(wire.input.form, Number(result.dataRevision) || undefined);
|
|
556
|
+
onBusyChange(false);
|
|
557
|
+
message.success(`${wire.operation.label}已提交`);
|
|
558
|
+
// The write has succeeded. A callback or read failure can only affect refresh.
|
|
559
|
+
try {
|
|
560
|
+
await onCommandSuccess(result);
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
if (mounted.current)
|
|
564
|
+
setRefreshFailure({ outcome: 'succeeded', message: errorMessage(error, '页面刷新失败') });
|
|
565
|
+
}
|
|
566
|
+
finally {
|
|
567
|
+
if (mounted.current) {
|
|
568
|
+
setSubmitting(false);
|
|
569
|
+
busyRef.current = false;
|
|
570
|
+
onBusyChange(false);
|
|
571
|
+
}
|
|
433
572
|
}
|
|
434
573
|
};
|
|
435
|
-
|
|
436
|
-
|
|
574
|
+
const refreshConfirmed = async () => {
|
|
575
|
+
if (busyRef.current)
|
|
576
|
+
return;
|
|
577
|
+
setSubmitting(true);
|
|
578
|
+
busyRef.current = true;
|
|
579
|
+
onBusyChange(true);
|
|
580
|
+
try {
|
|
581
|
+
await onRefresh();
|
|
582
|
+
if (mounted.current)
|
|
583
|
+
setRefreshFailure(null);
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
if (mounted.current)
|
|
587
|
+
setRefreshFailure(current => ({ outcome: current?.outcome || 'rejected', message: errorMessage(error, '页面刷新失败') }));
|
|
588
|
+
}
|
|
589
|
+
finally {
|
|
590
|
+
if (mounted.current) {
|
|
591
|
+
setSubmitting(false);
|
|
592
|
+
busyRef.current = false;
|
|
593
|
+
onBusyChange(false);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
const commandLocked = submitting || unknown || Boolean(pendingLocator) || Boolean(refreshFailure) || confirmedReadPending;
|
|
598
|
+
const locked = commandLocked || draftLocked || fileLocked;
|
|
599
|
+
if (!operations.length && !surface.taskForm && !unknown && !refreshFailure)
|
|
600
|
+
return renderLayout({ content: null, actions: null });
|
|
437
601
|
const primary = operations
|
|
438
602
|
.filter((operation) => operation.placement === 'primary')
|
|
439
603
|
.sort((left, right) => {
|
|
440
604
|
if (variant !== 'mobile')
|
|
441
605
|
return 0;
|
|
442
|
-
const order = { reject: 0, approve: 1 };
|
|
606
|
+
const order = { reject: 0, approve: 1, resubmit: 1 };
|
|
443
607
|
return (order[left.key] ?? 10) - (order[right.key] ?? 10);
|
|
444
608
|
});
|
|
445
609
|
const secondary = operations.filter((operation) => operation.placement !== 'primary');
|
|
446
|
-
|
|
610
|
+
const content = surface.taskForm || commandNeedsRefresh || ((submitting || unknown) && !pendingLocator) || unknown || refreshFailure ? (_jsxs(_Fragment, { children: [commandNeedsRefresh && !unknown && !pendingLocator && !refreshFailure && _jsx(Alert, { type: "info", showIcon: true, title: "\u8BF7\u5237\u65B0\u64CD\u4F5C\u540E\u7EE7\u7EED\u529E\u7406", description: "\u9875\u9762\u505C\u7559\u8F83\u4E45\uFF0C\u9700\u91CD\u65B0\u786E\u8BA4\u5F53\u524D\u529E\u7406\u6743\u9650\u3002\u5237\u65B0\u4F1A\u4FDD\u7559\u5C1A\u672A\u4FDD\u5B58\u7684\u8F93\u5165\u3002", action: _jsx(Button, { disabled: locked, loading: submitting, onClick: () => void refreshConfirmed(), children: "\u5237\u65B0\u64CD\u4F5C" }) }), 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'
|
|
611
|
+
? '任务操作已成功,但资料刷新失败' : '本次未提交,最新资料读取失败', description: refreshFailure.message, action: _jsx(Button, { disabled: submitting, onClick: () => void refreshConfirmed(), children: "\u5237\u65B0\u8D44\u6599" }) })] })) : null;
|
|
612
|
+
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 || commandNeedsRefresh || 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 || commandNeedsRefresh || 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 || commandNeedsRefresh || taskForm.stale || taskForm.draftNeedsSave || !operation.enabled, onClick: () => {
|
|
447
613
|
setMoreOpen(false);
|
|
448
614
|
selectOperation(operation);
|
|
449
615
|
}, 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 })] }));
|
|
616
|
+
return renderLayout({ content, actions });
|
|
450
617
|
}
|
|
451
618
|
/**
|
|
452
619
|
* Shared lifecycle for the embeddable task and instance operation panels.
|
|
@@ -456,13 +623,40 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, })
|
|
|
456
623
|
* idempotency, and state transitions; all operation controls continue to be
|
|
457
624
|
* rendered by WorkflowOperations above.
|
|
458
625
|
*/
|
|
459
|
-
function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: suppliedSurface, onSurfaceChange, onCompleted, onCommandCompleted, loadSurface, matchesSurface, missingIdentifierMessage, surfaceMismatchMessage, loadingLabel, loadErrorFallback, }) {
|
|
626
|
+
function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: suppliedSurface, onSurfaceChange, onCompleted, onCommandCompleted, loadSurface, matchesSurface, missingIdentifierMessage, surfaceMismatchMessage, loadingLabel, loadErrorFallback, renderLayout, }) {
|
|
460
627
|
const normalizedIdentifier = identifier.trim();
|
|
628
|
+
const runtime = useOptionalRuntime();
|
|
629
|
+
const { message } = App.useApp();
|
|
630
|
+
const locatorScope = surfaceKind === 'task' && runtime
|
|
631
|
+
? workflowTaskCommandScope(applicationCode(), runtime.identity.environment.id, runtime.identity.userId, normalizedIdentifier) : '';
|
|
632
|
+
const [locatorState, setLocatorState] = useState(() => ({ scope: locatorScope, value: locatorScope ? readPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope) : null }));
|
|
633
|
+
const [writing, setWriting] = useState(false);
|
|
634
|
+
const [settlement, setSettlement] = useState(null);
|
|
635
|
+
const [confirmedReadFailure, setConfirmedReadFailure] = useState(null);
|
|
636
|
+
const locator = locatorState.scope === locatorScope ? locatorState.value : null;
|
|
637
|
+
useEffect(() => {
|
|
638
|
+
setLocatorState({ scope: locatorScope, value: locatorScope ? readPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope) : null });
|
|
639
|
+
}, [locatorScope]);
|
|
640
|
+
const persistLocator = (value) => {
|
|
641
|
+
if (!locatorScope)
|
|
642
|
+
return;
|
|
643
|
+
if (!writePendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope, value))
|
|
644
|
+
message.warning('原请求已保留在当前页面,请在此确认提交结果。');
|
|
645
|
+
setLocatorState({ scope: locatorScope, value });
|
|
646
|
+
};
|
|
647
|
+
const clearLocator = (key) => {
|
|
648
|
+
if (locatorScope)
|
|
649
|
+
clearPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope, key);
|
|
650
|
+
setLocatorState(current => current.scope === locatorScope && current.value?.idempotencyKey === key
|
|
651
|
+
? { scope: locatorScope, value: null } : current);
|
|
652
|
+
};
|
|
461
653
|
const inputSurface = suppliedSurface || null;
|
|
462
654
|
const suppliedSurfaceMatches = matchesSurface(inputSurface, normalizedIdentifier);
|
|
463
655
|
const initialSurface = suppliedSurfaceMatches ? inputSurface : null;
|
|
464
656
|
const [surface, setSurface] = useState(initialSurface);
|
|
465
657
|
const [surfaceIdentifier, setSurfaceIdentifier] = useState(initialSurface ? normalizedIdentifier : null);
|
|
658
|
+
const displayedSurfaceRef = useRef(surface);
|
|
659
|
+
displayedSurfaceRef.current = surface;
|
|
466
660
|
const [acceptedInputSurface, setAcceptedInputSurface] = useState(initialSurface ? inputSurface : null);
|
|
467
661
|
const [loading, setLoading] = useState(!initialSurface);
|
|
468
662
|
const [loadingIdentifier, setLoadingIdentifier] = useState(initialSurface ? null : normalizedIdentifier);
|
|
@@ -514,8 +708,10 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
514
708
|
}
|
|
515
709
|
const requestInputSurface = currentInputSurfaceRef.current;
|
|
516
710
|
setAcceptedInputSurface(requestInputSurface);
|
|
517
|
-
|
|
518
|
-
|
|
711
|
+
if (!matchesSurface(displayedSurfaceRef.current, requestIdentifier)) {
|
|
712
|
+
setSurface(null);
|
|
713
|
+
setSurfaceIdentifier(null);
|
|
714
|
+
}
|
|
519
715
|
setLoading(true);
|
|
520
716
|
setLoadingIdentifier(requestIdentifier);
|
|
521
717
|
setErrorState(null);
|
|
@@ -530,7 +726,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
530
726
|
identifier: requestIdentifier,
|
|
531
727
|
message: surfaceMismatchMessage,
|
|
532
728
|
});
|
|
533
|
-
|
|
729
|
+
throw new Error(surfaceMismatchMessage);
|
|
534
730
|
}
|
|
535
731
|
setSurface(nextSurface);
|
|
536
732
|
setSurfaceIdentifier(requestIdentifier);
|
|
@@ -546,7 +742,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
546
742
|
message: errorMessage(reason, loadErrorFallback),
|
|
547
743
|
});
|
|
548
744
|
}
|
|
549
|
-
|
|
745
|
+
throw reason;
|
|
550
746
|
}
|
|
551
747
|
finally {
|
|
552
748
|
if (isCurrentRequest(sequence)) {
|
|
@@ -592,9 +788,11 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
592
788
|
requestSequence.current += 1;
|
|
593
789
|
};
|
|
594
790
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
791
|
+
if (!matchesSurface(displayedSurfaceRef.current, normalizedIdentifier)) {
|
|
792
|
+
setSurface(null);
|
|
793
|
+
setSurfaceIdentifier(null);
|
|
794
|
+
}
|
|
795
|
+
void refresh().catch(() => undefined);
|
|
598
796
|
return () => {
|
|
599
797
|
activeRef.current = false;
|
|
600
798
|
requestSequence.current += 1;
|
|
@@ -633,32 +831,40 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
633
831
|
setLoading(false);
|
|
634
832
|
setLoadingIdentifier(null);
|
|
635
833
|
}
|
|
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
|
-
|
|
834
|
+
try {
|
|
835
|
+
await completeWorkflowCommand(surfaceKind, result, {
|
|
836
|
+
refresh: async () => {
|
|
837
|
+
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
const nextSurface = await refresh();
|
|
841
|
+
return isCurrentGeneration(identifierAtStart, generationAtStart)
|
|
842
|
+
? nextSurface
|
|
843
|
+
: null;
|
|
844
|
+
},
|
|
845
|
+
onCommandCompleted: async (commandResult) => {
|
|
846
|
+
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
await onCommandCompletedRef.current?.(commandResult);
|
|
850
|
+
},
|
|
851
|
+
onCompleted: async (nextSurface, commandResult) => {
|
|
852
|
+
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const callback = onCompletedRef.current;
|
|
856
|
+
if (!callback)
|
|
857
|
+
return;
|
|
858
|
+
await callback(nextSurface, commandResult);
|
|
859
|
+
},
|
|
860
|
+
});
|
|
861
|
+
if (isCurrentGeneration(identifierAtStart, generationAtStart))
|
|
862
|
+
setConfirmedReadFailure(null);
|
|
863
|
+
}
|
|
864
|
+
catch (error) {
|
|
865
|
+
if (isCurrentGeneration(identifierAtStart, generationAtStart))
|
|
866
|
+
setConfirmedReadFailure({ result, message: errorMessage(error, '页面刷新失败') });
|
|
867
|
+
}
|
|
662
868
|
}, [
|
|
663
869
|
isCurrentGeneration,
|
|
664
870
|
normalizedIdentifier,
|
|
@@ -689,19 +895,36 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
689
895
|
loadingIdentifier === normalizedIdentifier ||
|
|
690
896
|
surfaceIdentifier !== normalizedIdentifier ||
|
|
691
897
|
!acceptedInput);
|
|
898
|
+
const receipt = locator && _jsx(WorkflowTaskCommandReceipt, { locator: locator, busy: writing, onSettled: async (result, text) => {
|
|
899
|
+
clearLocator(locator.idempotencyKey);
|
|
900
|
+
setSettlement({ key: locator.idempotencyKey, result });
|
|
901
|
+
message.info(text);
|
|
902
|
+
try {
|
|
903
|
+
if (result)
|
|
904
|
+
await completed(result);
|
|
905
|
+
else
|
|
906
|
+
await refreshCurrent();
|
|
907
|
+
}
|
|
908
|
+
catch (error) {
|
|
909
|
+
message.warning(result ? '原操作已成功,请刷新查看最新资料。' : errorMessage(error, '资料刷新失败'));
|
|
910
|
+
}
|
|
911
|
+
} }, locatorScope);
|
|
912
|
+
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" }) });
|
|
913
|
+
const layout = (parts) => renderLayout
|
|
914
|
+
? renderLayout({ ...parts, surface: renderSurface || undefined }) : _jsxs(_Fragment, { children: [parts.content, parts.actions] });
|
|
692
915
|
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, {}) }));
|
|
916
|
+
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
917
|
}
|
|
695
918
|
if (renderError && !renderSurface) {
|
|
696
|
-
return (_jsx(Alert, { action: _jsx(Button, { onClick: () => void refresh(), children: "\u91CD\u8BD5" }), description: renderError, showIcon: true, type: "error" }));
|
|
919
|
+
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
920
|
}
|
|
698
921
|
if (!renderSurface)
|
|
699
|
-
return null;
|
|
700
|
-
return (_jsxs(_Fragment, { children: [renderError &&
|
|
922
|
+
return layout({ content: receipt || confirmedWarning ? _jsxs(_Fragment, { children: [receipt, confirmedWarning] }) : null, actions: null });
|
|
923
|
+
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
924
|
}
|
|
702
925
|
/** 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" }));
|
|
926
|
+
export function WorkflowTaskOperationsPanel({ taskId, variant = 'desktop', surface, onSurfaceChange, onCompleted, onCommandCompleted, renderLayout, }) {
|
|
927
|
+
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
928
|
}
|
|
706
929
|
/** Public, embeddable Workflow instance operation surface. */
|
|
707
930
|
export function WorkflowInstanceOperationsPanel({ instanceId, variant = 'desktop', surface, onSurfaceChange, onCompleted, onCommandCompleted, }) {
|
|
@@ -717,7 +940,7 @@ export function WorkflowSummarySection({ surface }) {
|
|
|
717
940
|
};
|
|
718
941
|
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
942
|
}
|
|
720
|
-
function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations, variant, onClose, onEdit, drawer, drawerState, newPageHref, editing, busy, }) {
|
|
943
|
+
function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations, taskContent, variant, onClose, onEdit, drawer, drawerState, newPageHref, editing, busy, }) {
|
|
721
944
|
const navigate = useNavigate();
|
|
722
945
|
const timeZone = usePresentationTimeZone();
|
|
723
946
|
const [tab, setTab] = useState('application');
|
|
@@ -735,13 +958,13 @@ function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations
|
|
|
735
958
|
const loadAudit = useCallback(() => loadWorkflowDataAudit(instance.id), [instance.id]);
|
|
736
959
|
const back = onClose || (() => navigate(variant === 'mobile' ? '/m/work-center' : '/work-center'));
|
|
737
960
|
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: [
|
|
961
|
+
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
962
|
{ key: 'application', label: '申请内容', children: _jsx(WorkflowBusinessDetailSections, { surface: surface, variant: variant }) },
|
|
740
963
|
{ key: 'history', label: '审批历史', children: _jsx(WorkflowTimelineSection, { timeline: timeline }) },
|
|
741
964
|
{ key: 'changes', label: '变更记录', children: tab === 'changes' && business.surface && business.resourceCode && business.recordId
|
|
742
965
|
? _jsx(RecordChangeHistory, { resourceCode: business.resourceCode, recordId: business.recordId, surface: business.surface, readable: () => true, loadPage: loadAudit })
|
|
743
966
|
: _jsx(Empty, { description: "\u6682\u65E0\u53D8\u66F4\u8BB0\u5F55" }) },
|
|
744
|
-
] })] });
|
|
967
|
+
] }), taskContent && _jsx("div", { className: "oxa-workflow-task-content", children: taskContent })] });
|
|
745
968
|
}
|
|
746
969
|
export function DesktopWorkflowDetailRenderer(props) {
|
|
747
970
|
return _jsx(StandardWorkflowDetailRenderer, { ...props, variant: "desktop" });
|
|
@@ -830,10 +1053,6 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
|
|
|
830
1053
|
const detailPath = surface ? (variant === 'mobile' ? surface.detailNavigation.mobilePath : surface.detailNavigation.desktopPath) : '';
|
|
831
1054
|
const newPageHref = useHref(detailPath || '.');
|
|
832
1055
|
const close = onDismiss || (() => navigate(returnPath || (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 });
|
|
837
1056
|
const onCommandCompleted = async (result) => {
|
|
838
1057
|
if (kind === 'task' && result.advanced === true) {
|
|
839
1058
|
const nextId = String(result.instanceId || '').trim();
|
|
@@ -845,11 +1064,15 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
|
|
|
845
1064
|
else
|
|
846
1065
|
await refresh();
|
|
847
1066
|
};
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1067
|
+
if (!surface || !detail || !instance)
|
|
1068
|
+
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)) &&
|
|
1069
|
+
_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" }) })] });
|
|
1070
|
+
if (surface.detailNavigation.custom)
|
|
1071
|
+
return _jsx(Navigate, { replace: true, to: detailPath });
|
|
1072
|
+
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
1073
|
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 });
|
|
1074
|
+
return task ? _jsx(WorkflowTaskOperationsPanel, { onCommandCompleted: onCommandCompleted, surface: surface, taskId: task.id, variant: variant, renderLayout: ({ content, actions, surface: currentSurface }) => renderDetail(actions, content, currentSurface) }, task.id)
|
|
1075
|
+
: renderDetail(_jsx(WorkflowInstanceOperationsPanel, { instanceId: instance.id, onCommandCompleted: onCommandCompleted, surface: surface, variant: variant }));
|
|
853
1076
|
}
|
|
854
1077
|
export function WorkflowRecordDetailPage({ variant = 'desktop', ...props }) { return _jsx(WorkflowDetailPage, { ...props, variant: variant, kind: "record" }); }
|
|
855
1078
|
export function WorkflowTaskPage({ variant = 'desktop', returnPath, }) {
|
|
@@ -1483,7 +1706,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1483
1706
|
launchSurface?.submission.kind !== 'standard-process')) {
|
|
1484
1707
|
return frame(_jsx(Result, { status: "500", title: "\u6807\u51C6\u6D41\u7A0B\u5408\u540C\u4E0D\u5B8C\u6574" }));
|
|
1485
1708
|
}
|
|
1486
|
-
if (!commandId && fields.some(field => field.type === 'subtable')) {
|
|
1709
|
+
if (!commandId && namedIntent && fields.some(field => field.type === 'subtable')) {
|
|
1487
1710
|
return frame(_jsx(Result, { status: "error", title: "\u6807\u51C6\u6D41\u7A0B\u4E0D\u652F\u6301\u5305\u542B\u53EF\u5199\u5B50\u8868\u7684\u4E3B\u4F53\u8868\u5355", subTitle: "\u5F53\u524D\u6807\u51C6\u63D0\u4EA4 Surface \u5C1A\u672A\u58F0\u660E\u53EF\u5199\u5B50\u8868\u6E32\u67D3\u5668\u3002" }));
|
|
1488
1711
|
}
|
|
1489
1712
|
const submit = async (values) => {
|
|
@@ -1507,7 +1730,8 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1507
1730
|
setRecoveryObservedAbsent(false);
|
|
1508
1731
|
};
|
|
1509
1732
|
try {
|
|
1510
|
-
const encoded = normalizeFormValues(values, subjectDefinition.surface)
|
|
1733
|
+
const encoded = namedIntent ? normalizeFormValues(values, subjectDefinition.surface)
|
|
1734
|
+
: standardProcessFormValues(values, subjectDefinition.surface, resources, (field, mode) => fieldWritable(field, mode === 'create' ? 'create' : 'edit', hasCapability, identity.isAppSuperAdmin));
|
|
1511
1735
|
const data = Object.fromEntries(fields.filter(field => Object.hasOwn(encoded, field.key)).map(field => [field.key, encoded[field.key]]));
|
|
1512
1736
|
const signature = JSON.stringify({ workflowCode, subjectId, environmentKey: identity.environment.key, submissionMode, data });
|
|
1513
1737
|
if (submissionAttempt.current?.signature !== signature) {
|
|
@@ -1696,6 +1920,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1696
1920
|
const uploadOperationCode = namedIntent?.operationCode || definition.processOperationCode;
|
|
1697
1921
|
const fieldRenderers = uploadOperationCode
|
|
1698
1922
|
? {
|
|
1923
|
+
...(!namedIntent ? { renderSubtable: ({ field, disabled, operation, recordId }) => _jsx(SubtableField, { field: field, disabled: disabled, operation: operation, parentRecordId: recordId, mobile: variant === 'mobile' }) } : {}),
|
|
1699
1924
|
...(namedIntent ? { referenceLaunch: { workflowCode: definition.code, operationCode: namedIntent.operationCode } } : {}),
|
|
1700
1925
|
upload: async (field, file) => await uploadOperationManagedFile({
|
|
1701
1926
|
operationCode: uploadOperationCode,
|