openxiangda 2.0.0-alpha.70 → 2.0.0-alpha.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/Shell.d.ts.map +1 -1
- package/dist/browser/Shell.js +1 -4
- package/dist/browser/Shell.js.map +1 -1
- package/dist/browser/admin-access.d.ts +7 -0
- package/dist/browser/admin-access.d.ts.map +1 -0
- package/dist/browser/admin-access.js +13 -0
- package/dist/browser/admin-access.js.map +1 -0
- package/dist/browser/application.d.ts +3 -2
- package/dist/browser/application.d.ts.map +1 -1
- package/dist/browser/application.js +36 -31
- package/dist/browser/application.js.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +2 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +362 -16
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
- package/dist/browser/platform-client.d.ts +3 -1
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +13 -0
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/route-manifest.d.ts +1 -7
- package/dist/browser/route-manifest.d.ts.map +1 -1
- package/dist/browser/route-manifest.js +1 -43
- package/dist/browser/route-manifest.js.map +1 -1
- package/dist/browser/workflow-definitions.d.ts +25 -0
- package/dist/browser/workflow-definitions.d.ts.map +1 -1
- package/dist/browser/workflow-definitions.js +9 -3
- package/dist/browser/workflow-definitions.js.map +1 -1
- package/dist/browser/workflow-launch.d.ts +36 -0
- package/dist/browser/workflow-launch.d.ts.map +1 -0
- package/dist/browser/workflow-launch.js +103 -0
- package/dist/browser/workflow-launch.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/nest.d.ts +1 -1
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +1 -1
- package/dist/nest.js.map +1 -1
- package/dist/react.d.ts +2 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +2 -0
- package/dist/react.js.map +1 -1
- package/package.json +7 -7
- package/skills/openxiangda-v2/SKILL.md +3 -3
- package/skills/openxiangda-v2/references/frontend.md +14 -9
- package/skills/openxiangda-v2/references/workflow-events.md +52 -14
- package/skills/openxiangda-v2/references/workspace.md +1 -1
|
@@ -5,11 +5,12 @@ import { normalizeWorkflowBusinessDetail, } from 'openxiangda-contracts/browser'
|
|
|
5
5
|
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
6
6
|
import { Link, Navigate, useNavigate, useParams, useSearchParams, } from 'react-router-dom';
|
|
7
7
|
import { Shell } from '../../Shell';
|
|
8
|
-
import { executeWorkflowOperation, loadWorkflowInstanceDetail, loadWorkflowInstanceSurface, loadWorkflowLaunchSurface, loadWorkflowTaskSurface, loadWorkflowTaskDetail, loadWorkflowWorkCenter, answerBusinessProcessCommand, commitStandardProcess, createNativeResourceClient, loadProcessCommandSurface, retryBusinessProcessCommand, searchDirectory, } from '../../platform-client';
|
|
9
|
-
import { useWorkflowDefinition } from '../../workflow-definitions';
|
|
8
|
+
import { executeWorkflowOperation, executeWorkflowLaunchNamedOperation, loadWorkflowInstanceDetail, loadWorkflowInstanceSurface, loadWorkflowLaunchSurface, loadWorkflowTaskSurface, loadWorkflowTaskDetail, loadWorkflowWorkCenter, answerBusinessProcessCommand, commitStandardProcess, createNativeResourceClient, loadProcessCommandSurface, retryBusinessProcessCommand, searchDirectory, uploadOperationManagedFile, } from '../../platform-client';
|
|
9
|
+
import { useWorkflowDefinition, } from '../../workflow-definitions';
|
|
10
10
|
import { useResourceDefinitions } from '../../resource-definitions';
|
|
11
11
|
import { useRuntime } from '../../runtime';
|
|
12
12
|
import { MobileSurfaceFieldControl, SurfaceFieldControl, SurfaceFieldValue, } from '../resource/SurfaceFields';
|
|
13
|
+
import { buildWorkflowNamedOperationInput, parseWorkflowNamedOperationResult, } from '../../workflow-launch';
|
|
13
14
|
import { normalizeFormValues, normalizeRecordForForm, } from '../platform-fields/field-form-codec';
|
|
14
15
|
import { PlatformAvatar } from '../PlatformAvatar';
|
|
15
16
|
/**
|
|
@@ -915,7 +916,131 @@ function RequirementFields({ requirements, }) {
|
|
|
915
916
|
value: 'userId' in candidate ? candidate.userId : candidate.value,
|
|
916
917
|
})) }) }, requirement.id))) }));
|
|
917
918
|
}
|
|
918
|
-
|
|
919
|
+
function sameJson(left, right) {
|
|
920
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
921
|
+
}
|
|
922
|
+
function namedLaunchIntentMatches(generated, surface) {
|
|
923
|
+
if (!generated || !surface)
|
|
924
|
+
return generated === surface;
|
|
925
|
+
return (generated.operationCode === surface.operationCode &&
|
|
926
|
+
generated.method === surface.method &&
|
|
927
|
+
generated.path === surface.href &&
|
|
928
|
+
generated.requiredCapability === surface.requiredCapability &&
|
|
929
|
+
generated.requestSchemaDigest === surface.requestSchemaDigest &&
|
|
930
|
+
generated.responseSchemaDigest === surface.responseSchemaDigest &&
|
|
931
|
+
sameJson(generated.inputs, surface.inputs) &&
|
|
932
|
+
sameJson(generated.output, surface.output));
|
|
933
|
+
}
|
|
934
|
+
function fieldValueLabel(value) {
|
|
935
|
+
if (value === undefined || value === null || value === '')
|
|
936
|
+
return '';
|
|
937
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
938
|
+
const item = value;
|
|
939
|
+
if (typeof item.label === 'string')
|
|
940
|
+
return item.label;
|
|
941
|
+
}
|
|
942
|
+
if (Array.isArray(value))
|
|
943
|
+
return value.map(fieldValueLabel).filter(Boolean).join('、');
|
|
944
|
+
return String(value);
|
|
945
|
+
}
|
|
946
|
+
function subjectRecordLabel(record, definition) {
|
|
947
|
+
const preferred = definition.surface.list?.searchableFields || [];
|
|
948
|
+
const candidates = [
|
|
949
|
+
...preferred,
|
|
950
|
+
...(definition.surface.form?.fieldOrder || []),
|
|
951
|
+
...Object.keys(definition.surface.fields),
|
|
952
|
+
];
|
|
953
|
+
for (const fieldCode of candidates) {
|
|
954
|
+
const label = fieldValueLabel(record[fieldCode]);
|
|
955
|
+
if (label)
|
|
956
|
+
return label;
|
|
957
|
+
}
|
|
958
|
+
return String(record.id || '业务记录');
|
|
959
|
+
}
|
|
960
|
+
function SubjectRecordSelector({ definition, value, onChange, }) {
|
|
961
|
+
const [keyword, setKeyword] = useState('');
|
|
962
|
+
const [options, setOptions] = useState([]);
|
|
963
|
+
const [loading, setLoading] = useState(false);
|
|
964
|
+
useEffect(() => {
|
|
965
|
+
let active = true;
|
|
966
|
+
const timer = window.setTimeout(() => {
|
|
967
|
+
setLoading(true);
|
|
968
|
+
void createNativeResourceClient(definition.code, definition.surface)
|
|
969
|
+
.list({ page: 1, pageSize: 20, ...(keyword.trim() ? { keyword } : {}) })
|
|
970
|
+
.then(page => {
|
|
971
|
+
if (!active)
|
|
972
|
+
return;
|
|
973
|
+
setOptions(page.rows
|
|
974
|
+
.map(record => ({
|
|
975
|
+
value: String(record.id || ''),
|
|
976
|
+
label: subjectRecordLabel(record, definition),
|
|
977
|
+
}))
|
|
978
|
+
.filter(option => option.value));
|
|
979
|
+
})
|
|
980
|
+
.catch(() => {
|
|
981
|
+
if (active)
|
|
982
|
+
setOptions([]);
|
|
983
|
+
})
|
|
984
|
+
.finally(() => {
|
|
985
|
+
if (active)
|
|
986
|
+
setLoading(false);
|
|
987
|
+
});
|
|
988
|
+
}, 250);
|
|
989
|
+
return () => {
|
|
990
|
+
active = false;
|
|
991
|
+
window.clearTimeout(timer);
|
|
992
|
+
};
|
|
993
|
+
}, [definition, keyword]);
|
|
994
|
+
return (_jsx(Select, { allowClear: true, filterOption: false, loading: loading, onChange: next => onChange(next || undefined), onSearch: setKeyword, options: options, placeholder: "\u641C\u7D22\u5E76\u9009\u62E9\u5DF2\u6709\u4E1A\u52A1\u8BB0\u5F55", showSearch: true, value: value || undefined }));
|
|
995
|
+
}
|
|
996
|
+
async function workflowContextPrefillValue(field, rawValue, resources) {
|
|
997
|
+
const value = rawValue.trim();
|
|
998
|
+
if (!value || value.length > 500) {
|
|
999
|
+
throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_VALUE_INVALID');
|
|
1000
|
+
}
|
|
1001
|
+
if (field.type === 'resource-ref.single') {
|
|
1002
|
+
const source = field.source;
|
|
1003
|
+
const target = source ? resources[source.resourceCode] : undefined;
|
|
1004
|
+
if (!source || !target) {
|
|
1005
|
+
throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_SOURCE_REQUIRED');
|
|
1006
|
+
}
|
|
1007
|
+
const record = await createNativeResourceClient(target.code, target.surface).get(value);
|
|
1008
|
+
const label = fieldValueLabel(record[source.labelField]);
|
|
1009
|
+
if (!label || String(record.id || '') !== value) {
|
|
1010
|
+
throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_RECORD_INVALID');
|
|
1011
|
+
}
|
|
1012
|
+
const description = (source.descriptionFields || [])
|
|
1013
|
+
.map(fieldCode => fieldValueLabel(record[fieldCode]))
|
|
1014
|
+
.filter(Boolean)
|
|
1015
|
+
.join(' · ');
|
|
1016
|
+
const snapshot = Object.fromEntries((source.snapshotFields || []).map(fieldCode => [
|
|
1017
|
+
fieldCode,
|
|
1018
|
+
record[fieldCode],
|
|
1019
|
+
]));
|
|
1020
|
+
return {
|
|
1021
|
+
resourceCode: source.resourceCode,
|
|
1022
|
+
value,
|
|
1023
|
+
label,
|
|
1024
|
+
...(description ? { description } : {}),
|
|
1025
|
+
...(Object.keys(snapshot).length ? { snapshot } : {}),
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
if (field.type === 'number.integer' || field.type === 'number.decimal') {
|
|
1029
|
+
const parsed = Number(value);
|
|
1030
|
+
if (!Number.isFinite(parsed)) {
|
|
1031
|
+
throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_VALUE_INVALID');
|
|
1032
|
+
}
|
|
1033
|
+
return parsed;
|
|
1034
|
+
}
|
|
1035
|
+
if (field.type === 'boolean') {
|
|
1036
|
+
if (!['true', 'false'].includes(value)) {
|
|
1037
|
+
throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_VALUE_INVALID');
|
|
1038
|
+
}
|
|
1039
|
+
return value === 'true';
|
|
1040
|
+
}
|
|
1041
|
+
return value;
|
|
1042
|
+
}
|
|
1043
|
+
export function WorkflowSubmissionPage({ instancePath, workflowCode: declaredWorkflowCode, variant = 'desktop', } = {}) {
|
|
919
1044
|
const { workflowCode: routeWorkflowCode = '' } = useParams();
|
|
920
1045
|
const workflowCode = declaredWorkflowCode || routeWorkflowCode;
|
|
921
1046
|
const definition = useWorkflowDefinition(workflowCode);
|
|
@@ -931,13 +1056,40 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
931
1056
|
const [launchError, setLaunchError] = useState(null);
|
|
932
1057
|
const [processSurface, setProcessSurface] = useState(null);
|
|
933
1058
|
const [processError, setProcessError] = useState(null);
|
|
1059
|
+
const [completion, setCompletion] = useState(null);
|
|
1060
|
+
const submitInFlight = useRef(false);
|
|
934
1061
|
const pathCommandId = useParams().commandId;
|
|
935
1062
|
const commandId = pathCommandId || searchParams.get('processCommandId') || '';
|
|
936
1063
|
const subjectId = searchParams.get('subjectId') || '';
|
|
1064
|
+
const generatedNamedSubmission = definition?.launch.submission;
|
|
1065
|
+
const [submissionMode, setSubmissionMode] = useState(subjectId ? 'existing' : 'create');
|
|
937
1066
|
const subjectDefinition = definition
|
|
938
1067
|
? resources[definition.subject.resourceCode]
|
|
939
1068
|
: undefined;
|
|
940
|
-
|
|
1069
|
+
useEffect(() => {
|
|
1070
|
+
if (!generatedNamedSubmission)
|
|
1071
|
+
return;
|
|
1072
|
+
if (subjectId && generatedNamedSubmission.existing) {
|
|
1073
|
+
setSubmissionMode('existing');
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
if (submissionMode === 'create' && generatedNamedSubmission.create)
|
|
1077
|
+
return;
|
|
1078
|
+
if (submissionMode === 'existing' && generatedNamedSubmission.existing)
|
|
1079
|
+
return;
|
|
1080
|
+
setSubmissionMode(generatedNamedSubmission.create ? 'create' : 'existing');
|
|
1081
|
+
}, [generatedNamedSubmission, subjectId, submissionMode]);
|
|
1082
|
+
const surfaceNamedSubmission = launchSurface?.submission.kind === 'named-operation'
|
|
1083
|
+
? launchSurface.submission
|
|
1084
|
+
: undefined;
|
|
1085
|
+
const namedIntent = surfaceNamedSubmission?.[submissionMode];
|
|
1086
|
+
const mutationMode = generatedNamedSubmission
|
|
1087
|
+
? submissionMode === 'existing'
|
|
1088
|
+
? 'update'
|
|
1089
|
+
: 'create'
|
|
1090
|
+
: subjectId
|
|
1091
|
+
? 'update'
|
|
1092
|
+
: 'create';
|
|
941
1093
|
const fields = useMemo(() => {
|
|
942
1094
|
if (!subjectDefinition)
|
|
943
1095
|
return [];
|
|
@@ -955,6 +1107,9 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
955
1107
|
.filter((field) => Boolean(field))
|
|
956
1108
|
.filter(field => !field.system && field.widget !== 'readonly')
|
|
957
1109
|
.filter(field => {
|
|
1110
|
+
if (namedIntent) {
|
|
1111
|
+
return Object.values(namedIntent.inputs).some(binding => binding.source === 'field' && binding.fieldCode === field.key);
|
|
1112
|
+
}
|
|
958
1113
|
if (identity.isAppSuperAdmin)
|
|
959
1114
|
return true;
|
|
960
1115
|
const capabilities = mutationMode === 'create'
|
|
@@ -962,7 +1117,13 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
962
1117
|
: field.updateCapabilities;
|
|
963
1118
|
return capabilities.length > 0 && capabilities.every(hasCapability);
|
|
964
1119
|
});
|
|
965
|
-
}, [
|
|
1120
|
+
}, [
|
|
1121
|
+
hasCapability,
|
|
1122
|
+
identity.isAppSuperAdmin,
|
|
1123
|
+
mutationMode,
|
|
1124
|
+
namedIntent,
|
|
1125
|
+
subjectDefinition,
|
|
1126
|
+
]);
|
|
966
1127
|
useEffect(() => {
|
|
967
1128
|
let active = true;
|
|
968
1129
|
setLaunchSurface(null);
|
|
@@ -981,10 +1142,19 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
981
1142
|
const actualSummaryFields = [
|
|
982
1143
|
...(surface.subject.summaryFields || []),
|
|
983
1144
|
].sort();
|
|
1145
|
+
const generatedSubmission = definition?.launch.submission;
|
|
1146
|
+
const submissionMatches = generatedSubmission
|
|
1147
|
+
? surface.submission.kind === 'named-operation' &&
|
|
1148
|
+
namedLaunchIntentMatches(generatedSubmission.create, surface.submission.create) &&
|
|
1149
|
+
namedLaunchIntentMatches(generatedSubmission.existing, surface.submission.existing) &&
|
|
1150
|
+
sameJson(generatedSubmission.context || [], surface.submission.context)
|
|
1151
|
+
: surface.submission.kind === 'standard-process' &&
|
|
1152
|
+
surface.submission.processOperationCode ===
|
|
1153
|
+
definition?.processOperationCode;
|
|
984
1154
|
if (!definition ||
|
|
985
1155
|
surface.environmentKey !== identity.environment.key ||
|
|
986
1156
|
surface.environmentId !== identity.environment.id ||
|
|
987
|
-
|
|
1157
|
+
!submissionMatches ||
|
|
988
1158
|
surface.subject.resourceCode !== definition.subject.resourceCode ||
|
|
989
1159
|
JSON.stringify(actualProjection) !== JSON.stringify(expectedProjection) ||
|
|
990
1160
|
JSON.stringify(actualSummaryFields) !==
|
|
@@ -1003,7 +1173,10 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1003
1173
|
};
|
|
1004
1174
|
}, [commandId, definition, identity.environment.id, identity.environment.key, workflowCode]);
|
|
1005
1175
|
useEffect(() => {
|
|
1006
|
-
if (!subjectDefinition ||
|
|
1176
|
+
if (!subjectDefinition ||
|
|
1177
|
+
!subjectId ||
|
|
1178
|
+
commandId ||
|
|
1179
|
+
mutationMode !== 'update')
|
|
1007
1180
|
return;
|
|
1008
1181
|
let active = true;
|
|
1009
1182
|
const client = createNativeResourceClient(subjectDefinition.code, subjectDefinition.surface);
|
|
@@ -1021,7 +1194,56 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1021
1194
|
return () => {
|
|
1022
1195
|
active = false;
|
|
1023
1196
|
};
|
|
1024
|
-
}, [commandId, subjectDefinition, subjectForm, subjectId]);
|
|
1197
|
+
}, [commandId, mutationMode, subjectDefinition, subjectForm, subjectId]);
|
|
1198
|
+
useEffect(() => {
|
|
1199
|
+
if (!surfaceNamedSubmission ||
|
|
1200
|
+
!namedIntent ||
|
|
1201
|
+
!subjectDefinition ||
|
|
1202
|
+
commandId ||
|
|
1203
|
+
mutationMode !== 'create')
|
|
1204
|
+
return;
|
|
1205
|
+
const declaredFields = new Set(Object.values(namedIntent.inputs).flatMap(binding => binding.source === 'field' ? [binding.fieldCode] : []));
|
|
1206
|
+
const requested = surfaceNamedSubmission.context
|
|
1207
|
+
.map(context => ({
|
|
1208
|
+
...context,
|
|
1209
|
+
value: searchParams.get(context.queryParameter),
|
|
1210
|
+
}))
|
|
1211
|
+
.filter((context) => Boolean(context.value) && declaredFields.has(context.fieldCode));
|
|
1212
|
+
if (!requested.length)
|
|
1213
|
+
return;
|
|
1214
|
+
let active = true;
|
|
1215
|
+
void Promise.all(requested.map(async (context) => {
|
|
1216
|
+
const field = subjectDefinition.surface.fields[context.fieldCode];
|
|
1217
|
+
if (!field || field.system || field.widget === 'readonly') {
|
|
1218
|
+
throw new Error('OPENXIANGDA_WORKFLOW_LAUNCH_CONTEXT_FIELD_INVALID');
|
|
1219
|
+
}
|
|
1220
|
+
return [
|
|
1221
|
+
context.fieldCode,
|
|
1222
|
+
await workflowContextPrefillValue({ key: context.fieldCode, ...field }, context.value, resources),
|
|
1223
|
+
];
|
|
1224
|
+
}))
|
|
1225
|
+
.then(entries => {
|
|
1226
|
+
if (active)
|
|
1227
|
+
subjectForm.setFieldsValue(Object.fromEntries(entries));
|
|
1228
|
+
})
|
|
1229
|
+
.catch(error => {
|
|
1230
|
+
if (active) {
|
|
1231
|
+
setLaunchError(errorMessage(error, '上下文预填失败'));
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
return () => {
|
|
1235
|
+
active = false;
|
|
1236
|
+
};
|
|
1237
|
+
}, [
|
|
1238
|
+
commandId,
|
|
1239
|
+
mutationMode,
|
|
1240
|
+
namedIntent,
|
|
1241
|
+
resources,
|
|
1242
|
+
searchParams,
|
|
1243
|
+
subjectDefinition,
|
|
1244
|
+
subjectForm,
|
|
1245
|
+
surfaceNamedSubmission,
|
|
1246
|
+
]);
|
|
1025
1247
|
useEffect(() => {
|
|
1026
1248
|
if (!commandId) {
|
|
1027
1249
|
setProcessSurface(null);
|
|
@@ -1043,7 +1265,11 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1043
1265
|
setProcessSurface(next);
|
|
1044
1266
|
setProcessError(null);
|
|
1045
1267
|
if (next.command.status === 'started' && next.command.workflowInstanceId) {
|
|
1046
|
-
|
|
1268
|
+
if (!instancePath ||
|
|
1269
|
+
(instancePath.match(/:instanceId/g) || []).length !== 1) {
|
|
1270
|
+
throw new Error('OPENXIANGDA_WORKFLOW_INSTANCE_ROUTE_MISSING');
|
|
1271
|
+
}
|
|
1272
|
+
navigate(instancePath.replace(':instanceId', encodeURIComponent(next.command.workflowInstanceId)), { replace: true });
|
|
1047
1273
|
return;
|
|
1048
1274
|
}
|
|
1049
1275
|
if (['accepted', 'resolving', 'ready', 'starting', 'retry_wait'].includes(next.command.status)) {
|
|
@@ -1061,26 +1287,91 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1061
1287
|
if (timer)
|
|
1062
1288
|
clearTimeout(timer);
|
|
1063
1289
|
};
|
|
1064
|
-
}, [
|
|
1065
|
-
|
|
1290
|
+
}, [
|
|
1291
|
+
commandId,
|
|
1292
|
+
definition,
|
|
1293
|
+
identity.environment.key,
|
|
1294
|
+
instancePath,
|
|
1295
|
+
navigate,
|
|
1296
|
+
workflowCode,
|
|
1297
|
+
]);
|
|
1298
|
+
const frame = (content) => variant === 'desktop' ? (_jsx("div", { className: "oxa-workflow-desktop-page oxa-workflow-submission-standalone-page", children: content })) : content;
|
|
1066
1299
|
if (!definition)
|
|
1067
1300
|
return frame(_jsx(Result, { status: "404", title: "\u672A\u58F0\u660E\u8BE5\u5DE5\u4F5C\u6D41" }));
|
|
1068
1301
|
if (definition.launch.mode !== 'standalone' &&
|
|
1069
1302
|
definition.launch.mode !== 'hidden-handoff')
|
|
1070
1303
|
return frame(_jsx(Result, { status: "404", title: "\u8BE5\u5DE5\u4F5C\u6D41\u4E0D\u63D0\u4F9B\u6807\u51C6\u53D1\u8D77\u9875\u9762" }));
|
|
1071
|
-
if (!
|
|
1304
|
+
if (!subjectDefinition)
|
|
1072
1305
|
return frame(_jsx(Result, { status: "500", title: "\u6807\u51C6\u6D41\u7A0B\u5408\u540C\u4E0D\u5B8C\u6574" }));
|
|
1073
1306
|
if (launchError && !commandId)
|
|
1074
1307
|
return frame(_jsx(Result, { status: "error", title: "\u53D1\u8D77\u9875\u9762\u5F53\u524D\u4E0D\u53EF\u7528", subTitle: launchError }));
|
|
1075
1308
|
if (!launchSurface && !commandId)
|
|
1076
1309
|
return frame(_jsx(Spin, { className: "oxa-workflow-launch-loading", size: "large" }));
|
|
1310
|
+
if (!commandId &&
|
|
1311
|
+
generatedNamedSubmission &&
|
|
1312
|
+
(!surfaceNamedSubmission || !namedIntent)) {
|
|
1313
|
+
return frame(_jsx(Result, { status: "500", title: "Named Action \u63D0\u4EA4\u5408\u540C\u4E0D\u5B8C\u6574" }));
|
|
1314
|
+
}
|
|
1315
|
+
if (!commandId &&
|
|
1316
|
+
!generatedNamedSubmission &&
|
|
1317
|
+
(!definition.processOperationCode ||
|
|
1318
|
+
launchSurface?.submission.kind !== 'standard-process')) {
|
|
1319
|
+
return frame(_jsx(Result, { status: "500", title: "\u6807\u51C6\u6D41\u7A0B\u5408\u540C\u4E0D\u5B8C\u6574" }));
|
|
1320
|
+
}
|
|
1077
1321
|
if (!commandId && fields.some(field => field.type === 'subtable')) {
|
|
1078
|
-
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: "\
|
|
1322
|
+
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" }));
|
|
1079
1323
|
}
|
|
1080
1324
|
const submit = async (values) => {
|
|
1325
|
+
if (submitInFlight.current)
|
|
1326
|
+
return;
|
|
1327
|
+
submitInFlight.current = true;
|
|
1081
1328
|
setLoading(true);
|
|
1082
1329
|
try {
|
|
1083
1330
|
const data = normalizeFormValues(values, subjectDefinition.surface);
|
|
1331
|
+
if (namedIntent && launchSurface) {
|
|
1332
|
+
let subject;
|
|
1333
|
+
if (submissionMode === 'existing') {
|
|
1334
|
+
if (!subjectId) {
|
|
1335
|
+
throw new Error('OPENXIANGDA_WORKFLOW_EXISTING_SUBJECT_REQUIRED');
|
|
1336
|
+
}
|
|
1337
|
+
const current = await createNativeResourceClient(subjectDefinition.code, subjectDefinition.surface).get(subjectId);
|
|
1338
|
+
const revision = Number(current.revision);
|
|
1339
|
+
if (!Number.isSafeInteger(revision) || revision < 1) {
|
|
1340
|
+
throw new Error('OPENXIANGDA_WORKFLOW_EXISTING_SUBJECT_REVISION_REQUIRED');
|
|
1341
|
+
}
|
|
1342
|
+
subject = { id: subjectId, revision };
|
|
1343
|
+
}
|
|
1344
|
+
const response = await executeWorkflowLaunchNamedOperation(namedIntent, buildWorkflowNamedOperationInput(namedIntent, {
|
|
1345
|
+
values: data,
|
|
1346
|
+
idempotencyKey: randomId(`workflow-action:${workflowCode}`),
|
|
1347
|
+
requestedAt: new Date().toISOString(),
|
|
1348
|
+
subjectProfile: identity.subjectProfile,
|
|
1349
|
+
...(subject ? { subject } : {}),
|
|
1350
|
+
}));
|
|
1351
|
+
const outcome = parseWorkflowNamedOperationResult(namedIntent, response, {
|
|
1352
|
+
appCode: launchSurface.appCode,
|
|
1353
|
+
environmentKey: launchSurface.environmentKey,
|
|
1354
|
+
workflowCode,
|
|
1355
|
+
resourceCode: subjectDefinition.code,
|
|
1356
|
+
});
|
|
1357
|
+
if (outcome.kind === 'workflow-command') {
|
|
1358
|
+
const next = new URLSearchParams(searchParams);
|
|
1359
|
+
next.set('processCommandId', outcome.command.id);
|
|
1360
|
+
next.delete('subjectId');
|
|
1361
|
+
setSearchParams(next, { replace: true });
|
|
1362
|
+
message.success(outcome.command.replayed ? '已恢复原提交命令' : '提交命令已受理');
|
|
1363
|
+
}
|
|
1364
|
+
else {
|
|
1365
|
+
setCompletion({
|
|
1366
|
+
subjectId: outcome.subjectId,
|
|
1367
|
+
...(outcome.subjectRevision
|
|
1368
|
+
? { subjectRevision: outcome.subjectRevision }
|
|
1369
|
+
: {}),
|
|
1370
|
+
});
|
|
1371
|
+
message.success('业务提交成功,无需审批');
|
|
1372
|
+
}
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1084
1375
|
let mutation;
|
|
1085
1376
|
if (subjectId) {
|
|
1086
1377
|
const current = await createNativeResourceClient(subjectDefinition.code, subjectDefinition.surface).get(subjectId);
|
|
@@ -1114,6 +1405,7 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1114
1405
|
message.error(errorMessage(error, '业务与流程命令提交失败'));
|
|
1115
1406
|
}
|
|
1116
1407
|
finally {
|
|
1408
|
+
submitInFlight.current = false;
|
|
1117
1409
|
setLoading(false);
|
|
1118
1410
|
}
|
|
1119
1411
|
};
|
|
@@ -1153,9 +1445,53 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1153
1445
|
setLoading(false);
|
|
1154
1446
|
}
|
|
1155
1447
|
};
|
|
1448
|
+
const selectMode = (nextMode) => {
|
|
1449
|
+
if (!generatedNamedSubmission?.[nextMode])
|
|
1450
|
+
return;
|
|
1451
|
+
setSubmissionMode(nextMode);
|
|
1452
|
+
setCompletion(null);
|
|
1453
|
+
subjectForm.resetFields();
|
|
1454
|
+
const next = new URLSearchParams(searchParams);
|
|
1455
|
+
next.delete('processCommandId');
|
|
1456
|
+
if (nextMode === 'create')
|
|
1457
|
+
next.delete('subjectId');
|
|
1458
|
+
setSearchParams(next, { replace: true });
|
|
1459
|
+
};
|
|
1460
|
+
const selectSubject = (nextSubjectId) => {
|
|
1461
|
+
setCompletion(null);
|
|
1462
|
+
subjectForm.resetFields();
|
|
1463
|
+
const next = new URLSearchParams(searchParams);
|
|
1464
|
+
next.delete('processCommandId');
|
|
1465
|
+
if (nextSubjectId)
|
|
1466
|
+
next.set('subjectId', nextSubjectId);
|
|
1467
|
+
else
|
|
1468
|
+
next.delete('subjectId');
|
|
1469
|
+
setSearchParams(next, { replace: true });
|
|
1470
|
+
};
|
|
1471
|
+
const launchControls = generatedNamedSubmission ? (_jsxs(Space, { direction: "vertical", size: "middle", style: { width: '100%' }, children: [generatedNamedSubmission.create && generatedNamedSubmission.existing ? (_jsx(Segmented, { onChange: value => selectMode(value), options: [
|
|
1472
|
+
{ label: '新建并提交', value: 'create' },
|
|
1473
|
+
{ label: '选择已有记录', value: 'existing' },
|
|
1474
|
+
], value: submissionMode })) : null, submissionMode === 'existing' && subjectDefinition ? (_jsx(SubjectRecordSelector, { definition: subjectDefinition, onChange: selectSubject, value: subjectId })) : null] })) : null;
|
|
1475
|
+
const fieldRenderers = namedIntent
|
|
1476
|
+
? {
|
|
1477
|
+
upload: async (field, file) => await uploadOperationManagedFile({
|
|
1478
|
+
operationCode: namedIntent.operationCode,
|
|
1479
|
+
resourceCode: subjectDefinition.code,
|
|
1480
|
+
fieldCode: field.key,
|
|
1481
|
+
intent: submissionMode === 'existing' ? 'update' : 'create',
|
|
1482
|
+
file,
|
|
1483
|
+
...(submissionMode === 'existing' && subjectId
|
|
1484
|
+
? { recordId: subjectId }
|
|
1485
|
+
: {}),
|
|
1486
|
+
}),
|
|
1487
|
+
}
|
|
1488
|
+
: undefined;
|
|
1156
1489
|
const shared = {
|
|
1157
1490
|
title: launchSurface?.title || definition.title,
|
|
1158
|
-
description: definition.description ||
|
|
1491
|
+
description: definition.description ||
|
|
1492
|
+
(namedIntent
|
|
1493
|
+
? '业务操作将在服务端完成校验、幂等提交,并按规则决定是否进入审批'
|
|
1494
|
+
: '业务数据和流程发起意图将原子提交'),
|
|
1159
1495
|
fields,
|
|
1160
1496
|
subjectDefinition,
|
|
1161
1497
|
subjectForm,
|
|
@@ -1164,6 +1500,10 @@ export function WorkflowSubmissionPage({ workflowCode: declaredWorkflowCode, var
|
|
|
1164
1500
|
processError,
|
|
1165
1501
|
loading,
|
|
1166
1502
|
mutationMode,
|
|
1503
|
+
launchControls,
|
|
1504
|
+
completion,
|
|
1505
|
+
fieldRenderers,
|
|
1506
|
+
recordId: mutationMode === 'update' ? subjectId : undefined,
|
|
1167
1507
|
onBack: () => navigate(-1),
|
|
1168
1508
|
onSubmit: submit,
|
|
1169
1509
|
onAnswer: answer,
|
|
@@ -1180,15 +1520,21 @@ function ProcessCommandPanel({ form, surface, error, loading, onAnswer, onRetry,
|
|
|
1180
1520
|
return (_jsxs(Card, { title: `提交状态 · ${command.status}`, children: [command.lastError ? (_jsx(Alert, { description: command.lastError.preview, message: command.lastError.code, showIcon: true, type: "error" })) : null, command.status === 'awaiting_input' ? (_jsxs(Form, { form: form, layout: "vertical", onFinish: values => void onAnswer(values), children: [_jsx(RequirementFields, { requirements: surface.requirements }), _jsx(Button, { htmlType: "submit", loading: loading, type: "primary", children: "\u63D0\u4EA4\u8865\u5145\u4FE1\u606F" })] })) : null, surface.resume.retry ? (_jsx(Button, { loading: loading, onClick: () => void onRetry(), children: "\u91CD\u8BD5\u539F\u547D\u4EE4" })) : null, ['cancelled', 'dead_letter'].includes(command.status) ? (_jsx(Result, { status: "error", title: "\u6D41\u7A0B\u672A\u53D1\u8D77", subTitle: "\u4E1A\u52A1\u6570\u636E\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u6309\u547D\u4EE4\u72B6\u6001\u5904\u7406\u3002" })) : null, !['awaiting_input', 'cancelled', 'dead_letter'].includes(command.status) ? (_jsx(Typography.Text, { type: "secondary", children: "\u547D\u4EE4\u53EF\u5B89\u5168\u6062\u590D\uFF0C\u9875\u9762\u4F1A\u6309 commandId \u81EA\u52A8\u5237\u65B0\u3002" })) : null] }));
|
|
1181
1521
|
}
|
|
1182
1522
|
function DesktopProcessSubmissionRenderer(props) {
|
|
1523
|
+
if (props.completion) {
|
|
1524
|
+
return (_jsx("div", { className: "oxa-workflow-submission oxa-workflow-submission-desktop", children: _jsx(Result, { extra: _jsx(Button, { onClick: props.onBack, children: "\u8FD4\u56DE" }), status: "success", subTitle: `业务记录 ${props.completion.subjectId} 已提交,本次无需进入审批流程。`, title: "\u4E1A\u52A1\u63D0\u4EA4\u6210\u529F" }) }));
|
|
1525
|
+
}
|
|
1183
1526
|
if (props.processSurface || props.processError) {
|
|
1184
1527
|
return (_jsx("div", { className: "oxa-workflow-submission oxa-workflow-submission-desktop", children: _jsx(ProcessCommandPanel, { error: props.processError, form: props.requirementForm, loading: props.loading, onAnswer: props.onAnswer, onRetry: props.onRetry, surface: props.processSurface }) }));
|
|
1185
1528
|
}
|
|
1186
|
-
return (_jsx("div", { className: "oxa-workflow-submission oxa-workflow-submission-desktop", children: _jsxs(Card, { children: [_jsx(Typography.Title, { level: 2, children: props.title }), _jsx(Typography.Text, { type: "secondary", children: props.description }), _jsxs(Form, { form: props.subjectForm, layout: "vertical", onFinish: values => void props.onSubmit(values), children: [_jsx("div", { className: "oxa-grid", children: props.fields.map(field => (_jsx(SurfaceFieldControl, { disabled: false, field: field, operation: props.mutationMode === 'update' ? 'update' : 'create', resourceCode: props.subjectDefinition.code }, field.key))) }), _jsxs(Space, { children: [_jsx(Button, { icon: _jsx(ArrowLeftOutlined, {}), onClick: props.onBack, children: "\u8FD4\u56DE" }), _jsx(Button, { htmlType: "submit", loading: props.loading, type: "primary", children: "\u63D0\u4EA4\u5BA1\u6279" })] })] })] }) }));
|
|
1529
|
+
return (_jsx("div", { className: "oxa-workflow-submission oxa-workflow-submission-desktop", children: _jsxs(Card, { children: [_jsx(Typography.Title, { level: 2, children: props.title }), _jsx(Typography.Text, { type: "secondary", children: props.description }), props.launchControls, _jsxs(Form, { form: props.subjectForm, layout: "vertical", onFinish: values => void props.onSubmit(values), children: [_jsx("div", { className: "oxa-grid", children: props.fields.map(field => (_jsx(SurfaceFieldControl, { disabled: false, field: field, operation: props.mutationMode === 'update' ? 'update' : 'create', recordId: props.recordId, renderers: props.fieldRenderers, resourceCode: props.subjectDefinition.code }, field.key))) }), _jsxs(Space, { children: [_jsx(Button, { icon: _jsx(ArrowLeftOutlined, {}), onClick: props.onBack, children: "\u8FD4\u56DE" }), _jsx(Button, { htmlType: "submit", loading: props.loading, type: "primary", children: "\u63D0\u4EA4\u5BA1\u6279" })] })] })] }) }));
|
|
1187
1530
|
}
|
|
1188
1531
|
function MobileProcessSubmissionRenderer(props) {
|
|
1532
|
+
if (props.completion) {
|
|
1533
|
+
return (_jsx("div", { className: "oxa-mobile-page", children: _jsx(Result, { extra: _jsx(Button, { onClick: props.onBack, children: "\u8FD4\u56DE" }), status: "success", subTitle: `业务记录 ${props.completion.subjectId} 已提交,本次无需进入审批流程。`, title: "\u4E1A\u52A1\u63D0\u4EA4\u6210\u529F" }) }));
|
|
1534
|
+
}
|
|
1189
1535
|
if (props.processSurface || props.processError) {
|
|
1190
1536
|
return (_jsx("div", { className: "oxa-mobile-page", children: _jsx(ProcessCommandPanel, { error: props.processError, form: props.requirementForm, loading: props.loading, onAnswer: props.onAnswer, onRetry: props.onRetry, surface: props.processSurface }) }));
|
|
1191
1537
|
}
|
|
1192
|
-
return (_jsxs("div", { className: "oxa-mobile-page oxa-workflow-submission-mobile", children: [_jsx(Typography.Title, { level: 3, children: props.title }), _jsx(Typography.Text, { type: "secondary", children: props.description }), _jsxs(Form, { className: "oxa-mobile-form", form: props.subjectForm, layout: "vertical", onFinish: values => void props.onSubmit(values), children: [props.fields.map(field => (_jsx(MobileSurfaceFieldControl, { disabled: false, field: field, operation: props.mutationMode === 'update' ? 'update' : 'create', resourceCode: props.subjectDefinition.code }, field.key))), _jsx(Button, { block: true, htmlType: "submit", loading: props.loading, type: "primary", children: "\u63D0\u4EA4\u5BA1\u6279" })] })] }));
|
|
1538
|
+
return (_jsxs("div", { className: "oxa-mobile-page oxa-workflow-submission-mobile", children: [_jsx(Typography.Title, { level: 3, children: props.title }), _jsx(Typography.Text, { type: "secondary", children: props.description }), props.launchControls, _jsxs(Form, { className: "oxa-mobile-form", form: props.subjectForm, layout: "vertical", onFinish: values => void props.onSubmit(values), children: [props.fields.map(field => (_jsx(MobileSurfaceFieldControl, { disabled: false, field: field, operation: props.mutationMode === 'update' ? 'update' : 'create', recordId: props.recordId, renderers: props.fieldRenderers, resourceCode: props.subjectDefinition.code }, field.key))), _jsx(Button, { block: true, htmlType: "submit", loading: props.loading, type: "primary", children: "\u63D0\u4EA4\u5BA1\u6279" })] })] }));
|
|
1193
1539
|
}
|
|
1194
1540
|
//# sourceMappingURL=StandardWorkflowPages.js.map
|