openxiangda 2.48.2 → 2.55.1

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.
Files changed (178) hide show
  1. package/dist/browser/AuthoritativeSelector.d.ts +3 -2
  2. package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
  3. package/dist/browser/AuthoritativeSelector.js +32 -11
  4. package/dist/browser/AuthoritativeSelector.js.map +1 -1
  5. package/dist/browser/FilePreviewPage.d.ts.map +1 -1
  6. package/dist/browser/FilePreviewPage.js +4 -0
  7. package/dist/browser/FilePreviewPage.js.map +1 -1
  8. package/dist/browser/components/administration/RoleMembershipManager.d.ts.map +1 -1
  9. package/dist/browser/components/administration/RoleMembershipManager.js +5 -5
  10. package/dist/browser/components/administration/RoleMembershipManager.js.map +1 -1
  11. package/dist/browser/components/administration/scope-applicability.d.ts +3 -0
  12. package/dist/browser/components/administration/scope-applicability.d.ts.map +1 -0
  13. package/dist/browser/components/administration/scope-applicability.js +7 -0
  14. package/dist/browser/components/administration/scope-applicability.js.map +1 -0
  15. package/dist/browser/components/platform-fields/ConstrainedUserField.d.ts +16 -0
  16. package/dist/browser/components/platform-fields/ConstrainedUserField.d.ts.map +1 -0
  17. package/dist/browser/components/platform-fields/ConstrainedUserField.js +140 -0
  18. package/dist/browser/components/platform-fields/ConstrainedUserField.js.map +1 -0
  19. package/dist/browser/components/platform-fields/ManagedMediaPlayer.d.ts +19 -0
  20. package/dist/browser/components/platform-fields/ManagedMediaPlayer.d.ts.map +1 -0
  21. package/dist/browser/components/platform-fields/ManagedMediaPlayer.js +42 -0
  22. package/dist/browser/components/platform-fields/ManagedMediaPlayer.js.map +1 -0
  23. package/dist/browser/components/platform-fields/MobileSelection.d.ts +3 -1
  24. package/dist/browser/components/platform-fields/MobileSelection.d.ts.map +1 -1
  25. package/dist/browser/components/platform-fields/MobileSelection.js +2 -2
  26. package/dist/browser/components/platform-fields/MobileSelection.js.map +1 -1
  27. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +3 -2
  28. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
  29. package/dist/browser/components/platform-fields/ResourceReferenceField.js +2 -2
  30. package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
  31. package/dist/browser/components/platform-fields/SubtableField.js +2 -2
  32. package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
  33. package/dist/browser/components/platform-fields/managed-media-read.d.ts +19 -0
  34. package/dist/browser/components/platform-fields/managed-media-read.d.ts.map +1 -0
  35. package/dist/browser/components/platform-fields/managed-media-read.js +32 -0
  36. package/dist/browser/components/platform-fields/managed-media-read.js.map +1 -0
  37. package/dist/browser/components/platform-fields/user-candidate-context.d.ts +51 -0
  38. package/dist/browser/components/platform-fields/user-candidate-context.d.ts.map +1 -0
  39. package/dist/browser/components/platform-fields/user-candidate-context.js +62 -0
  40. package/dist/browser/components/platform-fields/user-candidate-context.js.map +1 -0
  41. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
  42. package/dist/browser/components/resource/GeneratedResourceCrud.js +26 -2
  43. package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
  44. package/dist/browser/components/resource/GeneratedResourceForm.js +1 -1
  45. package/dist/browser/components/resource/GeneratedResourceForm.js.map +1 -1
  46. package/dist/browser/components/resource/RecordDetailFrame.d.ts +3 -1
  47. package/dist/browser/components/resource/RecordDetailFrame.d.ts.map +1 -1
  48. package/dist/browser/components/resource/RecordDetailFrame.js +2 -2
  49. package/dist/browser/components/resource/RecordDetailFrame.js.map +1 -1
  50. package/dist/browser/components/resource/ResourceFormFrame.d.ts +2 -1
  51. package/dist/browser/components/resource/ResourceFormFrame.d.ts.map +1 -1
  52. package/dist/browser/components/resource/ResourceFormFrame.js +2 -2
  53. package/dist/browser/components/resource/ResourceFormFrame.js.map +1 -1
  54. package/dist/browser/components/resource/ResourceRecordComments.d.ts +13 -0
  55. package/dist/browser/components/resource/ResourceRecordComments.d.ts.map +1 -0
  56. package/dist/browser/components/resource/ResourceRecordComments.js +75 -0
  57. package/dist/browser/components/resource/ResourceRecordComments.js.map +1 -0
  58. package/dist/browser/components/resource/ResourceRecordDeletion.d.ts +7 -0
  59. package/dist/browser/components/resource/ResourceRecordDeletion.d.ts.map +1 -0
  60. package/dist/browser/components/resource/ResourceRecordDeletion.js +53 -0
  61. package/dist/browser/components/resource/ResourceRecordDeletion.js.map +1 -0
  62. package/dist/browser/components/resource/ResourceRecordPrintPreview.d.ts +16 -0
  63. package/dist/browser/components/resource/ResourceRecordPrintPreview.d.ts.map +1 -0
  64. package/dist/browser/components/resource/ResourceRecordPrintPreview.js +92 -0
  65. package/dist/browser/components/resource/ResourceRecordPrintPreview.js.map +1 -0
  66. package/dist/browser/components/resource/SurfaceFields.d.ts +8 -3
  67. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
  68. package/dist/browser/components/resource/SurfaceFields.js +16 -8
  69. package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
  70. package/dist/browser/components/resource/generated-resource-definition.d.ts +13 -0
  71. package/dist/browser/components/resource/generated-resource-definition.d.ts.map +1 -1
  72. package/dist/browser/components/resource/record-comment-session.d.ts +17 -0
  73. package/dist/browser/components/resource/record-comment-session.d.ts.map +1 -0
  74. package/dist/browser/components/resource/record-comment-session.js +64 -0
  75. package/dist/browser/components/resource/record-comment-session.js.map +1 -0
  76. package/dist/browser/components/resource/record-deletion-session.d.ts +19 -0
  77. package/dist/browser/components/resource/record-deletion-session.d.ts.map +1 -0
  78. package/dist/browser/components/resource/record-deletion-session.js +64 -0
  79. package/dist/browser/components/resource/record-deletion-session.js.map +1 -0
  80. package/dist/browser/components/resource/record-print-session.d.ts +12 -0
  81. package/dist/browser/components/resource/record-print-session.d.ts.map +1 -0
  82. package/dist/browser/components/resource/record-print-session.js +32 -0
  83. package/dist/browser/components/resource/record-print-session.js.map +1 -0
  84. package/dist/browser/components/resource/resource-field-selection.d.ts +1 -0
  85. package/dist/browser/components/resource/resource-field-selection.d.ts.map +1 -1
  86. package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
  87. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +13 -2
  88. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  89. package/dist/browser/components/workflow/StandardWorkflowPages.js +68 -36
  90. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  91. package/dist/browser/components/workflow/WorkflowNodeCard.js +2 -2
  92. package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -1
  93. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -1
  94. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +4 -4
  95. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
  96. package/dist/browser/components/workflow/WorkflowRecordEditor.js +1 -1
  97. package/dist/browser/components/workflow/WorkflowRecordEditor.js.map +1 -1
  98. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.d.ts +9 -0
  99. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.d.ts.map +1 -0
  100. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.js +50 -0
  101. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.js.map +1 -0
  102. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +2 -1
  103. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -1
  104. package/dist/browser/components/workflow/WorkflowTaskForm.js +18 -3
  105. package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -1
  106. package/dist/browser/components/workflow/workflow-submission-form.d.ts +18 -0
  107. package/dist/browser/components/workflow/workflow-submission-form.d.ts.map +1 -0
  108. package/dist/browser/components/workflow/workflow-submission-form.js +44 -0
  109. package/dist/browser/components/workflow/workflow-submission-form.js.map +1 -0
  110. package/dist/browser/components/workflow/workflow-task-required-errors.d.ts +10 -0
  111. package/dist/browser/components/workflow/workflow-task-required-errors.d.ts.map +1 -0
  112. package/dist/browser/components/workflow/workflow-task-required-errors.js +28 -0
  113. package/dist/browser/components/workflow/workflow-task-required-errors.js.map +1 -0
  114. package/dist/browser/durable-command.d.ts.map +1 -1
  115. package/dist/browser/durable-command.js +6 -1
  116. package/dist/browser/durable-command.js.map +1 -1
  117. package/dist/browser/platform-client.d.ts +30 -1
  118. package/dist/browser/platform-client.d.ts.map +1 -1
  119. package/dist/browser/platform-client.js +161 -5
  120. package/dist/browser/platform-client.js.map +1 -1
  121. package/dist/browser/record-comments.css +14 -0
  122. package/dist/browser/record-deletion.css +11 -0
  123. package/dist/browser/record-print.css +31 -0
  124. package/dist/browser/styles.css +30 -0
  125. package/dist/browser/workflow-operation-input.d.ts +15 -0
  126. package/dist/browser/workflow-operation-input.d.ts.map +1 -0
  127. package/dist/browser/workflow-operation-input.js +64 -0
  128. package/dist/browser/workflow-operation-input.js.map +1 -0
  129. package/dist/core.d.ts +2 -2
  130. package/dist/core.d.ts.map +1 -1
  131. package/dist/core.js +1 -1
  132. package/dist/core.js.map +1 -1
  133. package/dist/field-kit.d.ts +3 -0
  134. package/dist/field-kit.d.ts.map +1 -1
  135. package/dist/field-kit.js +3 -0
  136. package/dist/field-kit.js.map +1 -1
  137. package/dist/nest.d.ts +1 -1
  138. package/dist/nest.d.ts.map +1 -1
  139. package/dist/nest.js.map +1 -1
  140. package/dist/react.d.ts +6 -2
  141. package/dist/react.d.ts.map +1 -1
  142. package/dist/react.js +5 -1
  143. package/dist/react.js.map +1 -1
  144. package/dist/testing.d.ts +1 -1
  145. package/dist/testing.d.ts.map +1 -1
  146. package/dist/testing.js +1 -1
  147. package/dist/testing.js.map +1 -1
  148. package/documentation/administration.md +7 -1
  149. package/documentation/backend.md +72 -1
  150. package/documentation/data-authz.md +42 -2
  151. package/documentation/declarations-cheatsheet.md +9 -0
  152. package/documentation/field-components.md +44 -0
  153. package/documentation/frontend.md +8 -0
  154. package/documentation/getting-started.md +7 -7
  155. package/documentation/managed-concurrency-frontend.md +1 -1
  156. package/documentation/manifest.json +11 -11
  157. package/documentation/testing.md +17 -0
  158. package/documentation/workflow-events.md +127 -2
  159. package/package.json +23 -20
  160. package/releases/2.51.0.json +32 -0
  161. package/releases/2.54.4.json +30 -0
  162. package/releases/2.54.6.json +30 -0
  163. package/releases/2.55.0.json +34 -0
  164. package/releases/2.55.1.json +32 -0
  165. package/skills/manifest.json +1 -1
  166. package/skills/openxiangda-v2/SKILL.md +4 -4
  167. package/skills/openxiangda-v2/references/administration.md +7 -1
  168. package/skills/openxiangda-v2/references/backend.md +72 -1
  169. package/skills/openxiangda-v2/references/data-authz.md +42 -2
  170. package/skills/openxiangda-v2/references/declarations-cheatsheet.md +9 -0
  171. package/skills/openxiangda-v2/references/field-components.md +44 -0
  172. package/skills/openxiangda-v2/references/frontend.md +8 -0
  173. package/skills/openxiangda-v2/references/getting-started.md +7 -7
  174. package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +1 -1
  175. package/skills/openxiangda-v2/references/testing.md +17 -0
  176. package/skills/openxiangda-v2/references/workflow-events.md +127 -2
  177. package/releases/2.48.1.json +0 -30
  178. package/releases/2.48.2.json +0 -29
@@ -3,6 +3,7 @@ import { applicationCode } from '../../runtime-meta';
3
3
  import { readPendingWorkflowSubmission, writePendingWorkflowSubmission, clearPendingWorkflowSubmission, workflowSubmissionScope, submissionLocatorStorage, standardProcessWasRejected } from '../../workflow-submission-recovery';
4
4
  import { readPendingWorkflowTaskCommand, writePendingWorkflowTaskCommand, clearPendingWorkflowTaskCommand, workflowTaskCommandScope, workflowCommandTokenDigest, workflowTaskCommandWasRejected } from '../../workflow-task-command-recovery';
5
5
  import { WorkflowTaskForm, useWorkflowTaskForm } from './WorkflowTaskForm';
6
+ import { retainedWorkflowOperation, workflowOperationSignature, workflowOperationStringError, workflowOperationInputFailure } from '../../workflow-operation-input';
6
7
  import { WorkflowPendingCommandGuard, WorkflowTaskCommandReceipt } from './WorkflowTaskCommandReceipt';
7
8
  import { PresentationTime, usePresentationTimeZone } from '../../presentation-time';
8
9
  import { ArrowLeftOutlined, ClockCircleOutlined, EllipsisOutlined, ReloadOutlined, CloseOutlined, ExpandOutlined, CompressOutlined, ExportOutlined, } from '@ant-design/icons';
@@ -28,6 +29,7 @@ import { PlatformAvatar } from '../PlatformAvatar';
28
29
  import { SubtableField } from '../platform-fields/SubtableField';
29
30
  import { standardProcessFormValues } from './standard-process-values';
30
31
  import { fieldWritable } from '../resource/resource-page-helpers';
32
+ import { workflowSubmissionFormProjection, workflowSubmissionPrefill } from './workflow-submission-form';
31
33
  /**
32
34
  * An advanced task command has completed the current task and may have
33
35
  * created a new task. Reading the old task Surface in that case is expected
@@ -87,6 +89,7 @@ function workflowStatus(status) {
87
89
  running: { label: '审批中', color: 'processing' },
88
90
  returned: { label: '已退回', color: 'orange' },
89
91
  completed: { label: '已完成', color: 'success' },
92
+ skipped: { label: '已跳过', color: 'default' },
90
93
  approved: { label: '已同意', color: 'success' },
91
94
  rejected: { label: '已拒绝', color: 'error' },
92
95
  withdrawn: { label: '已撤回', color: 'default' },
@@ -132,25 +135,6 @@ function workflowSurfaceMatchesInstance(surface, instanceId) {
132
135
  function surfaceBusinessDetail(surface) {
133
136
  return normalizeWorkflowBusinessDetail(surface.presentation.businessDetail);
134
137
  }
135
- function workflowOperationSignature(operation) {
136
- return JSON.stringify({
137
- key: operation.key,
138
- kind: operation.kind,
139
- label: operation.label,
140
- placement: operation.placement,
141
- group: operation.group,
142
- audience: operation.audience,
143
- emphasis: operation.emphasis,
144
- tone: operation.tone,
145
- visible: operation.visible,
146
- enabled: operation.enabled,
147
- disabledReason: operation.disabledReason,
148
- inputSchema: operation.inputSchema,
149
- uiSchema: operation.uiSchema,
150
- execute: operation.execute,
151
- refresh: operation.refresh,
152
- });
153
- }
154
138
  const WORKFLOW_APP_ACTION_DISABLED_REASON = '应用动作由应用页面负责';
155
139
  function standardWorkflowOperations(surface) {
156
140
  return surface.operations
@@ -320,7 +304,7 @@ export function WorkflowTimelineSection({ timeline, }) {
320
304
  const operations = item.operations || [];
321
305
  const visiblePeople = visibleWorkflowTimelinePeople(item, operations);
322
306
  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));
307
+ 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 })] }), item.status === 'skipped' && _jsx(Typography.Text, { type: "secondary", children: "\u65E0\u5BA1\u6279\u4EBA\uFF0C\u6309\u6B64\u8282\u70B9\u7684\u89C4\u5219\u81EA\u52A8\u7EE7\u7EED\u3002" }), 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));
324
308
  }) })) : (_jsx(Empty, { description: "\u6682\u65E0\u6D41\u7A0B\u8F68\u8FF9", image: Empty.PRESENTED_IMAGE_SIMPLE })) }));
325
309
  }
326
310
  function WorkflowMemberPicker({ id, placeholder, value, onChange, multiple = false, variant }) {
@@ -347,6 +331,11 @@ function OperationFields({ operation, variant, }) {
347
331
  return (_jsx(_Fragment, { children: schemaProperties(operation).map(({ key, property, required, ui }) => {
348
332
  const rules = [
349
333
  ...(required ? [{ required: true, message: `请填写${property.title || key}` }] : []),
334
+ ...(property.type === 'string' ? [{ validator: async (_rule, value) => {
335
+ const error = workflowOperationStringError(property, value, required, property.title || key);
336
+ if (error)
337
+ throw new Error(error);
338
+ } }] : []),
350
339
  ...(property.type === 'array' ? [{ validator: async (_rule, value) => {
351
340
  if (value == null && !required)
352
341
  return;
@@ -370,7 +359,7 @@ function OperationFields({ operation, variant, }) {
370
359
  else if (property.format === 'date-time') {
371
360
  control = _jsx(Input, { type: "datetime-local" });
372
361
  }
373
- return (_jsx(Form.Item, { initialValue: property.default, label: property.title || key, name: key, rules: rules, children: control }, key));
362
+ return (_jsx(Form.Item, { initialValue: property.default, label: property.title || key, name: key, rules: rules, validateFirst: true, children: control }, key));
374
363
  }) }));
375
364
  }
376
365
  function OperationDialog({ error, operation, submitting, variant, onCancel, onSubmit, }) {
@@ -392,6 +381,7 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pen
392
381
  const [selectedState, setSelectedState] = useState(null);
393
382
  const [moreOpen, setMoreOpen] = useState(false);
394
383
  const [operationError, setOperationError] = useState('');
384
+ const [retainRefusedInput, setRetainRefusedInput] = useState(false);
395
385
  const [submitting, setSubmitting] = useState(false);
396
386
  const [draftLocked, setDraftLocked] = useState(false);
397
387
  const [fileLocked, setFileLocked] = useState(false);
@@ -429,16 +419,14 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pen
429
419
  timer = setTimeout(tick, Math.min(commandExpiresAt - Date.now(), 2_147_483_647));
430
420
  return () => clearTimeout(timer);
431
421
  }, [surface.commandToken, commandExpiresAt]);
432
- const selected = !commandNeedsRefresh && selectedState?.surface === surface
433
- ? operations.find((operation) => operation.key === selectedState.operation.key &&
434
- workflowOperationSignature(operation) ===
435
- selectedState.operationSignature) || null
436
- : null;
422
+ const selected = commandNeedsRefresh ? null
423
+ : retainedWorkflowOperation(selectedState, surface, operations, retainRefusedInput);
437
424
  useEffect(() => {
438
425
  if (selectedState && !selected && !submitting && !unknown)
439
426
  setSelectedState(null);
440
427
  }, [selected, selectedState, submitting, unknown]);
441
428
  const selectOperation = (operation) => {
429
+ setRetainRefusedInput(false);
442
430
  setOperationError('');
443
431
  setSelectedState({
444
432
  operation,
@@ -519,13 +507,13 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pen
519
507
  if (rejected) {
520
508
  clearLocator(wire.key);
521
509
  request.current = null;
522
- setSelectedState(null);
510
+ setRetainRefusedInput(true);
523
511
  }
524
512
  else {
525
513
  setUnknown(true);
526
514
  setSelectedState(null);
527
515
  }
528
- const failure = errorMessage(error, '任务操作尚未完成');
516
+ const failure = workflowOperationInputFailure(error) || errorMessage(error, '任务操作尚未完成');
529
517
  setOperationError(failure);
530
518
  if (rejected) {
531
519
  message.error(failure);
@@ -607,12 +595,12 @@ function WorkflowOperations({ surface, variant, onRefresh, onCommandSuccess, pen
607
595
  return (order[left.key] ?? 10) - (order[right.key] ?? 10);
608
596
  });
609
597
  const secondary = operations.filter((operation) => operation.placement !== 'primary');
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'
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'
611
599
  ? '任务操作已成功,但资料刷新失败' : '本次未提交,最新资料读取失败', description: refreshFailure.message, action: _jsx(Button, { disabled: submitting, onClick: () => void refreshConfirmed(), children: "\u5237\u65B0\u8D44\u6599" }) })] })) : null;
612
600
  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: () => {
613
601
  setMoreOpen(false);
614
602
  selectOperation(operation);
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 })] }));
603
+ }, type: "text", title: operation.disabledReason, children: operation.label }, operation.key))) }))] }), _jsx(OperationDialog, { error: operationError, onCancel: () => { setRetainRefusedInput(false); setSelectedState(null); }, onSubmit: (values) => void submit(values), operation: selected, submitting: submitting, variant: variant })] }));
616
604
  return renderLayout({ content, actions });
617
605
  }
618
606
  /**
@@ -950,7 +938,8 @@ function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations
950
938
  const titleField = workflowDetailGroups(business).flatMap(group => group.fields).find(field => field.type === 'text.short');
951
939
  const title = titleField && business.record[titleField.key] ? String(business.record[titleField.key]) : summary.title;
952
940
  const activeNode = timeline?.display?.entries.find(entry => entry.status === 'active');
953
- const people = activeNode?.people.map(person => person.displayName).filter(Boolean).join('、');
941
+ const activeFlow = activeNode && timeline?.flow.find(entry => entry.key === activeNode.key && entry.status === 'active');
942
+ const people = activeFlow?.assignees.filter(person => person.status === 'active').map(person => person.displayName).filter(Boolean).join('、');
954
943
  const statusTone = workflowStatus(instance.status).color;
955
944
  const bannerTone = statusTone === 'error' ? 'error' : 'active';
956
945
  const edit = workflowHasEnded(instance) ? onEdit : undefined;
@@ -1254,7 +1243,7 @@ async function workflowContextPrefillValue(field, rawValue, resources) {
1254
1243
  }
1255
1244
  return workflowContextScalarValue(field, value);
1256
1245
  }
1257
- export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWorkflowCode, variant = 'desktop', onDismiss, onCompleted, } = {}) {
1246
+ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWorkflowCode, variant = 'desktop', onDismiss, onCompleted, formOptions, } = {}) {
1258
1247
  const { workflowCode: routeWorkflowCode = '' } = useParams();
1259
1248
  const workflowCode = declaredWorkflowCode || routeWorkflowCode;
1260
1249
  const definition = useWorkflowDefinition(workflowCode);
@@ -1265,6 +1254,9 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1265
1254
  const { message } = App.useApp();
1266
1255
  const [subjectForm] = Form.useForm();
1267
1256
  const [requirementForm] = Form.useForm();
1257
+ const watchedFormValues = Form.useWatch([], { form: subjectForm, preserve: true });
1258
+ const [prefillError, setPrefillError] = useState(false);
1259
+ const prefill = useRef({ context: '', applied: new Set() });
1268
1260
  const [loading, setLoading] = useState(false);
1269
1261
  const [launchSurface, setLaunchSurface] = useState(null);
1270
1262
  const [launchError, setLaunchError] = useState(null);
@@ -1357,6 +1349,41 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1357
1349
  namedIntent,
1358
1350
  subjectDefinition,
1359
1351
  ]);
1352
+ const formProjection = useMemo(() => {
1353
+ try {
1354
+ const values = subjectDefinition ? normalizeFormValues(watchedFormValues || {}, subjectDefinition.surface) : {};
1355
+ return { ...workflowSubmissionFormProjection(fields, values, formOptions?.fieldState?.(values)), error: false };
1356
+ }
1357
+ catch {
1358
+ return { fields, values: {}, hiddenValues: {}, error: true };
1359
+ }
1360
+ }, [fields, formOptions?.fieldState, subjectDefinition, watchedFormValues]);
1361
+ const prefillContext = JSON.stringify([recoveryScope, identity.environment.activeAppVersionId, submissionMode, subjectId]);
1362
+ useEffect(() => {
1363
+ if (!launchSurface || commandId || pendingSubmission || formOptions?.preparation || mutationMode !== 'create' || !subjectDefinition ||
1364
+ launchSurface.environmentId !== identity.environment.id || (generatedNamedSubmission && !namedIntent))
1365
+ return;
1366
+ if (prefill.current.context !== prefillContext)
1367
+ prefill.current = { context: prefillContext, applied: new Set() };
1368
+ try {
1369
+ const values = workflowSubmissionPrefill(fields, formOptions?.initialValues || {}, prefill.current.applied, key => subjectForm.isFieldTouched(key));
1370
+ const normalized = normalizeRecordForForm(values, subjectDefinition.surface);
1371
+ subjectForm.setFields(Object.entries(normalized).map(([name, value]) => ({ name, value, touched: false })));
1372
+ setPrefillError(false);
1373
+ }
1374
+ catch {
1375
+ setPrefillError(true);
1376
+ }
1377
+ }, [commandId, fields, formOptions?.initialValues, formOptions?.preparation, generatedNamedSubmission, identity.environment.id,
1378
+ launchSurface, mutationMode, namedIntent, pendingSubmission, prefillContext, subjectDefinition, subjectForm]);
1379
+ useEffect(() => {
1380
+ if (loading || commandId || pendingSubmission || !launchSurface || formProjection.error || !subjectDefinition)
1381
+ return;
1382
+ const values = normalizeRecordForForm(formProjection.hiddenValues, subjectDefinition.surface);
1383
+ const changes = Object.entries(values).filter(([key, value]) => JSON.stringify(subjectForm.getFieldValue(key)) !== JSON.stringify(value));
1384
+ if (changes.length)
1385
+ subjectForm.setFields(changes.map(([name, value]) => ({ name, value, errors: [] })));
1386
+ }, [commandId, formProjection, launchSurface, loading, pendingSubmission, subjectDefinition, subjectForm]);
1360
1387
  useEffect(() => {
1361
1388
  let active = true;
1362
1389
  setLaunchSurface(null);
@@ -1691,6 +1718,8 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1691
1718
  : '当前部署版本未声明 launch 配置;请升级工具链后为 workflows.definitions[].launch 显式声明 mode' }));
1692
1719
  if (!subjectDefinition)
1693
1720
  return frame(_jsx(Result, { status: "500", title: "\u6807\u51C6\u6D41\u7A0B\u5408\u540C\u4E0D\u5B8C\u6574" }));
1721
+ if (!commandId && formOptions?.preparation)
1722
+ return frame(formOptions.preparation);
1694
1723
  if (launchError && !commandId)
1695
1724
  return frame(_jsx(Result, { status: "error", title: "\u53D1\u8D77\u9875\u9762\u5F53\u524D\u4E0D\u53EF\u7528", subTitle: launchError }));
1696
1725
  if (!launchSurface && !commandId)
@@ -1710,7 +1739,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1710
1739
  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" }));
1711
1740
  }
1712
1741
  const submit = async (values) => {
1713
- if (submitInFlight.current || commandId || completion || !launchSurface)
1742
+ if (submitInFlight.current || commandId || completion || !launchSurface || formOptions?.preparation || prefillError || formProjection.error)
1714
1743
  return;
1715
1744
  const unresolved = readPendingWorkflowSubmission(submissionLocatorStorage(), recoveryScope);
1716
1745
  if (pendingSubmission || unresolved) {
@@ -1732,7 +1761,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1732
1761
  try {
1733
1762
  const encoded = namedIntent ? normalizeFormValues(values, subjectDefinition.surface)
1734
1763
  : standardProcessFormValues(values, subjectDefinition.surface, resources, (field, mode) => fieldWritable(field, mode === 'create' ? 'create' : 'edit', hasCapability, identity.isAppSuperAdmin));
1735
- const data = Object.fromEntries(fields.filter(field => Object.hasOwn(encoded, field.key)).map(field => [field.key, encoded[field.key]]));
1764
+ const data = workflowSubmissionFormProjection(fields, encoded, formOptions?.fieldState?.(encoded)).values;
1736
1765
  const signature = JSON.stringify({ workflowCode, subjectId, environmentKey: identity.environment.key, submissionMode, data });
1737
1766
  if (submissionAttempt.current?.signature !== signature) {
1738
1767
  submissionAttempt.current = { signature, idempotencyKey: randomId(`process:${workflowCode}`), requestedAt: new Date().toISOString() };
@@ -1945,7 +1974,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1945
1974
  (namedIntent
1946
1975
  ? '业务操作将在服务端完成校验、幂等提交,并按规则决定是否进入审批'
1947
1976
  : '业务数据和流程发起意图将原子提交'),
1948
- fields,
1977
+ fields: formProjection.fields,
1949
1978
  subjectDefinition,
1950
1979
  subjectForm,
1951
1980
  requirementForm,
@@ -1959,7 +1988,10 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1959
1988
  completion,
1960
1989
  embedded: Boolean(onDismiss),
1961
1990
  fieldRenderers,
1991
+ formIntro: formOptions?.intro,
1992
+ formError: prefillError || formProjection.error ? '表单规则暂不可用,请联系管理员。' : undefined,
1962
1993
  recordId: mutationMode === 'update' ? subjectId : undefined,
1994
+ expectedRevision: mutationMode === 'update' ? loadedSubjectRevision : undefined,
1963
1995
  onBack: onDismiss ? dismissDrawer : () => navigate(-1),
1964
1996
  onSubmit: submit,
1965
1997
  onAnswer: answer,
@@ -1988,7 +2020,7 @@ function StandardProcessSubmissionRenderer(props) {
1988
2020
  }, new Map())].map(([section, fields]) => ({ section, fields }));
1989
2021
  if (props.completion)
1990
2022
  return _jsx(Result, { status: "success", title: "\u63D0\u4EA4\u6210\u529F", extra: _jsx(Button, { onClick: props.onBack, children: "\u8FD4\u56DE" }) });
1991
- 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, form: props.subjectForm, busy: props.loading || props.submitted, pending: props.loading || props.processing, submitDisabled: props.submitted, submitLabel: "\u63D0\u4EA4\u5BA1\u6279", canWriteField: () => true, renderers: props.fieldRenderers, feedback: _jsxs(_Fragment, { children: [props.launchControls, 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 })] });
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 })] });
1992
2024
  }
1993
2025
  function DesktopProcessSubmissionRenderer(props) { return _jsx(StandardProcessSubmissionRenderer, { ...props, variant: "desktop" }); }
1994
2026
  function MobileProcessSubmissionRenderer(props) { return _jsx(StandardProcessSubmissionRenderer, { ...props, variant: "mobile" }); }