@tmagic/form 1.8.0-beta.0 → 1.8.0-beta.2

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.
@@ -38,6 +38,9 @@
38
38
  //#endregion
39
39
  dayjs = __toESM(dayjs, 1);
40
40
  dayjs_plugin_utc = __toESM(dayjs_plugin_utc, 1);
41
+ //#region packages/form/src/schema.ts
42
+ var FORM_DIFF_CONFIG_KEY = Symbol("mFormDiffConfig");
43
+ //#endregion
41
44
  //#region node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_freeGlobal.js
42
45
  /** Detect free variable `global` from Node.js. */
43
46
  var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
@@ -2889,7 +2892,8 @@
2889
2892
  var _hoisted_5$3 = ["innerHTML"];
2890
2893
  var _hoisted_6$1 = ["innerHTML"];
2891
2894
  var _hoisted_7$1 = ["innerHTML"];
2892
- var _hoisted_8$1 = {
2895
+ var _hoisted_8$1 = ["innerHTML"];
2896
+ var _hoisted_9 = {
2893
2897
  key: 5,
2894
2898
  style: { "text-align": "center" }
2895
2899
  };
@@ -2921,11 +2925,20 @@
2921
2925
  const props = __props;
2922
2926
  const emit = __emit;
2923
2927
  const mForm = (0, vue.inject)("mForm");
2928
+ const diffConfig = (0, vue.inject)(FORM_DIFF_CONFIG_KEY, {});
2924
2929
  const expand = (0, vue.ref)(false);
2925
2930
  const name = (0, vue.computed)(() => props.config.name || "");
2926
2931
  const showDiff = (0, vue.computed)(() => {
2927
2932
  if (!props.isCompare) return false;
2928
- return !isEqual(name.value ? props.model[name.value] : props.model, name.value ? props.lastValues[name.value] : props.lastValues);
2933
+ const curValue = name.value ? props.model[name.value] : props.model;
2934
+ const lastValue = name.value ? props.lastValues[name.value] : props.lastValues;
2935
+ const customShowDiff = diffConfig.showDiff;
2936
+ if (typeof customShowDiff === "function") return Boolean(customShowDiff({
2937
+ curValue,
2938
+ lastValue,
2939
+ config: props.config
2940
+ }));
2941
+ return !isEqual(curValue, lastValue);
2929
2942
  });
2930
2943
  const items = (0, vue.computed)(() => props.config.items);
2931
2944
  const itemProp = (0, vue.computed)(() => {
@@ -2946,6 +2959,35 @@
2946
2959
  if (type.value === "component" && props.config.component) return props.config.component;
2947
2960
  return getField(type.value || "container") || `m-${items.value ? "form" : "fields"}-${type.value}`;
2948
2961
  });
2962
+ /**
2963
+ * 自接管对比的字段类型白名单。
2964
+ *
2965
+ * 这类字段在 `isCompare === true` 且存在差异时,不再由 Container 渲染前后两份独立组件来对比,
2966
+ * 而是只渲染一次组件,将 `model` / `lastValues` / `isCompare` 一并传给字段组件,
2967
+ * 由字段组件内部自行展示前后差异(典型场景:vs-code 字段使用 monaco 自带的 diff 编辑器)。
2968
+ *
2969
+ * 这样做的好处:
2970
+ * 1. 避免重型字段(如 monaco 编辑器)在对比模式下被实例化两次,节省资源;
2971
+ * 2. 提供更专业的对比视觉效果(如 monaco diff 的行级高亮、左右滚动同步等)。
2972
+ *
2973
+ * 注意:像 `event-select` / `code-select-col` 这类内部由列表 / 嵌套子表单组成的复合字段,若按默认逻辑
2974
+ * 渲染前后两份独立组件,会出现两套下拉框 + 两份参数表单(或两套「添加事件」按钮、两份完整面板),
2975
+ * 体验很差。这类字段在内部把 `is-compare`/`lastValues` 透传给子级容器,由子级逐项展示差异,
2976
+ * 因此同样归类为自接管对比字段。
2977
+ */
2978
+ const DEFAULT_SELF_DIFF_FIELD_TYPES = [
2979
+ "vs-code",
2980
+ "event-select",
2981
+ "code-select-col",
2982
+ "code-select"
2983
+ ];
2984
+ const effectiveSelfDiffFieldTypes = (0, vue.computed)(() => {
2985
+ const custom = diffConfig.selfDiffFieldTypes;
2986
+ if (typeof custom === "function") return new Set(custom([...DEFAULT_SELF_DIFF_FIELD_TYPES]));
2987
+ if (Array.isArray(custom)) return new Set([...DEFAULT_SELF_DIFF_FIELD_TYPES, ...custom]);
2988
+ return new Set(DEFAULT_SELF_DIFF_FIELD_TYPES);
2989
+ });
2990
+ const isSelfDiffField = (0, vue.computed)(() => effectiveSelfDiffFieldTypes.value.has(type.value));
2949
2991
  const disabled = (0, vue.computed)(() => props.disabled || filterFunction(mForm, props.config.disabled, props));
2950
2992
  const text = (0, vue.computed)(() => filterFunction(mForm, props.config.text, props));
2951
2993
  const tooltip = (0, vue.computed)(() => {
@@ -3114,7 +3156,13 @@
3114
3156
  "label-width",
3115
3157
  "style"
3116
3158
  ])) : type.value && display$3.value && !showDiff.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)(formItemProps.value, { class: { "tmagic-form-hidden": `${itemLabelWidth.value}` === "0" || !text.value } }), {
3117
- label: (0, vue.withCtx)(() => [(0, vue.createVNode)(FormLabel_default, {
3159
+ label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
3160
+ config: __props.config,
3161
+ type: type.value,
3162
+ text: text.value,
3163
+ prop: itemProp.value,
3164
+ disabled: disabled.value
3165
+ }, () => [(0, vue.createVNode)(FormLabel_default, {
3118
3166
  tip: __props.config.tip,
3119
3167
  type: type.value,
3120
3168
  "use-label": __props.config.useLabel,
@@ -3126,7 +3174,7 @@
3126
3174
  "use-label",
3127
3175
  "label-title",
3128
3176
  "text"
3129
- ])]),
3177
+ ])])]),
3130
3178
  default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3131
3179
  key: 0,
3132
3180
  placement: tooltip.value.placement
@@ -3155,7 +3203,7 @@
3155
3203
  "last-values",
3156
3204
  "is-compare"
3157
3205
  ]))]),
3158
- _: 1
3206
+ _: 3
3159
3207
  }, 16, ["class"]), __props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3160
3208
  key: 0,
3161
3209
  placement: "top"
@@ -3171,12 +3219,18 @@
3171
3219
  _: 1
3172
3220
  })) : (0, vue.createCommentVNode)("v-if", true)], 64)) : type.value && display$3.value && showDiff.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 3 }, [
3173
3221
  (0, vue.createCommentVNode)(" 对比 "),
3174
- (0, vue.createCommentVNode)(" 上次内容 "),
3175
- (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)(formItemProps.value, { class: {
3222
+ (0, vue.createCommentVNode)(" 自接管对比的字段类型(如 vs-code):只渲染一次组件,由字段内部用 diff 编辑器/视图自行展示前后差异 "),
3223
+ isSelfDiffField.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)({ key: 0 }, formItemProps.value, { class: {
3176
3224
  "tmagic-form-hidden": `${itemLabelWidth.value}` === "0" || !text.value,
3177
- "show-diff": true
3225
+ "self-diff": true
3178
3226
  } }), {
3179
- label: (0, vue.withCtx)(() => [(0, vue.createVNode)(FormLabel_default, {
3227
+ label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
3228
+ config: __props.config,
3229
+ type: type.value,
3230
+ text: text.value,
3231
+ prop: itemProp.value,
3232
+ disabled: disabled.value
3233
+ }, () => [(0, vue.createVNode)(FormLabel_default, {
3180
3234
  tip: __props.config.tip,
3181
3235
  type: type.value,
3182
3236
  "use-label": __props.config.useLabel,
@@ -3188,88 +3242,148 @@
3188
3242
  "use-label",
3189
3243
  "label-title",
3190
3244
  "text"
3191
- ])]),
3245
+ ])])]),
3192
3246
  default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3193
3247
  key: 0,
3194
3248
  placement: tooltip.value.placement
3195
3249
  }, {
3196
3250
  content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_4$4)]),
3197
3251
  default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
3198
- model: __props.lastValues,
3252
+ model: __props.model,
3253
+ "last-values": __props.lastValues,
3254
+ "is-compare": __props.isCompare,
3199
3255
  onChange: onChangeHandler
3200
- }), null, 16, ["model"]))]),
3256
+ }), null, 16, [
3257
+ "model",
3258
+ "last-values",
3259
+ "is-compare"
3260
+ ]))]),
3201
3261
  _: 1
3202
3262
  }, 8, ["placement"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
3203
- model: __props.lastValues,
3263
+ model: __props.model,
3264
+ "last-values": __props.lastValues,
3265
+ "is-compare": __props.isCompare,
3204
3266
  onChange: onChangeHandler
3205
- }), null, 16, ["model"]))]),
3206
- _: 1
3207
- }, 16, ["class"]),
3208
- __props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3209
- key: 0,
3210
- placement: "top"
3211
- }, {
3212
- content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: __props.config.tip }, null, 8, _hoisted_5$3)]),
3213
- default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicIcon), { style: {
3214
- "line-height": "40px",
3215
- "margin-left": "5px"
3216
- } }, {
3217
- default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_element_plus_icons_vue.WarningFilled))]),
3218
- _: 1
3219
- })]),
3220
- _: 1
3221
- })) : (0, vue.createCommentVNode)("v-if", true),
3222
- (0, vue.createCommentVNode)(" 当前内容 "),
3223
- (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)(formItemProps.value, {
3224
- style: __props.config.tip ? "flex: 1" : "",
3225
- class: {
3267
+ }), null, 16, [
3268
+ "model",
3269
+ "last-values",
3270
+ "is-compare"
3271
+ ]))]),
3272
+ _: 3
3273
+ }, 16, ["class"])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [
3274
+ (0, vue.createCommentVNode)(" 普通字段:渲染前后两份独立的组件用于对比 "),
3275
+ (0, vue.createCommentVNode)(" 上次内容 "),
3276
+ (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)(formItemProps.value, { class: {
3226
3277
  "tmagic-form-hidden": `${itemLabelWidth.value}` === "0" || !text.value,
3227
- "show-diff": true
3228
- }
3229
- }), {
3230
- label: (0, vue.withCtx)(() => [(0, vue.createVNode)(FormLabel_default, {
3231
- tip: __props.config.tip,
3232
- type: type.value,
3233
- "use-label": __props.config.useLabel,
3234
- "label-title": __props.config.labelTitle,
3235
- text: text.value
3236
- }, null, 8, [
3237
- "tip",
3238
- "type",
3239
- "use-label",
3240
- "label-title",
3241
- "text"
3242
- ])]),
3243
- default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3278
+ "show-before-diff": true
3279
+ } }), {
3280
+ label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
3281
+ config: __props.config,
3282
+ type: type.value,
3283
+ text: text.value,
3284
+ prop: itemProp.value,
3285
+ disabled: disabled.value
3286
+ }, () => [(0, vue.createVNode)(FormLabel_default, {
3287
+ tip: __props.config.tip,
3288
+ type: type.value,
3289
+ "use-label": __props.config.useLabel,
3290
+ "label-title": __props.config.labelTitle,
3291
+ text: text.value
3292
+ }, null, 8, [
3293
+ "tip",
3294
+ "type",
3295
+ "use-label",
3296
+ "label-title",
3297
+ "text"
3298
+ ])])]),
3299
+ default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3300
+ key: 0,
3301
+ placement: tooltip.value.placement
3302
+ }, {
3303
+ content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$3)]),
3304
+ default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
3305
+ model: __props.lastValues,
3306
+ onChange: onChangeHandler
3307
+ }), null, 16, ["model"]))]),
3308
+ _: 1
3309
+ }, 8, ["placement"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
3310
+ model: __props.lastValues,
3311
+ onChange: onChangeHandler
3312
+ }), null, 16, ["model"]))]),
3313
+ _: 3
3314
+ }, 16, ["class"]),
3315
+ __props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3244
3316
  key: 0,
3245
- placement: tooltip.value.placement
3317
+ placement: "top"
3246
3318
  }, {
3247
- content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_6$1)]),
3248
- default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
3319
+ content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: __props.config.tip }, null, 8, _hoisted_6$1)]),
3320
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicIcon), { style: {
3321
+ "line-height": "40px",
3322
+ "margin-left": "5px"
3323
+ } }, {
3324
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_element_plus_icons_vue.WarningFilled))]),
3325
+ _: 1
3326
+ })]),
3327
+ _: 1
3328
+ })) : (0, vue.createCommentVNode)("v-if", true),
3329
+ (0, vue.createCommentVNode)(" 当前内容 "),
3330
+ (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)(formItemProps.value, {
3331
+ style: __props.config.tip ? "flex: 1" : "",
3332
+ class: {
3333
+ "tmagic-form-hidden": `${itemLabelWidth.value}` === "0" || !text.value,
3334
+ "show-after-diff": true
3335
+ }
3336
+ }), {
3337
+ label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
3338
+ config: __props.config,
3339
+ type: type.value,
3340
+ text: text.value,
3341
+ prop: itemProp.value,
3342
+ disabled: disabled.value
3343
+ }, () => [(0, vue.createVNode)(FormLabel_default, {
3344
+ tip: __props.config.tip,
3345
+ type: type.value,
3346
+ "use-label": __props.config.useLabel,
3347
+ "label-title": __props.config.labelTitle,
3348
+ text: text.value
3349
+ }, null, 8, [
3350
+ "tip",
3351
+ "type",
3352
+ "use-label",
3353
+ "label-title",
3354
+ "text"
3355
+ ])])]),
3356
+ default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3357
+ key: 0,
3358
+ placement: tooltip.value.placement
3359
+ }, {
3360
+ content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_7$1)]),
3361
+ default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
3362
+ model: __props.model,
3363
+ onChange: onChangeHandler
3364
+ }), null, 16, ["model"]))]),
3365
+ _: 1
3366
+ }, 8, ["placement"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
3249
3367
  model: __props.model,
3250
3368
  onChange: onChangeHandler
3251
3369
  }), null, 16, ["model"]))]),
3370
+ _: 3
3371
+ }, 16, ["style", "class"]),
3372
+ __props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3373
+ key: 1,
3374
+ placement: "top"
3375
+ }, {
3376
+ content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: __props.config.tip }, null, 8, _hoisted_8$1)]),
3377
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicIcon), { style: {
3378
+ "line-height": "40px",
3379
+ "margin-left": "5px"
3380
+ } }, {
3381
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_element_plus_icons_vue.WarningFilled))]),
3382
+ _: 1
3383
+ })]),
3252
3384
  _: 1
3253
- }, 8, ["placement"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
3254
- model: __props.model,
3255
- onChange: onChangeHandler
3256
- }), null, 16, ["model"]))]),
3257
- _: 1
3258
- }, 16, ["style", "class"]),
3259
- __props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
3260
- key: 1,
3261
- placement: "top"
3262
- }, {
3263
- content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: __props.config.tip }, null, 8, _hoisted_7$1)]),
3264
- default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicIcon), { style: {
3265
- "line-height": "40px",
3266
- "margin-left": "5px"
3267
- } }, {
3268
- default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_element_plus_icons_vue.WarningFilled))]),
3269
- _: 1
3270
- })]),
3271
- _: 1
3272
- })) : (0, vue.createCommentVNode)("v-if", true)
3385
+ })) : (0, vue.createCommentVNode)("v-if", true)
3386
+ ], 64))
3273
3387
  ], 64)) : items.value && display$3.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 4 }, [(isValidName() ? __props.model[name.value] : __props.model) ? ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, (0, vue.renderList)(items.value, (item) => {
3274
3388
  return (0, vue.openBlock)(), (0, vue.createBlock)(_component_Container, {
3275
3389
  key: key(item),
@@ -3285,7 +3399,11 @@
3285
3399
  prop: itemProp.value,
3286
3400
  onChange: onChangeHandler,
3287
3401
  onAddDiffCount
3288
- }, null, 8, [
3402
+ }, (0, vue.createSlots)({ _: 2 }, [_ctx.$slots.label ? {
3403
+ name: "label",
3404
+ fn: (0, vue.withCtx)((labelProps) => [(0, vue.renderSlot)(_ctx.$slots, "label", (0, vue.mergeProps)({ ref_for: true }, labelProps))]),
3405
+ key: "0"
3406
+ } : void 0]), 1032, [
3289
3407
  "model",
3290
3408
  "last-values",
3291
3409
  "is-compare",
@@ -3297,7 +3415,7 @@
3297
3415
  "label-width",
3298
3416
  "prop"
3299
3417
  ]);
3300
- }), 128)) : (0, vue.createCommentVNode)("v-if", true)], 64)) : (0, vue.createCommentVNode)("v-if", true), __props.config.expand && type.value !== "fieldset" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8$1, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
3418
+ }), 128)) : (0, vue.createCommentVNode)("v-if", true)], 64)) : (0, vue.createCommentVNode)("v-if", true), __props.config.expand && type.value !== "fieldset" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_9, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
3301
3419
  type: "primary",
3302
3420
  size: "small",
3303
3421
  disabled: false,
@@ -3340,7 +3458,9 @@
3340
3458
  keyProp: { default: "__key" },
3341
3459
  popperClass: {},
3342
3460
  preventSubmitDefault: { type: Boolean },
3343
- extendState: {}
3461
+ extendState: {},
3462
+ showDiff: {},
3463
+ selfDiffFieldTypes: {}
3344
3464
  },
3345
3465
  emits: [
3346
3466
  "change",
@@ -3358,14 +3478,45 @@
3358
3478
  const lastValuesProcessed = (0, vue.ref)({});
3359
3479
  const fields = /* @__PURE__ */ new Map();
3360
3480
  const requestFuc = getConfig("request");
3481
+ /**
3482
+ * formState 实现说明:
3483
+ *
3484
+ * 1. 与 props 直接对应的字段(config / initValues / lastValues / isCompare / parentValues /
3485
+ * keyProp / popperClass)使用「访问器(getter)」定义,每次读取都会回到 `props.xxx`
3486
+ * 取最新值,不存在「props 变了但 formState 还没同步过来」的中间态。
3487
+ *
3488
+ * 2. `values` / `lastValuesProcessed` 是 ref,Vue 的 `reactive` 会自动解包,因此每次
3489
+ * 访问 `formState.values` / `formState.lastValuesProcessed` 也都是当前 ref 值。
3490
+ *
3491
+ * 3. `extendState` 注入的字段在下方的 `watchEffect` 中合并到 `formState`:
3492
+ * - data 描述符(普通字段)通过 `formState[key] = value` 写入,走 reactive proxy 的
3493
+ * set,触发依赖通知;`extendState` 同步段读到的响应式数据变化时会自动重跑,
3494
+ * 把最新值刷进 formState。
3495
+ * - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
3496
+ * 读时求值,每次读取都会重新执行 getter。
3497
+ */
3361
3498
  const formState = (0, vue.reactive)({
3362
- keyProp: props.keyProp,
3363
- popperClass: props.popperClass,
3364
- config: props.config,
3365
- initValues: props.initValues,
3366
- isCompare: props.isCompare,
3367
- lastValues: props.lastValues,
3368
- parentValues: props.parentValues,
3499
+ get keyProp() {
3500
+ return props.keyProp;
3501
+ },
3502
+ get popperClass() {
3503
+ return props.popperClass;
3504
+ },
3505
+ get config() {
3506
+ return props.config;
3507
+ },
3508
+ get initValues() {
3509
+ return props.initValues;
3510
+ },
3511
+ get isCompare() {
3512
+ return props.isCompare;
3513
+ },
3514
+ get lastValues() {
3515
+ return props.lastValues;
3516
+ },
3517
+ get parentValues() {
3518
+ return props.parentValues;
3519
+ },
3369
3520
  values,
3370
3521
  lastValuesProcessed,
3371
3522
  $emit: emit,
@@ -3382,22 +3533,57 @@
3382
3533
  });
3383
3534
  }
3384
3535
  });
3385
- (0, vue.watchEffect)(async () => {
3386
- formState.initValues = props.initValues;
3387
- formState.lastValues = props.lastValues;
3388
- formState.isCompare = props.isCompare;
3389
- formState.config = props.config;
3390
- formState.keyProp = props.keyProp;
3391
- formState.popperClass = props.popperClass;
3392
- formState.parentValues = props.parentValues;
3393
- if (typeof props.extendState === "function") {
3394
- const state = await props.extendState(formState) || {};
3395
- Object.entries(state).forEach(([key, value]) => {
3396
- formState[key] = value;
3397
- });
3536
+ /**
3537
+ * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
3538
+ * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
3539
+ *
3540
+ * extendState: (formState) => ({
3541
+ * username: store.username, // 同步读 store,会被跟踪
3542
+ * env: store.env,
3543
+ * })
3544
+ *
3545
+ * `store.username` 变化时,整个 effect 重跑,新值会被刷进 `formState`。
3546
+ *
3547
+ * prop 派生字段(initValues / config / ...)已经在上方用 getter 定义,
3548
+ * 这里不再重复同步;因此 `props.initValues` 这类高频变化也不会再触发
3549
+ * `extendState` 重跑(旧版的性能问题修复点)。
3550
+ *
3551
+ * 实现细节:
3552
+ * - data 描述符:通过 `formState[key] = value` 走 reactive proxy 的 set,
3553
+ * 触发依赖通知;与旧版「逐项赋值」语义完全等价。
3554
+ * - accessor 描述符(`{ get stage() {...} }`)按原样写入 formState,调用方
3555
+ * 可以自行控制读时求值;强制 `configurable: true` 以便下一次重跑可再 define。
3556
+ */
3557
+ (0, vue.watchEffect)(async (onCleanup) => {
3558
+ const { extendState } = props;
3559
+ if (typeof extendState !== "function") return;
3560
+ let stale = false;
3561
+ onCleanup(() => {
3562
+ stale = true;
3563
+ });
3564
+ let state = {};
3565
+ try {
3566
+ state = await extendState(formState) || {};
3567
+ } catch (e) {
3568
+ console.error("[MForm] extendState failed:", e);
3569
+ return;
3570
+ }
3571
+ if (stale) return;
3572
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) if ("value" in descriptor) formState[key] = state[key];
3573
+ else {
3574
+ descriptor.configurable = true;
3575
+ Object.defineProperty(formState, key, descriptor);
3398
3576
  }
3399
3577
  });
3400
3578
  (0, vue.provide)("mForm", formState);
3579
+ (0, vue.provide)(FORM_DIFF_CONFIG_KEY, {
3580
+ get showDiff() {
3581
+ return props.showDiff;
3582
+ },
3583
+ get selfDiffFieldTypes() {
3584
+ return props.selfDiffFieldTypes;
3585
+ }
3586
+ });
3401
3587
  const changeRecords = (0, vue.shallowRef)([]);
3402
3588
  (0, vue.watch)([() => props.config, () => props.initValues], ([config], [preConfig]) => {
3403
3589
  changeRecords.value = [];
@@ -3514,7 +3700,11 @@
3514
3700
  "step-active": __props.stepActive,
3515
3701
  size: __props.size,
3516
3702
  onChange: changeHandler
3517
- }, null, 8, [
3703
+ }, (0, vue.createSlots)({ _: 2 }, [_ctx.$slots.label ? {
3704
+ name: "label",
3705
+ fn: (0, vue.withCtx)((labelProps) => [(0, vue.renderSlot)(_ctx.$slots, "label", (0, vue.mergeProps)({ ref_for: true }, labelProps))]),
3706
+ key: "0"
3707
+ } : void 0]), 1032, [
3518
3708
  "disabled",
3519
3709
  "config",
3520
3710
  "model",
@@ -3525,7 +3715,7 @@
3525
3715
  "size"
3526
3716
  ]);
3527
3717
  }), 128)) : (0, vue.createCommentVNode)("v-if", true)]),
3528
- _: 1
3718
+ _: 3
3529
3719
  }, 8, [
3530
3720
  "model",
3531
3721
  "label-width",
@@ -4665,6 +4855,9 @@
4665
4855
  prop: props.prop
4666
4856
  });
4667
4857
  });
4858
+ (0, vue.watch)([() => props.model, () => props.lastValues], () => {
4859
+ diffCount.value = {};
4860
+ });
4668
4861
  const tabItems = (tab) => props.config.dynamic ? props.config.items : tab.items;
4669
4862
  const tabClickHandler = (tab) => {
4670
4863
  if (typeof tab === "object") tabClick(mForm, tab, props);
@@ -4739,7 +4932,7 @@
4739
4932
  default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(tabs.value, (tab, tabIndex) => {
4740
4933
  return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.mergeProps)({ key: tab[(0, vue.unref)(mForm)?.keyProp || "__key"] ?? tabIndex }, { ref_for: true }, (0, vue.unref)(tabPaneComponent)?.props({
4741
4934
  name: filter(tab.status) || tabIndex.toString(),
4742
- lazy: tab.lazy || false
4935
+ lazy: __props.isCompare ? false : tab.lazy || false
4743
4936
  }) || {}), {
4744
4937
  label: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("span", null, [(0, vue.createTextVNode)((0, vue.toDisplayString)(filter(tab.title)), 1), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicBadge), {
4745
4938
  hidden: !diffCount.value[Number(tabIndex)],
@@ -4880,16 +5073,17 @@
4880
5073
  }), (0, vue.createElementVNode)("span", { innerHTML: title.value }, null, 8, _hoisted_1$9)]),
4881
5074
  _: 1
4882
5075
  }, 8, ["disabled"]),
4883
- (0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
5076
+ !__props.isCompare ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
5077
+ key: 0,
4884
5078
  type: "danger",
4885
5079
  size: "small",
4886
5080
  link: "",
4887
5081
  icon: (0, vue.unref)(_element_plus_icons_vue.Delete),
4888
5082
  disabled: __props.disabled,
4889
5083
  onClick: removeHandler
4890
- }, null, 8, ["icon", "disabled"]), [[vue.vShow, showDelete.value]]),
4891
- copyable.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
4892
- key: 0,
5084
+ }, null, 8, ["icon", "disabled"])), [[vue.vShow, showDelete.value]]) : (0, vue.createCommentVNode)("v-if", true),
5085
+ copyable.value && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
5086
+ key: 1,
4893
5087
  link: "",
4894
5088
  size: "small",
4895
5089
  type: "primary",
@@ -4900,7 +5094,7 @@
4900
5094
  default: (0, vue.withCtx)(() => [..._cache[6] || (_cache[6] = [(0, vue.createTextVNode)("复制", -1)])]),
4901
5095
  _: 1
4902
5096
  }, 8, ["icon", "disabled"])) : (0, vue.createCommentVNode)("v-if", true),
4903
- movable.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
5097
+ movable.value && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [(0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
4904
5098
  link: "",
4905
5099
  size: "small",
4906
5100
  disabled: __props.disabled,
@@ -4919,8 +5113,8 @@
4919
5113
  default: (0, vue.withCtx)(() => [..._cache[8] || (_cache[8] = [(0, vue.createTextVNode)("下移", -1)])]),
4920
5114
  _: 1
4921
5115
  }, 8, ["disabled", "icon"]), [[vue.vShow, __props.index !== length.value - 1]])], 64)) : (0, vue.createCommentVNode)("v-if", true),
4922
- __props.config.moveSpecifyLocation ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicPopover), {
4923
- key: 2,
5116
+ __props.config.moveSpecifyLocation && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicPopover), {
5117
+ key: 3,
4924
5118
  trigger: "click",
4925
5119
  placement: "top",
4926
5120
  width: "200",
@@ -4966,7 +5160,7 @@
4966
5160
  _: 1
4967
5161
  }, 8, ["visible"])) : (0, vue.createCommentVNode)("v-if", true),
4968
5162
  itemExtra.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
4969
- key: 3,
5163
+ key: 4,
4970
5164
  innerHTML: itemExtra.value,
4971
5165
  class: "m-form-tip"
4972
5166
  }, null, 8, _hoisted_3$3)) : (0, vue.createCommentVNode)("v-if", true)
@@ -5006,7 +5200,10 @@
5006
5200
  key: 1,
5007
5201
  class: "el-table__empty-block"
5008
5202
  };
5009
- var _hoisted_4$1 = { class: "m-fields-group-list-footer" };
5203
+ var _hoisted_4$1 = {
5204
+ key: 3,
5205
+ class: "m-fields-group-list-footer"
5206
+ };
5010
5207
  var _hoisted_5 = { style: {
5011
5208
  "display": "flex",
5012
5209
  "justify-content": "flex-end",
@@ -5091,7 +5288,7 @@
5091
5288
  "group-model"
5092
5289
  ]);
5093
5290
  }), 128)),
5094
- (0, vue.createElementVNode)("div", _hoisted_4$1, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div", _hoisted_5, [(0, vue.renderSlot)(_ctx.$slots, "add-button")])])
5291
+ !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4$1, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div", _hoisted_5, [(0, vue.renderSlot)(_ctx.$slots, "add-button")])])) : (0, vue.createCommentVNode)("v-if", true)
5095
5292
  ]);
5096
5293
  };
5097
5294
  }
@@ -5693,7 +5890,7 @@
5693
5890
  default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(isFullscreen) ? "退出全屏" : "全屏编辑"), 1)]),
5694
5891
  _: 1
5695
5892
  }, 8, ["icon", "onClick"])) : (0, vue.createCommentVNode)("v-if", true),
5696
- (0, vue.unref)(importable) ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicUpload), {
5893
+ (0, vue.unref)(importable) && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicUpload), {
5697
5894
  key: 2,
5698
5895
  style: { "display": "inline-block" },
5699
5896
  ref: "excelBtn",
@@ -5713,7 +5910,7 @@
5713
5910
  }, 8, ["disabled"])]),
5714
5911
  _: 1
5715
5912
  }, 8, ["disabled", "on-change"])) : (0, vue.createCommentVNode)("v-if", true),
5716
- (0, vue.unref)(importable) ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
5913
+ (0, vue.unref)(importable) && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
5717
5914
  key: 3,
5718
5915
  size: "small",
5719
5916
  type: "warning",
@@ -5724,7 +5921,7 @@
5724
5921
  default: (0, vue.withCtx)(() => [..._cache[1] || (_cache[1] = [(0, vue.createTextVNode)("清空", -1)])]),
5725
5922
  _: 1
5726
5923
  }, 8, ["disabled", "onClick"])) : (0, vue.createCommentVNode)("v-if", true)
5727
- ]), (0, vue.renderSlot)(_ctx.$slots, "add-button")]),
5924
+ ]), !__props.isCompare ? (0, vue.renderSlot)(_ctx.$slots, "add-button", { key: 0 }) : (0, vue.createCommentVNode)("v-if", true)]),
5728
5925
  __props.config.pagination ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicPagination), {
5729
5926
  layout: "total, sizes, prev, pager, next, jumper",
5730
5927
  "hide-on-single-page": __props.model[modelName.value].length < (0, vue.unref)(pageSize),
@@ -7803,6 +8000,7 @@
7803
8000
  } };
7804
8001
  var createForm = (config) => config;
7805
8002
  //#endregion
8003
+ exports.FORM_DIFF_CONFIG_KEY = FORM_DIFF_CONFIG_KEY;
7806
8004
  exports.MCascader = Cascader_default;
7807
8005
  exports.MCheckbox = Checkbox_default;
7808
8006
  exports.MCheckboxGroup = CheckboxGroup_default;