sy-form-components 0.2.0 → 0.2.2

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