cloud-web-corejs 1.1.0-dev.11 → 1.1.0-dev.13

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 (48) hide show
  1. package/package.json +1 -1
  2. package/src/components/VabUpload/view.vue +25 -25
  3. package/src/components/excelExport/exportColumnMemory.js +118 -0
  4. package/src/components/excelExport/exportFieldDialog.vue +50 -38
  5. package/src/components/excelExport/index.js +30 -13
  6. package/src/components/excelExport/mixins.js +390 -64
  7. package/src/components/excelImport/mixins.js +898 -850
  8. package/src/components/mobile/wf/addTaskUserdialog.vue +100 -100
  9. package/src/components/mobile/wf/content.vue +4 -4
  10. package/src/components/mobile/wf/deleteTaskUserDialog.vue +73 -73
  11. package/src/components/mobile/wf/setCandidateDialog.vue +69 -69
  12. package/src/components/mobile/wf/urgingDialog.vue +75 -75
  13. package/src/components/table/index.js +14 -1
  14. package/src/components/table/vxeFilter/mixin.js +28 -18
  15. package/src/components/xform/docs/2026-07 table/344/270/216excelExport/344/277/256/345/244/215/345/217/212/345/257/274/345/207/272/344/274/230/345/214/226.md" +64 -57
  16. package/src/components/xform/docs/2026-08 xform H5 P0 /345/256/236/347/216/260/350/247/204/346/240/274.md" +528 -0
  17. package/src/components/xform/docs/2026-08 xform H5 P1 /345/256/236/347/216/260/350/247/204/346/240/274.md" +412 -0
  18. package/src/components/xform/docs/2026-08 xform H5 P2 /345/256/236/347/216/260/350/247/204/346/240/274.md" +287 -0
  19. package/src/components/xform/docs/2026-08 xform /347/247/273/345/212/250/347/253/257/345/270/203/345/261/200/345/257/271/351/275/220 bill_setting /346/226/271/346/241/210.md" +400 -0
  20. package/src/components/xform/docs/2026-09 /346/235/241/344/273/266/345/257/274/345/207/272/345/244/247/346/225/260/346/215/256/351/207/217/345/264/251/346/272/203/346/216/222/346/237/245.md" +389 -0
  21. package/src/components/xform/form-designer/form-widget/container-widget/detail-h5-widget.vue +243 -243
  22. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-pane-widget.vue +228 -228
  23. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-widget.vue +165 -165
  24. package/src/components/xform/form-designer/form-widget/dialog/importDialogMixin.js +61 -2
  25. package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +3 -0
  26. package/src/components/xform/form-designer/form-widget/field-widget/singleUpload-widget.vue +145 -145
  27. package/src/components/xform/form-render/container-item/data-table-item.vue +350 -347
  28. package/src/components/xform/form-render/container-item/data-table-mixin.js +240 -37
  29. package/src/components/xform/form-render/container-item/list-h5-item.vue +1 -1
  30. package/src/components/xform/utils/dynamicSchemaUtil.js +385 -361
  31. package/src/layout/components/TagsView/index.vue +325 -323
  32. package/src/store/modules/tagsView.js +241 -217
  33. package/src/utils/importLimit.js +72 -0
  34. package/src/utils/pdfUtil.js +6 -1
  35. package/src/utils/request.js +17 -0
  36. package/src/views/demo/bizTab/bill/billConfig.js +41 -0
  37. package/src/views/demo/bizTab/bill/detail.vue +436 -0
  38. package/src/views/demo/bizTab/bill/list.vue +288 -0
  39. package/src/views/demo/bizTab/bill/productDialog.vue +176 -0
  40. package/src/views/demo/bizTab/simple/billApi.js +123 -0
  41. package/src/views/demo/bizTab/simple/detail.vue +407 -0
  42. package/src/views/demo/bizTab/simple/list.vue +217 -0
  43. package/src/views/demo/bizTab/standalone/index.vue +121 -0
  44. package/src/views/demo/bizTab/wf/billConfig.js +44 -0
  45. package/src/views/demo/bizTab/wf/detail.vue +661 -0
  46. package/src/views/demo/bizTab/wf/list.vue +242 -0
  47. package/src/views/user/home/wjl/content.vue +1569 -0
  48. package/src/views/user/outLink/cc_form_view.vue +188 -0
@@ -1,3 +1,4 @@
1
+ import Vue from "vue";
1
2
  import emitter from "../../../../components/xform/utils/emitter";
2
3
  import i18n from "../../../../components/xform/utils/i18n";
3
4
  import refMixin from "../../../../components/xform/form-render/refMixin";
@@ -47,6 +48,7 @@ import {
47
48
  getDynamicSchemaOption,
48
49
  isActionColumnFormat,
49
50
  isNonDataExportColumn,
51
+ isBlankExportColumn,
50
52
  normalizeDynamicColumns as normalizeDynamicColumnList,
51
53
  resolveDynamicSchemaResponse,
52
54
  } from "../../utils/dynamicSchemaUtil";
@@ -72,6 +74,22 @@ import {
72
74
  } from "../../utils/treeTableUtil";
73
75
  import { tableTreeMixins } from "../../../../mixins/tableTree/index.js";
74
76
 
77
+ /**
78
+ * 列一直建不出来时,行级 schema 重建的最大重试次数(每次隔一帧)。
79
+ * 见 initFieldSchemaData:那里的 $nextTick 自递归原本没有上限。
80
+ */
81
+ const MAX_SCHEMA_INIT_RETRY = 50;
82
+
83
+ /**
84
+ * 超过多少行就不再预建全量行级 schema,改由 getRowFieldSchema 按需建。
85
+ * 预建是按「行数 × 组件列数」做 deepClone(createRowFieldSchemaMap),万行量级是
86
+ * GB 级内存 —— 与条件导出那次标签页崩溃是同一个根因,只是这里常驻 fieldSchemaMap。
87
+ * 触发口:表单导入一次灌入大批行、树表全量加载(BOM)。
88
+ * 阈值取 1000:列表分页最大档是 500,普通分页列表永远不会进懒建模式,行为零变化。
89
+ * 可由 widget.options.lazyRowSchemaThreshold 覆盖。
90
+ */
91
+ const LAZY_ROW_SCHEMA_THRESHOLD = 1000;
92
+
75
93
  let modules = {};
76
94
  const baseRefUtil = {
77
95
  emitter,
@@ -300,6 +318,74 @@ modules = {
300
318
  }
301
319
  return widget.options.labelKey || "label";
302
320
  },
321
+ /** @returns {Number} 超过多少行改走行级 schema 懒建。 */
322
+ getLazyRowSchemaThreshold() {
323
+ let value = Number(this.widget?.options?.lazyRowSchemaThreshold);
324
+ if (isFinite(value) && value > 0) return value;
325
+ return LAZY_ROW_SCHEMA_THRESHOLD;
326
+ },
327
+ /**
328
+ * 行级 schema 的统一读取口:预建模式下就是 fieldSchemaMap 里的那份,懒建模式下
329
+ * (行数超阈值,见 LAZY_ROW_SCHEMA_THRESHOLD)按需创建,只有真正渲染/校验到的行
330
+ * 才付克隆代价 —— vxe 虚拟滚动下这远小于全量。
331
+ *
332
+ * 懒建刻意**不用 $set**:本方法会在渲染期被模板调用(#widget / #widgetList /
333
+ * #editWidget 都要读行级 schema),给被 render 依赖的 fieldSchemaMap 新增响应式
334
+ * 属性会当场触发重渲染,形成 "infinite update loop"。改为 Vue.observable 让 schema
335
+ * 对象自身保持响应(行内脚本 setDisabled / setOptionItems 仍能刷新视图),再普通
336
+ * 赋值挂进 map;同一行同一次渲染内多次读取拿到的是同一个对象,不会对不上。
337
+ * @param {Object} row 行数据。
338
+ * @returns {Object|null}
339
+ */
340
+ getRowFieldSchema(row) {
341
+ let rowKey = row && row._X_ROW_KEY;
342
+ if (!rowKey) return null;
343
+ // 导出行有自己的惰性克隆通道(getExportRowWidget),不进 fieldSchemaMap
344
+ if (row._X_EXPORT_ROW) return null;
345
+ let rowSchema = this.fieldSchemaMap[rowKey];
346
+ if (rowSchema) return rowSchema;
347
+ if (!this.getTableFullColumns().length) return null;
348
+ rowSchema = Vue.observable(this.createRowFieldSchemaMap());
349
+ this.fieldSchemaMap[rowKey] = rowSchema;
350
+ return rowSchema;
351
+ },
352
+ /**
353
+ * 导出行的行级组件 schema:按需惰性克隆,缓存挂在行对象上、随行一起丢弃。
354
+ *
355
+ * 导出行不进 fieldSchemaMap(见 initExportRows),但**不能**直接把列模板交出去:
356
+ * 仍会逐单元格挂载的那几类列(widgetRender 自定义组件列、Image2 但本次没开
357
+ * showImageAtTable 的附件列)在挂载时会跑用户脚本,而 setDisabled / setHidden /
358
+ * setOptionItems 这些 API 是直接写 field.options 的 —— 交出模板就等于让脚本改到
359
+ * 列模板本身,而 createRowFieldSchemaMap 又是从该模板克隆各行 schema,污染会一直
360
+ * 留到重新加载表单配置为止。
361
+ *
362
+ * 必须**记忆化**:`#widget` 插槽一个单元格里会多次调用取值(v-if / :field / :key /
363
+ * 字段名),每次返回新对象会让这几处互相对不上。
364
+ *
365
+ * 代价只落在真正会挂载的少数列上,不会退回按「行数 × 列数」克隆。
366
+ * @param {Object} row 导出行。
367
+ * @param {Object} widget 列模板组件 schema。
368
+ * @returns {Object|null}
369
+ */
370
+ getExportRowWidget(row, widget) {
371
+ if (!widget || !widget.id) return widget || null;
372
+ let cache = row.__X_EXPORT_WIDGETS;
373
+ if (!cache) {
374
+ cache = {};
375
+ // 不可枚举:避免混进行数据被序列化或遍历到
376
+ Object.defineProperty(row, "__X_EXPORT_WIDGETS", {
377
+ value: cache,
378
+ enumerable: false,
379
+ configurable: true,
380
+ writable: true,
381
+ });
382
+ }
383
+ // 用原模板 id 做键:克隆体自己的 id 是新生成的,不能拿来查
384
+ if (!cache[widget.id]) {
385
+ cache[widget.id] = this.cloneFieldSchema(widget);
386
+ }
387
+ return cache[widget.id];
388
+ },
303
389
  /**
304
390
  * 获取当前行独立的列组件 schema;缺失时按列模板即时创建。
305
391
  * @param {Object} obj VXE 单元格参数。
@@ -311,11 +397,17 @@ modules = {
311
397
  if (!rowKey || !widget?.id) {
312
398
  return null;
313
399
  }
314
- let rowSchema = this.fieldSchemaMap[rowKey];
315
- if (!rowSchema) {
316
- rowSchema = this.createRowFieldSchemaMap();
317
- this.$set(this.fieldSchemaMap, rowKey, rowSchema);
318
- } else if (!rowSchema[widget.id]) {
400
+ // 导出行不进 fieldSchemaMap(见 initExportRows)。这里必须短路:取值兜底渲染会
401
+ // 走到本方法,缺 schema 时下面那段会按行懒建一整套再 $set 进 fieldSchemaMap,把
402
+ // initExportRows 省下的开销原样加回来,且因为走 $set 还会被深度观测,比原来更贵。
403
+ // 但也不能直接交出列模板——挂载时跑的用户脚本会写进 field.options,
404
+ // 详见 getExportRowWidget。
405
+ if (obj.row._X_EXPORT_ROW) {
406
+ return this.getExportRowWidget(obj.row, widget);
407
+ }
408
+ let rowSchema = this.getRowFieldSchema(obj.row);
409
+ if (!rowSchema) return null;
410
+ if (!rowSchema[widget.id]) {
319
411
  this.$set(rowSchema, widget.id, this.cloneFieldSchema(widget));
320
412
  }
321
413
  return rowSchema[widget.id] || null;
@@ -595,7 +687,14 @@ modules = {
595
687
  let row = rowParam.row;
596
688
  let params = rowParam.column.params;
597
689
  let widgetId = fieldWidget ? fieldWidget.id : params.widget.id;
598
- let widget = this.fieldSchemaMap[row._X_ROW_KEY][widgetId];
690
+ // 导出行不进 fieldSchemaMap,不短路会在 fieldSchemaMap[undefined] 上取值直接崩。
691
+ // 同样走惰性克隆而不是直接交模板,理由见 getExportRowWidget。
692
+ if (row._X_EXPORT_ROW) {
693
+ return this.getExportRowWidget(row, fieldWidget || params.widget);
694
+ }
695
+ // 懒建模式下这一行可能还没建过 schema,直接下标取值会 TypeError
696
+ let rowSchema = this.getRowFieldSchema(row);
697
+ let widget = rowSchema ? rowSchema[widgetId] : null;
599
698
  return widget;
600
699
  },
601
700
  /** @param {String} name 组件名。@param {Function} callback 每行回调。 */
@@ -919,7 +1018,7 @@ modules = {
919
1018
  if (!row || !templateWidget) {
920
1019
  return templateWidget;
921
1020
  }
922
- const schema = this.fieldSchemaMap[row._X_ROW_KEY];
1021
+ const schema = this.getRowFieldSchema(row);
923
1022
  if (schema && schema[templateWidget.id]) {
924
1023
  return schema[templateWidget.id];
925
1024
  }
@@ -1762,6 +1861,11 @@ modules = {
1762
1861
  t.type || t.widget?.type,
1763
1862
  t.widget?.options || t.options
1764
1863
  ),
1864
+ exportBlank: isBlankExportColumn(
1865
+ t.formatS,
1866
+ t.type || t.widget?.type,
1867
+ t.exportType
1868
+ ),
1765
1869
  },
1766
1870
  visible: this.getColumnVisible(t),
1767
1871
  slots: {},
@@ -1849,6 +1953,12 @@ modules = {
1849
1953
  "textarea",
1850
1954
  "a-link",
1851
1955
  "a-text",
1956
+ // 脚本输入框:展示值就是 fieldModel,不做任何转换,走纯函数完全等价。
1957
+ // 不走这里会落到 getCellValue 的 vNode 挂载兜底,而它内部是**异步组件**
1958
+ // code-editor —— 同步挂载后立刻爬 DOM 根本读不到内容(异步组件那一刻还没
1959
+ // 解析完),所以这类列此前导出为空;顺带每个单元格挂一个代码编辑器,是所有
1960
+ // 类型里最贵的一种。
1961
+ "script-input",
1852
1962
  ];
1853
1963
  if (widget && types.includes(widget.type)) {
1854
1964
  const func = (obj) => {
@@ -1867,9 +1977,14 @@ modules = {
1867
1977
  if (fieldWidget && !fieldWidget.options.hidden) {
1868
1978
  let widgetType = fieldWidget.type;
1869
1979
  if (
1870
- ["input", "number", "textarea", "a-link", "a-text"].includes(
1871
- widgetType
1872
- )
1980
+ [
1981
+ "input",
1982
+ "number",
1983
+ "textarea",
1984
+ "a-link",
1985
+ "a-text",
1986
+ "script-input",
1987
+ ].includes(widgetType)
1873
1988
  ) {
1874
1989
  return value;
1875
1990
  }
@@ -2526,6 +2641,9 @@ modules = {
2526
2641
  let customParam = {
2527
2642
  config: {
2528
2643
  modal: false,
2644
+ // 导出取消时要能掐断在途取数请求。令牌由 excelExport 生成后随导出参数
2645
+ // 带过来,这里塞进 config,formHttp 的 ...opts 会透传给 axios。
2646
+ cancelToken: options?.cancelToken,
2529
2647
  },
2530
2648
  export: true,
2531
2649
  exportParam: options,
@@ -2642,8 +2760,8 @@ modules = {
2642
2760
  : [];
2643
2761
  // that.handleNullValue(rows);
2644
2762
  if (customParam?.export) {
2645
- //导出
2646
- this.initExportFieldSchemaData(rows);
2763
+ //导出:只补行主键+标记,不建行级 schema(大数据量会 OOM)
2764
+ this.initExportRows(rows);
2647
2765
  } else {
2648
2766
  // VXE 与表单必须共用同一批标准化行,否则 _X_ROW_KEY 不一致,
2649
2767
  // 行虽能进入编辑态,但 editWidget 无法取得对应的行级 schema。
@@ -2656,7 +2774,7 @@ modules = {
2656
2774
  }
2657
2775
 
2658
2776
  resolve(res);
2659
- if (res.type === "success") {
2777
+ if (that.shouldEmitQueryLoaded(res, customParam)) {
2660
2778
  if (that.widget.options.isTreeTable) {
2661
2779
  if (rows.length > 0) {
2662
2780
  let fullAllDataRowMap =
@@ -2722,18 +2840,7 @@ modules = {
2722
2840
  }
2723
2841
  }
2724
2842
  }
2725
- that.$nextTick(() => {
2726
- setTimeout(function () {
2727
- dataTableConfig.callback &&
2728
- dataTableConfig.callback(rows);
2729
- tableOption.callback && tableOption.callback(rows);
2730
- that.handleCustomEvent(
2731
- that.widget.options.formScriptCallback,
2732
- ["rows"],
2733
- [rows]
2734
- );
2735
- }, 0);
2736
- });
2843
+ that.emitTableDataLoaded(rows, tableOption);
2737
2844
  }
2738
2845
  };
2739
2846
  this.loadDefaultQueryList(reqData, done, customParam);
@@ -3141,6 +3248,53 @@ modules = {
3141
3248
  let scriptCode = this.widget.options.formScriptCode || defaultScriptCode;
3142
3249
  return scriptCode;
3143
3250
  },
3251
+ /**
3252
+ * 本次取数要不要跑「屏幕上那张表格」的成功副作用(树表展开、宿主回调、
3253
+ * tableOption.callback 回写表单模型、formScriptCallback)。
3254
+ *
3255
+ * 导出取数复用的是普通查询这条 proxyConfig.ajax.query,此前只在「建不建行级
3256
+ * schema」那一处分了叉,成功副作用整段照跑,而它们对导出**零意义**:数据在
3257
+ * `resolve(res)` 时就已经交给 excelExport 了,回调还都排在 $nextTick +
3258
+ * setTimeout 之后,改什么也影响不到导出内容。跑了反而有害:
3259
+ * 1. `formScriptCallback`(用户配的「数据加载完成」脚本)会按导出页数被连着触发
3260
+ * N 次,`rows` 是屏幕上根本看不见的数据;脚本里发的请求还会跟导出取数抢连接;
3261
+ * 2. `tableOption.callback` 是 `formModel[fieldKeyName] = rows`,会把表单模型覆盖
3262
+ * 成导出的最后一页 —— 导出之后 `getValue()` 返回的不再是当前页,且页面上看不
3263
+ * 出任何异常,直到下次查询才被冲掉;
3264
+ * 3. 树表分支会对没进表格的导出行 `setTreeExpand`、去 `fullAllDataRowMap` 里查它们,
3265
+ * 中途还反复开关 `$grid.treeConfig.lazy`,并发几页时互相打架。
3266
+ *
3267
+ * `customParam.export` 由 exportAjax 统一置位,覆盖条件导出与明细的选择/条件导出
3268
+ * 三条会发请求的通道(勾选导出/当前页导出不走这里)。
3269
+ * @param {Object} res 取数响应。
3270
+ * @param {Object} [customParam] 调用方附加参数。
3271
+ * @returns {Boolean}
3272
+ */
3273
+ shouldEmitQueryLoaded(res, customParam) {
3274
+ if (res?.type !== "success") return false;
3275
+ return !customParam?.export;
3276
+ },
3277
+ /**
3278
+ * 派发「表格数据加载完成」的三个回调:宿主注入的 callback、tableOption.callback
3279
+ * (回写表单模型),以及用户配的 formScriptCallback。
3280
+ * 是否该派发由 shouldEmitQueryLoaded 判定,这里只负责发。
3281
+ * @param {Array} rows 本次加载的行。
3282
+ * @param {Object} tableOption 表格配置(callback 挂在它上面)。
3283
+ */
3284
+ emitTableDataLoaded(rows, tableOption) {
3285
+ this.$nextTick(() => {
3286
+ setTimeout(() => {
3287
+ let dataTableConfig = this.dataTableConfig || {};
3288
+ dataTableConfig.callback && dataTableConfig.callback(rows);
3289
+ tableOption && tableOption.callback && tableOption.callback(rows);
3290
+ this.handleCustomEvent(
3291
+ this.widget.options.formScriptCallback,
3292
+ ["rows"],
3293
+ [rows]
3294
+ );
3295
+ }, 0);
3296
+ });
3297
+ },
3144
3298
  /**
3145
3299
  * 执行默认列表查询。
3146
3300
  * @param {Object} reqData 查询请求数据。
@@ -3379,6 +3533,8 @@ modules = {
3379
3533
  * 可以挂多个明细导出按钮、各导各自的列、各走各自的脚本),组装成 exportItemConfig 随
3380
3534
  * 导出参数下发,下游(字段选择弹框 / 分页取数 / 脱敏剔除)一律优先读它,读不到才回落
3381
3535
  * 表格属性那套。
3536
+ * option.exportButtonName 为导出按钮标识,原样透传给字段选择弹框,用于按按钮分组存放
3537
+ * 勾选记忆(见 excelExport/exportColumnMemory.js)。
3382
3538
  */
3383
3539
  exportData(option) {
3384
3540
  let exportOption = { ...option };
@@ -3612,11 +3768,13 @@ modules = {
3612
3768
  const fieldsToValidate = [];
3613
3769
  let tableColumns = this.widget.options.tableColumns;
3614
3770
  checkRows.forEach((row) => {
3615
- let fieldSchema = this.fieldSchemaMap[row._X_ROW_KEY];
3771
+ let fieldSchema = this.getRowFieldSchema(row) || {};
3616
3772
  tableColumns.forEach((column) => {
3617
3773
  if (column.widget) {
3774
+ // 列未就绪时 getRowFieldSchema 会给 null,取不到行级组件就按"不必填"跳过,
3775
+ // 而不是在这里抛异常把整个校验打断
3618
3776
  let widget = fieldSchema[column.widget.id];
3619
- let required = widget.options.required || false;
3777
+ let required = widget?.options?.required || false;
3620
3778
  if (required) {
3621
3779
  let propName = this.getColumnWidgetProp(widget, row);
3622
3780
  fieldsToValidate.push(propName);
@@ -3625,7 +3783,7 @@ modules = {
3625
3783
  if (column.widgetList) {
3626
3784
  column.widgetList.forEach((itemWidget) => {
3627
3785
  let widget = fieldSchema[itemWidget.id];
3628
- let required = widget.options.required || false;
3786
+ let required = widget?.options?.required || false;
3629
3787
  if (required) {
3630
3788
  let propName = this.getColumnWidgetProp(widget, row);
3631
3789
  fieldsToValidate.push(propName);
@@ -3666,9 +3824,9 @@ modules = {
3666
3824
  let sourceWidgetId = isEdit
3667
3825
  ? obj.column?.params?.editWidget?.id
3668
3826
  : obj.column?.params?.widget?.id;
3669
- if (!sourceWidgetId || !this.fieldSchemaMap[obj.row._X_ROW_KEY])
3670
- return "false";
3671
- let fieldWidget = this.fieldSchemaMap[obj.row._X_ROW_KEY][sourceWidgetId];
3827
+ let rowSchema = this.getRowFieldSchema(obj.row);
3828
+ if (!sourceWidgetId || !rowSchema) return "false";
3829
+ let fieldWidget = rowSchema[sourceWidgetId];
3672
3830
  if (!fieldWidget) {
3673
3831
  return "false";
3674
3832
  }
@@ -5690,8 +5848,9 @@ modules = {
5690
5848
  /**
5691
5849
  * 为每一行创建独立字段 schema,避免组件状态在不同行之间共享。
5692
5850
  * @param {Boolean} initFlag true 时忽略旧 schema 并全部重新创建。
5851
+ * @param {Number} retryCount 列未就绪时已重试的次数,见 MAX_SCHEMA_INIT_RETRY。
5693
5852
  */
5694
- initFieldSchemaData(initFlag) {
5853
+ initFieldSchemaData(initFlag, retryCount = 0) {
5695
5854
  //初始化fieldSchemaData!!!
5696
5855
  /*if (this.widget.type !== 'sub-form') {
5697
5856
  return
@@ -5706,6 +5865,14 @@ modules = {
5706
5865
  if (!this.getTableFullColumns().length) {
5707
5866
  return false;
5708
5867
  }
5868
+ // 大数据量不再预建:按「行数 × 组件列数」深克隆,万行量级直接把标签页撑爆
5869
+ // (与条件导出那次崩溃同源)。交给 getRowFieldSchema 在渲染/校验时按需建。
5870
+ if (rowLength > this.getLazyRowSchemaThreshold()) {
5871
+ // initFlag 表示"整体重建",此时旧 schema 必须丢弃;否则(addRow /
5872
+ // deleteRow)保留已建的那些,避免把行内脚本写进去的状态一起清掉。
5873
+ if (initFlag) this.fieldSchemaMap = {};
5874
+ return true;
5875
+ }
5709
5876
  let fieldSchemaMap = {};
5710
5877
  let fieldSchemaMap0 = this.fieldSchemaMap;
5711
5878
  for (let i = 0; i < rowLength; i++) {
@@ -5714,10 +5881,12 @@ modules = {
5714
5881
  if (initFlag) {
5715
5882
  fieldSchemaMap2 = this.createRowFieldSchemaMap();
5716
5883
  } else {
5717
- let fieldSchemaMap01 = fieldSchemaMap0[rowId];
5718
- fieldSchemaMap2 = fieldSchemaMap01
5719
- ? this.$baseLodash.cloneDeep(fieldSchemaMap01)
5720
- : this.createRowFieldSchemaMap();
5884
+ // 沿用旧行的 schema 对象本身,不再 cloneDeep:该对象本来就是这一行
5885
+ // 独享的(按 rowId 分桶),克隆只会产出语义完全相同的另一份,白占一份
5886
+ // 内存。而本分支的调用方是 addRow / deleteRow —— 每增删一行都把全表深
5887
+ // 克隆一遍是 O(),千行树表上每次增删都要停顿数秒并制造等量垃圾。
5888
+ fieldSchemaMap2
5889
+ = fieldSchemaMap0[rowId] || this.createRowFieldSchemaMap();
5721
5890
  }
5722
5891
  fieldSchemaMap[rowId] = fieldSchemaMap2;
5723
5892
  }
@@ -5725,9 +5894,19 @@ modules = {
5725
5894
  return true;
5726
5895
  };
5727
5896
  if (!build()) {
5897
+ // 列未就绪时隔一帧重试。必须有上限:动态列请求失败 / 列配置为空时列永远不会
5898
+ // 出现,而 rowIdData 非空,这条 $nextTick 自递归就成了每帧一次的死循环,
5899
+ // 页面永久卡死(setValue 侧另有 pendingSchemaInit 挡了一条入口,但
5900
+ // initValue / addRow / deleteRow / 动态列重载都能直接进到这里)。
5901
+ if (retryCount >= MAX_SCHEMA_INIT_RETRY) {
5902
+ console.warn(
5903
+ "[data-table] 表格列始终未就绪,已停止行级 schema 重建重试"
5904
+ );
5905
+ return;
5906
+ }
5728
5907
  this.$nextTick(() => {
5729
5908
  if (this.rowIdData.length) {
5730
- this.initFieldSchemaData(initFlag);
5909
+ this.initFieldSchemaData(initFlag, retryCount + 1);
5731
5910
  }
5732
5911
  });
5733
5912
  }
@@ -5824,6 +6003,30 @@ modules = {
5824
6003
  return newFieldSchema;
5825
6004
  },
5826
6005
  //end1
6006
+ /**
6007
+ * 导出取数的行初始化:只补行主键并打导出标记,**不建行级 schema**。
6008
+ *
6009
+ * 行级 schema 的意义是让同一列的组件在不同行之间互不干扰(行内脚本改 options、
6010
+ * 编辑态等)。导出行既不进 vxe 表格也不会被编辑,createRowFieldSchemaMap 产出的
6011
+ * 只是列模板的等价深克隆(仅 id 不同)—— 异步选项同步写的是列模板本身
6012
+ * (collectColumnWidgetConfigRequests),行内脚本改的是已挂载的组件实例,都不会让
6013
+ * 导出行的 schema 与列模板产生差异。
6014
+ *
6015
+ * 但代价是按「行数 × 组件列数」做 deepClone 并常驻 fieldSchemaMap,而该 map 在导出
6016
+ * 期间没有任何释放路径(只有删行、或下次正常查询走 initFieldSchemaData 整体重建才清),
6017
+ * 10 万行量级直接把标签页撑爆。取值侧对缺失行级 schema 本就有回退列模板的分支
6018
+ * (列 filterVal、getTableColumnWidget、getRowWidget),故跳过构建不改变导出内容。
6019
+ *
6020
+ * 注意:树表懒加载走的仍是 initExportFieldSchemaData —— 那批行是要进表格的真实行。
6021
+ * @param {Array} rows 导出取回的当页数据。
6022
+ */
6023
+ initExportRows(rows) {
6024
+ if (!rows) return;
6025
+ for (let row of rows) {
6026
+ if (!row._X_ROW_KEY) row._X_ROW_KEY = "row_" + generateId();
6027
+ row._X_EXPORT_ROW = true;
6028
+ }
6029
+ },
5827
6030
  /** @param {Array} rows 导出数据。为无行主键的数据创建临时 schema。 */
5828
6031
  initExportFieldSchemaData(rows) {
5829
6032
  if (!rows) return;
@@ -481,7 +481,7 @@
481
481
  width="100%"
482
482
  top="0px"
483
483
  v-el-drag-dialog
484
- v-el-dialog-center
484
+ v-el-dialog-center
485
485
  :append-to-body ="true"
486
486
  :destroy-on-close="true"
487
487
  >