lyflowchart 1.0.137 → 1.0.152

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/ActionsConfig-BrfcGMc2.js +521 -0
  2. package/dist/{ApprovalEditorModal-19j5zbe2.js → ApprovalEditorModal-HuU6SRJe.js} +1 -1
  3. package/dist/{Cell_click_approve-BGDZUzTS.js → Cell_click_approve-DiMuUB1k.js} +22 -20
  4. package/dist/{MyProcess-FWGEwQcv.js → MyProcess-C6fgOFiw.js} +1 -1
  5. package/dist/{approval-BW2WjPxY.js → approval-1GfOMaS4.js} +3 -3
  6. package/dist/{approval-BaD4Bmw6.js → approval-BlbNEsGQ.js} +1 -1
  7. package/dist/{approvalHistory-B2gpQbFC.js → approvalHistory-D-5rRWNw.js} +1 -1
  8. package/dist/{approvalPageConfig-D0zPXOUf.js → approvalPageConfig-4VU81v-x.js} +13 -13
  9. package/dist/{columnTables-DLwtgcC7.js → columnTables-DFwoawLF.js} +76 -69
  10. package/dist/components/approval/ApprovalEditorModal.vue.d.ts +2 -0
  11. package/dist/components/approval/components/approvalPageConfig/ActionsConfig.vue.d.ts +481 -0
  12. package/dist/components/approval/components/approvalPageConfig/leftColumn.vue.d.ts +1210 -0
  13. package/dist/components/approval/components/approvalPageConfig/middleColumn.vue.d.ts +605 -0
  14. package/dist/components/approval/components/approvalPageConfig/tableConfig.vue.d.ts +605 -0
  15. package/dist/components/approval/core.vue.d.ts +2 -0
  16. package/dist/components/approval/typing.d.ts +1 -1
  17. package/dist/components/approval/useApprovalRecordActions.d.ts +3 -1
  18. package/dist/constants.d.ts +26 -0
  19. package/dist/{core-Cv0Erg9E.js → core-BkpI8NUK.js} +355 -314
  20. package/dist/{debugCode-Cm9-WiUG.js → debugCode-CQm5weGM.js} +1 -1
  21. package/dist/{default-VdDMlY4e.js → default-kv1XZD9P.js} +28 -21
  22. package/dist/{example_code-C_xF8RRG.js → example_code-DKjqP7KK.js} +6 -0
  23. package/dist/index.js +18 -16
  24. package/dist/{leftColumn-CsPjufue.js → leftColumn-OrLOxcyw.js} +2 -2
  25. package/dist/lyflowchart.css +1 -1
  26. package/dist/{middleColumn-C7M6-eVo.js → middleColumn-DUBZPkDG.js} +2 -2
  27. package/dist/{recordActions-BgFlNsGU.js → recordActions-3vqHADOf.js} +1 -1
  28. package/dist/{tableConfig-uLXue-BS.js → tableConfig-W9yGeZs-.js} +41 -41
  29. package/dist/{tableModal-BcYfVL02.js → tableModal-H0SGP8PM.js} +2 -2
  30. package/dist/{useApprovalRecordActions-BQ6MgV2L.js → useApprovalRecordActions-B82xPY8g.js} +63 -63
  31. package/dist/{utils-CLet2gLV.js → utils-B1lkML14.js} +5 -1
  32. package/dist/{viewer-Dv3kQsMf.js → viewer-C_OHXXRU.js} +915 -916
  33. package/package.json +1 -1
  34. package/dist/ActionsConfig-BuvSvRbv.js +0 -395
  35. package/dist/ActionsConfig-BuvSvRbv.js.map +0 -1
  36. package/dist/ApprovalEditorModal-19j5zbe2.js.map +0 -1
  37. package/dist/CancelModal-BUi3ieI8.js.map +0 -1
  38. package/dist/Cell_click_approve-BGDZUzTS.js.map +0 -1
  39. package/dist/JsonTags-BbWLqghI.js.map +0 -1
  40. package/dist/MyProcess-FWGEwQcv.js.map +0 -1
  41. package/dist/approval-BW2WjPxY.js.map +0 -1
  42. package/dist/approval-BaD4Bmw6.js.map +0 -1
  43. package/dist/approvalHistory-B2gpQbFC.js.map +0 -1
  44. package/dist/approvalHistoryViewModal-DgLpv2ot.js.map +0 -1
  45. package/dist/approvalPageConfig-D0zPXOUf.js.map +0 -1
  46. package/dist/approveLeftConfig-BOU_UgHp.js.map +0 -1
  47. package/dist/codeHistoryViewModal-BfSjIbEU.js.map +0 -1
  48. package/dist/columnTables-DLwtgcC7.js.map +0 -1
  49. package/dist/core-Cv0Erg9E.js.map +0 -1
  50. package/dist/dataStoreSettingHistoryViewModal-D_so-KLp.js.map +0 -1
  51. package/dist/debugCode-Cm9-WiUG.js.map +0 -1
  52. package/dist/debugCode-dD1YnQSD.js.map +0 -1
  53. package/dist/default-VdDMlY4e.js.map +0 -1
  54. package/dist/example_code-C_xF8RRG.js.map +0 -1
  55. package/dist/flowHistoryViewModal-D8DJP7Te.js.map +0 -1
  56. package/dist/index.js.map +0 -1
  57. package/dist/init-plugin-fQTSQzui.js.map +0 -1
  58. package/dist/leftColumn-CsPjufue.js.map +0 -1
  59. package/dist/middleColumn-C7M6-eVo.js.map +0 -1
  60. package/dist/recordActions-BgFlNsGU.js.map +0 -1
  61. package/dist/settingsState-CI81PG-i.js.map +0 -1
  62. package/dist/tableConfig-uLXue-BS.js.map +0 -1
  63. package/dist/tableModal-BcYfVL02.js.map +0 -1
  64. package/dist/useApprovalRecordActions-BQ6MgV2L.js.map +0 -1
  65. package/dist/utils-CLet2gLV.js.map +0 -1
  66. package/dist/v0001-OaBeBCXI.js.map +0 -1
  67. package/dist/viewer-Dv3kQsMf.js.map +0 -1
  68. package/dist/vue-print-next-HRweUmNi.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"core-Cv0Erg9E.js","names":[],"sources":["../src/components/approval/SystemTime.vue","../src/components/approval/SystemTime.vue","../src/components/approval/components/FormCodeInput.vue","../src/components/approval/components/FormCodeInput.vue","../src/components/approval/components/FormContextInput.vue","../src/components/approval/components/FormContextInput.vue","../src/components/approval/CreateByCascader.vue","../src/components/approval/CreateByCascader.vue","../src/components/approval/PostionCascader.vue","../src/components/approval/PostionCascader.vue","../src/components/approval/components/FormFlowOrgInput.vue","../src/components/approval/components/FormFlowOrgInput.vue","../src/components/approval/components/columnForm.vue","../src/components/approval/components/columnForm.vue","../src/components/approval/components/columnDataList.vue","../src/components/approval/components/columnDataList.vue","../src/components/approval/components/columnUnknown.vue","../src/components/approval/components/columnUnknown.vue","../src/components/approval/approvalViewId.ts","../src/components/approval/components/drawerTablesList.vue","../src/components/approval/components/drawerTablesList.vue","../src/components/approval/components/drawerDataList.vue","../src/components/approval/components/drawerDataList.vue","../src/components/approval/CostCompanySelect.vue","../src/components/approval/CostCompanySelect.vue","../src/components/approval/CostDepartmentSelect.vue","../src/components/approval/CostDepartmentSelect.vue","../src/components/approval/CreateBySelect.vue","../src/components/approval/CreateBySelect.vue","../src/components/approval/core.vue","../src/components/approval/core.vue"],"sourcesContent":["<template>\n <a-date-picker\n size=\"small\"\n :value=\"innerValue\"\n :disabled=\"disabled\"\n @change=\"handleChange($event, true)\"\n />\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport dayjs from 'dayjs';\nexport default defineComponent({\n name: 'CreateBySelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n date: string;\n data_ch: string;\n date_short: string;\n }>,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const dataList = ref<any>([]);\n\n const handleChange = (value: any, userUpdate) => {\n if (!value) {\n emit('update:value', null);\n emit('change', null);\n return;\n }\n\n const res = {\n date: value.format('YYYY-MM-DD'),\n date_ch: value.format('YYYY年MM月DD日'),\n date_short: value.format('YYYYMMDD'),\n };\n\n emit('update:value', res);\n emit('change', userUpdate);\n };\n const innerValue = computed(() => {\n if (props.value) {\n try {\n const datObj = dayjs(props.value.date, 'YYYY-MM-DD');\n return datObj;\n } catch {\n return null;\n }\n } else {\n return null;\n }\n });\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n newValue => {\n if (!newValue?.date) {\n const now = dayjs();\n handleChange(now, false);\n }\n },\n {\n immediate: true,\n deep: true,\n },\n );\n\n return {\n dataList,\n innerValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-date-picker\n size=\"small\"\n :value=\"innerValue\"\n :disabled=\"disabled\"\n @change=\"handleChange($event, true)\"\n />\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport dayjs from 'dayjs';\nexport default defineComponent({\n name: 'CreateBySelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n date: string;\n data_ch: string;\n date_short: string;\n }>,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const dataList = ref<any>([]);\n\n const handleChange = (value: any, userUpdate) => {\n if (!value) {\n emit('update:value', null);\n emit('change', null);\n return;\n }\n\n const res = {\n date: value.format('YYYY-MM-DD'),\n date_ch: value.format('YYYY年MM月DD日'),\n date_short: value.format('YYYYMMDD'),\n };\n\n emit('update:value', res);\n emit('change', userUpdate);\n };\n const innerValue = computed(() => {\n if (props.value) {\n try {\n const datObj = dayjs(props.value.date, 'YYYY-MM-DD');\n return datObj;\n } catch {\n return null;\n }\n } else {\n return null;\n }\n });\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n newValue => {\n if (!newValue?.date) {\n const now = dayjs();\n handleChange(now, false);\n }\n },\n {\n immediate: true,\n deep: true,\n },\n );\n\n return {\n dataList,\n innerValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <span>\n <a-input\n size=\"small\"\n :value=\"innerValue\"\n :disabled=\"disabled\"\n @update:value=\"handleChange\"\n ></a-input>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, PropType, ref } from 'vue';\nexport default defineComponent({\n name: 'FormCodeInput',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n code: string;\n }>,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const dataList = ref<any>([]);\n\n const handleChange = (value: any) => {\n if (!value) {\n emit('update:value', null);\n emit('change', true);\n return;\n }\n const res = {\n code: value,\n };\n emit('update:value', res);\n emit('change', true);\n };\n const innerValue = computed(() => {\n if (props.value) {\n return props.value.code;\n } else {\n return null;\n }\n });\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n\n return {\n dataList,\n innerValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\">\n// 禁用态下文字保持正常黑色(antd 默认用 colorTextDisabled = rgba(0, 0, 0, 0.25),太浅看不清)\n:deep(.ant-input-disabled),\n:deep(.ant-input[disabled]) {\n color: var(--text-color, rgba(0, 0, 0, 0.88));\n}\n</style>\n","<template>\n <span>\n <a-input\n size=\"small\"\n :value=\"innerValue\"\n :disabled=\"disabled\"\n @update:value=\"handleChange\"\n ></a-input>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, PropType, ref } from 'vue';\nexport default defineComponent({\n name: 'FormCodeInput',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n code: string;\n }>,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const dataList = ref<any>([]);\n\n const handleChange = (value: any) => {\n if (!value) {\n emit('update:value', null);\n emit('change', true);\n return;\n }\n const res = {\n code: value,\n };\n emit('update:value', res);\n emit('change', true);\n };\n const innerValue = computed(() => {\n if (props.value) {\n return props.value.code;\n } else {\n return null;\n }\n });\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n\n return {\n dataList,\n innerValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\">\n// 禁用态下文字保持正常黑色(antd 默认用 colorTextDisabled = rgba(0, 0, 0, 0.25),太浅看不清)\n:deep(.ant-input-disabled),\n:deep(.ant-input[disabled]) {\n color: var(--text-color, rgba(0, 0, 0, 0.88));\n}\n</style>\n","<template>\n <span>\n <a-input\n size=\"small\"\n :value=\"innerValue\"\n :disabled=\"disabled\"\n @update:value=\"handleChange\"\n ></a-input>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, PropType, ref, watch } from 'vue';\nexport default defineComponent({\n name: 'FormContextInput',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n context: string;\n }>,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const dataList = ref<any>([]);\n const innerValue = computed(() => {\n if (props.value?.context) {\n return props.value.context;\n } else {\n return null;\n }\n });\n\n const handleChange = (value: any) => {\n if (!value) {\n emit('update:value', null);\n emit('change', true);\n return;\n }\n const res = {\n context: value,\n };\n emit('update:value', res);\n emit('change', true);\n };\n\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n\n return {\n dataList,\n innerValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <span>\n <a-input\n size=\"small\"\n :value=\"innerValue\"\n :disabled=\"disabled\"\n @update:value=\"handleChange\"\n ></a-input>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, PropType, ref, watch } from 'vue';\nexport default defineComponent({\n name: 'FormContextInput',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n context: string;\n }>,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const dataList = ref<any>([]);\n const innerValue = computed(() => {\n if (props.value?.context) {\n return props.value.context;\n } else {\n return null;\n }\n });\n\n const handleChange = (value: any) => {\n if (!value) {\n emit('update:value', null);\n emit('change', true);\n return;\n }\n const res = {\n context: value,\n };\n emit('update:value', res);\n emit('change', true);\n };\n\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n\n return {\n dataList,\n innerValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-cascader\n v-model:value=\"innerValue\"\n :options=\"dataSource\"\n placeholder=\"请选择制单人\"\n @change=\"handleChange($event, true)\"\n :allowClear=\"false\"\n :disabled=\"disabled\"\n style=\"min-height: 24px\"\n ></a-cascader>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, onMounted, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostDepartmentSelect',\n components: {},\n props: {\n value: {\n type: Object,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['change'],\n\n setup(props, { emit }) {\n const cascaderOptions = ref<any>([]);\n const flatDataSource = ref<any>([]);\n\n // 1. Corrected processData - uses API field names, and item.business_person.id for leaf value\n const processData = (data: any[]) => {\n const options: any[] = [];\n const companyMap = new Map<string, any>();\n\n data.forEach(item => {\n const companyId = item.cost_company.id;\n const companyName = item.cost_company.name;\n\n const departmentId = item.department.id;\n const departmentName = item.department.name;\n\n // The person's actual ID\n const personBusinessPersonId = item.business_person.id;\n const personName = item.business_person.name;\n\n let companyNode = companyMap.get(companyId);\n if (!companyNode) {\n companyNode = { value: companyId, label: companyName, children: [] };\n companyMap.set(companyId, companyNode);\n options.push(companyNode);\n }\n\n let departmentNode = companyNode.children.find(\n (child: any) => child.value === departmentId,\n );\n if (!departmentNode) {\n departmentNode = { value: departmentId, label: departmentName, children: [] };\n companyNode.children.push(departmentNode);\n }\n\n // Add business_person as a leaf node, ensuring no duplicates within the same branch\n const personExists = departmentNode.children.some(\n (child: any) => child.value === personBusinessPersonId,\n );\n if (!personExists) {\n departmentNode.children.push({\n value: personBusinessPersonId, // Changed to item.business_person.id\n label: personName,\n });\n }\n });\n return options;\n };\n\n // 2. Corrected getData\n const getData = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_cascaded_my_business_person');\n if (res && res.length > 0) {\n flatDataSource.value = res;\n cascaderOptions.value = processData(res);\n const cost_company = props.value?.cost_company;\n const cost_department = props.value?.cost_department;\n const create_by = props.value?.create_by;\n if (!cost_company?.id || !cost_department?.id || !create_by?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].business_person.id,\n ],\n false,\n );\n }\n } else {\n flatDataSource.value = [];\n cascaderOptions.value = [];\n }\n };\n const innerValue = computed(() => {\n const cost_company = props.value?.cost_company;\n const cost_department = props.value?.cost_department;\n const create_by = props.value?.create_by;\n if (cost_company?.id && cost_department?.id && create_by?.id) {\n return [cost_company.id, cost_department.id, create_by.id];\n } else {\n return null;\n }\n });\n // 3. Corrected\n\n const handleChange = (value: any[] | null, userUpdate) => {\n const clearValue = () => {\n const res = {\n cost_company: null,\n cost_department: null,\n create_by: null,\n person_cost_company: null,\n person_department: null,\n person_position: null,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n };\n\n if (!value || value.length === 0) {\n clearValue();\n return;\n }\n\n // value array is [companyId, departmentId, personBusinessPersonId]\n const selectedCompanyId = value[0];\n const selectedDepartmentId = value[1];\n const selectedPersonBusinessPersonId = value[2];\n\n // Find item by matching all three parts\n const findItem = flatDataSource.value.find(\n (item: any) =>\n item.cost_company.id === selectedCompanyId &&\n item.department.id === selectedDepartmentId &&\n item.business_person.id === selectedPersonBusinessPersonId,\n );\n\n if (findItem) {\n // Construct the output object using component's output field names\n const res = {\n cost_company: findItem.cost_company,\n cost_department: findItem.department, // Maps API 'department' to output 'cost_department'\n create_by: findItem.business_person, // Maps API 'business_person' to output 'create_by' with its actual ID\n person_cost_company: null,\n person_department: null,\n person_position: null,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n } else {\n clearValue();\n }\n };\n\n const filterOption = (inputValue: string, path: any[]) => {\n return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);\n };\n watch(\n () => props.value,\n newValue => {\n if (flatDataSource.value && flatDataSource.value.length > 0) {\n const cost_company = newValue?.cost_company;\n const cost_department = newValue?.cost_department;\n const create_by = newValue?.create_by;\n if (!cost_company?.id || !cost_department?.id || !create_by?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].business_person.id,\n ],\n false,\n );\n }\n }\n },\n { deep: true },\n );\n\n onMounted(() => {\n getData();\n });\n\n return {\n dataSource: cascaderOptions,\n handleChange,\n filterOption,\n innerValue,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-cascader\n v-model:value=\"innerValue\"\n :options=\"dataSource\"\n placeholder=\"请选择制单人\"\n @change=\"handleChange($event, true)\"\n :allowClear=\"false\"\n :disabled=\"disabled\"\n style=\"min-height: 24px\"\n ></a-cascader>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, onMounted, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostDepartmentSelect',\n components: {},\n props: {\n value: {\n type: Object,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['change'],\n\n setup(props, { emit }) {\n const cascaderOptions = ref<any>([]);\n const flatDataSource = ref<any>([]);\n\n // 1. Corrected processData - uses API field names, and item.business_person.id for leaf value\n const processData = (data: any[]) => {\n const options: any[] = [];\n const companyMap = new Map<string, any>();\n\n data.forEach(item => {\n const companyId = item.cost_company.id;\n const companyName = item.cost_company.name;\n\n const departmentId = item.department.id;\n const departmentName = item.department.name;\n\n // The person's actual ID\n const personBusinessPersonId = item.business_person.id;\n const personName = item.business_person.name;\n\n let companyNode = companyMap.get(companyId);\n if (!companyNode) {\n companyNode = { value: companyId, label: companyName, children: [] };\n companyMap.set(companyId, companyNode);\n options.push(companyNode);\n }\n\n let departmentNode = companyNode.children.find(\n (child: any) => child.value === departmentId,\n );\n if (!departmentNode) {\n departmentNode = { value: departmentId, label: departmentName, children: [] };\n companyNode.children.push(departmentNode);\n }\n\n // Add business_person as a leaf node, ensuring no duplicates within the same branch\n const personExists = departmentNode.children.some(\n (child: any) => child.value === personBusinessPersonId,\n );\n if (!personExists) {\n departmentNode.children.push({\n value: personBusinessPersonId, // Changed to item.business_person.id\n label: personName,\n });\n }\n });\n return options;\n };\n\n // 2. Corrected getData\n const getData = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_cascaded_my_business_person');\n if (res && res.length > 0) {\n flatDataSource.value = res;\n cascaderOptions.value = processData(res);\n const cost_company = props.value?.cost_company;\n const cost_department = props.value?.cost_department;\n const create_by = props.value?.create_by;\n if (!cost_company?.id || !cost_department?.id || !create_by?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].business_person.id,\n ],\n false,\n );\n }\n } else {\n flatDataSource.value = [];\n cascaderOptions.value = [];\n }\n };\n const innerValue = computed(() => {\n const cost_company = props.value?.cost_company;\n const cost_department = props.value?.cost_department;\n const create_by = props.value?.create_by;\n if (cost_company?.id && cost_department?.id && create_by?.id) {\n return [cost_company.id, cost_department.id, create_by.id];\n } else {\n return null;\n }\n });\n // 3. Corrected\n\n const handleChange = (value: any[] | null, userUpdate) => {\n const clearValue = () => {\n const res = {\n cost_company: null,\n cost_department: null,\n create_by: null,\n person_cost_company: null,\n person_department: null,\n person_position: null,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n };\n\n if (!value || value.length === 0) {\n clearValue();\n return;\n }\n\n // value array is [companyId, departmentId, personBusinessPersonId]\n const selectedCompanyId = value[0];\n const selectedDepartmentId = value[1];\n const selectedPersonBusinessPersonId = value[2];\n\n // Find item by matching all three parts\n const findItem = flatDataSource.value.find(\n (item: any) =>\n item.cost_company.id === selectedCompanyId &&\n item.department.id === selectedDepartmentId &&\n item.business_person.id === selectedPersonBusinessPersonId,\n );\n\n if (findItem) {\n // Construct the output object using component's output field names\n const res = {\n cost_company: findItem.cost_company,\n cost_department: findItem.department, // Maps API 'department' to output 'cost_department'\n create_by: findItem.business_person, // Maps API 'business_person' to output 'create_by' with its actual ID\n person_cost_company: null,\n person_department: null,\n person_position: null,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n } else {\n clearValue();\n }\n };\n\n const filterOption = (inputValue: string, path: any[]) => {\n return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);\n };\n watch(\n () => props.value,\n newValue => {\n if (flatDataSource.value && flatDataSource.value.length > 0) {\n const cost_company = newValue?.cost_company;\n const cost_department = newValue?.cost_department;\n const create_by = newValue?.create_by;\n if (!cost_company?.id || !cost_department?.id || !create_by?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].business_person.id,\n ],\n false,\n );\n }\n }\n },\n { deep: true },\n );\n\n onMounted(() => {\n getData();\n });\n\n return {\n dataSource: cascaderOptions,\n handleChange,\n filterOption,\n innerValue,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-cascader\n v-model:value=\"innerValue\"\n :options=\"dataSource\"\n placeholder=\"请选择职位\"\n @change=\"handleChange($event, true)\"\n :allowClear=\"false\"\n :disabled=\"disabled\"\n style=\"min-height: 24px\"\n ></a-cascader>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, nextTick, onMounted, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nimport { debounce } from 'lodash';\n\nexport default defineComponent({\n name: 'PostionCascader',\n components: {},\n props: {\n value: {\n type: Object,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['change'],\n\n setup(props, { emit }) {\n const cascaderOptions = ref<any[]>([]);\n const flatDataSource = ref<any[]>([]);\n\n const processData = (data: any[]) => {\n const options: any[] = [];\n const companyMap = new Map<string, any>();\n\n data.forEach(item => {\n const companyId = item.cost_company.id;\n const companyName = item.cost_company.name;\n const departmentId = item.department.id;\n const departmentName = item.department.name;\n const positionId = item.position.id;\n const positionName = item.position.name;\n\n let companyNode = companyMap.get(companyId);\n if (!companyNode) {\n companyNode = { value: companyId, label: companyName, children: [] };\n companyMap.set(companyId, companyNode);\n options.push(companyNode);\n }\n\n let departmentNode = companyNode.children.find(child => child.value === departmentId);\n if (!departmentNode) {\n departmentNode = { value: departmentId, label: departmentName, children: [] };\n companyNode.children.push(departmentNode);\n }\n\n const positionExists = departmentNode.children.some(child => child.value === positionId);\n if (!positionExists) {\n departmentNode.children.push({ value: positionId, label: positionName });\n }\n });\n return options;\n };\n\n const getData = async () => {\n const personId = props.value?.create_by?.id;\n const createDate = props.value?.create_date?.date;\n\n if (!personId || !createDate) {\n flatDataSource.value = [];\n cascaderOptions.value = [];\n return;\n }\n\n const res = await getApiData(\n {\n business_person_id: personId,\n create_date: createDate,\n },\n '/approve/get_cascaded_person_position',\n );\n\n if (res && res.length > 0) {\n flatDataSource.value = res;\n cascaderOptions.value = processData(res);\n const person_cost_company = props.value?.person_cost_company;\n const person_department = props.value?.person_department;\n const person_position = props.value?.person_position;\n if (!person_cost_company?.id || !person_department?.id || !person_position?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].position.id,\n ],\n false,\n );\n }\n } else {\n flatDataSource.value = [];\n cascaderOptions.value = [];\n }\n };\n const innerValue = computed(() => {\n const person_cost_company = props.value?.person_cost_company;\n const person_department = props.value?.person_department;\n const person_position = props.value?.person_position;\n if (person_cost_company?.id && person_department?.id && person_position?.id) {\n return [person_cost_company.id, person_department.id, person_position.id];\n } else {\n return null;\n }\n });\n\n const handleChange = (value: any[] | null, userUpdate) => {\n const clearValue = () => {\n const res = {\n person_cost_company: null,\n person_department: null,\n person_position: null,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n };\n\n if (!value || value.length < 3) {\n clearValue();\n return;\n }\n\n const [selectedCompanyId, selectedDepartmentId, selectedPositionId] = value;\n\n const findItem = flatDataSource.value.find(\n item =>\n item.cost_company.id === selectedCompanyId &&\n item.department.id === selectedDepartmentId &&\n item.position.id === selectedPositionId,\n );\n\n if (findItem) {\n const res = {\n person_cost_company: findItem.cost_company,\n person_department: findItem.department,\n person_position: findItem.position,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n } else {\n clearValue();\n }\n };\n\n watch(\n () => [props.value?.create_by?.id, props.value?.create_date?.date],\n ([newPersonId, newDate], [oldPersonId, oldDate]) => {\n if (newPersonId !== oldPersonId || newDate !== oldDate) {\n getData();\n }\n },\n );\n const defuatValue = debounce(() => {\n const newValue = props.value;\n if (flatDataSource.value && flatDataSource.value.length > 0) {\n const person_cost_company = newValue?.person_cost_company;\n const person_department = newValue?.person_department;\n const person_position = newValue?.person_position;\n if (!person_cost_company?.id || !person_department?.id || !person_position?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].position.id,\n ],\n false,\n );\n }\n }\n }, 200);\n watch(\n () => props.value,\n newValue => {\n defuatValue();\n },\n { deep: true },\n );\n\n onMounted(() => {\n getData();\n });\n\n return {\n dataSource: cascaderOptions,\n handleChange,\n innerValue,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-cascader\n v-model:value=\"innerValue\"\n :options=\"dataSource\"\n placeholder=\"请选择职位\"\n @change=\"handleChange($event, true)\"\n :allowClear=\"false\"\n :disabled=\"disabled\"\n style=\"min-height: 24px\"\n ></a-cascader>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, nextTick, onMounted, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nimport { debounce } from 'lodash';\n\nexport default defineComponent({\n name: 'PostionCascader',\n components: {},\n props: {\n value: {\n type: Object,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['change'],\n\n setup(props, { emit }) {\n const cascaderOptions = ref<any[]>([]);\n const flatDataSource = ref<any[]>([]);\n\n const processData = (data: any[]) => {\n const options: any[] = [];\n const companyMap = new Map<string, any>();\n\n data.forEach(item => {\n const companyId = item.cost_company.id;\n const companyName = item.cost_company.name;\n const departmentId = item.department.id;\n const departmentName = item.department.name;\n const positionId = item.position.id;\n const positionName = item.position.name;\n\n let companyNode = companyMap.get(companyId);\n if (!companyNode) {\n companyNode = { value: companyId, label: companyName, children: [] };\n companyMap.set(companyId, companyNode);\n options.push(companyNode);\n }\n\n let departmentNode = companyNode.children.find(child => child.value === departmentId);\n if (!departmentNode) {\n departmentNode = { value: departmentId, label: departmentName, children: [] };\n companyNode.children.push(departmentNode);\n }\n\n const positionExists = departmentNode.children.some(child => child.value === positionId);\n if (!positionExists) {\n departmentNode.children.push({ value: positionId, label: positionName });\n }\n });\n return options;\n };\n\n const getData = async () => {\n const personId = props.value?.create_by?.id;\n const createDate = props.value?.create_date?.date;\n\n if (!personId || !createDate) {\n flatDataSource.value = [];\n cascaderOptions.value = [];\n return;\n }\n\n const res = await getApiData(\n {\n business_person_id: personId,\n create_date: createDate,\n },\n '/approve/get_cascaded_person_position',\n );\n\n if (res && res.length > 0) {\n flatDataSource.value = res;\n cascaderOptions.value = processData(res);\n const person_cost_company = props.value?.person_cost_company;\n const person_department = props.value?.person_department;\n const person_position = props.value?.person_position;\n if (!person_cost_company?.id || !person_department?.id || !person_position?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].position.id,\n ],\n false,\n );\n }\n } else {\n flatDataSource.value = [];\n cascaderOptions.value = [];\n }\n };\n const innerValue = computed(() => {\n const person_cost_company = props.value?.person_cost_company;\n const person_department = props.value?.person_department;\n const person_position = props.value?.person_position;\n if (person_cost_company?.id && person_department?.id && person_position?.id) {\n return [person_cost_company.id, person_department.id, person_position.id];\n } else {\n return null;\n }\n });\n\n const handleChange = (value: any[] | null, userUpdate) => {\n const clearValue = () => {\n const res = {\n person_cost_company: null,\n person_department: null,\n person_position: null,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n };\n\n if (!value || value.length < 3) {\n clearValue();\n return;\n }\n\n const [selectedCompanyId, selectedDepartmentId, selectedPositionId] = value;\n\n const findItem = flatDataSource.value.find(\n item =>\n item.cost_company.id === selectedCompanyId &&\n item.department.id === selectedDepartmentId &&\n item.position.id === selectedPositionId,\n );\n\n if (findItem) {\n const res = {\n person_cost_company: findItem.cost_company,\n person_department: findItem.department,\n person_position: findItem.position,\n };\n Object.assign(props.value, res);\n emit('change', userUpdate);\n } else {\n clearValue();\n }\n };\n\n watch(\n () => [props.value?.create_by?.id, props.value?.create_date?.date],\n ([newPersonId, newDate], [oldPersonId, oldDate]) => {\n if (newPersonId !== oldPersonId || newDate !== oldDate) {\n getData();\n }\n },\n );\n const defuatValue = debounce(() => {\n const newValue = props.value;\n if (flatDataSource.value && flatDataSource.value.length > 0) {\n const person_cost_company = newValue?.person_cost_company;\n const person_department = newValue?.person_department;\n const person_position = newValue?.person_position;\n if (!person_cost_company?.id || !person_department?.id || !person_position?.id) {\n handleChange(\n [\n flatDataSource.value[0].cost_company.id,\n flatDataSource.value[0].department.id,\n flatDataSource.value[0].position.id,\n ],\n false,\n );\n }\n }\n }, 200);\n watch(\n () => props.value,\n newValue => {\n defuatValue();\n },\n { deep: true },\n );\n\n onMounted(() => {\n getData();\n });\n\n return {\n dataSource: cascaderOptions,\n handleChange,\n innerValue,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <span>\n <a-input\n size=\"small\"\n :value=\"innerValue\"\n :readonly=\"true\"\n :disabled=\"disabled\"\n ></a-input>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { getApiData } from '@/init-plugin';\nimport { computed, defineComponent, onMounted, PropType } from 'vue';\nexport default defineComponent({\n name: 'FormCodeInput',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: string;\n name: string;\n }>,\n },\n modelType: {\n type: String,\n required: true,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const innerValue = computed(() => {\n if (props.value) {\n return props.value.name;\n } else {\n return null;\n }\n });\n const getFlowOrg = async () => {\n const res = await getApiData(\n {\n menu_flag: props.modelType,\n },\n '/approve/query_flow_node_list',\n );\n if (res && res.data?.length) {\n emit('update:value', { id: res.data[0].flow_org_id, name: res.data[0].flow_org__name });\n }\n };\n onMounted(() => {\n getFlowOrg();\n });\n return { innerValue };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <span>\n <a-input\n size=\"small\"\n :value=\"innerValue\"\n :readonly=\"true\"\n :disabled=\"disabled\"\n ></a-input>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { getApiData } from '@/init-plugin';\nimport { computed, defineComponent, onMounted, PropType } from 'vue';\nexport default defineComponent({\n name: 'FormCodeInput',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: string;\n name: string;\n }>,\n },\n modelType: {\n type: String,\n required: true,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const innerValue = computed(() => {\n if (props.value) {\n return props.value.name;\n } else {\n return null;\n }\n });\n const getFlowOrg = async () => {\n const res = await getApiData(\n {\n menu_flag: props.modelType,\n },\n '/approve/query_flow_node_list',\n );\n if (res && res.data?.length) {\n emit('update:value', { id: res.data[0].flow_org_id, name: res.data[0].flow_org__name });\n }\n };\n onMounted(() => {\n getFlowOrg();\n });\n return { innerValue };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <div\n class=\"form-container\"\n ref=\"formContainerRef\"\n >\n <div class=\"form-body\">\n <div class=\"base-info\">\n <a-card :body-style=\"{ padding: '10px 10px 0' }\">\n <template #extra>\n <a-tag\n v-if=\"isEdit\"\n color=\"blue\"\n >\n 流水号:{{ editState.number }}【编辑】\n </a-tag>\n <a-tag\n v-else\n color=\"blue\"\n >\n 流水号:{{ globalData.number }}\n </a-tag>\n </template>\n <template #title>基础信息</template>\n <a-form\n layout=\"vertical\"\n size=\"small\"\n :model=\"globalData\"\n ref=\"formRef\"\n >\n <a-row :gutter=\"36\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"单据编号\"\n name=\"form_code\"\n :rules=\"[{ required: true }]\"\n >\n <form-code-input\n v-model:value=\"globalData.form_code\"\n :disabled=\"isGlobalDisabled('form_code')\"\n @change=\"handleGlobalDataChange($event)\"\n ></form-code-input>\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"制单日期\"\n name=\"create_date\"\n :rules=\"[{ required: true }]\"\n >\n <SystemTime\n v-model:value=\"globalData.create_date\"\n :disabled=\"isGlobalDisabled('create_date')\"\n @change=\"handleGlobalDataChange($event)\"\n style=\"width: 100%\"\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"8\">\n <a-form-item\n label=\"流程组织\"\n name=\"create_by\"\n :validateTrigger=\"false\"\n >\n <FormFlowOrgInput\n v-model:value=\"globalData.flow_org\"\n :model-type=\"modelType\"\n :disabled=\"isGlobalDisabled('flow_org')\"\n @change=\"handleGlobalDataChange($event)\"\n ></FormFlowOrgInput>\n </a-form-item>\n </a-col>\n <a-col :span=\"8\">\n <a-form-item\n label=\"制单人\"\n name=\"create_by\"\n :validateTrigger=\"false\"\n :rules=\"isDev ? [] : [{ required: true }]\"\n >\n <CreateByCascader\n :value=\"globalData\"\n :disabled=\"isGlobalDisabled('create_by')\"\n @change=\"handleGlobalDataChange($event)\"\n ></CreateByCascader>\n </a-form-item>\n </a-col>\n <a-col :span=\"8\">\n <a-form-item\n label=\"职位\"\n name=\"person_position\"\n :validateTrigger=\"false\"\n :rules=\"isDev ? [] : [{ required: true }]\"\n >\n <PostionCascader\n :value=\"globalData\"\n :disabled=\"isGlobalDisabled('person_position')\"\n @change=\"handleGlobalDataChange($event)\"\n ></PostionCascader>\n </a-form-item>\n </a-col>\n </a-row>\n\n <a-form-item\n label=\"流程主题\"\n name=\"context\"\n :rules=\"[{ required: true }]\"\n >\n <form-context-input\n v-model:value=\"globalData.context\"\n :disabled=\"isGlobalDisabled('context')\"\n @change=\"handleGlobalDataChange\"\n style=\"width: 100%\"\n ></form-context-input>\n </a-form-item>\n </a-form>\n </a-card>\n </div>\n <form-render-3\n v-if=\"columnConfig.form?.dynamicFieldList\"\n :form=\"localForm\"\n :model=\"modelRef\"\n :options=\"columnConfig.form?.options\"\n :validateInfos=\"validateInfos\"\n @update_model=\"onUpdateModel\"\n :alwaysShowGroup=\"true\"\n :context=\"context.contexts?.[modelType]\"\n :nestValidate=\"nestValidate\"\n :worker-host-functions=\"workerHostFunctions\"\n :lock-structure=\"lockStructure\"\n />\n </div>\n <div\n class=\"form-footer\"\n v-if=\"columnConfig.actions && columnConfig.actions.length > 0\"\n >\n <actions-bar\n :actions=\"columnConfig.actions\"\n @click=\"handleAction\"\n :params=\"{\n context: context.contexts?.[modelType] || {},\n }\"\n />\n </div>\n </div>\n <CancelModal\n v-model:cancel-modal-show=\"cancelModalShow\"\n :id=\"cancelRecordId\"\n :event-bus=\"eventBus\"\n ></CancelModal>\n</template>\n\n<script lang=\"ts\">\nimport { ApprovalSetting, FormSection } from '../typing';\n\n// 该 props 由父组件(index.vue)创建的 mitt 实例传入,这里仅声明本组件用到的接口\ninterface ApprovalEventBus {\n on(event: string, handler: (payload: any) => void): void;\n off(event: string, handler: (payload: any) => void): void;\n emit(event: string, payload?: any): void;\n}\n\n/**\n * 必须放在普通 <script> 块里(<script setup> 不允许 ES 模块导出):\n * 父组件 index.vue 的默认导出类型会引用本组件的 props 类型,类型不可命名时\n * vue-tsc 既产不出本文件的 .d.ts,也会连锁让 index.vue 报 TS4082。\n */\nexport interface ColumnFormProps {\n columnConfig: FormSection;\n height: number;\n modelType: string;\n eventBus: ApprovalEventBus;\n globalData: Record<string, any>;\n topFormRef: any;\n approvalConfig: ApprovalSetting;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { useForm } from 'ant-design-vue/es/form';\nimport { defineAsyncComponent, computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue';\nimport { SelectTableConfig } from '../typing';\n//@ts-ignore\nimport {\n CLEAR_CONTEXT,\n SET_EDIT,\n SET_FORM_MODEL,\n useContextStore,\n} from '@/components/approval/store/context';\nimport { message, Modal } from 'ant-design-vue';\nimport { executeScriptInWorker, getApiData, modalBox } from '@/init-plugin';\nimport { createModifyApprove } from '../utils';\nimport { getDataStoreConfig } from '../index';\nimport { cloneDeep, debounce } from 'lodash';\nimport SystemTime from '../SystemTime.vue';\nimport actionsBar from './actionsBar.vue';\nimport FormCodeInput from './FormCodeInput.vue';\nimport FormContextInput from './FormContextInput.vue';\nimport CreateByCascader from '../CreateByCascader.vue';\nimport PostionCascader from '../PostionCascader.vue';\nimport CancelModal from './CancelModal.vue';\nimport FormFlowOrgInput from './FormFlowOrgInput.vue';\n\ndefineOptions({ name: 'ApprovalColumnForm' });\n\n// ApprovalEventBus / ColumnFormProps 见文件顶部的普通 <script> 块(为了能 export)\nconst props = defineProps<ColumnFormProps>();\nconst emit = defineEmits<{ (e: 'globalDataChange', update: any): void }>();\n\nconst context = useContextStore();\nconst modelRef = ref(cloneDeep(props.columnConfig.form.model));\nconst rulesRef = reactive(cloneDeep(props.columnConfig.form.rules));\nconst validateInfos = ref({});\nconst isEdit = ref(false);\nconst modifyMode = ref(false);\nconst sourceApproveRecordId = ref<any>(null);\n// 修改模式锁定表单结构(隐藏添加/清空/导入/行删除),由 FormRender3 深层透传\nconst lockStructure = ref(false);\n// 本地开发模式(非生产)下放宽校验:制单人/职位不强制必填\nconst isDev = process.env.NODE_ENV !== 'production';\nconst editState = ref<any>({});\nconst nestValidate = ref({});\nconst formRef = ref();\n/**\n * 本组件根元素(`.form-container`)。\n * 校验失败后要把第一个报错字段滚进视野,**必须在本实例的子树里找**:\n * 页面 + 「修改」全屏模态框会同时存在两个 `.form-container`,而 `a-modal` 的 wrapper\n * 追加在 `#app` 之后 —— 文档级查询取 `[0]` 拿到的是**页面**那个,会把背后那个页面滚起来、\n * 模态框自己不动。同一个组件会有多份实例这件事,与竖条 Teleport 锚点是同一类问题。\n */\nconst formContainerRef = ref<HTMLElement | null>(null);\nconst cancelModalShow = ref(false);\nconst cancelRecordId = ref(null);\n// 记录需要忽略校验的字段\nconst removeRulKeys = ref([]);\nlet validate: any;\n\n// ===== 编辑态字段可编辑性控制(基于数据存储规则配置 ExcelColumnConfig.is_modifiable)=====\n// 明细/表单字段(source_type='form'):默认禁止编辑,仅当规则里对应字段 is_modifiable=true 才允许\n// 全局字段(source_type='global'):默认允许编辑,仅当规则里对应字段 is_modifiable=false 才禁止\n// 且:字段本身在页面配置里就已禁用(disabled=true,如只读/系统回填字段)时,编辑态一律保持禁用,\n// 不因规则 is_modifiable=true 而放开(原有禁用状态优先)\n// 另外:页面配置里每个字段可显式指定「是否可编辑」三态(editable_mode:自动/禁用/可用,见 FieldSetting 高级属性),\n// 非自动时以显式配置为准(禁用=强制不可编辑,可用=强制可编辑),自动/未配置时才走上面的规则计算逻辑\n// 注:与后端 approve/utils.py::check_data_store 不同,这里只控制「编辑态 UI 是否可改」,不改变导入结构\nconst formEditable = ref<Map<string, boolean>>(new Map());\nconst globalEditable = ref<Map<string, boolean>>(new Map());\n\nconst loadEditableMaps = async () => {\n try {\n const { config } = await getDataStoreConfig(props.modelType);\n const fMap = new Map<string, boolean>();\n const gMap = new Map<string, boolean>();\n for (const rule of (config as any[]) || []) {\n for (const f of rule.fields || []) {\n const isMod = !!(f.data_column && f.data_column.is_modifiable);\n if (f.source_type === 'form' && Array.isArray(f.source_value) && f.source_value.length) {\n // source_value 是表单字段 key 路径(cascade 选择的是 field.key,叶子即字段自身的 key),\n // 取最后一段(叶子字段 key)作为匹配键,与表单叶子字段的 key 对齐。\n // 注意:表单字段的 name 不在 source_value 中,不能用来匹配。\n fMap.set(f.source_value[f.source_value.length - 1], isMod);\n } else if (\n f.source_type === 'global' &&\n Array.isArray(f.source_value) &&\n f.source_value.length\n ) {\n // source_value[0] 即顶部全局组件绑定的 globalData 属性名(form_code/create_date/flow_org/create_by/person_position/context)\n gMap.set(f.source_value[0], isMod);\n }\n }\n }\n formEditable.value = fMap;\n globalEditable.value = gMap;\n } catch (e) {\n console.error('加载数据存储配置失败,编辑态字段可编辑性控制未生效', e);\n formEditable.value = new Map();\n globalEditable.value = new Map();\n }\n};\n\n// 明细/表单字段:未配置 → 默认禁止;配置且 is_modifiable=false → 禁止\n// 入参为表单叶子字段的 key(与 formEditable 的键一致,见 loadEditableMaps)\nconst isFormFieldDisabled = (fieldKey: string): boolean => {\n if (!fieldKey) return false;\n const editable = formEditable.value.get(fieldKey);\n if (editable === undefined) return true;\n return !editable;\n};\n\n// 全局字段里「系统生成、任何场景都禁止编辑」的名单:\n// 单据编号由后端按 前缀+年份后两位+月份+流水号 生成并落库 FormCode(/approve/get_form_code),\n// 新建、编辑、修改、复制一律只读,不参与数据存储规则 is_modifiable 的放开逻辑\nconst ALWAYS_READONLY_GLOBAL_PROPS = ['form_code'];\n\n// 全局字段:命中强制只读名单 → 禁;未配置 → 默认可编辑;配置且 is_modifiable=false → 禁止\nconst isGlobalDisabled = (prop: string): boolean => {\n if (ALWAYS_READONLY_GLOBAL_PROPS.includes(prop)) return true;\n const editable = globalEditable.value.get(prop);\n if (editable === undefined) return false;\n return !editable;\n};\n\n// 读取字段在页面配置里的「是否可编辑」三态配置(FormDesignModal → FieldSetting 高级属性):\n// 'disabled' 强制禁用 | 'enabled' 强制可用 | 'auto' / 未配置(旧配置兼容)→ 自动,走下面的默认计算逻辑\nconst getEditableMode = (item: any): 'auto' | 'disabled' | 'enabled' => {\n const mode = item?.editable_mode;\n return mode === 'disabled' || mode === 'enabled' ? mode : 'auto';\n};\n\n// 单个字段最终是否禁用。\n// inherited:外层容器(表单模板)显式配置的三态,作为内层字段的默认值。\n// 优先级:字段自身显式配置 > 外层容器显式配置 > 自动计算逻辑\n// 自动计算逻辑:页面配置里本来就 disabled 的字段保持禁用;否则按数据存储规则 is_modifiable 判定\nconst resolveFieldDisabled = (item: any, inherited: 'auto' | 'disabled' | 'enabled'): boolean => {\n const own = getEditableMode(item);\n const mode = own === 'auto' ? inherited : own;\n if (mode === 'disabled') return true;\n if (mode === 'enabled') return false;\n return !!item.disabled || isFormFieldDisabled(item.key);\n};\n\n// 递归遍历表单 dynamicFieldList,对叶子字段设置 disabled\n// 容器(分组,带 children)与表单模板(formtemplate,带嵌套 form.dynamicFieldList):\n// - 分组无 name,无法在 FieldSetting 中配置,仅递归\n// - formtemplate 自身不吃 disabled(渲染层 FormTemplate 不读该字段、也不下传),\n// 但显式配置的「禁用/可用」会作为默认值下传给内部字段,内部字段自身的显式配置优先\n// 叶子字段判定:有 key,且无 children / 嵌套 form 包裹。\nconst applyFormFieldDisabled = (form: any): any => {\n if (!form || !form.dynamicFieldList) return form;\n const clone = cloneDeep(form);\n const walk = (items: any[], inherited: 'auto' | 'disabled' | 'enabled' = 'auto') => {\n for (const item of items || []) {\n // 本层有效配置:自身显式配置优先,否则沿用外层下传的默认值,供子级继承\n const own = getEditableMode(item);\n const nextInherited = own === 'auto' ? inherited : own;\n // 1. 分组/容器:含 children,仅递归\n if (item.children && Array.isArray(item.children) && item.children.length) {\n walk(item.children, nextInherited);\n }\n // 2. 表单模板(formtemplate 等)嵌套 form.dynamicFieldList,需下钻到内部字段\n if (item.form && item.form.dynamicFieldList) {\n walk(item.form.dynamicFieldList, nextInherited);\n }\n // 3. 叶子字段:有 key,且无 children / 嵌套 form 包裹\n if (\n item.key &&\n !(item.children && item.children.length) &&\n !(item.form && item.form.dynamicFieldList)\n ) {\n item.disabled = resolveFieldDisabled(item, inherited);\n }\n }\n };\n walk(clone.dynamicFieldList);\n return clone;\n};\n\n// 编辑态(lockStructure)才克隆并打 disabled;新建/复制态直接返回原表单(不影响配置页)\nconst localForm = computed(() => {\n if (!lockStructure.value) return props.columnConfig.form;\n return applyFormFieldDisabled(props.columnConfig.form);\n});\n\n// 退出编辑态时清空映射,避免残留禁用全局字段\nwatch(lockStructure, val => {\n if (!val) {\n formEditable.value = new Map();\n globalEditable.value = new Map();\n }\n});\nconst syncValidate = ([_modelRef, _removeRulKeys]: any[]) => {\n const new_rules_obj = {};\n Object.keys(rulesRef).forEach(key => {\n if (key in _modelRef && !_removeRulKeys[key]) {\n new_rules_obj[key] = rulesRef[key];\n }\n });\n const newRes: any = useForm(_modelRef, new_rules_obj);\n validate = newRes.validate;\n validateInfos.value = newRes.validateInfos;\n};\nconst onUpdateModel = async params => {\n if (params.add_key) {\n // 添加字段时,不忽略校验,所以需要从removeRulKeys中删除\n delete removeRulKeys.value[params.add_key];\n syncValidate([modelRef.value, removeRulKeys.value]);\n } else if (params.remove_key) {\n // 删除字段时,忽略校验,所以需要添加到removeRulKeys中\n removeRulKeys.value[params.remove_key] = true;\n syncValidate([modelRef.value, removeRulKeys.value]);\n }\n};\nconst handleAction = action => {\n if (!action.action) {\n console.error('未定义action');\n return;\n }\n eventAction({\n code: action.code,\n action: action,\n params: {\n context: context.contexts[props.modelType],\n settings: action.settings,\n },\n });\n};\n\nconst saveContext = debounce(async (value = null) => {\n saveContextImmediately(value);\n}, 1000);\nconst saveContextImmediately = async (value = null) => {\n if (value === null) {\n value = modelRef.value;\n }\n context[SET_FORM_MODEL](props.modelType, value);\n await getApiData(\n { name: props.modelType, context: context.contexts[props.modelType] },\n '/approve/update_user_page_context',\n );\n};\nconst clearForm = async () => {\n editState.value = {};\n isEdit.value = false;\n modelRef.value = cloneDeep(props.columnConfig.form.model);\n context[CLEAR_CONTEXT](props.modelType);\n await getApiData({ name: props.modelType, context: null }, '/approve/update_user_page_context');\n props.eventBus.emit('reinit');\n};\nconst eventAction = async ({ code, action, params }) => {\n const action_type = action.action;\n // action.loading = true;\n try {\n if (action_type === 'save') {\n saveContext();\n } else if (action_type === 'save_approve') {\n let has_error = false;\n try {\n await validate();\n } catch (e) {\n console.log(e);\n has_error = true;\n }\n for (const func of Object.values(nestValidate.value)) {\n if (func) {\n try {\n await func();\n } catch (e) {\n console.log(e);\n has_error = true;\n }\n }\n }\n if (props.topFormRef) {\n try {\n await props.topFormRef.validate();\n } catch (e) {\n console.log(e);\n has_error = true;\n }\n }\n try {\n await formRef.value.validate();\n } catch (e) {\n has_error = true;\n }\n if (has_error) {\n // ⛔ 别写成 document.querySelectorAll('.form-container .ant-form-item-has-error'):\n // 那是**文档级**查询,取 `[0]` 只会拿到文档里靠前的那个实例(页面),\n // 于是模态框里点保存校验失败时,滚的是背后那个页面。\n // 改为从本实例根元素往下找 —— 单实例时与旧写法结果完全一致。\n const fieldItem =\n formContainerRef.value?.querySelectorAll('.ant-form-item-has-error') ?? [];\n if (fieldItem.length > 0) {\n fieldItem[0].scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n return;\n }\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n message.error(e.message);\n return;\n }\n if (isEdit.value) {\n if (modifyMode.value) {\n await createModifyApprove({\n source_approve_record_id: sourceApproveRecordId.value,\n data: { ...res.data, globalData: props.globalData },\n page_setting_history_id: context.contexts?.[props.modelType]?.current_history_id,\n context: props.globalData.context?.context || '',\n });\n } else {\n await getApiData(\n {\n approve_record_id: editState.value.id,\n data: { ...res.data, globalData: props.globalData },\n context: props.globalData.context?.context || '',\n },\n '/approve/update_approve_record',\n );\n }\n } else {\n await getApiData(\n {\n menu_flag: props.modelType,\n data: {\n ...res.data,\n globalData: props.globalData,\n },\n page_setting_history_id: context.contexts?.[props.modelType]?.current_history_id,\n context: props.globalData.context?.context || '',\n number: props.globalData.number,\n },\n '/approve/create_approve_record',\n );\n }\n message.success('提交成功');\n // clearForm() 会把 isEdit / modifyMode 重置掉,所以先捕获再清。\n // 详情场景的全屏模态框靠这个事件**刷新背后的详情与列表** —— 但**不关**模态框\n // (2026-09-21 定案:保存只是暂存,用户还要在右侧继续「提交」,关闭走右上角关闭按钮)。\n // 路由页面场景没有监听方,emit 出去无副作用。\n const saved_is_edit = isEdit.value;\n const saved_modify_mode = modifyMode.value;\n clearForm();\n props.eventBus.emit('saved', {\n isEdit: saved_is_edit,\n modifyMode: saved_modify_mode,\n });\n }\n } else if (action_type === 'commit_approve') {\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const _id of ids) {\n await getApiData({ approve_record_id: _id }, '/approve/commit_approve_record');\n }\n props.eventBus.emit('reload_table');\n message.success('提交成功');\n }\n } else if (action_type === 'delete_approve') {\n if (code) {\n Modal.confirm({\n title: '提示',\n content: '是否确认要执行删除操作',\n async onOk() {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const id of ids) {\n await getApiData({ approve_record_id: id }, '/approve/delete_approve_record');\n }\n props.eventBus.emit('reload_table');\n message.success('删除成功');\n },\n onCancel() {},\n });\n }\n } else if (action_type === 'cancel_approve') {\n if (code) {\n Modal.confirm({\n title: '提示',\n content: '是否确认要执行撤销操作',\n async onOk() {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const id of ids) {\n await getApiData({ approve_record_id: id }, '/approve/cancel_approve_record');\n }\n props.eventBus.emit('reload_table');\n message.success('撤销成功');\n },\n onCancel() {},\n });\n }\n } else if (action_type === 'cancel_agree_approve') {\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n if (!(ids.length === 1)) {\n message.error('每次仅能作废一个审批单');\n return;\n }\n cancelRecordId.value = ids[0];\n cancelModalShow.value = true;\n }\n } else if (action_type === 'send_reminder') {\n if (code) {\n Modal.confirm({\n title: '提示',\n content: '是否确认要执行催办操作',\n async onOk() {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const id of ids) {\n await getApiData({ process_instance_id: id }, '/lyapprove/manul_recreate_task');\n }\n message.success('催办成功');\n },\n onCancel() {},\n });\n }\n } else if (action_type === 'clear_form') {\n Modal.confirm({\n title: '确定要清空表单吗?',\n onOk: () => {\n clearForm();\n },\n });\n } else if (action_type === 'process') {\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n if (res != null) {\n modelRef.value = res;\n saveContext();\n }\n }\n }\n } finally {\n // action.loading = false;\n }\n};\nconst updateFormEvent = ({ data, state }) => {\n modelRef.value = data;\n editState.value = state;\n isEdit.value = true;\n modifyMode.value = !!(state && state.modifyMode);\n sourceApproveRecordId.value = (state && state.source_approve_record_id) || null;\n // 修改模式,或记录本身带 modify_source(即「修改上一个审批」的记录)时,锁定表单结构\n lockStructure.value = modifyMode.value || !!(state && state.modify_source_id);\n if (lockStructure.value) loadEditableMaps();\n context[SET_EDIT](props.modelType, true, state);\n saveContextImmediately();\n};\n/**\n * 复制为新审批(copy_approve):用源审批的数据覆盖当前表单,但表单本身回到「新建」态,\n * 保存时会走 create_approve_record 新建一条待提交审批。\n * 全局数据(含重新生成后的流水号、单据编号)与只读动态值的清空/重算由 index.vue 处理。\n */\nconst copyFormEvent = ({ data }) => {\n modelRef.value = data;\n editState.value = {};\n isEdit.value = false;\n modifyMode.value = false;\n sourceApproveRecordId.value = null;\n lockStructure.value = false;\n formEditable.value = new Map();\n globalEditable.value = new Map();\n context[SET_EDIT](props.modelType, false, {});\n saveContextImmediately();\n};\nonMounted(() => {\n props.eventBus.on('run_action', eventAction);\n props.eventBus.on('update_form', updateFormEvent);\n props.eventBus.on('copy_form', copyFormEvent);\n const {\n formModel,\n isEdit: _isedit,\n editState: _editstate,\n } = context.contexts?.[props.modelType] || {};\n if (formModel) {\n modelRef.value = formModel;\n }\n syncValidate([modelRef.value, removeRulKeys.value]);\n if (_isedit) {\n isEdit.value = _isedit;\n editState.value = _editstate;\n modifyMode.value = !!(editState.value && editState.value.modifyMode);\n sourceApproveRecordId.value =\n (editState.value && editState.value.source_approve_record_id) || null;\n // 修改模式,或记录本身带 modify_source(即「修改上一个审批」的记录)时,锁定表单结构\n lockStructure.value =\n modifyMode.value || !!(editState.value && editState.value.modify_source_id);\n if (lockStructure.value) loadEditableMaps();\n }\n});\nconst handleGlobalDataChange = update => {\n emit('globalDataChange', update);\n};\nwatch(\n () => modelRef.value,\n newValue => {\n saveContext(newValue);\n syncValidate([newValue, removeRulKeys.value]);\n },\n { deep: true },\n);\nonUnmounted(() => {\n props.eventBus.off('run_action', eventAction);\n props.eventBus.off('update_form', updateFormEvent);\n props.eventBus.off('copy_form', copyFormEvent);\n});\n/**\n * 「数据选择」弹窗:供自定义按钮代码(workerHostFunctions)调用,打开已配置的数据列表弹窗。\n *\n * @param title 弹窗标题\n * @param tables 要展示的表,逐表可配置:\n * - `id`:页面配置里的「表格标识」\n * - `isMul`:是否多选(true → checkbox,否则 radio)\n * - `min_count` / `max_count`:**可选**,最少/最多选择条数。配置了才校验(每张表各自校验,\n * 只在点确定时拦截),并在表头提示规则与实时已选条数、确定不满足时在弹窗底部红字提示。\n * 全部表都没配 → 与历史行为完全一致。\n * @returns {Promise<{ context: any } | null>} 确定为 `{ context }`,取消为 null\n */\nconst showTables = async ({ title, tables }: { title?: string; tables?: SelectTableConfig[] }) => {\n let thisColumnConfig = null;\n for (const item of props.approvalConfig?.columns || []) {\n if (item.type === 'tables') {\n thisColumnConfig = item;\n break;\n }\n }\n return new Promise(async (resolve, reject) => {\n const tempModal = reactive({\n component: defineAsyncComponent(() => import('./tableModal.vue')),\n columnConfig: thisColumnConfig,\n height: props.height,\n eventBus: props.eventBus,\n modelType: props.modelType,\n approvalConfig: props.approvalConfig,\n tables: tables || [],\n title: title || '数据选择',\n open: true,\n hideAllButtons: true,\n ok: (data: any) => {\n resolve(data);\n },\n cancel: () => {\n resolve(null);\n },\n });\n modalBox(tempModal);\n });\n};\nconst workerHostFunctions = {\n showTables,\n};\n</script>\n<style lang=\"less\" scoped>\n.form-container {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n height: 100%;\n padding: 4px;\n .form-header {\n padding: 4px;\n }\n .form-body {\n flex: 1 1 auto;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 4px;\n }\n .form-footer {\n flex: 0 0 auto;\n padding: 8px;\n border-top: 1px solid #e8e8e8;\n display: flex;\n justify-content: flex-end;\n }\n}\n.base-info {\n ::v-deep(.ant-card-head) {\n padding: 0 8px;\n min-height: 44px;\n background-color: rgba(0, 0, 0, 0.02);\n }\n}\n</style>\n","<template>\n <div\n class=\"form-container\"\n ref=\"formContainerRef\"\n >\n <div class=\"form-body\">\n <div class=\"base-info\">\n <a-card :body-style=\"{ padding: '10px 10px 0' }\">\n <template #extra>\n <a-tag\n v-if=\"isEdit\"\n color=\"blue\"\n >\n 流水号:{{ editState.number }}【编辑】\n </a-tag>\n <a-tag\n v-else\n color=\"blue\"\n >\n 流水号:{{ globalData.number }}\n </a-tag>\n </template>\n <template #title>基础信息</template>\n <a-form\n layout=\"vertical\"\n size=\"small\"\n :model=\"globalData\"\n ref=\"formRef\"\n >\n <a-row :gutter=\"36\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"单据编号\"\n name=\"form_code\"\n :rules=\"[{ required: true }]\"\n >\n <form-code-input\n v-model:value=\"globalData.form_code\"\n :disabled=\"isGlobalDisabled('form_code')\"\n @change=\"handleGlobalDataChange($event)\"\n ></form-code-input>\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"制单日期\"\n name=\"create_date\"\n :rules=\"[{ required: true }]\"\n >\n <SystemTime\n v-model:value=\"globalData.create_date\"\n :disabled=\"isGlobalDisabled('create_date')\"\n @change=\"handleGlobalDataChange($event)\"\n style=\"width: 100%\"\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"8\">\n <a-form-item\n label=\"流程组织\"\n name=\"create_by\"\n :validateTrigger=\"false\"\n >\n <FormFlowOrgInput\n v-model:value=\"globalData.flow_org\"\n :model-type=\"modelType\"\n :disabled=\"isGlobalDisabled('flow_org')\"\n @change=\"handleGlobalDataChange($event)\"\n ></FormFlowOrgInput>\n </a-form-item>\n </a-col>\n <a-col :span=\"8\">\n <a-form-item\n label=\"制单人\"\n name=\"create_by\"\n :validateTrigger=\"false\"\n :rules=\"isDev ? [] : [{ required: true }]\"\n >\n <CreateByCascader\n :value=\"globalData\"\n :disabled=\"isGlobalDisabled('create_by')\"\n @change=\"handleGlobalDataChange($event)\"\n ></CreateByCascader>\n </a-form-item>\n </a-col>\n <a-col :span=\"8\">\n <a-form-item\n label=\"职位\"\n name=\"person_position\"\n :validateTrigger=\"false\"\n :rules=\"isDev ? [] : [{ required: true }]\"\n >\n <PostionCascader\n :value=\"globalData\"\n :disabled=\"isGlobalDisabled('person_position')\"\n @change=\"handleGlobalDataChange($event)\"\n ></PostionCascader>\n </a-form-item>\n </a-col>\n </a-row>\n\n <a-form-item\n label=\"流程主题\"\n name=\"context\"\n :rules=\"[{ required: true }]\"\n >\n <form-context-input\n v-model:value=\"globalData.context\"\n :disabled=\"isGlobalDisabled('context')\"\n @change=\"handleGlobalDataChange\"\n style=\"width: 100%\"\n ></form-context-input>\n </a-form-item>\n </a-form>\n </a-card>\n </div>\n <form-render-3\n v-if=\"columnConfig.form?.dynamicFieldList\"\n :form=\"localForm\"\n :model=\"modelRef\"\n :options=\"columnConfig.form?.options\"\n :validateInfos=\"validateInfos\"\n @update_model=\"onUpdateModel\"\n :alwaysShowGroup=\"true\"\n :context=\"context.contexts?.[modelType]\"\n :nestValidate=\"nestValidate\"\n :worker-host-functions=\"workerHostFunctions\"\n :lock-structure=\"lockStructure\"\n />\n </div>\n <div\n class=\"form-footer\"\n v-if=\"columnConfig.actions && columnConfig.actions.length > 0\"\n >\n <actions-bar\n :actions=\"columnConfig.actions\"\n @click=\"handleAction\"\n :params=\"{\n context: context.contexts?.[modelType] || {},\n }\"\n />\n </div>\n </div>\n <CancelModal\n v-model:cancel-modal-show=\"cancelModalShow\"\n :id=\"cancelRecordId\"\n :event-bus=\"eventBus\"\n ></CancelModal>\n</template>\n\n<script lang=\"ts\">\nimport { ApprovalSetting, FormSection } from '../typing';\n\n// 该 props 由父组件(index.vue)创建的 mitt 实例传入,这里仅声明本组件用到的接口\ninterface ApprovalEventBus {\n on(event: string, handler: (payload: any) => void): void;\n off(event: string, handler: (payload: any) => void): void;\n emit(event: string, payload?: any): void;\n}\n\n/**\n * 必须放在普通 <script> 块里(<script setup> 不允许 ES 模块导出):\n * 父组件 index.vue 的默认导出类型会引用本组件的 props 类型,类型不可命名时\n * vue-tsc 既产不出本文件的 .d.ts,也会连锁让 index.vue 报 TS4082。\n */\nexport interface ColumnFormProps {\n columnConfig: FormSection;\n height: number;\n modelType: string;\n eventBus: ApprovalEventBus;\n globalData: Record<string, any>;\n topFormRef: any;\n approvalConfig: ApprovalSetting;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { useForm } from 'ant-design-vue/es/form';\nimport { defineAsyncComponent, computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue';\nimport { SelectTableConfig } from '../typing';\n//@ts-ignore\nimport {\n CLEAR_CONTEXT,\n SET_EDIT,\n SET_FORM_MODEL,\n useContextStore,\n} from '@/components/approval/store/context';\nimport { message, Modal } from 'ant-design-vue';\nimport { executeScriptInWorker, getApiData, modalBox } from '@/init-plugin';\nimport { createModifyApprove } from '../utils';\nimport { getDataStoreConfig } from '../index';\nimport { cloneDeep, debounce } from 'lodash';\nimport SystemTime from '../SystemTime.vue';\nimport actionsBar from './actionsBar.vue';\nimport FormCodeInput from './FormCodeInput.vue';\nimport FormContextInput from './FormContextInput.vue';\nimport CreateByCascader from '../CreateByCascader.vue';\nimport PostionCascader from '../PostionCascader.vue';\nimport CancelModal from './CancelModal.vue';\nimport FormFlowOrgInput from './FormFlowOrgInput.vue';\n\ndefineOptions({ name: 'ApprovalColumnForm' });\n\n// ApprovalEventBus / ColumnFormProps 见文件顶部的普通 <script> 块(为了能 export)\nconst props = defineProps<ColumnFormProps>();\nconst emit = defineEmits<{ (e: 'globalDataChange', update: any): void }>();\n\nconst context = useContextStore();\nconst modelRef = ref(cloneDeep(props.columnConfig.form.model));\nconst rulesRef = reactive(cloneDeep(props.columnConfig.form.rules));\nconst validateInfos = ref({});\nconst isEdit = ref(false);\nconst modifyMode = ref(false);\nconst sourceApproveRecordId = ref<any>(null);\n// 修改模式锁定表单结构(隐藏添加/清空/导入/行删除),由 FormRender3 深层透传\nconst lockStructure = ref(false);\n// 本地开发模式(非生产)下放宽校验:制单人/职位不强制必填\nconst isDev = process.env.NODE_ENV !== 'production';\nconst editState = ref<any>({});\nconst nestValidate = ref({});\nconst formRef = ref();\n/**\n * 本组件根元素(`.form-container`)。\n * 校验失败后要把第一个报错字段滚进视野,**必须在本实例的子树里找**:\n * 页面 + 「修改」全屏模态框会同时存在两个 `.form-container`,而 `a-modal` 的 wrapper\n * 追加在 `#app` 之后 —— 文档级查询取 `[0]` 拿到的是**页面**那个,会把背后那个页面滚起来、\n * 模态框自己不动。同一个组件会有多份实例这件事,与竖条 Teleport 锚点是同一类问题。\n */\nconst formContainerRef = ref<HTMLElement | null>(null);\nconst cancelModalShow = ref(false);\nconst cancelRecordId = ref(null);\n// 记录需要忽略校验的字段\nconst removeRulKeys = ref([]);\nlet validate: any;\n\n// ===== 编辑态字段可编辑性控制(基于数据存储规则配置 ExcelColumnConfig.is_modifiable)=====\n// 明细/表单字段(source_type='form'):默认禁止编辑,仅当规则里对应字段 is_modifiable=true 才允许\n// 全局字段(source_type='global'):默认允许编辑,仅当规则里对应字段 is_modifiable=false 才禁止\n// 且:字段本身在页面配置里就已禁用(disabled=true,如只读/系统回填字段)时,编辑态一律保持禁用,\n// 不因规则 is_modifiable=true 而放开(原有禁用状态优先)\n// 另外:页面配置里每个字段可显式指定「是否可编辑」三态(editable_mode:自动/禁用/可用,见 FieldSetting 高级属性),\n// 非自动时以显式配置为准(禁用=强制不可编辑,可用=强制可编辑),自动/未配置时才走上面的规则计算逻辑\n// 注:与后端 approve/utils.py::check_data_store 不同,这里只控制「编辑态 UI 是否可改」,不改变导入结构\nconst formEditable = ref<Map<string, boolean>>(new Map());\nconst globalEditable = ref<Map<string, boolean>>(new Map());\n\nconst loadEditableMaps = async () => {\n try {\n const { config } = await getDataStoreConfig(props.modelType);\n const fMap = new Map<string, boolean>();\n const gMap = new Map<string, boolean>();\n for (const rule of (config as any[]) || []) {\n for (const f of rule.fields || []) {\n const isMod = !!(f.data_column && f.data_column.is_modifiable);\n if (f.source_type === 'form' && Array.isArray(f.source_value) && f.source_value.length) {\n // source_value 是表单字段 key 路径(cascade 选择的是 field.key,叶子即字段自身的 key),\n // 取最后一段(叶子字段 key)作为匹配键,与表单叶子字段的 key 对齐。\n // 注意:表单字段的 name 不在 source_value 中,不能用来匹配。\n fMap.set(f.source_value[f.source_value.length - 1], isMod);\n } else if (\n f.source_type === 'global' &&\n Array.isArray(f.source_value) &&\n f.source_value.length\n ) {\n // source_value[0] 即顶部全局组件绑定的 globalData 属性名(form_code/create_date/flow_org/create_by/person_position/context)\n gMap.set(f.source_value[0], isMod);\n }\n }\n }\n formEditable.value = fMap;\n globalEditable.value = gMap;\n } catch (e) {\n console.error('加载数据存储配置失败,编辑态字段可编辑性控制未生效', e);\n formEditable.value = new Map();\n globalEditable.value = new Map();\n }\n};\n\n// 明细/表单字段:未配置 → 默认禁止;配置且 is_modifiable=false → 禁止\n// 入参为表单叶子字段的 key(与 formEditable 的键一致,见 loadEditableMaps)\nconst isFormFieldDisabled = (fieldKey: string): boolean => {\n if (!fieldKey) return false;\n const editable = formEditable.value.get(fieldKey);\n if (editable === undefined) return true;\n return !editable;\n};\n\n// 全局字段里「系统生成、任何场景都禁止编辑」的名单:\n// 单据编号由后端按 前缀+年份后两位+月份+流水号 生成并落库 FormCode(/approve/get_form_code),\n// 新建、编辑、修改、复制一律只读,不参与数据存储规则 is_modifiable 的放开逻辑\nconst ALWAYS_READONLY_GLOBAL_PROPS = ['form_code'];\n\n// 全局字段:命中强制只读名单 → 禁;未配置 → 默认可编辑;配置且 is_modifiable=false → 禁止\nconst isGlobalDisabled = (prop: string): boolean => {\n if (ALWAYS_READONLY_GLOBAL_PROPS.includes(prop)) return true;\n const editable = globalEditable.value.get(prop);\n if (editable === undefined) return false;\n return !editable;\n};\n\n// 读取字段在页面配置里的「是否可编辑」三态配置(FormDesignModal → FieldSetting 高级属性):\n// 'disabled' 强制禁用 | 'enabled' 强制可用 | 'auto' / 未配置(旧配置兼容)→ 自动,走下面的默认计算逻辑\nconst getEditableMode = (item: any): 'auto' | 'disabled' | 'enabled' => {\n const mode = item?.editable_mode;\n return mode === 'disabled' || mode === 'enabled' ? mode : 'auto';\n};\n\n// 单个字段最终是否禁用。\n// inherited:外层容器(表单模板)显式配置的三态,作为内层字段的默认值。\n// 优先级:字段自身显式配置 > 外层容器显式配置 > 自动计算逻辑\n// 自动计算逻辑:页面配置里本来就 disabled 的字段保持禁用;否则按数据存储规则 is_modifiable 判定\nconst resolveFieldDisabled = (item: any, inherited: 'auto' | 'disabled' | 'enabled'): boolean => {\n const own = getEditableMode(item);\n const mode = own === 'auto' ? inherited : own;\n if (mode === 'disabled') return true;\n if (mode === 'enabled') return false;\n return !!item.disabled || isFormFieldDisabled(item.key);\n};\n\n// 递归遍历表单 dynamicFieldList,对叶子字段设置 disabled\n// 容器(分组,带 children)与表单模板(formtemplate,带嵌套 form.dynamicFieldList):\n// - 分组无 name,无法在 FieldSetting 中配置,仅递归\n// - formtemplate 自身不吃 disabled(渲染层 FormTemplate 不读该字段、也不下传),\n// 但显式配置的「禁用/可用」会作为默认值下传给内部字段,内部字段自身的显式配置优先\n// 叶子字段判定:有 key,且无 children / 嵌套 form 包裹。\nconst applyFormFieldDisabled = (form: any): any => {\n if (!form || !form.dynamicFieldList) return form;\n const clone = cloneDeep(form);\n const walk = (items: any[], inherited: 'auto' | 'disabled' | 'enabled' = 'auto') => {\n for (const item of items || []) {\n // 本层有效配置:自身显式配置优先,否则沿用外层下传的默认值,供子级继承\n const own = getEditableMode(item);\n const nextInherited = own === 'auto' ? inherited : own;\n // 1. 分组/容器:含 children,仅递归\n if (item.children && Array.isArray(item.children) && item.children.length) {\n walk(item.children, nextInherited);\n }\n // 2. 表单模板(formtemplate 等)嵌套 form.dynamicFieldList,需下钻到内部字段\n if (item.form && item.form.dynamicFieldList) {\n walk(item.form.dynamicFieldList, nextInherited);\n }\n // 3. 叶子字段:有 key,且无 children / 嵌套 form 包裹\n if (\n item.key &&\n !(item.children && item.children.length) &&\n !(item.form && item.form.dynamicFieldList)\n ) {\n item.disabled = resolveFieldDisabled(item, inherited);\n }\n }\n };\n walk(clone.dynamicFieldList);\n return clone;\n};\n\n// 编辑态(lockStructure)才克隆并打 disabled;新建/复制态直接返回原表单(不影响配置页)\nconst localForm = computed(() => {\n if (!lockStructure.value) return props.columnConfig.form;\n return applyFormFieldDisabled(props.columnConfig.form);\n});\n\n// 退出编辑态时清空映射,避免残留禁用全局字段\nwatch(lockStructure, val => {\n if (!val) {\n formEditable.value = new Map();\n globalEditable.value = new Map();\n }\n});\nconst syncValidate = ([_modelRef, _removeRulKeys]: any[]) => {\n const new_rules_obj = {};\n Object.keys(rulesRef).forEach(key => {\n if (key in _modelRef && !_removeRulKeys[key]) {\n new_rules_obj[key] = rulesRef[key];\n }\n });\n const newRes: any = useForm(_modelRef, new_rules_obj);\n validate = newRes.validate;\n validateInfos.value = newRes.validateInfos;\n};\nconst onUpdateModel = async params => {\n if (params.add_key) {\n // 添加字段时,不忽略校验,所以需要从removeRulKeys中删除\n delete removeRulKeys.value[params.add_key];\n syncValidate([modelRef.value, removeRulKeys.value]);\n } else if (params.remove_key) {\n // 删除字段时,忽略校验,所以需要添加到removeRulKeys中\n removeRulKeys.value[params.remove_key] = true;\n syncValidate([modelRef.value, removeRulKeys.value]);\n }\n};\nconst handleAction = action => {\n if (!action.action) {\n console.error('未定义action');\n return;\n }\n eventAction({\n code: action.code,\n action: action,\n params: {\n context: context.contexts[props.modelType],\n settings: action.settings,\n },\n });\n};\n\nconst saveContext = debounce(async (value = null) => {\n saveContextImmediately(value);\n}, 1000);\nconst saveContextImmediately = async (value = null) => {\n if (value === null) {\n value = modelRef.value;\n }\n context[SET_FORM_MODEL](props.modelType, value);\n await getApiData(\n { name: props.modelType, context: context.contexts[props.modelType] },\n '/approve/update_user_page_context',\n );\n};\nconst clearForm = async () => {\n editState.value = {};\n isEdit.value = false;\n modelRef.value = cloneDeep(props.columnConfig.form.model);\n context[CLEAR_CONTEXT](props.modelType);\n await getApiData({ name: props.modelType, context: null }, '/approve/update_user_page_context');\n props.eventBus.emit('reinit');\n};\nconst eventAction = async ({ code, action, params }) => {\n const action_type = action.action;\n // action.loading = true;\n try {\n if (action_type === 'save') {\n saveContext();\n } else if (action_type === 'save_approve') {\n let has_error = false;\n try {\n await validate();\n } catch (e) {\n console.log(e);\n has_error = true;\n }\n for (const func of Object.values(nestValidate.value)) {\n if (func) {\n try {\n await func();\n } catch (e) {\n console.log(e);\n has_error = true;\n }\n }\n }\n if (props.topFormRef) {\n try {\n await props.topFormRef.validate();\n } catch (e) {\n console.log(e);\n has_error = true;\n }\n }\n try {\n await formRef.value.validate();\n } catch (e) {\n has_error = true;\n }\n if (has_error) {\n // ⛔ 别写成 document.querySelectorAll('.form-container .ant-form-item-has-error'):\n // 那是**文档级**查询,取 `[0]` 只会拿到文档里靠前的那个实例(页面),\n // 于是模态框里点保存校验失败时,滚的是背后那个页面。\n // 改为从本实例根元素往下找 —— 单实例时与旧写法结果完全一致。\n const fieldItem =\n formContainerRef.value?.querySelectorAll('.ant-form-item-has-error') ?? [];\n if (fieldItem.length > 0) {\n fieldItem[0].scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n return;\n }\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n message.error(e.message);\n return;\n }\n if (isEdit.value) {\n if (modifyMode.value) {\n await createModifyApprove({\n source_approve_record_id: sourceApproveRecordId.value,\n data: { ...res.data, globalData: props.globalData },\n page_setting_history_id: context.contexts?.[props.modelType]?.current_history_id,\n context: props.globalData.context?.context || '',\n });\n } else {\n await getApiData(\n {\n approve_record_id: editState.value.id,\n data: { ...res.data, globalData: props.globalData },\n context: props.globalData.context?.context || '',\n },\n '/approve/update_approve_record',\n );\n }\n } else {\n await getApiData(\n {\n menu_flag: props.modelType,\n data: {\n ...res.data,\n globalData: props.globalData,\n },\n page_setting_history_id: context.contexts?.[props.modelType]?.current_history_id,\n context: props.globalData.context?.context || '',\n number: props.globalData.number,\n },\n '/approve/create_approve_record',\n );\n }\n message.success('提交成功');\n // clearForm() 会把 isEdit / modifyMode 重置掉,所以先捕获再清。\n // 详情场景的全屏模态框靠这个事件**刷新背后的详情与列表** —— 但**不关**模态框\n // (2026-09-21 定案:保存只是暂存,用户还要在右侧继续「提交」,关闭走右上角关闭按钮)。\n // 路由页面场景没有监听方,emit 出去无副作用。\n const saved_is_edit = isEdit.value;\n const saved_modify_mode = modifyMode.value;\n clearForm();\n props.eventBus.emit('saved', {\n isEdit: saved_is_edit,\n modifyMode: saved_modify_mode,\n });\n }\n } else if (action_type === 'commit_approve') {\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const _id of ids) {\n await getApiData({ approve_record_id: _id }, '/approve/commit_approve_record');\n }\n props.eventBus.emit('reload_table');\n message.success('提交成功');\n }\n } else if (action_type === 'delete_approve') {\n if (code) {\n Modal.confirm({\n title: '提示',\n content: '是否确认要执行删除操作',\n async onOk() {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const id of ids) {\n await getApiData({ approve_record_id: id }, '/approve/delete_approve_record');\n }\n props.eventBus.emit('reload_table');\n message.success('删除成功');\n },\n onCancel() {},\n });\n }\n } else if (action_type === 'cancel_approve') {\n if (code) {\n Modal.confirm({\n title: '提示',\n content: '是否确认要执行撤销操作',\n async onOk() {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const id of ids) {\n await getApiData({ approve_record_id: id }, '/approve/cancel_approve_record');\n }\n props.eventBus.emit('reload_table');\n message.success('撤销成功');\n },\n onCancel() {},\n });\n }\n } else if (action_type === 'cancel_agree_approve') {\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n if (!(ids.length === 1)) {\n message.error('每次仅能作废一个审批单');\n return;\n }\n cancelRecordId.value = ids[0];\n cancelModalShow.value = true;\n }\n } else if (action_type === 'send_reminder') {\n if (code) {\n Modal.confirm({\n title: '提示',\n content: '是否确认要执行催办操作',\n async onOk() {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n let { ids } = res;\n\n if (!ids) {\n message.error('代码未返回ids');\n return;\n }\n if (!(ids instanceof Array)) {\n message.error('ids应为数组');\n return;\n }\n for (const id of ids) {\n await getApiData({ process_instance_id: id }, '/lyapprove/manul_recreate_task');\n }\n message.success('催办成功');\n },\n onCancel() {},\n });\n }\n } else if (action_type === 'clear_form') {\n Modal.confirm({\n title: '确定要清空表单吗?',\n onOk: () => {\n clearForm();\n },\n });\n } else if (action_type === 'process') {\n if (code) {\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e.message);\n return;\n }\n if (res != null) {\n modelRef.value = res;\n saveContext();\n }\n }\n }\n } finally {\n // action.loading = false;\n }\n};\nconst updateFormEvent = ({ data, state }) => {\n modelRef.value = data;\n editState.value = state;\n isEdit.value = true;\n modifyMode.value = !!(state && state.modifyMode);\n sourceApproveRecordId.value = (state && state.source_approve_record_id) || null;\n // 修改模式,或记录本身带 modify_source(即「修改上一个审批」的记录)时,锁定表单结构\n lockStructure.value = modifyMode.value || !!(state && state.modify_source_id);\n if (lockStructure.value) loadEditableMaps();\n context[SET_EDIT](props.modelType, true, state);\n saveContextImmediately();\n};\n/**\n * 复制为新审批(copy_approve):用源审批的数据覆盖当前表单,但表单本身回到「新建」态,\n * 保存时会走 create_approve_record 新建一条待提交审批。\n * 全局数据(含重新生成后的流水号、单据编号)与只读动态值的清空/重算由 index.vue 处理。\n */\nconst copyFormEvent = ({ data }) => {\n modelRef.value = data;\n editState.value = {};\n isEdit.value = false;\n modifyMode.value = false;\n sourceApproveRecordId.value = null;\n lockStructure.value = false;\n formEditable.value = new Map();\n globalEditable.value = new Map();\n context[SET_EDIT](props.modelType, false, {});\n saveContextImmediately();\n};\nonMounted(() => {\n props.eventBus.on('run_action', eventAction);\n props.eventBus.on('update_form', updateFormEvent);\n props.eventBus.on('copy_form', copyFormEvent);\n const {\n formModel,\n isEdit: _isedit,\n editState: _editstate,\n } = context.contexts?.[props.modelType] || {};\n if (formModel) {\n modelRef.value = formModel;\n }\n syncValidate([modelRef.value, removeRulKeys.value]);\n if (_isedit) {\n isEdit.value = _isedit;\n editState.value = _editstate;\n modifyMode.value = !!(editState.value && editState.value.modifyMode);\n sourceApproveRecordId.value =\n (editState.value && editState.value.source_approve_record_id) || null;\n // 修改模式,或记录本身带 modify_source(即「修改上一个审批」的记录)时,锁定表单结构\n lockStructure.value =\n modifyMode.value || !!(editState.value && editState.value.modify_source_id);\n if (lockStructure.value) loadEditableMaps();\n }\n});\nconst handleGlobalDataChange = update => {\n emit('globalDataChange', update);\n};\nwatch(\n () => modelRef.value,\n newValue => {\n saveContext(newValue);\n syncValidate([newValue, removeRulKeys.value]);\n },\n { deep: true },\n);\nonUnmounted(() => {\n props.eventBus.off('run_action', eventAction);\n props.eventBus.off('update_form', updateFormEvent);\n props.eventBus.off('copy_form', copyFormEvent);\n});\n/**\n * 「数据选择」弹窗:供自定义按钮代码(workerHostFunctions)调用,打开已配置的数据列表弹窗。\n *\n * @param title 弹窗标题\n * @param tables 要展示的表,逐表可配置:\n * - `id`:页面配置里的「表格标识」\n * - `isMul`:是否多选(true → checkbox,否则 radio)\n * - `min_count` / `max_count`:**可选**,最少/最多选择条数。配置了才校验(每张表各自校验,\n * 只在点确定时拦截),并在表头提示规则与实时已选条数、确定不满足时在弹窗底部红字提示。\n * 全部表都没配 → 与历史行为完全一致。\n * @returns {Promise<{ context: any } | null>} 确定为 `{ context }`,取消为 null\n */\nconst showTables = async ({ title, tables }: { title?: string; tables?: SelectTableConfig[] }) => {\n let thisColumnConfig = null;\n for (const item of props.approvalConfig?.columns || []) {\n if (item.type === 'tables') {\n thisColumnConfig = item;\n break;\n }\n }\n return new Promise(async (resolve, reject) => {\n const tempModal = reactive({\n component: defineAsyncComponent(() => import('./tableModal.vue')),\n columnConfig: thisColumnConfig,\n height: props.height,\n eventBus: props.eventBus,\n modelType: props.modelType,\n approvalConfig: props.approvalConfig,\n tables: tables || [],\n title: title || '数据选择',\n open: true,\n hideAllButtons: true,\n ok: (data: any) => {\n resolve(data);\n },\n cancel: () => {\n resolve(null);\n },\n });\n modalBox(tempModal);\n });\n};\nconst workerHostFunctions = {\n showTables,\n};\n</script>\n<style lang=\"less\" scoped>\n.form-container {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n height: 100%;\n padding: 4px;\n .form-header {\n padding: 4px;\n }\n .form-body {\n flex: 1 1 auto;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 4px;\n }\n .form-footer {\n flex: 0 0 auto;\n padding: 8px;\n border-top: 1px solid #e8e8e8;\n display: flex;\n justify-content: flex-end;\n }\n}\n.base-info {\n ::v-deep(.ant-card-head) {\n padding: 0 8px;\n min-height: 44px;\n background-color: rgba(0, 0, 0, 0.02);\n }\n}\n</style>\n","<template>\n <div class=\"data-list-container\">\n <div\n class=\"data-list-header\"\n ref=\"headerRef\"\n >\n <div class=\"data-list-title\">\n <b>\n {{ columnConfig.table?.title }}\n </b>\n </div>\n </div>\n <div class=\"data-list-body\">\n <ApprovalTable\n v-if=\"columnConfig.table\"\n :config=\"columnConfig.table\"\n :height=\"contentHeight\"\n :modelType=\"modelType\"\n :event-bus=\"eventBus\"\n />\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, ref } from 'vue';\nimport ApprovalTable from './table.vue';\nimport { useResizeObserver } from '@vueuse/core';\nexport default defineComponent({\n name: 'ApprovalColumnDataList',\n props: {\n columnConfig: {\n type: Object,\n required: true,\n },\n height: {\n type: Number,\n required: true,\n },\n eventBus: {\n type: Object,\n required: true,\n },\n modelType: {\n type: String,\n required: true,\n },\n },\n setup(props) {\n const headerRef = ref(null);\n const headerHeight = ref(null);\n useResizeObserver(headerRef, entries => {\n headerHeight.value = entries[0].contentRect.height;\n });\n const contentHeight = computed(() => {\n if (headerRef.value && props.height) {\n return props.height - headerHeight.value;\n } else {\n return null;\n }\n });\n return { headerRef, contentHeight };\n },\n components: {\n ApprovalTable,\n },\n});\n</script>\n<style lang=\"less\" scoped>\n.data-list-container {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n height: 100%;\n padding: 4px;\n .data-list-header {\n display: flex;\n flex: 0 0 auto;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 4px;\n margin-right: 26px;\n .data-list-title {\n font-size: 15px;\n }\n }\n .data-list-body {\n flex: 1 1 auto;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 4px;\n }\n}\n</style>\n","<template>\n <div class=\"data-list-container\">\n <div\n class=\"data-list-header\"\n ref=\"headerRef\"\n >\n <div class=\"data-list-title\">\n <b>\n {{ columnConfig.table?.title }}\n </b>\n </div>\n </div>\n <div class=\"data-list-body\">\n <ApprovalTable\n v-if=\"columnConfig.table\"\n :config=\"columnConfig.table\"\n :height=\"contentHeight\"\n :modelType=\"modelType\"\n :event-bus=\"eventBus\"\n />\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, ref } from 'vue';\nimport ApprovalTable from './table.vue';\nimport { useResizeObserver } from '@vueuse/core';\nexport default defineComponent({\n name: 'ApprovalColumnDataList',\n props: {\n columnConfig: {\n type: Object,\n required: true,\n },\n height: {\n type: Number,\n required: true,\n },\n eventBus: {\n type: Object,\n required: true,\n },\n modelType: {\n type: String,\n required: true,\n },\n },\n setup(props) {\n const headerRef = ref(null);\n const headerHeight = ref(null);\n useResizeObserver(headerRef, entries => {\n headerHeight.value = entries[0].contentRect.height;\n });\n const contentHeight = computed(() => {\n if (headerRef.value && props.height) {\n return props.height - headerHeight.value;\n } else {\n return null;\n }\n });\n return { headerRef, contentHeight };\n },\n components: {\n ApprovalTable,\n },\n});\n</script>\n<style lang=\"less\" scoped>\n.data-list-container {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n height: 100%;\n padding: 4px;\n .data-list-header {\n display: flex;\n flex: 0 0 auto;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 4px;\n margin-right: 26px;\n .data-list-title {\n font-size: 15px;\n }\n }\n .data-list-body {\n flex: 1 1 auto;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 4px;\n }\n}\n</style>\n","<template>\n <div class=\"unknow-content\">\n <a-spin>\n <a-empty></a-empty>\n </a-spin>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'ApprovalColumnUnknown',\n props: {},\n setup(props) {\n return {};\n },\n components: {},\n});\n</script>\n<style lang=\"less\" scoped>\n.unknow-content {\n margin-top: 100px;\n}\n</style>\n","<template>\n <div class=\"unknow-content\">\n <a-spin>\n <a-empty></a-empty>\n </a-spin>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'ApprovalColumnUnknown',\n props: {},\n setup(props) {\n return {};\n },\n components: {},\n});\n</script>\n<style lang=\"less\" scoped>\n.unknow-content {\n margin-top: 100px;\n}\n</style>\n","import type { InjectionKey } from 'vue';\nimport { genID } from './utils';\n\n/**\n * 三栏根容器 `.approval-view` 的**实例级唯一 id 前缀**。\n *\n * 为什么必须唯一:竖条(`drawerTablesList` / `drawerDataList`)里的内容\n * 只能挂在 `.column-item` 之外 —— `ColumnLayout` 的 `.column-item` 是\n * `position: relative; overflow: hidden`,竖条留在原地会被裁掉,所以它们\n * 一律用 `<Teleport>` 跳出到三栏的根容器上。\n *\n * 但 `Teleport` 的 `to` 一旦写成**类名选择器**,走的就是 `document.querySelector`\n * (见 `@vue/runtime-core` 的 `resolveTarget`),只会拿到文档里的**第一个**匹配项。\n * 这个容器又**天然会有多个实例**:\n *\n * 1. 路由页:`approval/index.vue` → `core.vue`(在 `#app` 里)\n * 2. 「修改」弹出的全屏模态框:`ApprovalEditorModal.vue` → `core.vue`\n * (`a-modal` 的 `getContainer` 默认是 `document.body`,wrapper 追加在 `#app` **之后**)\n *\n * 于是模态框里的竖条会被插进**背后那个页面**的容器里 —— 表现为模态框左右栏空白,\n * 而背后页面里多出一份重影(2026-09-21 用 jsdom 严格复现:类名锚点下,模态框那一侧竖条 0 根,\n * 两根都落在页面容器里;并且这个失败**不报错**,只是静默少渲染)。\n *\n * 修法:由 `core.vue` 生成实例级 id 挂到根容器上,并把 id 注入下来,\n * 竖条把 Teleport 目标写成 `#<id>` —— 各实例互不干扰,且不依赖渲染顺序。\n */\nexport const APPROVAL_VIEW_ID_PREFIX = 'approval-view-';\n\n/**\n * 本实例 `.approval-view` 容器的 id(由 `core.vue` provide,见下)。\n * 竖条组件据此把 Teleport 目标写成 `#<id>`。\n */\nexport const APPROVAL_VIEW_ID: InjectionKey<string> = Symbol('approval-view-id');\n\n/**\n * 生成实例级唯一容器 id。\n * 复用 `utils.genID()`(`crypto.getRandomValues` 取 128 位随机数转 hex);\n * 前缀固定以字母开头,保证 `#id` 这种选择器写法始终合法。\n */\nexport const buildApprovalViewId = (): string => `${APPROVAL_VIEW_ID_PREFIX}${genID()}`;\n","<template>\n <!--\n Teleport 目标是**本实例** `.approval-view` 的 id(由 core.vue 注入),不是类名选择器。\n ⛔ 别改回 `to=\".approval-view\"`:选择器只命中文档里第一个同类容器,而页面 + 修改模态框\n 会同时存在两个,模态框的竖条会被插到背后那个页面里(左右栏空白)。\n `v-if=\"teleportTo\"` 也不是可有可无:`#id` 选择器要求目标**此刻已在文档中**,\n 否则 Vue 只留一条警告、子树根本不挂载(空挂载,且不报错)——\n 所以等本组件 onMounted(此时 core 的根 div 已进 DOM)再渲染。\n -->\n <Teleport\n v-if=\"teleportTo\"\n :to=\"teleportTo\"\n >\n <div class=\"drawer-tables-list\">\n <a-tag\n class=\"item\"\n color=\"blue\"\n v-for=\"value in groups\"\n @click=\"openDrawer(value)\"\n >\n {{ value }}\n </a-tag>\n </div>\n </Teleport>\n <a-drawer\n v-model:open=\"open\"\n :title=\"title\"\n placement=\"left\"\n width=\"80%\"\n class=\"tables-drawer\"\n >\n <columnTables\n v-if=\"title && open\"\n :columnConfig=\"columnConfig\"\n :groupTitle=\"title\"\n :height=\"height\"\n :eventBus=\"eventBus\"\n :modelType=\"modelType\"\n :approvalConfig=\"approvalConfig\"\n ></columnTables>\n </a-drawer>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, inject, onMounted, PropType, ref } from 'vue';\nimport { ApprovalSetting } from '../typing';\nimport { APPROVAL_VIEW_ID } from '../approvalViewId';\nimport columnTables from './columnTables.vue';\n\nexport default defineComponent({\n name: 'drawerTablesList',\n props: {\n columnConfig: {\n type: Object,\n required: true,\n },\n height: {\n type: Number,\n required: true,\n },\n eventBus: {\n type: Object,\n required: true,\n },\n modelType: {\n type: String,\n required: true,\n },\n approvalConfig: {\n type: Object as PropType<ApprovalSetting>,\n required: true,\n },\n },\n setup(props) {\n const open = ref(false);\n const title = ref('');\n\n /**\n * Teleport 目标:本实例 `.approval-view` 的 id(core.vue 注入)。\n * 缺注入属于「组件被放到 core.vue 之外」的配置错误 —— 直接抛错,不静默降级成空竖条。\n */\n const viewId = inject(APPROVAL_VIEW_ID, null);\n if (!viewId) {\n throw new Error(\n '[lyflowchart] drawerTablesList 必须渲染在 approval/core.vue 之内:缺少 .approval-view 的 id 注入',\n );\n }\n /**\n * 空串 = 暂不渲染 Teleport。`#id` 选择器要求目标已在文档里:本组件若与 core 的根 div\n * 在同一轮 mount 中被创建,那一刻根 div 还没插进文档,Teleport 会「找不到目标 → 子树不挂载」。\n * 等 onMounted 再挂,两种时序都稳。\n */\n const teleportTo = ref('');\n onMounted(() => {\n teleportTo.value = `#${viewId}`;\n });\n\n const groups = computed(() => {\n const res = [];\n\n for (const item of props.columnConfig.tables) {\n if (item.is_hidden) {\n continue;\n }\n const group_title = item.group_title || '未命名';\n if (!res.includes(group_title)) {\n res.push(group_title);\n }\n }\n return res;\n });\n const openDrawer = value => {\n title.value = value;\n open.value = true;\n };\n return { groups, open, openDrawer, title, teleportTo };\n },\n components: { columnTables },\n});\n</script>\n<style lang=\"less\" scoped>\n.drawer-tables-list {\n position: absolute;\n top: -20px;\n bottom: 0;\n left: -23px;\n z-index: 1;\n width: 30px;\n text-align: left;\n padding-top: 10px;\n padding-bottom: 10px;\n padding-right: 0;\n writing-mode: vertical-lr;\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 10px;\n .item {\n cursor: pointer;\n padding: 4px;\n font-size: 20px;\n letter-spacing: 5px;\n }\n}\n</style>\n","<template>\n <!--\n Teleport 目标是**本实例** `.approval-view` 的 id(由 core.vue 注入),不是类名选择器。\n ⛔ 别改回 `to=\".approval-view\"`:选择器只命中文档里第一个同类容器,而页面 + 修改模态框\n 会同时存在两个,模态框的竖条会被插到背后那个页面里(左右栏空白)。\n `v-if=\"teleportTo\"` 也不是可有可无:`#id` 选择器要求目标**此刻已在文档中**,\n 否则 Vue 只留一条警告、子树根本不挂载(空挂载,且不报错)——\n 所以等本组件 onMounted(此时 core 的根 div 已进 DOM)再渲染。\n -->\n <Teleport\n v-if=\"teleportTo\"\n :to=\"teleportTo\"\n >\n <div class=\"drawer-tables-list\">\n <a-tag\n class=\"item\"\n color=\"blue\"\n v-for=\"value in groups\"\n @click=\"openDrawer(value)\"\n >\n {{ value }}\n </a-tag>\n </div>\n </Teleport>\n <a-drawer\n v-model:open=\"open\"\n :title=\"title\"\n placement=\"left\"\n width=\"80%\"\n class=\"tables-drawer\"\n >\n <columnTables\n v-if=\"title && open\"\n :columnConfig=\"columnConfig\"\n :groupTitle=\"title\"\n :height=\"height\"\n :eventBus=\"eventBus\"\n :modelType=\"modelType\"\n :approvalConfig=\"approvalConfig\"\n ></columnTables>\n </a-drawer>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, inject, onMounted, PropType, ref } from 'vue';\nimport { ApprovalSetting } from '../typing';\nimport { APPROVAL_VIEW_ID } from '../approvalViewId';\nimport columnTables from './columnTables.vue';\n\nexport default defineComponent({\n name: 'drawerTablesList',\n props: {\n columnConfig: {\n type: Object,\n required: true,\n },\n height: {\n type: Number,\n required: true,\n },\n eventBus: {\n type: Object,\n required: true,\n },\n modelType: {\n type: String,\n required: true,\n },\n approvalConfig: {\n type: Object as PropType<ApprovalSetting>,\n required: true,\n },\n },\n setup(props) {\n const open = ref(false);\n const title = ref('');\n\n /**\n * Teleport 目标:本实例 `.approval-view` 的 id(core.vue 注入)。\n * 缺注入属于「组件被放到 core.vue 之外」的配置错误 —— 直接抛错,不静默降级成空竖条。\n */\n const viewId = inject(APPROVAL_VIEW_ID, null);\n if (!viewId) {\n throw new Error(\n '[lyflowchart] drawerTablesList 必须渲染在 approval/core.vue 之内:缺少 .approval-view 的 id 注入',\n );\n }\n /**\n * 空串 = 暂不渲染 Teleport。`#id` 选择器要求目标已在文档里:本组件若与 core 的根 div\n * 在同一轮 mount 中被创建,那一刻根 div 还没插进文档,Teleport 会「找不到目标 → 子树不挂载」。\n * 等 onMounted 再挂,两种时序都稳。\n */\n const teleportTo = ref('');\n onMounted(() => {\n teleportTo.value = `#${viewId}`;\n });\n\n const groups = computed(() => {\n const res = [];\n\n for (const item of props.columnConfig.tables) {\n if (item.is_hidden) {\n continue;\n }\n const group_title = item.group_title || '未命名';\n if (!res.includes(group_title)) {\n res.push(group_title);\n }\n }\n return res;\n });\n const openDrawer = value => {\n title.value = value;\n open.value = true;\n };\n return { groups, open, openDrawer, title, teleportTo };\n },\n components: { columnTables },\n});\n</script>\n<style lang=\"less\" scoped>\n.drawer-tables-list {\n position: absolute;\n top: -20px;\n bottom: 0;\n left: -23px;\n z-index: 1;\n width: 30px;\n text-align: left;\n padding-top: 10px;\n padding-bottom: 10px;\n padding-right: 0;\n writing-mode: vertical-lr;\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 10px;\n .item {\n cursor: pointer;\n padding: 4px;\n font-size: 20px;\n letter-spacing: 5px;\n }\n}\n</style>\n","<template>\n <!--\n Teleport 目标是**本实例** `.approval-view` 的 id(由 core.vue 注入),不是类名选择器。\n ⛔ 别改回 `to=\".approval-view\"`:选择器只命中文档里第一个同类容器,而页面 + 修改模态框\n 会同时存在两个,模态框的竖条会被插到背后那个页面里(左右栏空白)。\n `v-if=\"teleportTo\"` 见 drawerTablesList.vue 的同名说明。\n -->\n <Teleport\n v-if=\"teleportTo\"\n :to=\"teleportTo\"\n >\n <div class=\"drawer-data-list\">\n <a-tag\n class=\"item\"\n color=\"blue\"\n @click=\"openDrawer()\"\n >\n 审批列表\n </a-tag>\n </div>\n </Teleport>\n <a-drawer\n v-model:open=\"open\"\n title=\"审批列表\"\n placement=\"right\"\n width=\"80%\"\n >\n <columnDataList\n :v-if=\"open\"\n :columnConfig=\"columnConfig\"\n :height=\"height\"\n :eventBus=\"eventBus\"\n :modelType=\"modelType\"\n :approvalConfig=\"approvalConfig\"\n ></columnDataList>\n </a-drawer>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, inject, onMounted, PropType, ref } from 'vue';\nimport { ApprovalSetting } from '../typing';\nimport { APPROVAL_VIEW_ID } from '../approvalViewId';\nimport columnDataList from './columnDataList.vue';\n\nexport default defineComponent({\n name: 'drawerDataList',\n props: {\n columnConfig: {\n type: Object,\n required: true,\n },\n height: {\n type: Number,\n required: true,\n },\n eventBus: {\n type: Object,\n required: true,\n },\n modelType: {\n type: String,\n required: true,\n },\n approvalConfig: {\n type: Object as PropType<ApprovalSetting>,\n required: true,\n },\n },\n setup(props) {\n const open = ref(false);\n const openDrawer = () => {\n open.value = true;\n };\n\n /** Teleport 目标:本实例 `.approval-view` 的 id(core.vue 注入),说明见 drawerTablesList.vue */\n const viewId = inject(APPROVAL_VIEW_ID, null);\n if (!viewId) {\n throw new Error(\n '[lyflowchart] drawerDataList 必须渲染在 approval/core.vue 之内:缺少 .approval-view 的 id 注入',\n );\n }\n const teleportTo = ref('');\n onMounted(() => {\n teleportTo.value = `#${viewId}`;\n });\n\n return { open, openDrawer, teleportTo };\n },\n components: { columnDataList },\n});\n</script>\n<style lang=\"less\" scoped>\n.drawer-data-list {\n position: absolute;\n top: -20px;\n right: -20px;\n bottom: 0;\n z-index: 1;\n width: 30px;\n text-align: left;\n padding-top: 10px;\n padding-bottom: 10px;\n padding-right: 0;\n writing-mode: vertical-lr;\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 10px;\n .item {\n cursor: pointer;\n padding: 4px;\n font-size: 20px;\n letter-spacing: 5px;\n }\n}\n</style>\n","<template>\n <!--\n Teleport 目标是**本实例** `.approval-view` 的 id(由 core.vue 注入),不是类名选择器。\n ⛔ 别改回 `to=\".approval-view\"`:选择器只命中文档里第一个同类容器,而页面 + 修改模态框\n 会同时存在两个,模态框的竖条会被插到背后那个页面里(左右栏空白)。\n `v-if=\"teleportTo\"` 见 drawerTablesList.vue 的同名说明。\n -->\n <Teleport\n v-if=\"teleportTo\"\n :to=\"teleportTo\"\n >\n <div class=\"drawer-data-list\">\n <a-tag\n class=\"item\"\n color=\"blue\"\n @click=\"openDrawer()\"\n >\n 审批列表\n </a-tag>\n </div>\n </Teleport>\n <a-drawer\n v-model:open=\"open\"\n title=\"审批列表\"\n placement=\"right\"\n width=\"80%\"\n >\n <columnDataList\n :v-if=\"open\"\n :columnConfig=\"columnConfig\"\n :height=\"height\"\n :eventBus=\"eventBus\"\n :modelType=\"modelType\"\n :approvalConfig=\"approvalConfig\"\n ></columnDataList>\n </a-drawer>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, inject, onMounted, PropType, ref } from 'vue';\nimport { ApprovalSetting } from '../typing';\nimport { APPROVAL_VIEW_ID } from '../approvalViewId';\nimport columnDataList from './columnDataList.vue';\n\nexport default defineComponent({\n name: 'drawerDataList',\n props: {\n columnConfig: {\n type: Object,\n required: true,\n },\n height: {\n type: Number,\n required: true,\n },\n eventBus: {\n type: Object,\n required: true,\n },\n modelType: {\n type: String,\n required: true,\n },\n approvalConfig: {\n type: Object as PropType<ApprovalSetting>,\n required: true,\n },\n },\n setup(props) {\n const open = ref(false);\n const openDrawer = () => {\n open.value = true;\n };\n\n /** Teleport 目标:本实例 `.approval-view` 的 id(core.vue 注入),说明见 drawerTablesList.vue */\n const viewId = inject(APPROVAL_VIEW_ID, null);\n if (!viewId) {\n throw new Error(\n '[lyflowchart] drawerDataList 必须渲染在 approval/core.vue 之内:缺少 .approval-view 的 id 注入',\n );\n }\n const teleportTo = ref('');\n onMounted(() => {\n teleportTo.value = `#${viewId}`;\n });\n\n return { open, openDrawer, teleportTo };\n },\n components: { columnDataList },\n});\n</script>\n<style lang=\"less\" scoped>\n.drawer-data-list {\n position: absolute;\n top: -20px;\n right: -20px;\n bottom: 0;\n z-index: 1;\n width: 30px;\n text-align: left;\n padding-top: 10px;\n padding-bottom: 10px;\n padding-right: 0;\n writing-mode: vertical-lr;\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 10px;\n .item {\n cursor: pointer;\n padding: 4px;\n font-size: 20px;\n letter-spacing: 5px;\n }\n}\n</style>\n","<template>\n <a-select\n v-model:value=\"selectValue\"\n @change=\"handleChange($event, false)\"\n style=\"max-width: 220px; min-width: 150px\"\n placeholder=\"请选择\"\n show-search\n :filter-option=\"filterOption\"\n size=\"small\"\n >\n >\n <a-select-option\n v-for=\"item in excelTypeList\"\n :key=\"item.id\"\n :value=\"item.id\"\n :name=\"item.name\"\n >\n <a-tooltip>\n {{ item.name }}\n <template #title>{{ item.name }}</template>\n </a-tooltip>\n </a-select-option>\n </a-select>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostCompanySelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: number;\n name: string;\n area: string;\n code: string;\n }>,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const excelTypeList = ref<any>([]);\n const selectValue = ref<any>(props.value);\n const getList = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_my_cost_company');\n excelTypeList.value = res;\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n };\n const handleChange = (value: any, is_watch = false) => {\n if (!value) {\n selectValue.value = null;\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const findItem = excelTypeList.value.find((item: any) => item.id === value);\n if (findItem && findItem.id !== selectValue.value?.id) {\n selectValue.value = findItem.id;\n }\n if (!findItem) {\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const res = {\n id: findItem.id,\n name: findItem.name,\n area: findItem.area,\n code: findItem.code,\n };\n emit('update:value', res);\n if (!is_watch) {\n emit('change', res);\n }\n };\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n (newValue, oldValue) => {\n if (newValue?.id === oldValue?.id) {\n return;\n }\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n },\n );\n onMounted(() => {\n getList();\n });\n return {\n excelTypeList,\n selectValue,\n filterOption,\n handleChange,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-select\n v-model:value=\"selectValue\"\n @change=\"handleChange($event, false)\"\n style=\"max-width: 220px; min-width: 150px\"\n placeholder=\"请选择\"\n show-search\n :filter-option=\"filterOption\"\n size=\"small\"\n >\n >\n <a-select-option\n v-for=\"item in excelTypeList\"\n :key=\"item.id\"\n :value=\"item.id\"\n :name=\"item.name\"\n >\n <a-tooltip>\n {{ item.name }}\n <template #title>{{ item.name }}</template>\n </a-tooltip>\n </a-select-option>\n </a-select>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostCompanySelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: number;\n name: string;\n area: string;\n code: string;\n }>,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const excelTypeList = ref<any>([]);\n const selectValue = ref<any>(props.value);\n const getList = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_my_cost_company');\n excelTypeList.value = res;\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n };\n const handleChange = (value: any, is_watch = false) => {\n if (!value) {\n selectValue.value = null;\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const findItem = excelTypeList.value.find((item: any) => item.id === value);\n if (findItem && findItem.id !== selectValue.value?.id) {\n selectValue.value = findItem.id;\n }\n if (!findItem) {\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const res = {\n id: findItem.id,\n name: findItem.name,\n area: findItem.area,\n code: findItem.code,\n };\n emit('update:value', res);\n if (!is_watch) {\n emit('change', res);\n }\n };\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n (newValue, oldValue) => {\n if (newValue?.id === oldValue?.id) {\n return;\n }\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n },\n );\n onMounted(() => {\n getList();\n });\n return {\n excelTypeList,\n selectValue,\n filterOption,\n handleChange,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-select\n v-model:value=\"selectValue\"\n @change=\"handleChange($event, false)\"\n style=\"min-width: 120px; max-width: 220px\"\n placeholder=\"请选择\"\n show-search\n :filter-option=\"filterOption\"\n size=\"small\"\n >\n <a-select-option\n v-for=\"item in excelTypeList\"\n :key=\"item.id\"\n :value=\"item.id\"\n :name=\"item.name\"\n >\n {{ item.name }}\n </a-select-option>\n </a-select>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostDepartmentSelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: number;\n code: string;\n name: string;\n kind: string;\n bz: string;\n start_date: string;\n end_date: string;\n }>,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const KEYS = ['id', 'code', 'name', 'kind', 'bz', 'start_date', 'end_date'];\n const excelTypeList = ref<any>([]);\n const selectValue = ref<any>(props.value);\n const getList = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_my_department');\n excelTypeList.value = res;\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n };\n const handleChange = (value: any, is_watch = false) => {\n if (!value) {\n selectValue.value = null;\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const findItem = excelTypeList.value.find((item: any) => item.id === value);\n if (findItem && findItem.id !== selectValue.value?.id) {\n selectValue.value = findItem.id;\n }\n if (!findItem) {\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const res = {};\n for (const key of KEYS) {\n res[key] = findItem[key];\n }\n emit('update:value', res);\n if (!is_watch) {\n emit('change', res);\n }\n };\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n (newValue, oldValue) => {\n if (newValue?.id === oldValue?.id) {\n return;\n }\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n },\n );\n onMounted(() => {\n getList();\n });\n return {\n excelTypeList,\n selectValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-select\n v-model:value=\"selectValue\"\n @change=\"handleChange($event, false)\"\n style=\"min-width: 120px; max-width: 220px\"\n placeholder=\"请选择\"\n show-search\n :filter-option=\"filterOption\"\n size=\"small\"\n >\n <a-select-option\n v-for=\"item in excelTypeList\"\n :key=\"item.id\"\n :value=\"item.id\"\n :name=\"item.name\"\n >\n {{ item.name }}\n </a-select-option>\n </a-select>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostDepartmentSelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: number;\n code: string;\n name: string;\n kind: string;\n bz: string;\n start_date: string;\n end_date: string;\n }>,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const KEYS = ['id', 'code', 'name', 'kind', 'bz', 'start_date', 'end_date'];\n const excelTypeList = ref<any>([]);\n const selectValue = ref<any>(props.value);\n const getList = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_my_department');\n excelTypeList.value = res;\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n };\n const handleChange = (value: any, is_watch = false) => {\n if (!value) {\n selectValue.value = null;\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const findItem = excelTypeList.value.find((item: any) => item.id === value);\n if (findItem && findItem.id !== selectValue.value?.id) {\n selectValue.value = findItem.id;\n }\n if (!findItem) {\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const res = {};\n for (const key of KEYS) {\n res[key] = findItem[key];\n }\n emit('update:value', res);\n if (!is_watch) {\n emit('change', res);\n }\n };\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n (newValue, oldValue) => {\n if (newValue?.id === oldValue?.id) {\n return;\n }\n let id = props.value?.id;\n if (!id) {\n id = excelTypeList.value[0]?.id;\n }\n handleChange(id, true);\n },\n );\n onMounted(() => {\n getList();\n });\n return {\n excelTypeList,\n selectValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-select\n v-model:value=\"selectValue\"\n @change=\"handleChange($event, false)\"\n style=\"min-width: 120px; max-width: 220px\"\n placeholder=\"请选择\"\n show-search\n :filter-option=\"filterOption\"\n size=\"small\"\n >\n <a-select-option\n v-for=\"item in dataList\"\n :key=\"item.id\"\n :value=\"item.id\"\n :name=\"item.name\"\n >\n {{ item.name }}\n </a-select-option>\n </a-select>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostDepartmentSelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: number;\n code: string;\n name: string;\n kind: string;\n bz: string;\n start_date: string;\n end_date: string;\n }>,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const KEYS = ['id', 'code', 'name', 'id_str', 'bz'];\n const dataList = ref<any>([]);\n const selectValue = ref<any>(props.value);\n const getList = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_my_business_person');\n dataList.value = res;\n let id = props.value?.id;\n if (!id) {\n id = dataList.value[0]?.id;\n }\n handleChange(id, true);\n };\n const handleChange = (value: any, is_watch = false) => {\n if (!value) {\n selectValue.value = null;\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const findItem = dataList.value.find((item: any) => item.id === value);\n if (findItem && findItem.id !== selectValue.value?.id) {\n selectValue.value = findItem.id;\n }\n if (!findItem) {\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const res = {};\n for (const key of KEYS) {\n res[key] = findItem[key];\n }\n emit('update:value', res);\n if (!is_watch) {\n emit('change', res);\n }\n };\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n (newValue, oldValue) => {\n if (newValue?.id === oldValue?.id) {\n return;\n }\n let id = props.value?.id;\n if (!id) {\n id = dataList.value[0]?.id;\n }\n handleChange(id, true);\n },\n );\n onMounted(() => {\n getList();\n });\n return {\n dataList,\n selectValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-select\n v-model:value=\"selectValue\"\n @change=\"handleChange($event, false)\"\n style=\"min-width: 120px; max-width: 220px\"\n placeholder=\"请选择\"\n show-search\n :filter-option=\"filterOption\"\n size=\"small\"\n >\n <a-select-option\n v-for=\"item in dataList\"\n :key=\"item.id\"\n :value=\"item.id\"\n :name=\"item.name\"\n >\n {{ item.name }}\n </a-select-option>\n </a-select>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onMounted, PropType, ref, watch } from 'vue';\nimport { getApiData } from '@/init-plugin';\nexport default defineComponent({\n name: 'CostDepartmentSelect',\n components: {},\n props: {\n value: {\n type: Object as PropType<{\n id: number;\n code: string;\n name: string;\n kind: string;\n bz: string;\n start_date: string;\n end_date: string;\n }>,\n },\n },\n emits: ['update:value', 'change'],\n\n setup(props, { emit }) {\n const KEYS = ['id', 'code', 'name', 'id_str', 'bz'];\n const dataList = ref<any>([]);\n const selectValue = ref<any>(props.value);\n const getList = async () => {\n const res = await getApiData({ is_active: true }, '/approve/get_my_business_person');\n dataList.value = res;\n let id = props.value?.id;\n if (!id) {\n id = dataList.value[0]?.id;\n }\n handleChange(id, true);\n };\n const handleChange = (value: any, is_watch = false) => {\n if (!value) {\n selectValue.value = null;\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const findItem = dataList.value.find((item: any) => item.id === value);\n if (findItem && findItem.id !== selectValue.value?.id) {\n selectValue.value = findItem.id;\n }\n if (!findItem) {\n emit('update:value', null);\n if (!is_watch) {\n emit('change', null);\n }\n return;\n }\n const res = {};\n for (const key of KEYS) {\n res[key] = findItem[key];\n }\n emit('update:value', res);\n if (!is_watch) {\n emit('change', res);\n }\n };\n const filterOption = (input: string, option: any) => {\n return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;\n };\n watch(\n () => props.value,\n (newValue, oldValue) => {\n if (newValue?.id === oldValue?.id) {\n return;\n }\n let id = props.value?.id;\n if (!id) {\n id = dataList.value[0]?.id;\n }\n handleChange(id, true);\n },\n );\n onMounted(() => {\n getList();\n });\n return {\n dataList,\n selectValue,\n handleChange,\n filterOption,\n };\n },\n});\n</script>\n<style scoped lang=\"less\"></style>\n","<template>\n <a-config-provider :theme=\"themeConfig\">\n <!--\n `:id` + 类的组合是刻意的:\n - **类名 `.approval-view`** 是样式钩子(`style.less` 里的折叠面板内边距、本文件\n scoped 的 `height: 100%`),必须保留;\n - **实例级 id** 是竖条的 Teleport 锚点(见 `approvalViewId.ts` 的说明)——\n 光有类名不够,页面 + 修改模态框同时存在时会有两个 `.approval-view`。\n -->\n <div\n class=\"approval-view\"\n :id=\"approvalViewId\"\n >\n <ColumnLayout\n v-model:modelValue=\"layoutValue\"\n :minWidth=\"0\"\n :show-zoom-btn=\"false\"\n :resizeable=\"false\"\n >\n <template #default=\"{ index }\">\n <div\n class=\"column-item-content\"\n ref=\"columnItemContentRef\"\n >\n <component\n :is=\"getComponentName(index)\"\n :column-config=\"getColumnConfig(index)\"\n :global-data=\"globalData\"\n :height=\"columnHeight\"\n :modelType=\"modelType\"\n :eventBus=\"eventBus\"\n :topFormRef=\"topFormRef\"\n :approvalConfig=\"approvalConfig\"\n @globalDataChange=\"handleGlobalDataChange(getComponentName(index), $event)\"\n />\n </div>\n </template>\n </ColumnLayout>\n </div>\n </a-config-provider>\n</template>\n\n<script lang=\"ts\">\n/**\n * 审批「左中右三栏」核心组件 —— **不依赖路由**。\n *\n * 为什么要有这一层:审批页原本只有「路由页面」一种用法,`modelType` 是从 `route.path`\n * 末段推出来的。现在详情页/列表单元格要把它当作**全屏模态框**弹出来(修改、删除后编辑),\n * 那里没有对应路由,所以把「一切靠参数控制」的部分抽成本组件:\n *\n * - `modelType`(= 页面配置的 menu_flag):**prop 传入**,不再读路由;\n * - `approveRecordId`:**可选**。传了就表示「打开即进入编辑态」,见 onMounted 的说明。\n *\n * 两种用法:\n * 1. 路由页面 → `approval/index.vue`(薄壳,从路由推出 modelType);\n * 2. 全屏模态 → `approval/ApprovalEditorModal.vue`(传 modelType + approveRecordId)。\n * 两者共用本组件,逻辑只有一份。\n *\n * ⚠️ props 必须放在普通 `<script>` 块里 export(与 columnForm.vue 的 ColumnFormProps 同理):\n * 模态框组件会持有本组件的模板 ref,TS 需要能**命名**这个 props 类型;放在 <script setup> 里\n * 无法 export,会导致本文件产不出 .d.ts,并连锁让引用方报 TS4082。\n */\nexport interface ApprovalCoreProps {\n /** 页面配置的菜单标识(menu_flag)。原来从 route.path 末段取,现在由调用方传入 */\n modelType: string;\n /**\n * 打开即进入编辑态的审批记录 id(ApproveRecord.id)。\n * 不传 = 普通用法,编辑态由页面自身事件驱动(路由页面的用法)。\n */\n approveRecordId?: number | null;\n}\n\n// window.setDebugCode 供控制台手动开关代码调试(见下方 <script setup> 的赋值处)。\n// declare global 必须放在普通 <script> 顶层 —— <script setup> 是函数作用域,放那里报 TS1234。\ndeclare global {\n interface Window {\n setDebugCode?: (checked: boolean) => void;\n }\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue';\nimport { getApprovalConfig, getFlowConfig } from './index';\nimport ColumnApprovalTables from './components/columnTables.vue';\nimport ColumnApprovalForm from './components/columnForm.vue';\nimport ColumnApprovalDataList from './components/columnDataList.vue';\nimport ColumnApprovalUnknown from './components/columnUnknown.vue';\nimport drawerTablesList from './components/drawerTablesList.vue';\nimport drawerDataList from './components/drawerDataList.vue';\nimport { ApprovalSetting } from './typing';\nimport { executeScriptInWorker, getApiData, useUserStore } from '@/init-plugin';\nimport './style.less';\nimport mitt from 'mitt';\nimport {\n SET_CURRENT_FLOW_HISTORY_ID,\n SET_CURRENT_HISTORY_ID,\n SET_EDIT,\n SET_FORM_MODEL,\n SET_GLOBAL_DATA,\n SET_RAW,\n SET_REQUST_FLOW_HISTORY_ID,\n SET_REQUST_HISTORY_ID,\n useContextStore,\n} from '@/components/approval/store/context';\nimport { SET_ENABLE, useDebugCodeStore } from './store/debugCode';\nimport { message, Modal } from 'ant-design-vue';\nimport CostCompanySelect from './CostCompanySelect.vue';\nimport CostCompanyDepartment from './CostDepartmentSelect.vue';\nimport CreateBySelect from './CreateBySelect.vue';\nimport SystemTime from './SystemTime.vue';\nimport { cloneDeep, debounce } from 'lodash';\nimport dayjs from 'dayjs';\nimport FormCodeInput from './components/FormCodeInput.vue';\nimport CreateByCascader from './CreateByCascader.vue';\nimport PostionCascader from './PostionCascader.vue';\nimport { clearDynamicValueFields, getFormDynamicFieldList } from './utils';\nimport { APPROVAL_VIEW_ID, buildApprovalViewId } from './approvalViewId';\n\n/**\n * ⚠️⚠️ 这份 `components` 注册表**不是多余的**,删掉页面会静默变空白,务必保留。\n *\n * 模板里是 `<component :is=\"getComponentName(index)\" />`,而 `getComponentName` 返回的是\n * **字符串**(`'drawerTablesList'` / `'ColumnApprovalForm'` / `'drawerDataList'` /\n * `'ColumnApprovalUnknown'`)。字符串式动态解析走的是 Vue 的 `resolveAsset`:\n *\n * resolve(instance.components || Component.components, name) || resolve(appContext.components, name)\n *\n * 它**只查组件选项(`components`)与全局注册,不会去查 `<script setup>` 的顶层绑定** ——\n * 所以哪怕这些组件在上面 import 了,按名字也解析不到。后果是:\n * - 运行时只在控制台留 `Failed to resolve component: drawerTablesList` 警告,三栏渲染成空白;\n * - **SFC 编译、vue-tsc、`yarn build` 全都不报错**(本文件当初从 Options API 的\n * `components: {}` 搬成 `<script setup>` 时漏掉这份表,就是这样逃过所有检查的)。\n *\n * 另注:`getComponentName` 的返回值还被当作**名字**传给 `handleGlobalDataChange(name, $event)`,\n * 所以也不能图省事把它改成「返回组件对象」——那会连带改坏这个回调的语义。\n */\ndefineOptions({\n name: 'ApprovalCore',\n components: {\n ColumnApprovalTables,\n ColumnApprovalForm,\n ColumnApprovalDataList,\n ColumnApprovalUnknown,\n CostCompanySelect,\n CostCompanyDepartment,\n CreateBySelect,\n SystemTime,\n FormCodeInput,\n CreateByCascader,\n PostionCascader,\n drawerTablesList,\n drawerDataList,\n },\n});\n\n// ApprovalCoreProps 见文件顶部普通 <script> 块(为了能 export)\nconst props = withDefaults(defineProps<ApprovalCoreProps>(), {\n approveRecordId: null,\n});\n\nconst emit = defineEmits<{\n /**\n * 保存成功。`isEdit` 为真表示这是一次「修改」(而非「新建」)。\n * 详情场景的模态框据此决定「关掉模态框回到详情页」还是「留在原地继续录入」。\n */\n (e: 'saved', payload: { isEdit?: boolean }): void;\n}>();\n\nconst context = useContextStore();\nconst userStore = useUserStore();\nconst eventBus = mitt();\n/** 与 props.modelType 同步;下面全部沿用小写 modelType.value 的写法,便于与宿主/后端字段对齐 */\nconst modelType = computed(() => props.modelType);\nconst columnCount = ref(3);\nconst is_debug_code_auth = ref(false);\nconst debugCodeStor = useDebugCodeStore();\n\n/**\n * 本实例三栏容器的唯一 id:挂到根 div 上(模板里的 `:id`),并注入给竖条组件\n * 当 Teleport 锚点。**不能用类名当锚点** —— 路由页与「修改」模态框会同时存在两个\n * `.approval-view`,原因与实测见 `./approvalViewId.ts` 的注释。\n */\nconst approvalViewId = buildApprovalViewId();\nprovide(APPROVAL_VIEW_ID, approvalViewId);\n\nconst approvalConfig = ref<ApprovalSetting | null>(null);\nconst flowConfig = ref<string | null>(null);\nconst globalData = ref<any>({});\nconst columnHeight = ref(0);\nconst columnItemContentRef = ref(null);\n\nconst topFormRef = ref();\nconst themeConfig = computed(() => {\n return {\n token: {\n // controlHeight: 20,\n // fontSize: 12,\n },\n };\n});\nconst layoutValue = computed(() => {\n let hasTable = false;\n if (approvalConfig.value?.columns) {\n for (const column of approvalConfig.value?.columns) {\n if (column.type === 'tables') {\n for (const item of column.tables) {\n if (!item.is_hidden) {\n hasTable = true;\n break;\n }\n }\n break;\n }\n }\n }\n if (hasTable) {\n return ['30px', '1fr', '30px'];\n } else {\n return ['0px', '1fr', '30px'];\n }\n});\n\n/**\n * 生成新流水号(全局数据 number,ApproveRecord.number 上有唯一约束)\n */\nconst genRecordNumber = async (config: any) => {\n return await getApiData(\n {\n prefix: config?.number_prefix,\n suffix: config?.number_suffix,\n digit_place: config?.number_digit_place,\n },\n '/approve/get_record_number',\n );\n};\n/**\n * 生成新单据编号(全局数据 form_code),与后端 get_form_code 算法对齐:\n * 编号格式为 前缀+年份后两位+月份+流水号\n */\nconst genFormCode = async (config: any) => {\n return await getApiData(\n {\n prefix: config?.form_code_prefix,\n },\n '/approve/get_form_code',\n );\n};\n/**\n * 生成「今天」的制单日期,结构对齐 SystemTime.vue 的取值格式\n * (create_date 同时参与职位查询,日期不同会导致查出的职位不同)\n */\nconst genCreateDate = () => {\n const now = dayjs();\n return {\n date: now.format('YYYY-MM-DD'),\n date_ch: now.format('YYYY年MM月DD日'),\n date_short: now.format('YYYYMMDD'),\n };\n};\n/**\n * 初始化/刷新页面配置与全局数据\n * @param options.skip_auto_numbering 加载「待编辑记录」时置 true:流水号/单据编号沿用记录自身携带的值,\n * 不做新建态的自动取号。必须显式传参而不是只看 store 里的 isEdit —— 点「修改/编辑」时本函数\n * 跑在进入编辑态之前(isEdit 仍为 false),会被当成新建重新取号;而\n * /approve/get_record_number 与 /approve/get_form_code 每次调用都会写 RecordNumber/FormCode 表,\n * 误调用既改掉单号、又让编号序列跳号。\n */\nconst initConfig = async (options?: { skip_auto_numbering?: boolean }) => {\n const skip_auto_numbering = !!options?.skip_auto_numbering;\n const res = await getApiData({ name: modelType.value }, '/approve/get_user_page_context', false, {\n skip_error: true,\n });\n let saved_current_history_id = null;\n if (res) {\n saved_current_history_id = res.current_history_id;\n context[SET_RAW](modelType.value, res);\n }\n const history_id = context.contexts?.[modelType.value]?.request_history_id;\n const flow_history_id = context.contexts?.[modelType.value]?.request_flow_history_id;\n const { config, current_history_id } = await getApprovalConfig(modelType.value, null, history_id);\n const { content: flow_config, current_history_id: current_flow_history_id } = await getFlowConfig(\n modelType.value,\n flow_history_id,\n );\n approvalConfig.value = config;\n flowConfig.value = flow_config;\n context[SET_CURRENT_HISTORY_ID](modelType.value, current_history_id);\n context[SET_CURRENT_FLOW_HISTORY_ID](modelType.value, current_flow_history_id);\n if (current_history_id != saved_current_history_id) {\n context[SET_FORM_MODEL](modelType.value, null);\n }\n columnCount.value = config.columns.length;\n const global_data = context.contexts?.[modelType.value]?.globalData;\n if (global_data) {\n globalData.value = global_data;\n }\n if (\n !skip_auto_numbering &&\n !context.contexts?.[modelType.value]?.isEdit &&\n (!globalData.value.number ||\n !globalData.value.number.startsWith(config.number_prefix) ||\n !globalData.value.number.endsWith(config.number_suffix))\n ) {\n const number = await genRecordNumber(config);\n globalData.value.number = number;\n saveContextImmediately();\n }\n // 与后端 get_form_code 算法对齐:编号格式为 前缀+年份后两位+月份+流水号\n // 需校验已生成的编码是否以「前缀+当前日期」开头,否则前缀变更(如长变短)或跨月时不会重新生成\n const now_date = new Date();\n const year_suffix = String(now_date.getFullYear()).slice(-2);\n const month = String(now_date.getMonth() + 1).padStart(2, '0');\n const form_code_date_prefix = `${config.form_code_prefix || ''}${year_suffix}${month}`;\n if (\n !skip_auto_numbering &&\n !context.contexts?.[modelType.value]?.isEdit &&\n config.form_code_prefix &&\n (!globalData.value.form_code?.code ||\n !globalData.value.form_code.code.startsWith(form_code_date_prefix))\n ) {\n const number = await genFormCode(config);\n globalData.value.form_code = { code: number };\n saveContextImmediately();\n }\n};\n\nconst getComponentName = (index: number) => {\n const item = approvalConfig.value?.columns[index];\n switch (item?.type) {\n case 'tables':\n return 'drawerTablesList';\n case 'form':\n return 'ColumnApprovalForm';\n case 'data_list':\n return 'drawerDataList';\n default:\n return 'ColumnApprovalUnknown';\n }\n};\nconst getColumnConfig = (index: number) => {\n const item = approvalConfig.value?.columns[index];\n return item;\n};\nconst resize = () => {\n if (columnItemContentRef.value) {\n columnHeight.value = columnItemContentRef.value.offsetHeight - 8.5; // 32为padding或间距,可根据实际调整\n }\n};\nwindow.setDebugCode = checked => {\n debugCodeStor[SET_ENABLE](checked);\n if (checked) {\n message.success('代码调试已开启');\n } else {\n message.info('代码调试已关闭');\n }\n};\nconst saveContext = debounce(async () => {\n saveContextImmediately();\n}, 1000);\nconst saveContextImmediately = async () => {\n await getApiData(\n { name: modelType.value, context: context.contexts[modelType.value] },\n '/approve/update_user_page_context',\n );\n};\nconst genModifyNumber = baseNumber => {\n if (!baseNumber) return baseNumber;\n if (baseNumber.indexOf('-') === -1) {\n return `${baseNumber}-1`;\n }\n const idx = baseNumber.lastIndexOf('-');\n const head = baseNumber.substring(0, idx);\n const tail = baseNumber.substring(idx + 1);\n if (/^\\d+$/.test(tail)) {\n return `${head}-${parseInt(tail, 10) + 1}`;\n }\n return `${baseNumber}-1`;\n};\n\n/**\n * 按审批记录 id 进入编辑态 —— 「修改」的**唯一**实现,两条入口都走这里:\n * 1. 列表页行按钮 / 详情页按钮 → 跑完 actionCode 拿到 `{ id }` 后调用;\n * 2. 模态框带 `approveRecordId` 打开 → onMounted 直接调用。\n *\n * 编辑态**不止一种**,都由记录自身字段派生(调用方不需要、也不应该自己判断):\n * - **普通编辑**:`process_status === 'init'` 或 `result_status === 'reject'`\n * → 流水号不变;表单结构可编辑(除非记录自带 modify_source,见下)\n * - **修改已通过的审批**(modifyMode):`approved + pass + is_modifiable + modify_status === '正常'`\n * → 先过 `/approve/check_approve_can_modify`,流水号变 `原号-1`,并且**锁定表单结构**\n * - **再次编辑「修改单」**:记录 B 本身带 `modify_source_id`\n * → 走普通编辑,但因为 B 的来源是修改单,同样**锁定表单结构**\n * 三者分别落成 columnForm 的 `isEdit` / `modifyMode` / `sourceApproveRecordId` / `lockStructure`,\n * 所以不能用一个布尔量表达。\n */\nconst applyApproveRecord = async (id: number) => {\n const approve_res = await getApiData({ approve_record_id: id }, '/approve/get_approve_record');\n const {\n page_setting_history_id,\n flow_setting_history_id,\n data,\n number,\n process_status,\n result_status,\n is_modifiable,\n modify_status,\n } = approve_res;\n // 记录本身若带 modify_source(即它是「修改上一个审批」的记录),编辑时必须锁定表单结构\n // (隐藏明细/表单模板的添加、清空、导入、行删除按钮),但流水号不再变化\n const modifySourceId =\n approve_res.modify_source_id ??\n (approve_res.modify_source && approve_res.modify_source.id) ??\n null;\n context[SET_REQUST_HISTORY_ID](modelType.value, page_setting_history_id);\n context[SET_REQUST_FLOW_HISTORY_ID](modelType.value, flow_setting_history_id);\n globalData.value = data.globalData;\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n await saveContextImmediately();\n // 编辑/修改一律沿用记录自身的流水号与单据编号(不重新取号),\n // 详见 initConfig 的 skip_auto_numbering 说明\n await initConfig({ skip_auto_numbering: true });\n // 已通过且可修改:进入修改模式(前端先算展示流水号,后端最终定)\n const isModifyApproved =\n process_status === 'approved' &&\n result_status === 'pass' &&\n is_modifiable === true &&\n modify_status === '正常';\n if (isModifyApproved) {\n const checkRes = await getApiData(\n { approve_record_id: id },\n '/approve/check_approve_can_modify',\n );\n if (!checkRes || !checkRes.can_modify) {\n message.error((checkRes && checkRes.msg) || '该审批记录不可修改');\n return;\n }\n const newNumber = genModifyNumber(number);\n globalData.value.number = newNumber;\n\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n eventBus.emit('update_form', {\n data,\n state: {\n id,\n number: newNumber,\n modifyMode: true,\n source_approve_record_id: id,\n modify_source_id: modifySourceId,\n },\n });\n } else {\n // 标准编辑(含「修改审批」记录 B 的再次编辑):流水号保持不变,\n // 若 B 本身带 modify_source 则锁定表单结构\n eventBus.emit('update_form', { data, state: { id, number, modify_source_id: modifySourceId } });\n }\n};\n\nconst eventAction = async ({ code, action, params }) => {\n const action_type = action.action;\n if (action_type === 'edit_approve') {\n if (!code) {\n return;\n }\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e instanceof Error ? e.message : String(e));\n return;\n }\n const { id } = res;\n if (!id) {\n message.error('代码未返回id');\n return;\n }\n await applyApproveRecord(id);\n } else if (action_type === 'copy_approve') {\n // 复制为新审批:把源审批的数据整份搬到当前表单,作为一条新的「待提交」审批。\n // 与 edit_approve 的区别:不复用源单据的 id/历史配置,且以下数据必须重新生成 ——\n // 1. 全局数据里的流水号、单据编号(否则与源单据撞唯一键/编号)\n // 2. 表单里配置的只读动态值(序号、覆盖ID 等,computeDynamicValue 不会重算已有值)\n if (!code) {\n return;\n }\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e instanceof Error ? e.message : String(e));\n return;\n }\n const { id } = res || {};\n if (!id) {\n message.error('代码未返回id');\n return;\n }\n const confirm = await new Promise<boolean>(resolve => {\n Modal.confirm({\n title: '复制表单',\n content: '将覆盖当前表单数据,并以新的单据编号、流水号新建一条待提交审批',\n onOk: () => resolve(true),\n onCancel: () => resolve(false),\n });\n });\n if (!confirm) {\n return;\n }\n const approve_res = await getApiData({ approve_record_id: id }, '/approve/get_approve_record');\n const source_data = approve_res?.data;\n if (!source_data) {\n message.error('未获取到审批数据');\n return;\n }\n const config = approvalConfig.value || ({} as ApprovalSetting);\n // 1) 全局数据:继承源单据(制单人/流程组织/流程主题等),\n // 但流水号、单据编号、制单日期必须重新生成,职位需按新日期重新解析\n const new_global_data = {\n ...(globalData.value || {}),\n ...(cloneDeep(source_data.globalData) || {}),\n };\n new_global_data.number = await genRecordNumber(config);\n // 制单日期取今天(不能沿用源单据的旧日期:职位查询依赖该日期)\n new_global_data.create_date = genCreateDate();\n // 职位是 (制单人, 制单日期) 派生出来的数据,日期已变为今天,必须按今天重新解析:\n // 清空三件套后由 PostionCascader.getData() 自动按当天重算(查不到则置空,走必填校验拦截)\n new_global_data.person_cost_company = null;\n new_global_data.person_department = null;\n new_global_data.person_position = null;\n if (config.form_code_prefix) {\n new_global_data.form_code = { code: await genFormCode(config) };\n } else {\n // 未配置单据编号前缀(该页面不使用单据编号)时不继承源单据的旧编号\n delete new_global_data.form_code;\n }\n globalData.value = new_global_data;\n // 2) 回到「新建」态:清空编辑态与历史版本指向,按当前页面配置渲染\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n context[SET_EDIT](modelType.value, false, {});\n context[SET_REQUST_HISTORY_ID](modelType.value, null);\n context[SET_REQUST_FLOW_HISTORY_ID](modelType.value, null);\n // 3) 表单数据:源单据 data 去掉 globalData(全局数据由上方单独维护),\n // 并清空只读动态值,交由 DynamicValueField / FormTemplate 重新计算\n const form_model = cloneDeep(source_data);\n delete form_model.globalData;\n clearDynamicValueFields(form_model, getFormDynamicFieldList(config));\n context[SET_FORM_MODEL](modelType.value, form_model);\n // 先持久化再 initConfig:initConfig 会重新拉取用户上下文与当前页面配置\n await saveContextImmediately();\n await initConfig();\n context[SET_FORM_MODEL](modelType.value, form_model);\n eventBus.emit('copy_form', { data: form_model });\n }\n};\nconst eventReinit = async () => {\n initConfig();\n};\n/**\n * 「保存成功」从表单列(columnForm.vue)冒上来后原样转发给外层。\n * 详情场景的模态框需要它来判断「这次是修改还是新建」以及要不要刷新详情/列表。\n * 路由页面场景没人监听,转发出去也无副作用。\n */\nconst eventSaved = (payload: { isEdit?: boolean }) => {\n emit('saved', payload || {});\n};\nconst handleGlobalDataChange = (_cid, update) => {\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n if (update) {\n saveContext();\n }\n};\n\nonMounted(async () => {\n eventBus.on('run_action', eventAction);\n eventBus.on('reinit', eventReinit);\n eventBus.on('saved', eventSaved);\n is_debug_code_auth.value = userStore.CHECK_AUTH('approve/debug_code', '开启代码调试');\n window.addEventListener('resize', resize);\n resize();\n /**\n * ⚠️ 顺序不能颠倒:带 approveRecordId 时**必须先 applyApproveRecord**,\n * 绝不能先跑一次普通的 initConfig()。\n * 原因见 initConfig 的 skip_auto_numbering 说明 —— 普通 initConfig() 会把「待编辑记录」\n * 当成新建去重新取流水号/单据编号,既改掉原单号又让编号序列跳号;\n * 而且 applyApproveRecord 内部本来就会调 initConfig({skip_auto_numbering:true}),\n * 先跑一次等于白发一次写库请求。\n */\n if (props.approveRecordId) {\n await applyApproveRecord(props.approveRecordId);\n } else {\n await initConfig();\n }\n // initConfig 可能会改写 layoutValue(是否含表格),尺寸需在其之后再量一次\n resize();\n});\n\n// 组件卸载时移除监听\nonUnmounted(() => {\n eventBus.off('run_action', eventAction);\n eventBus.off('reinit', eventReinit);\n eventBus.off('saved', eventSaved);\n window.removeEventListener('resize', resize);\n});\n\n// 路由页面切换节点时(同一个页面实例复用),父级会换 modelType;模态框场景不会变\nwatch(\n () => props.modelType,\n (val, old) => {\n if (!val || val === old) return;\n initConfig();\n },\n);\n\ndefineExpose({\n /** 按审批记录 id 进入编辑态(编辑态种类由记录字段派生,见上方注释) */\n applyApproveRecord,\n /** 重新拉取页面配置与全局数据 */\n reinit: eventReinit,\n /** 供外部(模态框)在需要时重新量一次高度 */\n resize,\n});\n</script>\n\n<style lang=\"less\" scoped>\n.header-content {\n padding: 8px 16px;\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n gap: 8px;\n}\n\n.header-label {\n &::before {\n content: '';\n display: block;\n position: absolute;\n margin-left: 4px;\n width: 1px;\n background-color: #c1c1c1;\n top: 4px;\n bottom: 4px;\n left: -9px;\n }\n}\n.header-item {\n position: relative;\n display: flex-inline;\n flex-direction: row;\n align-items: center;\n}\n.header-value {\n min-width: 500px;\n flex: 0;\n line-height: 24px;\n}\n.column-item-content {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n.header-item-space {\n display: block;\n width: 10px;\n}\n.zoom-btn-wraper {\n position: absolute;\n z-index: 1;\n\n width: 100%;\n display: flex;\n top: -6px;\n justify-content: space-between;\n padding-right: 20px;\n\n .zom-btn {\n font-size: 20px;\n padding: 0;\n }\n .right {\n }\n}\n/* 模态框里由外层给固定高度,这里撑满;路由页面下父级无显式高度时该声明自然退化为 auto,无副作用 */\n.approval-view {\n height: 100%;\n}\n</style>\n","<template>\n <a-config-provider :theme=\"themeConfig\">\n <!--\n `:id` + 类的组合是刻意的:\n - **类名 `.approval-view`** 是样式钩子(`style.less` 里的折叠面板内边距、本文件\n scoped 的 `height: 100%`),必须保留;\n - **实例级 id** 是竖条的 Teleport 锚点(见 `approvalViewId.ts` 的说明)——\n 光有类名不够,页面 + 修改模态框同时存在时会有两个 `.approval-view`。\n -->\n <div\n class=\"approval-view\"\n :id=\"approvalViewId\"\n >\n <ColumnLayout\n v-model:modelValue=\"layoutValue\"\n :minWidth=\"0\"\n :show-zoom-btn=\"false\"\n :resizeable=\"false\"\n >\n <template #default=\"{ index }\">\n <div\n class=\"column-item-content\"\n ref=\"columnItemContentRef\"\n >\n <component\n :is=\"getComponentName(index)\"\n :column-config=\"getColumnConfig(index)\"\n :global-data=\"globalData\"\n :height=\"columnHeight\"\n :modelType=\"modelType\"\n :eventBus=\"eventBus\"\n :topFormRef=\"topFormRef\"\n :approvalConfig=\"approvalConfig\"\n @globalDataChange=\"handleGlobalDataChange(getComponentName(index), $event)\"\n />\n </div>\n </template>\n </ColumnLayout>\n </div>\n </a-config-provider>\n</template>\n\n<script lang=\"ts\">\n/**\n * 审批「左中右三栏」核心组件 —— **不依赖路由**。\n *\n * 为什么要有这一层:审批页原本只有「路由页面」一种用法,`modelType` 是从 `route.path`\n * 末段推出来的。现在详情页/列表单元格要把它当作**全屏模态框**弹出来(修改、删除后编辑),\n * 那里没有对应路由,所以把「一切靠参数控制」的部分抽成本组件:\n *\n * - `modelType`(= 页面配置的 menu_flag):**prop 传入**,不再读路由;\n * - `approveRecordId`:**可选**。传了就表示「打开即进入编辑态」,见 onMounted 的说明。\n *\n * 两种用法:\n * 1. 路由页面 → `approval/index.vue`(薄壳,从路由推出 modelType);\n * 2. 全屏模态 → `approval/ApprovalEditorModal.vue`(传 modelType + approveRecordId)。\n * 两者共用本组件,逻辑只有一份。\n *\n * ⚠️ props 必须放在普通 `<script>` 块里 export(与 columnForm.vue 的 ColumnFormProps 同理):\n * 模态框组件会持有本组件的模板 ref,TS 需要能**命名**这个 props 类型;放在 <script setup> 里\n * 无法 export,会导致本文件产不出 .d.ts,并连锁让引用方报 TS4082。\n */\nexport interface ApprovalCoreProps {\n /** 页面配置的菜单标识(menu_flag)。原来从 route.path 末段取,现在由调用方传入 */\n modelType: string;\n /**\n * 打开即进入编辑态的审批记录 id(ApproveRecord.id)。\n * 不传 = 普通用法,编辑态由页面自身事件驱动(路由页面的用法)。\n */\n approveRecordId?: number | null;\n}\n\n// window.setDebugCode 供控制台手动开关代码调试(见下方 <script setup> 的赋值处)。\n// declare global 必须放在普通 <script> 顶层 —— <script setup> 是函数作用域,放那里报 TS1234。\ndeclare global {\n interface Window {\n setDebugCode?: (checked: boolean) => void;\n }\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue';\nimport { getApprovalConfig, getFlowConfig } from './index';\nimport ColumnApprovalTables from './components/columnTables.vue';\nimport ColumnApprovalForm from './components/columnForm.vue';\nimport ColumnApprovalDataList from './components/columnDataList.vue';\nimport ColumnApprovalUnknown from './components/columnUnknown.vue';\nimport drawerTablesList from './components/drawerTablesList.vue';\nimport drawerDataList from './components/drawerDataList.vue';\nimport { ApprovalSetting } from './typing';\nimport { executeScriptInWorker, getApiData, useUserStore } from '@/init-plugin';\nimport './style.less';\nimport mitt from 'mitt';\nimport {\n SET_CURRENT_FLOW_HISTORY_ID,\n SET_CURRENT_HISTORY_ID,\n SET_EDIT,\n SET_FORM_MODEL,\n SET_GLOBAL_DATA,\n SET_RAW,\n SET_REQUST_FLOW_HISTORY_ID,\n SET_REQUST_HISTORY_ID,\n useContextStore,\n} from '@/components/approval/store/context';\nimport { SET_ENABLE, useDebugCodeStore } from './store/debugCode';\nimport { message, Modal } from 'ant-design-vue';\nimport CostCompanySelect from './CostCompanySelect.vue';\nimport CostCompanyDepartment from './CostDepartmentSelect.vue';\nimport CreateBySelect from './CreateBySelect.vue';\nimport SystemTime from './SystemTime.vue';\nimport { cloneDeep, debounce } from 'lodash';\nimport dayjs from 'dayjs';\nimport FormCodeInput from './components/FormCodeInput.vue';\nimport CreateByCascader from './CreateByCascader.vue';\nimport PostionCascader from './PostionCascader.vue';\nimport { clearDynamicValueFields, getFormDynamicFieldList } from './utils';\nimport { APPROVAL_VIEW_ID, buildApprovalViewId } from './approvalViewId';\n\n/**\n * ⚠️⚠️ 这份 `components` 注册表**不是多余的**,删掉页面会静默变空白,务必保留。\n *\n * 模板里是 `<component :is=\"getComponentName(index)\" />`,而 `getComponentName` 返回的是\n * **字符串**(`'drawerTablesList'` / `'ColumnApprovalForm'` / `'drawerDataList'` /\n * `'ColumnApprovalUnknown'`)。字符串式动态解析走的是 Vue 的 `resolveAsset`:\n *\n * resolve(instance.components || Component.components, name) || resolve(appContext.components, name)\n *\n * 它**只查组件选项(`components`)与全局注册,不会去查 `<script setup>` 的顶层绑定** ——\n * 所以哪怕这些组件在上面 import 了,按名字也解析不到。后果是:\n * - 运行时只在控制台留 `Failed to resolve component: drawerTablesList` 警告,三栏渲染成空白;\n * - **SFC 编译、vue-tsc、`yarn build` 全都不报错**(本文件当初从 Options API 的\n * `components: {}` 搬成 `<script setup>` 时漏掉这份表,就是这样逃过所有检查的)。\n *\n * 另注:`getComponentName` 的返回值还被当作**名字**传给 `handleGlobalDataChange(name, $event)`,\n * 所以也不能图省事把它改成「返回组件对象」——那会连带改坏这个回调的语义。\n */\ndefineOptions({\n name: 'ApprovalCore',\n components: {\n ColumnApprovalTables,\n ColumnApprovalForm,\n ColumnApprovalDataList,\n ColumnApprovalUnknown,\n CostCompanySelect,\n CostCompanyDepartment,\n CreateBySelect,\n SystemTime,\n FormCodeInput,\n CreateByCascader,\n PostionCascader,\n drawerTablesList,\n drawerDataList,\n },\n});\n\n// ApprovalCoreProps 见文件顶部普通 <script> 块(为了能 export)\nconst props = withDefaults(defineProps<ApprovalCoreProps>(), {\n approveRecordId: null,\n});\n\nconst emit = defineEmits<{\n /**\n * 保存成功。`isEdit` 为真表示这是一次「修改」(而非「新建」)。\n * 详情场景的模态框据此决定「关掉模态框回到详情页」还是「留在原地继续录入」。\n */\n (e: 'saved', payload: { isEdit?: boolean }): void;\n}>();\n\nconst context = useContextStore();\nconst userStore = useUserStore();\nconst eventBus = mitt();\n/** 与 props.modelType 同步;下面全部沿用小写 modelType.value 的写法,便于与宿主/后端字段对齐 */\nconst modelType = computed(() => props.modelType);\nconst columnCount = ref(3);\nconst is_debug_code_auth = ref(false);\nconst debugCodeStor = useDebugCodeStore();\n\n/**\n * 本实例三栏容器的唯一 id:挂到根 div 上(模板里的 `:id`),并注入给竖条组件\n * 当 Teleport 锚点。**不能用类名当锚点** —— 路由页与「修改」模态框会同时存在两个\n * `.approval-view`,原因与实测见 `./approvalViewId.ts` 的注释。\n */\nconst approvalViewId = buildApprovalViewId();\nprovide(APPROVAL_VIEW_ID, approvalViewId);\n\nconst approvalConfig = ref<ApprovalSetting | null>(null);\nconst flowConfig = ref<string | null>(null);\nconst globalData = ref<any>({});\nconst columnHeight = ref(0);\nconst columnItemContentRef = ref(null);\n\nconst topFormRef = ref();\nconst themeConfig = computed(() => {\n return {\n token: {\n // controlHeight: 20,\n // fontSize: 12,\n },\n };\n});\nconst layoutValue = computed(() => {\n let hasTable = false;\n if (approvalConfig.value?.columns) {\n for (const column of approvalConfig.value?.columns) {\n if (column.type === 'tables') {\n for (const item of column.tables) {\n if (!item.is_hidden) {\n hasTable = true;\n break;\n }\n }\n break;\n }\n }\n }\n if (hasTable) {\n return ['30px', '1fr', '30px'];\n } else {\n return ['0px', '1fr', '30px'];\n }\n});\n\n/**\n * 生成新流水号(全局数据 number,ApproveRecord.number 上有唯一约束)\n */\nconst genRecordNumber = async (config: any) => {\n return await getApiData(\n {\n prefix: config?.number_prefix,\n suffix: config?.number_suffix,\n digit_place: config?.number_digit_place,\n },\n '/approve/get_record_number',\n );\n};\n/**\n * 生成新单据编号(全局数据 form_code),与后端 get_form_code 算法对齐:\n * 编号格式为 前缀+年份后两位+月份+流水号\n */\nconst genFormCode = async (config: any) => {\n return await getApiData(\n {\n prefix: config?.form_code_prefix,\n },\n '/approve/get_form_code',\n );\n};\n/**\n * 生成「今天」的制单日期,结构对齐 SystemTime.vue 的取值格式\n * (create_date 同时参与职位查询,日期不同会导致查出的职位不同)\n */\nconst genCreateDate = () => {\n const now = dayjs();\n return {\n date: now.format('YYYY-MM-DD'),\n date_ch: now.format('YYYY年MM月DD日'),\n date_short: now.format('YYYYMMDD'),\n };\n};\n/**\n * 初始化/刷新页面配置与全局数据\n * @param options.skip_auto_numbering 加载「待编辑记录」时置 true:流水号/单据编号沿用记录自身携带的值,\n * 不做新建态的自动取号。必须显式传参而不是只看 store 里的 isEdit —— 点「修改/编辑」时本函数\n * 跑在进入编辑态之前(isEdit 仍为 false),会被当成新建重新取号;而\n * /approve/get_record_number 与 /approve/get_form_code 每次调用都会写 RecordNumber/FormCode 表,\n * 误调用既改掉单号、又让编号序列跳号。\n */\nconst initConfig = async (options?: { skip_auto_numbering?: boolean }) => {\n const skip_auto_numbering = !!options?.skip_auto_numbering;\n const res = await getApiData({ name: modelType.value }, '/approve/get_user_page_context', false, {\n skip_error: true,\n });\n let saved_current_history_id = null;\n if (res) {\n saved_current_history_id = res.current_history_id;\n context[SET_RAW](modelType.value, res);\n }\n const history_id = context.contexts?.[modelType.value]?.request_history_id;\n const flow_history_id = context.contexts?.[modelType.value]?.request_flow_history_id;\n const { config, current_history_id } = await getApprovalConfig(modelType.value, null, history_id);\n const { content: flow_config, current_history_id: current_flow_history_id } = await getFlowConfig(\n modelType.value,\n flow_history_id,\n );\n approvalConfig.value = config;\n flowConfig.value = flow_config;\n context[SET_CURRENT_HISTORY_ID](modelType.value, current_history_id);\n context[SET_CURRENT_FLOW_HISTORY_ID](modelType.value, current_flow_history_id);\n if (current_history_id != saved_current_history_id) {\n context[SET_FORM_MODEL](modelType.value, null);\n }\n columnCount.value = config.columns.length;\n const global_data = context.contexts?.[modelType.value]?.globalData;\n if (global_data) {\n globalData.value = global_data;\n }\n if (\n !skip_auto_numbering &&\n !context.contexts?.[modelType.value]?.isEdit &&\n (!globalData.value.number ||\n !globalData.value.number.startsWith(config.number_prefix) ||\n !globalData.value.number.endsWith(config.number_suffix))\n ) {\n const number = await genRecordNumber(config);\n globalData.value.number = number;\n saveContextImmediately();\n }\n // 与后端 get_form_code 算法对齐:编号格式为 前缀+年份后两位+月份+流水号\n // 需校验已生成的编码是否以「前缀+当前日期」开头,否则前缀变更(如长变短)或跨月时不会重新生成\n const now_date = new Date();\n const year_suffix = String(now_date.getFullYear()).slice(-2);\n const month = String(now_date.getMonth() + 1).padStart(2, '0');\n const form_code_date_prefix = `${config.form_code_prefix || ''}${year_suffix}${month}`;\n if (\n !skip_auto_numbering &&\n !context.contexts?.[modelType.value]?.isEdit &&\n config.form_code_prefix &&\n (!globalData.value.form_code?.code ||\n !globalData.value.form_code.code.startsWith(form_code_date_prefix))\n ) {\n const number = await genFormCode(config);\n globalData.value.form_code = { code: number };\n saveContextImmediately();\n }\n};\n\nconst getComponentName = (index: number) => {\n const item = approvalConfig.value?.columns[index];\n switch (item?.type) {\n case 'tables':\n return 'drawerTablesList';\n case 'form':\n return 'ColumnApprovalForm';\n case 'data_list':\n return 'drawerDataList';\n default:\n return 'ColumnApprovalUnknown';\n }\n};\nconst getColumnConfig = (index: number) => {\n const item = approvalConfig.value?.columns[index];\n return item;\n};\nconst resize = () => {\n if (columnItemContentRef.value) {\n columnHeight.value = columnItemContentRef.value.offsetHeight - 8.5; // 32为padding或间距,可根据实际调整\n }\n};\nwindow.setDebugCode = checked => {\n debugCodeStor[SET_ENABLE](checked);\n if (checked) {\n message.success('代码调试已开启');\n } else {\n message.info('代码调试已关闭');\n }\n};\nconst saveContext = debounce(async () => {\n saveContextImmediately();\n}, 1000);\nconst saveContextImmediately = async () => {\n await getApiData(\n { name: modelType.value, context: context.contexts[modelType.value] },\n '/approve/update_user_page_context',\n );\n};\nconst genModifyNumber = baseNumber => {\n if (!baseNumber) return baseNumber;\n if (baseNumber.indexOf('-') === -1) {\n return `${baseNumber}-1`;\n }\n const idx = baseNumber.lastIndexOf('-');\n const head = baseNumber.substring(0, idx);\n const tail = baseNumber.substring(idx + 1);\n if (/^\\d+$/.test(tail)) {\n return `${head}-${parseInt(tail, 10) + 1}`;\n }\n return `${baseNumber}-1`;\n};\n\n/**\n * 按审批记录 id 进入编辑态 —— 「修改」的**唯一**实现,两条入口都走这里:\n * 1. 列表页行按钮 / 详情页按钮 → 跑完 actionCode 拿到 `{ id }` 后调用;\n * 2. 模态框带 `approveRecordId` 打开 → onMounted 直接调用。\n *\n * 编辑态**不止一种**,都由记录自身字段派生(调用方不需要、也不应该自己判断):\n * - **普通编辑**:`process_status === 'init'` 或 `result_status === 'reject'`\n * → 流水号不变;表单结构可编辑(除非记录自带 modify_source,见下)\n * - **修改已通过的审批**(modifyMode):`approved + pass + is_modifiable + modify_status === '正常'`\n * → 先过 `/approve/check_approve_can_modify`,流水号变 `原号-1`,并且**锁定表单结构**\n * - **再次编辑「修改单」**:记录 B 本身带 `modify_source_id`\n * → 走普通编辑,但因为 B 的来源是修改单,同样**锁定表单结构**\n * 三者分别落成 columnForm 的 `isEdit` / `modifyMode` / `sourceApproveRecordId` / `lockStructure`,\n * 所以不能用一个布尔量表达。\n */\nconst applyApproveRecord = async (id: number) => {\n const approve_res = await getApiData({ approve_record_id: id }, '/approve/get_approve_record');\n const {\n page_setting_history_id,\n flow_setting_history_id,\n data,\n number,\n process_status,\n result_status,\n is_modifiable,\n modify_status,\n } = approve_res;\n // 记录本身若带 modify_source(即它是「修改上一个审批」的记录),编辑时必须锁定表单结构\n // (隐藏明细/表单模板的添加、清空、导入、行删除按钮),但流水号不再变化\n const modifySourceId =\n approve_res.modify_source_id ??\n (approve_res.modify_source && approve_res.modify_source.id) ??\n null;\n context[SET_REQUST_HISTORY_ID](modelType.value, page_setting_history_id);\n context[SET_REQUST_FLOW_HISTORY_ID](modelType.value, flow_setting_history_id);\n globalData.value = data.globalData;\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n await saveContextImmediately();\n // 编辑/修改一律沿用记录自身的流水号与单据编号(不重新取号),\n // 详见 initConfig 的 skip_auto_numbering 说明\n await initConfig({ skip_auto_numbering: true });\n // 已通过且可修改:进入修改模式(前端先算展示流水号,后端最终定)\n const isModifyApproved =\n process_status === 'approved' &&\n result_status === 'pass' &&\n is_modifiable === true &&\n modify_status === '正常';\n if (isModifyApproved) {\n const checkRes = await getApiData(\n { approve_record_id: id },\n '/approve/check_approve_can_modify',\n );\n if (!checkRes || !checkRes.can_modify) {\n message.error((checkRes && checkRes.msg) || '该审批记录不可修改');\n return;\n }\n const newNumber = genModifyNumber(number);\n globalData.value.number = newNumber;\n\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n eventBus.emit('update_form', {\n data,\n state: {\n id,\n number: newNumber,\n modifyMode: true,\n source_approve_record_id: id,\n modify_source_id: modifySourceId,\n },\n });\n } else {\n // 标准编辑(含「修改审批」记录 B 的再次编辑):流水号保持不变,\n // 若 B 本身带 modify_source 则锁定表单结构\n eventBus.emit('update_form', { data, state: { id, number, modify_source_id: modifySourceId } });\n }\n};\n\nconst eventAction = async ({ code, action, params }) => {\n const action_type = action.action;\n if (action_type === 'edit_approve') {\n if (!code) {\n return;\n }\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e instanceof Error ? e.message : String(e));\n return;\n }\n const { id } = res;\n if (!id) {\n message.error('代码未返回id');\n return;\n }\n await applyApproveRecord(id);\n } else if (action_type === 'copy_approve') {\n // 复制为新审批:把源审批的数据整份搬到当前表单,作为一条新的「待提交」审批。\n // 与 edit_approve 的区别:不复用源单据的 id/历史配置,且以下数据必须重新生成 ——\n // 1. 全局数据里的流水号、单据编号(否则与源单据撞唯一键/编号)\n // 2. 表单里配置的只读动态值(序号、覆盖ID 等,computeDynamicValue 不会重算已有值)\n if (!code) {\n return;\n }\n let res;\n try {\n res = await executeScriptInWorker(code, params);\n } catch (e) {\n console.error(e);\n message.error(e instanceof Error ? e.message : String(e));\n return;\n }\n const { id } = res || {};\n if (!id) {\n message.error('代码未返回id');\n return;\n }\n const confirm = await new Promise<boolean>(resolve => {\n Modal.confirm({\n title: '复制表单',\n content: '将覆盖当前表单数据,并以新的单据编号、流水号新建一条待提交审批',\n onOk: () => resolve(true),\n onCancel: () => resolve(false),\n });\n });\n if (!confirm) {\n return;\n }\n const approve_res = await getApiData({ approve_record_id: id }, '/approve/get_approve_record');\n const source_data = approve_res?.data;\n if (!source_data) {\n message.error('未获取到审批数据');\n return;\n }\n const config = approvalConfig.value || ({} as ApprovalSetting);\n // 1) 全局数据:继承源单据(制单人/流程组织/流程主题等),\n // 但流水号、单据编号、制单日期必须重新生成,职位需按新日期重新解析\n const new_global_data = {\n ...(globalData.value || {}),\n ...(cloneDeep(source_data.globalData) || {}),\n };\n new_global_data.number = await genRecordNumber(config);\n // 制单日期取今天(不能沿用源单据的旧日期:职位查询依赖该日期)\n new_global_data.create_date = genCreateDate();\n // 职位是 (制单人, 制单日期) 派生出来的数据,日期已变为今天,必须按今天重新解析:\n // 清空三件套后由 PostionCascader.getData() 自动按当天重算(查不到则置空,走必填校验拦截)\n new_global_data.person_cost_company = null;\n new_global_data.person_department = null;\n new_global_data.person_position = null;\n if (config.form_code_prefix) {\n new_global_data.form_code = { code: await genFormCode(config) };\n } else {\n // 未配置单据编号前缀(该页面不使用单据编号)时不继承源单据的旧编号\n delete new_global_data.form_code;\n }\n globalData.value = new_global_data;\n // 2) 回到「新建」态:清空编辑态与历史版本指向,按当前页面配置渲染\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n context[SET_EDIT](modelType.value, false, {});\n context[SET_REQUST_HISTORY_ID](modelType.value, null);\n context[SET_REQUST_FLOW_HISTORY_ID](modelType.value, null);\n // 3) 表单数据:源单据 data 去掉 globalData(全局数据由上方单独维护),\n // 并清空只读动态值,交由 DynamicValueField / FormTemplate 重新计算\n const form_model = cloneDeep(source_data);\n delete form_model.globalData;\n clearDynamicValueFields(form_model, getFormDynamicFieldList(config));\n context[SET_FORM_MODEL](modelType.value, form_model);\n // 先持久化再 initConfig:initConfig 会重新拉取用户上下文与当前页面配置\n await saveContextImmediately();\n await initConfig();\n context[SET_FORM_MODEL](modelType.value, form_model);\n eventBus.emit('copy_form', { data: form_model });\n }\n};\nconst eventReinit = async () => {\n initConfig();\n};\n/**\n * 「保存成功」从表单列(columnForm.vue)冒上来后原样转发给外层。\n * 详情场景的模态框需要它来判断「这次是修改还是新建」以及要不要刷新详情/列表。\n * 路由页面场景没人监听,转发出去也无副作用。\n */\nconst eventSaved = (payload: { isEdit?: boolean }) => {\n emit('saved', payload || {});\n};\nconst handleGlobalDataChange = (_cid, update) => {\n context[SET_GLOBAL_DATA](modelType.value, globalData.value);\n if (update) {\n saveContext();\n }\n};\n\nonMounted(async () => {\n eventBus.on('run_action', eventAction);\n eventBus.on('reinit', eventReinit);\n eventBus.on('saved', eventSaved);\n is_debug_code_auth.value = userStore.CHECK_AUTH('approve/debug_code', '开启代码调试');\n window.addEventListener('resize', resize);\n resize();\n /**\n * ⚠️ 顺序不能颠倒:带 approveRecordId 时**必须先 applyApproveRecord**,\n * 绝不能先跑一次普通的 initConfig()。\n * 原因见 initConfig 的 skip_auto_numbering 说明 —— 普通 initConfig() 会把「待编辑记录」\n * 当成新建去重新取流水号/单据编号,既改掉原单号又让编号序列跳号;\n * 而且 applyApproveRecord 内部本来就会调 initConfig({skip_auto_numbering:true}),\n * 先跑一次等于白发一次写库请求。\n */\n if (props.approveRecordId) {\n await applyApproveRecord(props.approveRecordId);\n } else {\n await initConfig();\n }\n // initConfig 可能会改写 layoutValue(是否含表格),尺寸需在其之后再量一次\n resize();\n});\n\n// 组件卸载时移除监听\nonUnmounted(() => {\n eventBus.off('run_action', eventAction);\n eventBus.off('reinit', eventReinit);\n eventBus.off('saved', eventSaved);\n window.removeEventListener('resize', resize);\n});\n\n// 路由页面切换节点时(同一个页面实例复用),父级会换 modelType;模态框场景不会变\nwatch(\n () => props.modelType,\n (val, old) => {\n if (!val || val === old) return;\n initConfig();\n },\n);\n\ndefineExpose({\n /** 按审批记录 id 进入编辑态(编辑态种类由记录字段派生,见上方注释) */\n applyApproveRecord,\n /** 重新拉取页面配置与全局数据 */\n reinit: eventReinit,\n /** 供外部(模态框)在需要时重新量一次高度 */\n resize,\n});\n</script>\n\n<style lang=\"less\" scoped>\n.header-content {\n padding: 8px 16px;\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n gap: 8px;\n}\n\n.header-label {\n &::before {\n content: '';\n display: block;\n position: absolute;\n margin-left: 4px;\n width: 1px;\n background-color: #c1c1c1;\n top: 4px;\n bottom: 4px;\n left: -9px;\n }\n}\n.header-item {\n position: relative;\n display: flex-inline;\n flex-direction: row;\n align-items: center;\n}\n.header-value {\n min-width: 500px;\n flex: 0;\n line-height: 24px;\n}\n.column-item-content {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n.header-item-space {\n display: block;\n width: 10px;\n}\n.zoom-btn-wraper {\n position: absolute;\n z-index: 1;\n\n width: 100%;\n display: flex;\n top: -6px;\n justify-content: space-between;\n padding-right: 20px;\n\n .zom-btn {\n font-size: 20px;\n padding: 0;\n }\n .right {\n }\n}\n/* 模态框里由外层给固定高度,这里撑满;路由页面下父级无显式高度时该声明自然退化为 auto,无副作用 */\n.approval-view {\n height: 100%;\n}\n</style>\n"],"mappings":"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"}