openxiangda 2.0.0-alpha.99 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -20
  3. package/bin/distribution/commands.js +55 -0
  4. package/bin/distribution/launcher.js +49 -0
  5. package/bin/distribution/migrate.js +60 -0
  6. package/bin/distribution/releases.js +52 -0
  7. package/bin/distribution/skills.js +80 -0
  8. package/bin/distribution/update.js +68 -0
  9. package/bin/distribution/workspace.js +85 -0
  10. package/bin/run.js +9 -11
  11. package/dist/browser/AuthoritativeSelector.d.ts +3 -2
  12. package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
  13. package/dist/browser/AuthoritativeSelector.js +39 -24
  14. package/dist/browser/AuthoritativeSelector.js.map +1 -1
  15. package/dist/browser/components/platform-fields/MobileFieldControls.d.ts.map +1 -1
  16. package/dist/browser/components/platform-fields/MobileFieldControls.js +2 -2
  17. package/dist/browser/components/platform-fields/MobileFieldControls.js.map +1 -1
  18. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +4 -2
  19. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
  20. package/dist/browser/components/platform-fields/ResourceReferenceField.js +2 -2
  21. package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
  22. package/dist/browser/components/platform-fields/rich-text-value.d.ts.map +1 -1
  23. package/dist/browser/components/platform-fields/rich-text-value.js +11 -1
  24. package/dist/browser/components/platform-fields/rich-text-value.js.map +1 -1
  25. package/dist/browser/components/resource/RecordDetailFrame.js +1 -1
  26. package/dist/browser/components/resource/RecordDetailFrame.js.map +1 -1
  27. package/dist/browser/components/resource/SurfaceFields.d.ts +3 -2
  28. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
  29. package/dist/browser/components/resource/SurfaceFields.js +14 -7
  30. package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
  31. package/dist/browser/components/resource/resource-import.d.ts +16 -1
  32. package/dist/browser/components/resource/resource-import.d.ts.map +1 -1
  33. package/dist/browser/components/resource/resource-import.js +58 -34
  34. package/dist/browser/components/resource/resource-import.js.map +1 -1
  35. package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
  36. package/dist/browser/components/todo/ApplicationTodoCenterPage.d.ts.map +1 -1
  37. package/dist/browser/components/todo/ApplicationTodoCenterPage.js +1 -2
  38. package/dist/browser/components/todo/ApplicationTodoCenterPage.js.map +1 -1
  39. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  40. package/dist/browser/components/workflow/StandardWorkflowPages.js +54 -52
  41. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  42. package/dist/browser/platform-client.d.ts +3 -2
  43. package/dist/browser/platform-client.d.ts.map +1 -1
  44. package/dist/browser/platform-client.js +69 -18
  45. package/dist/browser/platform-client.js.map +1 -1
  46. package/dist/browser/record-detail.css +3 -2
  47. package/dist/browser/runtime.d.ts.map +1 -1
  48. package/dist/browser/runtime.js +26 -2
  49. package/dist/browser/runtime.js.map +1 -1
  50. package/dist/browser/workflow-launch.d.ts +4 -1
  51. package/dist/browser/workflow-launch.d.ts.map +1 -1
  52. package/dist/browser/workflow-launch.js +32 -0
  53. package/dist/browser/workflow-launch.js.map +1 -1
  54. package/dist/core.d.ts +1 -1
  55. package/dist/core.d.ts.map +1 -1
  56. package/dist/core.js.map +1 -1
  57. package/documentation/AGENTS.md +26 -0
  58. package/documentation/administration.md +27 -0
  59. package/documentation/application-foundation.md +162 -0
  60. package/documentation/appspec.md +152 -0
  61. package/documentation/backend.md +132 -0
  62. package/documentation/concepts.md +61 -0
  63. package/documentation/data-authz.md +62 -0
  64. package/documentation/delivery.md +110 -0
  65. package/documentation/development.md +32 -0
  66. package/documentation/field-components.md +236 -0
  67. package/documentation/frontend.md +269 -0
  68. package/documentation/getting-started.md +66 -0
  69. package/documentation/interaction-patterns.md +56 -0
  70. package/documentation/manifest.json +120 -0
  71. package/documentation/product-design.md +142 -0
  72. package/documentation/public-access.md +167 -0
  73. package/documentation/reference/cli.md +27 -0
  74. package/documentation/reference/mcp.md +649 -0
  75. package/documentation/testing.md +63 -0
  76. package/documentation/upgrading.md +39 -0
  77. package/documentation/workflow-events.md +181 -0
  78. package/launcher-skill/openxiangda/SKILL.md +24 -0
  79. package/package.json +72 -9
  80. package/releases/2.0.0.json +50 -0
  81. package/skills/manifest.json +2 -2
  82. package/skills/openxiangda-v2/SKILL.md +64 -51
  83. package/skills/openxiangda-v2/agents/openai.yaml +2 -2
  84. package/skills/openxiangda-v2/references/administration.md +27 -0
  85. package/skills/openxiangda-v2/references/application-foundation.md +162 -0
  86. package/skills/openxiangda-v2/references/appspec.md +132 -47
  87. package/skills/openxiangda-v2/references/backend.md +101 -248
  88. package/skills/openxiangda-v2/references/cli.md +27 -0
  89. package/skills/openxiangda-v2/references/concepts.md +61 -0
  90. package/skills/openxiangda-v2/references/data-authz.md +36 -388
  91. package/skills/openxiangda-v2/references/delivery.md +110 -49
  92. package/skills/openxiangda-v2/references/development.md +32 -0
  93. package/skills/openxiangda-v2/references/field-components.md +236 -0
  94. package/skills/openxiangda-v2/references/frontend.md +254 -280
  95. package/skills/openxiangda-v2/references/getting-started.md +66 -0
  96. package/skills/openxiangda-v2/references/interaction-patterns.md +56 -0
  97. package/skills/openxiangda-v2/references/mcp.md +649 -0
  98. package/skills/openxiangda-v2/references/product-design.md +142 -0
  99. package/skills/openxiangda-v2/references/public-access.md +92 -84
  100. package/skills/openxiangda-v2/references/testing.md +45 -56
  101. package/skills/openxiangda-v2/references/upgrading.md +39 -0
  102. package/skills/openxiangda-v2/references/workflow-events.md +143 -285
  103. package/skills/openxiangda-v2/references/architecture.md +0 -9
  104. package/skills/openxiangda-v2/references/commands.md +0 -21
  105. package/skills/openxiangda-v2/references/discovery.md +0 -15
  106. package/skills/openxiangda-v2/references/workspace.md +0 -62
@@ -1,17 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ArrowLeftOutlined, ClockCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, EllipsisOutlined, ReloadOutlined, CloseOutlined, ExpandOutlined, CompressOutlined, ExportOutlined, } from '@ant-design/icons';
2
+ import { ArrowLeftOutlined, ClockCircleOutlined, EllipsisOutlined, ReloadOutlined, CloseOutlined, ExpandOutlined, CompressOutlined, ExportOutlined, } from '@ant-design/icons';
3
3
  import { Alert, App, Button, Card, Drawer, Empty, Form, Input, Modal, Result, Segmented, Select, Space, Spin, Table, Tabs, Tag, Tooltip, Typography, } from 'antd';
4
4
  import { normalizeWorkflowBusinessDetail, } from 'openxiangda-contracts/browser';
5
5
  import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
6
6
  import { Link, Navigate, useHref, useNavigate, useParams, useSearchParams, } from 'react-router-dom';
7
- import { Shell } from '../../Shell';
8
- import { executeWorkflowOperation, executeWorkflowLaunchNamedOperation, loadWorkflowInstanceDetail, loadWorkflowRecordDetail, loadWorkflowDataAudit, loadWorkflowInstanceSurface, loadWorkflowLaunchSurface, loadWorkflowTaskSurface, loadWorkflowTaskDetail, loadWorkflowWorkCenter, answerBusinessProcessCommand, commitStandardProcess, createNativeResourceClient, loadProcessCommandSurface, retryBusinessProcessCommand, searchDirectory, uploadOperationManagedFile, } from '../../platform-client';
7
+ import { PlatformDirectoryPicker } from '../platform-fields/PlatformDirectoryPicker';
8
+ import { directoryStoredValues } from '../platform-fields/directory-value';
9
+ import { executeWorkflowOperation, executeWorkflowLaunchNamedOperation, loadWorkflowInstanceDetail, loadWorkflowRecordDetail, loadWorkflowDataAudit, loadWorkflowInstanceSurface, loadWorkflowLaunchSurface, loadWorkflowTaskSurface, loadWorkflowTaskDetail, loadWorkflowWorkCenter, answerBusinessProcessCommand, commitStandardProcess, createNativeResourceClient, loadProcessCommandSurface, retryBusinessProcessCommand, uploadOperationManagedFile, } from '../../platform-client';
9
10
  import { useWorkflowDefinition, } from '../../workflow-definitions';
10
11
  import { useResourceDefinitions } from '../../resource-definitions';
11
12
  import { selectedSurfaceFields } from '../resource/resource-field-selection';
12
13
  import { useRuntime } from '../../runtime';
13
14
  import { SurfaceFieldValue, } from '../resource/SurfaceFields';
14
- import { buildWorkflowNamedOperationInput, parseWorkflowNamedOperationResult, workflowLaunchContractJsonEqual, } from '../../workflow-launch';
15
+ import { workflowContextScalarValue, processStatusReadRetryDelay, buildWorkflowNamedOperationInput, parseWorkflowNamedOperationResult, workflowLaunchContractJsonEqual, } from '../../workflow-launch';
15
16
  import { normalizeFormValues, normalizeRecordForForm, } from '../platform-fields/field-form-codec';
16
17
  import { RecordDetailFrame, RecordDetailSections, detailTime } from '../resource/RecordDetailFrame';
17
18
  import { RecordChangeHistory } from '../resource/RecordChangeHistory';
@@ -75,6 +76,9 @@ function workflowStatus(status) {
75
76
  };
76
77
  return states[status] || { label: status || '未知', color: 'default' };
77
78
  }
79
+ function workflowHasEnded(instance) {
80
+ return ['completed', 'approved', 'rejected', 'withdrawn', 'terminated', 'cancelled', 'expired'].includes(instance.status);
81
+ }
78
82
  function StatusTag({ status }) {
79
83
  const state = workflowStatus(status);
80
84
  return _jsx(Tag, { color: state.color, children: state.label });
@@ -302,28 +306,15 @@ export function WorkflowTimelineSection({ timeline, }) {
302
306
  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 }), _jsx(StatusTag, { status: item.status })] }), 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
307
  }) })) : (_jsx(Empty, { description: "\u6682\u65E0\u6D41\u7A0B\u8F68\u8FF9", image: Empty.PRESENTED_IMAGE_SIMPLE })) }));
304
308
  }
305
- function WorkflowUserSelect({ id, placeholder, value, onChange, multiple = false, maxCount, }) {
306
- const [options, setOptions] = useState([]);
307
- const [loading, setLoading] = useState(false);
308
- const sequence = useRef(0);
309
- useEffect(() => () => { sequence.current += 1; }, []);
310
- const search = (keyword) => {
311
- const current = ++sequence.current;
312
- setLoading(true);
313
- void searchDirectory('user', { keyword })
314
- .then((page) => {
315
- if (current !== sequence.current)
316
- return;
317
- setOptions(page.items.map((item) => ({ label: item.label, value: item.id })));
318
- })
319
- .catch(() => { if (current === sequence.current)
320
- setOptions([]); })
321
- .finally(() => {
322
- if (current === sequence.current)
323
- setLoading(false);
324
- });
325
- };
326
- return (_jsx(Select, { id: id, mode: multiple ? 'multiple' : undefined, maxCount: maxCount, filterOption: false, loading: loading, onChange: onChange, onSearch: search, options: options, placeholder: placeholder || '搜索并选择人员', showSearch: true, value: value }));
309
+ function WorkflowMemberPicker({ id, placeholder, value, onChange, multiple = false, variant }) {
310
+ const [snapshots, setSnapshots] = useState([]);
311
+ const ids = Array.isArray(value) ? value : value ? [value] : [];
312
+ const selected = ids.map(id => snapshots.find(item => item.value === id) || { value: id, label: '已选成员' });
313
+ return _jsx(PlatformDirectoryPicker, { id: id, kind: "user", mobile: variant === 'mobile', multiple: multiple, placeholder: placeholder || '请选择成员', value: multiple ? selected : selected[0], onChange: next => {
314
+ const items = directoryStoredValues(next);
315
+ setSnapshots(items);
316
+ onChange?.(multiple ? items.map(item => item.value) : items[0]?.value);
317
+ } });
327
318
  }
328
319
  function schemaProperties(operation) {
329
320
  const schema = operation.inputSchema;
@@ -335,7 +326,7 @@ function schemaProperties(operation) {
335
326
  required: schema.required?.includes(key) === true,
336
327
  }));
337
328
  }
338
- function OperationFields({ operation, }) {
329
+ function OperationFields({ operation, variant, }) {
339
330
  return (_jsx(_Fragment, { children: schemaProperties(operation).map(({ key, property, required, ui }) => {
340
331
  const rules = [
341
332
  ...(required ? [{ required: true, message: `请填写${property.title || key}` }] : []),
@@ -349,7 +340,7 @@ function OperationFields({ operation, }) {
349
340
  ];
350
341
  let control = _jsx(Input, { placeholder: ui.placeholder });
351
342
  if (ui.component === 'user_select')
352
- control = _jsx(WorkflowUserSelect, { multiple: property.type === 'array' || ui.mode === 'multiple', maxCount: property.maxItems, placeholder: ui.placeholder });
343
+ control = _jsx(WorkflowMemberPicker, { variant: variant, multiple: property.type === 'array' || ui.mode === 'multiple', placeholder: ui.placeholder || `请选择${property.title || '成员'}` });
353
344
  else if (property.enum) {
354
345
  control = (_jsx(Select, { options: property.enum.map((value, index) => ({
355
346
  label: property.enumNames?.[index] || value,
@@ -373,9 +364,9 @@ function OperationDialog({ operation, submitting, variant, onCancel, onSubmit, }
373
364
  if (!operation)
374
365
  return null;
375
366
  const ui = operation.uiSchema;
376
- const formNode = (_jsxs(Form, { form: form, layout: "vertical", onFinish: onSubmit, children: [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 })] }));
367
+ const formNode = (_jsxs(Form, { form: form, layout: "vertical", onFinish: onSubmit, children: [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 })] }));
377
368
  if (variant === 'mobile') {
378
- return (_jsx(Drawer, { extra: _jsx(Button, { loading: submitting, onClick: () => form.submit(), type: "primary", children: ui.confirmText || `确认${operation.label}` }), onClose: onCancel, open: true, placement: "bottom", size: "large", title: operation.label, children: formNode }));
369
+ 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 }));
379
370
  }
380
371
  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 }));
381
372
  }
@@ -734,11 +725,13 @@ function StandardWorkflowDetailRenderer({ surface, timeline, warning, operations
734
725
  const activeNode = timeline?.display?.entries.find(entry => entry.status === 'active');
735
726
  const people = activeNode?.people.map(person => person.displayName).filter(Boolean).join('、');
736
727
  const statusTone = workflowStatus(instance.status).color;
737
- const bannerTone = statusTone === 'success' ? 'success' : statusTone === 'error' ? 'error' : activeNode ? 'active' : 'neutral';
728
+ const bannerTone = statusTone === 'error' ? 'error' : 'active';
729
+ const edit = workflowHasEnded(instance) ? onEdit : undefined;
730
+ const hasActions = standardWorkflowOperations(surface).length > 0;
738
731
  const loadAudit = useCallback(() => loadWorkflowDataAudit(instance.id), [instance.id]);
739
732
  const back = onClose || (() => navigate(variant === 'mobile' ? '/m/work-center' : '/work-center'));
740
733
  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,
741
- summary.submittedAt ? `${detailTime(summary.submittedAt)} 创建` : ''].filter(Boolean).join(' · '), updatedAt: business.record.updated_at || instance.completedAt || instance.startedAt, onClose: back, onEdit: onEdit, editing: editing, busy: busy, drawer: drawer, drawerState: drawerState, newPageHref: newPageHref, footer: _jsxs(_Fragment, { children: [operations, _jsx(Button, { onClick: back, children: "\u5173\u95ED" }), onEdit && _jsx(Button, { onClick: onEdit, children: "\u7F16\u8F91" })] }), children: [warning && _jsx(Alert, { description: warning, showIcon: true, type: "warning" }), _jsxs("div", { className: `oxa-workflow-current-node is-${bannerTone}`, role: "status", children: [_jsxs("span", { children: [bannerTone === 'success' ? _jsx(CheckCircleOutlined, {}) : bannerTone === 'error' ? _jsx(CloseCircleOutlined, {}) : _jsx(ClockCircleOutlined, {}), activeNode ? `当前节点:${activeNode.title}` : workflowStatus(instance.status).label] }), people && _jsxs("span", { children: ["\u7B49\u5F85", people, "\u5904\u7406"] })] }), _jsx(Tabs, { activeKey: tab, onChange: setTab, items: [
734
+ summary.submittedAt ? `${detailTime(summary.submittedAt)} 创建` : ''].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: [
742
735
  { key: 'application', label: '申请内容', children: _jsx(WorkflowBusinessDetailSections, { surface: surface, variant: variant }) },
743
736
  { key: 'history', label: '审批历史', children: _jsx(WorkflowTimelineSection, { timeline: timeline }) },
744
737
  { key: 'changes', label: '变更记录', children: tab === 'changes' && business.surface && business.resourceCode && business.recordId
@@ -852,7 +845,7 @@ function WorkflowDetailPage({ kind, variant, resourceCode, recordId, onDismiss,
852
845
  ? _jsx(WorkflowTaskOperationsPanel, { onCommandCompleted: onCommandCompleted, surface: surface, taskId: task.id, variant: variant }, task.id)
853
846
  : _jsx(WorkflowInstanceOperationsPanel, { instanceId: instance.id, onCommandCompleted: onCommandCompleted, surface: surface, variant: variant });
854
847
  return _jsx(StandardWorkflowDetailRenderer, { surface: surface, timeline: timeline, warning: error, operations: operations, variant: variant, drawer: Boolean(onDismiss), drawerState: drawerState, newPageHref: newPageHref, onClose: editing ? () => { if (!editBusy)
855
- 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: identity.isAppSuperAdmin && (business?.status === 'ready' || business?.status === 'stale') ? () => setEditing(true) : undefined });
848
+ 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 });
856
849
  }
857
850
  export function WorkflowRecordDetailPage({ variant = 'desktop', ...props }) { return _jsx(WorkflowDetailPage, { ...props, variant: variant, kind: "record" }); }
858
851
  export function WorkflowTaskPage({ variant = 'desktop', }) {
@@ -902,7 +895,7 @@ export function WorkflowWorkCenterPage({ variant = 'desktop' }) {
902
895
  current: pageNumber, pageSize, total: page?.total || 0, showSizeChanger: true,
903
896
  onChange: (number, size) => { setPageNumber(number); setPageSize(size); },
904
897
  } }) : _jsxs(_Fragment, { children: [loading && _jsx(Spin, {}), _jsx("div", { className: "oxa-work-center-mobile-list", children: page?.items.map(item => _jsxs("button", { type: "button", className: "oxa-work-center-item", onClick: () => open(item), children: [_jsxs("div", { children: [_jsx("strong", { children: item.title }), _jsx(StatusTag, { status: item.instanceStatus || item.status })] }), _jsx("p", { children: [item.workflowTitle, item.taskTitle].filter(Boolean).join(' · ') }), _jsx("time", { children: formatTime(item.occurredAt) })] }, item.id)) }), !loading && !page?.items.length && !error && _jsx(Empty, { description: "\u6682\u65E0\u76F8\u5173\u7533\u8BF7" }), Boolean(page && page.total > pageSize) && _jsxs("div", { className: "oxa-mobile-pagination", children: [_jsx(Button, { disabled: pageNumber <= 1, onClick: () => setPageNumber(value => value - 1), children: "\u4E0A\u4E00\u9875" }), _jsxs("span", { children: ["\u7B2C ", pageNumber, " \u9875"] }), _jsx(Button, { disabled: pageNumber * pageSize >= (page?.total || 0), onClick: () => setPageNumber(value => value + 1), children: "\u4E0B\u4E00\u9875" })] })] })] });
905
- return variant === 'desktop' ? _jsx(Shell, { children: content }) : content;
898
+ return content;
906
899
  }
907
900
  function RequirementFields({ requirements, }) {
908
901
  return (_jsx(_Fragment, { children: requirements.map((requirement) => (_jsx(Form.Item, { label: requirement.title, name: requirement.id, rules: requirement.required
@@ -1024,20 +1017,7 @@ async function workflowContextPrefillValue(field, rawValue, resources) {
1024
1017
  ...(Object.keys(snapshot).length ? { snapshot } : {}),
1025
1018
  };
1026
1019
  }
1027
- if (field.type === 'number.integer' || field.type === 'number.decimal') {
1028
- const parsed = Number(value);
1029
- if (!Number.isFinite(parsed)) {
1030
- throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_VALUE_INVALID');
1031
- }
1032
- return parsed;
1033
- }
1034
- if (field.type === 'boolean') {
1035
- if (!['true', 'false'].includes(value)) {
1036
- throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_VALUE_INVALID');
1037
- }
1038
- return value === 'true';
1039
- }
1040
- return value;
1020
+ return workflowContextScalarValue(field, value);
1041
1021
  }
1042
1022
  export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWorkflowCode, variant = 'desktop', onDismiss, onCompleted, } = {}) {
1043
1023
  const { workflowCode: routeWorkflowCode = '' } = useParams();
@@ -1263,16 +1243,29 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1263
1243
  }
1264
1244
  let active = true;
1265
1245
  let timer;
1246
+ const startedAt = Date.now();
1247
+ let failures = 0;
1248
+ let controller;
1266
1249
  const refresh = async () => {
1250
+ if (!active)
1251
+ return;
1252
+ if (Date.now() - startedAt >= 60_000) {
1253
+ setProcessError('申请已提交,处理尚未结束;可稍后刷新状态,无需重复提交');
1254
+ return;
1255
+ }
1256
+ controller = new AbortController();
1257
+ const timeout = setTimeout(() => controller?.abort(new DOMException('状态读取超时', 'TimeoutError')), Math.min(10_000, 60_000 - (Date.now() - startedAt)));
1267
1258
  try {
1268
- const next = await loadProcessCommandSurface(commandId);
1259
+ const next = await loadProcessCommandSurface(commandId, controller.signal);
1269
1260
  if (!active)
1270
1261
  return;
1271
- if (next.command.environmentKey !== identity.environment.key ||
1262
+ if (next.command.id !== commandId ||
1263
+ next.command.environmentKey !== identity.environment.key ||
1272
1264
  next.command.workflowCode !== workflowCode ||
1273
1265
  next.command.subject.resourceCode !== definition?.subject.resourceCode) {
1274
1266
  throw new Error('OPENXIANGDA_PROCESS_COMMAND_SCOPE_MISMATCH');
1275
1267
  }
1268
+ failures = 0;
1276
1269
  setProcessSurface(next);
1277
1270
  setProcessError(null);
1278
1271
  if (next.command.status === 'started' && next.command.workflowInstanceId) {
@@ -1295,13 +1288,21 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1295
1288
  }
1296
1289
  }
1297
1290
  catch (error) {
1298
- if (active)
1299
- setProcessError(errorMessage(error, '命令状态读取失败'));
1291
+ if (!active)
1292
+ return;
1293
+ const delay = processStatusReadRetryDelay(error, ++failures, Date.now() - startedAt);
1294
+ setProcessError(delay === null ? '申请已提交,暂时无法读取处理状态;请稍后刷新,无需重复提交' : '申请已提交,正在重新读取处理状态,请勿重复提交');
1295
+ if (delay !== null)
1296
+ timer = setTimeout(() => void refresh(), delay);
1297
+ }
1298
+ finally {
1299
+ clearTimeout(timeout);
1300
1300
  }
1301
1301
  };
1302
1302
  void refresh();
1303
1303
  return () => {
1304
1304
  active = false;
1305
+ controller?.abort();
1305
1306
  if (timer)
1306
1307
  clearTimeout(timer);
1307
1308
  };
@@ -1545,6 +1546,7 @@ export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWor
1545
1546
  const uploadOperationCode = namedIntent?.operationCode || definition.processOperationCode;
1546
1547
  const fieldRenderers = uploadOperationCode
1547
1548
  ? {
1549
+ ...(namedIntent ? { referenceLaunch: { workflowCode: definition.code, operationCode: namedIntent.operationCode } } : {}),
1548
1550
  upload: async (field, file) => await uploadOperationManagedFile({
1549
1551
  operationCode: uploadOperationCode,
1550
1552
  resourceCode: subjectDefinition.code,