sy-form-components 0.2.0 → 0.2.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.
- package/README.md +5 -5
- package/dist/index.d.mts +537 -1
- package/dist/index.d.ts +537 -1
- package/dist/index.js +2229 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2192 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4036,7 +4036,7 @@ function FormProvider({
|
|
|
4036
4036
|
});
|
|
4037
4037
|
}, []);
|
|
4038
4038
|
const getFieldValue = useCallback((fieldId) => formData[fieldId], [formData]);
|
|
4039
|
-
const
|
|
4039
|
+
const getFormData2 = useCallback(() => ({ ...formData }), [formData]);
|
|
4040
4040
|
const validateFieldById = useCallback(
|
|
4041
4041
|
async (fieldId) => {
|
|
4042
4042
|
const field = schema.fields.find((f) => f.fieldId === fieldId);
|
|
@@ -4113,7 +4113,7 @@ function FormProvider({
|
|
|
4113
4113
|
},
|
|
4114
4114
|
setFieldValue,
|
|
4115
4115
|
getFieldValue,
|
|
4116
|
-
getFormData,
|
|
4116
|
+
getFormData: getFormData2,
|
|
4117
4117
|
validateField: validateFieldById,
|
|
4118
4118
|
validateAll,
|
|
4119
4119
|
resetForm,
|
|
@@ -4133,7 +4133,7 @@ function FormProvider({
|
|
|
4133
4133
|
config.submit,
|
|
4134
4134
|
setFieldValue,
|
|
4135
4135
|
getFieldValue,
|
|
4136
|
-
|
|
4136
|
+
getFormData2,
|
|
4137
4137
|
validateFieldById,
|
|
4138
4138
|
validateAll,
|
|
4139
4139
|
resetForm,
|
|
@@ -4204,14 +4204,14 @@ function FormActions({
|
|
|
4204
4204
|
showReset = true,
|
|
4205
4205
|
onSubmit
|
|
4206
4206
|
}) {
|
|
4207
|
-
const { mode, validateAll, getFormData, resetForm, api, config } = useFormContext();
|
|
4207
|
+
const { mode, validateAll, getFormData: getFormData2, resetForm, api, config } = useFormContext();
|
|
4208
4208
|
const [isSubmitting, setIsSubmitting] = useState13(false);
|
|
4209
4209
|
const [submitError, setSubmitError] = useState13(null);
|
|
4210
4210
|
const handleSubmit = useCallback2(async () => {
|
|
4211
4211
|
setSubmitError(null);
|
|
4212
4212
|
const valid = await validateAll();
|
|
4213
4213
|
if (!valid) return;
|
|
4214
|
-
const values =
|
|
4214
|
+
const values = getFormData2();
|
|
4215
4215
|
setIsSubmitting(true);
|
|
4216
4216
|
try {
|
|
4217
4217
|
const beforeResult = await config.submit?.beforeSubmit?.(values);
|
|
@@ -4242,7 +4242,7 @@ function FormActions({
|
|
|
4242
4242
|
} finally {
|
|
4243
4243
|
setIsSubmitting(false);
|
|
4244
4244
|
}
|
|
4245
|
-
}, [api, config,
|
|
4245
|
+
}, [api, config, getFormData2, mode, onSubmit, validateAll]);
|
|
4246
4246
|
const handleReset = useCallback2(() => {
|
|
4247
4247
|
resetForm();
|
|
4248
4248
|
}, [resetForm]);
|
|
@@ -4302,6 +4302,160 @@ function FormContainer({
|
|
|
4302
4302
|
] });
|
|
4303
4303
|
}
|
|
4304
4304
|
|
|
4305
|
+
// src/core/constants.ts
|
|
4306
|
+
var PROCESS_STATUS_META = {
|
|
4307
|
+
running: { label: "\u5BA1\u6279\u4E2D", tone: "brand" },
|
|
4308
|
+
waiting: { label: "\u7B49\u5F85\u4E2D", tone: "neutral" },
|
|
4309
|
+
exception: { label: "\u6D41\u7A0B\u5F02\u5E38", tone: "danger" },
|
|
4310
|
+
completed: { label: "\u5DF2\u5B8C\u6210", tone: "success" },
|
|
4311
|
+
terminated: { label: "\u5DF2\u62D2\u7EDD", tone: "danger" },
|
|
4312
|
+
withdrawn: { label: "\u5DF2\u64A4\u9500", tone: "neutral" },
|
|
4313
|
+
pending: { label: "\u5F85\u5904\u7406", tone: "brand" },
|
|
4314
|
+
cancelled: { label: "\u5DF2\u53D6\u6D88", tone: "neutral" }
|
|
4315
|
+
};
|
|
4316
|
+
var TASK_STATUS_META = {
|
|
4317
|
+
pending: { label: "\u5F85\u5904\u7406", tone: "brand" },
|
|
4318
|
+
approved: { label: "\u5DF2\u540C\u610F", tone: "success" },
|
|
4319
|
+
rejected: { label: "\u5DF2\u62D2\u7EDD", tone: "danger" },
|
|
4320
|
+
returned: { label: "\u5DF2\u9000\u56DE", tone: "warning" },
|
|
4321
|
+
suspended: { label: "\u5DF2\u6302\u8D77", tone: "neutral" },
|
|
4322
|
+
cancelled: { label: "\u5DF2\u53D6\u6D88", tone: "neutral" },
|
|
4323
|
+
copied: { label: "\u5DF2\u6284\u9001", tone: "neutral" },
|
|
4324
|
+
waiting: { label: "\u7B49\u5F85\u4E2D", tone: "neutral" },
|
|
4325
|
+
simulated: { label: "\u672A\u5F00\u59CB", tone: "neutral" }
|
|
4326
|
+
};
|
|
4327
|
+
|
|
4328
|
+
// src/core/processApi.ts
|
|
4329
|
+
async function getProcessBasic(request, formInstId) {
|
|
4330
|
+
const response = await request({
|
|
4331
|
+
url: `/workflow/instance/${formInstId}/basic`,
|
|
4332
|
+
method: "get"
|
|
4333
|
+
});
|
|
4334
|
+
return response.data || response.result;
|
|
4335
|
+
}
|
|
4336
|
+
async function getProcessProgress(request, formInstId) {
|
|
4337
|
+
const response = await request({
|
|
4338
|
+
url: `/workflow/instance/${formInstId}`,
|
|
4339
|
+
method: "get"
|
|
4340
|
+
});
|
|
4341
|
+
return response.data || response.result || [];
|
|
4342
|
+
}
|
|
4343
|
+
async function checkUserApproval(request, formInstId) {
|
|
4344
|
+
const response = await request({
|
|
4345
|
+
url: `/workflow/instance/${formInstId}/permission`,
|
|
4346
|
+
method: "get"
|
|
4347
|
+
});
|
|
4348
|
+
return response.data || response.result;
|
|
4349
|
+
}
|
|
4350
|
+
async function handleApproval(request, params) {
|
|
4351
|
+
const response = await request({
|
|
4352
|
+
url: "/workflow/approve",
|
|
4353
|
+
method: "post",
|
|
4354
|
+
data: params
|
|
4355
|
+
});
|
|
4356
|
+
return response.data || response.result;
|
|
4357
|
+
}
|
|
4358
|
+
async function withdrawProcess(request, params) {
|
|
4359
|
+
const response = await request({
|
|
4360
|
+
url: `/workflow/instance/${params.instanceId}/withdraw`,
|
|
4361
|
+
method: "put",
|
|
4362
|
+
data: { reason: params.reason }
|
|
4363
|
+
});
|
|
4364
|
+
return response.data || response.result;
|
|
4365
|
+
}
|
|
4366
|
+
async function transferTask(request, params) {
|
|
4367
|
+
const response = await request({
|
|
4368
|
+
url: `/workflow/task/${params.taskId}/transfer`,
|
|
4369
|
+
method: "put",
|
|
4370
|
+
data: { newAssignee: params.newAssignee, reason: params.reason }
|
|
4371
|
+
});
|
|
4372
|
+
return response.data || response.result;
|
|
4373
|
+
}
|
|
4374
|
+
async function returnTask(request, params) {
|
|
4375
|
+
const response = await request({
|
|
4376
|
+
url: `/workflow/task/${params.taskId}/return`,
|
|
4377
|
+
method: "put",
|
|
4378
|
+
data: { targetNodeId: params.targetNodeId, reason: params.reason }
|
|
4379
|
+
});
|
|
4380
|
+
return response.data || response.result;
|
|
4381
|
+
}
|
|
4382
|
+
async function resubmitTask(request, params) {
|
|
4383
|
+
const response = await request({
|
|
4384
|
+
url: `/workflow/task/${params.taskId}/resubmit`,
|
|
4385
|
+
method: "post",
|
|
4386
|
+
data: {
|
|
4387
|
+
formUuid: params.formUuid,
|
|
4388
|
+
appType: params.appType,
|
|
4389
|
+
updateFormDataJson: params.updateFormDataJson,
|
|
4390
|
+
comments: params.comments
|
|
4391
|
+
}
|
|
4392
|
+
});
|
|
4393
|
+
return response.data || response.result;
|
|
4394
|
+
}
|
|
4395
|
+
async function saveTask(request, params) {
|
|
4396
|
+
const response = await request({
|
|
4397
|
+
url: "/workflow/task/save",
|
|
4398
|
+
method: "post",
|
|
4399
|
+
data: params
|
|
4400
|
+
});
|
|
4401
|
+
return response.data || response.result;
|
|
4402
|
+
}
|
|
4403
|
+
async function getReturnableNodes(request, taskId) {
|
|
4404
|
+
const response = await request({
|
|
4405
|
+
url: `/workflow/task/${taskId}/returnable-nodes`,
|
|
4406
|
+
method: "get"
|
|
4407
|
+
});
|
|
4408
|
+
return response.data || response.result || [];
|
|
4409
|
+
}
|
|
4410
|
+
async function previewProcess(request, params) {
|
|
4411
|
+
const response = await request({
|
|
4412
|
+
url: "/workflow/preview",
|
|
4413
|
+
method: "post",
|
|
4414
|
+
data: params
|
|
4415
|
+
});
|
|
4416
|
+
return response.data || response.result || [];
|
|
4417
|
+
}
|
|
4418
|
+
async function getProcessDefinition(request, formUuid) {
|
|
4419
|
+
const response = await request({
|
|
4420
|
+
url: "/workflow/definition/form",
|
|
4421
|
+
method: "get",
|
|
4422
|
+
params: { formUuid }
|
|
4423
|
+
});
|
|
4424
|
+
return response.data || response.result;
|
|
4425
|
+
}
|
|
4426
|
+
async function getFormData(request, params) {
|
|
4427
|
+
const response = await request({
|
|
4428
|
+
url: "/form/queryFormDataByFormInstanceId",
|
|
4429
|
+
method: "get",
|
|
4430
|
+
params
|
|
4431
|
+
});
|
|
4432
|
+
return response.data || response.result;
|
|
4433
|
+
}
|
|
4434
|
+
async function deleteFormData(request, params) {
|
|
4435
|
+
const response = await request({
|
|
4436
|
+
url: `/${params.appType}/v1/form/deleteFormData.json`,
|
|
4437
|
+
method: "post",
|
|
4438
|
+
data: params
|
|
4439
|
+
});
|
|
4440
|
+
return response.data || response.result;
|
|
4441
|
+
}
|
|
4442
|
+
async function getChangeRecords(request, params) {
|
|
4443
|
+
const response = await request({
|
|
4444
|
+
url: "/form/getFormDataChangeRecords",
|
|
4445
|
+
method: "get",
|
|
4446
|
+
params
|
|
4447
|
+
});
|
|
4448
|
+
return response.data || response.result;
|
|
4449
|
+
}
|
|
4450
|
+
async function getViewPermission(request, params) {
|
|
4451
|
+
const response = await request({
|
|
4452
|
+
url: "/permission/form-group/view-permissions",
|
|
4453
|
+
method: "get",
|
|
4454
|
+
params
|
|
4455
|
+
});
|
|
4456
|
+
return response.data || response.result;
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4305
4459
|
// src/layout/FormSection/index.tsx
|
|
4306
4460
|
import { useState as useState14 } from "react";
|
|
4307
4461
|
import { jsx as jsx70, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
@@ -4502,7 +4656,7 @@ function FormSummary({
|
|
|
4502
4656
|
const { schema, formData } = useFormContext();
|
|
4503
4657
|
const displayFields = fields ? schema.fields.filter((f) => fields.includes(f.fieldId)) : schema.fields;
|
|
4504
4658
|
const colClass = columnClasses2[columns];
|
|
4505
|
-
const
|
|
4659
|
+
const formatValue2 = (value) => {
|
|
4506
4660
|
if (value === null || value === void 0 || value === "") return "--";
|
|
4507
4661
|
if (Array.isArray(value)) {
|
|
4508
4662
|
if (value.length === 0) return "--";
|
|
@@ -4518,7 +4672,7 @@ function FormSummary({
|
|
|
4518
4672
|
"data-testid": `summary-field-${field.fieldId}`,
|
|
4519
4673
|
children: [
|
|
4520
4674
|
/* @__PURE__ */ jsx74("span", { className: labelClassName ?? "text-sm text-gray-500 mb-1", children: field.label }),
|
|
4521
|
-
/* @__PURE__ */ jsx74("span", { className: valueClassName ?? "text-sm text-gray-900", children:
|
|
4675
|
+
/* @__PURE__ */ jsx74("span", { className: valueClassName ?? "text-sm text-gray-900", children: formatValue2(formData[field.fieldId]) })
|
|
4522
4676
|
]
|
|
4523
4677
|
},
|
|
4524
4678
|
field.fieldId
|
|
@@ -4575,7 +4729,7 @@ function useFormEngine(schema, config) {
|
|
|
4575
4729
|
});
|
|
4576
4730
|
}, []);
|
|
4577
4731
|
const getFieldValue = useCallback3((fieldId) => formData[fieldId], [formData]);
|
|
4578
|
-
const
|
|
4732
|
+
const getFormData2 = useCallback3(() => ({ ...formData }), [formData]);
|
|
4579
4733
|
const validateAll = useCallback3(async () => {
|
|
4580
4734
|
const fieldRules = {};
|
|
4581
4735
|
for (const field of schema.fields) {
|
|
@@ -4602,7 +4756,7 @@ function useFormEngine(schema, config) {
|
|
|
4602
4756
|
formData,
|
|
4603
4757
|
setFieldValue,
|
|
4604
4758
|
getFieldValue,
|
|
4605
|
-
getFormData,
|
|
4759
|
+
getFormData: getFormData2,
|
|
4606
4760
|
validateAll,
|
|
4607
4761
|
resetForm,
|
|
4608
4762
|
mode: config.mode,
|
|
@@ -4631,7 +4785,7 @@ function useFormData(initialValues = {}) {
|
|
|
4631
4785
|
},
|
|
4632
4786
|
[formData]
|
|
4633
4787
|
);
|
|
4634
|
-
const
|
|
4788
|
+
const getFormData2 = useCallback4(() => {
|
|
4635
4789
|
return { ...formData };
|
|
4636
4790
|
}, [formData]);
|
|
4637
4791
|
const resetForm = useCallback4(() => {
|
|
@@ -4642,7 +4796,7 @@ function useFormData(initialValues = {}) {
|
|
|
4642
4796
|
formData,
|
|
4643
4797
|
setFieldValue,
|
|
4644
4798
|
getFieldValue,
|
|
4645
|
-
getFormData,
|
|
4799
|
+
getFormData: getFormData2,
|
|
4646
4800
|
resetForm,
|
|
4647
4801
|
dirtyFields
|
|
4648
4802
|
};
|
|
@@ -4706,60 +4860,2085 @@ function useFormSubmit(config) {
|
|
|
4706
4860
|
return { submit, isSubmitting, submitError };
|
|
4707
4861
|
}
|
|
4708
4862
|
|
|
4863
|
+
// src/hooks/useFieldPermission.ts
|
|
4864
|
+
import { useMemo as useMemo7, useCallback as useCallback6 } from "react";
|
|
4865
|
+
function useFieldPermission(options) {
|
|
4866
|
+
const { viewPermissions, processDefinition, currentTask, isApprover, mode } = options;
|
|
4867
|
+
const computeBehaviors = useCallback6(() => {
|
|
4868
|
+
const behaviors = {};
|
|
4869
|
+
if (!currentTask && viewPermissions) {
|
|
4870
|
+
const { fieldPermissions } = viewPermissions;
|
|
4871
|
+
for (const [fieldId, perm] of Object.entries(fieldPermissions)) {
|
|
4872
|
+
if (perm === "FORM_FILED_HIDDEN") {
|
|
4873
|
+
behaviors[fieldId] = "HIDDEN";
|
|
4874
|
+
} else if (perm === "FORM_FILED_VIEW") {
|
|
4875
|
+
behaviors[fieldId] = "READONLY";
|
|
4876
|
+
} else if (perm === "FORM_FILED_EDIT") {
|
|
4877
|
+
behaviors[fieldId] = mode === "edit" ? "NORMAL" : "READONLY";
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
return behaviors;
|
|
4881
|
+
}
|
|
4882
|
+
if (currentTask && !isApprover && viewPermissions) {
|
|
4883
|
+
const { fieldPermissions } = viewPermissions;
|
|
4884
|
+
for (const [fieldId, perm] of Object.entries(fieldPermissions)) {
|
|
4885
|
+
if (perm === "FORM_FILED_HIDDEN") {
|
|
4886
|
+
behaviors[fieldId] = "HIDDEN";
|
|
4887
|
+
} else {
|
|
4888
|
+
behaviors[fieldId] = "READONLY";
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
return behaviors;
|
|
4892
|
+
}
|
|
4893
|
+
if (currentTask && isApprover && currentTask.nodeType === "originator_return") {
|
|
4894
|
+
if (processDefinition?.flowConfig && processDefinition.startNodeId) {
|
|
4895
|
+
const startConfig = processDefinition.flowConfig[processDefinition.startNodeId];
|
|
4896
|
+
if (startConfig) {
|
|
4897
|
+
for (const [fieldId, behavior] of Object.entries(startConfig)) {
|
|
4898
|
+
behaviors[fieldId] = mode === "edit" ? behavior : "READONLY";
|
|
4899
|
+
}
|
|
4900
|
+
return behaviors;
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4903
|
+
if (viewPermissions) {
|
|
4904
|
+
for (const fieldId of Object.keys(viewPermissions.fieldPermissions)) {
|
|
4905
|
+
if (viewPermissions.fieldPermissions[fieldId] === "FORM_FILED_HIDDEN") {
|
|
4906
|
+
behaviors[fieldId] = "HIDDEN";
|
|
4907
|
+
} else {
|
|
4908
|
+
behaviors[fieldId] = mode === "edit" ? "NORMAL" : "READONLY";
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
return behaviors;
|
|
4913
|
+
}
|
|
4914
|
+
if (currentTask && isApprover && processDefinition?.flowConfig) {
|
|
4915
|
+
const nodeConfig = processDefinition.flowConfig[currentTask.nodeId];
|
|
4916
|
+
if (nodeConfig) {
|
|
4917
|
+
for (const [fieldId, behavior] of Object.entries(nodeConfig)) {
|
|
4918
|
+
behaviors[fieldId] = mode === "edit" ? behavior : "READONLY";
|
|
4919
|
+
}
|
|
4920
|
+
return behaviors;
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
if (viewPermissions) {
|
|
4924
|
+
const { fieldPermissions } = viewPermissions;
|
|
4925
|
+
for (const [fieldId, perm] of Object.entries(fieldPermissions)) {
|
|
4926
|
+
if (perm === "FORM_FILED_HIDDEN") {
|
|
4927
|
+
behaviors[fieldId] = "HIDDEN";
|
|
4928
|
+
} else if (perm === "FORM_FILED_VIEW") {
|
|
4929
|
+
behaviors[fieldId] = "READONLY";
|
|
4930
|
+
} else if (perm === "FORM_FILED_EDIT") {
|
|
4931
|
+
behaviors[fieldId] = mode === "edit" ? "NORMAL" : "READONLY";
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
}
|
|
4935
|
+
return behaviors;
|
|
4936
|
+
}, [viewPermissions, processDefinition, currentTask, isApprover, mode]);
|
|
4937
|
+
const fieldBehaviors = useMemo7(() => computeBehaviors(), [computeBehaviors]);
|
|
4938
|
+
return { fieldBehaviors, computeBehaviors };
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4941
|
+
// src/hooks/useFormDetail.ts
|
|
4942
|
+
import { useState as useState20, useEffect as useEffect27, useCallback as useCallback7, useRef as useRef7 } from "react";
|
|
4943
|
+
function buildFieldBehaviors(permissions, mode) {
|
|
4944
|
+
const behaviors = {};
|
|
4945
|
+
if (!permissions) return behaviors;
|
|
4946
|
+
for (const [fieldId, perm] of Object.entries(permissions.fieldPermissions)) {
|
|
4947
|
+
if (perm === "FORM_FILED_HIDDEN") {
|
|
4948
|
+
behaviors[fieldId] = "HIDDEN";
|
|
4949
|
+
} else if (perm === "FORM_FILED_VIEW") {
|
|
4950
|
+
behaviors[fieldId] = "READONLY";
|
|
4951
|
+
} else if (perm === "FORM_FILED_EDIT") {
|
|
4952
|
+
behaviors[fieldId] = mode === "edit" ? "NORMAL" : "READONLY";
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
return behaviors;
|
|
4956
|
+
}
|
|
4957
|
+
function useFormDetail(options) {
|
|
4958
|
+
const { formUuid, appType, formInstanceId, onPermissionDenied } = options;
|
|
4959
|
+
const { api } = useFormContext();
|
|
4960
|
+
const request = api.request;
|
|
4961
|
+
const [loading, setLoading] = useState20(true);
|
|
4962
|
+
const [mode, setMode] = useState20("readonly");
|
|
4963
|
+
const [formData, setFormData] = useState20(null);
|
|
4964
|
+
const [instanceInfo, setInstanceInfo] = useState20(null);
|
|
4965
|
+
const [permissions, setPermissions] = useState20(null);
|
|
4966
|
+
const mountedRef = useRef7(true);
|
|
4967
|
+
useEffect27(() => {
|
|
4968
|
+
mountedRef.current = true;
|
|
4969
|
+
return () => {
|
|
4970
|
+
mountedRef.current = false;
|
|
4971
|
+
};
|
|
4972
|
+
}, []);
|
|
4973
|
+
const loadData = useCallback7(async () => {
|
|
4974
|
+
if (!mountedRef.current) return;
|
|
4975
|
+
setLoading(true);
|
|
4976
|
+
try {
|
|
4977
|
+
const [permResult, formResult] = await Promise.all([
|
|
4978
|
+
getViewPermission(request, { formUuid, appType, formInstanceId }),
|
|
4979
|
+
getFormData(request, { formInstanceId, appType, formUuid })
|
|
4980
|
+
]);
|
|
4981
|
+
if (!mountedRef.current) return;
|
|
4982
|
+
if (!permResult || !permResult.operations || permResult.operations.length === 0) {
|
|
4983
|
+
onPermissionDenied?.();
|
|
4984
|
+
}
|
|
4985
|
+
setPermissions(permResult);
|
|
4986
|
+
setInstanceInfo(formResult);
|
|
4987
|
+
setFormData(formResult?.data ?? null);
|
|
4988
|
+
} catch (error) {
|
|
4989
|
+
console.error("[useFormDetail] Failed to load data:", error);
|
|
4990
|
+
if (mountedRef.current) {
|
|
4991
|
+
setPermissions(null);
|
|
4992
|
+
setInstanceInfo(null);
|
|
4993
|
+
setFormData(null);
|
|
4994
|
+
}
|
|
4995
|
+
} finally {
|
|
4996
|
+
if (mountedRef.current) {
|
|
4997
|
+
setLoading(false);
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
}, [request, formUuid, appType, formInstanceId, onPermissionDenied]);
|
|
5001
|
+
useEffect27(() => {
|
|
5002
|
+
loadData();
|
|
5003
|
+
}, [loadData]);
|
|
5004
|
+
const fieldBehaviors = buildFieldBehaviors(permissions, mode);
|
|
5005
|
+
const canEdit = permissions?.operations?.includes("EDIT") ?? false;
|
|
5006
|
+
const canDelete = permissions?.operations?.includes("DELETE") ?? false;
|
|
5007
|
+
const canViewChangeRecords = permissions?.operations?.includes("VIEW_CHANGE_RECORDS") ?? false;
|
|
5008
|
+
const switchToEdit = useCallback7(() => {
|
|
5009
|
+
setMode("edit");
|
|
5010
|
+
loadData();
|
|
5011
|
+
}, [loadData]);
|
|
5012
|
+
const switchToReadonly = useCallback7(() => {
|
|
5013
|
+
setMode("readonly");
|
|
5014
|
+
}, []);
|
|
5015
|
+
const saveChanges = useCallback7(
|
|
5016
|
+
async (values) => {
|
|
5017
|
+
try {
|
|
5018
|
+
await api.updateFormData({
|
|
5019
|
+
formInstanceId,
|
|
5020
|
+
formUuid,
|
|
5021
|
+
appType,
|
|
5022
|
+
updateFormDataJson: JSON.stringify(values)
|
|
5023
|
+
});
|
|
5024
|
+
if (mountedRef.current) {
|
|
5025
|
+
setFormData(values);
|
|
5026
|
+
setMode("readonly");
|
|
5027
|
+
}
|
|
5028
|
+
return true;
|
|
5029
|
+
} catch (error) {
|
|
5030
|
+
console.error("[useFormDetail] Failed to save changes:", error);
|
|
5031
|
+
return false;
|
|
5032
|
+
}
|
|
5033
|
+
},
|
|
5034
|
+
[api, formInstanceId, formUuid, appType]
|
|
5035
|
+
);
|
|
5036
|
+
const deleteInstance = useCallback7(async () => {
|
|
5037
|
+
try {
|
|
5038
|
+
await deleteFormData(request, { formInstanceId, appType, formUuid });
|
|
5039
|
+
return true;
|
|
5040
|
+
} catch (error) {
|
|
5041
|
+
console.error("[useFormDetail] Failed to delete instance:", error);
|
|
5042
|
+
return false;
|
|
5043
|
+
}
|
|
5044
|
+
}, [request, formInstanceId, appType, formUuid]);
|
|
5045
|
+
return {
|
|
5046
|
+
loading,
|
|
5047
|
+
mode,
|
|
5048
|
+
formData,
|
|
5049
|
+
instanceInfo,
|
|
5050
|
+
permissions,
|
|
5051
|
+
fieldBehaviors,
|
|
5052
|
+
switchToEdit,
|
|
5053
|
+
switchToReadonly,
|
|
5054
|
+
saveChanges,
|
|
5055
|
+
deleteInstance,
|
|
5056
|
+
canEdit,
|
|
5057
|
+
canDelete,
|
|
5058
|
+
canViewChangeRecords
|
|
5059
|
+
};
|
|
5060
|
+
}
|
|
5061
|
+
|
|
5062
|
+
// src/hooks/useProcessDetail.ts
|
|
5063
|
+
import { useState as useState21, useEffect as useEffect28, useCallback as useCallback8, useRef as useRef8 } from "react";
|
|
5064
|
+
function useProcessDetail(options) {
|
|
5065
|
+
const { formUuid, appType, formInstanceId } = options;
|
|
5066
|
+
const { api } = useFormContext();
|
|
5067
|
+
const request = api.request;
|
|
5068
|
+
const [loading, setLoading] = useState21(true);
|
|
5069
|
+
const [mode, setMode] = useState21("readonly");
|
|
5070
|
+
const [processInfo, setProcessInfo] = useState21(null);
|
|
5071
|
+
const [progressList, setProgressList] = useState21([]);
|
|
5072
|
+
const [formData, setFormData] = useState21(null);
|
|
5073
|
+
const [instanceInfo, setInstanceInfo] = useState21(null);
|
|
5074
|
+
const [isApprover, setIsApprover] = useState21(false);
|
|
5075
|
+
const [canWithdraw, setCanWithdraw] = useState21(false);
|
|
5076
|
+
const [permissions, setPermissions] = useState21(null);
|
|
5077
|
+
const [processDefinition, setProcessDefinition] = useState21(null);
|
|
5078
|
+
const mountedRef = useRef8(true);
|
|
5079
|
+
useEffect28(() => {
|
|
5080
|
+
mountedRef.current = true;
|
|
5081
|
+
return () => {
|
|
5082
|
+
mountedRef.current = false;
|
|
5083
|
+
};
|
|
5084
|
+
}, []);
|
|
5085
|
+
const currentTask = processInfo?.currentTask ?? null;
|
|
5086
|
+
const processStatus = processInfo?.processStatus ?? null;
|
|
5087
|
+
const isOriginatorReturn = currentTask?.nodeType === "originator_return";
|
|
5088
|
+
const isProcessCompleted = processStatus === "completed" || processStatus === "terminated";
|
|
5089
|
+
const { fieldBehaviors } = useFieldPermission({
|
|
5090
|
+
viewPermissions: permissions ?? void 0,
|
|
5091
|
+
processDefinition: processDefinition ?? void 0,
|
|
5092
|
+
currentTask: currentTask ?? void 0,
|
|
5093
|
+
isApprover,
|
|
5094
|
+
mode
|
|
5095
|
+
});
|
|
5096
|
+
const activeActions = isApprover && currentTask?.actions ? currentTask.actions : [];
|
|
5097
|
+
const loadData = useCallback8(async () => {
|
|
5098
|
+
if (!mountedRef.current) return;
|
|
5099
|
+
setLoading(true);
|
|
5100
|
+
try {
|
|
5101
|
+
const [basicResult, approvalResult, permResult, formResult] = await Promise.all([
|
|
5102
|
+
getProcessBasic(request, formInstanceId),
|
|
5103
|
+
checkUserApproval(request, formInstanceId),
|
|
5104
|
+
getViewPermission(request, { formUuid, appType, formInstanceId }),
|
|
5105
|
+
getFormData(request, { formInstanceId, appType, formUuid })
|
|
5106
|
+
]);
|
|
5107
|
+
if (!mountedRef.current) return;
|
|
5108
|
+
setProcessInfo(basicResult);
|
|
5109
|
+
setIsApprover(approvalResult?.isApprover ?? false);
|
|
5110
|
+
setCanWithdraw(approvalResult?.canUndo ?? false);
|
|
5111
|
+
setPermissions(permResult);
|
|
5112
|
+
setInstanceInfo(formResult);
|
|
5113
|
+
setFormData(formResult?.data ?? null);
|
|
5114
|
+
if (permResult?.operations?.includes("VIEW_PROCESS") || permResult?.operations?.length > 0) {
|
|
5115
|
+
try {
|
|
5116
|
+
const progress = await getProcessProgress(request, formInstanceId);
|
|
5117
|
+
if (mountedRef.current) {
|
|
5118
|
+
setProgressList(progress);
|
|
5119
|
+
}
|
|
5120
|
+
} catch (error) {
|
|
5121
|
+
console.error("[useProcessDetail] Failed to load progress:", error);
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
const task = basicResult?.currentTask;
|
|
5125
|
+
if (approvalResult?.isApprover && task && (task.nodeType === "originator_return" || task.nodeType === "approval")) {
|
|
5126
|
+
try {
|
|
5127
|
+
const definition = await getProcessDefinition(request, formUuid);
|
|
5128
|
+
if (mountedRef.current) {
|
|
5129
|
+
setProcessDefinition(definition);
|
|
5130
|
+
}
|
|
5131
|
+
} catch (error) {
|
|
5132
|
+
console.error("[useProcessDetail] Failed to load process definition:", error);
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
} catch (error) {
|
|
5136
|
+
console.error("[useProcessDetail] Failed to load data:", error);
|
|
5137
|
+
if (mountedRef.current) {
|
|
5138
|
+
setProcessInfo(null);
|
|
5139
|
+
setFormData(null);
|
|
5140
|
+
setInstanceInfo(null);
|
|
5141
|
+
}
|
|
5142
|
+
} finally {
|
|
5143
|
+
if (mountedRef.current) {
|
|
5144
|
+
setLoading(false);
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
}, [request, formUuid, appType, formInstanceId]);
|
|
5148
|
+
useEffect28(() => {
|
|
5149
|
+
loadData();
|
|
5150
|
+
}, [loadData]);
|
|
5151
|
+
const switchToEdit = useCallback8(() => {
|
|
5152
|
+
setMode("edit");
|
|
5153
|
+
}, []);
|
|
5154
|
+
const switchToReadonly = useCallback8(() => {
|
|
5155
|
+
setMode("readonly");
|
|
5156
|
+
}, []);
|
|
5157
|
+
const refreshProgress = useCallback8(async () => {
|
|
5158
|
+
try {
|
|
5159
|
+
const [progress, basicResult] = await Promise.all([
|
|
5160
|
+
getProcessProgress(request, formInstanceId),
|
|
5161
|
+
getProcessBasic(request, formInstanceId)
|
|
5162
|
+
]);
|
|
5163
|
+
if (mountedRef.current) {
|
|
5164
|
+
setProgressList(progress);
|
|
5165
|
+
setProcessInfo(basicResult);
|
|
5166
|
+
}
|
|
5167
|
+
} catch (error) {
|
|
5168
|
+
console.error("[useProcessDetail] Failed to refresh progress:", error);
|
|
5169
|
+
}
|
|
5170
|
+
}, [request, formInstanceId]);
|
|
5171
|
+
return {
|
|
5172
|
+
loading,
|
|
5173
|
+
processInfo,
|
|
5174
|
+
processStatus,
|
|
5175
|
+
currentTask,
|
|
5176
|
+
progressList,
|
|
5177
|
+
formData,
|
|
5178
|
+
instanceInfo,
|
|
5179
|
+
isApprover,
|
|
5180
|
+
activeActions,
|
|
5181
|
+
fieldBehaviors,
|
|
5182
|
+
mode,
|
|
5183
|
+
isOriginatorReturn,
|
|
5184
|
+
isProcessCompleted,
|
|
5185
|
+
canWithdraw,
|
|
5186
|
+
switchToEdit,
|
|
5187
|
+
switchToReadonly,
|
|
5188
|
+
refreshProgress
|
|
5189
|
+
};
|
|
5190
|
+
}
|
|
5191
|
+
|
|
5192
|
+
// src/hooks/useApprovalActions.ts
|
|
5193
|
+
import { useState as useState22, useCallback as useCallback9, useRef as useRef9, useEffect as useEffect29 } from "react";
|
|
5194
|
+
function useApprovalActions(options) {
|
|
5195
|
+
const { formInstanceId, formUuid, appType, currentTaskId, onActionComplete, getFormValues } = options;
|
|
5196
|
+
const { api } = useFormContext();
|
|
5197
|
+
const request = api.request;
|
|
5198
|
+
const [isLoading, setIsLoading] = useState22(false);
|
|
5199
|
+
const [currentAction, setCurrentAction] = useState22(null);
|
|
5200
|
+
const [returnableNodes, setReturnableNodes] = useState22([]);
|
|
5201
|
+
const mountedRef = useRef9(true);
|
|
5202
|
+
useEffect29(() => {
|
|
5203
|
+
mountedRef.current = true;
|
|
5204
|
+
return () => {
|
|
5205
|
+
mountedRef.current = false;
|
|
5206
|
+
};
|
|
5207
|
+
}, []);
|
|
5208
|
+
const resetLoading = useCallback9(() => {
|
|
5209
|
+
if (mountedRef.current) {
|
|
5210
|
+
setIsLoading(false);
|
|
5211
|
+
setCurrentAction(null);
|
|
5212
|
+
}
|
|
5213
|
+
}, []);
|
|
5214
|
+
const approve = useCallback9(
|
|
5215
|
+
async (comments) => {
|
|
5216
|
+
setIsLoading(true);
|
|
5217
|
+
setCurrentAction("approve");
|
|
5218
|
+
try {
|
|
5219
|
+
const formValues = getFormValues?.();
|
|
5220
|
+
await handleApproval(request, {
|
|
5221
|
+
instanceId: formInstanceId,
|
|
5222
|
+
action: "approved",
|
|
5223
|
+
comments,
|
|
5224
|
+
appType,
|
|
5225
|
+
formUuid,
|
|
5226
|
+
updateFormDataJson: formValues ? JSON.stringify(formValues) : void 0
|
|
5227
|
+
});
|
|
5228
|
+
resetLoading();
|
|
5229
|
+
onActionComplete?.("approve");
|
|
5230
|
+
return true;
|
|
5231
|
+
} catch (error) {
|
|
5232
|
+
console.error("[useApprovalActions] approve failed:", error);
|
|
5233
|
+
resetLoading();
|
|
5234
|
+
return false;
|
|
5235
|
+
}
|
|
5236
|
+
},
|
|
5237
|
+
[request, formInstanceId, appType, formUuid, getFormValues, onActionComplete, resetLoading]
|
|
5238
|
+
);
|
|
5239
|
+
const reject = useCallback9(
|
|
5240
|
+
async (comments) => {
|
|
5241
|
+
setIsLoading(true);
|
|
5242
|
+
setCurrentAction("reject");
|
|
5243
|
+
try {
|
|
5244
|
+
const formValues = getFormValues?.();
|
|
5245
|
+
await handleApproval(request, {
|
|
5246
|
+
instanceId: formInstanceId,
|
|
5247
|
+
action: "rejected",
|
|
5248
|
+
comments,
|
|
5249
|
+
appType,
|
|
5250
|
+
formUuid,
|
|
5251
|
+
updateFormDataJson: formValues ? JSON.stringify(formValues) : void 0
|
|
5252
|
+
});
|
|
5253
|
+
resetLoading();
|
|
5254
|
+
onActionComplete?.("reject");
|
|
5255
|
+
return true;
|
|
5256
|
+
} catch (error) {
|
|
5257
|
+
console.error("[useApprovalActions] reject failed:", error);
|
|
5258
|
+
resetLoading();
|
|
5259
|
+
return false;
|
|
5260
|
+
}
|
|
5261
|
+
},
|
|
5262
|
+
[request, formInstanceId, appType, formUuid, getFormValues, onActionComplete, resetLoading]
|
|
5263
|
+
);
|
|
5264
|
+
const transfer = useCallback9(
|
|
5265
|
+
async (userId, reason) => {
|
|
5266
|
+
if (!currentTaskId) {
|
|
5267
|
+
console.error("[useApprovalActions] transfer failed: no currentTaskId");
|
|
5268
|
+
return false;
|
|
5269
|
+
}
|
|
5270
|
+
setIsLoading(true);
|
|
5271
|
+
setCurrentAction("transfer");
|
|
5272
|
+
try {
|
|
5273
|
+
await transferTask(request, {
|
|
5274
|
+
taskId: currentTaskId,
|
|
5275
|
+
newAssignee: userId,
|
|
5276
|
+
reason
|
|
5277
|
+
});
|
|
5278
|
+
resetLoading();
|
|
5279
|
+
onActionComplete?.("transfer");
|
|
5280
|
+
return true;
|
|
5281
|
+
} catch (error) {
|
|
5282
|
+
console.error("[useApprovalActions] transfer failed:", error);
|
|
5283
|
+
resetLoading();
|
|
5284
|
+
return false;
|
|
5285
|
+
}
|
|
5286
|
+
},
|
|
5287
|
+
[request, currentTaskId, onActionComplete, resetLoading]
|
|
5288
|
+
);
|
|
5289
|
+
const returnTo = useCallback9(
|
|
5290
|
+
async (nodeId, reason) => {
|
|
5291
|
+
if (!currentTaskId) {
|
|
5292
|
+
console.error("[useApprovalActions] returnTo failed: no currentTaskId");
|
|
5293
|
+
return false;
|
|
5294
|
+
}
|
|
5295
|
+
setIsLoading(true);
|
|
5296
|
+
setCurrentAction("return");
|
|
5297
|
+
try {
|
|
5298
|
+
await returnTask(request, {
|
|
5299
|
+
taskId: currentTaskId,
|
|
5300
|
+
targetNodeId: nodeId,
|
|
5301
|
+
reason
|
|
5302
|
+
});
|
|
5303
|
+
resetLoading();
|
|
5304
|
+
onActionComplete?.("return");
|
|
5305
|
+
return true;
|
|
5306
|
+
} catch (error) {
|
|
5307
|
+
console.error("[useApprovalActions] returnTo failed:", error);
|
|
5308
|
+
resetLoading();
|
|
5309
|
+
return false;
|
|
5310
|
+
}
|
|
5311
|
+
},
|
|
5312
|
+
[request, currentTaskId, onActionComplete, resetLoading]
|
|
5313
|
+
);
|
|
5314
|
+
const withdraw = useCallback9(
|
|
5315
|
+
async (reason) => {
|
|
5316
|
+
setIsLoading(true);
|
|
5317
|
+
setCurrentAction("withdraw");
|
|
5318
|
+
try {
|
|
5319
|
+
await withdrawProcess(request, {
|
|
5320
|
+
instanceId: formInstanceId,
|
|
5321
|
+
reason
|
|
5322
|
+
});
|
|
5323
|
+
resetLoading();
|
|
5324
|
+
onActionComplete?.("withdraw");
|
|
5325
|
+
return true;
|
|
5326
|
+
} catch (error) {
|
|
5327
|
+
console.error("[useApprovalActions] withdraw failed:", error);
|
|
5328
|
+
resetLoading();
|
|
5329
|
+
return false;
|
|
5330
|
+
}
|
|
5331
|
+
},
|
|
5332
|
+
[request, formInstanceId, onActionComplete, resetLoading]
|
|
5333
|
+
);
|
|
5334
|
+
const save = useCallback9(async () => {
|
|
5335
|
+
setIsLoading(true);
|
|
5336
|
+
setCurrentAction("save");
|
|
5337
|
+
try {
|
|
5338
|
+
const formValues = getFormValues?.() ?? {};
|
|
5339
|
+
await saveTask(request, {
|
|
5340
|
+
instanceId: formInstanceId,
|
|
5341
|
+
formUuid,
|
|
5342
|
+
appType,
|
|
5343
|
+
updateFormDataJson: JSON.stringify(formValues)
|
|
5344
|
+
});
|
|
5345
|
+
resetLoading();
|
|
5346
|
+
onActionComplete?.("save");
|
|
5347
|
+
return true;
|
|
5348
|
+
} catch (error) {
|
|
5349
|
+
console.error("[useApprovalActions] save failed:", error);
|
|
5350
|
+
resetLoading();
|
|
5351
|
+
return false;
|
|
5352
|
+
}
|
|
5353
|
+
}, [request, formInstanceId, formUuid, appType, getFormValues, onActionComplete, resetLoading]);
|
|
5354
|
+
const resubmit = useCallback9(
|
|
5355
|
+
async (comments) => {
|
|
5356
|
+
if (!currentTaskId) {
|
|
5357
|
+
console.error("[useApprovalActions] resubmit failed: no currentTaskId");
|
|
5358
|
+
return false;
|
|
5359
|
+
}
|
|
5360
|
+
setIsLoading(true);
|
|
5361
|
+
setCurrentAction("resubmit");
|
|
5362
|
+
try {
|
|
5363
|
+
const formValues = getFormValues?.() ?? {};
|
|
5364
|
+
await resubmitTask(request, {
|
|
5365
|
+
taskId: currentTaskId,
|
|
5366
|
+
formUuid,
|
|
5367
|
+
appType,
|
|
5368
|
+
updateFormDataJson: JSON.stringify(formValues),
|
|
5369
|
+
comments
|
|
5370
|
+
});
|
|
5371
|
+
resetLoading();
|
|
5372
|
+
onActionComplete?.("resubmit");
|
|
5373
|
+
return true;
|
|
5374
|
+
} catch (error) {
|
|
5375
|
+
console.error("[useApprovalActions] resubmit failed:", error);
|
|
5376
|
+
resetLoading();
|
|
5377
|
+
return false;
|
|
5378
|
+
}
|
|
5379
|
+
},
|
|
5380
|
+
[request, currentTaskId, formUuid, appType, getFormValues, onActionComplete, resetLoading]
|
|
5381
|
+
);
|
|
5382
|
+
const loadReturnableNodes = useCallback9(async () => {
|
|
5383
|
+
if (!currentTaskId) return;
|
|
5384
|
+
try {
|
|
5385
|
+
const nodes = await getReturnableNodes(request, currentTaskId);
|
|
5386
|
+
if (mountedRef.current) {
|
|
5387
|
+
setReturnableNodes(nodes);
|
|
5388
|
+
}
|
|
5389
|
+
} catch (error) {
|
|
5390
|
+
console.error("[useApprovalActions] loadReturnableNodes failed:", error);
|
|
5391
|
+
}
|
|
5392
|
+
}, [request, currentTaskId]);
|
|
5393
|
+
return {
|
|
5394
|
+
approve,
|
|
5395
|
+
reject,
|
|
5396
|
+
transfer,
|
|
5397
|
+
returnTo,
|
|
5398
|
+
withdraw,
|
|
5399
|
+
save,
|
|
5400
|
+
resubmit,
|
|
5401
|
+
isLoading,
|
|
5402
|
+
currentAction,
|
|
5403
|
+
returnableNodes,
|
|
5404
|
+
loadReturnableNodes
|
|
5405
|
+
};
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
// src/hooks/useChangeRecords.ts
|
|
5409
|
+
import { useState as useState23, useEffect as useEffect30, useCallback as useCallback10, useRef as useRef10 } from "react";
|
|
5410
|
+
function useChangeRecords(options) {
|
|
5411
|
+
const { formUuid, appType, formInstanceId, pageSize = 20, autoLoad = true } = options;
|
|
5412
|
+
const { api } = useFormContext();
|
|
5413
|
+
const request = api.request;
|
|
5414
|
+
const [records, setRecords] = useState23([]);
|
|
5415
|
+
const [loading, setLoading] = useState23(false);
|
|
5416
|
+
const [total, setTotal] = useState23(0);
|
|
5417
|
+
const [page, setPage] = useState23(1);
|
|
5418
|
+
const mountedRef = useRef10(true);
|
|
5419
|
+
useEffect30(() => {
|
|
5420
|
+
mountedRef.current = true;
|
|
5421
|
+
return () => {
|
|
5422
|
+
mountedRef.current = false;
|
|
5423
|
+
};
|
|
5424
|
+
}, []);
|
|
5425
|
+
const fetchRecords = useCallback10(
|
|
5426
|
+
async (pageNum, append) => {
|
|
5427
|
+
if (!mountedRef.current) return;
|
|
5428
|
+
setLoading(true);
|
|
5429
|
+
try {
|
|
5430
|
+
const result = await getChangeRecords(request, {
|
|
5431
|
+
formUuid,
|
|
5432
|
+
appType,
|
|
5433
|
+
formInstanceId,
|
|
5434
|
+
page: pageNum,
|
|
5435
|
+
pageSize
|
|
5436
|
+
});
|
|
5437
|
+
if (!mountedRef.current) return;
|
|
5438
|
+
if (append) {
|
|
5439
|
+
setRecords((prev) => [...prev, ...result.records]);
|
|
5440
|
+
} else {
|
|
5441
|
+
setRecords(result.records);
|
|
5442
|
+
}
|
|
5443
|
+
setTotal(result.total);
|
|
5444
|
+
setPage(pageNum);
|
|
5445
|
+
} catch (error) {
|
|
5446
|
+
console.error("[useChangeRecords] Failed to load change records:", error);
|
|
5447
|
+
} finally {
|
|
5448
|
+
if (mountedRef.current) {
|
|
5449
|
+
setLoading(false);
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
},
|
|
5453
|
+
[request, formUuid, appType, formInstanceId, pageSize]
|
|
5454
|
+
);
|
|
5455
|
+
useEffect30(() => {
|
|
5456
|
+
if (autoLoad) {
|
|
5457
|
+
fetchRecords(1, false);
|
|
5458
|
+
}
|
|
5459
|
+
}, [autoLoad, fetchRecords]);
|
|
5460
|
+
const hasMore = records.length < total;
|
|
5461
|
+
const loadMore = useCallback10(async () => {
|
|
5462
|
+
if (!hasMore || loading) return;
|
|
5463
|
+
await fetchRecords(page + 1, true);
|
|
5464
|
+
}, [hasMore, loading, page, fetchRecords]);
|
|
5465
|
+
const refresh = useCallback10(async () => {
|
|
5466
|
+
setRecords([]);
|
|
5467
|
+
setPage(1);
|
|
5468
|
+
setTotal(0);
|
|
5469
|
+
await fetchRecords(1, false);
|
|
5470
|
+
}, [fetchRecords]);
|
|
5471
|
+
return {
|
|
5472
|
+
records,
|
|
5473
|
+
loading,
|
|
5474
|
+
total,
|
|
5475
|
+
page,
|
|
5476
|
+
loadMore,
|
|
5477
|
+
refresh,
|
|
5478
|
+
hasMore
|
|
5479
|
+
};
|
|
5480
|
+
}
|
|
5481
|
+
|
|
5482
|
+
// src/hooks/useFormNavigation.ts
|
|
5483
|
+
import { useState as useState24, useCallback as useCallback11, useRef as useRef11, useEffect as useEffect31 } from "react";
|
|
5484
|
+
function useFormNavigation(options) {
|
|
5485
|
+
const {
|
|
5486
|
+
appType,
|
|
5487
|
+
formUuid,
|
|
5488
|
+
formType = "form",
|
|
5489
|
+
mode = "redirect",
|
|
5490
|
+
redirectDelay = 3e3,
|
|
5491
|
+
onStay
|
|
5492
|
+
} = options;
|
|
5493
|
+
const [isRedirecting, setIsRedirecting] = useState24(false);
|
|
5494
|
+
const [countdown, setCountdown] = useState24(0);
|
|
5495
|
+
const timerRef = useRef11(null);
|
|
5496
|
+
const redirectTargetRef = useRef11(null);
|
|
5497
|
+
const mountedRef = useRef11(true);
|
|
5498
|
+
useEffect31(() => {
|
|
5499
|
+
mountedRef.current = true;
|
|
5500
|
+
return () => {
|
|
5501
|
+
mountedRef.current = false;
|
|
5502
|
+
if (timerRef.current) {
|
|
5503
|
+
clearInterval(timerRef.current);
|
|
5504
|
+
timerRef.current = null;
|
|
5505
|
+
}
|
|
5506
|
+
};
|
|
5507
|
+
}, []);
|
|
5508
|
+
const navigateToDetail = useCallback11(
|
|
5509
|
+
(formInstId) => {
|
|
5510
|
+
window.location.href = `/${appType}/formDetail/${formUuid}?formInstId=${formInstId}`;
|
|
5511
|
+
},
|
|
5512
|
+
[appType, formUuid]
|
|
5513
|
+
);
|
|
5514
|
+
const navigateToProcessDetail = useCallback11(
|
|
5515
|
+
(formInstId) => {
|
|
5516
|
+
window.location.href = `/${appType}/processDetail/${formUuid}?formInstId=${formInstId}`;
|
|
5517
|
+
},
|
|
5518
|
+
[appType, formUuid]
|
|
5519
|
+
);
|
|
5520
|
+
const startRedirectCountdown = useCallback11(
|
|
5521
|
+
(targetUrl) => {
|
|
5522
|
+
const totalSeconds = Math.ceil(redirectDelay / 1e3);
|
|
5523
|
+
setIsRedirecting(true);
|
|
5524
|
+
setCountdown(totalSeconds);
|
|
5525
|
+
redirectTargetRef.current = targetUrl;
|
|
5526
|
+
timerRef.current = setInterval(() => {
|
|
5527
|
+
if (!mountedRef.current) {
|
|
5528
|
+
if (timerRef.current) {
|
|
5529
|
+
clearInterval(timerRef.current);
|
|
5530
|
+
timerRef.current = null;
|
|
5531
|
+
}
|
|
5532
|
+
return;
|
|
5533
|
+
}
|
|
5534
|
+
setCountdown((prev) => {
|
|
5535
|
+
const next = prev - 1;
|
|
5536
|
+
if (next <= 0) {
|
|
5537
|
+
if (timerRef.current) {
|
|
5538
|
+
clearInterval(timerRef.current);
|
|
5539
|
+
timerRef.current = null;
|
|
5540
|
+
}
|
|
5541
|
+
setIsRedirecting(false);
|
|
5542
|
+
if (redirectTargetRef.current) {
|
|
5543
|
+
window.location.href = redirectTargetRef.current;
|
|
5544
|
+
}
|
|
5545
|
+
return 0;
|
|
5546
|
+
}
|
|
5547
|
+
return next;
|
|
5548
|
+
});
|
|
5549
|
+
}, 1e3);
|
|
5550
|
+
},
|
|
5551
|
+
[redirectDelay]
|
|
5552
|
+
);
|
|
5553
|
+
const cancelRedirect = useCallback11(() => {
|
|
5554
|
+
if (timerRef.current) {
|
|
5555
|
+
clearInterval(timerRef.current);
|
|
5556
|
+
timerRef.current = null;
|
|
5557
|
+
}
|
|
5558
|
+
setIsRedirecting(false);
|
|
5559
|
+
setCountdown(0);
|
|
5560
|
+
redirectTargetRef.current = null;
|
|
5561
|
+
}, []);
|
|
5562
|
+
const handlePostSubmit = useCallback11(
|
|
5563
|
+
(formInstId) => {
|
|
5564
|
+
if (mode === "stay") {
|
|
5565
|
+
onStay?.(formInstId);
|
|
5566
|
+
return;
|
|
5567
|
+
}
|
|
5568
|
+
if (mode === "callback") {
|
|
5569
|
+
onStay?.(formInstId);
|
|
5570
|
+
return;
|
|
5571
|
+
}
|
|
5572
|
+
const targetUrl = formType === "process" ? `/${appType}/processDetail/${formUuid}?formInstId=${formInstId}` : `/${appType}/formDetail/${formUuid}?formInstId=${formInstId}`;
|
|
5573
|
+
startRedirectCountdown(targetUrl);
|
|
5574
|
+
},
|
|
5575
|
+
[mode, formType, appType, formUuid, onStay, startRedirectCountdown]
|
|
5576
|
+
);
|
|
5577
|
+
return {
|
|
5578
|
+
navigateToDetail,
|
|
5579
|
+
navigateToProcessDetail,
|
|
5580
|
+
handlePostSubmit,
|
|
5581
|
+
isRedirecting,
|
|
5582
|
+
countdown,
|
|
5583
|
+
cancelRedirect
|
|
5584
|
+
};
|
|
5585
|
+
}
|
|
5586
|
+
|
|
5587
|
+
// src/hooks/useDraftStorage.ts
|
|
5588
|
+
import { useState as useState25, useCallback as useCallback12, useEffect as useEffect32 } from "react";
|
|
5589
|
+
function getDraftKey(appType, formUuid) {
|
|
5590
|
+
return `${appType}__${formUuid}__draft`;
|
|
5591
|
+
}
|
|
5592
|
+
function readDraft(key) {
|
|
5593
|
+
try {
|
|
5594
|
+
const raw = localStorage.getItem(key);
|
|
5595
|
+
if (!raw) return null;
|
|
5596
|
+
const parsed = JSON.parse(raw);
|
|
5597
|
+
if (parsed && typeof parsed.data === "object" && typeof parsed.ts === "number") {
|
|
5598
|
+
return parsed;
|
|
5599
|
+
}
|
|
5600
|
+
return null;
|
|
5601
|
+
} catch {
|
|
5602
|
+
return null;
|
|
5603
|
+
}
|
|
5604
|
+
}
|
|
5605
|
+
function useDraftStorage(options) {
|
|
5606
|
+
const { appType, formUuid, autoRestore = false } = options;
|
|
5607
|
+
const key = getDraftKey(appType, formUuid);
|
|
5608
|
+
const [hasDraft, setHasDraft] = useState25(false);
|
|
5609
|
+
const [draftData, setDraftData] = useState25(null);
|
|
5610
|
+
const [draftTimestamp, setDraftTimestamp] = useState25(null);
|
|
5611
|
+
useEffect32(() => {
|
|
5612
|
+
const stored = readDraft(key);
|
|
5613
|
+
if (stored) {
|
|
5614
|
+
setHasDraft(true);
|
|
5615
|
+
setDraftTimestamp(stored.ts);
|
|
5616
|
+
if (autoRestore) {
|
|
5617
|
+
setDraftData(stored.data);
|
|
5618
|
+
}
|
|
5619
|
+
} else {
|
|
5620
|
+
setHasDraft(false);
|
|
5621
|
+
setDraftData(null);
|
|
5622
|
+
setDraftTimestamp(null);
|
|
5623
|
+
}
|
|
5624
|
+
}, [key, autoRestore]);
|
|
5625
|
+
const saveDraft = useCallback12(
|
|
5626
|
+
(data) => {
|
|
5627
|
+
const payload = { data, ts: Date.now() };
|
|
5628
|
+
try {
|
|
5629
|
+
localStorage.setItem(key, JSON.stringify(payload));
|
|
5630
|
+
setHasDraft(true);
|
|
5631
|
+
setDraftData(data);
|
|
5632
|
+
setDraftTimestamp(payload.ts);
|
|
5633
|
+
} catch (error) {
|
|
5634
|
+
console.error("[useDraftStorage] Failed to save draft:", error);
|
|
5635
|
+
}
|
|
5636
|
+
},
|
|
5637
|
+
[key]
|
|
5638
|
+
);
|
|
5639
|
+
const restoreDraft = useCallback12(() => {
|
|
5640
|
+
const stored = readDraft(key);
|
|
5641
|
+
if (stored) {
|
|
5642
|
+
setDraftData(stored.data);
|
|
5643
|
+
return stored.data;
|
|
5644
|
+
}
|
|
5645
|
+
return null;
|
|
5646
|
+
}, [key]);
|
|
5647
|
+
const clearDraft = useCallback12(() => {
|
|
5648
|
+
try {
|
|
5649
|
+
localStorage.removeItem(key);
|
|
5650
|
+
} catch (error) {
|
|
5651
|
+
console.error("[useDraftStorage] Failed to clear draft:", error);
|
|
5652
|
+
}
|
|
5653
|
+
setHasDraft(false);
|
|
5654
|
+
setDraftData(null);
|
|
5655
|
+
setDraftTimestamp(null);
|
|
5656
|
+
}, [key]);
|
|
5657
|
+
return {
|
|
5658
|
+
hasDraft,
|
|
5659
|
+
draftData,
|
|
5660
|
+
draftTimestamp,
|
|
5661
|
+
saveDraft,
|
|
5662
|
+
restoreDraft,
|
|
5663
|
+
clearDraft
|
|
5664
|
+
};
|
|
5665
|
+
}
|
|
5666
|
+
|
|
4709
5667
|
// src/utils/defineFormSchema.ts
|
|
4710
5668
|
function defineFormSchema(schema) {
|
|
4711
5669
|
return schema;
|
|
4712
5670
|
}
|
|
5671
|
+
|
|
5672
|
+
// src/modules/FormSummaryCard.tsx
|
|
5673
|
+
import { Fragment, jsx as jsx75, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5674
|
+
var toneClasses = {
|
|
5675
|
+
brand: "bg-blue-50 text-blue-600",
|
|
5676
|
+
success: "bg-green-50 text-green-600",
|
|
5677
|
+
danger: "bg-red-50 text-red-600",
|
|
5678
|
+
neutral: "bg-gray-100 text-gray-500",
|
|
5679
|
+
warning: "bg-amber-50 text-amber-600"
|
|
5680
|
+
};
|
|
5681
|
+
var FormSummaryCard = ({
|
|
5682
|
+
title,
|
|
5683
|
+
formInstanceId,
|
|
5684
|
+
creator,
|
|
5685
|
+
createdAt,
|
|
5686
|
+
status,
|
|
5687
|
+
className = "",
|
|
5688
|
+
children
|
|
5689
|
+
}) => {
|
|
5690
|
+
const shortId = formInstanceId ? formInstanceId.slice(0, 8) : null;
|
|
5691
|
+
const renderAvatar = () => {
|
|
5692
|
+
if (!creator) return null;
|
|
5693
|
+
if (creator.avatar) {
|
|
5694
|
+
return /* @__PURE__ */ jsx75(
|
|
5695
|
+
"img",
|
|
5696
|
+
{
|
|
5697
|
+
src: creator.avatar,
|
|
5698
|
+
alt: creator.name,
|
|
5699
|
+
className: "w-7 h-7 rounded-full object-cover"
|
|
5700
|
+
}
|
|
5701
|
+
);
|
|
5702
|
+
}
|
|
5703
|
+
const initial = creator.name.charAt(0);
|
|
5704
|
+
return /* @__PURE__ */ jsx75("span", { className: "w-7 h-7 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center text-xs font-medium", children: initial });
|
|
5705
|
+
};
|
|
5706
|
+
return /* @__PURE__ */ jsxs21("div", { className: `bg-white rounded-xl shadow-sm border border-gray-100 p-6 ${className}`, children: [
|
|
5707
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex items-start justify-between", children: [
|
|
5708
|
+
/* @__PURE__ */ jsxs21("div", { className: "min-w-0 flex-1", children: [
|
|
5709
|
+
title && /* @__PURE__ */ jsx75("h2", { className: "text-xl font-semibold text-gray-900 truncate", children: title }),
|
|
5710
|
+
shortId && /* @__PURE__ */ jsxs21("span", { className: "text-xs text-gray-400 mt-0.5 inline-block", children: [
|
|
5711
|
+
"#",
|
|
5712
|
+
shortId
|
|
5713
|
+
] })
|
|
5714
|
+
] }),
|
|
5715
|
+
status && /* @__PURE__ */ jsx75(
|
|
5716
|
+
"span",
|
|
5717
|
+
{
|
|
5718
|
+
className: `px-2.5 py-0.5 rounded-full text-xs font-medium whitespace-nowrap ${toneClasses[status.tone] || toneClasses.neutral}`,
|
|
5719
|
+
children: status.label
|
|
5720
|
+
}
|
|
5721
|
+
)
|
|
5722
|
+
] }),
|
|
5723
|
+
creator && /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2 mt-4 text-sm text-gray-600", children: [
|
|
5724
|
+
renderAvatar(),
|
|
5725
|
+
/* @__PURE__ */ jsx75("span", { className: "font-medium", children: creator.name }),
|
|
5726
|
+
creator.department && /* @__PURE__ */ jsxs21(Fragment, { children: [
|
|
5727
|
+
/* @__PURE__ */ jsx75("span", { className: "text-gray-300", children: "\xB7" }),
|
|
5728
|
+
/* @__PURE__ */ jsx75("span", { children: creator.department })
|
|
5729
|
+
] }),
|
|
5730
|
+
createdAt && /* @__PURE__ */ jsxs21(Fragment, { children: [
|
|
5731
|
+
/* @__PURE__ */ jsx75("span", { className: "text-gray-300", children: "\xB7" }),
|
|
5732
|
+
/* @__PURE__ */ jsx75("span", { className: "text-gray-400", children: createdAt })
|
|
5733
|
+
] })
|
|
5734
|
+
] }),
|
|
5735
|
+
children && /* @__PURE__ */ jsx75("div", { className: "mt-4", children })
|
|
5736
|
+
] });
|
|
5737
|
+
};
|
|
5738
|
+
|
|
5739
|
+
// src/modules/ChangeRecords.tsx
|
|
5740
|
+
import { useState as useState26 } from "react";
|
|
5741
|
+
import { Skeleton } from "antd";
|
|
5742
|
+
import { DownOutlined, UpOutlined } from "@ant-design/icons";
|
|
5743
|
+
import { jsx as jsx76, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5744
|
+
var ChangeRecords = ({
|
|
5745
|
+
records = [],
|
|
5746
|
+
loading = false,
|
|
5747
|
+
defaultExpanded = false,
|
|
5748
|
+
hasMore = false,
|
|
5749
|
+
onLoadMore,
|
|
5750
|
+
onExpand,
|
|
5751
|
+
className = "",
|
|
5752
|
+
renderItem
|
|
5753
|
+
}) => {
|
|
5754
|
+
const [expanded, setExpanded] = useState26(defaultExpanded);
|
|
5755
|
+
const handleToggle = () => {
|
|
5756
|
+
const next = !expanded;
|
|
5757
|
+
setExpanded(next);
|
|
5758
|
+
if (next && onExpand) {
|
|
5759
|
+
onExpand();
|
|
5760
|
+
}
|
|
5761
|
+
};
|
|
5762
|
+
const defaultRenderItem = (record) => /* @__PURE__ */ jsxs22("div", { className: "pl-4 py-3 border-l-2 border-gray-200 ml-1", children: [
|
|
5763
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2 text-xs text-gray-400", children: [
|
|
5764
|
+
/* @__PURE__ */ jsx76("span", { children: record.operatedAt }),
|
|
5765
|
+
/* @__PURE__ */ jsx76("span", { className: "text-gray-600 font-medium", children: record.operatorName }),
|
|
5766
|
+
/* @__PURE__ */ jsx76("span", { children: "\u4FEE\u6539\u4E86" }),
|
|
5767
|
+
/* @__PURE__ */ jsx76("span", { className: "text-gray-800 font-medium", children: record.fieldLabel })
|
|
5768
|
+
] }),
|
|
5769
|
+
/* @__PURE__ */ jsxs22("div", { className: "mt-1.5 text-sm text-gray-600 flex items-center gap-2", children: [
|
|
5770
|
+
/* @__PURE__ */ jsx76("span", { className: "bg-red-50 text-red-600 px-1.5 py-0.5 rounded text-xs line-through", children: formatValue(record.oldValue) }),
|
|
5771
|
+
/* @__PURE__ */ jsx76("span", { className: "text-gray-400", children: "\u2192" }),
|
|
5772
|
+
/* @__PURE__ */ jsx76("span", { className: "bg-green-50 text-green-600 px-1.5 py-0.5 rounded text-xs", children: formatValue(record.newValue) })
|
|
5773
|
+
] })
|
|
5774
|
+
] });
|
|
5775
|
+
return /* @__PURE__ */ jsxs22("div", { className: `bg-white rounded-xl shadow-sm border border-gray-100 ${className}`, children: [
|
|
5776
|
+
/* @__PURE__ */ jsxs22(
|
|
5777
|
+
"button",
|
|
5778
|
+
{
|
|
5779
|
+
type: "button",
|
|
5780
|
+
className: "w-full flex items-center justify-between p-6 text-left hover:bg-gray-50/50 transition-colors rounded-xl",
|
|
5781
|
+
onClick: handleToggle,
|
|
5782
|
+
children: [
|
|
5783
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
5784
|
+
/* @__PURE__ */ jsx76("h3", { className: "text-lg font-semibold text-gray-900", children: "\u53D8\u66F4\u8BB0\u5F55" }),
|
|
5785
|
+
/* @__PURE__ */ jsx76("span", { className: "text-xs text-gray-400 bg-gray-100 px-1.5 py-0.5 rounded-full", children: records.length })
|
|
5786
|
+
] }),
|
|
5787
|
+
/* @__PURE__ */ jsx76("span", { className: "text-gray-400 text-xs", children: expanded ? /* @__PURE__ */ jsx76(UpOutlined, {}) : /* @__PURE__ */ jsx76(DownOutlined, {}) })
|
|
5788
|
+
]
|
|
5789
|
+
}
|
|
5790
|
+
),
|
|
5791
|
+
expanded && /* @__PURE__ */ jsxs22("div", { className: "px-6 pb-6", children: [
|
|
5792
|
+
loading && records.length === 0 ? /* @__PURE__ */ jsx76(Skeleton, { active: true, paragraph: { rows: 3 } }) : records.length === 0 ? /* @__PURE__ */ jsx76("p", { className: "text-sm text-gray-400 text-center py-4", children: "\u6682\u65E0\u53D8\u66F4\u8BB0\u5F55" }) : /* @__PURE__ */ jsx76("div", { className: "space-y-1", children: records.map((record) => /* @__PURE__ */ jsx76("div", { children: renderItem ? renderItem(record) : defaultRenderItem(record) }, record.id)) }),
|
|
5793
|
+
hasMore && /* @__PURE__ */ jsx76(
|
|
5794
|
+
"button",
|
|
5795
|
+
{
|
|
5796
|
+
type: "button",
|
|
5797
|
+
className: "mt-4 w-full text-center text-sm text-blue-600 hover:text-blue-700 py-2 rounded-lg hover:bg-blue-50/50 transition-colors",
|
|
5798
|
+
onClick: onLoadMore,
|
|
5799
|
+
disabled: loading,
|
|
5800
|
+
children: loading ? "\u52A0\u8F7D\u4E2D..." : "\u52A0\u8F7D\u66F4\u591A"
|
|
5801
|
+
}
|
|
5802
|
+
)
|
|
5803
|
+
] })
|
|
5804
|
+
] });
|
|
5805
|
+
};
|
|
5806
|
+
function formatValue(value) {
|
|
5807
|
+
if (value === null || value === void 0) return "\u7A7A";
|
|
5808
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
5809
|
+
return String(value);
|
|
5810
|
+
}
|
|
5811
|
+
|
|
5812
|
+
// src/modules/ApprovalTimeline.tsx
|
|
5813
|
+
import { Fragment as Fragment2, jsx as jsx77, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
5814
|
+
var toneClasses2 = {
|
|
5815
|
+
brand: "bg-blue-50 text-blue-600",
|
|
5816
|
+
success: "bg-green-50 text-green-600",
|
|
5817
|
+
danger: "bg-red-50 text-red-600",
|
|
5818
|
+
neutral: "bg-gray-100 text-gray-500",
|
|
5819
|
+
warning: "bg-amber-50 text-amber-600"
|
|
5820
|
+
};
|
|
5821
|
+
function getNodePhase(task) {
|
|
5822
|
+
if (task.status === "approved" || task.status === "rejected" || task.status === "returned" || task.status === "copied") {
|
|
5823
|
+
return "completed";
|
|
5824
|
+
}
|
|
5825
|
+
if (task.status === "pending" || task.status === "waiting") {
|
|
5826
|
+
return "active";
|
|
5827
|
+
}
|
|
5828
|
+
return "pending";
|
|
5829
|
+
}
|
|
5830
|
+
var ApprovalTimeline = ({
|
|
5831
|
+
tasks,
|
|
5832
|
+
className = "",
|
|
5833
|
+
renderNode,
|
|
5834
|
+
showRemarks = true,
|
|
5835
|
+
compactMode = false
|
|
5836
|
+
}) => {
|
|
5837
|
+
if (!tasks || tasks.length === 0) {
|
|
5838
|
+
return /* @__PURE__ */ jsx77("div", { className: `bg-white rounded-xl shadow-sm border border-gray-100 p-6 ${className}`, children: /* @__PURE__ */ jsx77("p", { className: "text-sm text-gray-400 text-center", children: "\u6682\u65E0\u5BA1\u6279\u8BB0\u5F55" }) });
|
|
5839
|
+
}
|
|
5840
|
+
return /* @__PURE__ */ jsx77("div", { className: `${className}`, children: tasks.map((task, index) => {
|
|
5841
|
+
if (renderNode) {
|
|
5842
|
+
return /* @__PURE__ */ jsx77("div", { children: renderNode(task, index) }, task.taskId);
|
|
5843
|
+
}
|
|
5844
|
+
const phase = getNodePhase(task);
|
|
5845
|
+
const isLast = index === tasks.length - 1;
|
|
5846
|
+
const statusMeta = TASK_STATUS_META[task.status];
|
|
5847
|
+
return /* @__PURE__ */ jsxs23("div", { className: "flex gap-4", children: [
|
|
5848
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex flex-col items-center", children: [
|
|
5849
|
+
phase === "completed" && /* @__PURE__ */ jsx77("div", { className: "w-3 h-3 rounded-full bg-green-500 flex-shrink-0" }),
|
|
5850
|
+
phase === "active" && /* @__PURE__ */ jsx77("div", { className: "w-3 h-3 rounded-full bg-blue-500 ring-4 ring-blue-100 flex-shrink-0" }),
|
|
5851
|
+
phase === "pending" && /* @__PURE__ */ jsx77("div", { className: "w-3 h-3 rounded-full bg-gray-300 flex-shrink-0" }),
|
|
5852
|
+
!isLast && /* @__PURE__ */ jsx77(
|
|
5853
|
+
"div",
|
|
5854
|
+
{
|
|
5855
|
+
className: `w-0.5 flex-1 mt-1 ${phase === "completed" ? "bg-green-300" : phase === "active" ? "bg-blue-400" : "border-l-2 border-dashed border-gray-200"}`
|
|
5856
|
+
}
|
|
5857
|
+
)
|
|
5858
|
+
] }),
|
|
5859
|
+
/* @__PURE__ */ jsx77("div", { className: `flex-1 pb-6 ${isLast ? "pb-0" : ""}`, children: /* @__PURE__ */ jsxs23(
|
|
5860
|
+
"div",
|
|
5861
|
+
{
|
|
5862
|
+
className: `rounded-lg p-4 ${phase === "completed" ? "bg-white border border-gray-100" : phase === "active" ? "bg-white border-l-4 border-l-blue-500 border border-gray-100 shadow-sm" : "bg-gray-50 border border-gray-100 opacity-60"}`,
|
|
5863
|
+
children: [
|
|
5864
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
|
|
5865
|
+
/* @__PURE__ */ jsx77("span", { className: "text-sm font-medium text-gray-900", children: task.nodeName }),
|
|
5866
|
+
statusMeta && /* @__PURE__ */ jsx77(
|
|
5867
|
+
"span",
|
|
5868
|
+
{
|
|
5869
|
+
className: `px-2 py-0.5 rounded-full text-xs font-medium ${toneClasses2[statusMeta.tone] || toneClasses2.neutral}`,
|
|
5870
|
+
children: statusMeta.label
|
|
5871
|
+
}
|
|
5872
|
+
)
|
|
5873
|
+
] }),
|
|
5874
|
+
task.assigneeName && /* @__PURE__ */ jsxs23("div", { className: "mt-2 flex items-center gap-1.5 text-sm text-gray-600", children: [
|
|
5875
|
+
/* @__PURE__ */ jsx77("span", { className: "text-gray-400", children: "\u{1F464}" }),
|
|
5876
|
+
/* @__PURE__ */ jsxs23("span", { children: [
|
|
5877
|
+
phase === "active" ? "\u5F53\u524D\u5BA1\u6279\u4EBA: " : "",
|
|
5878
|
+
task.assigneeName
|
|
5879
|
+
] }),
|
|
5880
|
+
task.departmentName && /* @__PURE__ */ jsxs23(Fragment2, { children: [
|
|
5881
|
+
/* @__PURE__ */ jsx77("span", { className: "text-gray-300", children: "\xB7" }),
|
|
5882
|
+
/* @__PURE__ */ jsx77("span", { className: "text-gray-400", children: task.departmentName })
|
|
5883
|
+
] })
|
|
5884
|
+
] }),
|
|
5885
|
+
!compactMode && showRemarks && task.comments && /* @__PURE__ */ jsxs23("div", { className: "mt-2 bg-gray-50 rounded-md p-3 text-sm text-gray-600 italic", children: [
|
|
5886
|
+
"\u{1F4AC} \u201C",
|
|
5887
|
+
task.comments,
|
|
5888
|
+
"\u201D"
|
|
5889
|
+
] }),
|
|
5890
|
+
!compactMode && phase === "active" && !task.comments && /* @__PURE__ */ jsx77("div", { className: "mt-2 text-xs text-gray-400", children: "\u23F3 \u7B49\u5F85\u5904\u7406\u4E2D..." }),
|
|
5891
|
+
!compactMode && (task.actionAt || task.createdAt) && /* @__PURE__ */ jsxs23("div", { className: "mt-2 text-xs text-gray-400", children: [
|
|
5892
|
+
"\u{1F550} ",
|
|
5893
|
+
task.actionAt || task.createdAt
|
|
5894
|
+
] }),
|
|
5895
|
+
compactMode && (task.actionAt || task.createdAt) && /* @__PURE__ */ jsx77("div", { className: "mt-1 text-xs text-gray-400", children: task.actionAt || task.createdAt })
|
|
5896
|
+
]
|
|
5897
|
+
}
|
|
5898
|
+
) })
|
|
5899
|
+
] }, task.taskId);
|
|
5900
|
+
}) });
|
|
5901
|
+
};
|
|
5902
|
+
|
|
5903
|
+
// src/modules/ApprovalActions.tsx
|
|
5904
|
+
import { useState as useState27 } from "react";
|
|
5905
|
+
import { Button as Button5, Drawer, Input as Input8, Dropdown } from "antd";
|
|
5906
|
+
import { MoreOutlined, LoadingOutlined } from "@ant-design/icons";
|
|
5907
|
+
import { Fragment as Fragment3, jsx as jsx78, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5908
|
+
var { TextArea: TextArea4 } = Input8;
|
|
5909
|
+
var ApprovalActions = ({
|
|
5910
|
+
actions,
|
|
5911
|
+
onApprove,
|
|
5912
|
+
onReject,
|
|
5913
|
+
onTransfer,
|
|
5914
|
+
onReturn,
|
|
5915
|
+
onWithdraw,
|
|
5916
|
+
onSave,
|
|
5917
|
+
layout = "horizontal",
|
|
5918
|
+
maxVisible = 3,
|
|
5919
|
+
className = ""
|
|
5920
|
+
}) => {
|
|
5921
|
+
const [drawerAction, setDrawerAction] = useState27(null);
|
|
5922
|
+
const [comments, setComments] = useState27("");
|
|
5923
|
+
const [loading, setLoading] = useState27(false);
|
|
5924
|
+
const [saveLoading, setSaveLoading] = useState27(false);
|
|
5925
|
+
const handleOpenDrawer = (action) => {
|
|
5926
|
+
setComments("");
|
|
5927
|
+
setDrawerAction(action);
|
|
5928
|
+
};
|
|
5929
|
+
const handleConfirm = async () => {
|
|
5930
|
+
setLoading(true);
|
|
5931
|
+
try {
|
|
5932
|
+
if (drawerAction === "approve" && onApprove) {
|
|
5933
|
+
await onApprove(comments || void 0);
|
|
5934
|
+
} else if (drawerAction === "reject" && onReject) {
|
|
5935
|
+
await onReject(comments || void 0);
|
|
5936
|
+
} else if (drawerAction === "withdraw" && onWithdraw) {
|
|
5937
|
+
await onWithdraw(comments || void 0);
|
|
5938
|
+
}
|
|
5939
|
+
setDrawerAction(null);
|
|
5940
|
+
} finally {
|
|
5941
|
+
setLoading(false);
|
|
5942
|
+
}
|
|
5943
|
+
};
|
|
5944
|
+
const handleSave = async () => {
|
|
5945
|
+
if (!onSave) return;
|
|
5946
|
+
setSaveLoading(true);
|
|
5947
|
+
try {
|
|
5948
|
+
await onSave();
|
|
5949
|
+
} finally {
|
|
5950
|
+
setSaveLoading(false);
|
|
5951
|
+
}
|
|
5952
|
+
};
|
|
5953
|
+
const actionMap = {};
|
|
5954
|
+
actions.forEach((action) => {
|
|
5955
|
+
switch (action.action) {
|
|
5956
|
+
case "agree":
|
|
5957
|
+
actionMap["agree"] = {
|
|
5958
|
+
label: action.name.zh_CN || "\u540C\u610F",
|
|
5959
|
+
handler: () => handleOpenDrawer("approve"),
|
|
5960
|
+
type: "primary",
|
|
5961
|
+
color: "green"
|
|
5962
|
+
};
|
|
5963
|
+
break;
|
|
5964
|
+
case "rejected":
|
|
5965
|
+
actionMap["rejected"] = {
|
|
5966
|
+
label: action.name.zh_CN || "\u62D2\u7EDD",
|
|
5967
|
+
handler: () => handleOpenDrawer("reject"),
|
|
5968
|
+
type: "default"
|
|
5969
|
+
};
|
|
5970
|
+
break;
|
|
5971
|
+
case "transfer":
|
|
5972
|
+
actionMap["transfer"] = {
|
|
5973
|
+
label: action.name.zh_CN || "\u8F6C\u4EA4",
|
|
5974
|
+
handler: () => onTransfer?.(),
|
|
5975
|
+
type: "default"
|
|
5976
|
+
};
|
|
5977
|
+
break;
|
|
5978
|
+
case "return":
|
|
5979
|
+
actionMap["return"] = {
|
|
5980
|
+
label: action.name.zh_CN || "\u9000\u56DE",
|
|
5981
|
+
handler: () => onReturn?.(),
|
|
5982
|
+
type: "default"
|
|
5983
|
+
};
|
|
5984
|
+
break;
|
|
5985
|
+
case "withdraw":
|
|
5986
|
+
actionMap["withdraw"] = {
|
|
5987
|
+
label: action.name.zh_CN || "\u64A4\u9500",
|
|
5988
|
+
handler: () => handleOpenDrawer("withdraw"),
|
|
5989
|
+
type: "default"
|
|
5990
|
+
};
|
|
5991
|
+
break;
|
|
5992
|
+
case "save":
|
|
5993
|
+
actionMap["save"] = {
|
|
5994
|
+
label: action.name.zh_CN || "\u6682\u5B58",
|
|
5995
|
+
handler: handleSave,
|
|
5996
|
+
type: "default"
|
|
5997
|
+
};
|
|
5998
|
+
break;
|
|
5999
|
+
}
|
|
6000
|
+
});
|
|
6001
|
+
const allButtons = Object.entries(actionMap);
|
|
6002
|
+
const visibleButtons = allButtons.slice(0, maxVisible);
|
|
6003
|
+
const moreButtons = allButtons.slice(maxVisible);
|
|
6004
|
+
const drawerTitle = drawerAction === "approve" ? "\u5BA1\u6279\u610F\u89C1" : drawerAction === "reject" ? "\u62D2\u7EDD\u7406\u7531" : drawerAction === "withdraw" ? "\u64A4\u9500\u539F\u56E0" : "\u5BA1\u6279\u610F\u89C1";
|
|
6005
|
+
return /* @__PURE__ */ jsxs24(Fragment3, { children: [
|
|
6006
|
+
/* @__PURE__ */ jsxs24(
|
|
6007
|
+
"div",
|
|
6008
|
+
{
|
|
6009
|
+
className: `${layout === "horizontal" ? "flex items-center gap-3" : "flex flex-col gap-2"} ${className}`,
|
|
6010
|
+
children: [
|
|
6011
|
+
visibleButtons.map(([key, btn]) => /* @__PURE__ */ jsx78(
|
|
6012
|
+
Button5,
|
|
6013
|
+
{
|
|
6014
|
+
type: btn.type === "primary" ? "primary" : "default",
|
|
6015
|
+
className: btn.color === "green" ? "!bg-green-600 !border-green-600 hover:!bg-green-700" : "",
|
|
6016
|
+
onClick: btn.handler,
|
|
6017
|
+
loading: key === "save" && saveLoading,
|
|
6018
|
+
children: btn.label
|
|
6019
|
+
},
|
|
6020
|
+
key
|
|
6021
|
+
)),
|
|
6022
|
+
moreButtons.length > 0 && /* @__PURE__ */ jsx78(
|
|
6023
|
+
Dropdown,
|
|
6024
|
+
{
|
|
6025
|
+
menu: {
|
|
6026
|
+
items: moreButtons.map(([key, btn]) => ({
|
|
6027
|
+
key,
|
|
6028
|
+
label: btn.label,
|
|
6029
|
+
onClick: btn.handler
|
|
6030
|
+
}))
|
|
6031
|
+
},
|
|
6032
|
+
trigger: ["click"],
|
|
6033
|
+
children: /* @__PURE__ */ jsx78(Button5, { icon: /* @__PURE__ */ jsx78(MoreOutlined, {}), children: "\u66F4\u591A" })
|
|
6034
|
+
}
|
|
6035
|
+
)
|
|
6036
|
+
]
|
|
6037
|
+
}
|
|
6038
|
+
),
|
|
6039
|
+
/* @__PURE__ */ jsx78(
|
|
6040
|
+
Drawer,
|
|
6041
|
+
{
|
|
6042
|
+
title: drawerTitle,
|
|
6043
|
+
open: drawerAction !== null,
|
|
6044
|
+
onClose: () => setDrawerAction(null),
|
|
6045
|
+
width: 400,
|
|
6046
|
+
footer: /* @__PURE__ */ jsxs24("div", { className: "flex justify-end gap-3", children: [
|
|
6047
|
+
/* @__PURE__ */ jsx78(Button5, { onClick: () => setDrawerAction(null), children: "\u53D6\u6D88" }),
|
|
6048
|
+
/* @__PURE__ */ jsxs24(Button5, { type: "primary", onClick: handleConfirm, loading, children: [
|
|
6049
|
+
loading && /* @__PURE__ */ jsx78(LoadingOutlined, {}),
|
|
6050
|
+
"\u786E\u8BA4"
|
|
6051
|
+
] })
|
|
6052
|
+
] }),
|
|
6053
|
+
children: /* @__PURE__ */ jsx78("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs24("div", { children: [
|
|
6054
|
+
/* @__PURE__ */ jsx78("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: drawerAction === "approve" ? "\u5BA1\u6279\u610F\u89C1\uFF08\u53EF\u9009\uFF09" : "\u8BF7\u8F93\u5165\u7406\u7531" }),
|
|
6055
|
+
/* @__PURE__ */ jsx78(
|
|
6056
|
+
TextArea4,
|
|
6057
|
+
{
|
|
6058
|
+
rows: 4,
|
|
6059
|
+
value: comments,
|
|
6060
|
+
onChange: (e) => setComments(e.target.value),
|
|
6061
|
+
placeholder: drawerAction === "approve" ? "\u8BF7\u8F93\u5165\u5BA1\u6279\u610F\u89C1..." : drawerAction === "reject" ? "\u8BF7\u8F93\u5165\u62D2\u7EDD\u7406\u7531..." : "\u8BF7\u8F93\u5165\u64A4\u9500\u539F\u56E0...",
|
|
6062
|
+
maxLength: 500,
|
|
6063
|
+
showCount: true
|
|
6064
|
+
}
|
|
6065
|
+
)
|
|
6066
|
+
] }) })
|
|
6067
|
+
}
|
|
6068
|
+
)
|
|
6069
|
+
] });
|
|
6070
|
+
};
|
|
6071
|
+
|
|
6072
|
+
// src/modules/FormActionBar.tsx
|
|
6073
|
+
import { useState as useState28 } from "react";
|
|
6074
|
+
import { Button as Button6, Modal as Modal2 } from "antd";
|
|
6075
|
+
import { Fragment as Fragment4, jsx as jsx79, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
6076
|
+
var FormActionBar = ({
|
|
6077
|
+
actions,
|
|
6078
|
+
position = "bottom-fixed",
|
|
6079
|
+
className = ""
|
|
6080
|
+
}) => {
|
|
6081
|
+
const [loadingKeys, setLoadingKeys] = useState28(/* @__PURE__ */ new Set());
|
|
6082
|
+
const visibleActions = actions.filter((a) => a.visible !== false);
|
|
6083
|
+
const sortedActions = [...visibleActions].sort((a, b) => {
|
|
6084
|
+
if (a.type === "danger" && b.type !== "danger") return -1;
|
|
6085
|
+
if (a.type !== "danger" && b.type === "danger") return 1;
|
|
6086
|
+
if (a.type === "primary" && b.type !== "primary") return 1;
|
|
6087
|
+
if (a.type !== "primary" && b.type === "primary") return -1;
|
|
6088
|
+
return 0;
|
|
6089
|
+
});
|
|
6090
|
+
const handleClick = async (action) => {
|
|
6091
|
+
if (action.confirm) {
|
|
6092
|
+
Modal2.confirm({
|
|
6093
|
+
title: action.confirm.title,
|
|
6094
|
+
content: action.confirm.content,
|
|
6095
|
+
okText: "\u786E\u8BA4",
|
|
6096
|
+
cancelText: "\u53D6\u6D88",
|
|
6097
|
+
onOk: async () => {
|
|
6098
|
+
await executeAction(action);
|
|
6099
|
+
}
|
|
6100
|
+
});
|
|
6101
|
+
} else {
|
|
6102
|
+
await executeAction(action);
|
|
6103
|
+
}
|
|
6104
|
+
};
|
|
6105
|
+
const executeAction = async (action) => {
|
|
6106
|
+
setLoadingKeys((prev) => new Set(prev).add(action.key));
|
|
6107
|
+
try {
|
|
6108
|
+
await action.onClick();
|
|
6109
|
+
} finally {
|
|
6110
|
+
setLoadingKeys((prev) => {
|
|
6111
|
+
const next = new Set(prev);
|
|
6112
|
+
next.delete(action.key);
|
|
6113
|
+
return next;
|
|
6114
|
+
});
|
|
6115
|
+
}
|
|
6116
|
+
};
|
|
6117
|
+
const isFixed = position === "bottom-fixed";
|
|
6118
|
+
const bar = /* @__PURE__ */ jsx79(
|
|
6119
|
+
"div",
|
|
6120
|
+
{
|
|
6121
|
+
className: `${isFixed ? "fixed bottom-0 left-0 right-0 z-50 backdrop-blur-lg bg-white/80 border-t border-gray-200 shadow-[0_-1px_3px_rgba(0,0,0,0.05)] px-6 py-3" : ""} ${className}`,
|
|
6122
|
+
children: /* @__PURE__ */ jsx79("div", { className: "flex items-center justify-end gap-3 flex-wrap md:flex-nowrap", children: sortedActions.map((action) => {
|
|
6123
|
+
const isLoading = action.loading || loadingKeys.has(action.key);
|
|
6124
|
+
return /* @__PURE__ */ jsx79(
|
|
6125
|
+
Button6,
|
|
6126
|
+
{
|
|
6127
|
+
type: action.type === "danger" ? "primary" : action.type === "text" ? "text" : action.type || "default",
|
|
6128
|
+
danger: action.type === "danger",
|
|
6129
|
+
loading: isLoading,
|
|
6130
|
+
disabled: action.disabled,
|
|
6131
|
+
icon: action.icon,
|
|
6132
|
+
onClick: () => handleClick(action),
|
|
6133
|
+
className: "md:w-auto w-full",
|
|
6134
|
+
children: action.label
|
|
6135
|
+
},
|
|
6136
|
+
action.key
|
|
6137
|
+
);
|
|
6138
|
+
}) })
|
|
6139
|
+
}
|
|
6140
|
+
);
|
|
6141
|
+
if (isFixed) {
|
|
6142
|
+
return /* @__PURE__ */ jsxs25(Fragment4, { children: [
|
|
6143
|
+
bar,
|
|
6144
|
+
/* @__PURE__ */ jsx79("div", { className: "h-16" })
|
|
6145
|
+
] });
|
|
6146
|
+
}
|
|
6147
|
+
return bar;
|
|
6148
|
+
};
|
|
6149
|
+
|
|
6150
|
+
// src/modules/DraftManager.tsx
|
|
6151
|
+
import { Button as Button7 } from "antd";
|
|
6152
|
+
import { EditOutlined } from "@ant-design/icons";
|
|
6153
|
+
import { jsx as jsx80, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6154
|
+
function formatRelativeTime(timestamp) {
|
|
6155
|
+
const now = Date.now();
|
|
6156
|
+
const diff = now - timestamp;
|
|
6157
|
+
const minutes = Math.floor(diff / 6e4);
|
|
6158
|
+
const hours = Math.floor(diff / 36e5);
|
|
6159
|
+
const days = Math.floor(diff / 864e5);
|
|
6160
|
+
if (minutes < 1) return "\u521A\u521A";
|
|
6161
|
+
if (minutes < 60) return `${minutes}\u5206\u949F\u524D`;
|
|
6162
|
+
if (hours < 24) return `${hours}\u5C0F\u65F6\u524D`;
|
|
6163
|
+
return `${days}\u5929\u524D`;
|
|
6164
|
+
}
|
|
6165
|
+
var DraftManager = ({
|
|
6166
|
+
hasDraft,
|
|
6167
|
+
draftTimestamp,
|
|
6168
|
+
onRestore,
|
|
6169
|
+
onDiscard,
|
|
6170
|
+
className = ""
|
|
6171
|
+
}) => {
|
|
6172
|
+
if (!hasDraft) return null;
|
|
6173
|
+
const timeLabel = draftTimestamp ? formatRelativeTime(draftTimestamp) : null;
|
|
6174
|
+
return /* @__PURE__ */ jsx80(
|
|
6175
|
+
"div",
|
|
6176
|
+
{
|
|
6177
|
+
className: `bg-blue-50 border border-blue-200 rounded-lg p-4 animate-[slideDown_0.3s_ease-out] ${className}`,
|
|
6178
|
+
children: /* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between flex-wrap gap-3", children: [
|
|
6179
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2 text-sm text-blue-700", children: [
|
|
6180
|
+
/* @__PURE__ */ jsx80(EditOutlined, { className: "text-blue-500" }),
|
|
6181
|
+
/* @__PURE__ */ jsxs26("span", { children: [
|
|
6182
|
+
"\u68C0\u6D4B\u5230\u672A\u63D0\u4EA4\u7684\u8349\u7A3F",
|
|
6183
|
+
timeLabel && /* @__PURE__ */ jsxs26("span", { className: "text-blue-500 ml-1", children: [
|
|
6184
|
+
"\uFF08\u4FDD\u5B58\u4E8E ",
|
|
6185
|
+
timeLabel,
|
|
6186
|
+
"\uFF09"
|
|
6187
|
+
] })
|
|
6188
|
+
] })
|
|
6189
|
+
] }),
|
|
6190
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
6191
|
+
/* @__PURE__ */ jsx80(Button7, { type: "text", size: "small", onClick: onDiscard, className: "!text-gray-500", children: "\u4E22\u5F03" }),
|
|
6192
|
+
/* @__PURE__ */ jsx80(Button7, { type: "primary", size: "small", onClick: onRestore, children: "\u6062\u590D\u586B\u5199" })
|
|
6193
|
+
] })
|
|
6194
|
+
] })
|
|
6195
|
+
}
|
|
6196
|
+
);
|
|
6197
|
+
};
|
|
6198
|
+
|
|
6199
|
+
// src/modules/ProcessPreview.tsx
|
|
6200
|
+
import { Modal as Modal3, Skeleton as Skeleton2, Button as Button8 } from "antd";
|
|
6201
|
+
import { CheckCircleOutlined, UserOutlined } from "@ant-design/icons";
|
|
6202
|
+
import { jsx as jsx81, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
6203
|
+
var ProcessPreview = ({
|
|
6204
|
+
open,
|
|
6205
|
+
onClose,
|
|
6206
|
+
onConfirm,
|
|
6207
|
+
routes,
|
|
6208
|
+
loading = false
|
|
6209
|
+
}) => {
|
|
6210
|
+
return /* @__PURE__ */ jsx81(
|
|
6211
|
+
Modal3,
|
|
6212
|
+
{
|
|
6213
|
+
title: "\u6D41\u7A0B\u9884\u89C8",
|
|
6214
|
+
open,
|
|
6215
|
+
onCancel: onClose,
|
|
6216
|
+
width: 520,
|
|
6217
|
+
footer: /* @__PURE__ */ jsxs27("div", { className: "flex justify-end gap-3", children: [
|
|
6218
|
+
/* @__PURE__ */ jsx81(Button8, { onClick: onClose, children: "\u53D6\u6D88" }),
|
|
6219
|
+
/* @__PURE__ */ jsx81(Button8, { type: "primary", onClick: onConfirm, loading, children: "\u786E\u8BA4\u63D0\u4EA4" })
|
|
6220
|
+
] }),
|
|
6221
|
+
children: loading && routes.length === 0 ? /* @__PURE__ */ jsx81(Skeleton2, { active: true, paragraph: { rows: 4 } }) : routes.length === 0 ? /* @__PURE__ */ jsx81("p", { className: "text-sm text-gray-400 text-center py-8", children: "\u6682\u65E0\u6D41\u7A0B\u8282\u70B9" }) : /* @__PURE__ */ jsx81("div", { className: "py-2", children: routes.map((route, index) => {
|
|
6222
|
+
const isLast = index === routes.length - 1;
|
|
6223
|
+
return /* @__PURE__ */ jsxs27("div", { className: "flex gap-3", children: [
|
|
6224
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col items-center", children: [
|
|
6225
|
+
/* @__PURE__ */ jsx81("div", { className: "w-6 h-6 rounded-full bg-blue-50 border-2 border-blue-400 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx81(CheckCircleOutlined, { className: "text-blue-500 text-xs" }) }),
|
|
6226
|
+
!isLast && /* @__PURE__ */ jsx81("div", { className: "w-0.5 flex-1 bg-blue-200 mt-1" })
|
|
6227
|
+
] }),
|
|
6228
|
+
/* @__PURE__ */ jsxs27("div", { className: `flex-1 ${isLast ? "pb-0" : "pb-5"}`, children: [
|
|
6229
|
+
/* @__PURE__ */ jsx81("div", { className: "text-sm font-medium text-gray-900", children: route.nodeName }),
|
|
6230
|
+
route.assignees && route.assignees.length > 0 && /* @__PURE__ */ jsxs27("div", { className: "mt-1 flex items-center gap-1.5 flex-wrap", children: [
|
|
6231
|
+
/* @__PURE__ */ jsx81(UserOutlined, { className: "text-gray-400 text-xs" }),
|
|
6232
|
+
route.assignees.map((assignee) => /* @__PURE__ */ jsx81(
|
|
6233
|
+
"span",
|
|
6234
|
+
{
|
|
6235
|
+
className: "text-xs text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded",
|
|
6236
|
+
children: assignee.name
|
|
6237
|
+
},
|
|
6238
|
+
assignee.id
|
|
6239
|
+
))
|
|
6240
|
+
] })
|
|
6241
|
+
] })
|
|
6242
|
+
] }, route.nodeId);
|
|
6243
|
+
}) })
|
|
6244
|
+
}
|
|
6245
|
+
);
|
|
6246
|
+
};
|
|
6247
|
+
|
|
6248
|
+
// src/templates/FormSubmitTemplate.tsx
|
|
6249
|
+
import { useState as useState29, useCallback as useCallback13 } from "react";
|
|
6250
|
+
import { Button as Button9 } from "antd";
|
|
6251
|
+
import { CheckCircleFilled } from "@ant-design/icons";
|
|
6252
|
+
import { Fragment as Fragment5, jsx as jsx82, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6253
|
+
var SubmitSuccessCard = ({
|
|
6254
|
+
info,
|
|
6255
|
+
mode,
|
|
6256
|
+
isRedirecting,
|
|
6257
|
+
countdown,
|
|
6258
|
+
onContinue,
|
|
6259
|
+
onViewDetail,
|
|
6260
|
+
renderSuccess
|
|
6261
|
+
}) => {
|
|
6262
|
+
if (renderSuccess) {
|
|
6263
|
+
return /* @__PURE__ */ jsx82(Fragment5, { children: renderSuccess(info) });
|
|
6264
|
+
}
|
|
6265
|
+
return /* @__PURE__ */ jsx82("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: /* @__PURE__ */ jsxs28("div", { className: "flex flex-col items-center py-16 animate-[fadeIn_0.3s_ease-out,scaleIn_0.3s_ease-out]", children: [
|
|
6266
|
+
/* @__PURE__ */ jsx82("div", { className: "w-12 h-12 rounded-full bg-green-100 flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx82(CheckCircleFilled, { className: "text-2xl text-green-500" }) }),
|
|
6267
|
+
/* @__PURE__ */ jsx82("h2", { className: "text-lg font-semibold text-gray-900 mb-1", children: "\u63D0\u4EA4\u6210\u529F" }),
|
|
6268
|
+
/* @__PURE__ */ jsx82("p", { className: "text-sm text-gray-500 mb-6", children: info.message || "\u5DF2\u6210\u529F\u521B\u5EFA\u4E00\u6761\u65B0\u8BB0\u5F55" }),
|
|
6269
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-3", children: [
|
|
6270
|
+
(mode === "stay" || mode === "redirect") && /* @__PURE__ */ jsx82(Button9, { onClick: onContinue, children: "\u7EE7\u7EED\u63D0\u4EA4" }),
|
|
6271
|
+
/* @__PURE__ */ jsx82(Button9, { type: "primary", onClick: onViewDetail, children: "\u67E5\u770B\u8BE6\u60C5" })
|
|
6272
|
+
] }),
|
|
6273
|
+
isRedirecting && /* @__PURE__ */ jsxs28("div", { className: "mt-6 w-48", children: [
|
|
6274
|
+
/* @__PURE__ */ jsxs28("div", { className: "text-xs text-gray-400 text-center mb-1", children: [
|
|
6275
|
+
countdown,
|
|
6276
|
+
"\u79D2\u540E\u81EA\u52A8\u8DF3\u8F6C"
|
|
6277
|
+
] }),
|
|
6278
|
+
/* @__PURE__ */ jsx82("div", { className: "h-1 bg-gray-200 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx82(
|
|
6279
|
+
"div",
|
|
6280
|
+
{
|
|
6281
|
+
className: "h-full bg-blue-500 transition-all duration-1000",
|
|
6282
|
+
style: { width: `${countdown / 3 * 100}%` }
|
|
6283
|
+
}
|
|
6284
|
+
) })
|
|
6285
|
+
] })
|
|
6286
|
+
] }) });
|
|
6287
|
+
};
|
|
6288
|
+
var InnerFormContent = ({
|
|
6289
|
+
schema,
|
|
6290
|
+
config,
|
|
6291
|
+
formType,
|
|
6292
|
+
submitSuccessMode,
|
|
6293
|
+
enableDraft,
|
|
6294
|
+
header,
|
|
6295
|
+
footer,
|
|
6296
|
+
beforeForm,
|
|
6297
|
+
afterForm,
|
|
6298
|
+
renderForm,
|
|
6299
|
+
renderSuccess,
|
|
6300
|
+
onSubmitSuccess
|
|
6301
|
+
}) => {
|
|
6302
|
+
const { validateAll, getFormData: getFormData2, resetForm } = useFormContext();
|
|
6303
|
+
const [submitted, setSubmitted] = useState29(false);
|
|
6304
|
+
const [successInfo, setSuccessInfo] = useState29(null);
|
|
6305
|
+
const [submitting, setSubmitting] = useState29(false);
|
|
6306
|
+
const { hasDraft, draftTimestamp, saveDraft, restoreDraft, clearDraft } = useDraftStorage({
|
|
6307
|
+
appType: config.appType,
|
|
6308
|
+
formUuid: config.formUuid
|
|
6309
|
+
});
|
|
6310
|
+
const { navigateToDetail, navigateToProcessDetail, isRedirecting, countdown, handlePostSubmit } = useFormNavigation({
|
|
6311
|
+
appType: config.appType,
|
|
6312
|
+
formUuid: config.formUuid,
|
|
6313
|
+
formType,
|
|
6314
|
+
mode: submitSuccessMode === "continue" ? "stay" : submitSuccessMode
|
|
6315
|
+
});
|
|
6316
|
+
const handleSubmit = useCallback13(async () => {
|
|
6317
|
+
const valid = await validateAll();
|
|
6318
|
+
if (!valid) return;
|
|
6319
|
+
setSubmitting(true);
|
|
6320
|
+
try {
|
|
6321
|
+
const formData = getFormData2();
|
|
6322
|
+
if (config.submit?.beforeSubmit) {
|
|
6323
|
+
const shouldContinue = await config.submit.beforeSubmit(formData);
|
|
6324
|
+
if (shouldContinue === false) {
|
|
6325
|
+
setSubmitting(false);
|
|
6326
|
+
return;
|
|
6327
|
+
}
|
|
6328
|
+
}
|
|
6329
|
+
const formInstId = `inst_${Date.now()}`;
|
|
6330
|
+
if (config.submit?.afterSubmit) {
|
|
6331
|
+
await config.submit.afterSubmit({ formInstanceId: formInstId, data: formData });
|
|
6332
|
+
}
|
|
6333
|
+
if (enableDraft) {
|
|
6334
|
+
clearDraft();
|
|
6335
|
+
}
|
|
6336
|
+
onSubmitSuccess?.(formInstId);
|
|
6337
|
+
if (submitSuccessMode === "continue") {
|
|
6338
|
+
resetForm();
|
|
6339
|
+
} else {
|
|
6340
|
+
setSuccessInfo({ formInstanceId: formInstId });
|
|
6341
|
+
setSubmitted(true);
|
|
6342
|
+
handlePostSubmit(formInstId);
|
|
6343
|
+
}
|
|
6344
|
+
} catch (error) {
|
|
6345
|
+
console.error("[FormSubmitTemplate] Submit failed:", error);
|
|
6346
|
+
} finally {
|
|
6347
|
+
setSubmitting(false);
|
|
6348
|
+
}
|
|
6349
|
+
}, [
|
|
6350
|
+
validateAll,
|
|
6351
|
+
getFormData2,
|
|
6352
|
+
config,
|
|
6353
|
+
enableDraft,
|
|
6354
|
+
clearDraft,
|
|
6355
|
+
onSubmitSuccess,
|
|
6356
|
+
submitSuccessMode,
|
|
6357
|
+
resetForm,
|
|
6358
|
+
handlePostSubmit
|
|
6359
|
+
]);
|
|
6360
|
+
const handleSaveDraft = useCallback13(() => {
|
|
6361
|
+
const data = getFormData2();
|
|
6362
|
+
saveDraft(data);
|
|
6363
|
+
}, [getFormData2, saveDraft]);
|
|
6364
|
+
const handleRestoreDraft = useCallback13(() => {
|
|
6365
|
+
restoreDraft();
|
|
6366
|
+
}, [restoreDraft]);
|
|
6367
|
+
const handleContinue = useCallback13(() => {
|
|
6368
|
+
setSubmitted(false);
|
|
6369
|
+
setSuccessInfo(null);
|
|
6370
|
+
resetForm();
|
|
6371
|
+
}, [resetForm]);
|
|
6372
|
+
const handleViewDetail = useCallback13(() => {
|
|
6373
|
+
if (!successInfo) return;
|
|
6374
|
+
if (formType === "process") {
|
|
6375
|
+
navigateToProcessDetail(successInfo.formInstanceId);
|
|
6376
|
+
} else {
|
|
6377
|
+
navigateToDetail(successInfo.formInstanceId);
|
|
6378
|
+
}
|
|
6379
|
+
}, [successInfo, formType, navigateToDetail, navigateToProcessDetail]);
|
|
6380
|
+
const actions = [];
|
|
6381
|
+
if (enableDraft) {
|
|
6382
|
+
actions.push({
|
|
6383
|
+
key: "draft",
|
|
6384
|
+
label: "\u6682\u5B58",
|
|
6385
|
+
type: "default",
|
|
6386
|
+
onClick: handleSaveDraft
|
|
6387
|
+
});
|
|
6388
|
+
}
|
|
6389
|
+
actions.push({
|
|
6390
|
+
key: "reset",
|
|
6391
|
+
label: "\u91CD\u7F6E",
|
|
6392
|
+
type: "default",
|
|
6393
|
+
onClick: () => resetForm()
|
|
6394
|
+
});
|
|
6395
|
+
actions.push({
|
|
6396
|
+
key: "submit",
|
|
6397
|
+
label: "\u63D0\u4EA4",
|
|
6398
|
+
type: "primary",
|
|
6399
|
+
loading: submitting,
|
|
6400
|
+
onClick: handleSubmit
|
|
6401
|
+
});
|
|
6402
|
+
return /* @__PURE__ */ jsxs28("div", { className: "min-h-screen bg-gray-50/50", children: [
|
|
6403
|
+
/* @__PURE__ */ jsxs28("div", { className: "max-w-4xl mx-auto py-8 px-6 pb-24", children: [
|
|
6404
|
+
header || /* @__PURE__ */ jsxs28("div", { className: "mb-6", children: [
|
|
6405
|
+
/* @__PURE__ */ jsx82("h1", { className: "text-2xl font-bold text-gray-900", children: schema.formMeta.title }),
|
|
6406
|
+
/* @__PURE__ */ jsx82("p", { className: "text-sm text-gray-500 mt-1", children: "\u8BF7\u586B\u5199\u4EE5\u4E0B\u4FE1\u606F" })
|
|
6407
|
+
] }),
|
|
6408
|
+
enableDraft && hasDraft && !submitted && /* @__PURE__ */ jsx82("div", { className: "mb-6", children: /* @__PURE__ */ jsx82(
|
|
6409
|
+
DraftManager,
|
|
6410
|
+
{
|
|
6411
|
+
hasDraft,
|
|
6412
|
+
draftTimestamp,
|
|
6413
|
+
onRestore: handleRestoreDraft,
|
|
6414
|
+
onDiscard: clearDraft
|
|
6415
|
+
}
|
|
6416
|
+
) }),
|
|
6417
|
+
!submitted ? /* @__PURE__ */ jsxs28("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6 animate-[fadeIn_0.2s_ease-out]", children: [
|
|
6418
|
+
beforeForm,
|
|
6419
|
+
renderForm ? renderForm({ schema, config }) : /* @__PURE__ */ jsx82(FormRenderer, { columns: 2 }),
|
|
6420
|
+
afterForm
|
|
6421
|
+
] }) : successInfo && /* @__PURE__ */ jsx82(
|
|
6422
|
+
SubmitSuccessCard,
|
|
6423
|
+
{
|
|
6424
|
+
info: successInfo,
|
|
6425
|
+
mode: submitSuccessMode,
|
|
6426
|
+
isRedirecting,
|
|
6427
|
+
countdown,
|
|
6428
|
+
onContinue: handleContinue,
|
|
6429
|
+
onViewDetail: handleViewDetail,
|
|
6430
|
+
renderSuccess
|
|
6431
|
+
}
|
|
6432
|
+
),
|
|
6433
|
+
footer
|
|
6434
|
+
] }),
|
|
6435
|
+
!submitted && /* @__PURE__ */ jsx82(FormActionBar, { actions, position: "bottom-fixed" })
|
|
6436
|
+
] });
|
|
6437
|
+
};
|
|
6438
|
+
var FormSubmitTemplate = ({
|
|
6439
|
+
schema,
|
|
6440
|
+
config,
|
|
6441
|
+
formType = "form",
|
|
6442
|
+
submitSuccessMode = "redirect",
|
|
6443
|
+
enableDraft = false,
|
|
6444
|
+
header,
|
|
6445
|
+
footer,
|
|
6446
|
+
beforeForm,
|
|
6447
|
+
afterForm,
|
|
6448
|
+
renderForm,
|
|
6449
|
+
renderSuccess,
|
|
6450
|
+
onSubmitSuccess
|
|
6451
|
+
}) => {
|
|
6452
|
+
return /* @__PURE__ */ jsx82(FormProvider, { schema, config, children: /* @__PURE__ */ jsx82(
|
|
6453
|
+
InnerFormContent,
|
|
6454
|
+
{
|
|
6455
|
+
schema,
|
|
6456
|
+
config,
|
|
6457
|
+
formType,
|
|
6458
|
+
submitSuccessMode,
|
|
6459
|
+
enableDraft,
|
|
6460
|
+
header,
|
|
6461
|
+
footer,
|
|
6462
|
+
beforeForm,
|
|
6463
|
+
afterForm,
|
|
6464
|
+
renderForm,
|
|
6465
|
+
renderSuccess,
|
|
6466
|
+
onSubmitSuccess
|
|
6467
|
+
}
|
|
6468
|
+
) });
|
|
6469
|
+
};
|
|
6470
|
+
|
|
6471
|
+
// src/templates/FormDetailTemplate.tsx
|
|
6472
|
+
import { useCallback as useCallback14 } from "react";
|
|
6473
|
+
|
|
6474
|
+
// src/templates/PageSkeleton.tsx
|
|
6475
|
+
import { Skeleton as Skeleton3 } from "antd";
|
|
6476
|
+
import { jsx as jsx83, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
6477
|
+
var CardSkeleton = ({ children }) => /* @__PURE__ */ jsx83("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children });
|
|
6478
|
+
var SummaryCardSkeleton = () => /* @__PURE__ */ jsxs29(CardSkeleton, { children: [
|
|
6479
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex items-start justify-between", children: [
|
|
6480
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex-1", children: [
|
|
6481
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "large", style: { width: 200 } }),
|
|
6482
|
+
/* @__PURE__ */ jsx83("div", { className: "mt-2", children: /* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "small", style: { width: 80 } }) })
|
|
6483
|
+
] }),
|
|
6484
|
+
/* @__PURE__ */ jsx83(Skeleton3.Button, { active: true, size: "small", shape: "round", style: { width: 60 } })
|
|
6485
|
+
] }),
|
|
6486
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-3 mt-4", children: [
|
|
6487
|
+
/* @__PURE__ */ jsx83(Skeleton3.Avatar, { active: true, size: "small" }),
|
|
6488
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "small", style: { width: 120 } })
|
|
6489
|
+
] })
|
|
6490
|
+
] });
|
|
6491
|
+
var FormGridSkeleton = () => /* @__PURE__ */ jsx83(CardSkeleton, { children: /* @__PURE__ */ jsx83("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-5", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs29("div", { className: "space-y-2", children: [
|
|
6492
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "small", style: { width: 80 } }),
|
|
6493
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, block: true, style: { width: "100%" } })
|
|
6494
|
+
] }, i)) }) });
|
|
6495
|
+
var ActionBarSkeleton = () => /* @__PURE__ */ jsx83("div", { className: "fixed bottom-0 left-0 right-0 backdrop-blur-lg bg-white/80 border-t border-gray-200 px-6 py-3", children: /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-end gap-3", children: [
|
|
6496
|
+
/* @__PURE__ */ jsx83(Skeleton3.Button, { active: true, style: { width: 80 } }),
|
|
6497
|
+
/* @__PURE__ */ jsx83(Skeleton3.Button, { active: true, style: { width: 80 } })
|
|
6498
|
+
] }) });
|
|
6499
|
+
var TimelineSkeleton = () => /* @__PURE__ */ jsxs29(CardSkeleton, { children: [
|
|
6500
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "default", style: { width: 100, marginBottom: 16 } }),
|
|
6501
|
+
/* @__PURE__ */ jsx83("div", { className: "space-y-4", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs29("div", { className: "flex gap-4", children: [
|
|
6502
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col items-center", children: [
|
|
6503
|
+
/* @__PURE__ */ jsx83("div", { className: "w-3 h-3 rounded-full bg-gray-200 animate-pulse" }),
|
|
6504
|
+
i < 2 && /* @__PURE__ */ jsx83("div", { className: "w-0.5 flex-1 bg-gray-200 mt-1" })
|
|
6505
|
+
] }),
|
|
6506
|
+
/* @__PURE__ */ jsx83("div", { className: "flex-1 pb-4", children: /* @__PURE__ */ jsx83(Skeleton3, { active: true, paragraph: { rows: 1 }, title: { width: "60%" } }) })
|
|
6507
|
+
] }, i)) })
|
|
6508
|
+
] });
|
|
6509
|
+
var PageSkeleton = ({ type }) => {
|
|
6510
|
+
if (type === "submit") {
|
|
6511
|
+
return /* @__PURE__ */ jsxs29("div", { className: "space-y-6", children: [
|
|
6512
|
+
/* @__PURE__ */ jsxs29("div", { className: "space-y-2", children: [
|
|
6513
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "large", style: { width: 200 } }),
|
|
6514
|
+
/* @__PURE__ */ jsx83(Skeleton3.Input, { active: true, size: "small", style: { width: 300 } })
|
|
6515
|
+
] }),
|
|
6516
|
+
/* @__PURE__ */ jsx83(FormGridSkeleton, {}),
|
|
6517
|
+
/* @__PURE__ */ jsx83(ActionBarSkeleton, {})
|
|
6518
|
+
] });
|
|
6519
|
+
}
|
|
6520
|
+
if (type === "detail") {
|
|
6521
|
+
return /* @__PURE__ */ jsxs29("div", { className: "space-y-6", children: [
|
|
6522
|
+
/* @__PURE__ */ jsx83(SummaryCardSkeleton, {}),
|
|
6523
|
+
/* @__PURE__ */ jsx83(FormGridSkeleton, {}),
|
|
6524
|
+
/* @__PURE__ */ jsx83(ActionBarSkeleton, {})
|
|
6525
|
+
] });
|
|
6526
|
+
}
|
|
6527
|
+
return /* @__PURE__ */ jsxs29("div", { className: "space-y-6", children: [
|
|
6528
|
+
/* @__PURE__ */ jsx83(SummaryCardSkeleton, {}),
|
|
6529
|
+
/* @__PURE__ */ jsx83(FormGridSkeleton, {}),
|
|
6530
|
+
/* @__PURE__ */ jsx83(TimelineSkeleton, {}),
|
|
6531
|
+
/* @__PURE__ */ jsx83(ActionBarSkeleton, {})
|
|
6532
|
+
] });
|
|
6533
|
+
};
|
|
6534
|
+
|
|
6535
|
+
// src/templates/FormDetailTemplate.tsx
|
|
6536
|
+
import { Fragment as Fragment6, jsx as jsx84, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6537
|
+
var InnerDetailContent = ({
|
|
6538
|
+
schema,
|
|
6539
|
+
formUuid,
|
|
6540
|
+
appType,
|
|
6541
|
+
formInstanceId,
|
|
6542
|
+
enableEdit = true,
|
|
6543
|
+
enableDelete = false,
|
|
6544
|
+
enableChangeRecords = false,
|
|
6545
|
+
header,
|
|
6546
|
+
footer,
|
|
6547
|
+
renderSummary,
|
|
6548
|
+
renderActions,
|
|
6549
|
+
onDelete,
|
|
6550
|
+
onSave
|
|
6551
|
+
}) => {
|
|
6552
|
+
const {
|
|
6553
|
+
loading,
|
|
6554
|
+
mode,
|
|
6555
|
+
formData,
|
|
6556
|
+
instanceInfo,
|
|
6557
|
+
fieldBehaviors,
|
|
6558
|
+
switchToEdit,
|
|
6559
|
+
switchToReadonly,
|
|
6560
|
+
saveChanges,
|
|
6561
|
+
deleteInstance,
|
|
6562
|
+
canEdit,
|
|
6563
|
+
canDelete,
|
|
6564
|
+
canViewChangeRecords
|
|
6565
|
+
} = useFormDetail({ formUuid, appType, formInstanceId });
|
|
6566
|
+
const {
|
|
6567
|
+
records,
|
|
6568
|
+
loading: recordsLoading,
|
|
6569
|
+
hasMore,
|
|
6570
|
+
loadMore,
|
|
6571
|
+
refresh: refreshRecords
|
|
6572
|
+
} = useChangeRecords({
|
|
6573
|
+
formUuid,
|
|
6574
|
+
appType,
|
|
6575
|
+
formInstanceId,
|
|
6576
|
+
autoLoad: enableChangeRecords && canViewChangeRecords
|
|
6577
|
+
});
|
|
6578
|
+
const handleSave = useCallback14(async () => {
|
|
6579
|
+
if (!formData) return;
|
|
6580
|
+
const success = await saveChanges(formData);
|
|
6581
|
+
if (success) {
|
|
6582
|
+
onSave?.(formData);
|
|
6583
|
+
}
|
|
6584
|
+
}, [formData, saveChanges, onSave]);
|
|
6585
|
+
const handleDelete = useCallback14(async () => {
|
|
6586
|
+
const success = await deleteInstance();
|
|
6587
|
+
if (success) {
|
|
6588
|
+
onDelete?.();
|
|
6589
|
+
}
|
|
6590
|
+
}, [deleteInstance, onDelete]);
|
|
6591
|
+
const handleCancel = useCallback14(() => {
|
|
6592
|
+
switchToReadonly();
|
|
6593
|
+
}, [switchToReadonly]);
|
|
6594
|
+
const readonlyActions = [];
|
|
6595
|
+
if (enableEdit && canEdit) {
|
|
6596
|
+
readonlyActions.push({
|
|
6597
|
+
key: "edit",
|
|
6598
|
+
label: "\u7F16\u8F91",
|
|
6599
|
+
type: "primary",
|
|
6600
|
+
onClick: switchToEdit
|
|
6601
|
+
});
|
|
6602
|
+
}
|
|
6603
|
+
if (enableDelete && canDelete) {
|
|
6604
|
+
readonlyActions.push({
|
|
6605
|
+
key: "delete",
|
|
6606
|
+
label: "\u5220\u9664",
|
|
6607
|
+
type: "danger",
|
|
6608
|
+
onClick: handleDelete,
|
|
6609
|
+
confirm: { title: "\u786E\u8BA4\u5220\u9664", content: "\u5220\u9664\u540E\u5C06\u65E0\u6CD5\u6062\u590D\uFF0C\u786E\u8BA4\u8981\u5220\u9664\u5417\uFF1F" }
|
|
6610
|
+
});
|
|
6611
|
+
}
|
|
6612
|
+
const editActions = [
|
|
6613
|
+
{ key: "cancel", label: "\u53D6\u6D88", type: "default", onClick: handleCancel },
|
|
6614
|
+
{ key: "save", label: "\u4FDD\u5B58", type: "primary", onClick: handleSave }
|
|
6615
|
+
];
|
|
6616
|
+
const currentActions = mode === "readonly" ? readonlyActions : editActions;
|
|
6617
|
+
const formConfig = {
|
|
6618
|
+
mode: mode === "edit" ? "edit" : "readonly",
|
|
6619
|
+
formUuid,
|
|
6620
|
+
appType,
|
|
6621
|
+
formInstanceId,
|
|
6622
|
+
permissions: {
|
|
6623
|
+
fieldPermissions: fieldBehaviors,
|
|
6624
|
+
operations: []
|
|
6625
|
+
}
|
|
6626
|
+
};
|
|
6627
|
+
if (loading) {
|
|
6628
|
+
return /* @__PURE__ */ jsx84("div", { className: "min-h-screen bg-gray-50/50", children: /* @__PURE__ */ jsx84("div", { className: "max-w-4xl mx-auto py-8 px-6 pb-24", children: /* @__PURE__ */ jsx84(PageSkeleton, { type: "detail" }) }) });
|
|
6629
|
+
}
|
|
6630
|
+
return /* @__PURE__ */ jsxs30("div", { className: "min-h-screen bg-gray-50/50", children: [
|
|
6631
|
+
/* @__PURE__ */ jsx84("div", { className: "max-w-4xl mx-auto py-8 px-6 pb-24 space-y-6", children: /* @__PURE__ */ jsxs30("div", { className: "animate-[fadeIn_0.2s_ease-out]", children: [
|
|
6632
|
+
header,
|
|
6633
|
+
renderSummary && instanceInfo ? renderSummary(instanceInfo) : /* @__PURE__ */ jsx84(
|
|
6634
|
+
FormSummaryCard,
|
|
6635
|
+
{
|
|
6636
|
+
title: schema.formMeta.title,
|
|
6637
|
+
formInstanceId,
|
|
6638
|
+
creator: instanceInfo?.creator ? {
|
|
6639
|
+
name: instanceInfo.creator.name,
|
|
6640
|
+
avatar: instanceInfo.creator.avatar,
|
|
6641
|
+
department: instanceInfo.creator.department
|
|
6642
|
+
} : void 0,
|
|
6643
|
+
createdAt: instanceInfo?.createdAt,
|
|
6644
|
+
status: mode === "edit" ? { label: "\u7F16\u8F91\u4E2D", tone: "brand" } : void 0
|
|
6645
|
+
}
|
|
6646
|
+
),
|
|
6647
|
+
mode === "edit" && /* @__PURE__ */ jsx84("div", { className: "bg-blue-50 border border-blue-200 rounded-lg px-4 py-3 text-sm text-blue-700 transition-all duration-150", children: "\u6B63\u5728\u7F16\u8F91\uFF0C\u4FEE\u6539\u540E\u8BF7\u4FDD\u5B58" }),
|
|
6648
|
+
/* @__PURE__ */ jsx84("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: /* @__PURE__ */ jsx84(FormProvider, { schema, config: formConfig, initialValues: formData ?? void 0, children: /* @__PURE__ */ jsx84(FormRenderer, { columns: 2 }) }) }),
|
|
6649
|
+
enableChangeRecords && canViewChangeRecords && /* @__PURE__ */ jsx84(
|
|
6650
|
+
ChangeRecords,
|
|
6651
|
+
{
|
|
6652
|
+
records,
|
|
6653
|
+
loading: recordsLoading,
|
|
6654
|
+
hasMore,
|
|
6655
|
+
onLoadMore: loadMore,
|
|
6656
|
+
onExpand: refreshRecords
|
|
6657
|
+
}
|
|
6658
|
+
),
|
|
6659
|
+
footer
|
|
6660
|
+
] }) }),
|
|
6661
|
+
currentActions.length > 0 && (renderActions ? /* @__PURE__ */ jsx84(Fragment6, { children: renderActions(currentActions) }) : /* @__PURE__ */ jsx84(FormActionBar, { position: "bottom-fixed", actions: currentActions }))
|
|
6662
|
+
] });
|
|
6663
|
+
};
|
|
6664
|
+
var FormDetailTemplate = (props) => {
|
|
6665
|
+
const { schema, formUuid, appType, formInstanceId } = props;
|
|
6666
|
+
const wrapperConfig = {
|
|
6667
|
+
mode: "readonly",
|
|
6668
|
+
formUuid,
|
|
6669
|
+
appType,
|
|
6670
|
+
formInstanceId
|
|
6671
|
+
};
|
|
6672
|
+
return /* @__PURE__ */ jsx84(FormProvider, { schema, config: wrapperConfig, children: /* @__PURE__ */ jsx84(InnerDetailContent, { ...props }) });
|
|
6673
|
+
};
|
|
6674
|
+
|
|
6675
|
+
// src/templates/ProcessDetailTemplate.tsx
|
|
6676
|
+
import { useCallback as useCallback15, useRef as useRef12 } from "react";
|
|
6677
|
+
import { Fragment as Fragment7, jsx as jsx85, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
6678
|
+
function FormDataBridge({
|
|
6679
|
+
formDataRef
|
|
6680
|
+
}) {
|
|
6681
|
+
const { getFormData: getFormData2 } = useFormContext();
|
|
6682
|
+
formDataRef.current = getFormData2;
|
|
6683
|
+
return null;
|
|
6684
|
+
}
|
|
6685
|
+
var InnerProcessContent = ({
|
|
6686
|
+
schema,
|
|
6687
|
+
formUuid,
|
|
6688
|
+
appType,
|
|
6689
|
+
formInstanceId,
|
|
6690
|
+
header,
|
|
6691
|
+
renderTimeline,
|
|
6692
|
+
renderActions,
|
|
6693
|
+
beforeForm,
|
|
6694
|
+
afterForm,
|
|
6695
|
+
onActionComplete
|
|
6696
|
+
}) => {
|
|
6697
|
+
const formDataRef = useRef12(void 0);
|
|
6698
|
+
const {
|
|
6699
|
+
loading,
|
|
6700
|
+
processInfo,
|
|
6701
|
+
processStatus,
|
|
6702
|
+
currentTask,
|
|
6703
|
+
progressList,
|
|
6704
|
+
formData,
|
|
6705
|
+
isApprover,
|
|
6706
|
+
activeActions,
|
|
6707
|
+
fieldBehaviors,
|
|
6708
|
+
mode,
|
|
6709
|
+
isOriginatorReturn,
|
|
6710
|
+
canWithdraw,
|
|
6711
|
+
switchToEdit,
|
|
6712
|
+
switchToReadonly,
|
|
6713
|
+
refreshProgress
|
|
6714
|
+
} = useProcessDetail({ formUuid, appType, formInstanceId });
|
|
6715
|
+
const { approve, reject, withdraw, save, resubmit } = useApprovalActions({
|
|
6716
|
+
formInstanceId,
|
|
6717
|
+
formUuid,
|
|
6718
|
+
appType,
|
|
6719
|
+
currentTaskId: currentTask?.taskId,
|
|
6720
|
+
onActionComplete: async (action) => {
|
|
6721
|
+
onActionComplete?.(action);
|
|
6722
|
+
await refreshProgress();
|
|
6723
|
+
},
|
|
6724
|
+
getFormValues: () => formDataRef.current?.() ?? {}
|
|
6725
|
+
});
|
|
6726
|
+
const handleApprove = useCallback15(
|
|
6727
|
+
async (comments) => {
|
|
6728
|
+
await approve(comments);
|
|
6729
|
+
},
|
|
6730
|
+
[approve]
|
|
6731
|
+
);
|
|
6732
|
+
const handleReject = useCallback15(
|
|
6733
|
+
async (comments) => {
|
|
6734
|
+
await reject(comments);
|
|
6735
|
+
},
|
|
6736
|
+
[reject]
|
|
6737
|
+
);
|
|
6738
|
+
const handleWithdraw = useCallback15(
|
|
6739
|
+
async (reason) => {
|
|
6740
|
+
await withdraw(reason);
|
|
6741
|
+
},
|
|
6742
|
+
[withdraw]
|
|
6743
|
+
);
|
|
6744
|
+
const handleSave = useCallback15(async () => {
|
|
6745
|
+
await save();
|
|
6746
|
+
}, [save]);
|
|
6747
|
+
const handleResubmit = useCallback15(async () => {
|
|
6748
|
+
await resubmit();
|
|
6749
|
+
}, [resubmit]);
|
|
6750
|
+
const buildActions = () => {
|
|
6751
|
+
const actions = [];
|
|
6752
|
+
if (isApprover && activeActions.length > 0) {
|
|
6753
|
+
return [];
|
|
6754
|
+
}
|
|
6755
|
+
if (isOriginatorReturn) {
|
|
6756
|
+
if (mode === "readonly") {
|
|
6757
|
+
actions.push({
|
|
6758
|
+
key: "edit",
|
|
6759
|
+
label: "\u7F16\u8F91",
|
|
6760
|
+
type: "primary",
|
|
6761
|
+
onClick: switchToEdit
|
|
6762
|
+
});
|
|
6763
|
+
} else {
|
|
6764
|
+
actions.push({
|
|
6765
|
+
key: "cancel",
|
|
6766
|
+
label: "\u53D6\u6D88",
|
|
6767
|
+
type: "default",
|
|
6768
|
+
onClick: switchToReadonly
|
|
6769
|
+
});
|
|
6770
|
+
actions.push({
|
|
6771
|
+
key: "resubmit",
|
|
6772
|
+
label: "\u91CD\u65B0\u63D0\u4EA4",
|
|
6773
|
+
type: "primary",
|
|
6774
|
+
onClick: handleResubmit
|
|
6775
|
+
});
|
|
6776
|
+
}
|
|
6777
|
+
return actions;
|
|
6778
|
+
}
|
|
6779
|
+
if (canWithdraw) {
|
|
6780
|
+
actions.push({
|
|
6781
|
+
key: "withdraw",
|
|
6782
|
+
label: "\u64A4\u9500",
|
|
6783
|
+
type: "default",
|
|
6784
|
+
onClick: () => handleWithdraw(),
|
|
6785
|
+
confirm: { title: "\u786E\u8BA4\u64A4\u9500", content: "\u786E\u8BA4\u8981\u64A4\u9500\u6B64\u6D41\u7A0B\u5417\uFF1F" }
|
|
6786
|
+
});
|
|
6787
|
+
}
|
|
6788
|
+
return actions;
|
|
6789
|
+
};
|
|
6790
|
+
const formConfig = {
|
|
6791
|
+
mode: mode === "edit" ? "edit" : "readonly",
|
|
6792
|
+
formUuid,
|
|
6793
|
+
appType,
|
|
6794
|
+
formInstanceId,
|
|
6795
|
+
permissions: {
|
|
6796
|
+
fieldPermissions: fieldBehaviors,
|
|
6797
|
+
operations: []
|
|
6798
|
+
}
|
|
6799
|
+
};
|
|
6800
|
+
if (loading) {
|
|
6801
|
+
return /* @__PURE__ */ jsx85("div", { className: "min-h-screen bg-gray-50/50", children: /* @__PURE__ */ jsx85("div", { className: "max-w-4xl mx-auto py-8 px-6 pb-24", children: /* @__PURE__ */ jsx85(PageSkeleton, { type: "process" }) }) });
|
|
6802
|
+
}
|
|
6803
|
+
const bottomActions = buildActions();
|
|
6804
|
+
const showApprovalActions = isApprover && activeActions.length > 0;
|
|
6805
|
+
return /* @__PURE__ */ jsxs31("div", { className: "min-h-screen bg-gray-50/50", children: [
|
|
6806
|
+
/* @__PURE__ */ jsx85("div", { className: "max-w-4xl mx-auto py-8 px-6 pb-24 space-y-6", children: /* @__PURE__ */ jsxs31("div", { className: "animate-[fadeIn_0.2s_ease-out]", children: [
|
|
6807
|
+
header,
|
|
6808
|
+
/* @__PURE__ */ jsx85(
|
|
6809
|
+
FormSummaryCard,
|
|
6810
|
+
{
|
|
6811
|
+
title: schema.formMeta.title,
|
|
6812
|
+
formInstanceId,
|
|
6813
|
+
creator: processInfo?.originatorName ? {
|
|
6814
|
+
name: processInfo.originatorName,
|
|
6815
|
+
department: processInfo.originatorDepartment
|
|
6816
|
+
} : void 0,
|
|
6817
|
+
createdAt: processInfo?.createdAt,
|
|
6818
|
+
status: processStatus ? PROCESS_STATUS_META[processStatus] : void 0
|
|
6819
|
+
}
|
|
6820
|
+
),
|
|
6821
|
+
beforeForm,
|
|
6822
|
+
mode === "edit" && /* @__PURE__ */ jsx85("div", { className: "bg-blue-50 border border-blue-200 rounded-lg px-4 py-3 text-sm text-blue-700 transition-all duration-150", children: "\u6B63\u5728\u7F16\u8F91\u8868\u5355\uFF0C\u4FEE\u6539\u540E\u8BF7\u91CD\u65B0\u63D0\u4EA4" }),
|
|
6823
|
+
/* @__PURE__ */ jsx85("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: /* @__PURE__ */ jsxs31(FormProvider, { schema, config: formConfig, initialValues: formData ?? void 0, children: [
|
|
6824
|
+
/* @__PURE__ */ jsx85(FormDataBridge, { formDataRef }),
|
|
6825
|
+
/* @__PURE__ */ jsx85(FormRenderer, { columns: 2 })
|
|
6826
|
+
] }) }),
|
|
6827
|
+
afterForm,
|
|
6828
|
+
/* @__PURE__ */ jsxs31("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
|
|
6829
|
+
/* @__PURE__ */ jsx85("h3", { className: "text-lg font-semibold text-gray-900 mb-4", children: "\u5BA1\u6279\u8FDB\u5EA6" }),
|
|
6830
|
+
renderTimeline ? renderTimeline(progressList) : /* @__PURE__ */ jsx85(ApprovalTimeline, { tasks: progressList, showRemarks: true })
|
|
6831
|
+
] })
|
|
6832
|
+
] }) }),
|
|
6833
|
+
showApprovalActions && (renderActions ? /* @__PURE__ */ jsx85(Fragment7, { children: renderActions(activeActions) }) : /* @__PURE__ */ jsx85("div", { className: "fixed bottom-0 left-0 right-0 z-50 backdrop-blur-lg bg-white/80 border-t border-gray-200 shadow-[0_-1px_3px_rgba(0,0,0,0.05)] px-6 py-3", children: /* @__PURE__ */ jsx85("div", { className: "max-w-4xl mx-auto flex items-center justify-end", children: /* @__PURE__ */ jsx85(
|
|
6834
|
+
ApprovalActions,
|
|
6835
|
+
{
|
|
6836
|
+
actions: activeActions,
|
|
6837
|
+
onApprove: handleApprove,
|
|
6838
|
+
onReject: handleReject,
|
|
6839
|
+
onWithdraw: handleWithdraw,
|
|
6840
|
+
onSave: handleSave
|
|
6841
|
+
}
|
|
6842
|
+
) }) })),
|
|
6843
|
+
!showApprovalActions && bottomActions.length > 0 && /* @__PURE__ */ jsx85(FormActionBar, { position: "bottom-fixed", actions: bottomActions })
|
|
6844
|
+
] });
|
|
6845
|
+
};
|
|
6846
|
+
var ProcessDetailTemplate = (props) => {
|
|
6847
|
+
const { schema, formUuid, appType, formInstanceId } = props;
|
|
6848
|
+
const wrapperConfig = {
|
|
6849
|
+
mode: "readonly",
|
|
6850
|
+
formUuid,
|
|
6851
|
+
appType,
|
|
6852
|
+
formInstanceId
|
|
6853
|
+
};
|
|
6854
|
+
return /* @__PURE__ */ jsx85(FormProvider, { schema, config: wrapperConfig, children: /* @__PURE__ */ jsx85(InnerProcessContent, { ...props }) });
|
|
6855
|
+
};
|
|
4713
6856
|
export {
|
|
4714
6857
|
AddressField,
|
|
6858
|
+
ApprovalActions,
|
|
6859
|
+
ApprovalTimeline,
|
|
4715
6860
|
AssociationFormField,
|
|
4716
6861
|
AttachmentField,
|
|
4717
6862
|
CascadeDateField,
|
|
4718
6863
|
CascadeSelectField,
|
|
6864
|
+
ChangeRecords,
|
|
4719
6865
|
CheckboxField,
|
|
4720
6866
|
ComponentRegistryContext,
|
|
4721
6867
|
ComponentRegistryProvider,
|
|
4722
6868
|
DateField,
|
|
4723
6869
|
DepartmentSelectField,
|
|
4724
6870
|
DigitalSignatureField,
|
|
6871
|
+
DraftManager,
|
|
4725
6872
|
EditorField,
|
|
4726
6873
|
UserSelectField as EmployeeSelectField,
|
|
4727
6874
|
FieldWrapper,
|
|
6875
|
+
FormActionBar,
|
|
4728
6876
|
FormActions,
|
|
4729
6877
|
FormContainer,
|
|
4730
6878
|
FormContext,
|
|
6879
|
+
FormDetailTemplate,
|
|
4731
6880
|
FormGrid,
|
|
4732
6881
|
FormProvider,
|
|
4733
6882
|
FormRenderer,
|
|
4734
6883
|
FormSection,
|
|
4735
6884
|
FormSteps,
|
|
6885
|
+
FormSubmitTemplate,
|
|
4736
6886
|
FormSummary,
|
|
6887
|
+
FormSummaryCard,
|
|
4737
6888
|
FormTabs,
|
|
4738
6889
|
ImageField,
|
|
4739
6890
|
JSONField,
|
|
4740
6891
|
LocationField,
|
|
4741
6892
|
MultiSelectField,
|
|
4742
6893
|
NumberField,
|
|
6894
|
+
PROCESS_STATUS_META,
|
|
6895
|
+
PageSkeleton,
|
|
6896
|
+
ProcessDetailTemplate,
|
|
6897
|
+
ProcessPreview,
|
|
4743
6898
|
RadioField,
|
|
4744
6899
|
SelectField,
|
|
4745
6900
|
SerialNumberField,
|
|
4746
6901
|
SubFormField,
|
|
6902
|
+
TASK_STATUS_META,
|
|
4747
6903
|
TextAreaField,
|
|
4748
6904
|
TextField,
|
|
4749
6905
|
TextAreaField as TextareaField,
|
|
4750
6906
|
UserSelectField,
|
|
6907
|
+
checkUserApproval,
|
|
4751
6908
|
createFormRuntimeApi,
|
|
4752
6909
|
defaultComponentRegistry,
|
|
4753
6910
|
defineFormSchema,
|
|
6911
|
+
deleteFormData,
|
|
4754
6912
|
evaluateEffects,
|
|
6913
|
+
getChangeRecords,
|
|
6914
|
+
getFormData,
|
|
6915
|
+
getProcessBasic,
|
|
6916
|
+
getProcessDefinition,
|
|
6917
|
+
getProcessProgress,
|
|
6918
|
+
getReturnableNodes,
|
|
6919
|
+
getViewPermission,
|
|
6920
|
+
handleApproval,
|
|
6921
|
+
previewProcess,
|
|
6922
|
+
resubmitTask,
|
|
6923
|
+
returnTask,
|
|
6924
|
+
saveTask,
|
|
6925
|
+
transferTask,
|
|
6926
|
+
useApprovalActions,
|
|
6927
|
+
useChangeRecords,
|
|
4755
6928
|
useComponent,
|
|
4756
6929
|
useDeviceDetect,
|
|
6930
|
+
useDraftStorage,
|
|
4757
6931
|
useFieldBehavior,
|
|
6932
|
+
useFieldPermission,
|
|
4758
6933
|
useFormContext,
|
|
4759
6934
|
useFormData,
|
|
6935
|
+
useFormDetail,
|
|
4760
6936
|
useFormEngine,
|
|
6937
|
+
useFormNavigation,
|
|
4761
6938
|
useFormSubmit,
|
|
6939
|
+
useProcessDetail,
|
|
4762
6940
|
validateAllFields,
|
|
4763
|
-
validateField
|
|
6941
|
+
validateField,
|
|
6942
|
+
withdrawProcess
|
|
4764
6943
|
};
|
|
4765
6944
|
//# sourceMappingURL=index.mjs.map
|