openxiangda 2.55.1 → 2.59.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/README.md +1 -0
- package/dist/browser/AuthoritativeSelector.d.ts +3 -2
- package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
- package/dist/browser/AuthoritativeSelector.js +20 -11
- package/dist/browser/AuthoritativeSelector.js.map +1 -1
- package/dist/browser/components/platform-fields/DateTimeField.d.ts +1 -1
- package/dist/browser/components/platform-fields/DateTimeField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/DateTimeField.js +15 -8
- package/dist/browser/components/platform-fields/DateTimeField.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileDateTimeField.d.ts +1 -1
- package/dist/browser/components/platform-fields/MobileDateTimeField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileDateTimeField.js +5 -3
- package/dist/browser/components/platform-fields/MobileDateTimeField.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileZonedDateTimeField.js +2 -2
- package/dist/browser/components/platform-fields/MobileZonedDateTimeField.js.map +1 -1
- package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +3 -2
- package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/ResourceReferenceField.js +3 -3
- package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.d.ts +11 -2
- package/dist/browser/components/platform-fields/SubtableField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.js +55 -24
- package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
- package/dist/browser/components/platform-fields/ZonedDateTimeField.js +2 -2
- package/dist/browser/components/platform-fields/ZonedDateTimeField.js.map +1 -1
- package/dist/browser/components/platform-fields/reference-binding-change.d.ts +6 -0
- package/dist/browser/components/platform-fields/reference-binding-change.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/reference-binding-change.js +32 -0
- package/dist/browser/components/platform-fields/reference-binding-change.js.map +1 -0
- package/dist/browser/components/platform-fields/user-candidate-context.d.ts +3 -0
- package/dist/browser/components/platform-fields/user-candidate-context.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/user-candidate-context.js +12 -4
- package/dist/browser/components/platform-fields/user-candidate-context.js.map +1 -1
- package/dist/browser/components/platform-fields/zoned-date-time.d.ts +4 -0
- package/dist/browser/components/platform-fields/zoned-date-time.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/zoned-date-time.js +9 -1
- package/dist/browser/components/platform-fields/zoned-date-time.js.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceCrud.js +2 -2
- package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceForm.js +2 -2
- package/dist/browser/components/resource/GeneratedResourceForm.js.map +1 -1
- package/dist/browser/components/resource/ResourceFormFrame.d.ts +1 -1
- package/dist/browser/components/resource/ResourceFormFrame.d.ts.map +1 -1
- package/dist/browser/components/resource/ResourceFormFrame.js +12 -1
- package/dist/browser/components/resource/ResourceFormFrame.js.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.d.ts +5 -1
- package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.js +13 -5
- package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
- package/dist/browser/components/resource/generated-resource-definition.d.ts +1 -0
- package/dist/browser/components/resource/generated-resource-definition.d.ts.map +1 -1
- package/dist/browser/components/resource/resource-field-selection.d.ts +1 -0
- package/dist/browser/components/resource/resource-field-selection.d.ts.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 +3 -2
- 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 +15 -3
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +80 -20
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowDelegationManager.js +13 -8
- package/dist/browser/components/workflow/WorkflowDelegationManager.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowDiagram.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowDiagram.js +5 -2
- 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 +2 -1
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeCard.d.ts +1 -1
- package/dist/browser/components/workflow/WorkflowNodeCard.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeCard.js +7 -5
- 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 +14 -11
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +3 -1
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowTaskForm.js +17 -8
- package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -1
- package/dist/browser/components/workflow/standard-process-values.d.ts +10 -2
- package/dist/browser/components/workflow/standard-process-values.d.ts.map +1 -1
- package/dist/browser/components/workflow/standard-process-values.js +22 -1
- package/dist/browser/components/workflow/standard-process-values.js.map +1 -1
- package/dist/browser/components/workflow/workflow-flow-layout.d.ts.map +1 -1
- package/dist/browser/components/workflow/workflow-flow-layout.js +33 -3
- package/dist/browser/components/workflow/workflow-flow-layout.js.map +1 -1
- package/dist/browser/components/workflow/workflow-submission-form.d.ts +4 -0
- package/dist/browser/components/workflow/workflow-submission-form.d.ts.map +1 -1
- package/dist/browser/components/workflow/workflow-submission-form.js +20 -0
- package/dist/browser/components/workflow/workflow-submission-form.js.map +1 -1
- package/dist/browser/durable-command.js +2 -2
- package/dist/browser/durable-command.js.map +1 -1
- package/dist/browser/managed-read-recovery.d.ts +2 -0
- package/dist/browser/managed-read-recovery.d.ts.map +1 -1
- package/dist/browser/managed-read-recovery.js +6 -1
- package/dist/browser/managed-read-recovery.js.map +1 -1
- package/dist/browser/platform-client.d.ts +8 -1
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +39 -2
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/runtime-authorization-recovery.d.ts.map +1 -1
- package/dist/browser/runtime-authorization-recovery.js +36 -9
- package/dist/browser/runtime-authorization-recovery.js.map +1 -1
- package/dist/browser/runtime.d.ts +3 -1
- package/dist/browser/runtime.d.ts.map +1 -1
- package/dist/browser/runtime.js.map +1 -1
- package/dist/browser/workflow-operation-input.js +1 -1
- package/dist/browser/workflow-operation-input.js.map +1 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/core.d.ts +5 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +3 -1
- package/dist/core.js.map +1 -1
- package/dist/expressions.d.ts +4 -0
- package/dist/expressions.d.ts.map +1 -0
- package/dist/expressions.js +3 -0
- package/dist/expressions.js.map +1 -0
- package/documentation/administration.md +33 -0
- package/documentation/backend.md +117 -2
- package/documentation/data-authz.md +30 -0
- package/documentation/declarations-cheatsheet.md +2 -1
- package/documentation/development.md +7 -0
- package/documentation/field-components.md +44 -1
- package/documentation/getting-started.md +60 -7
- package/documentation/managed-concurrency-frontend.md +10 -4
- package/documentation/manifest.json +10 -10
- package/documentation/workflow-events.md +303 -9
- package/package.json +26 -21
- package/releases/2.55.5.json +30 -0
- package/releases/2.55.6.json +32 -0
- package/releases/2.57.1.json +31 -0
- package/releases/2.58.0.json +37 -0
- package/releases/2.58.1.json +31 -0
- package/releases/2.59.0.json +36 -0
- package/releases/2.59.1.json +37 -0
- package/releases/2.59.2.json +33 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +4 -4
- package/skills/openxiangda-v2/references/administration.md +33 -0
- package/skills/openxiangda-v2/references/backend.md +117 -2
- package/skills/openxiangda-v2/references/data-authz.md +30 -0
- package/skills/openxiangda-v2/references/declarations-cheatsheet.md +2 -1
- package/skills/openxiangda-v2/references/development.md +7 -0
- package/skills/openxiangda-v2/references/field-components.md +44 -1
- package/skills/openxiangda-v2/references/getting-started.md +60 -7
- package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +10 -4
- package/skills/openxiangda-v2/references/workflow-events.md +303 -9
|
@@ -27,9 +27,9 @@ import { ResourceFormContent } from '../resource/ResourceFormFrame';
|
|
|
27
27
|
import { WorkflowRecordEditor } from './WorkflowRecordEditor';
|
|
28
28
|
import { PlatformAvatar } from '../PlatformAvatar';
|
|
29
29
|
import { SubtableField } from '../platform-fields/SubtableField';
|
|
30
|
-
import { standardProcessFormValues } from './standard-process-values';
|
|
30
|
+
import { assertNamedSubtableReadonlyFields, namedProcessFormValues, standardProcessFormValues } from './standard-process-values';
|
|
31
31
|
import { fieldWritable } from '../resource/resource-page-helpers';
|
|
32
|
-
import { workflowSubmissionFormProjection, workflowSubmissionPrefill } from './workflow-submission-form';
|
|
32
|
+
import { workflowSubmissionFormProjection, workflowSubmissionPrefill, workflowSubmissionValueLinkage } from './workflow-submission-form';
|
|
33
33
|
/**
|
|
34
34
|
* An advanced task command has completed the current task and may have
|
|
35
35
|
* created a new task. Reading the old task Surface in that case is expected
|
|
@@ -55,10 +55,13 @@ export async function completeWorkflowCommand(kind, result, options) {
|
|
|
55
55
|
catch (error) {
|
|
56
56
|
refreshFailure = error;
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
const failure = refreshFailure;
|
|
59
|
+
const taskSurfaceUnavailable = kind === 'task' && ((failure?.status === 403 && failure.code === 'WORKFLOW_V2_TASK_FORBIDDEN') ||
|
|
60
|
+
(failure?.status === 404 && failure.code === 'WORKFLOW_V2_TASK_NOT_FOUND'));
|
|
61
|
+
await options.onCommandCompleted?.(result, { taskSurfaceUnavailable });
|
|
59
62
|
if (nextSurface)
|
|
60
63
|
await options.onCompleted?.(nextSurface, result);
|
|
61
|
-
if (refreshFailure)
|
|
64
|
+
if (refreshFailure && !(taskSurfaceUnavailable && options.onCommandCompleted))
|
|
62
65
|
throw refreshFailure;
|
|
63
66
|
return nextSurface;
|
|
64
67
|
}
|
|
@@ -595,7 +598,7 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pen
|
|
|
595
598
|
return (order[left.key] ?? 10) - (order[right.key] ?? 10);
|
|
596
599
|
});
|
|
597
600
|
const secondary = operations.filter((operation) => operation.placement !== 'primary');
|
|
598
|
-
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, taskVersion: surface.task?.version ? Number(surface.task.version) : undefined, 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'
|
|
601
|
+
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, operationPending: submitting || unknown || Boolean(pendingLocator) || draftLocked || fileLocked, taskVersion: surface.task?.version ? Number(surface.task.version) : undefined, 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'
|
|
599
602
|
? '任务操作已成功,但资料刷新失败' : '本次未提交,最新资料读取失败', description: refreshFailure.message, action: _jsx(Button, { disabled: submitting, onClick: () => void refreshConfirmed(), children: "\u5237\u65B0\u8D44\u6599" }) })] })) : null;
|
|
600
603
|
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: () => {
|
|
601
604
|
setMoreOpen(false);
|
|
@@ -621,6 +624,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
621
624
|
const [writing, setWriting] = useState(false);
|
|
622
625
|
const [settlement, setSettlement] = useState(null);
|
|
623
626
|
const [confirmedReadFailure, setConfirmedReadFailure] = useState(null);
|
|
627
|
+
const [taskCommandSettled, setTaskCommandSettled] = useState(false);
|
|
624
628
|
const locator = locatorState.scope === locatorScope ? locatorState.value : null;
|
|
625
629
|
useEffect(() => {
|
|
626
630
|
setLocatorState({ scope: locatorScope, value: locatorScope ? readPendingWorkflowTaskCommand(submissionLocatorStorage(), locatorScope) : null });
|
|
@@ -748,6 +752,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
748
752
|
]);
|
|
749
753
|
useEffect(() => {
|
|
750
754
|
activeRef.current = true;
|
|
755
|
+
setTaskCommandSettled(false);
|
|
751
756
|
requestSequence.current += 1;
|
|
752
757
|
if (!normalizedIdentifier) {
|
|
753
758
|
setSurface(null);
|
|
@@ -830,11 +835,19 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
830
835
|
? nextSurface
|
|
831
836
|
: null;
|
|
832
837
|
},
|
|
833
|
-
onCommandCompleted: async (commandResult) => {
|
|
838
|
+
onCommandCompleted: async (commandResult, context) => {
|
|
834
839
|
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
835
840
|
return;
|
|
836
841
|
}
|
|
837
|
-
|
|
842
|
+
if (context?.taskSurfaceUnavailable) {
|
|
843
|
+
setSurface(null);
|
|
844
|
+
setSurfaceIdentifier(identifierAtStart);
|
|
845
|
+
setLoading(false);
|
|
846
|
+
setLoadingIdentifier(null);
|
|
847
|
+
setErrorState(null);
|
|
848
|
+
setTaskCommandSettled(true);
|
|
849
|
+
}
|
|
850
|
+
await onCommandCompletedRef.current?.(commandResult, context);
|
|
838
851
|
},
|
|
839
852
|
onCompleted: async (nextSurface, commandResult) => {
|
|
840
853
|
if (!isCurrentGeneration(identifierAtStart, generationAtStart)) {
|
|
@@ -907,7 +920,7 @@ function WorkflowOperationsPanel({ identifier, surfaceKind, variant, surface: su
|
|
|
907
920
|
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" })] })) });
|
|
908
921
|
}
|
|
909
922
|
if (!renderSurface)
|
|
910
|
-
return layout({ content: receipt || confirmedWarning ? _jsxs(_Fragment, { children: [receipt, confirmedWarning] }) : null, actions: null });
|
|
923
|
+
return layout({ content: receipt || confirmedWarning || taskCommandSettled ? _jsxs(_Fragment, { children: [receipt, confirmedWarning, taskCommandSettled && !confirmedWarning && _jsx(Alert, { type: "success", showIcon: true, title: "\u4EFB\u52A1\u64CD\u4F5C\u5DF2\u6210\u529F", description: "\u4F60\u7684\u672C\u6B21\u529E\u7406\u5DF2\u5B8C\u6210\uFF0C\u6D41\u7A0B\u53EF\u80FD\u4ECD\u5728\u7B49\u5F85\u5176\u4ED6\u5904\u7406\u4EBA\u3002" })] }) : null, actions: null });
|
|
911
924
|
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}`));
|
|
912
925
|
}
|
|
913
926
|
/** Public, embeddable Workflow task operation surface. */
|
|
@@ -933,6 +946,7 @@ function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations
|
|
|
933
946
|
const timeZone = usePresentationTimeZone();
|
|
934
947
|
const [tab, setTab] = useState('application');
|
|
935
948
|
const instance = surfaceInstance(surface);
|
|
949
|
+
const deadline = surfaceTask(surface)?.completionDeadline;
|
|
936
950
|
const business = surfaceBusinessDetail(surface);
|
|
937
951
|
const summary = surface.presentation.summary;
|
|
938
952
|
const titleField = workflowDetailGroups(business).flatMap(group => group.fields).find(field => field.type === 'text.short');
|
|
@@ -947,7 +961,7 @@ function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations
|
|
|
947
961
|
const loadAudit = useCallback(() => loadWorkflowDataAudit(instance.id), [instance.id]);
|
|
948
962
|
const back = onClose || (() => navigate(variant === 'mobile' ? '/m/work-center' : '/work-center'));
|
|
949
963
|
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,
|
|
950
|
-
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: [
|
|
964
|
+
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"] })] }), deadline && !workflowHasEnded(instance) && ['pending', 'failed'].includes(deadline.status) && _jsx(Alert, { showIcon: true, type: deadline.status === 'failed' ? 'warning' : 'info', title: deadline.status === 'failed' ? '到期自动处理未成功' : `未提前完成时,将于 ${detailTime(deadline.deadlineAt, timeZone)} 自动同意`, description: deadline.status === 'failed' ? '流程仍可人工办理。自动处理已停止,请联系流程管理员查看执行记录。' : '可以在此之前填写可选内容并手动提交;自动处理不会代替任何人记录审批意见。' }), _jsx(Tabs, { activeKey: tab, onChange: setTab, items: [
|
|
951
965
|
{ key: 'application', label: '申请内容', children: _jsx(WorkflowBusinessDetailSections, { surface: surface, variant: variant }) },
|
|
952
966
|
{ key: 'history', label: '审批历史', children: _jsx(WorkflowTimelineSection, { timeline: timeline }) },
|
|
953
967
|
{ key: 'changes', label: '变更记录', children: tab === 'changes' && business.surface && business.resourceCode && business.recordId
|
|
@@ -1033,6 +1047,16 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
|
|
|
1033
1047
|
const id = recordId || String(kind === 'task' ? params.taskId || '' : kind === 'record' ? params.id || '' : params.instanceId || '');
|
|
1034
1048
|
const navigate = useNavigate();
|
|
1035
1049
|
const { identity } = useRuntime();
|
|
1050
|
+
const commandHostKey = `${identity.identityScope}:${identity.environment.id}:${kind}:${id}`;
|
|
1051
|
+
const commandHostRef = useRef(null);
|
|
1052
|
+
useEffect(() => {
|
|
1053
|
+
const host = { key: commandHostKey };
|
|
1054
|
+
commandHostRef.current = host;
|
|
1055
|
+
return () => {
|
|
1056
|
+
if (commandHostRef.current === host)
|
|
1057
|
+
commandHostRef.current = null;
|
|
1058
|
+
};
|
|
1059
|
+
}, [commandHostKey]);
|
|
1036
1060
|
const [editing, setEditing] = useState(false);
|
|
1037
1061
|
const [editBusy, setEditBusy] = useState(false);
|
|
1038
1062
|
const { detail, surface, timeline, loading, error, refresh } = useWorkflowDetail({ kind, id, resourceCode });
|
|
@@ -1042,12 +1066,17 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
|
|
|
1042
1066
|
const detailPath = surface ? (variant === 'mobile' ? surface.detailNavigation.mobilePath : surface.detailNavigation.desktopPath) : '';
|
|
1043
1067
|
const newPageHref = useHref(detailPath || '.');
|
|
1044
1068
|
const close = onDismiss || (() => navigate(returnPath || (detail ? variant === 'mobile' ? detail.navigationContext.mobileReturnPath : detail.navigationContext.desktopReturnPath : variant === 'mobile' ? '/m/work-center' : '/work-center')));
|
|
1045
|
-
const onCommandCompleted = async (result) => {
|
|
1046
|
-
|
|
1047
|
-
|
|
1069
|
+
const onCommandCompleted = async (result, context) => {
|
|
1070
|
+
const host = commandHostRef.current;
|
|
1071
|
+
if (!host || host.key !== commandHostKey)
|
|
1072
|
+
return;
|
|
1073
|
+
if (kind === 'task' && (result.advanced === true || context?.taskSurfaceUnavailable)) {
|
|
1074
|
+
const nextId = String(result.instanceId || surface?.instance.id || '').trim();
|
|
1048
1075
|
if (!nextId)
|
|
1049
|
-
|
|
1076
|
+
throw new Error('WORKFLOW_INSTANCE_ID_REQUIRED_AFTER_COMMAND');
|
|
1050
1077
|
const next = await loadWorkflowInstanceDetail(nextId);
|
|
1078
|
+
if (commandHostRef.current !== host)
|
|
1079
|
+
return;
|
|
1051
1080
|
navigate(variant === 'mobile' ? next.surface.detailNavigation.mobilePath : next.surface.detailNavigation.desktopPath, { replace: true });
|
|
1052
1081
|
}
|
|
1053
1082
|
else
|
|
@@ -1256,6 +1285,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1256
1285
|
const [requirementForm] = Form.useForm();
|
|
1257
1286
|
const watchedFormValues = Form.useWatch([], { form: subjectForm, preserve: true });
|
|
1258
1287
|
const [prefillError, setPrefillError] = useState(false);
|
|
1288
|
+
const [linkageError, setLinkageError] = useState(false);
|
|
1259
1289
|
const prefill = useRef({ context: '', applied: new Set() });
|
|
1260
1290
|
const [loading, setLoading] = useState(false);
|
|
1261
1291
|
const [launchSurface, setLaunchSurface] = useState(null);
|
|
@@ -1359,6 +1389,22 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1359
1389
|
}
|
|
1360
1390
|
}, [fields, formOptions?.fieldState, subjectDefinition, watchedFormValues]);
|
|
1361
1391
|
const prefillContext = JSON.stringify([recoveryScope, identity.environment.activeAppVersionId, submissionMode, subjectId]);
|
|
1392
|
+
useEffect(() => { setLinkageError(false); }, [prefillContext]);
|
|
1393
|
+
const onValuesChange = (changed, values) => {
|
|
1394
|
+
if (!formOptions?.valueLinkage || loading || commandId || pendingSubmission || !subjectDefinition)
|
|
1395
|
+
return;
|
|
1396
|
+
try {
|
|
1397
|
+
const canonical = normalizeFormValues(values, subjectDefinition.surface);
|
|
1398
|
+
const visible = workflowSubmissionFormProjection(fields, canonical, formOptions.fieldState?.(canonical)).fields;
|
|
1399
|
+
const patch = workflowSubmissionValueLinkage(visible, normalizeFormValues(changed, subjectDefinition.surface), canonical, formOptions.valueLinkage);
|
|
1400
|
+
const normalized = normalizeRecordForForm(patch, subjectDefinition.surface);
|
|
1401
|
+
subjectForm.setFields(Object.entries(normalized).map(([name, value]) => ({ name, value, touched: true, errors: [] })));
|
|
1402
|
+
setLinkageError(false);
|
|
1403
|
+
}
|
|
1404
|
+
catch {
|
|
1405
|
+
setLinkageError(true);
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1362
1408
|
useEffect(() => {
|
|
1363
1409
|
if (!launchSurface || commandId || pendingSubmission || formOptions?.preparation || mutationMode !== 'create' || !subjectDefinition ||
|
|
1364
1410
|
launchSurface.environmentId !== identity.environment.id || (generatedNamedSubmission && !namedIntent))
|
|
@@ -1735,11 +1781,12 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1735
1781
|
launchSurface?.submission.kind !== 'standard-process')) {
|
|
1736
1782
|
return frame(_jsx(Result, { status: "500", title: "\u6807\u51C6\u6D41\u7A0B\u5408\u540C\u4E0D\u5B8C\u6574" }));
|
|
1737
1783
|
}
|
|
1738
|
-
if (!commandId && namedIntent && fields.some(field => field.type === 'subtable'
|
|
1739
|
-
|
|
1784
|
+
if (!commandId && namedIntent && fields.some(field => field.type === 'subtable' &&
|
|
1785
|
+
(submissionMode !== 'create' || namedIntent.ownedSubject?.resourceCode !== subjectDefinition.code || !namedIntent.ownedSubject.subtables.some(table => table.fieldCode === field.key)))) {
|
|
1786
|
+
return frame(_jsx(Result, { status: "error", title: "\u5B50\u8868\u63D0\u4EA4\u914D\u7F6E\u4E0D\u5B8C\u6574", subTitle: "\u8BF7\u8054\u7CFB\u5E94\u7528\u7BA1\u7406\u5458\u68C0\u67E5\u53D1\u8D77\u914D\u7F6E\u3002" }));
|
|
1740
1787
|
}
|
|
1741
1788
|
const submit = async (values) => {
|
|
1742
|
-
if (submitInFlight.current || commandId || completion || !launchSurface || formOptions?.preparation || prefillError || formProjection.error)
|
|
1789
|
+
if (submitInFlight.current || commandId || completion || !launchSurface || formOptions?.preparation || prefillError || linkageError || formProjection.error)
|
|
1743
1790
|
return;
|
|
1744
1791
|
const unresolved = readPendingWorkflowSubmission(submissionLocatorStorage(), recoveryScope);
|
|
1745
1792
|
if (pendingSubmission || unresolved) {
|
|
@@ -1759,7 +1806,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1759
1806
|
setRecoveryObservedAbsent(false);
|
|
1760
1807
|
};
|
|
1761
1808
|
try {
|
|
1762
|
-
const encoded = namedIntent ?
|
|
1809
|
+
const encoded = namedIntent ? namedProcessFormValues(values, subjectDefinition.surface, resources, namedIntent.ownedSubject, formOptions?.subtableReadonlyFields)
|
|
1763
1810
|
: standardProcessFormValues(values, subjectDefinition.surface, resources, (field, mode) => fieldWritable(field, mode === 'create' ? 'create' : 'edit', hasCapability, identity.isAppSuperAdmin));
|
|
1764
1811
|
const data = workflowSubmissionFormProjection(fields, encoded, formOptions?.fieldState?.(encoded)).values;
|
|
1765
1812
|
const signature = JSON.stringify({ workflowCode, subjectId, environmentKey: identity.environment.key, submissionMode, data });
|
|
@@ -1949,8 +1996,20 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1949
1996
|
const uploadOperationCode = namedIntent?.operationCode || definition.processOperationCode;
|
|
1950
1997
|
const fieldRenderers = uploadOperationCode
|
|
1951
1998
|
? {
|
|
1952
|
-
|
|
1999
|
+
renderSubtable: ({ field, disabled, operation, recordId }) => {
|
|
2000
|
+
const grant = namedIntent?.ownedSubject?.subtables.find(table => table.fieldCode === field.key);
|
|
2001
|
+
assertNamedSubtableReadonlyFields(subjectDefinition.surface, namedIntent?.ownedSubject, formOptions?.subtableReadonlyFields || {});
|
|
2002
|
+
return _jsx(SubtableField, { field: field, disabled: disabled, operation: operation, parentRecordId: recordId, mobile: variant === 'mobile', ...(namedIntent && grant ? { launch: { fieldCodes: grant.fieldCodes,
|
|
2003
|
+
readonlyFieldCodes: formOptions?.subtableReadonlyFields?.[field.key],
|
|
2004
|
+
reference: { workflowCode: definition.code, operationCode: namedIntent.operationCode, subtableFieldCode: field.key },
|
|
2005
|
+
upload: (childField, file) => uploadOperationManagedFile({
|
|
2006
|
+
operationCode: uploadOperationCode, resourceCode: field.subtable.resourceCode,
|
|
2007
|
+
fieldCode: childField.key, intent: 'create', file,
|
|
2008
|
+
}),
|
|
2009
|
+
} } : {}) });
|
|
2010
|
+
},
|
|
1953
2011
|
...(namedIntent ? { referenceLaunch: { workflowCode: definition.code, operationCode: namedIntent.operationCode } } : {}),
|
|
2012
|
+
candidateScopeValues: { ...formOptions?.candidateScopeValues, ...formProjection.values },
|
|
1954
2013
|
upload: async (field, file) => await uploadOperationManagedFile({
|
|
1955
2014
|
operationCode: uploadOperationCode,
|
|
1956
2015
|
resourceCode: subjectDefinition.code,
|
|
@@ -1989,11 +2048,12 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
|
|
|
1989
2048
|
embedded: Boolean(onDismiss),
|
|
1990
2049
|
fieldRenderers,
|
|
1991
2050
|
formIntro: formOptions?.intro,
|
|
1992
|
-
formError: prefillError || formProjection.error ? '表单规则暂不可用,请联系管理员。' : undefined,
|
|
2051
|
+
formError: prefillError || linkageError || formProjection.error ? '表单规则暂不可用,请联系管理员。' : undefined,
|
|
1993
2052
|
recordId: mutationMode === 'update' ? subjectId : undefined,
|
|
1994
2053
|
expectedRevision: mutationMode === 'update' ? loadedSubjectRevision : undefined,
|
|
1995
2054
|
onBack: onDismiss ? dismissDrawer : () => navigate(-1),
|
|
1996
2055
|
onSubmit: submit,
|
|
2056
|
+
onValuesChange,
|
|
1997
2057
|
onAnswer: answer,
|
|
1998
2058
|
onRetry: retry,
|
|
1999
2059
|
onRefresh: () => { setProcessError(null); setProcessRefreshAttempt(value => value + 1); },
|
|
@@ -2020,7 +2080,7 @@ function StandardProcessSubmissionRenderer(props) {
|
|
|
2020
2080
|
}, new Map())].map(([section, fields]) => ({ section, fields }));
|
|
2021
2081
|
if (props.completion)
|
|
2022
2082
|
return _jsx(Result, { status: "success", title: "\u63D0\u4EA4\u6210\u529F", extra: _jsx(Button, { onClick: props.onBack, children: "\u8FD4\u56DE" }) });
|
|
2023
|
-
return _jsxs("div", { className: props.variant === 'mobile' ? 'oxa-mobile-page oxa-mobile-entry oxa-workflow-submission-mobile' : 'oxa-workflow-entry', children: [!props.embedded && _jsxs("header", { className: props.variant === 'mobile' ? 'oxa-mobile-header' : 'oxa-workflow-entry-header', children: [_jsx(Button, { type: "text", "aria-label": "\u8FD4\u56DE", icon: _jsx(ArrowLeftOutlined, {}), disabled: props.processing, onClick: props.onBack }), _jsx("h3", { children: props.title }), _jsx("span", {})] }), _jsx(ResourceFormContent, { variant: props.variant, mode: props.mutationMode === 'update' ? 'edit' : 'create', resourceCode: props.subjectDefinition.code, recordId: props.recordId, groups: groups, expectedRevision: props.expectedRevision, initialValues: props.mutationMode === 'update' ? undefined : Object.fromEntries(props.fields.filter(field => field.type === 'user.multiple').map(field => [field.key, []])), form: props.subjectForm, busy: props.loading || props.submitted, pending: props.loading || props.processing, submitDisabled: props.submitted || Boolean(props.formError), submitLabel: "\u63D0\u4EA4\u5BA1\u6279", canWriteField: () => true, renderers: props.fieldRenderers, feedback: _jsxs(_Fragment, { children: [props.formIntro, props.launchControls, props.formError && _jsx(Alert, { type: "error", showIcon: true, title: props.formError }), props.processing && _jsx(Alert, { type: "info", showIcon: true, title: "\u6B63\u5728\u63D0\u4EA4\u7533\u8BF7\uFF0C\u8BF7\u7A0D\u5019\u2026" })] }), onSubmit: values => void props.onSubmit(values) }), _jsx(ProcessCommandPanel, { error: props.processError, form: props.requirementForm, loading: props.loading, onAnswer: props.onAnswer, onRetry: props.onRetry, onRefresh: props.onRefresh, surface: props.processSurface })] });
|
|
2083
|
+
return _jsxs("div", { className: props.variant === 'mobile' ? 'oxa-mobile-page oxa-mobile-entry oxa-workflow-submission-mobile' : 'oxa-workflow-entry', children: [!props.embedded && _jsxs("header", { className: props.variant === 'mobile' ? 'oxa-mobile-header' : 'oxa-workflow-entry-header', children: [_jsx(Button, { type: "text", "aria-label": "\u8FD4\u56DE", icon: _jsx(ArrowLeftOutlined, {}), disabled: props.processing, onClick: props.onBack }), _jsx("h3", { children: props.title }), _jsx("span", {})] }), _jsx(ResourceFormContent, { variant: props.variant, mode: props.mutationMode === 'update' ? 'edit' : 'create', resourceCode: props.subjectDefinition.code, recordId: props.recordId, groups: groups, expectedRevision: props.expectedRevision, initialValues: props.mutationMode === 'update' ? undefined : Object.fromEntries(props.fields.filter(field => field.type === 'user.multiple').map(field => [field.key, []])), form: props.subjectForm, busy: props.loading || props.submitted, pending: props.loading || props.processing, submitDisabled: props.submitted || Boolean(props.formError), submitLabel: "\u63D0\u4EA4\u5BA1\u6279", canWriteField: () => true, renderers: props.fieldRenderers, feedback: _jsxs(_Fragment, { children: [props.formIntro, props.launchControls, props.formError && _jsx(Alert, { type: "error", showIcon: true, title: props.formError }), props.processing && _jsx(Alert, { type: "info", showIcon: true, title: "\u6B63\u5728\u63D0\u4EA4\u7533\u8BF7\uFF0C\u8BF7\u7A0D\u5019\u2026" })] }), onValuesChange: props.onValuesChange, onSubmit: values => void props.onSubmit(values) }), _jsx(ProcessCommandPanel, { error: props.processError, form: props.requirementForm, loading: props.loading, onAnswer: props.onAnswer, onRetry: props.onRetry, onRefresh: props.onRefresh, surface: props.processSurface })] });
|
|
2024
2084
|
}
|
|
2025
2085
|
function DesktopProcessSubmissionRenderer(props) { return _jsx(StandardProcessSubmissionRenderer, { ...props, variant: "desktop" }); }
|
|
2026
2086
|
function MobileProcessSubmissionRenderer(props) { return _jsx(StandardProcessSubmissionRenderer, { ...props, variant: "mobile" }); }
|