cloud-web-corejs 1.0.283 → 1.0.284
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/excelExport/conditionExportConfig.js +112 -0
- package/src/components/excelExport/exportType.js +8 -0
- package/src/components/excelExport/index.vue +7 -1
- package/src/components/excelExport/mixins.js +410 -259
- package/src/components/xform/form-designer/form-widget/dialog/importDialog.vue +190 -185
- package/src/components/xform/form-designer/form-widget/dialog/importDialogMixin.js +2641 -1833
- package/src/components/xform/form-designer/form-widget/field-widget/import-button-widget.vue +18 -5
- package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +2 -1
- package/src/components/xform/form-designer/form-widget/field-widget/table-export-button-widget.vue +2 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import-button-editor.vue +62 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +236 -96
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/empty-number-input.vue +51 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +27 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/table-export-button-editor.vue +33 -3
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +31 -0
- package/src/components/xform/form-render/container-item/data-table-mixin.js +3 -1
- 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" +0 -389
- 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" +0 -233
|
@@ -1,233 +0,0 @@
|
|
|
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 早发现),未实施。
|