cloud-web-corejs 1.0.281 → 1.0.283

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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/components/excelExport/exportColumnMemory.js +118 -0
  3. package/src/components/excelExport/exportFieldDialog.vue +63 -40
  4. package/src/components/excelExport/exportItemConfigUtil.js +30 -0
  5. package/src/components/excelExport/index.js +30 -13
  6. package/src/components/excelExport/mixins.js +406 -68
  7. package/src/components/excelImport/index.vue +1 -1
  8. package/src/components/excelImport/mixins.js +56 -8
  9. package/src/components/table/index.js +14 -1
  10. package/src/components/table/vxeFilter/mixin.js +28 -18
  11. 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" +11 -4
  12. 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
  13. package/src/components/xform/docs/2026-09 /347/274/226/350/276/221/350/241/250/350/241/214/345/206/205/344/277/235/345/255/230/346/240/241/351/252/214/350/214/203/345/233/264/344/270/216/345/210/227/345/277/205/345/241/253/350/247/243/346/236/220/344/277/256/345/244/215.md" +233 -0
  14. package/src/components/xform/form-designer/form-widget/dialog/importDialogMixin.js +61 -2
  15. package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +9 -0
  16. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/exportItemColumns-dialog.vue +7 -1
  17. package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +51 -0
  18. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +4 -0
  19. package/src/components/xform/form-render/container-item/data-table-item.vue +7 -4
  20. package/src/components/xform/form-render/container-item/data-table-mixin.js +465 -128
  21. package/src/components/xform/utils/dynamicSchemaUtil.js +24 -0
  22. package/src/components/xform/utils/tableColumnHelper.js +46 -4
  23. package/src/components/xform/utils/textMaskUtil.js +6 -3
  24. package/src/layout/components/TagsView/index.vue +4 -2
  25. package/src/store/modules/tagsView.js +27 -3
  26. package/src/utils/assetUrl.js +19 -0
  27. package/src/utils/importLimit.js +72 -0
  28. package/src/utils/pdfUtil.js +6 -1
  29. package/src/utils/request.js +17 -0
  30. package/src/utils/vab.js +5 -1
@@ -0,0 +1,233 @@
1
+ # 编辑表行内保存的校验范围 & 列必填解析 —— 修复文档(2026-09-03)
2
+
3
+ > 状态:**两项均已编码 + 单测过,待联调**。
4
+ > 改动文件:`src/components/xform/form-render/container-item/data-table-mixin.js`、
5
+ > `src/components/xform/utils/tableColumnHelper.js`。
6
+ > 新增单测:`tests/unit/components/xform/editRowValidateScope.spec.js`(6 条)、
7
+ > `tests/unit/components/xform/columnRequiredFlag.spec.js`(7 条)。
8
+ > 行号均为 2026-09-03 工作区快照,后续会漂移,以函数名为准。
9
+ > 同步:dev 与 stdxx 两分支均**未搬**。
10
+
11
+ ---
12
+
13
+ ## 一、两个问题
14
+
15
+ | # | 现象 | 根因一句话 |
16
+ |---|------|-----------|
17
+ | A | 编辑(树)表点行内保存 ✓,别的行缺必填、甚至表格外的字段没填,都会把这一行的保存拦住 | `saveEditRow` 走的是整表 + 全表单的 `formRef.validate` |
18
+ | B | 某列 `required` 与 `editWidget.options.required` 都是 `false`,运行起来却必填(表头星号 + 拦保存) | 列在设计器里配过展示组件后又改回空,残留的 `columnOption.required` 仍被 `resolveColumnRequiredFlag` 无条件读取 |
19
+
20
+ 两者独立,但都落在"必填校验"这条线上,一起记。
21
+
22
+ ---
23
+
24
+ ## 二、问题 A:行内保存跑了全表校验
25
+
26
+ ### 2.1 原链路
27
+
28
+ ```
29
+ data-table-item.vue #editTreeButtonGroup 插槽的「保存」a-link
30
+ → saveEditRow(obj) [data-table-mixin.js:4469]
31
+ → formRef.validate(resolve) ← 整表 + 表外字段
32
+ → el-form.$baseValidate 原生规则(只覆盖已渲染的 form-item)
33
+ → runExtraFormValidations() [indexMixin.js:3862]
34
+ ├─ validateArrayValueFieldsRequired() 全表单数组类值字段
35
+ ├─ validateDataTableCellsRequired() **每个数据表格逐行**必填
36
+ └─ validateDataTableDatasetRequired() 数据表整体必填
37
+ → $baseConfirm → clearActived/setActiveRow → formHttp(只发当前行)
38
+ ```
39
+
40
+ 保存粒度是**行**(`requestRow = obj.row`,报文里只有这一行),校验粒度却是**整表单**。
41
+
42
+ ### 2.2 改动
43
+
44
+ `validateCellsRequired` 抽出核心循环,让"校验哪些行"与"prop 里的行下标"分离:
45
+
46
+ ```js
47
+ // data-table-mixin.js:1045
48
+ validateCellsRequired() {
49
+ ...
50
+ return this.runCellsRequiredCheck(rows, rows); // 整体保存:全表逐行
51
+ },
52
+ // data-table-mixin.js:1063
53
+ runCellsRequiredCheck(targetRows, indexRows) { ... }
54
+ ```
55
+
56
+ - `targetRows` —— 本次要校验的行;
57
+ - `indexRows` —— 求行下标用的**完整数据集**。
58
+ 单行校验时**必须**传全量数据集,否则 `getValidationRowIndex` 拿到的是 0,
59
+ 拼出来的 `items.0.f_code` 会定位到错误的行。
60
+
61
+ 新增三个方法:
62
+
63
+ | 方法 | 位置 | 职责 |
64
+ |------|------|------|
65
+ | `validateEditRowRequired(row)` | `data-table-mixin.js:1130` | 只对该行跑必填(内部 `runCellsRequiredCheck([row], 全量)`) |
66
+ | `collectRowValidateProps(row)` | `data-table-mixin.js:1141` | 收该行的单元格 prop,按真实行下标拼,并**按 `renderForm.fields` 过滤掉未注册的** |
67
+ | `validateEditRow(row)` | `data-table-mixin.js:1184` | 入口:原生规则 → 必填兜底,任一失败弹消息返回 false |
68
+
69
+ `saveEditRow` 的第一步随之改为:
70
+
71
+ ```js
72
+ // 行内保存只提交当前行,校验范围同步收敛到当前行:其他行与表外字段
73
+ // 的必填不该拦住单行保存(整体保存仍走 formRef.validate 的全量校验)
74
+ if (!this.validateEditRow(obj.row)) return false;
75
+ ```
76
+
77
+ ### 2.3 行为对照
78
+
79
+ | 通道 | 原生规则(正则 / 自定义 validator) | 必填 |
80
+ |------|--------------------------------|------|
81
+ | 整体保存(`formRef.validate`) | 全表单已渲染的 form-item | 全表逐行 + 数据集必填 + 数组类字段 |
82
+ | 行内保存(`validateEditRow`) | **仅当前行**已注册的 prop | **仅当前行** |
83
+
84
+ ### 2.4 两个坑(已在实现里处理)
85
+
86
+ 1. **prop 必须先按 `renderForm.fields` 过滤**。element 的 `validateField(props, cb)` 在传入的 prop
87
+ 一个都没注册时会打 `[Element Warn] please pass correct props!`。编辑表用的是
88
+ vxe `editConfig: { trigger: "manual", mode: "row" }`,`edit` 插槽只在**正在编辑的那一行**渲染,
89
+ 未编辑行的 prop 本就不在 `fields` 里。
90
+ 2. **`getValidationRows` 读的是 computed `fieldKeyName`**,不是 `getFieldKeyName(this.widget)`。
91
+ 写单测造上下文时必须直给 `fieldKeyName`,否则会掉进 `$grid.getTableData()` 兜底分支。
92
+
93
+ ---
94
+
95
+ ## 三、问题 B:残留 `columnOption` 让列凭空必填
96
+
97
+ ### 3.1 判据
98
+
99
+ 问题列的模板 JSON(节选):
100
+
101
+ | 位置 | 值 |
102
+ |------|-----|
103
+ | 列级 `required` | `false` |
104
+ | `formatS` / `widget` | `""` / `null` ← 展示组件已改回空 |
105
+ | `editFormatS` / `editWidget.options.required` | `"editInput"` / `false` |
106
+ | **`columnOption.required`** | **`true`** ← 残留快照 |
107
+
108
+ ### 3.2 根因:两条读取路径口径不一致
109
+
110
+ | 路径 | 读什么 | 结果 |
111
+ |------|--------|------|
112
+ | 加载时 `applyColumnMetaToFieldWidget`(`util.js:919`,由 `handleTableColumnWidget`(`indexMixin.js:674`)调用) | **只读对应侧**:编辑侧读 `editWidgetOptions ?? editColumnOption` | `editWidget.options.required` = `false` ✅ |
113
+ | 运行时 `resolveColumnRequiredFlag`(`tableColumnHelper.js:90`) | 改动前**两侧都读、且不看 `formatS`**:`widgetOptions ?? columnOption` | `true` ❌ |
114
+
115
+ 该 flag 有**两个出口**,所以现象是"星号 + 拦保存"一起来:
116
+
117
+ - `applyColumnLabelIcon`(`tableColumnHelper.js:126`)→ 表头画 `vxe-cell--required-icon`;
118
+ - `isCellFieldRequired`(`tableCellValidateUtil.js:52`)→ 组件自身 `required` 为 false 时**落到**该 flag → 进必填校验。
119
+
120
+ ### 3.3 改动
121
+
122
+ 新增两个内部函数,给静态列的列级 option 加门控:
123
+
124
+ ```js
125
+ // tableColumnHelper.js:12
126
+ function hasColumnWidgetSide(columnConfig, isEdit) {
127
+ if (isEdit) {
128
+ return !!(columnConfig.editWidget || columnFormatMap[columnConfig.editFormatS]);
129
+ }
130
+ return !!(columnConfig.widget || columnFormatMap[columnConfig.formatS]);
131
+ }
132
+ // tableColumnHelper.js:32
133
+ function getEffectiveColumnOptions(columnConfig, isEdit) { ... }
134
+ ```
135
+
136
+ `resolveColumnRequiredFlag` 的兜底改为:
137
+
138
+ ```js
139
+ const widgetOptions = getEffectiveColumnOptions(columnConfig, false);
140
+ const editWidgetOptions = getEffectiveColumnOptions(columnConfig, true);
141
+ return !!(widgetOptions?.required || editWidgetOptions?.required);
142
+ ```
143
+
144
+ 口径:
145
+
146
+ - **动态列**的 `widgetOptions` / `editWidgetOptions` 直接生效(它们本就没有 `formatS`,不门控);
147
+ - **设计器静态列**的 `columnOption` / `editColumnOption` 只在该侧
148
+ `columnFormatMap[formatS]` 能映射出组件类型(或 widget 已实例化)时才读。
149
+
150
+ **门控判据必须用 `columnFormatMap`,不能用"`formatS` 非空"** —— 纯格式化列(`formatS: "d1"` 这类格式码)
151
+ 同样不建 widget,那份残留 option 也不该作数;用 `columnFormatMap` 才与加载时的实例化口径完全一致。
152
+
153
+ ### 3.4 排除项:展示态不会被误渲染成组件
154
+
155
+ 展示侧组件的实例化在三条路径上都以 `columnFormatMap[formatS]` 为门:
156
+
157
+ | 路径 | 位置 |
158
+ |------|------|
159
+ | 运行态 | `form-render/indexMixin.js:690` |
160
+ | 设计器 | `form-designer/form-widget/container-widget/data-table-mixin.js:220` |
161
+ | H5 列表 | `form-render/container-item/list-h5-item.vue:1692` |
162
+
163
+ `formatS` 为空 → widget 保持 null → `createColumn` 的展示插槽 if 链(`data-table-mixin.js:2158`)
164
+ 一条都不命中 → 单元格走 `formatter: formatterValue` 纯文本。
165
+ `addColumProperty`(`data-table-mixin.js:2011`)展开的 `columnOption` 取自 **widget 实例**的 options,
166
+ 不是 JSON 里那份残留。
167
+
168
+ 所以残留 `columnOption` 在改动前唯一漏出来的地方就是 `resolveColumnRequiredFlag` ——
169
+ 全仓读 `columnOption` 的点里只有它不看 `formatS`。
170
+
171
+ ### 3.5 老数据不做清理
172
+
173
+ 渲染路径对这类残留**只有补齐、没有校验、也没有清理**:`handleTableColumnWidget` 是单向的
174
+ (`formatS` 映射得出组件才建 widget),不会比对"widget 不存在但 columnOption 还在",
175
+ 全仓也没有任何删除 `columnOption` 的写法;设计器侧 `cloneTableColumnsForEdit`
176
+ (`table-column-dialog.vue:1107`)还会在 `!row.widget` 时把它深拷贝带进编辑态再写回模板。
177
+
178
+ 结论:**DB 里的残留不必清** —— 代码侧已经兜住,清理反而要动存量模板。
179
+ 若要早发现,最轻的一档是在 `handleTableColumnWidget` 里对
180
+ "该侧无组件却带着 columnOption"仅开发环境 `console.warn`(未实施)。
181
+
182
+ ---
183
+
184
+ ## 四、改动清单
185
+
186
+ | 文件 | 改动 |
187
+ |------|------|
188
+ | `form-render/container-item/data-table-mixin.js` | `validateCellsRequired` 抽出 `runCellsRequiredCheck(targetRows, indexRows)`;新增 `validateEditRowRequired` / `collectRowValidateProps` / `validateEditRow`;`saveEditRow` 首步由 `formRef.validate` 换成 `validateEditRow(obj.row)` |
189
+ | `utils/tableColumnHelper.js` | 新增 `hasColumnWidgetSide` / `getEffectiveColumnOptions`(并 `import { columnFormatMap } from "./util"`);`resolveColumnRequiredFlag` 兜底改走门控 |
190
+ | `tests/unit/components/xform/editRowValidateScope.spec.js` | 新增,6 条 |
191
+ | `tests/unit/components/xform/columnRequiredFlag.spec.js` | 新增,7 条 |
192
+
193
+ 未改动、行为保持不变:`validateForm` / `validate` / `runExtraFormValidations` 三个整体保存入口,
194
+ `validateCheckRow`(勾选行操作的行级校验),H5 列表的必填口径(只读列级 `t.required`)。
195
+
196
+ ---
197
+
198
+ ## 五、验证
199
+
200
+ - `npx jest tests/unit/components/xform` —— 28 套全过(含两个新增 spec)。
201
+ - `npx jest tests/unit/components` —— 49 套 712 条,711 通过;唯一失败
202
+ `mobile/h5PopDialog.spec.js`(`selectUserDialog.vue` 缺 `custom-class="h5-pop-dialog"`)
203
+ 属 H5 wf 弹层那条线的既有状态,**与本次改动无关**。
204
+ - eslint:`data-table-mixin.js` 无新增报错(51 条 operator-linebreak 均为既有欠账,
205
+ 行号不落在新增段);`tableColumnHelper.js` 由 4 条降至 2 条。
206
+
207
+ 单测覆盖点:
208
+
209
+ | spec | 覆盖 |
210
+ |------|------|
211
+ | editRowValidateScope | 整体保存仍全表拦 / 别的行缺必填不拦当前行 / 当前行自己缺必填仍拦 / prop 带真实行下标且只发当前行 / 未注册 prop 不下发 / 原生错优先于必填兜底 |
212
+ | columnRequiredFlag | 残留 columnOption 不再必填 / 老数据(formatS 有值、widget 未实例化)仍必填 / 纯格式化列不读 / editColumnOption 按 editFormatS 门控 / 动态列不受门控 / 列级与实例 required 照旧 / 空配置 |
213
+
214
+ ---
215
+
216
+ ## 六、影响面与联调点
217
+
218
+ | 变更 | 影响面 | 联调重点 |
219
+ |------|--------|----------|
220
+ | A | 仅编辑树表的 `editTreeButtonGroup` 行内保存 | 当前行必填仍拦、错误能定位到该行;他行/表外字段缺失不再误拦;原生正则规则在当前行仍生效 |
221
+ | B | 全量表格的必填标记(表头星号)与单元格必填校验 | 抽查若干正常配置的必填列,星号与校验都还在;问题列星号消失、不再拦保存 |
222
+
223
+ B 的潜在风险:若有表单**依赖**这份残留 `columnOption.required` 来实现必填(即列级和组件级都没配、
224
+ 全靠残留生效),改后会变成非必填。属于"配置本就不合规"的情况,联调时留意用户反馈的
225
+ "某列突然不必填了",正解是去列配置或组件上把 required 补回。
226
+
227
+ ---
228
+
229
+ ## 七、待办
230
+
231
+ 1. 真机联调(两项均未联调)。
232
+ 2. **同步 dev 与 stdxx 两分支**(按既有同步规则:JS 可整体覆盖、样式不覆盖)。
233
+ 3. 可选:`handleTableColumnWidget` 的 dev-only `console.warn`(残留列级 option 早发现),未实施。
@@ -8,6 +8,14 @@ let XLSX = window.XLSX || { read, utils };
8
8
  import { getToken } from "../../../../../utils/auth";
9
9
  import XEUtils from "xe-utils";
10
10
  import { getErrorMsg } from "@base/utils/index.js";
11
+ import {
12
+ getImportCellText,
13
+ getImportFileSizeLimit,
14
+ getImportRowLimit,
15
+ isImportFileOversize,
16
+ isImportRowsOverLimit,
17
+ toFileSizeMb,
18
+ } from "../../../../../utils/importLimit";
11
19
 
12
20
  let configUtil = {
13
21
  baseUrl: process.env.VUE_APP_BASE_API,
@@ -372,6 +380,25 @@ tmixins = {
372
380
  let that = this;
373
381
  let option = this.option;
374
382
 
383
+ // 业务侧的 importFileLimitSize 允许到 200MB,而这里是整文件 readAsBinaryString +
384
+ // XLSX.read 同步解析,占用约为文件体积的 5~20 倍 —— 那个量级必然把标签页撑爆,
385
+ // 且崩在库内部,连提示都给不出来。这里再收一道解析安全上限,可用
386
+ // importOption.maxFileSize 覆盖(0 表示不限制)。
387
+ if (isImportFileOversize(file, option)) {
388
+ this.$baseAlert(
389
+ this.$t1(
390
+ "导入文件过大({size}MB),当前最多支持 {limit}MB,请拆分后分批导入",
391
+ {
392
+ size: toFileSizeMb(file.size),
393
+ limit: toFileSizeMb(getImportFileSizeLimit(option)),
394
+ }
395
+ )
396
+ );
397
+ // 与上游那道 importFileLimitSize 校验保持一致:只提示、不关弹窗,
398
+ // 用户可以直接重选一个小文件。
399
+ return false;
400
+ }
401
+
375
402
  if (option.importOption.multipleSheet) {
376
403
  this.readExcel2(file, callback);
377
404
  return;
@@ -403,6 +430,22 @@ tmixins = {
403
430
  let range = configUtil.XLSX.utils.decode_range(sheet["!ref"]);
404
431
  let dataSize = range.e.r + 1; //行数
405
432
  that.dataSize = dataSize - 3 >= 0 ? dataSize - 3 : 0;
433
+ // 行数闸门:下面逐格取值、建行对象、再整批发包全是同步的,行数失控时主线程会被
434
+ // 占死甚至 OOM。文件体积不大但行极多(窄表)时只有这一道能拦。
435
+ if (isImportRowsOverLimit(that.dataSize, option)) {
436
+ that.clearImportTimer();
437
+ that.$baseAlert(
438
+ that.$t1(
439
+ "导入数据 {size} 行,超过单次上限 {limit} 行,请拆分后分批导入",
440
+ {
441
+ size: that.dataSize,
442
+ limit: getImportRowLimit(option),
443
+ }
444
+ )
445
+ );
446
+ that.handleClose2();
447
+ return false;
448
+ }
406
449
  let titles = [];
407
450
  let fields = [];
408
451
 
@@ -428,7 +471,7 @@ tmixins = {
428
471
  if (typeof nextCell === "undefined") {
429
472
  row.push(void 0);
430
473
  } else {
431
- row.push(nextCell.w.trim());
474
+ row.push(getImportCellText(nextCell));
432
475
  }
433
476
  }
434
477
  if (rowNum === 1) {
@@ -1483,6 +1526,22 @@ tmixins = {
1483
1526
  let range = configUtil.XLSX.utils.decode_range(sheet["!ref"]);
1484
1527
  let dataSize = range.e.r + 1; //行数
1485
1528
  that.dataSize = dataSize - 3 >= 0 ? dataSize - 3 : 0;
1529
+ // 行数闸门:下面逐格取值、建行对象、再整批发包全是同步的,行数失控时主线程会被
1530
+ // 占死甚至 OOM。文件体积不大但行极多(窄表)时只有这一道能拦。
1531
+ if (isImportRowsOverLimit(that.dataSize, option)) {
1532
+ that.clearImportTimer();
1533
+ that.$baseAlert(
1534
+ that.$t1(
1535
+ "导入数据 {size} 行,超过单次上限 {limit} 行,请拆分后分批导入",
1536
+ {
1537
+ size: that.dataSize,
1538
+ limit: getImportRowLimit(option),
1539
+ }
1540
+ )
1541
+ );
1542
+ that.handleClose2();
1543
+ return false;
1544
+ }
1486
1545
  let titles = [];
1487
1546
  let fields = [];
1488
1547
 
@@ -1508,7 +1567,7 @@ tmixins = {
1508
1567
  if (typeof nextCell === "undefined") {
1509
1568
  row.push(void 0);
1510
1569
  } else {
1511
- row.push(nextCell.w.trim());
1570
+ row.push(getImportCellText(nextCell));
1512
1571
  }
1513
1572
  }
1514
1573
  if (rowNum === 1) {
@@ -103,6 +103,15 @@ export default {
103
103
  targetRef: this.field.options.tableRef || null,
104
104
  pageSize: this.field.options.exportPageSize || null,
105
105
  showImageAtTable: this.field.options.showImageAtTable || null,
106
+ // 明细导出的列 / 脚本编码 / 取数参数三项各自独立:按钮上维护了哪项就以哪项为准,
107
+ // 留空的那项沿用数据表格属性上那套。参数脚本原样下发,由数据表格求值(this 是
108
+ // 表格组件,与配在表格属性上时同义)
109
+ exportItemColumns: this.field.options.exportItemColumns || null,
110
+ exportItemScriptCode: this.field.options.exportItemScriptCode || null,
111
+ exportItemParam: this.field.options.exportItemParam || null,
112
+ // 字段勾选记忆按按钮分组存放,组件名是唯一且稳定的分组标识(见 exportColumnMemory.js)。
113
+ // 同一张表挂多个明细导出按钮时,各按钮的勾选互不覆盖。
114
+ exportButtonName: this.field.options.name || null,
106
115
  };
107
116
  let tableExportParam = this.handleCustomEvent(this.field.options.tableExportParam);
108
117
  let options = { ...opt, ...tableExportParam, type: type };
@@ -353,7 +353,13 @@ export default {
353
353
  return;
354
354
  }
355
355
  }
356
- this.optionModel.exportItemColumns = this.$baseLodash.cloneDeep(this.tableData);
356
+ // 用 $set:导出按钮是后加的宿主,历史表单 JSON 里没有 exportItemColumns 这个键,
357
+ // 直接赋值不会触发「已维护」文案更新
358
+ this.$set(
359
+ this.optionModel,
360
+ "exportItemColumns",
361
+ this.$baseLodash.cloneDeep(this.tableData)
362
+ );
357
363
  this.closeHandle();
358
364
  },
359
365
  generateRow() {
@@ -34,16 +34,59 @@
34
34
  <i class="el-icon-edit"></i>
35
35
  </a>
36
36
  </el-form-item>
37
+ <el-form-item label="明细导出脚本编码" class="form-item-label-top">
38
+ <el-input v-model="optionModel.exportItemScriptCode"></el-input>
39
+ </el-form-item>
40
+ <el-form-item label="明细导出查询参数">
41
+ <a
42
+ href="javascript:void(0);"
43
+ class="a-link link-oneLind"
44
+ @click="editEventHandler('exportItemParam', tableConfigParams)"
45
+ >
46
+ <span>{{ optionModel.exportItemParam }}</span>
47
+ <i class="el-icon-edit"></i>
48
+ </a>
49
+ </el-form-item>
50
+ <el-form-item label="明细导出列维护">
51
+ <a
52
+ href="javascript:void(0);"
53
+ class="a-link link-oneLind"
54
+ @click="showExportItemColumnsDialog = true"
55
+ >
56
+ <span>{{
57
+ optionModel.exportItemColumns && optionModel.exportItemColumns.length
58
+ ? "已维护"
59
+ : null
60
+ }}</span>
61
+ <i class="el-icon-edit"></i>
62
+ </a>
63
+ </el-form-item>
64
+ <el-form-item label-width="0">
65
+ <div class="export-item-columns-tip">
66
+ 脚本编码、查询参数、导出列三项各自独立:留空的那项沿用数据表格属性上配的,维护了就以本按钮为准。
67
+ </div>
68
+ </el-form-item>
69
+ <exportItemColumnsDialog
70
+ v-if="showExportItemColumnsDialog"
71
+ :visiable.sync="showExportItemColumnsDialog"
72
+ :designer="designer"
73
+ :selectedWidget="selectedWidget"
74
+ :optionModel="optionModel"
75
+ />
37
76
  </div>
38
77
  </template>
39
78
 
40
79
  <script>
41
80
  import i18n from "../../../../utils/i18n";
42
81
  import eventMixin from "../event-handler/eventMixin";
82
+ import exportItemColumnsDialog from "../container-data-table/exportItemColumns-dialog.vue";
43
83
 
44
84
  export default {
45
85
  name: "select-export-item-button-editor",
46
86
  mixins: [i18n, eventMixin],
87
+ components: {
88
+ exportItemColumnsDialog,
89
+ },
47
90
  props: {
48
91
  designer: Object,
49
92
  selectedWidget: Object,
@@ -52,6 +95,9 @@ export default {
52
95
  data() {
53
96
  return {
54
97
  eventParams: [],
98
+ // 与数据表格属性面板同一套:脚本里可直接用 dataId / formCode
99
+ tableConfigParams: ["dataId", "formCode"],
100
+ showExportItemColumnsDialog: false,
55
101
  };
56
102
  },
57
103
  methods: {
@@ -71,4 +117,9 @@ export default {
71
117
  ::v-deep.export-divider .el-divider__text.is-center {
72
118
  width: 162px;
73
119
  }
120
+ .export-item-columns-tip {
121
+ line-height: 18px;
122
+ color: #909399;
123
+ font-size: 12px;
124
+ }
74
125
  </style>
@@ -3318,6 +3318,10 @@ export const advancedFields = [
3318
3318
  showImageAtTable: false,
3319
3319
  selectExportItemFlag: 1,
3320
3320
  exportItemConditionEnabled: !1,
3321
+ // 按钮级明细导出配置:三项各自独立,留空的那项沿用数据表格属性上维护的
3322
+ exportItemColumns: [],
3323
+ exportItemScriptCode: null,
3324
+ exportItemParam: "",
3321
3325
 
3322
3326
  onCreated: "",
3323
3327
  onMounted: "",
@@ -183,7 +183,10 @@
183
183
  <div>
184
184
  <template v-for="(fieldWidget, index) in obj.column.params.widgetList">
185
185
  <component
186
- v-if="!!fieldSchemaMap[obj.row._X_ROW_KEY] && !!obj.row._X_ROW_KEY"
186
+ v-if="
187
+ !!obj.row._X_ROW_KEY &&
188
+ (!!getRowFieldSchema(obj.row) || !!obj.row._X_EXPORT_ROW)
189
+ "
187
190
  :is="getColumnWidgetName(fieldWidget)"
188
191
  v-bind="getRowWidgetOption(obj, fieldWidget)"
189
192
  :form-model="globalModel.formModel"
@@ -205,15 +208,15 @@
205
208
  </template>
206
209
  <template #editWidget="obj">
207
210
  <component
208
- v-if="!!fieldSchemaMap[obj.row._X_ROW_KEY]"
211
+ v-if="!!getRowFieldSchema(obj.row)"
209
212
  :is="getColumnWidgetName(obj.column.params.editWidget)"
210
- :field="fieldSchemaMap[obj.row._X_ROW_KEY][obj.column.params.editWidget.id]"
213
+ :field="getRowFieldSchema(obj.row)[obj.column.params.editWidget.id]"
211
214
  :form-model="globalModel.formModel"
212
215
  :designer="null"
213
216
  :key="
214
217
  obj.rowIndex +
215
218
  '-' +
216
- fieldSchemaMap[obj.row._X_ROW_KEY][obj.column.params.editWidget.id].id
219
+ getRowFieldSchema(obj.row)[obj.column.params.editWidget.id].id
217
220
  "
218
221
  :parent-widget="widget"
219
222
  :columnConfig="obj.column.params.columnConfig"