cloud-web-corejs 1.0.54-dev.781 → 1.0.54-dev.783

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 (33) hide show
  1. package/package.json +1 -1
  2. package/src/components/VabUpload/index.vue +242 -242
  3. package/src/components/VabUpload/mixins.js +1971 -1971
  4. package/src/components/VabUpload/privateProfileDialog.vue +2 -2
  5. package/src/components/hiprint/view/design/index.vue +7 -2
  6. package/src/components/obsUpload/index.vue +234 -234
  7. package/src/components/obsUpload/mixins.js +1542 -1542
  8. package/src/components/vb-tabs/x-tabs.vue +7 -3
  9. package/src/components/xform/docs//346/240/221/350/241/250rowField/346/224/266/346/225/233-/350/220/275/345/234/260/346/226/207/346/241/243.md +1427 -0
  10. package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +2 -2
  11. package/src/components/xform/form-designer/form-widget/dialog/formDrawer.vue +2 -2
  12. package/src/components/xform/form-designer/form-widget/dialog/searchFormDialog.vue +2 -2
  13. package/src/components/xform/form-designer/form-widget/field-widget/copy_button-widget.vue +11 -2
  14. package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +369 -369
  15. package/src/components/xform/form-designer/setting-panel/property-editor/fileTypesSelect.vue +69 -23
  16. package/src/components/xform/form-render/container-item/data-table-item.vue +1 -1
  17. package/src/components/xform/form-render/container-item/data-table-mixin.js +1469 -428
  18. package/src/components/xform/form-render/indexMixin.js +379 -263
  19. package/src/components/xform/mixins/defaultHandle.js +234 -28
  20. package/src/components/xform/mixins/scriptHttp.js +4 -4
  21. package/src/components/xform/utils/treeTableUtil.js +1265 -0
  22. package/src/components/xform/utils/util.js +29 -14
  23. package/src/microRouter/index.js +3 -0
  24. package/src/mixins/tableTree/index.js +77 -14
  25. package/src/store/config/index.js +28 -28
  26. package/src/utils/menuAdapter.js +277 -277
  27. package/src/utils/resolveViewComponent.js +203 -203
  28. package/src/utils/vab.js +6 -3
  29. package/src/views/bd/setting/formVersion/ftHistoryDialog.vue +9 -2
  30. package/src/views/user/common_attribute/list.vue +1 -1
  31. package/src/views/user/form/vform/render.vue +17 -2
  32. package/src/views/user/form/view/list.vue +11 -10
  33. package/src/views/user/wf/wfReport/index.vue +625 -625
@@ -52,9 +52,19 @@ import formulaDialog from "@base/components/xform/form-designer/form-widget/dial
52
52
  import baseFormulaDialog from "@base/components/xform/form-designer/form-widget/dialog/baseFormulaDialog.vue";
53
53
  import QRCode from "qrcode";
54
54
  import { openLuckysheetDialog } from "@base/components/luckysheet";
55
- import {
56
- openComponentDialog as mountComponentDialog,
57
- } from "@base/utils/componentDialog";
55
+ import {
56
+ openComponentDialog as mountComponentDialog,
57
+ } from "@base/utils/componentDialog";
58
+ import {
59
+ buildTreeSubmitData,
60
+ copyTreeData,
61
+ getTreeLoadState,
62
+ isTemporaryTreeKey,
63
+ resolveTreeCopyConfig,
64
+ resolveTreeFields,
65
+ resolveTreeIdentityConfig,
66
+ resolveTreeSubmitConfig,
67
+ } from "../utils/treeTableUtil";
58
68
 
59
69
  let modules = {};
60
70
  const baseRefUtil = {
@@ -1283,12 +1293,12 @@ modules = {
1283
1293
 
1284
1294
  return hasModifyItem;
1285
1295
  },
1286
- loadFormData(options) {
1287
- let config = options.config || {};
1296
+ loadFormData(options = {}) {
1297
+ let config = options.config || {};
1288
1298
  let that = this;
1289
1299
  let formConfig = this.formConfig;
1290
1300
  let entity = formConfig.entity;
1291
- let dataId = this.dataId;
1301
+ let dataId = options.dataId ?? this.dataId;
1292
1302
  let reportTemplate = this.reportTemplate;
1293
1303
  let scriptCode = formConfig.formScriptCode || "getOne";
1294
1304
 
@@ -1317,11 +1327,13 @@ modules = {
1317
1327
  ...formScriptParam,
1318
1328
  },
1319
1329
  },
1320
- ...defaultOption,
1321
- success: (res) => {
1322
- formData = res.objx || {};
1323
- this.setFormData(formData);
1324
- options.callback && options.callback(formData);
1330
+ ...defaultOption,
1331
+ success: (res) => {
1332
+ formData = res.objx || {};
1333
+ this.setFormData(formData, {
1334
+ replace: options.replace === true,
1335
+ });
1336
+ options.callback && options.callback(formData);
1325
1337
  },
1326
1338
  ...config,
1327
1339
  });
@@ -1989,12 +2001,22 @@ modules = {
1989
2001
  n
1990
2002
  );
1991
2003
  },
1992
- setFormData: function (e) {
1993
- let t = this;
2004
+ setFormData: function (e, options = {}) {
2005
+ let t = this;
1994
2006
  /*Object.keys(this.formDataModel).forEach(function (i) {
1995
2007
  e && e.hasOwnProperty(i) && (t.formDataModel[i] = baseRefUtil.deepClone(e[i]));
1996
2008
  });*/
1997
- Object.assign(t.formDataModel, baseRefUtil.deepClone(e));
2009
+ let nextFormData = baseRefUtil.deepClone(e || {});
2010
+ if (options.replace === true) {
2011
+ Object.keys(t.formDataModel).forEach((key) => {
2012
+ t.$delete(t.formDataModel, key);
2013
+ });
2014
+ Object.keys(nextFormData).forEach((key) => {
2015
+ t.$set(t.formDataModel, key, nextFormData[key]);
2016
+ });
2017
+ } else {
2018
+ Object.assign(t.formDataModel, nextFormData);
2019
+ }
1998
2020
  this.currentFormData = e || {};
1999
2021
  this.broadcast("ContainerItem", "setFormData", this.formDataModel),
2000
2022
  this.broadcast("FieldWidget", "setFormData", this.formDataModel);
@@ -3971,13 +3993,206 @@ modules = {
3971
3993
  reject(msg);
3972
3994
  });
3973
3995
  });
3974
- },
3975
- getSubData2(flag) {
3996
+ },
3997
+ getTreeTableUtilContext(tableTarget, $grid, source) {
3998
+ let treeConfig = $grid?.treeConfig || {};
3999
+ let originOption
4000
+ = $grid?.params?.originOption || $grid?.originOption || {};
4001
+ let fields = resolveTreeFields(treeConfig, {
4002
+ strict: true,
4003
+ });
4004
+ let identityConfig = resolveTreeIdentityConfig(
4005
+ treeConfig,
4006
+ originOption.treeIdentityConfig || {}
4007
+ );
4008
+ let copyConfig = resolveTreeCopyConfig(
4009
+ fields,
4010
+ identityConfig,
4011
+ originOption.treeCopyConfig || {}
4012
+ );
4013
+ let submitConfig = resolveTreeSubmitConfig(
4014
+ originOption.treeSubmitConfig || {}
4015
+ );
4016
+ let temporaryKeyRegistry
4017
+ = tableTarget?.treeTemporaryKeyRegistry || new Set();
4018
+ let knownFormalKeyRegistry
4019
+ = tableTarget?.treeKnownFormalKeyRegistry || new Set();
4020
+
4021
+ this.collectTreeRuntimeRows(source || [], treeConfig).forEach((row) => {
4022
+ let rowValue = row[fields.rowField];
4023
+ let marker = row._X_TREE_TEMP_KEY;
4024
+ if (marker !== undefined && marker !== null) {
4025
+ temporaryKeyRegistry.add(marker);
4026
+ }
4027
+ if (
4028
+ rowValue !== undefined
4029
+ && rowValue !== null
4030
+ && rowValue !== ""
4031
+ && !isTemporaryTreeKey(row, fields.rowField, identityConfig)
4032
+ ) {
4033
+ knownFormalKeyRegistry.add(rowValue);
4034
+ }
4035
+ });
4036
+
4037
+ return {
4038
+ fields,
4039
+ identityConfig,
4040
+ copyConfig,
4041
+ submitConfig,
4042
+ temporaryKeyRegistry,
4043
+ knownFormalKeyRegistry,
4044
+ };
4045
+ },
4046
+ collectTreeRuntimeRows(rows, treeConfig) {
4047
+ let result = [];
4048
+ let visited = new WeakSet();
4049
+ let childrenFields = [
4050
+ treeConfig?.children,
4051
+ treeConfig?.mapChildren || "_X_ROW_CHILD",
4052
+ ].filter(Boolean);
4053
+ let visit = (items) => {
4054
+ if (!Array.isArray(items)) return;
4055
+ items.forEach((item) => {
4056
+ if (!item || typeof item !== "object" || visited.has(item)) return;
4057
+ visited.add(item);
4058
+ result.push(item);
4059
+ childrenFields.forEach((field) => {
4060
+ visit(item[field]);
4061
+ });
4062
+ });
4063
+ };
4064
+ visit(rows);
4065
+ return result;
4066
+ },
4067
+ getTreeRuntimeSource($grid, source) {
4068
+ let result = Array.isArray(source) ? source.slice() : [];
4069
+ let runtimeSources = [
4070
+ $grid?.getTableData?.()?.fullData,
4071
+ $grid?.$refs?.xTable?.tableFullTreeData,
4072
+ ];
4073
+ runtimeSources.forEach((rows) => {
4074
+ if (!Array.isArray(rows)) return;
4075
+ rows.forEach((row) => {
4076
+ if (!result.includes(row)) result.push(row);
4077
+ });
4078
+ });
4079
+ return result;
4080
+ },
4081
+ getTreeUnloadedRows($grid, treeConfig) {
4082
+ let xTable = $grid?.$refs?.xTable;
4083
+ let fullData = this.getTreeRuntimeSource($grid, []);
4084
+ return this.collectTreeRuntimeRows(fullData, treeConfig).filter(
4085
+ (row) =>
4086
+ getTreeLoadState(row, {
4087
+ fields: resolveTreeFields(treeConfig),
4088
+ isTreeNodeLoaded:
4089
+ typeof xTable?.isTreeExpandLoaded === "function"
4090
+ ? (targetRow) => xTable.isTreeExpandLoaded(targetRow)
4091
+ : null,
4092
+ }).requiresLoad
4093
+ );
4094
+ },
4095
+ async ensureTreeTableLoadState(formTemplateTableDTO, operation) {
4096
+ let tableTarget = this.getWidgetRef(formTemplateTableDTO.uniqueName);
4097
+ let $grid = tableTarget?.getGridTable?.();
4098
+ let treeConfig = $grid?.treeConfig;
4099
+ if (!$grid || !treeConfig?.lazy) return;
4100
+
4101
+ let treeContext = this.getTreeTableUtilContext(
4102
+ tableTarget,
4103
+ $grid,
4104
+ this.formDataModel[formTemplateTableDTO.name] || []
4105
+ );
4106
+ let strategy = operation === "copy"
4107
+ ? treeContext.copyConfig.lazyStrategy
4108
+ : treeContext.submitConfig.unloadedChildrenStrategy;
4109
+ if (operation === "submit" && strategy === "omit") return;
4110
+
4111
+ let xTable = $grid.$refs?.xTable;
4112
+ if (
4113
+ !xTable
4114
+ || typeof xTable.isTreeExpandLoaded !== "function"
4115
+ || typeof $grid.setTreeExpand !== "function"
4116
+ ) {
4117
+ throw new Error(
4118
+ `[${formTemplateTableDTO.tableAlias}]无法读取树节点加载状态`
4119
+ );
4120
+ }
4121
+
4122
+ let unloadedRows = this.getTreeUnloadedRows($grid, treeConfig);
4123
+ if (!unloadedRows.length) return;
4124
+ if (strategy !== "loadAll") {
4125
+ let action = operation === "copy" ? "复制" : "保存";
4126
+ throw new Error(
4127
+ `[${formTemplateTableDTO.tableAlias}]存在尚未加载的树节点,请先展开后再${action}`
4128
+ );
4129
+ }
4130
+
4131
+ let loopCount = 0;
4132
+ while (unloadedRows.length) {
4133
+ if (loopCount++ > 100) {
4134
+ throw new Error(
4135
+ `[${formTemplateTableDTO.tableAlias}]树节点层级过深,无法完成加载`
4136
+ );
4137
+ }
4138
+ let currentRows = unloadedRows;
4139
+ await Promise.all(
4140
+ currentRows.map((row) => $grid.setTreeExpand(row, true))
4141
+ );
4142
+ unloadedRows = this.getTreeUnloadedRows($grid, treeConfig);
4143
+ if (
4144
+ unloadedRows.length === currentRows.length
4145
+ && unloadedRows.every((row) => currentRows.includes(row))
4146
+ ) {
4147
+ throw new Error(
4148
+ `[${formTemplateTableDTO.tableAlias}]树节点加载未完成,已停止保存`
4149
+ );
4150
+ }
4151
+ }
4152
+ },
4153
+ async ensureTreeTableReadyForSubmit(formTemplateTableDTO) {
4154
+ return this.ensureTreeTableLoadState(
4155
+ formTemplateTableDTO,
4156
+ "submit"
4157
+ );
4158
+ },
4159
+ async prepareTreeTablesForCopy() {
4160
+ let treeTables = this.getFormTemplateTableDTOs().filter(
4161
+ (item) => item.isTreeTable
4162
+ );
4163
+ for (let index = 0; index < treeTables.length; index++) {
4164
+ await this.ensureTreeTableLoadState(treeTables[index], "copy");
4165
+ }
4166
+ },
4167
+ async buildSubmitPayload(option) {
4168
+ let treeTables = this.getFormTemplateTableDTOs().filter(
4169
+ (item) => item.isTreeTable
4170
+ );
4171
+ for (let index = 0; index < treeTables.length; index++) {
4172
+ await this.ensureTreeTableReadyForSubmit(treeTables[index]);
4173
+ }
4174
+ let formDataSnapshot = this.$baseLodash.cloneDeep(this.formDataModel);
4175
+ let subData = this.getSubData2(false, {
4176
+ mode: "submit",
4177
+ formDataModel: formDataSnapshot,
4178
+ });
4179
+ if (option) {
4180
+ let realFormData = {};
4181
+ Object.keys(option).forEach((key) => {
4182
+ realFormData[option[key]] = subData[key];
4183
+ });
4184
+ return realFormData;
4185
+ }
4186
+ return subData;
4187
+ },
4188
+ getSubData2(flag, context = {}) {
3976
4189
  let that = this;
3977
4190
  let formCode = this.reportTemplate.formCode;
3978
4191
  let tableFiledMap = this.getTableFiledMap();
3979
4192
  let formTemplateTableDTOs = this.getFormTemplateTableDTOs();
3980
- let formDataModel = this.formDataModel;
4193
+ let formDataModel
4194
+ = context.formDataModel
4195
+ || this.$baseLodash.cloneDeep(this.formDataModel);
3981
4196
  let formConfig = this.formConfig;
3982
4197
 
3983
4198
  let res = {};
@@ -4012,63 +4227,32 @@ modules = {
4012
4227
  newFormData[tableAlias] = item ?? null;
4013
4228
  } else {
4014
4229
  if (formTemplateTableDTO.isTreeTable) {
4015
- let tableTarget = this.getWidgetRef(
4016
- formTemplateTableDTO.uniqueName
4017
- );
4018
- let $grid = tableTarget.getGridTable();
4019
- let parentField = $grid.treeConfig.parentField;
4020
- let treeTaBm = newFormData.treeTaBm || [];
4021
- treeTaBm.push(formTemplateTableDTO.tableAlias);
4022
- newFormData.treeTaBm = treeTaBm;
4023
- // 树的主键以 treeConfig.rowField 为准:transform 模式下 vxe 是用它
4024
- // (xe-utils toArrayTree 的 key) 建树的,根节点判定必须与之同源,
4025
- // 否则判出来的顶层节点和表格里的实际层级对不上。
4026
- let idField = $grid.treeConfig.rowField || "id";
4027
- let tableDatas = this.$baseLodash.cloneDeep(
4028
- formDataModel[formTemplateTableDTO.name] || []
4029
- );
4030
- // 根节点判定必须在下面清空临时 id 之前完成:新增子行的父 id 是
4031
- // "row_xxx",清空后变成空值,之后再判定就会被误判成根节点,既提交成
4032
- // 顶层节点又已嵌在父行的 children 里,造成重复与层级错乱。
4033
- // 判定口径与 toArrayTree 一致:父值为空(null/undefined/""/0/"0")视为
4034
- // 根;父值非空但父行不在本表数据里(过滤/查询后的孤儿行)也要收进顶层
4035
- // 数组,否则整棵子树被静默丢弃——它的 parentField 原值保留不清空,
4036
- // 后端据此重新挂接到既有父节点。
4037
- let idSet = new Set();
4038
- tableDatas.forEach((tableData) => {
4039
- let id = tableData[idField];
4040
- if (id !== null && id !== undefined && id !== "") {
4041
- idSet.add(String(id));
4042
- }
4043
- });
4044
- let isRootFlags = tableDatas.map((tableData) => {
4045
- let parentValue = tableData[parentField];
4046
- if ([null, undefined, "", 0, "0"].includes(parentValue)) {
4047
- return true;
4048
- }
4049
- return !idSet.has(String(parentValue));
4050
- });
4051
- // 临时 id 要连字面量 id 一起清:新增行(addTreeRow)把 "row_xxx" 写在
4052
- // row.id 上,复制(handleCopyTreeData)写在 rowField 上,来源不同,
4053
- // 只清一个会把临时 id 提交给后端。rowField 缺省时两者是同一字段。
4054
- let clearTempValue = (tableData, field) => {
4055
- let value = tableData[field];
4056
- if (value && value.startsWith && value.startsWith("row_")) {
4057
- tableData[field] = null;
4058
- }
4059
- };
4060
- tableDatas.forEach((tableData) => {
4061
- clearTempValue(tableData, idField);
4062
- if (idField !== "id") {
4063
- clearTempValue(tableData, "id");
4064
- }
4065
- clearTempValue(tableData, parentField);
4066
- if (tableData[parentField] === undefined)
4067
- tableData[parentField] = null;
4068
- });
4069
- tableDatas = tableDatas.filter((item, index) => isRootFlags[index]);
4070
- newFormData[tableAlias] = tableDatas;
4071
- } else {
4230
+ let tableTarget = this.getWidgetRef(
4231
+ formTemplateTableDTO.uniqueName
4232
+ );
4233
+ let $grid = tableTarget.getGridTable();
4234
+ let treeTaBm = newFormData.treeTaBm || [];
4235
+ treeTaBm.push(formTemplateTableDTO.tableAlias);
4236
+ newFormData.treeTaBm = treeTaBm;
4237
+ let modelRows = formDataModel[formTemplateTableDTO.name];
4238
+ let sourceRows = Array.isArray(modelRows) ? modelRows : [];
4239
+ let treeContext = this.getTreeTableUtilContext(
4240
+ tableTarget,
4241
+ $grid,
4242
+ sourceRows
4243
+ );
4244
+ newFormData[tableAlias] = buildTreeSubmitData(sourceRows, {
4245
+ ...treeContext,
4246
+ submitConfig:
4247
+ context.mode === "submit"
4248
+ ? treeContext.submitConfig
4249
+ : {
4250
+ ...treeContext.submitConfig,
4251
+ orphanParentStrategy: "preserve",
4252
+ },
4253
+ strict: context.mode === "submit",
4254
+ });
4255
+ } else {
4072
4256
  newFormData[tableAlias] =
4073
4257
  formDataModel[formTemplateTableDTO.name] ?? null;
4074
4258
  }
@@ -4265,10 +4449,10 @@ modules = {
4265
4449
  this.$baseReload();
4266
4450
  }
4267
4451
  },
4268
- reloadForm(option) {
4269
- let target1 = this.$attrs["parent-target"];
4270
- let target2 = target1?.$attrs["parent-target"];
4271
- let target = !target2 ? this : target1;
4452
+ reloadForm(option) {
4453
+ let target1 = this.$attrs["parent-target"];
4454
+ let target2 = target1?.$attrs["parent-target"];
4455
+ let target = !target2 ? this : target1;
4272
4456
  /* if (this.$attrs['reloadDialog'] !== true) {
4273
4457
  target = this.$attrs['parent-target'];
4274
4458
  }else{
@@ -4278,8 +4462,44 @@ modules = {
4278
4462
  for (let key in updateParam) {
4279
4463
  target.$emit("update:" + key, updateParam[key]);
4280
4464
  }*/
4281
- target.$baseReload(option);
4282
- },
4465
+ try {
4466
+ let reloadListener = target?.$listeners?.reload;
4467
+ if (Array.isArray(reloadListener)) {
4468
+ return Promise.all(
4469
+ reloadListener.map((listener) => listener(target, option))
4470
+ );
4471
+ }
4472
+ if (typeof reloadListener === "function") {
4473
+ return Promise.resolve(reloadListener(target, option));
4474
+ }
4475
+ return Promise.resolve(target.$baseReload(option));
4476
+ } catch (error) {
4477
+ return Promise.reject(error);
4478
+ }
4479
+ },
4480
+ async reloadSavedFormData(option = {}) {
4481
+ let updateParam = option.updateParam || {};
4482
+ let nextDataId = updateParam.dataId ?? this.dataId;
4483
+ let nextFormCode = updateParam.formCode;
4484
+ if (nextDataId === undefined || nextDataId === null || nextDataId === "") {
4485
+ throw new Error("缺少保存后的数据 ID,无法重新加载表单。");
4486
+ }
4487
+ let response = await this.loadFormData({
4488
+ dataId: nextDataId,
4489
+ replace: true,
4490
+ });
4491
+ if (!response || response.type !== "success") {
4492
+ throw new Error(response?.content || "保存后的表单数据重新加载失败。");
4493
+ }
4494
+ if (nextDataId !== undefined && nextDataId !== null) {
4495
+ this.$emit("update:dataId", nextDataId);
4496
+ }
4497
+ if (nextFormCode) {
4498
+ this.$emit("update:formCode", nextFormCode);
4499
+ }
4500
+ await new Promise((resolve) => this.$nextTick(resolve));
4501
+ return response;
4502
+ },
4283
4503
  saveForm(callback) {
4284
4504
  this.validateForm((valid) => {
4285
4505
  if (!valid) return;
@@ -4674,181 +4894,69 @@ modules = {
4674
4894
  getFormRef() {
4675
4895
  return this;
4676
4896
  },
4677
- isObject(value) {
4678
- return Object.prototype.toString.call(value) === "[object Object]";
4679
- },
4680
- handleCopyTreeData(value, widget) {
4681
- if (!value || !widget || !Array.isArray(value) || value.length === 0)
4682
- return;
4683
-
4684
- // 获取树形表格配置
4685
- const widgetName = widget.options.name;
4686
- const gridRef = this.getWidgetRef(widgetName);
4687
- const $grid = gridRef.getGridTable();
4688
- const treeConfig = $grid.treeConfig;
4689
- const idField = treeConfig.rowField || "id";
4690
- const parentField = treeConfig.parentField;
4691
- const childrenField = treeConfig.children;
4692
-
4693
- // 初始化 id 生成器
4694
- const baseTime = new Date().valueOf();
4695
- let counter = 0;
4696
- const idMap = {}; // 旧 id 到新 id 的映射
4697
-
4698
- // 生成新的 id(以 'row_' 开头)
4699
- const generateNewId = () => {
4700
- counter++;
4701
- return `row_${baseTime}_${counter}_${Math.floor(
4702
- Math.random() * 1000000
4703
- )}`;
4704
- };
4705
-
4706
- // 收集所有节点(包括扁平数组和嵌套结构中的节点),使用 Set 去重
4707
- const allNodes = [];
4708
- const processedNodes = new WeakSet(); // 使用 WeakSet 来跟踪已处理的节点,避免重复处理
4709
-
4710
- const collectAllNodes = (nodes) => {
4711
- if (!Array.isArray(nodes)) return;
4712
- nodes.forEach((node) => {
4713
- if (node && this.isObject(node) && !processedNodes.has(node)) {
4714
- processedNodes.add(node);
4715
- allNodes.push(node);
4716
- // 递归收集嵌套在 childrenField 中的节点
4717
- if (node[childrenField] && Array.isArray(node[childrenField])) {
4718
- collectAllNodes(node[childrenField]);
4719
- }
4720
- }
4721
- });
4722
- };
4723
- collectAllNodes(value);
4724
-
4725
- // 第一步:为所有节点生成新的 id 并建立映射
4726
- // 注意:即使 id 为 null,也要生成新 id
4727
- allNodes.forEach((node) => {
4728
- if (node[idField] !== undefined && node[idField] !== null) {
4729
- // 如果节点已有 id,记录映射关系
4730
- const oldId = node[idField];
4731
- const newId = generateNewId();
4732
- idMap[oldId] = newId;
4733
- node[idField] = newId;
4734
- } else {
4735
- // 如果节点 id 为 null 或 undefined,直接生成新 id
4736
- const newId = generateNewId();
4737
- node[idField] = newId;
4738
- }
4739
- });
4740
-
4741
- // 第二步:更新所有节点的 parentField(使用映射的新 id)
4742
- allNodes.forEach((node) => {
4743
- if (
4744
- node[parentField] !== undefined &&
4745
- node[parentField] !== null &&
4746
- node[parentField] !== 0
4747
- ) {
4748
- const oldParentId = node[parentField];
4749
- // 如果父节点的旧 id 在映射中,更新为新 id
4750
- if (idMap[oldParentId]) {
4751
- node[parentField] = idMap[oldParentId];
4752
- } else {
4753
- // 如果父节点不在映射中(可能是外部引用或已处理),尝试在 allNodes 中查找
4754
- const parentNode = allNodes.find((n) => n[idField] === oldParentId);
4755
- if (parentNode) {
4756
- node[parentField] = parentNode[idField];
4757
- } else {
4758
- // 找不到父节点,设置为 0(根节点)
4759
- node[parentField] = 0;
4760
- }
4761
- }
4762
- }
4763
- });
4764
-
4765
- // 第三步:更新嵌套的 childrenField 结构中的 parentField
4766
- const updateNestedChildrenParent = (node) => {
4767
- if (
4768
- !node ||
4769
- !node[childrenField] ||
4770
- !Array.isArray(node[childrenField]) ||
4771
- node[childrenField].length === 0
4772
- ) {
4773
- return;
4774
- }
4775
-
4776
- node[childrenField].forEach((child) => {
4777
- if (child && node[idField]) {
4778
- child[parentField] = node[idField];
4779
- }
4780
- updateNestedChildrenParent(child);
4781
- });
4782
- };
4783
- allNodes.forEach((node) => updateNestedChildrenParent(node));
4784
-
4785
- // 第四步:处理节点中的其他数组字段(如子表单、附件列表等)
4786
- // 注意:需要跳过树形结构相关的字段,避免误处理
4787
- const treeRelatedFields = new Set([
4788
- idField,
4789
- parentField,
4790
- childrenField,
4791
- "_X_ROW_KEY",
4792
- "_X_ROW_CHILD",
4793
- "f_wbs",
4794
- ]);
4795
- const processedArrayNodes = new WeakSet(); // 跟踪已处理的数组节点,避免重复处理
4796
-
4797
- const processNodeArrayFields = (node) => {
4798
- if (!node || !this.isObject(node)) return;
4799
-
4800
- // 如果节点已经在 allNodes 中(是树形节点),跳过处理,避免覆盖已生成的 id
4801
- if (processedNodes.has(node)) {
4802
- return;
4803
- }
4804
-
4805
- Object.keys(node).forEach((key) => {
4806
- // 跳过树形结构相关字段
4807
- if (treeRelatedFields.has(key)) {
4808
- return;
4809
- }
4810
-
4811
- const fieldValue = node[key];
4812
-
4813
- // 处理数组字段
4814
- if (Array.isArray(fieldValue) && fieldValue.length > 0) {
4815
- fieldValue.forEach((item) => {
4816
- if (this.isObject(item)) {
4817
- // 如果这个对象是树形节点(在 allNodes 中),跳过处理
4818
- if (processedNodes.has(item)) {
4819
- return;
4820
- }
4821
-
4822
- // 只有非树形节点的数组元素才需要清空 id
4823
- if (item.id !== undefined) {
4824
- item.id = null;
4825
- }
4826
- this.handleCopyDefaultData(item);
4827
-
4828
- // 标记已处理,避免重复处理
4829
- if (!processedArrayNodes.has(item)) {
4830
- processedArrayNodes.add(item);
4831
- processNodeArrayFields(item);
4832
- }
4833
- }
4834
- });
4835
- return;
4836
- }
4837
-
4838
- // 处理嵌套对象
4839
- if (this.isObject(fieldValue)) {
4840
- // 如果这个对象是树形节点,跳过处理
4841
- if (!processedNodes.has(fieldValue)) {
4842
- processNodeArrayFields(fieldValue);
4843
- }
4844
- }
4845
- });
4846
- };
4847
-
4848
- // 处理所有节点中的其他数组字段
4849
- allNodes.forEach((node) => processNodeArrayFields(node));
4850
- },
4851
- handleCopyDefaultData(data) {
4897
+ isObject(value) {
4898
+ return Object.prototype.toString.call(value) === "[object Object]";
4899
+ },
4900
+ handleCopyTreeData(value, widget) {
4901
+ if (!Array.isArray(value) || !widget) return;
4902
+
4903
+ let widgetName = widget.options.name;
4904
+ let gridRef = this.getWidgetRef(widgetName);
4905
+ let $grid = gridRef?.getGridTable?.();
4906
+ if (!$grid) {
4907
+ throw new Error(`[${widgetName}]树表尚未初始化`);
4908
+ }
4909
+ if (
4910
+ $grid.treeConfig?.lazy
4911
+ && this.getTreeUnloadedRows($grid, $grid.treeConfig).length
4912
+ ) {
4913
+ throw new Error(
4914
+ `[${widgetName}]存在尚未加载的树节点,无法复制不完整子树`
4915
+ );
4916
+ }
4917
+
4918
+ // prepareTreeTablesForCopy 会在深拷贝及 copyDataHandle 之前完成 loadAll,
4919
+ // 此处只消费准备好的副本;不能再混入 VXE 活对象,否则会覆盖脚本修改并产生同键冲突。
4920
+ let sourceRows = value;
4921
+ if (!sourceRows.length) return;
4922
+
4923
+ let treeContext = this.getTreeTableUtilContext(
4924
+ gridRef,
4925
+ $grid,
4926
+ sourceRows
4927
+ );
4928
+ let copiedRows = copyTreeData(sourceRows, {
4929
+ ...treeContext,
4930
+ temporaryKeyRegistry: new Set(
4931
+ treeContext.temporaryKeyRegistry
4932
+ ),
4933
+ targetRows: [],
4934
+ });
4935
+ let fields = treeContext.fields;
4936
+ let ignoredFields = new Set([
4937
+ fields.rowField,
4938
+ fields.parentField,
4939
+ fields.childrenField,
4940
+ fields.mapChildrenField,
4941
+ fields.hasChildField,
4942
+ treeContext.identityConfig.physicalIdField,
4943
+ "_X_ROW_KEY",
4944
+ "_X_ROW_CHILD",
4945
+ "_X_TREE_TEMP_KEY",
4946
+ "f_wbs",
4947
+ ]);
4948
+
4949
+ copiedRows.forEach((row) => {
4950
+ this.handleCopyDefaultData(row);
4951
+ Object.keys(row).forEach((key) => {
4952
+ if (ignoredFields.has(key) || !Array.isArray(row[key])) return;
4953
+ this.handleCopyData(row[key], key);
4954
+ });
4955
+ });
4956
+
4957
+ value.splice(0, value.length, ...copiedRows);
4958
+ },
4959
+ handleCopyDefaultData(data) {
4852
4960
  data.create_by = null;
4853
4961
  data._create_by = null;
4854
4962
  data.create_date = null;
@@ -4903,14 +5011,22 @@ modules = {
4903
5011
  });
4904
5012
  }
4905
5013
  },
4906
- openCopyEditTab(copyData) {
4907
- let formData = this.$baseLodash.cloneDeep(copyData || this.formDataModel);
4908
- if (formData) {
4909
- this.handleCopyData(formData);
4910
- }
4911
-
4912
- this.$emit("openCopyEditTab", formData);
4913
- },
5014
+ async openCopyEditTab(copyData) {
5015
+ try {
5016
+ await this.prepareTreeTablesForCopy();
5017
+ let formData = this.$baseLodash.cloneDeep(
5018
+ copyData || this.formDataModel
5019
+ );
5020
+ if (formData) {
5021
+ this.handleCopyData(formData);
5022
+ }
5023
+ this.$emit("openCopyEditTab", formData);
5024
+ return true;
5025
+ } catch (error) {
5026
+ this.$message.error(error?.message || "树表数据尚未准备完成");
5027
+ return false;
5028
+ }
5029
+ },
4914
5030
 
4915
5031
  async exportPdf() {
4916
5032
  // statusEl.style.display = 'block';