cloud-web-corejs 1.0.54-dev.739 → 1.0.54-dev.740

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cloud-web-corejs",
3
3
  "private": false,
4
- "version": "1.0.54-dev.739",
4
+ "version": "1.0.54-dev.740",
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
7
7
  "lint": "eslint --ext .js,.vue src",
@@ -70,15 +70,14 @@ if (p.autoAdd) {
70
70
  if (!dataId) { // dataId 注入参数,无=新建
71
71
  let f = this.getFormRef();
72
72
  let sourceId = f.getFormParam() && f.getFormParam().sourceId;
73
- f.initChangeFromSource(sourceId, {
73
+ f.initChangeFromSource(sourceId, { // 单层扁平配置,取数/对比/清洗参数同层
74
74
  sourceFormCode: '原单formCode', // 用原单模板拉原单数据(原单≠变更单模板时)
75
- compareRowKey: 'uuid',
76
- sanitize: { // 传给 sanitizeChangeData
77
- defaultFields: ['billType'], // 主表字段不吃原单值、保留变更单默认值
78
- subDefaultFields: { 明细A: ['status'] }, // 明细列不吃原单值
79
- subSourceFields: { 明细A: 'f_source_id' }, // 原明细 id 回填
80
- treeSubTables: ['分类明细'],
81
- },
75
+ compareRowKey: 'uuid', // 对比参数
76
+ excludeFields: ['f_type'], // 对比参数:主表不对比字段
77
+ defaultFields: ['billType'], // 清洗参数:主表字段不吃原单值、保留变更单默认值
78
+ subDefaultFields: { 明细A: ['status'] }, // 清洗参数:明细列不吃原单值
79
+ subSourceFields: { 明细A: 'f_source_id' },// 清洗参数:原明细 id 回填
80
+ treeSubTables: ['分类明细'], // 清洗参数
82
81
  });
83
82
  }
84
83
  ```
@@ -171,10 +170,12 @@ enableCompareBySource(that) {
171
170
  - **白名单优先于黑名单**:某张表一旦配了白名单,该表的黑名单整体失效,别同时配。这个优先关系按表独立生效——主表用白名单、明细用黑名单是允许的。
172
171
  - 系统字段(`id/create_by/create_date/modify_by/modify_date/head_table_id/alias_id/object_foreign_id` 等)、附件字段(`attachments_` 前缀)、`subSourceFields` 回填字段,**已默认排除**,不用写。
173
172
  - 跨表场景(compareMapping)下白名单**自动推导**:主表白名单来自 `mapping.master[].to`,每张明细的白名单来自该表 `fields[].to` —— 主表与各明细互不串味,无需手写。
174
- - `sanitize.defaultFields`(主表)/ `sanitize.subDefaultFields`(明细表 `{keyName:[列prop]}`):这些字段**不吃原单值**,保留变更单自身值/默认值。
175
- - `sanitize.subExtraClearFields`:子表额外清空的外键字段,默认 `head_table_id/headTableId/alias_id/object_foreign_id`。
176
- - `sanitize.attachmentKeepFields`:附件文件对象保留字段白名单,默认 `name/thumbnail/extension/large/fileSize/domain/source/medium/url`(表头附件、data-table 单元格附件都按此精简;`sanitize.cleanAttachment:false` 可整体关闭)。
177
- - `sanitize.subSourceFields`:`{ 明细keyName: 配置 }`,把原明细行/原单表头字段回填到明细业务字段。配置支持:
173
+ > **配置是单层扁平的**:`initChangeFromSource` 的 options 同时供取数、对比、清洗三类参数,**平铺在同一层**,无 `sanitize` 子对象。三组键互不相交(对比 `excludeFields/includeFields/compareRowKey/compareMapping…`、清洗 `defaultFields/subDefaultFields/subSourceFields/treeSubTables…`、取数 `sourceFormCode/subParams…`),各方法各取所需。直接单独调用 `sanitizeChangeData(oldData, options)` 时,它只挑自己认得的清洗键,其余忽略。
174
+
175
+ - `defaultFields`(主表)/ `subDefaultFields`(明细表 `{keyName:[列prop]}`):这些字段**不吃原单值**,保留变更单自身值/默认值。
176
+ - `subExtraClearFields`:子表额外清空的外键字段,默认 `head_table_id/headTableId/alias_id/object_foreign_id`。
177
+ - `attachmentKeepFields`:附件文件对象保留字段白名单,默认 `name/thumbnail/extension/large/fileSize/domain/source/medium/url`(表头附件、data-table 单元格附件都按此精简;`cleanAttachment:false` 可整体关闭)。
178
+ - `subSourceFields`:`{ 明细keyName: 配置 }`,把原明细行/原单表头字段回填到明细业务字段。配置支持:
178
179
  - `'目标字段'` → 原明细 `id` → 目标字段
179
180
  - `{ from:'明细字段', to:'目标字段' }`(from 默认 `id`)
180
181
  - `{ fromHeader:'表头字段', to:'目标字段' }` → 原单表头字段回填
@@ -183,11 +184,78 @@ enableCompareBySource(that) {
183
184
 
184
185
  > **回填字段自动排除对比**:回填出的字段(如 `f_source_item_id`)只存在于新单行,原单行没有 → 逐字段比较时是「空 → 有值」,会把整表行判成**变更行(黄)**。`sanitizeChangeData` 已自动把回填目标字段登记进 `compareAutoExcludeFields`(函数式配置也支持:通过比对函数执行前后新增的 key 捕获),无需手工配置。
185
186
  > **但模式 A(打开已保存的变更单点「对比」)不会走 sanitize**,此时请把这些字段一并写进 `excludeFields`,例如 `excludeFields: ['f_type', 'f_source_id', 'f_source_item_id']`。
186
- - `sanitize.treeSubTables`:树表配置 `[{ name, idField, parentField }]`,id/parent_id 会重新生成并保留层级。
187
+ - `treeSubTables`:树表配置 `[{ name, idField, parentField }]`,id/parent_id 会重新生成并保留层级。
187
188
  - **保存**:提交时 `getReqFormData` 自动剥除对比快照字段 `hData`,无需业务处理。
188
- - **行级高亮**:变更行橙色、新增行绿色(各带左侧色条),新增行不逐格显示感叹号;行级判定与单元格判定走**同一个** `isCompareExcludeField(字段名, 明细表名)`,名单口径完全一致。
189
+ - **行级高亮**:变更行橙色、新增行绿色(各带左侧色条),新增行不逐格显示感叹号。
190
+ > **行变黄只校验「数据表格列」对应的字段**(取自设计器 `tableColumns` 的叶子列 `prop`,含运行时动态列,排除附件列)。后台多返回的非列字段、`subSourceFields` 回填字段等**天然不参与**行级判定——这是正向定义,比黑名单更可靠。白/黑名单(`subExcludeFields/subIncludeFields`)在列集之上做进一步收窄。取不到列(实例未就绪)时退回「两行键并集」旧口径。
189
191
  > 附件恒不对比:新单附件已按 `attachmentKeepFields` 白名单精简(9 个字段),原单快照里是完整对象(含 id/createDate/sn…),直接比必然不等。故按 `attachments_` 前缀(设计器 `keyNamePrefixMap` 固定前缀)在行级判定里整体跳过。
190
192
 
193
+ ### 全字段参考配置(options 全集)
194
+ `initChangeFromSource(sourceId, options)` 的 options 是**单层扁平**对象。`enableCompareBySource` 接收其中的**取数 + 对比**字段(不含清洗,模式 B 不填充新单);`sanitizeChangeData(oldData, options)` 只取其中的**清洗**字段。
195
+
196
+ #### A. 常用字段(按业务需要填)
197
+ ```js
198
+ formRef.initChangeFromSource(sourceId, {
199
+
200
+ // ── 取数 ──
201
+ sourceFormCode: '订单formCode', // 原单≠变更单模板时必填(枚举原单子表/entity/formCode);结构一致可省略
202
+ sourceKeyField: 'f_no', // 原单存的是编码而非 id 时,指定主表用哪个字段查
203
+ subParams: { // 明细需要额外查询参数时;值可为对象或 (ctx)=>对象,ctx={masterData,masterId}
204
+ '订单明细': { f_status: 1 },
205
+ },
206
+
207
+ // ── 对比 ──
208
+ compareRowKey: 'f_uuid', // 子表行匹配主键(务必是明细里稳定唯一的业务键)
209
+ excludeFields: ['f_type'], // 主表不对比字段
210
+ subExcludeFields: { // 明细不对比字段:{ 明细keyName: [字段名] }
211
+ test_source_bill_item: ['f_source_item_id'],
212
+ },
213
+
214
+ // ── 清洗 ──
215
+ defaultFields: ['f_no'], // 主表:不吃原单值、保留变更单自身默认值的字段
216
+ subDefaultFields: { // 明细:{ 明细keyName: ['列prop'] },取该列设计器默认值
217
+ test_source_bill_item: ['f_state'],
218
+ },
219
+ subSourceFields: { // 原明细行/原单表头字段回填到明细
220
+ test_source_bill_item: (row, header) => { row.f_source_item_id = row.id; },
221
+ // 也支持:'目标字段' | { from, to } | { fromHeader, to } | [ ...多个 ]
222
+ },
223
+ treeSubTables: ['分类明细'], // 有树表时才填:重生成 id/parent_id 并保层级
224
+ });
225
+ ```
226
+
227
+ 跨表场景(B)另加 `compareMapping`(白名单、行主键由它自动推导,此时 `subRowKeys/includeFields` 不用手写):
228
+ ```js
229
+ compareMapping: {
230
+ master: [{ from: 'o_cust', to: 'f_cust' }],
231
+ subs: [{
232
+ from: 'order_item', to: 'test_source_bill_item',
233
+ rowKey: { from: 'o_line_no', to: 'f_line_no' },
234
+ fields: [{ from: 'o_qty', to: 'f_qty' }],
235
+ }],
236
+ },
237
+ transformOldData: null, // 可选:映射之外的值转换兜底钩子 (oldData, srcData) => oldData
238
+ ```
239
+
240
+ #### B. 其余选项(均有默认值,一般省略)
241
+ | 字段 | 默认 | 说明 |
242
+ |---|---|---|
243
+ | `compare` | `true` | `false`=只填充新单、不开启对比(可稍后手动 `enableCompare`) |
244
+ | `includeFields` | `null` | 主表白名单:设置后主表只比这些字段、主表黑名单失效 |
245
+ | `subIncludeFields` | `{}` | 明细白名单:`{ 明细keyName: [字段] }`,设置后该表只比这些、该表黑名单失效 |
246
+ | `subRowKeys` | `{}` | 按明细覆盖行主键 `{ 明细keyName: 字段 }`(跨表由 `compareMapping` 自动推导) |
247
+ | `excludeTypes` | 附件/上传类 | 覆盖不参与对比的字段「类型」 |
248
+ | `commonParams` | `{}` | 追加到「所有」明细/附件包的公共查询参数 |
249
+ | `sourceIdField` | `'id'` | 从主表响应取「真实主键」的字段名(用于发明细/附件包) |
250
+ | `sourceIdIsKey` | `false` | `true`=传的就是 id → 主表/明细并行查(快路径) |
251
+ | `isLoading` | `true` | 取数是否显示 loading |
252
+ | `masterScriptCode` | `'getOne'` | 主表读取脚本 |
253
+ | `reportTemplate`/`formCode`/`formVersion`/`entity` | 取自模板 | 覆盖取数用的模板/编号/版本/主表 entity |
254
+ | `masterClearFields` | 系统字段集 | 覆盖主表默认清理字段(id/createBy/createDate/modifyBy/modifyDate/…) |
255
+ | `subExtraClearFields` | 外键集 | 覆盖子表额外清空字段(head_table_id/alias_id/object_foreign_id/…) |
256
+ | `attachmentKeepFields` | 9 字段白名单 | 覆盖附件保留字段(name/thumbnail/extension/large/fileSize/domain/source/medium/url) |
257
+ | `cleanAttachment` | `true` | `false`=不精简附件字段 |
258
+
191
259
  ### 完整接入示例(GlobalConfig)
192
260
  把对比相关逻辑收敛到 `getGlobalConfig()` 返回对象里,详情页脚本按需调用。
193
261
 
@@ -227,15 +295,13 @@ return {
227
295
  that.formModel.f_source_id = sourceId;
228
296
  that.formModel.f_type = 1;
229
297
  that.getFormRef().initChangeFromSource(sourceId, {
230
- compareRowKey: compareRowKey,
231
- excludeFields: excludeFields,
232
- sanitize: { // 传给 sanitizeChangeData
233
- defaultFields: defaultFields,
234
- subSourceFields: {
235
- // test_source_bill_item 原单明细ID回填到 f_source_item_id
236
- test_source_bill_item: (row, header) => {
237
- row.f_source_item_id = row.id;
238
- },
298
+ compareRowKey: compareRowKey, // 对比参数
299
+ excludeFields: excludeFields, // 对比参数
300
+ defaultFields: defaultFields, // 清洗参数(同层平铺,无 sanitize 子对象)
301
+ subSourceFields: { // 清洗参数
302
+ // test_source_bill_item 原单明细ID回填到 f_source_item_id
303
+ test_source_bill_item: (row, header) => {
304
+ row.f_source_item_id = row.id;
239
305
  },
240
306
  },
241
307
  });
@@ -465,7 +531,7 @@ compareDelListOption: {},
465
531
  - **`getCompareSubTables()` / `getCompareSubTablesFrom(widgetList)`**:枚举需独立发包的 data-table 子表。
466
532
  - **`fetchTemplateByFormCode(formCode)`** → `Promise<{reportTemplate, formConfig, widgetList}>`:按 formCode 拉模板(`/formTemplate/getByFormCode`)。
467
533
  - **`enableCompareBySource(sourceId, options)`**(模式B 一行):`loadOldData` → `enableCompare`。
468
- - **`initChangeFromSource(sourceId, options)`**(模式A 一行):`loadOldData` → `sanitizeChangeData(old, options.sanitize)` → `setFormData(新单)` → `enableCompare(原始旧数据)`。
534
+ - **`initChangeFromSource(sourceId, options)`**(模式A 一行,options 单层扁平):`loadOldData` → `applyCompareSourceTransform` → `sanitizeChangeData(old, options)` → `setFormData(新单)` → `enableCompare(原始旧数据)`。
469
535
 
470
536
  **数据清洗(变更初始化)**
471
537
  - **`sanitizeChangeData(oldData, options)`** → 清洗后克隆:清主/子表系统字段(id/createBy/createDate/modifyBy/modifyDate/_createBy/_modifyBy + snake_case)、子表外键(head_table_id/alias_id/object_foreign_id)、附件白名单精简(attachmentKeepFields)、不覆盖取默认(defaultFields/subDefaultFields)、原单字段回填(subSourceFields)、树表 id/parent_id 重生成(treeSubTables)。
@@ -580,7 +646,7 @@ let f = this.getFormRef();
580
646
 
581
647
  // 模式A 新建(onMounted):自动多包取原单 + 清洗 + 填充 + 对比
582
648
  f.initChangeFromSource(sourceId, { sourceFormCode:'原单formCode', compareRowKey:'uuid', excludeFields:['status'],
583
- sanitize:{ defaultFields:['billType'], subSourceFields:{ 明细A:'f_source_id' }, treeSubTables:['分类明细'] } });
649
+ defaultFields:['billType'], subSourceFields:{ 明细A:'f_source_id' }, treeSubTables:['分类明细'] });
584
650
 
585
651
  // 模式B 已存(对比按钮):自动多包取原单 + 对比
586
652
  f.enableCompareBySource(sourceId, { sourceFormCode:'原单formCode', compareRowKey:'uuid' });
@@ -2380,13 +2380,30 @@ modules = {
2380
2380
  Array.isArray(this.oldFormData[subFormName])
2381
2381
  );
2382
2382
  },
2383
- /** 行级差异:比较当前行与原单行的标量字段(跳过内部字段、排除字段与附件列) */
2384
- isCompareRowValuesChanged: function (oldRow, row, skipKeys, subFormName) {
2383
+ /**
2384
+ * 行级差异:比较当前行与原单行。
2385
+ * compareKeys 传入时(数据表格场景)只比这些字段——即数据表格「列」对应的字段,
2386
+ * 后台多返回的非列字段、回填字段等一律不参与,从根上避免误判为「变更行」。
2387
+ * 不传时退回「两行键并集」旧口径(兼容非数据表格调用)。
2388
+ */
2389
+ isCompareRowValuesChanged: function (
2390
+ oldRow,
2391
+ row,
2392
+ skipKeys,
2393
+ subFormName,
2394
+ compareKeys
2395
+ ) {
2385
2396
  let skip = skipKeys || {};
2386
- let keys = {};
2387
- Object.keys(oldRow || {}).forEach((k) => (keys[k] = 1));
2388
- Object.keys(row || {}).forEach((k) => (keys[k] = 1));
2389
- return Object.keys(keys).some((k) => {
2397
+ let keys;
2398
+ if (Array.isArray(compareKeys)) {
2399
+ keys = compareKeys;
2400
+ } else {
2401
+ let set = {};
2402
+ Object.keys(oldRow || {}).forEach((k) => (set[k] = 1));
2403
+ Object.keys(row || {}).forEach((k) => (set[k] = 1));
2404
+ keys = Object.keys(set);
2405
+ }
2406
+ return keys.some((k) => {
2390
2407
  if (
2391
2408
  k === "hData" ||
2392
2409
  k.charAt(0) === "_" ||
@@ -2416,10 +2433,44 @@ modules = {
2416
2433
  if (inst && typeof inst.getAttachmentType === "function") {
2417
2434
  (inst.getAttachmentType() || []).forEach((p) => (skip[p] = 1));
2418
2435
  }
2419
- return this.isCompareRowValuesChanged(old, row, skip, subFormName)
2436
+ // 只比「数据表格列」对应的字段;取不到列(实例未就绪)时退回并集口径
2437
+ let compareKeys = this.getSubTableColumnProps(subFormName);
2438
+ if (!compareKeys.length) compareKeys = null;
2439
+ return this.isCompareRowValuesChanged(
2440
+ old,
2441
+ row,
2442
+ skip,
2443
+ subFormName,
2444
+ compareKeys
2445
+ )
2420
2446
  ? "xform-compare-row-changed"
2421
2447
  : "";
2422
2448
  },
2449
+ /**
2450
+ * 取某数据表格「列」对应的字段名(叶子列 prop),供行级对比限定比较范围用。
2451
+ * 与 getSubTableDisplayColumns 不同:不要求 label(隐藏/无标题列也算业务列),
2452
+ * 但排除附件列(附件不参与对比)。取自实例的 widget.options.tableColumns(含运行时动态列)。
2453
+ */
2454
+ getSubTableColumnProps: function (subFormName) {
2455
+ let inst = this.getSubTableInstance(subFormName);
2456
+ let tableColumns =
2457
+ inst && inst.widget && inst.widget.options
2458
+ ? inst.widget.options.tableColumns
2459
+ : null;
2460
+ if (!tableColumns) return [];
2461
+ let props = [];
2462
+ let walk = (cols) => {
2463
+ (cols || []).forEach((item) => {
2464
+ if (item.children && item.children.length) {
2465
+ walk(item.children);
2466
+ } else if (item.prop && item.formatS !== "editAttachment") {
2467
+ props.push(item.prop);
2468
+ }
2469
+ });
2470
+ };
2471
+ walk(tableColumns);
2472
+ return props;
2473
+ },
2423
2474
  /** 返回某子表被删除的行(旧有、当前按主键找不到)。实时计算。 */
2424
2475
  getDelData: function (subFormName) {
2425
2476
  // 未映射/不参与对比的子表:没有"删除行"概念
@@ -2874,11 +2925,17 @@ modules = {
2874
2925
  },
2875
2926
  /**
2876
2927
  * 通用:新建变更单时,自动获取原单 → 清洗 → 填充新单 → 开启对比(模式 A 一行接入)。
2928
+ * options 为**单层**扁平对象,同时供 loadOldData / applyCompareSourceTransform /
2929
+ * sanitizeChangeData / enableCompare 消费——各组键互不相交,无需分层。
2877
2930
  * @param {String|Number} sourceId 原单主键值(id 或编码)
2878
- * @param {Object} [options] loadOldData 的选项 + enableCompare 的选项,另加:
2879
- * sanitize 传给 sanitizeChangeData 的清洗选项
2880
- * compare 默认 true 自动开启对比;传 false 则只用原单数据填充新单、不开启对比
2881
- * (可用返回的 oldData 稍后手动 enableCompare(oldData, options))
2931
+ * @param {Object} [options]
2932
+ * 取数:sourceFormCode / sourceKeyField / sourceIdField / commonParams / subParams …
2933
+ * 对比:excludeFields / includeFields / subExcludeFields / subIncludeFields /
2934
+ * compareRowKey / subRowKeys / compareMapping / transformOldData …
2935
+ * 清洗:masterClearFields / subExtraClearFields / defaultFields / subDefaultFields /
2936
+ * subSourceFields / attachmentKeepFields / cleanAttachment / treeSubTables …
2937
+ * compare 默认 true 自动开启对比;传 false 则只用原单数据填充新单、不开启对比
2938
+ * (可用返回的 oldData 稍后手动 enableCompare(oldData, options))
2882
2939
  * @returns {Promise<Object>} 归一化后的原单数据(对比基准)
2883
2940
  */
2884
2941
  initChangeFromSource: function (sourceId, options) {
@@ -2886,7 +2943,9 @@ modules = {
2886
2943
  return this.loadOldData(sourceId, options).then((srcData) => {
2887
2944
  // 跨表:先归一化到当前表单键空间,否则字段名对不上、数据填不进变更单
2888
2945
  let oldData = this.applyCompareSourceTransform(srcData, options);
2889
- let newData = this.sanitizeChangeData(oldData, options.sanitize || {});
2946
+ // 单层配置:对比参数(enableCompare)与清洗参数(sanitizeChangeData)平铺在同一 options
2947
+ // 两组键互不相交,各方法各取所需,无需分层。
2948
+ let newData = this.sanitizeChangeData(oldData, options);
2890
2949
  this.setFormData(newData);
2891
2950
  // compare:false → 只用原单数据填充新单,不开启对比(可稍后手动 enableCompare(oldData))
2892
2951
  if (options.compare !== false) {