cloud-web-corejs 1.0.54-dev.713 → 1.0.54-dev.715

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 (21) hide show
  1. package/package.json +1 -1
  2. package/src/components/xform/XFormTabContainer//346/226/260/345/242/236/351/241/265/347/255/276/346/250/241/345/274/217-/350/220/275/345/234/260/345/256/236/346/226/275/346/226/207/346/241/243.md +232 -0
  3. package/src/components/xform/docs//345/257/271/346/257/224/345/212/237/350/203/275/350/220/275/345/234/260/346/226/271/346/241/210.md +563 -0
  4. package/src/components/xform/form-designer/form-widget/field-widget/cascader-widget.vue +48 -0
  5. package/src/components/xform/form-designer/form-widget/field-widget/fieldMixin.js +60 -0
  6. package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +116 -13
  7. package/src/components/xform/form-designer/form-widget/field-widget/mixins/autocomplete-mixin.js +5 -0
  8. package/src/components/xform/form-designer/form-widget/field-widget/mixins/vabsearch-mixin.js +13 -0
  9. package/src/components/xform/form-designer/form-widget/field-widget/status-widget.vue +11 -0
  10. package/src/components/xform/form-designer/form-widget/field-widget/switch-widget.vue +9 -1
  11. package/src/components/xform/form-designer/widget-panel/index.vue +29 -0
  12. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +138 -1
  13. package/src/components/xform/form-render/compareDelList.vue +83 -0
  14. package/src/components/xform/form-render/compareView.vue +76 -0
  15. package/src/components/xform/form-render/container-item/data-table-item.vue +15 -0
  16. package/src/components/xform/form-render/container-item/data-table-mixin.js +19 -0
  17. package/src/components/xform/form-render/index.vue +8 -1
  18. package/src/components/xform/form-render/indexMixin.js +757 -3
  19. package/src/components/xform/lang/en-US_extension.js +3 -0
  20. package/src/components/xform/lang/zh-CN.js +3 -0
  21. package/src/components/xform/mixins/defaultHandle.js +17 -0
@@ -222,6 +222,66 @@ modules = {
222
222
  ? resultList[0]
223
223
  : null;
224
224
  },
225
+ // ===================== 表单对比:差异判定与展示 =====================
226
+ /**
227
+ * 差异判定:用「原始存储值」比较(下拉/关联按 code/id 比),可被具体 widget override。
228
+ */
229
+ compareEquals: function (a, b) {
230
+ const isEmpty = (v) =>
231
+ v === null ||
232
+ v === undefined ||
233
+ v === "" ||
234
+ (Array.isArray(v) && v.length === 0);
235
+ if (isEmpty(a) && isEmpty(b)) return true;
236
+ if (isEmpty(a) || isEmpty(b)) return false;
237
+ if (Array.isArray(a) && Array.isArray(b)) {
238
+ if (a.length !== b.length) return false;
239
+ const sa = a.map((x) => String(x)).sort();
240
+ const sb = b.map((x) => String(x)).sort();
241
+ return sa.every((x, i) => x === sb[i]);
242
+ }
243
+ if (typeof a === "object" || typeof b === "object") {
244
+ try {
245
+ return JSON.stringify(a) === JSON.stringify(b);
246
+ } catch (e) {
247
+ return a === b;
248
+ }
249
+ }
250
+ return String(a) === String(b);
251
+ },
252
+ /**
253
+ * 把「任意原始值」解析成展示文本(label),用于对比 popover 展示旧值。
254
+ * 下拉/单选/多选按 optionItems 解析 code→label;其它类型返回原值。
255
+ */
256
+ resolveDisplayValue: function (rawValue) {
257
+ if (rawValue === null || rawValue === undefined || rawValue === "") {
258
+ return rawValue;
259
+ }
260
+ // 凡是有 optionItems 的映射组件(select/radio/checkbox/status/dropdown 等)
261
+ // 统一按 optionItems 做 code→label;关联/switch/cascader 等在各自 widget override。
262
+ let optionItems = this.field.options.optionItems;
263
+ if (Array.isArray(optionItems) && optionItems.length) {
264
+ const labelField = this.getOptionItemLabelKey();
265
+ const valueField = this.getOptionItemValueKey();
266
+ const values = Array.isArray(rawValue) ? rawValue : [rawValue];
267
+ const labels = values.map((val) => {
268
+ const item = optionItems.find((o) => o[valueField] === val);
269
+ return item ? this.$t1(item[labelField]) : val;
270
+ });
271
+ return labels.join(",");
272
+ }
273
+ return rawValue;
274
+ },
275
+ /**
276
+ * 对比「变更前」展示值:给出原单的行/主表对象,返回该字段应展示的旧 label。
277
+ * 默认按本字段存储键取原始值再 resolveDisplayValue;关联搜索类组件(值存 id、
278
+ * label 存在同行的伴随字段)在各自 mixin override,从 oldRow 里取伴随 label 字段。
279
+ * @param {Object} oldRow 原单主表对象或子表行对象
280
+ */
281
+ resolveCompareOldDisplay: function (oldRow) {
282
+ let raw = oldRow ? oldRow[this.fieldKeyName] : undefined;
283
+ return this.resolveDisplayValue(raw);
284
+ },
225
285
  initValueWatchEvent() {
226
286
  if (!this.designer) {
227
287
  this.$watch(
@@ -18,7 +18,16 @@
18
18
  <template v-if="formItemProp === 'false'">
19
19
  <template v-if="!field.options.hidden">
20
20
  <template v-if="isShowWidget()">
21
- <slot></slot>
21
+ <compareView
22
+ v-if="isCompareOn"
23
+ :isCompare="isCompareOn"
24
+ :isDiff="compareIsDiff"
25
+ :oldVal="compareOldDisplay"
26
+ :newVal="getShowValue()"
27
+ >
28
+ <slot></slot>
29
+ </compareView>
30
+ <slot v-else></slot>
22
31
  </template>
23
32
  <template
24
33
  v-else-if="
@@ -55,7 +64,16 @@
55
64
  </div>
56
65
  </template>
57
66
  <template v-else>
58
- <span>{{ getShowValue() }}</span>
67
+ <compareView
68
+ v-if="isCompareOn"
69
+ :isCompare="isCompareOn"
70
+ :isDiff="compareIsDiff"
71
+ :oldVal="compareOldDisplay"
72
+ :newVal="getShowValue()"
73
+ >
74
+ <span>{{ getShowValue() }}</span>
75
+ </compareView>
76
+ <span v-else>{{ getShowValue() }}</span>
59
77
  </template>
60
78
  </template>
61
79
  </template>
@@ -129,7 +147,16 @@
129
147
  {{ label }}
130
148
  </span>
131
149
  <template v-if="isShowWidget()">
132
- <slot></slot>
150
+ <compareView
151
+ v-if="isCompareOn"
152
+ :isCompare="isCompareOn"
153
+ :isDiff="compareIsDiff"
154
+ :oldVal="compareOldDisplay"
155
+ :newVal="getShowValue()"
156
+ >
157
+ <slot></slot>
158
+ </compareView>
159
+ <slot v-else></slot>
133
160
  </template>
134
161
  <template
135
162
  v-else-if="
@@ -162,7 +189,16 @@
162
189
  </div>
163
190
  </template>
164
191
  <template v-else>
165
- <span>{{ getShowValue() }}</span>
192
+ <compareView
193
+ v-if="isCompareOn"
194
+ :isCompare="isCompareOn"
195
+ :isDiff="compareIsDiff"
196
+ :oldVal="compareOldDisplay"
197
+ :newVal="getShowValue()"
198
+ >
199
+ <span>{{ getShowValue() }}</span>
200
+ </compareView>
201
+ <span v-else>{{ getShowValue() }}</span>
166
202
  </template>
167
203
  </el-form-item>
168
204
  </template>
@@ -216,10 +252,12 @@ import {
216
252
  getSubFormNameByFieldId,
217
253
  isVabsearchMultiWidget,
218
254
  } from "../../../../../components/xform/utils/util";
255
+ import compareView from "../../../../../components/xform/form-render/compareView.vue";
219
256
 
220
257
  export default {
221
258
  name: "form-item-wrapper",
222
259
  mixins: [i18n],
260
+ components: { compareView },
223
261
  props: {
224
262
  field: Object,
225
263
  designer: Object,
@@ -246,15 +284,21 @@ export default {
246
284
 
247
285
  rules: Array,
248
286
  },
249
- inject: [
250
- "getFormConfig",
251
- "getSubFormFieldFlag",
252
- "getSubFormName",
253
- "tableParam",
254
- "formItemProp",
255
- "getObjectFieldFlag",
256
- "getObjectName",
257
- ],
287
+ inject: {
288
+ getFormConfig: { default: () => () => ({}) },
289
+ getSubFormFieldFlag: { default: () => () => false },
290
+ getSubFormName: { default: () => () => "" },
291
+ tableParam: { default: null },
292
+ formItemProp: { default: null },
293
+ getObjectFieldFlag: { default: () => () => false },
294
+ getObjectName: { default: () => () => "" },
295
+ // 表单对比:非对比渲染场景(如设计器)给默认值,避免注入警告
296
+ getIsCompare: { default: () => () => false },
297
+ getOldFormData: { default: () => () => ({}) },
298
+ getCompareRowKey: { default: () => () => "uuid" },
299
+ getCompareExcludeTypes: { default: () => () => [] },
300
+ isCompareExcludeField: { default: () => () => false },
301
+ },
258
302
  data() {
259
303
  return {
260
304
  encryptFormula: null,
@@ -324,6 +368,65 @@ export default {
324
368
  (!!this.parentWidget ? this.parentWidget.type === "sub-form" : false)
325
369
  );
326
370
  },
371
+
372
+ // ===================== 表单对比 =====================
373
+ compareExcluded() {
374
+ // 按类型排除
375
+ let types = this.getCompareExcludeTypes() || [];
376
+ if (types.indexOf(this.field.type) !== -1) return true;
377
+ // 按字段名排除(系统审计字段 + 业务配置 compareExcludeFields)
378
+ let fieldKeyName =
379
+ (this.field.options.keyNameEnabled && this.field.options.keyName) ||
380
+ this.field.options.name;
381
+ return !!this.isCompareExcludeField(fieldKeyName);
382
+ },
383
+ isCompareOn() {
384
+ return !this.designer && !this.compareExcluded && !!this.getIsCompare();
385
+ },
386
+ // 原单的行/主表对象(供关联类组件取伴随 label 字段)
387
+ compareOldRow() {
388
+ // 表格/子表单行内字段:取该行 hData 快照
389
+ if (this.tableParam && this.tableParam.row) {
390
+ return this.tableParam.row.hData || null;
391
+ }
392
+ // 主表字段
393
+ return this.getOldFormData() || null;
394
+ },
395
+ compareOldRaw() {
396
+ let property =
397
+ (this.field.options.keyNameEnabled && this.field.options.keyName) ||
398
+ this.field.options.name;
399
+ let row = this.compareOldRow;
400
+ return row ? row[property] : null;
401
+ },
402
+ compareNewRaw() {
403
+ return this.$parent ? this.$parent.fieldModel : null;
404
+ },
405
+ // 表格新增行(无原单匹配,hData 为空或缺失):整行标识,不逐单元格显示感叹号
406
+ compareRowIsNew() {
407
+ if (!this.tableParam || !this.tableParam.row) return false;
408
+ let hData = this.tableParam.row.hData;
409
+ return !hData || Object.keys(hData).length === 0;
410
+ },
411
+ compareIsDiff() {
412
+ if (!this.isCompareOn) return false;
413
+ if (this.compareRowIsNew) return false;
414
+ let eq =
415
+ this.$parent && this.$parent.compareEquals
416
+ ? this.$parent.compareEquals(this.compareOldRaw, this.compareNewRaw)
417
+ : this.compareOldRaw === this.compareNewRaw;
418
+ return !eq;
419
+ },
420
+ compareOldDisplay() {
421
+ // 优先用 resolveCompareOldDisplay(可从 oldRow 取关联类的伴随 label 字段)
422
+ if (this.$parent && this.$parent.resolveCompareOldDisplay) {
423
+ return this.$parent.resolveCompareOldDisplay(this.compareOldRow);
424
+ }
425
+ if (this.$parent && this.$parent.resolveDisplayValue) {
426
+ return this.$parent.resolveDisplayValue(this.compareOldRaw);
427
+ }
428
+ return this.compareOldRaw;
429
+ },
327
430
  },
328
431
  created() {
329
432
  //
@@ -182,6 +182,11 @@ export default {
182
182
  fieldModelLabel() {
183
183
  return this.displayValue;
184
184
  },
185
+ // 对比旧值:label 存在原单同行的伴随字段(displayField),从 oldRow 取
186
+ resolveCompareOldDisplay(oldRow) {
187
+ if (!oldRow) return null;
188
+ return oldRow[this.displayField] ?? null;
189
+ },
185
190
  /**
186
191
  * 远程搜索:调用后台逻辑脚本,返回建议列表
187
192
  * el-autocomplete 的 fetch-suggestions 回调签名 (queryString, callback)
@@ -175,5 +175,18 @@ export default {
175
175
  fieldModelLabel() {
176
176
  return this.showValue;
177
177
  },
178
+ // 对比旧值:label 存在原单同行的伴随字段(vabSearchName),从 oldRow 取
179
+ resolveCompareOldDisplay(oldRow) {
180
+ if (!oldRow) return null;
181
+ let labelField = this.field.options.vabSearchName || this.fieldKeyName;
182
+ let multipleChoices = this.field.options.multipleChoices || false;
183
+ if (multipleChoices) {
184
+ let arr = oldRow[this.fieldKeyName];
185
+ return Array.isArray(arr)
186
+ ? arr.map((item) => item && item[labelField]).join(",")
187
+ : null;
188
+ }
189
+ return oldRow[labelField] ?? null;
190
+ },
178
191
  }
179
192
  }
@@ -149,6 +149,17 @@ export default {
149
149
  }
150
150
  return label;
151
151
  },
152
+ // 对比展示:按 statusParam 做 value→label(status 用 statusParam 而非 optionItems)
153
+ resolveDisplayValue(rawValue) {
154
+ if (rawValue === null || rawValue === undefined || rawValue === "") {
155
+ return rawValue;
156
+ }
157
+ let valueField = this.valueField;
158
+ let labelField = this.labelField;
159
+ let list = this.field.options.statusParam || [];
160
+ let item = list.find((it) => it[valueField] === rawValue);
161
+ return item ? this.getI18nLabel(item[labelField]) : rawValue;
162
+ },
152
163
  },
153
164
  };
154
165
  </script>
@@ -86,7 +86,15 @@
86
86
  },
87
87
 
88
88
  methods: {
89
-
89
+ // 对比展示:布尔值 → activeText/inactiveText
90
+ resolveDisplayValue(rawValue) {
91
+ if (rawValue === null || rawValue === undefined || rawValue === "") {
92
+ return rawValue;
93
+ }
94
+ return rawValue
95
+ ? this.field.options.activeText
96
+ : this.field.options.inactiveText;
97
+ },
90
98
  }
91
99
  }
92
100
  </script>
@@ -163,6 +163,19 @@
163
163
  </li>
164
164
  </draggable>
165
165
  </el-collapse-item>
166
+ <el-collapse-item name="compare" :title="i18nt('对比组件')">
167
+ <draggable tag="ul" :list="compareFields" :group="{name: 'dragGroup', pull: 'clone', put: false}"
168
+ :move="checkFieldMove"
169
+ :clone="handleFieldWidgetClone" ghost-class="ghost" :sort="false">
170
+ <li v-for="(fld, index) in compareFields" :key="index" class="field-widget-item"
171
+ :title="fld.displayName"
172
+ @dblclick="addFieldByDbClick(fld)">
173
+ <span><svg-icon :icon-class="fld.icon" class-name="color-svg-icon"/>
174
+ <span>{{ i18n2t(`designer.widgetLabel.${fld.type}`, `extension.widgetLabel.${fld.type}`) }}</span>
175
+ </span>
176
+ </li>
177
+ </draggable>
178
+ </el-collapse-item>
166
179
  </el-collapse>
167
180
  </el-tab-pane>
168
181
  <!-- <el-tab-pane v-if="showFormTemplates" name="formLib" style="padding: 8px">
@@ -192,12 +205,28 @@
192
205
  <script>
193
206
  import Draggable from 'vuedraggable'
194
207
  import indexMixin from './indexMixin.js';
208
+ import { compareFields } from './widgetsConfig';
195
209
 
196
210
  export default {
197
211
  name: "FieldPanel",
198
212
  mixins: [indexMixin],
199
213
  components: {
200
214
  Draggable,
215
+ },
216
+ data() {
217
+ return {
218
+ compareFields,
219
+ };
220
+ },
221
+ created() {
222
+ // 让「对比组件」分组默认展开
223
+ if (Array.isArray(this.businessActiveNames)) {
224
+ if (this.businessActiveNames.indexOf("compare") === -1) {
225
+ this.businessActiveNames.push("compare");
226
+ }
227
+ } else if (this.businessActiveNames !== "compare") {
228
+ this.businessActiveNames = [this.businessActiveNames, "compare"];
229
+ }
201
230
  }
202
231
  }
203
232
  </script>
@@ -928,7 +928,7 @@ const autocompleteConfig = {
928
928
  //condition传值格式:勾选后关键词以 { condition:[{field,value,filter:'like'}], current,size,searchCount } 结构传递
929
929
  conditionFormat: true,
930
930
  //condition格式下的分页条数
931
- conditionSize: 100,
931
+ conditionSize: 200,
932
932
  //condition格式下查询的数据表(taBm),留空则取字段本身 keyName
933
933
  conditionTaBm: null,
934
934
  prefixIcon: null,
@@ -4224,6 +4224,143 @@ export const businessFields = [
4224
4224
  },
4225
4225
  ];
4226
4226
 
4227
+ // ============== 对比组件模块(业务组件标签页下的独立分组)==============
4228
+ export const compareFields = [
4229
+ {
4230
+ type: "compare-button",
4231
+ targetType: "button",
4232
+ icon: "button",
4233
+ commonFlag: !0,
4234
+ formItemFlag: !1,
4235
+ columnFlag: true,
4236
+ options: {
4237
+ name: "",
4238
+ label: "对比",
4239
+ wfHideFlag: 1,
4240
+ columnWidth: "200px",
4241
+ size: "",
4242
+ displayStyle: "block",
4243
+ disabled: !1,
4244
+ hidden: !1,
4245
+ type: "default",
4246
+ plain: !1,
4247
+ round: !1,
4248
+ circle: !1,
4249
+ icon: null,
4250
+ customClass: "",
4251
+ onCreated: "",
4252
+ onMounted: "",
4253
+ onClick:
4254
+ "this.getFormRef().getGlobalConfig().enableCompareBySource(this)",
4255
+ accessType: "1",
4256
+ clickBindEvent: null,
4257
+ onBeforeClickButton: null,
4258
+ searchDialogConfig: {
4259
+ ...defaultSearchDialogConfig,
4260
+ },
4261
+ addTableDataConfig: {
4262
+ tableRef: null,
4263
+ tableData: {},
4264
+ },
4265
+ ...defaultWfConfig,
4266
+ hiddenByWf: true,
4267
+ ...defaultWidgetShowRuleConfig,
4268
+
4269
+ showRuleFlag: 1,
4270
+ showRuleEnabled: 1,
4271
+ showRules: [],
4272
+ },
4273
+ },
4274
+ {
4275
+ type: "compare-close-button",
4276
+ targetType: "button",
4277
+ icon: "button",
4278
+ commonFlag: !0,
4279
+ formItemFlag: !1,
4280
+ columnFlag: true,
4281
+ options: {
4282
+ name: "",
4283
+ label: "关闭对比",
4284
+ wfHideFlag: 1,
4285
+ columnWidth: "200px",
4286
+ size: "",
4287
+ displayStyle: "block",
4288
+ disabled: !1,
4289
+ hidden: !0, // 默认隐藏,开启对比后由 handleCompareButton 放出
4290
+ type: "default",
4291
+ plain: !1,
4292
+ round: !1,
4293
+ circle: !1,
4294
+ icon: null,
4295
+ customClass: "",
4296
+ onCreated: "",
4297
+ onMounted: "",
4298
+ onClick: "this.getFormRef().getGlobalConfig().disableCompare(this)",
4299
+ accessType: "1",
4300
+ clickBindEvent: null,
4301
+ onBeforeClickButton: null,
4302
+ searchDialogConfig: {
4303
+ ...defaultSearchDialogConfig,
4304
+ },
4305
+ addTableDataConfig: {
4306
+ tableRef: null,
4307
+ tableData: {},
4308
+ },
4309
+ ...defaultWfConfig,
4310
+ hiddenByWf: true,
4311
+ ...defaultWidgetShowRuleConfig,
4312
+
4313
+ showRuleFlag: 1,
4314
+ showRuleEnabled: 1,
4315
+ showRules: [],
4316
+ },
4317
+ },
4318
+ {
4319
+ type: "compare-del-button",
4320
+ targetType: "button",
4321
+ icon: "button",
4322
+ commonFlag: !0,
4323
+ formItemFlag: !1,
4324
+ columnFlag: true,
4325
+ options: {
4326
+ name: "",
4327
+ label: "查看删除明细",
4328
+ wfHideFlag: 1,
4329
+ columnWidth: "200px",
4330
+ size: "",
4331
+ displayStyle: "block",
4332
+ disabled: !1,
4333
+ hidden: !0, // 默认隐藏,开启对比后由 handleCompareButton 放出
4334
+ type: "default",
4335
+ plain: !1,
4336
+ round: !1,
4337
+ circle: !1,
4338
+ icon: null,
4339
+ customClass: "",
4340
+ onCreated: "",
4341
+ onMounted: "",
4342
+ onClick: "this.getFormRef().openCompareDelList('明细表keyName')",
4343
+ accessType: "1",
4344
+ clickBindEvent: null,
4345
+ onBeforeClickButton: null,
4346
+ searchDialogConfig: {
4347
+ ...defaultSearchDialogConfig,
4348
+ },
4349
+ addTableDataConfig: {
4350
+ tableRef: null,
4351
+ tableData: {},
4352
+ },
4353
+ ...defaultWfConfig,
4354
+ hiddenByWf: true,
4355
+ ...defaultWidgetShowRuleConfig,
4356
+
4357
+ showRuleFlag: 1,
4358
+ showRuleEnabled: 1,
4359
+ showRules: [],
4360
+ },
4361
+ },
4362
+ ];
4363
+
4227
4364
  export const keyNamePrefixMap = {
4228
4365
  vabUpload: "attachments_",
4229
4366
  baseAttachment: "attachments_",
@@ -0,0 +1,83 @@
1
+ <!--
2
+ /**
3
+ * 对比 - 查看删除数据弹窗
4
+ * option: { subFormName, columns:[{ title, field }], data:[...] }
5
+ * columns 为空时按首行数据的 key 自动生成列。
6
+ */
7
+ -->
8
+ <template>
9
+ <el-dialog
10
+ custom-class="dialog-style list-dialog dialog-checkbox pd_0"
11
+ :title="$t1('查看删除数据')"
12
+ :visible="visiable"
13
+ width="70%"
14
+ append-to-body
15
+ :modal-append-to-body="true"
16
+ :close-on-click-modal="false"
17
+ @close="handleClose"
18
+ v-el-drag-dialog
19
+ v-el-dialog-center
20
+ >
21
+ <div class="cont" style="height: 450px">
22
+ <vxe-grid
23
+ border
24
+ size="mini"
25
+ height="425px"
26
+ auto-resize
27
+ :columns="gridColumns"
28
+ :data="rows"
29
+ />
30
+ </div>
31
+ </el-dialog>
32
+ </template>
33
+
34
+ <script>
35
+ export default {
36
+ name: "CompareDelList",
37
+ props: {
38
+ visiable: { type: Boolean, default: false },
39
+ option: { type: Object, default: () => ({}) },
40
+ },
41
+ computed: {
42
+ rows() {
43
+ return (this.option && this.option.data) || [];
44
+ },
45
+ cols() {
46
+ let columns = (this.option && this.option.columns) || [];
47
+ if (columns.length) return columns;
48
+ // 无列配置时按首行 key 自动生成(排除内部字段)
49
+ let first = this.rows[0] || {};
50
+ return Object.keys(first)
51
+ .filter((k) => k !== "hData" && !k.startsWith("_"))
52
+ .map((k) => ({ field: k, title: k }));
53
+ },
54
+ // vxe-grid 列:序号列 + 业务列
55
+ gridColumns() {
56
+ let seq = {
57
+ type: "seq",
58
+ title: this.$t1("序号"),
59
+ width: 90,
60
+ align: "center",
61
+ };
62
+ let cols = this.cols.map((c) => {
63
+ let col = {
64
+ field: c.field,
65
+ title: c.title,
66
+ showOverflow: "tooltip",
67
+ };
68
+ // 沿用当前数据表格的列宽;都没有时给个最小宽度兜底
69
+ if (c.width) col.width = c.width;
70
+ if (c.minWidth) col.minWidth = c.minWidth;
71
+ if (!c.width && !c.minWidth) col.minWidth = 120;
72
+ return col;
73
+ });
74
+ return [seq].concat(cols);
75
+ },
76
+ },
77
+ methods: {
78
+ handleClose() {
79
+ this.$emit("update:visiable", false);
80
+ },
81
+ },
82
+ };
83
+ </script>
@@ -0,0 +1,76 @@
1
+ <!--
2
+ /**
3
+ * 表单对比提示组件
4
+ * 差异判定(isDiff)由字段侧(fieldMixin.compareEquals)算好传入,本组件不做裸值比较;
5
+ * oldVal 传入的是已解析的展示文本(label),用于 popover 展示"变更前"值。
6
+ * 注意:DOM 顺序里 slot 必须始终在前(index 0),图标为其后的条件兄弟节点,
7
+ * 否则 isDiff 切换时按索引 patch 会重建 slot 内的 input,导致手动输入时失焦。
8
+ * 视觉上用 flex order 把图标排到输入框前面。
9
+ */
10
+ -->
11
+ <template>
12
+ <span class="xform-compare-view">
13
+ <span class="xform-compare-slot"><slot></slot></span>
14
+ <span v-if="isCompare && isDiff" class="xform-compare-icon-wrap">
15
+ <el-popover placement="top-start" width="200" trigger="hover">
16
+ <div class="xform-compare-old">
17
+ {{ $t1("变更前") }}:{{ displayOldVal }}
18
+ </div>
19
+ <span slot="reference" class="xform-compare-icon">
20
+ <i class="el-icon-warning"></i>
21
+ </span>
22
+ </el-popover>
23
+ </span>
24
+ </span>
25
+ </template>
26
+
27
+ <script>
28
+ export default {
29
+ name: "CompareView",
30
+ props: {
31
+ isCompare: { type: Boolean, default: false },
32
+ isDiff: { type: Boolean, default: false },
33
+ oldVal: { default: null },
34
+ newVal: { default: null },
35
+ },
36
+ computed: {
37
+ displayOldVal() {
38
+ let v = this.oldVal;
39
+ if (v === null || v === undefined || v === "") return this.$t1("(空)");
40
+ return v;
41
+ },
42
+ },
43
+ };
44
+ </script>
45
+
46
+ <style scoped>
47
+ /* 对比态用 flex;图标固定在输入框前面(左侧),输入框占满剩余宽度 */
48
+ .xform-compare-view {
49
+ display: flex;
50
+ align-items: center;
51
+ width: 100%;
52
+ }
53
+ /* DOM 在前但视觉排到后面,输入框自适应占满 */
54
+ .xform-compare-slot {
55
+ order: 1;
56
+ flex: 1 1 auto;
57
+ min-width: 0;
58
+ }
59
+ /* DOM 在后但视觉排到前面 */
60
+ .xform-compare-icon-wrap {
61
+ order: 0;
62
+ flex: 0 0 auto;
63
+ margin-right: 4px;
64
+ line-height: 1;
65
+ }
66
+ .xform-compare-icon {
67
+ color: #e6a23c;
68
+ font-size: 14px;
69
+ line-height: 1;
70
+ cursor: pointer;
71
+ }
72
+ .xform-compare-old {
73
+ font-size: 12px;
74
+ word-break: break-all;
75
+ }
76
+ </style>