@tmagic/form 1.8.0-beta.25 → 1.8.0-beta.27
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/dist/es/Form.vue_vue_type_script_setup_true_lang.js +47 -120
- package/dist/es/FormBox.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/FormDialog.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/FormDrawer.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/containers/Col.vue_vue_type_script_setup_true_lang.js +3 -0
- package/dist/es/containers/Container.vue_vue_type_script_setup_true_lang.js +36 -51
- package/dist/es/containers/Fieldset.vue_vue_type_script_setup_true_lang.js +6 -0
- package/dist/es/containers/FlexLayout.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/containers/GroupList.vue_vue_type_script_setup_true_lang.js +37 -15
- package/dist/es/containers/GroupListItem.vue_vue_type_script_setup_true_lang.js +109 -97
- package/dist/es/containers/Panel.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/es/containers/Row.vue_vue_type_script_setup_true_lang.js +3 -0
- package/dist/es/containers/Step.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/containers/Tabs.vue_vue_type_script_setup_true_lang.js +7 -0
- package/dist/es/containers/table/Table.vue_vue_type_script_setup_true_lang.js +7 -5
- package/dist/es/containers/table/useTableColumns.js +5 -13
- package/dist/es/containers/table-group-list/TableGroupList.vue_vue_type_script_setup_true_lang.js +71 -78
- package/dist/es/containers/table-group-list/useAdd.js +26 -16
- package/dist/es/containers/table-group-list/useScrollLastItemIntoView.js +72 -0
- package/dist/es/fields/Cascader.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/CheckboxGroup/Index.js +5 -0
- package/dist/es/fields/{CheckboxGroup.vue_vue_type_script_setup_true_lang.js → CheckboxGroup/Index.vue_vue_type_script_setup_true_lang.js} +6 -7
- package/dist/es/fields/CheckboxGroup/effect.js +8 -0
- package/dist/es/fields/Date/Index.js +5 -0
- package/dist/es/fields/{Date.vue_vue_type_script_setup_true_lang.js → Date/Index.vue_vue_type_script_setup_true_lang.js} +5 -7
- package/dist/es/fields/Date/effect.js +10 -0
- package/dist/es/fields/DateTime/Index.js +5 -0
- package/dist/es/fields/{DateTime.vue_vue_type_script_setup_true_lang.js → DateTime/Index.vue_vue_type_script_setup_true_lang.js} +5 -9
- package/dist/es/fields/DateTime/effect.js +15 -0
- package/dist/es/fields/Display/Index.js +5 -0
- package/dist/es/fields/{Display.vue_vue_type_script_setup_true_lang.js → Display/Index.vue_vue_type_script_setup_true_lang.js} +6 -7
- package/dist/es/fields/Display/effect.js +8 -0
- package/dist/es/fields/DynamicField/Index.js +5 -0
- package/dist/es/fields/{DynamicField.vue_vue_type_script_setup_true_lang.js → DynamicField/Index.vue_vue_type_script_setup_true_lang.js} +11 -15
- package/dist/es/fields/DynamicField/effect.js +40 -0
- package/dist/es/fields/Link.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/Number.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/NumberRange/Index.js +5 -0
- package/dist/es/fields/{NumberRange.vue_vue_type_script_setup_true_lang.js → NumberRange/Index.vue_vue_type_script_setup_true_lang.js} +5 -6
- package/dist/es/fields/NumberRange/effect.js +8 -0
- package/dist/es/fields/Select.vue_vue_type_script_setup_true_lang.js +13 -6
- package/dist/es/fields/Text.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/headless.js +13 -0
- package/dist/es/index.js +17 -12
- package/dist/es/plugin.js +57 -41
- package/dist/es/schema.js +6 -8
- package/dist/es/style.css +81 -1
- package/dist/es/submitForm.js +44 -194
- package/dist/es/utils/builtInFields.js +49 -0
- package/dist/es/utils/collectFields.js +407 -0
- package/dist/es/utils/config.js +1 -8
- package/dist/es/utils/fieldInnerConfig.js +42 -0
- package/dist/es/utils/fieldValueEffects.js +80 -0
- package/dist/es/utils/form.js +96 -43
- package/dist/es/utils/formStateProxy.js +111 -0
- package/dist/es/utils/registerField.js +158 -0
- package/dist/es/utils/submitHeadless.js +54 -0
- package/dist/es/utils/tableGroupList.js +85 -0
- package/dist/es/utils/typeMatch.js +17 -19
- package/dist/es/utils/validateError.js +57 -0
- package/dist/es/utils/validateValues.js +115 -0
- package/dist/style.css +81 -1
- package/dist/themes/magic-admin.css +83 -7
- package/dist/tmagic-form-headless.umd.cjs +4080 -0
- package/dist/tmagic-form.umd.cjs +2020 -876
- package/package.json +10 -4
- package/src/Form.vue +49 -149
- package/src/FormBox.vue +5 -4
- package/src/FormDialog.vue +5 -5
- package/src/FormDrawer.vue +5 -5
- package/src/containers/Col.vue +2 -0
- package/src/containers/Container.vue +86 -157
- package/src/containers/Fieldset.vue +5 -0
- package/src/containers/FlexLayout.vue +2 -0
- package/src/containers/GroupList.vue +41 -11
- package/src/containers/GroupListItem.vue +83 -80
- package/src/containers/Panel.vue +3 -0
- package/src/containers/Row.vue +2 -0
- package/src/containers/Step.vue +2 -0
- package/src/containers/Tabs.vue +13 -0
- package/src/containers/table/ActionsColumn.vue +1 -1
- package/src/containers/table/Table.vue +4 -3
- package/src/containers/table/usePagination.ts +1 -1
- package/src/containers/table/useSortable.ts +1 -1
- package/src/containers/table/useTableColumns.ts +9 -19
- package/src/containers/table-group-list/TableGroupList.vue +43 -71
- package/src/containers/table-group-list/useAdd.ts +40 -25
- package/src/containers/table-group-list/useScrollLastItemIntoView.ts +94 -0
- package/src/fields/{CheckboxGroup.vue → CheckboxGroup/Index.vue} +3 -8
- package/src/fields/CheckboxGroup/effect.ts +27 -0
- package/src/fields/{Date.vue → Date/Index.vue} +2 -5
- package/src/fields/Date/effect.ts +29 -0
- package/src/fields/{DateTime.vue → DateTime/Index.vue} +2 -16
- package/src/fields/DateTime/effect.ts +36 -0
- package/src/fields/{Display.vue → Display/Index.vue} +3 -7
- package/src/fields/Display/effect.ts +28 -0
- package/src/fields/{DynamicField.vue → DynamicField/Index.vue} +11 -11
- package/src/fields/DynamicField/effect.ts +74 -0
- package/src/fields/{NumberRange.vue → NumberRange/Index.vue} +2 -6
- package/src/fields/NumberRange/effect.ts +27 -0
- package/src/fields/Select.vue +13 -4
- package/src/headless.ts +78 -0
- package/src/index.ts +32 -15
- package/src/plugin.ts +63 -42
- package/src/schema.ts +6 -8
- package/src/submitForm.ts +81 -409
- package/src/theme/group-list.scss +107 -1
- package/src/theme/themes/magic-admin/index.scss +2 -8
- package/src/utils/builtInFields.ts +69 -0
- package/src/utils/collectFields.ts +561 -0
- package/src/utils/config.ts +1 -15
- package/src/utils/fieldInnerConfig.ts +127 -0
- package/src/utils/fieldValueEffects.ts +140 -0
- package/src/utils/form.ts +141 -75
- package/src/utils/formStateProxy.ts +149 -0
- package/src/utils/registerField.ts +308 -0
- package/src/utils/submitHeadless.ts +206 -0
- package/src/utils/tableGroupList.ts +120 -0
- package/src/utils/typeMatch.ts +19 -15
- package/src/utils/validateError.ts +92 -0
- package/src/utils/validateValues.ts +177 -0
- package/types/headless.d.ts +682 -0
- package/types/index.d.ts +631 -272
- package/dist/es/fields/CheckboxGroup.js +0 -5
- package/dist/es/fields/Date.js +0 -5
- package/dist/es/fields/DateTime.js +0 -5
- package/dist/es/fields/Display.js +0 -5
- package/dist/es/fields/DynamicField.js +0 -5
- package/dist/es/fields/NumberRange.js +0 -5
- package/dist/es/utils/silentLeafFieldTypes.js +0 -49
- package/src/utils/silentLeafFieldTypes.ts +0 -71
package/dist/tmagic-form.umd.cjs
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue"), require("dayjs"), require("dayjs/plugin/utc"), require("@tmagic/design"), require("
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue"), require("async-validator"), require("@tmagic/utils"), require("dayjs"), require("dayjs/plugin/utc.js"), require("@tmagic/design/headless"), require("dayjs/plugin/customParseFormat.js"), require("@tmagic/design"), require("@element-plus/icons-vue"), require("@popperjs/core")) : typeof define === "function" && define.amd ? define([
|
|
3
3
|
"exports",
|
|
4
4
|
"vue",
|
|
5
|
+
"async-validator",
|
|
6
|
+
"@tmagic/utils",
|
|
5
7
|
"dayjs",
|
|
6
|
-
"dayjs/plugin/utc",
|
|
8
|
+
"dayjs/plugin/utc.js",
|
|
9
|
+
"@tmagic/design/headless",
|
|
10
|
+
"dayjs/plugin/customParseFormat.js",
|
|
7
11
|
"@tmagic/design",
|
|
8
|
-
"@tmagic/utils",
|
|
9
|
-
"dayjs/plugin/customParseFormat",
|
|
10
12
|
"@element-plus/icons-vue",
|
|
11
13
|
"@popperjs/core"
|
|
12
|
-
], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.TMagicForm = {}, global.Vue, global.dayjs, global.
|
|
13
|
-
})(this, function(exports, vue, dayjs,
|
|
14
|
+
], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.TMagicForm = {}, global.Vue, global.async_validator, global._tmagic_utils, global.dayjs, global.dayjs_plugin_utc_js, global._tmagic_design_headless, global.dayjs_plugin_customParseFormat_js, global._tmagic_design, global._element_plus_icons_vue, global._popperjs_core));
|
|
15
|
+
})(this, function(exports, vue, async_validator, _tmagic_utils, dayjs, dayjs_plugin_utc_js, _tmagic_design_headless, dayjs_plugin_customParseFormat_js, _tmagic_design, _element_plus_icons_vue, _popperjs_core) {
|
|
14
16
|
Object.defineProperties(exports, {
|
|
15
17
|
__esModule: { value: true },
|
|
16
18
|
[Symbol.toStringTag]: { value: "Module" }
|
|
@@ -37,23 +39,22 @@
|
|
|
37
39
|
enumerable: true
|
|
38
40
|
}) : target, mod));
|
|
39
41
|
//#endregion
|
|
42
|
+
async_validator = __toESM(async_validator, 1);
|
|
40
43
|
dayjs = __toESM(dayjs, 1);
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
dayjs_plugin_utc_js = __toESM(dayjs_plugin_utc_js, 1);
|
|
45
|
+
dayjs_plugin_customParseFormat_js = __toESM(dayjs_plugin_customParseFormat_js, 1);
|
|
43
46
|
//#region packages/form/src/schema.ts
|
|
44
47
|
var FORM_DIFF_CONFIG_KEY = Symbol("mFormDiffConfig");
|
|
45
48
|
var FORM_TYPE_MATCH_VALID_KEY = Symbol("mFormTypeMatchValid");
|
|
46
49
|
/**
|
|
47
|
-
*
|
|
50
|
+
* 宿主业务上下文,由 `MForm`(或更外层的 Editor)通过 `provide` 下发。
|
|
48
51
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* 重型字段组件(如 vs-code)也可 inject 该标记跳过自身渲染,省去无谓的实例化开销。
|
|
52
|
+
* 嵌套表单(Link 子表单、FormBox、临时校验表单等)会自动继承最近祖先的 context,
|
|
53
|
+
* 无需层层透传。
|
|
52
54
|
*
|
|
53
|
-
*
|
|
54
|
-
* 字段组件可以安全跳过,接入前需逐一审计;业务扩展请使用 `registerSilentLeafFieldTypes`。
|
|
55
|
+
* 配置回调统一通过 `mForm.xxx` 读取,由 formState 的读穿 Proxy 落到这里。
|
|
55
56
|
*/
|
|
56
|
-
var
|
|
57
|
+
var FORM_CONTEXT_KEY = Symbol("mFormContext");
|
|
57
58
|
//#endregion
|
|
58
59
|
//#region node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_freeGlobal.js
|
|
59
60
|
/** Detect free variable `global` from Node.js. */
|
|
@@ -2731,27 +2732,191 @@
|
|
|
2731
2732
|
return baseIsEqual(value, other);
|
|
2732
2733
|
}
|
|
2733
2734
|
//#endregion
|
|
2735
|
+
//#region node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isEqualWith.js
|
|
2736
|
+
/**
|
|
2737
|
+
* This method is like `_.isEqual` except that it accepts `customizer` which
|
|
2738
|
+
* is invoked to compare values. If `customizer` returns `undefined`, comparisons
|
|
2739
|
+
* are handled by the method instead. The `customizer` is invoked with up to
|
|
2740
|
+
* six arguments: (objValue, othValue [, index|key, object, other, stack]).
|
|
2741
|
+
*
|
|
2742
|
+
* @static
|
|
2743
|
+
* @memberOf _
|
|
2744
|
+
* @since 4.0.0
|
|
2745
|
+
* @category Lang
|
|
2746
|
+
* @param {*} value The value to compare.
|
|
2747
|
+
* @param {*} other The other value to compare.
|
|
2748
|
+
* @param {Function} [customizer] The function to customize comparisons.
|
|
2749
|
+
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
|
2750
|
+
* @example
|
|
2751
|
+
*
|
|
2752
|
+
* function isGreeting(value) {
|
|
2753
|
+
* return /^h(?:i|ello)$/.test(value);
|
|
2754
|
+
* }
|
|
2755
|
+
*
|
|
2756
|
+
* function customizer(objValue, othValue) {
|
|
2757
|
+
* if (isGreeting(objValue) && isGreeting(othValue)) {
|
|
2758
|
+
* return true;
|
|
2759
|
+
* }
|
|
2760
|
+
* }
|
|
2761
|
+
*
|
|
2762
|
+
* var array = ['hello', 'goodbye'];
|
|
2763
|
+
* var other = ['hi', 'goodbye'];
|
|
2764
|
+
*
|
|
2765
|
+
* _.isEqualWith(array, other, customizer);
|
|
2766
|
+
* // => true
|
|
2767
|
+
*/
|
|
2768
|
+
function isEqualWith(value, other, customizer) {
|
|
2769
|
+
customizer = typeof customizer == "function" ? customizer : void 0;
|
|
2770
|
+
var result = customizer ? customizer(value, other) : void 0;
|
|
2771
|
+
return result === void 0 ? baseIsEqual(value, other, void 0, customizer) : !!result;
|
|
2772
|
+
}
|
|
2773
|
+
//#endregion
|
|
2774
|
+
//#region packages/form/src/utils/fieldInnerConfig.ts
|
|
2775
|
+
/** 内置内部配置(由 `registerBuiltInFields` 写入;`clearFields` 不会清掉) */
|
|
2776
|
+
var builtInInnerConfigs = /* @__PURE__ */ new Map();
|
|
2777
|
+
/** 业务侧登记的内部配置 */
|
|
2778
|
+
var extraInnerConfigs = /* @__PURE__ */ new Map();
|
|
2779
|
+
/**
|
|
2780
|
+
* 登记复合字段的内部配置:无渲染校验遇到该 type 时,用返回值继续遍历内部字段。
|
|
2781
|
+
*
|
|
2782
|
+
* `type` 会按 Container 的规则归一化为中划线形式(`codeSelect` 与 `code-select` 等价)。
|
|
2783
|
+
* 重复登记以最后一次为准,便于业务侧覆盖内置实现。
|
|
2784
|
+
* `builtIn` 登记不受 `deleteFieldInnerConfig` / `clearFieldInnerConfigs` 影响。
|
|
2785
|
+
*
|
|
2786
|
+
* @param type - 字段 type
|
|
2787
|
+
* @param resolve - innerConfig 回调
|
|
2788
|
+
* @param [builtIn=false] - 是否写入内置表
|
|
2789
|
+
*/
|
|
2790
|
+
var registerFieldInnerConfig = (type, resolve, builtIn = false) => {
|
|
2791
|
+
if (typeof type !== "string" || !type || typeof resolve !== "function") return;
|
|
2792
|
+
(builtIn ? builtInInnerConfigs : extraInnerConfigs).set((0, _tmagic_utils.toLine)(type), resolve);
|
|
2793
|
+
};
|
|
2794
|
+
/**
|
|
2795
|
+
* 获取指定 type 的 innerConfig 回调(业务侧优先于内置)。
|
|
2796
|
+
*
|
|
2797
|
+
* @param type - 字段 type
|
|
2798
|
+
* @returns innerConfig 回调;未登记则为 `undefined`
|
|
2799
|
+
*/
|
|
2800
|
+
var getFieldInnerConfig = (type) => {
|
|
2801
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
2802
|
+
return extraInnerConfigs.get(key) ?? builtInInnerConfigs.get(key);
|
|
2803
|
+
};
|
|
2804
|
+
/**
|
|
2805
|
+
* 删除业务侧登记的 innerConfig(不影响内置)。
|
|
2806
|
+
*
|
|
2807
|
+
* @param type - 字段 type
|
|
2808
|
+
* @returns 是否删除成功
|
|
2809
|
+
*/
|
|
2810
|
+
var deleteFieldInnerConfig = (type) => extraInnerConfigs.delete((0, _tmagic_utils.toLine)(type));
|
|
2811
|
+
/** 清空业务侧登记的 innerConfig(不影响内置;主要用于单测)。 */
|
|
2812
|
+
var clearFieldInnerConfigs = () => extraInnerConfigs.clear();
|
|
2813
|
+
//#endregion
|
|
2814
|
+
//#region packages/form/src/utils/fieldValueEffects.ts
|
|
2815
|
+
/**
|
|
2816
|
+
* @fileoverview 叶子字段登记表:哪些 type 是叶子,以及该字段对表单值的初始化写入。
|
|
2817
|
+
*
|
|
2818
|
+
* 无渲染校验据此判定该 type 没有属于父表单的嵌套字段。
|
|
2819
|
+
* 业务自定义字段通过 `registerField` / `registerFields` 登记。
|
|
2820
|
+
* 内置叶子字段由 `MagicForm.install` 的 `registerBuiltInFields` 写入。
|
|
2821
|
+
* 未登记且没有 innerConfig 的 type:有 `items` 会下钻子项,自身有 `rules` 会校验自身。
|
|
2822
|
+
*
|
|
2823
|
+
* 这里只是登记表。各字段的 effect 写在对应组件同目录的 `fields/<Field>/effect.ts`,
|
|
2824
|
+
* 执行收口在 `collectFields` 的 `applyMountValueEffects`:渲染(`Form.vue`)
|
|
2825
|
+
* 与无渲染(`validateValues`)都在表单值初始化完成后调用它一次,
|
|
2826
|
+
* 字段组件自身不再在 setup 里改写 model。
|
|
2827
|
+
*
|
|
2828
|
+
* @module fieldValueEffects
|
|
2829
|
+
*/
|
|
2830
|
+
/** 内置叶子字段(由 `MagicForm.install` 写入;clearFields 不会清掉) */
|
|
2831
|
+
var builtInLeafFieldTypes = /* @__PURE__ */ new Set();
|
|
2832
|
+
var builtInMountValueEffects = /* @__PURE__ */ new Map();
|
|
2833
|
+
/** 业务侧登记的叶子字段与其挂载副作用 */
|
|
2834
|
+
var extraLeafFieldTypes = /* @__PURE__ */ new Set();
|
|
2835
|
+
var extraMountValueEffects = /* @__PURE__ */ new Map();
|
|
2836
|
+
/**
|
|
2837
|
+
* 登记一个叶子字段 type。由 `registerField` 调用,业务侧请走 `registerField`。
|
|
2838
|
+
*
|
|
2839
|
+
* 传了 `effect` 会覆盖该 type 已有的 extra effect(含覆盖内置);不传则清掉 extra effect,
|
|
2840
|
+
* 内置 effect 仍生效。
|
|
2841
|
+
*
|
|
2842
|
+
* @param type - 字段 type
|
|
2843
|
+
* @param [effect] - 挂载时改写 model 的副作用
|
|
2844
|
+
* @param [builtIn=false] - 是否写入内置表
|
|
2845
|
+
*/
|
|
2846
|
+
var registerLeafFieldType = (type, effect, builtIn = false) => {
|
|
2847
|
+
if (typeof type !== "string" || !type) return;
|
|
2848
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
2849
|
+
const types = builtIn ? builtInLeafFieldTypes : extraLeafFieldTypes;
|
|
2850
|
+
const effects = builtIn ? builtInMountValueEffects : extraMountValueEffects;
|
|
2851
|
+
types.add(key);
|
|
2852
|
+
if (typeof effect === "function") effects.set(key, effect);
|
|
2853
|
+
else if (!builtIn) effects.delete(key);
|
|
2854
|
+
};
|
|
2855
|
+
/**
|
|
2856
|
+
* 是否为叶子字段 type(内置 ∪ 已登记)。
|
|
2857
|
+
*
|
|
2858
|
+
* @param type - 字段 type
|
|
2859
|
+
* @returns 是否为叶子
|
|
2860
|
+
*/
|
|
2861
|
+
var isLeafFieldType = (type) => {
|
|
2862
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
2863
|
+
return extraLeafFieldTypes.has(key) || builtInLeafFieldTypes.has(key);
|
|
2864
|
+
};
|
|
2865
|
+
/**
|
|
2866
|
+
* 获取指定 type 挂载时改写 model 的副作用(已登记的优先于内置)。
|
|
2867
|
+
*
|
|
2868
|
+
* @param type - 字段 type
|
|
2869
|
+
* @returns 副作用函数;未登记则为 `undefined`
|
|
2870
|
+
*/
|
|
2871
|
+
var getFieldMountValueEffect = (type) => {
|
|
2872
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
2873
|
+
return extraMountValueEffects.get(key) ?? builtInMountValueEffects.get(key);
|
|
2874
|
+
};
|
|
2875
|
+
/**
|
|
2876
|
+
* 删除业务侧登记的叶子字段(不影响内置;主要用于单测)。
|
|
2877
|
+
*
|
|
2878
|
+
* @param type - 字段 type
|
|
2879
|
+
* @returns 是否删除成功
|
|
2880
|
+
*/
|
|
2881
|
+
var deleteLeafFieldType = (type) => {
|
|
2882
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
2883
|
+
extraMountValueEffects.delete(key);
|
|
2884
|
+
return extraLeafFieldTypes.delete(key);
|
|
2885
|
+
};
|
|
2886
|
+
/** 清空业务侧登记的叶子字段(不影响内置;主要用于单测)。 */
|
|
2887
|
+
var clearLeafFieldTypes = () => {
|
|
2888
|
+
extraLeafFieldTypes.clear();
|
|
2889
|
+
extraMountValueEffects.clear();
|
|
2890
|
+
};
|
|
2891
|
+
//#endregion
|
|
2892
|
+
//#region packages/form/src/utils/config.ts
|
|
2893
|
+
var $MAGIC_FORM = {};
|
|
2894
|
+
var isGlobalFlat = (0, vue.ref)(false);
|
|
2895
|
+
var setConfig = (option) => {
|
|
2896
|
+
$MAGIC_FORM = option;
|
|
2897
|
+
isGlobalFlat.value = option.flat ?? false;
|
|
2898
|
+
};
|
|
2899
|
+
var getConfig = (key) => $MAGIC_FORM[key];
|
|
2900
|
+
//#endregion
|
|
2734
2901
|
//#region packages/form/src/utils/typeMatch.ts
|
|
2735
|
-
dayjs.default.extend(
|
|
2736
|
-
var
|
|
2902
|
+
dayjs.default.extend(dayjs_plugin_customParseFormat_js.default);
|
|
2903
|
+
var extraTypeMatchRules = /* @__PURE__ */ new Map();
|
|
2904
|
+
var builtInTypeMatchRules = /* @__PURE__ */ new Map();
|
|
2737
2905
|
var isPromise = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
2738
|
-
/** 注册或覆盖某个字段 type 的 typeMatch
|
|
2739
|
-
var registerTypeMatchRule = (type, validator) => {
|
|
2740
|
-
|
|
2741
|
-
};
|
|
2742
|
-
/**
|
|
2743
|
-
var
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
});
|
|
2906
|
+
/** 注册或覆盖某个字段 type 的 typeMatch 校验规则。`builtIn` 登记不受 `clearTypeMatchRules` / `deleteTypeMatchRule` 影响。 */
|
|
2907
|
+
var registerTypeMatchRule = (type, validator, builtIn = false) => {
|
|
2908
|
+
(builtIn ? builtInTypeMatchRules : extraTypeMatchRules).set((0, _tmagic_utils.toLine)(type), validator);
|
|
2909
|
+
};
|
|
2910
|
+
/** 获取某个字段 type 的 typeMatch 校验规则(业务侧优先于内置) */
|
|
2911
|
+
var getTypeMatchRule = (type) => {
|
|
2912
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
2913
|
+
return extraTypeMatchRules.get(key) ?? builtInTypeMatchRules.get(key);
|
|
2747
2914
|
};
|
|
2748
|
-
/**
|
|
2749
|
-
var
|
|
2750
|
-
/**
|
|
2751
|
-
var deleteTypeMatchRule = (type) => typeMatchRuleRegistry.delete((0, _tmagic_utils.toLine)(type));
|
|
2752
|
-
/** 清空所有自定义 typeMatch 校验规则 */
|
|
2915
|
+
/** 删除业务侧 typeMatch 校验规则(不影响内置) */
|
|
2916
|
+
var deleteTypeMatchRule = (type) => extraTypeMatchRules.delete((0, _tmagic_utils.toLine)(type));
|
|
2917
|
+
/** 清空业务侧 typeMatch 校验规则(不影响内置) */
|
|
2753
2918
|
var clearTypeMatchRules = () => {
|
|
2754
|
-
|
|
2919
|
+
extraTypeMatchRules.clear();
|
|
2755
2920
|
};
|
|
2756
2921
|
/** 本地解析配置函数,避免与 form.ts 循环依赖 */
|
|
2757
2922
|
var resolveConfig = (mForm, config, props) => {
|
|
@@ -2884,7 +3049,7 @@
|
|
|
2884
3049
|
*/
|
|
2885
3050
|
var defaultMessage = (message, fallback, suggestion) => {
|
|
2886
3051
|
if (message) return message;
|
|
2887
|
-
return (0,
|
|
3052
|
+
return (0, _tmagic_design_headless.appendValidateSuggestion)(fallback, suggestion);
|
|
2888
3053
|
};
|
|
2889
3054
|
var isEmptyValue = (value) => value === void 0 || value === null || value === "";
|
|
2890
3055
|
var isEmptyArray = (value) => Array.isArray(value) && value.length === 0;
|
|
@@ -3215,8 +3380,117 @@
|
|
|
3215
3380
|
};
|
|
3216
3381
|
};
|
|
3217
3382
|
//#endregion
|
|
3383
|
+
//#region packages/form/src/utils/formStateProxy.ts
|
|
3384
|
+
/** 无上下文时共用的空对象,避免每次读取都分配新对象 */
|
|
3385
|
+
var EMPTY_CONTEXT = Object.freeze({});
|
|
3386
|
+
/**
|
|
3387
|
+
* 按优先级分层合并上下文,**靠后的层优先**。
|
|
3388
|
+
*
|
|
3389
|
+
* 用读穿 Proxy 而非 `{ ...a, ...b }`:展开会立即执行 accessor,
|
|
3390
|
+
* 而宿主允许用 `{ get stage() { ... } }` 这类读时求值的描述符。
|
|
3391
|
+
*/
|
|
3392
|
+
var mergeFormContexts = (...layers) => {
|
|
3393
|
+
const stack = layers.filter((layer) => Boolean(layer));
|
|
3394
|
+
if (stack.length === 0) return EMPTY_CONTEXT;
|
|
3395
|
+
if (stack.length === 1) return stack[0];
|
|
3396
|
+
const ordered = stack.slice().reverse();
|
|
3397
|
+
const owner = (k) => ordered.find((layer) => Reflect.has(layer, k));
|
|
3398
|
+
return new Proxy({}, {
|
|
3399
|
+
get: (_t, k) => owner(k)?.[k],
|
|
3400
|
+
has: (_t, k) => Boolean(owner(k)),
|
|
3401
|
+
ownKeys: () => [...new Set(ordered.flatMap((layer) => Reflect.ownKeys(layer)))],
|
|
3402
|
+
getOwnPropertyDescriptor: (_t, k) => {
|
|
3403
|
+
for (const layer of ordered) {
|
|
3404
|
+
const descriptor = Object.getOwnPropertyDescriptor(layer, k);
|
|
3405
|
+
if (descriptor) return {
|
|
3406
|
+
...descriptor,
|
|
3407
|
+
configurable: true
|
|
3408
|
+
};
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
});
|
|
3412
|
+
};
|
|
3413
|
+
/**
|
|
3414
|
+
* 存量下发配置沿用 Vue2 时代的写法,把回调第一个参数当组件实例用,靠 `vm.mForm.xxx`
|
|
3415
|
+
* 取表单状态。这类配置除了读,还会往上面挂方法做跨字段通信,例如:
|
|
3416
|
+
*
|
|
3417
|
+
* ```js
|
|
3418
|
+
* vm.mForm.checkPropertyLimit = async (...) => { ... } // 一个字段的 validator 里挂
|
|
3419
|
+
* await vm.mForm.checkPropertyLimit(...) // 另一处再取出来调用
|
|
3420
|
+
* ```
|
|
3421
|
+
*
|
|
3422
|
+
* 所以 `mForm` 必须能指回某个 formState:读能落到 core / context,写能经 `set` trap
|
|
3423
|
+
* 落到 coreState 并持久化。
|
|
3424
|
+
*
|
|
3425
|
+
* 优先级是 core > context > 合成自引用,三者都是刻意的:
|
|
3426
|
+
*
|
|
3427
|
+
* - **core**:`formState.mForm = formState` 这类直写(如 FormPreview 用自建 services 时)
|
|
3428
|
+
* 必须最优先。
|
|
3429
|
+
* - **context**:唯一的生产者是把父 formState 整体当 context 传下来的嵌套表单
|
|
3430
|
+
* (ComponentForm)。此时 `mForm` 命中 context 指向**父表单**,与 `extendState` 时代
|
|
3431
|
+
* 把父 formState 并入子状态的结果一致,跨字段通信仍落在同一份对象上。父 formState
|
|
3432
|
+
* 本身也是 Proxy,写入照样持久化,所以这里让 context 赢是对的,别「修正」成指向子表单。
|
|
3433
|
+
* - **合成自引用**:前两者都没有时才兜底,让 `vm.mForm.xxx = fn` 落到自己的 coreState。
|
|
3434
|
+
*
|
|
3435
|
+
* 由此推出一条约束:**不要往 context 里塞普通对象充当 `mForm`**。context 通常是 computed
|
|
3436
|
+
* 产物,依赖一变就重建,挂上去的方法会静默丢失。要么直写 core,要么什么都不放交给兜底。
|
|
3437
|
+
*
|
|
3438
|
+
* 枚举语义上合成的自引用表现得像原型链上的属性:`'mForm' in state` 为真,但不出现在
|
|
3439
|
+
* `Object.keys(state)` 里,`getOwnPropertyDescriptor` 也返回 undefined。这是故意的——
|
|
3440
|
+
* 按扩展字段打包 formState 的调用方(如发给 AI 的逻辑)会因循环引用炸掉。
|
|
3441
|
+
*/
|
|
3442
|
+
var SELF_REF_KEY = "mForm";
|
|
3443
|
+
/**
|
|
3444
|
+
* 将 coreState 与宿主业务上下文关联:读取时优先 core,miss 再读穿到 context。
|
|
3445
|
+
*
|
|
3446
|
+
* - `get` 用属性访问而非 `Reflect.get(t, k, receiver)`,避免破坏 Vue reactive 的 `__v_raw`;
|
|
3447
|
+
* - symbol 键一律只走 core,四个 trap 保持一致。context 是业务数据袋,不承载 symbol 键,
|
|
3448
|
+
* 把 Vue / 工具链的内部 symbol 隔离在 core 上才能让 `toRaw` / `isReactive` 判定正确;
|
|
3449
|
+
* - `ownKeys` + `getOwnPropertyDescriptor` 保证 `Object.entries(formState)` 能枚举到扩展字段
|
|
3450
|
+
* (admin-web-next 的 `pickPanelFormStateExtendFields` 依赖此语义);
|
|
3451
|
+
* - `set` 写入 coreState,第三方 `formState.xxx = v` 仍生效且优先于 context。
|
|
3452
|
+
*
|
|
3453
|
+
* 独立成文件,避免与 `form.ts` ↔ `typeMatch.ts` 形成循环依赖。
|
|
3454
|
+
*/
|
|
3455
|
+
var createFormStateProxy = (coreState, getContext) => {
|
|
3456
|
+
const resolve = () => {
|
|
3457
|
+
const ctx = (typeof getContext === "function" ? getContext() : (0, vue.unref)(getContext)) || EMPTY_CONTEXT;
|
|
3458
|
+
return ctx === proxy ? EMPTY_CONTEXT : ctx;
|
|
3459
|
+
};
|
|
3460
|
+
const proxy = new Proxy(coreState, {
|
|
3461
|
+
get(t, k) {
|
|
3462
|
+
if (typeof k === "symbol") return Reflect.get(t, k);
|
|
3463
|
+
const v = t[k];
|
|
3464
|
+
if (v !== void 0 || Reflect.has(t, k)) return v;
|
|
3465
|
+
const ctx = resolve();
|
|
3466
|
+
if (k in ctx) return ctx[k];
|
|
3467
|
+
return k === SELF_REF_KEY ? proxy : void 0;
|
|
3468
|
+
},
|
|
3469
|
+
set(t, k, value) {
|
|
3470
|
+
t[k] = value;
|
|
3471
|
+
return true;
|
|
3472
|
+
},
|
|
3473
|
+
has: (t, k) => Reflect.has(t, k) || typeof k !== "symbol" && (k in resolve() || k === SELF_REF_KEY),
|
|
3474
|
+
ownKeys: (t) => [.../* @__PURE__ */ new Set([...Reflect.ownKeys(t), ...Reflect.ownKeys(resolve()).filter((k) => typeof k !== "symbol")])],
|
|
3475
|
+
getOwnPropertyDescriptor: (t, k) => {
|
|
3476
|
+
const own = Reflect.getOwnPropertyDescriptor(t, k);
|
|
3477
|
+
if (own) return own;
|
|
3478
|
+
if (typeof k === "symbol") return void 0;
|
|
3479
|
+
const ctx = resolve();
|
|
3480
|
+
if (!(k in ctx)) return void 0;
|
|
3481
|
+
return {
|
|
3482
|
+
configurable: true,
|
|
3483
|
+
enumerable: true,
|
|
3484
|
+
writable: true,
|
|
3485
|
+
value: ctx[k]
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
});
|
|
3489
|
+
return proxy;
|
|
3490
|
+
};
|
|
3491
|
+
//#endregion
|
|
3218
3492
|
//#region packages/form/src/utils/form.ts
|
|
3219
|
-
var isTDesignAdapter = () => (0,
|
|
3493
|
+
var isTDesignAdapter = () => (0, _tmagic_design_headless.getDesignConfig)("adapterType") === "tdesign-vue-next";
|
|
3220
3494
|
/**
|
|
3221
3495
|
* 将 async-validator(Element Plus)风格的 validator 适配到当前 UI 库。
|
|
3222
3496
|
* TDesign 调用签名为 `(val) => boolean | CustomValidateObj | Promise`,无 callback。
|
|
@@ -3326,6 +3600,79 @@
|
|
|
3326
3600
|
if (type === "daterange" && !names) return [];
|
|
3327
3601
|
return "";
|
|
3328
3602
|
};
|
|
3603
|
+
/**
|
|
3604
|
+
* formState 中与表单 props 无关的公共部分:字段注册表、消息组件、post 请求。
|
|
3605
|
+
*
|
|
3606
|
+
* 由渲染式表单(`Form.vue`)与无渲染校验(`createHeadlessFormState`)共用,
|
|
3607
|
+
* 保证两者提供给字段配置(`onChange` / `validator` / 异步 options 等)的能力一致。
|
|
3608
|
+
*/
|
|
3609
|
+
var fallbackMessage = {
|
|
3610
|
+
error: (msg) => console.error(msg),
|
|
3611
|
+
success: (msg) => console.log(msg),
|
|
3612
|
+
warning: (msg) => console.warn(msg),
|
|
3613
|
+
info: (msg) => console.info(msg),
|
|
3614
|
+
closeAll: () => void 0
|
|
3615
|
+
};
|
|
3616
|
+
var fallbackMessageBox = {
|
|
3617
|
+
alert: (msg) => console.log(msg),
|
|
3618
|
+
confirm: (msg) => console.log(msg),
|
|
3619
|
+
close: (msg) => console.log(msg)
|
|
3620
|
+
};
|
|
3621
|
+
var createFormStateBase = (ui) => {
|
|
3622
|
+
const fields = /* @__PURE__ */ new Map();
|
|
3623
|
+
const requestFuc = getConfig("request");
|
|
3624
|
+
return {
|
|
3625
|
+
fields,
|
|
3626
|
+
setField: (prop, field) => fields.set(prop, field),
|
|
3627
|
+
getField: (prop) => fields.get(prop),
|
|
3628
|
+
deleteField: (prop) => fields.delete(prop),
|
|
3629
|
+
$messageBox: ui?.$messageBox ?? fallbackMessageBox,
|
|
3630
|
+
$message: ui?.$message ?? fallbackMessage,
|
|
3631
|
+
post: (options) => {
|
|
3632
|
+
if (requestFuc) return requestFuc({
|
|
3633
|
+
method: "POST",
|
|
3634
|
+
...options
|
|
3635
|
+
});
|
|
3636
|
+
}
|
|
3637
|
+
};
|
|
3638
|
+
};
|
|
3639
|
+
/**
|
|
3640
|
+
* 配置项的 `name` 是否可用于从 model 中下钻取值。
|
|
3641
|
+
*
|
|
3642
|
+
* 供 `Container.vue` 与无渲染校验(`collectValidatableFields`)共用,两者对「该不该下钻」
|
|
3643
|
+
* 的判断必须一致。
|
|
3644
|
+
*/
|
|
3645
|
+
var isValidName = (name) => {
|
|
3646
|
+
const valueType = typeof name;
|
|
3647
|
+
if (valueType !== "string" && valueType !== "symbol" && valueType !== "number") return false;
|
|
3648
|
+
if (name === "") return false;
|
|
3649
|
+
if (valueType === "number") return name >= 0;
|
|
3650
|
+
return true;
|
|
3651
|
+
};
|
|
3652
|
+
/**
|
|
3653
|
+
* 在 `prop` 后追加一段路径。
|
|
3654
|
+
*
|
|
3655
|
+
* 用于容器把 `prop` 透传给子级时再拼上索引 / key(如 group-list 的行、table 的行)。
|
|
3656
|
+
*/
|
|
3657
|
+
var appendProp = (prop = "", key) => `${prop}${prop ? "." : ""}${key}`;
|
|
3658
|
+
/**
|
|
3659
|
+
* 由父级 `prop` 与配置项 `name` 拼出该配置项的完整 `prop`(即 FormItem 的 prop)。
|
|
3660
|
+
*
|
|
3661
|
+
* 调用方传入的 name 已按 `config.name || ''` 归一化,空 name 表示该配置项不占据值路径上的一层,
|
|
3662
|
+
* 此时沿用父级 `prop`。
|
|
3663
|
+
*/
|
|
3664
|
+
var getItemProp = (prop = "", name = "") => name === "" ? prop ?? "" : appendProp(prop, name);
|
|
3665
|
+
/**
|
|
3666
|
+
* 归一化配置项的 `type`:求值动态 type、剥离容器语义的 type、驼峰转中划线、补默认值。
|
|
3667
|
+
*
|
|
3668
|
+
* 供 `Container.vue` 与无渲染校验共用,保证两者分派到的 type 完全一致。
|
|
3669
|
+
*/
|
|
3670
|
+
var resolveItemType = (mForm, config, props) => {
|
|
3671
|
+
let type = "type" in (config || {}) ? config.type : "";
|
|
3672
|
+
type = type && filterFunction(mForm, type, props);
|
|
3673
|
+
if (type === "form" || type === "container") return "";
|
|
3674
|
+
return type?.replace(/([A-Z])/g, "-$1").toLowerCase() || (config?.items ? "" : "text");
|
|
3675
|
+
};
|
|
3329
3676
|
var filterFunction = (mForm, config, props) => {
|
|
3330
3677
|
if (typeof config === "function") return config(mForm, {
|
|
3331
3678
|
values: (0, vue.readonly)(mForm?.initValues || {}),
|
|
@@ -3345,18 +3692,18 @@
|
|
|
3345
3692
|
if (config === false) return false;
|
|
3346
3693
|
return true;
|
|
3347
3694
|
};
|
|
3348
|
-
var
|
|
3695
|
+
var buildRules = function(mForm, r = [], props, typeMatchValid, adapt = (validator) => validator) {
|
|
3349
3696
|
let rules = cloneDeep(r);
|
|
3350
3697
|
if (typeof rules === "object" && !Array.isArray(rules)) rules = [rules];
|
|
3351
|
-
if (typeMatchValid
|
|
3698
|
+
if ((0, vue.unref)(typeMatchValid) && !rules.some((r) => typeof r.typeMatch !== "undefined")) rules.push({ typeMatch: true });
|
|
3352
3699
|
return rules.map((item) => {
|
|
3353
3700
|
if (item.typeMatch) {
|
|
3354
|
-
item.validator =
|
|
3701
|
+
item.validator = adapt(createTypeMatchValidator(mForm, props, item));
|
|
3355
3702
|
return item;
|
|
3356
3703
|
}
|
|
3357
3704
|
if (typeof item.validator === "function") {
|
|
3358
3705
|
const fnc = item.validator;
|
|
3359
|
-
item.validator =
|
|
3706
|
+
item.validator = adapt((rule, value, callback, source, options) => fnc({
|
|
3360
3707
|
rule,
|
|
3361
3708
|
value: props.config.names ? props.model : value,
|
|
3362
3709
|
callback,
|
|
@@ -3377,6 +3724,18 @@
|
|
|
3377
3724
|
return true;
|
|
3378
3725
|
});
|
|
3379
3726
|
};
|
|
3727
|
+
var getRules = function(mForm, r = [], props, typeMatchValid) {
|
|
3728
|
+
return buildRules(mForm, r, props, typeMatchValid, adaptFormValidator);
|
|
3729
|
+
};
|
|
3730
|
+
/**
|
|
3731
|
+
* 与 `getRules` 相同,但 validator 保持 async-validator(Element Plus)原生签名,不做 UI 库适配。
|
|
3732
|
+
*
|
|
3733
|
+
* 供无渲染校验(`validateValues`)使用:它直接把规则交给 async-validator 执行,
|
|
3734
|
+
* 不经过 TDesign 的 `validator(val)` 调用约定,因此不能套 `adaptFormValidator`。
|
|
3735
|
+
*/
|
|
3736
|
+
var getNativeRules = function(mForm, r = [], props, typeMatchValid) {
|
|
3737
|
+
return buildRules(mForm, r, props, typeMatchValid);
|
|
3738
|
+
};
|
|
3380
3739
|
var initValue = async (mForm, { initValues, config }) => {
|
|
3381
3740
|
if (!Array.isArray(config)) throw new Error("config应该为数组");
|
|
3382
3741
|
const initValuesCopy = cloneDeep(initValues);
|
|
@@ -3393,7 +3752,7 @@
|
|
|
3393
3752
|
let time;
|
|
3394
3753
|
if (["x", "timestamp"].includes(format)) time = (0, dayjs.default)(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
|
|
3395
3754
|
else if (typeof v === "string" && v.includes("Z") || v instanceof Date) {
|
|
3396
|
-
dayjs.default.extend(
|
|
3755
|
+
dayjs.default.extend(dayjs_plugin_utc_js.default);
|
|
3397
3756
|
time = (0, dayjs.default)(v).utcOffset(8).format(format);
|
|
3398
3757
|
} else time = (0, dayjs.default)(v).format(format);
|
|
3399
3758
|
if (time !== "Invalid Date") return time;
|
|
@@ -3417,47 +3776,712 @@
|
|
|
3417
3776
|
if (order === "ascending") data.sort((a, b) => a[prop] - b[prop]);
|
|
3418
3777
|
else if (order === "descending") data.sort((a, b) => b[prop] - a[prop]);
|
|
3419
3778
|
};
|
|
3779
|
+
var createObjectProp = (prop, key, name) => {
|
|
3780
|
+
if (prop === "") return key;
|
|
3781
|
+
const itemPath = `${prop}`.split(".");
|
|
3782
|
+
if (name) {
|
|
3783
|
+
if (`${itemPath[itemPath.length - 1]}` === `${name}`) return `${[...itemPath.slice(0, -1), key].join(".")}`;
|
|
3784
|
+
}
|
|
3785
|
+
return `${[...itemPath, key].join(".")}`;
|
|
3786
|
+
};
|
|
3787
|
+
//#endregion
|
|
3788
|
+
//#region packages/form/src/utils/tableGroupList.ts
|
|
3420
3789
|
/**
|
|
3421
|
-
*
|
|
3790
|
+
* table / group-list 是同一份配置的两种展示形态,可以互相切换(`TableGroupList.vue`)。
|
|
3422
3791
|
*
|
|
3423
|
-
*
|
|
3424
|
-
*
|
|
3425
|
-
*
|
|
3426
|
-
|
|
3792
|
+
* 本模块收口两种形态之间的配置派生,以及各形态下「子项配置怎么算出来」的规则,
|
|
3793
|
+
* 供渲染(`TableGroupList.vue` / `GroupListItem.vue` / `useTableColumns.ts`)与无渲染校验
|
|
3794
|
+
* (`collectValidatableFields`)共用,避免两条链路各写一份而产生偏差。
|
|
3795
|
+
*/
|
|
3796
|
+
/** group-list 形态的 type(兼容驼峰与中划线两种写法) */
|
|
3797
|
+
var isGroupListType = (type) => type === "groupList" || type === "group-list";
|
|
3798
|
+
/** 按 label 文案长度估算 label 宽度(中文按 20px、其他按 8px,最小 80px) */
|
|
3799
|
+
var calcLabelWidth = (label) => {
|
|
3800
|
+
if (!label) return "0px";
|
|
3801
|
+
const zhLength = label.match(/[^\x00-\xff]/g)?.length || 0;
|
|
3802
|
+
const chLength = label.length - zhLength;
|
|
3803
|
+
return `${Math.max(chLength * 8 + zhLength * 20, 80)}px`;
|
|
3804
|
+
};
|
|
3805
|
+
/** 由 group-list 形态的配置派生出 table 形态所需的配置;本身已是 table 形态则原样返回 */
|
|
3806
|
+
var toTableConfig = (config) => {
|
|
3807
|
+
if (!isGroupListType(config.type)) return config;
|
|
3808
|
+
const source = config;
|
|
3809
|
+
return {
|
|
3810
|
+
...config,
|
|
3811
|
+
type: "table",
|
|
3812
|
+
groupItems: source.items,
|
|
3813
|
+
items: source.tableItems || source.items.map((item) => ({
|
|
3814
|
+
...item,
|
|
3815
|
+
label: item.label || item.text,
|
|
3816
|
+
text: null
|
|
3817
|
+
}))
|
|
3818
|
+
};
|
|
3819
|
+
};
|
|
3820
|
+
/** 由 table 形态的配置派生出 group-list 形态所需的配置;本身已是 group-list 形态则原样返回 */
|
|
3821
|
+
var toGroupListConfig = (config) => {
|
|
3822
|
+
if (isGroupListType(config.type)) return config;
|
|
3823
|
+
const source = config;
|
|
3824
|
+
return {
|
|
3825
|
+
...config,
|
|
3826
|
+
type: "groupList",
|
|
3827
|
+
tableItems: source.items,
|
|
3828
|
+
items: source.groupItems || source.items.map((item) => {
|
|
3829
|
+
const text = item.text || item.label;
|
|
3830
|
+
return {
|
|
3831
|
+
...item,
|
|
3832
|
+
text,
|
|
3833
|
+
labelWidth: calcLabelWidth(text),
|
|
3834
|
+
span: item.span || 12
|
|
3835
|
+
};
|
|
3836
|
+
})
|
|
3837
|
+
};
|
|
3838
|
+
};
|
|
3839
|
+
/**
|
|
3840
|
+
* group-list 每一行渲染的 row 容器配置(`GroupListItem.vue` 渲染的 `Container` 的 config)。
|
|
3841
|
+
*
|
|
3842
|
+
* `keyProp` 由调用方从 `mForm.keyProp` 取,默认 `__key`。
|
|
3843
|
+
*/
|
|
3844
|
+
var getGroupListRowConfig = (config, index, keyProp) => {
|
|
3845
|
+
const key = keyProp || "__key";
|
|
3846
|
+
return {
|
|
3847
|
+
type: "row",
|
|
3848
|
+
span: config.span || 24,
|
|
3849
|
+
items: config.items,
|
|
3850
|
+
labelWidth: config.labelWidth,
|
|
3851
|
+
labelPosition: config.labelPosition,
|
|
3852
|
+
[key]: `${config[key]}${String(index)}`
|
|
3853
|
+
};
|
|
3854
|
+
};
|
|
3855
|
+
/**
|
|
3856
|
+
* 列是否会被渲染成一列(`hidden` 列不渲染,`display` 为假的列也不渲染)。
|
|
3427
3857
|
*
|
|
3428
|
-
*
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3858
|
+
* `display` 的求值上下文是表格自身的 props,由调用方通过 `evalDisplay` 注入。
|
|
3859
|
+
*/
|
|
3860
|
+
var isTableColumnRendered = (column, evalDisplay) => column.type !== "hidden" && Boolean(evalDisplay(column.display));
|
|
3861
|
+
/**
|
|
3862
|
+
* 单元格内 `Container` 实际收到的列配置:按行求值 `itemsFunction`,并去掉已在列层面消费过的 `display`。
|
|
3863
|
+
*/
|
|
3864
|
+
var makeTableColumnConfig = (column, row) => {
|
|
3865
|
+
const newConfig = cloneDeep(column);
|
|
3866
|
+
if (typeof column.itemsFunction === "function") newConfig.items = column.itemsFunction(row);
|
|
3867
|
+
delete newConfig.display;
|
|
3868
|
+
return newConfig;
|
|
3869
|
+
};
|
|
3870
|
+
//#endregion
|
|
3871
|
+
//#region packages/form/src/utils/collectFields.ts
|
|
3872
|
+
/** 已登记的 innerConfig 回调自身抛错时抛出(机制故障,不是漏登记) */
|
|
3873
|
+
var FieldInnerConfigError = class extends Error {
|
|
3874
|
+
code = "FIELD_INNER_CONFIG";
|
|
3875
|
+
type;
|
|
3876
|
+
prop;
|
|
3877
|
+
constructor(type, prop, cause) {
|
|
3878
|
+
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
3879
|
+
super(`[MForm] innerConfig for "${type}" at "${prop}" failed: ${reason}`);
|
|
3880
|
+
this.name = "FieldInnerConfigError";
|
|
3881
|
+
this.type = type;
|
|
3882
|
+
this.prop = prop;
|
|
3883
|
+
if (cause instanceof Error) this.cause = cause;
|
|
3884
|
+
}
|
|
3885
|
+
};
|
|
3886
|
+
var isFieldInnerConfigError = (error) => error instanceof FieldInnerConfigError || typeof error === "object" && error !== null && error.code === "FIELD_INNER_CONFIG";
|
|
3887
|
+
/** `effects` 模式下遍历全部配置,不受 display / 折叠状态影响 */
|
|
3888
|
+
var ignoresDisplay = (ctx) => ctx.mode === "effects";
|
|
3889
|
+
var extraContainerWalkers = /* @__PURE__ */ new Map();
|
|
3890
|
+
var builtInContainerWalkers = /* @__PURE__ */ new Map();
|
|
3891
|
+
var registerContainerWalker = (type, walker, builtIn = false) => {
|
|
3892
|
+
if (typeof type !== "string" || !type || typeof walker !== "function") return;
|
|
3893
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
3894
|
+
if (builtIn) {
|
|
3895
|
+
builtInContainerWalkers.set(key, walker);
|
|
3896
|
+
return;
|
|
3897
|
+
}
|
|
3898
|
+
extraContainerWalkers.set(key, walker);
|
|
3899
|
+
};
|
|
3900
|
+
var getContainerWalker = (type) => {
|
|
3901
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
3902
|
+
return extraContainerWalkers.get(key) ?? builtInContainerWalkers.get(key);
|
|
3903
|
+
};
|
|
3904
|
+
var deleteContainerWalker = (type) => extraContainerWalkers.delete((0, _tmagic_utils.toLine)(type));
|
|
3905
|
+
var clearContainerWalkers = () => extraContainerWalkers.clear();
|
|
3906
|
+
var getItems = (config) => config?.items;
|
|
3907
|
+
/**
|
|
3908
|
+
* `resolveItemType` 的静态版本:不求值函数型 `type`,由调用方按「未知」处理。
|
|
3432
3909
|
*
|
|
3433
|
-
*
|
|
3434
|
-
* 否则以普通字段形式赋值会让 proxy 的 set trap 抛出
|
|
3435
|
-
* `TypeError: 'set' on proxy: trap returned falsish`。
|
|
3910
|
+
* 两者必须保持一致,否则预扫描判定的 type 与实际遍历的不同,会漏执行 effect。
|
|
3436
3911
|
*/
|
|
3437
|
-
var
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3912
|
+
var staticItemType = (config) => {
|
|
3913
|
+
const type = "type" in config ? config.type : "";
|
|
3914
|
+
if (type === "form" || type === "container") return "";
|
|
3915
|
+
return `${type || ""}`.replace(/([A-Z])/g, "-$1").toLowerCase() || (config.items ? "" : "text");
|
|
3916
|
+
};
|
|
3917
|
+
/**
|
|
3918
|
+
* 静态预判一份配置子树是否可能触发值初始化写入。
|
|
3919
|
+
*
|
|
3920
|
+
* 只有「确定不会」时才返回 false。函数型 `type`、`itemsFunction`、业务登记的容器遍历器、
|
|
3921
|
+
* 登记了 innerConfig 的复合字段,其运行期结构静态看不出来,一律按可能触发处理。
|
|
3922
|
+
*
|
|
3923
|
+
* 只用在同一份 `items` 会被逐行 / 逐标签页重复展开的地方(table、group-list、dynamic tab):
|
|
3924
|
+
* 预判成本是 O(子项数),跳过省下的是 O(行数 × 子项数),无 effect 的多行表格能省一个量级。
|
|
3925
|
+
* 其余位置不做预判——扫描与遍历的单节点成本相当,扫完再遍历只会更慢。
|
|
3926
|
+
*
|
|
3927
|
+
* 只看 `items`:table / group-list 只遍历当前形态的子项,另一形态的
|
|
3928
|
+
* `tableItems` / `groupItems` 不参与遍历,判定范围与遍历保持一致。
|
|
3929
|
+
*/
|
|
3930
|
+
var mayRunEffects = (config) => {
|
|
3931
|
+
if (!config) return false;
|
|
3932
|
+
if (typeof config.type === "function" || typeof config.itemsFunction === "function") return true;
|
|
3933
|
+
const type = staticItemType(config);
|
|
3934
|
+
if (type === "hidden") return false;
|
|
3935
|
+
if (type) {
|
|
3936
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
3937
|
+
if (extraContainerWalkers.has(key)) return true;
|
|
3938
|
+
if (!builtInContainerWalkers.has(key)) {
|
|
3939
|
+
if (getFieldInnerConfig(type) || getFieldMountValueEffect(type)) return true;
|
|
3940
|
+
if (isLeafFieldType(type)) return false;
|
|
3445
3941
|
}
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3942
|
+
}
|
|
3943
|
+
return itemsMayRunEffects(config.items);
|
|
3944
|
+
};
|
|
3945
|
+
var itemsMayRunEffects = (items) => Array.isArray(items) && items.some((item) => mayRunEffects(item));
|
|
3946
|
+
/**
|
|
3947
|
+
* 复刻 `Container.vue` 的 `display`。
|
|
3948
|
+
*
|
|
3949
|
+
* 与渲染的唯一差异:`display: 'expand'`(「展开更多配置」按钮背后的字段)在此视为可见。
|
|
3950
|
+
* 「是否已展开」纯粹是交互状态,不改变字段是否属于这份配置,无渲染校验按配置声明的范围校验。
|
|
3951
|
+
*/
|
|
3952
|
+
var resolveDisplay = (ctx, config, nodeProps) => {
|
|
3953
|
+
if (ignoresDisplay(ctx)) return true;
|
|
3954
|
+
const value = display(ctx.mForm, config?.display, nodeProps);
|
|
3955
|
+
if (value === "expand") return true;
|
|
3956
|
+
return Boolean(value);
|
|
3957
|
+
};
|
|
3958
|
+
var addField = (ctx, node, itemProp, nodeProps) => {
|
|
3959
|
+
if (ctx.mode !== "collect") return;
|
|
3960
|
+
const rules = getNativeRules(ctx.mForm, node.config.rules, nodeProps, ctx.typeMatchValid);
|
|
3961
|
+
if (!rules.length) return;
|
|
3962
|
+
ctx.fields.push({
|
|
3963
|
+
prop: itemProp,
|
|
3964
|
+
rules,
|
|
3965
|
+
config: node.config,
|
|
3966
|
+
model: node.model
|
|
3967
|
+
});
|
|
3968
|
+
};
|
|
3969
|
+
var walkChildren = (ctx, items, model, prop) => {
|
|
3970
|
+
if (!Array.isArray(items)) return;
|
|
3971
|
+
for (const item of items) {
|
|
3972
|
+
if (!item) continue;
|
|
3973
|
+
walkNode(ctx, {
|
|
3974
|
+
config: item,
|
|
3975
|
+
model,
|
|
3976
|
+
prop
|
|
3977
|
+
});
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
var getContainerScope = (node) => {
|
|
3981
|
+
const { config, model } = node;
|
|
3982
|
+
const name = config.name || "";
|
|
3983
|
+
return {
|
|
3984
|
+
config,
|
|
3985
|
+
model,
|
|
3986
|
+
name,
|
|
3987
|
+
items: getItems(config),
|
|
3988
|
+
childModel: name ? model?.[name] : model
|
|
3989
|
+
};
|
|
3990
|
+
};
|
|
3991
|
+
/** containers/Tabs.vue */
|
|
3992
|
+
var expandTab = (ctx, node, itemProp) => {
|
|
3993
|
+
const { config, model, name, items, childModel } = getContainerScope(node);
|
|
3994
|
+
const tabsProps = {
|
|
3995
|
+
model,
|
|
3996
|
+
config,
|
|
3997
|
+
prop: itemProp
|
|
3998
|
+
};
|
|
3999
|
+
if (config.dynamic) {
|
|
4000
|
+
if (!name) return;
|
|
4001
|
+
const tabs = model?.[name] || [];
|
|
4002
|
+
if (!tabs.length) return;
|
|
4003
|
+
if (ctx.mode === "effects" && !itemsMayRunEffects(items)) return;
|
|
4004
|
+
tabs.forEach((_tab, tabIndex) => {
|
|
4005
|
+
walkChildren(ctx, items, childModel?.[tabIndex], appendProp(itemProp, tabIndex));
|
|
4006
|
+
});
|
|
4007
|
+
return;
|
|
4008
|
+
}
|
|
4009
|
+
const tabs = ignoresDisplay(ctx) ? items || [] : (items || []).filter((item) => display(ctx.mForm, item?.display, tabsProps));
|
|
4010
|
+
for (const tab of tabs) {
|
|
4011
|
+
const tabName = tab.name;
|
|
4012
|
+
walkChildren(ctx, getItems(tab), tabName ? childModel?.[tabName] : childModel, tabName ? appendProp(itemProp, tabName) : itemProp);
|
|
4013
|
+
}
|
|
4014
|
+
};
|
|
4015
|
+
/** containers/Row.vue → Col.vue:col 用 v-show 控制显隐,始终渲染 */
|
|
4016
|
+
var expandRow = (ctx, node, itemProp) => {
|
|
4017
|
+
const { items, childModel } = getContainerScope(node);
|
|
4018
|
+
walkChildren(ctx, items, childModel, itemProp);
|
|
4019
|
+
};
|
|
4020
|
+
/** containers/Fieldset.vue */
|
|
4021
|
+
var expandFieldset = (ctx, node, itemProp) => {
|
|
4022
|
+
const { config, items, childModel } = getContainerScope(node);
|
|
4023
|
+
if (!childModel) return;
|
|
4024
|
+
const { checkbox } = config;
|
|
4025
|
+
const checkboxName = typeof checkbox === "object" && typeof checkbox.name === "string" ? checkbox.name : "value";
|
|
4026
|
+
const checkboxTrueValue = typeof checkbox === "object" && typeof checkbox.trueValue !== "undefined" ? checkbox.trueValue : 1;
|
|
4027
|
+
if (!ignoresDisplay(ctx) && config.expand && childModel?.[checkboxName] !== checkboxTrueValue) return;
|
|
4028
|
+
walkChildren(ctx, items, childModel, itemProp);
|
|
4029
|
+
};
|
|
4030
|
+
/** containers/Panel.vue:折叠仅 display:none,子项照常渲染 */
|
|
4031
|
+
var expandPanel = (ctx, node, itemProp) => {
|
|
4032
|
+
const { items, childModel } = getContainerScope(node);
|
|
4033
|
+
if (!items?.length) return;
|
|
4034
|
+
walkChildren(ctx, items, childModel, itemProp);
|
|
4035
|
+
};
|
|
4036
|
+
/** containers/Step.vue:非当前步仅 v-show 隐藏,子项照常渲染;prop 基准被重置为 step.name */
|
|
4037
|
+
var expandStep = (ctx, node, _itemProp) => {
|
|
4038
|
+
const { model, items } = getContainerScope(node);
|
|
4039
|
+
for (const step of items || []) {
|
|
4040
|
+
const stepName = step?.name;
|
|
4041
|
+
walkChildren(ctx, getItems(step), stepName ? model?.[stepName] : model, `${stepName}`);
|
|
4042
|
+
}
|
|
4043
|
+
};
|
|
4044
|
+
/**
|
|
4045
|
+
* 遍历 table / group-list。
|
|
4046
|
+
*
|
|
4047
|
+
* `TableGroupList.vue` 按原始 `config.type` 决定初始展示形态(table 或 groupList),
|
|
4048
|
+
* 两种形态的子项结构不同,这里分别复刻(形态间的配置派生复用 `utils/tableGroupList`,
|
|
4049
|
+
* 与渲染式实现同源):
|
|
4050
|
+
* - table:逐列(跳过 hidden 列与 display 为假的列)× 逐行渲染 Container,行 prop 为 `${prop}.${index}`;
|
|
4051
|
+
* - groupList:逐行渲染一个 row 容器,包含 `items` 全部字段。
|
|
4052
|
+
*
|
|
4053
|
+
* 与渲染的差异:不做分页截断(table)、不跳过折叠行(groupList)。二者都是列表的视图状态,
|
|
4054
|
+
* 与「这些行的值是否合法」无关,无渲染校验覆盖全部行。
|
|
4055
|
+
*/
|
|
4056
|
+
var expandTableGroupList = (ctx, node, itemProp) => {
|
|
4057
|
+
const { config, model } = node;
|
|
4058
|
+
const name = config.name || "";
|
|
4059
|
+
const rows = model?.[name];
|
|
4060
|
+
if (!Array.isArray(rows) || !rows.length) return;
|
|
4061
|
+
if (isGroupListType(config.type)) {
|
|
4062
|
+
const groupListConfig = toGroupListConfig(config);
|
|
4063
|
+
if (ctx.mode === "effects" && !itemsMayRunEffects(groupListConfig.items)) return;
|
|
4064
|
+
rows.forEach((row, index) => {
|
|
4065
|
+
walkNode(ctx, {
|
|
4066
|
+
config: getGroupListRowConfig(groupListConfig, index, ctx.mForm?.keyProp),
|
|
4067
|
+
model: row,
|
|
4068
|
+
prop: appendProp(itemProp, index)
|
|
4069
|
+
});
|
|
4070
|
+
});
|
|
4071
|
+
return;
|
|
4072
|
+
}
|
|
4073
|
+
const tableItems = toTableConfig(config).items;
|
|
4074
|
+
if (!Array.isArray(tableItems)) return;
|
|
4075
|
+
if (ctx.mode === "effects" && !itemsMayRunEffects(tableItems)) return;
|
|
4076
|
+
const tableProps = {
|
|
4077
|
+
model,
|
|
4078
|
+
config,
|
|
4079
|
+
prop: itemProp
|
|
4080
|
+
};
|
|
4081
|
+
const evalDisplay = (display$4) => display(ctx.mForm, display$4, tableProps);
|
|
4082
|
+
const isRendered = (column) => ignoresDisplay(ctx) || isTableColumnRendered(column, evalDisplay);
|
|
4083
|
+
rows.forEach((row, index) => {
|
|
4084
|
+
for (const column of tableItems) {
|
|
4085
|
+
if (!column || !isRendered(column)) continue;
|
|
4086
|
+
walkNode(ctx, {
|
|
4087
|
+
config: makeTableColumnConfig(column, row),
|
|
4088
|
+
model: row,
|
|
4089
|
+
prop: appendProp(itemProp, index)
|
|
4090
|
+
});
|
|
3450
4091
|
}
|
|
3451
|
-
|
|
4092
|
+
});
|
|
4093
|
+
};
|
|
4094
|
+
/**
|
|
4095
|
+
* 执行某个叶子字段登记的值初始化写入。
|
|
4096
|
+
*
|
|
4097
|
+
* 跑在表单初始化路径上,单个字段的 effect 抛错不应该让整张表单渲染不出来,因此只记录并继续。
|
|
4098
|
+
*/
|
|
4099
|
+
var runMountValueEffect = (ctx, type, node, itemProp) => {
|
|
4100
|
+
const effect = getFieldMountValueEffect(type);
|
|
4101
|
+
if (!effect) return;
|
|
4102
|
+
try {
|
|
4103
|
+
effect({
|
|
4104
|
+
config: node.config,
|
|
4105
|
+
model: node.model,
|
|
4106
|
+
prop: itemProp,
|
|
4107
|
+
mForm: ctx.mForm,
|
|
4108
|
+
values: ctx.values
|
|
4109
|
+
});
|
|
4110
|
+
} catch (e) {
|
|
4111
|
+
console.error(`[MForm] mount value effect for "${type}" at "${itemProp}" failed:`, e);
|
|
3452
4112
|
}
|
|
3453
4113
|
};
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
4114
|
+
/**
|
|
4115
|
+
* 遍历已登记 innerConfig 的复合字段。
|
|
4116
|
+
*
|
|
4117
|
+
* `collect` 模式下回调抛错视为机制故障,包装成 `FieldInnerConfigError` 抛出,由校验流程暴露。
|
|
4118
|
+
* `effects` 模式跑在表单初始化路径上,抛出会让整张表单渲染不出来,因此只记录并跳过该子树。
|
|
4119
|
+
*/
|
|
4120
|
+
var walkInnerConfig = (ctx, type, node, itemProp) => {
|
|
4121
|
+
const resolve = getFieldInnerConfig(type);
|
|
4122
|
+
if (!resolve) return false;
|
|
4123
|
+
let result;
|
|
4124
|
+
try {
|
|
4125
|
+
result = resolve({
|
|
4126
|
+
config: node.config,
|
|
4127
|
+
model: node.model,
|
|
4128
|
+
prop: itemProp,
|
|
4129
|
+
parentProp: node.prop,
|
|
4130
|
+
mForm: ctx.mForm
|
|
4131
|
+
});
|
|
4132
|
+
} catch (e) {
|
|
4133
|
+
if (ctx.mode === "collect") throw new FieldInnerConfigError(type, itemProp, e);
|
|
4134
|
+
console.error(new FieldInnerConfigError(type, itemProp, e));
|
|
4135
|
+
return true;
|
|
4136
|
+
}
|
|
4137
|
+
if (!result) return true;
|
|
4138
|
+
const innerModel = result.model ?? node.model;
|
|
4139
|
+
const innerProp = result.prop ?? itemProp;
|
|
4140
|
+
walkChildren(ctx, Array.isArray(result.config) ? result.config : [result.config], innerModel, innerProp);
|
|
4141
|
+
return true;
|
|
4142
|
+
};
|
|
4143
|
+
/**
|
|
4144
|
+
* 遍历一个 Container 节点,分支顺序与 `Container.vue` 的模板保持一致。
|
|
4145
|
+
*
|
|
4146
|
+
* 对比模式(`isCompare`)在此被忽略:它只改变同一个 prop 渲染几份 FormItem,
|
|
4147
|
+
* 规则与取值完全相同,对校验结果没有影响。
|
|
4148
|
+
*/
|
|
4149
|
+
var walkNode = (ctx, node) => {
|
|
4150
|
+
const { config, prop } = node;
|
|
4151
|
+
const model = node.model ?? {};
|
|
4152
|
+
const nodeProps = {
|
|
4153
|
+
model,
|
|
4154
|
+
config,
|
|
4155
|
+
prop
|
|
4156
|
+
};
|
|
4157
|
+
const name = config.name || "";
|
|
4158
|
+
const items = getItems(config);
|
|
4159
|
+
const type = resolveItemType(ctx.mForm, config, nodeProps);
|
|
4160
|
+
const itemProp = getItemProp(prop, name);
|
|
4161
|
+
const text = filterFunction(ctx.mForm, config.text, nodeProps);
|
|
4162
|
+
if (type === "hidden") {
|
|
4163
|
+
addField(ctx, {
|
|
4164
|
+
...node,
|
|
4165
|
+
model
|
|
4166
|
+
}, itemProp, nodeProps);
|
|
4167
|
+
return;
|
|
4168
|
+
}
|
|
4169
|
+
const display = resolveDisplay(ctx, config, nodeProps);
|
|
4170
|
+
if (items && !text && type && display) {
|
|
4171
|
+
dispatchByType(ctx, type, {
|
|
4172
|
+
...node,
|
|
4173
|
+
model
|
|
4174
|
+
}, itemProp);
|
|
4175
|
+
return;
|
|
4176
|
+
}
|
|
4177
|
+
if (type && display) {
|
|
4178
|
+
addField(ctx, {
|
|
4179
|
+
...node,
|
|
4180
|
+
model
|
|
4181
|
+
}, itemProp, nodeProps);
|
|
4182
|
+
dispatchByType(ctx, type, {
|
|
4183
|
+
...node,
|
|
4184
|
+
model
|
|
4185
|
+
}, itemProp);
|
|
4186
|
+
return;
|
|
4187
|
+
}
|
|
4188
|
+
if (items && display) {
|
|
4189
|
+
const childModel = isValidName(name) ? model[name] : model;
|
|
4190
|
+
if (!childModel) return;
|
|
4191
|
+
walkChildren(ctx, items, childModel, itemProp);
|
|
4192
|
+
}
|
|
4193
|
+
};
|
|
4194
|
+
/**
|
|
4195
|
+
* 按 type 分派:已登记 walk 的容器 → 按容器模板遍历;
|
|
4196
|
+
* `effects` 模式下先执行本字段的 effect(可与 innerConfig 并存,如 `code-select` 先归一化再下钻);
|
|
4197
|
+
* 登记了 innerConfig 的复合字段 → 遍历其内部配置;叶子字段无子树。
|
|
4198
|
+
*
|
|
4199
|
+
* 未登记的 type:配置里若有 `items` 则按普通容器下钻;否则视为没有嵌套表单项。
|
|
4200
|
+
* 自身 rules 已在 FormItem 分支收集,有 rules 就会校验。
|
|
4201
|
+
*/
|
|
4202
|
+
var dispatchByType = (ctx, type, node, itemProp) => {
|
|
4203
|
+
const walkContainer = getContainerWalker(type);
|
|
4204
|
+
if (walkContainer) {
|
|
4205
|
+
walkContainer(ctx, node, itemProp);
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4208
|
+
if (ctx.mode === "effects") runMountValueEffect(ctx, type, node, itemProp);
|
|
4209
|
+
if (walkInnerConfig(ctx, type, node, itemProp)) return;
|
|
4210
|
+
if (isLeafFieldType(type)) return;
|
|
4211
|
+
const items = getItems(node.config);
|
|
4212
|
+
if (items?.length) {
|
|
4213
|
+
const { childModel } = getContainerScope(node);
|
|
4214
|
+
walkChildren(ctx, items, childModel, itemProp);
|
|
4215
|
+
}
|
|
4216
|
+
};
|
|
4217
|
+
/**
|
|
4218
|
+
* 纯逻辑收集「一份 config + 一份 values」中所有参与校验的字段。
|
|
4219
|
+
*
|
|
4220
|
+
* 遍历规则与 `Container.vue` 及各容器组件的模板一一对应,因此产出的 prop / rules
|
|
4221
|
+
* 与渲染式校验(挂载 MForm 后调用 `validate()`)等价,无需任何 DOM 或组件实例。
|
|
4222
|
+
*
|
|
4223
|
+
* 本函数只读不写。字段的值初始化副作用由 `applyMountValueEffects` 负责,
|
|
4224
|
+
* 调用方需在初始化表单值之后、收集字段之前执行一次(`validateValues` 已经这么做)。
|
|
4225
|
+
*
|
|
4226
|
+
* @param mForm - 表单状态;无渲染时由 `createHeadlessFormState` 构造
|
|
4227
|
+
* @param config - 表单配置
|
|
4228
|
+
* @param values - 表单值
|
|
4229
|
+
* @param [typeMatchValid] - 是否自动注入 typeMatch 规则;为 true 时,未显式声明
|
|
4230
|
+
* `typeMatch` 的字段会补上 `{ typeMatch: true }`,按字段 type 校验值形态
|
|
4231
|
+
* @returns 带规则的字段列表
|
|
4232
|
+
*/
|
|
4233
|
+
var collectValidatableFields = (mForm, config, values, typeMatchValid) => {
|
|
4234
|
+
const ctx = {
|
|
4235
|
+
mForm,
|
|
4236
|
+
typeMatchValid,
|
|
4237
|
+
fields: [],
|
|
4238
|
+
values,
|
|
4239
|
+
mode: "collect"
|
|
4240
|
+
};
|
|
4241
|
+
if (Array.isArray(config)) walkChildren(ctx, config, values, "");
|
|
4242
|
+
return ctx.fields;
|
|
4243
|
+
};
|
|
4244
|
+
/**
|
|
4245
|
+
* 执行「一份 config + 一份 values」中所有叶子字段登记的值初始化写入,就地改写 `values`。
|
|
4246
|
+
*
|
|
4247
|
+
* 渲染与无渲染两条链路共用的唯一执行点:字段组件自身不再在 setup 里改写 model,
|
|
4248
|
+
* 由持有完整表单值的一方(`Form.vue` / `validateValues`)在表单值初始化完成、
|
|
4249
|
+
* 且已挂到 `mForm.values` 之后调用一次。这样 effect 与动态 `type` 回调读到的
|
|
4250
|
+
* `formValue` 就是最新值,而不是上一轮的旧值。
|
|
4251
|
+
*
|
|
4252
|
+
* 与 `collectValidatableFields` 的差异:不看 `display`(`display: false` 的字段也会规整)。
|
|
4253
|
+
* `type: 'hidden'` 会在该节点停止遍历,内部字段不执行 effect。
|
|
4254
|
+
*
|
|
4255
|
+
* `prop` 与 `values` 都以传入的 `values` 为根,因此也可以用于 tab / table 新增行这类
|
|
4256
|
+
* 「先构造一份子树的值,再挂到表单上」的场景:传入子树配置与该行的值即可。
|
|
4257
|
+
*
|
|
4258
|
+
* @param mForm - 表单状态;无渲染时由 `createHeadlessFormState` 构造
|
|
4259
|
+
* @param config - 表单配置
|
|
4260
|
+
* @param values - 表单值(会被就地修改)
|
|
4261
|
+
*/
|
|
4262
|
+
var applyMountValueEffects = (mForm, config, values) => {
|
|
4263
|
+
if (!Array.isArray(config)) return;
|
|
4264
|
+
walkChildren({
|
|
4265
|
+
mForm,
|
|
4266
|
+
fields: [],
|
|
4267
|
+
values,
|
|
4268
|
+
mode: "effects"
|
|
4269
|
+
}, config, values, "");
|
|
4270
|
+
};
|
|
4271
|
+
//#endregion
|
|
4272
|
+
//#region packages/form/src/utils/validateError.ts
|
|
4273
|
+
/**
|
|
4274
|
+
* 通过 name 从 config 中查找对应的 text
|
|
4275
|
+
*
|
|
4276
|
+
* @param name - 字段名,支持点分隔的路径格式,如 'a.b.c'
|
|
4277
|
+
* @param config - 表单配置数组
|
|
4278
|
+
* @returns 找到的 text 值,如果未找到则返回 undefined
|
|
4279
|
+
*/
|
|
4280
|
+
var getTextByName = (name, config = []) => {
|
|
4281
|
+
if (!name || !Array.isArray(config)) return void 0;
|
|
4282
|
+
const nameParts = name.split(".");
|
|
4283
|
+
const findInConfig = (configs, parts) => {
|
|
4284
|
+
if (parts.length === 0) return void 0;
|
|
4285
|
+
const [currentPart, ...remainingParts] = parts;
|
|
4286
|
+
for (const item of configs) {
|
|
4287
|
+
if (item.name === currentPart) {
|
|
4288
|
+
if (remainingParts.length === 0) return typeof item.text === "string" ? item.text : void 0;
|
|
4289
|
+
if ("items" in item && Array.isArray(item.items)) {
|
|
4290
|
+
const result = findInConfig(item.items, remainingParts);
|
|
4291
|
+
if (result !== void 0) return result;
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
if ("items" in item && Array.isArray(item.items)) {
|
|
4295
|
+
const result = findInConfig(item.items, parts);
|
|
4296
|
+
if (result !== void 0) return result;
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
};
|
|
4300
|
+
return findInConfig(config, nameParts);
|
|
4301
|
+
};
|
|
4302
|
+
/**
|
|
4303
|
+
* 将校验返回的 invalidFields 汇总为可读的错误文案(多条以 `<br>` 拼接)。
|
|
4304
|
+
*
|
|
4305
|
+
* `useFieldTextInError` 为 `true`(默认)时用字段的 text 文案作为错误前缀,找不到则回退为字段 name。
|
|
4306
|
+
*
|
|
4307
|
+
* 由渲染式校验(Form.vue 的 `submitForm` / `validate`)与无渲染校验(`validateValues`)共用,
|
|
4308
|
+
* 保证两条校验链路产出的错误文案格式完全一致。
|
|
4309
|
+
*
|
|
4310
|
+
* @param invalidFields - async-validator 产出的字段错误表
|
|
4311
|
+
* @param [options] - 文案选项
|
|
4312
|
+
* @param [options.config] - 用于查找 text 的表单配置
|
|
4313
|
+
* @param [options.useFieldTextInError=true] - 错误前缀是否使用字段 text
|
|
4314
|
+
* @returns 拼接后的错误文案;无错误时为空串
|
|
4315
|
+
*/
|
|
4316
|
+
var formatValidateError = (invalidFields, { config = [], useFieldTextInError = true } = {}) => {
|
|
4317
|
+
const error = [];
|
|
4318
|
+
Object.entries(invalidFields).forEach(([prop, validateError]) => {
|
|
4319
|
+
validateError.forEach(({ field, message }) => {
|
|
4320
|
+
const name = field || prop;
|
|
4321
|
+
const text = (useFieldTextInError ? getTextByName(name, config) : void 0) || name;
|
|
4322
|
+
error.push(`${text} -> ${message}`);
|
|
4323
|
+
});
|
|
4324
|
+
});
|
|
4325
|
+
return error.join("<br>");
|
|
4326
|
+
};
|
|
4327
|
+
//#endregion
|
|
4328
|
+
//#region packages/form/src/utils/validateValues.ts
|
|
4329
|
+
/**
|
|
4330
|
+
* 构造一个不依赖组件实例的 `formState`。
|
|
4331
|
+
*
|
|
4332
|
+
* 字段结构与 `Form.vue` 中 provide 给子树的 `mForm` 保持一致,使配置里的
|
|
4333
|
+
* `display` / `rules.validator` / `filter` 等回调拿到的上下文与渲染式校验相同。
|
|
4334
|
+
*
|
|
4335
|
+
* 差异:没有真实的表单实例,因此 `$emit` 为空实现、`fields` 注册表始终为空
|
|
4336
|
+
* (该注册表在整个仓库中只写不读,不参与校验)。
|
|
4337
|
+
*/
|
|
4338
|
+
var createHeadlessFormState = (options) => {
|
|
4339
|
+
const context = options.context ?? {};
|
|
4340
|
+
const state = {
|
|
4341
|
+
keyProp: options.keyProp ?? "__key",
|
|
4342
|
+
popperClass: options.popperClass ?? "",
|
|
4343
|
+
config: options.config,
|
|
4344
|
+
initValues: options.initValues ?? {},
|
|
4345
|
+
isCompare: false,
|
|
4346
|
+
lastValues: {},
|
|
4347
|
+
parentValues: options.parentValues ?? {},
|
|
4348
|
+
values: {},
|
|
4349
|
+
lastValuesProcessed: {},
|
|
4350
|
+
$emit: () => void 0,
|
|
4351
|
+
...createFormStateBase()
|
|
4352
|
+
};
|
|
4353
|
+
return createFormStateProxy((0, vue.reactive)(state), () => context);
|
|
4354
|
+
};
|
|
4355
|
+
/**
|
|
4356
|
+
* 按 prop 路径从表单值中取字段值,路径中断时返回 `undefined`。
|
|
4357
|
+
*
|
|
4358
|
+
* 不复用 `@tmagic/utils` 的 `getValueByKeyPath`:后者在路径中断时抛错,
|
|
4359
|
+
* 而 Element Plus 的 FormItem 取值是宽松的(拿不到就是 `undefined`),此处与之对齐。
|
|
4360
|
+
*/
|
|
4361
|
+
var getFieldValue = (prop, values) => {
|
|
4362
|
+
if (!prop) return void 0;
|
|
4363
|
+
return prop.split(".").reduce((acc, key) => {
|
|
4364
|
+
if (acc === null || typeof acc !== "object") return void 0;
|
|
4365
|
+
return acc[key];
|
|
4366
|
+
}, values);
|
|
4367
|
+
};
|
|
4368
|
+
/**
|
|
4369
|
+
* 校验单个字段,返回 async-validator 的 `fields` 错误映射(通过则返回 `null`)。
|
|
4370
|
+
*
|
|
4371
|
+
* 与 Element Plus 的 FormItem 逐字段校验保持一致:
|
|
4372
|
+
* 每个字段独立构造一个 `Schema({ [prop]: rules })`,以字段自身的值为 source,
|
|
4373
|
+
* 并开启 `firstFields` 只取每个字段的首条错误;`trigger` 是 FormItem 用来筛选规则的
|
|
4374
|
+
* 元信息,交给 async-validator 前必须剔除,否则会改变规则的匹配方式。
|
|
4375
|
+
*/
|
|
4376
|
+
var validateField = async (field, values) => {
|
|
4377
|
+
const rules = field.rules.map(({ trigger, ...rule }) => rule);
|
|
4378
|
+
if (!rules.length) return null;
|
|
4379
|
+
const value = getFieldValue(field.prop, values);
|
|
4380
|
+
try {
|
|
4381
|
+
await new async_validator.default({ [field.prop]: rules }).validate({ [field.prop]: value }, { firstFields: true });
|
|
4382
|
+
return null;
|
|
4383
|
+
} catch (err) {
|
|
4384
|
+
if (err?.fields) return err.fields;
|
|
4385
|
+
return { [field.prop]: [{
|
|
4386
|
+
field: field.prop,
|
|
4387
|
+
message: err?.message ?? `${err}`
|
|
4388
|
+
}] };
|
|
3459
4389
|
}
|
|
3460
|
-
|
|
4390
|
+
};
|
|
4391
|
+
/**
|
|
4392
|
+
* 不挂载任何组件,纯逻辑地对「一份 config + 一份值」执行一次完整校验。
|
|
4393
|
+
*
|
|
4394
|
+
* 流程与渲染式校验一一对应,但不需要 DOM,也不会实例化任何字段组件:
|
|
4395
|
+
*
|
|
4396
|
+
* 1. 构造 headless `formState` 并挂上 `context` 读穿;
|
|
4397
|
+
* 2. `initValue` 初始化表单值(默认值、嵌套结构、`onInitValue` 等);
|
|
4398
|
+
* 3. `applyMountValueEffects` 执行字段登记的值初始化写入(与渲染式共用同一份登记表);
|
|
4399
|
+
* 4. 遍历 config 树收集所有带规则的字段(等价于渲染出的 FormItem 集合);
|
|
4400
|
+
* 5. 逐字段交给 async-validator 执行,汇总错误文案。
|
|
4401
|
+
*
|
|
4402
|
+
* @example
|
|
4403
|
+
* ```ts
|
|
4404
|
+
* const { error, values } = await validateValues({
|
|
4405
|
+
* config: [...],
|
|
4406
|
+
* initValues: { name: '' },
|
|
4407
|
+
* typeMatchValid: true,
|
|
4408
|
+
* });
|
|
4409
|
+
* ```
|
|
4410
|
+
*/
|
|
4411
|
+
var validateValues = async (options) => {
|
|
4412
|
+
const { config, initValues = {}, typeMatchValid, useFieldTextInError = true } = options;
|
|
4413
|
+
const formState = createHeadlessFormState(options);
|
|
4414
|
+
const values = await initValue(formState, {
|
|
4415
|
+
initValues,
|
|
4416
|
+
config
|
|
4417
|
+
});
|
|
4418
|
+
formState.values = values;
|
|
4419
|
+
applyMountValueEffects(formState, config, values);
|
|
4420
|
+
const fields = collectValidatableFields(formState, config, values, Boolean(typeMatchValid));
|
|
4421
|
+
const invalidFields = {};
|
|
4422
|
+
for (const field of fields) {
|
|
4423
|
+
const fieldErrors = await validateField(field, values);
|
|
4424
|
+
if (fieldErrors) Object.assign(invalidFields, fieldErrors);
|
|
4425
|
+
}
|
|
4426
|
+
return {
|
|
4427
|
+
values,
|
|
4428
|
+
invalidFields,
|
|
4429
|
+
error: formatValidateError(invalidFields, {
|
|
4430
|
+
config,
|
|
4431
|
+
useFieldTextInError
|
|
4432
|
+
})
|
|
4433
|
+
};
|
|
4434
|
+
};
|
|
4435
|
+
//#endregion
|
|
4436
|
+
//#region packages/form/src/utils/submitHeadless.ts
|
|
4437
|
+
var throwIfAborted = (signal, fnName) => {
|
|
4438
|
+
if (signal?.aborted) throw signal.reason ?? /* @__PURE__ */ new Error(`${fnName} aborted`);
|
|
4439
|
+
};
|
|
4440
|
+
var throwIfDialog = (dialog, fnName) => {
|
|
4441
|
+
if (dialog) throw new Error(`[MForm] ${fnName}({ dialog: true }) is not available from @tmagic/form/headless. Import from @tmagic/form instead.`);
|
|
4442
|
+
};
|
|
4443
|
+
/**
|
|
4444
|
+
* `submitForm` 与 `validateForm` 共用的无渲染校验流程:中断检查 → `validateValues`。
|
|
4445
|
+
*/
|
|
4446
|
+
var validateWithoutRender = async (fnName, options) => {
|
|
4447
|
+
const { signal, config, initValues, parentValues, keyProp, typeMatchValid, useFieldTextInError, context } = options;
|
|
4448
|
+
throwIfAborted(signal, fnName);
|
|
4449
|
+
const result = await validateValues({
|
|
4450
|
+
config,
|
|
4451
|
+
initValues,
|
|
4452
|
+
parentValues,
|
|
4453
|
+
keyProp,
|
|
4454
|
+
popperClass: options.popperClass,
|
|
4455
|
+
typeMatchValid,
|
|
4456
|
+
useFieldTextInError,
|
|
4457
|
+
context
|
|
4458
|
+
});
|
|
4459
|
+
throwIfAborted(signal, fnName);
|
|
4460
|
+
return result;
|
|
4461
|
+
};
|
|
4462
|
+
/**
|
|
4463
|
+
* 以命令式方式对一份「表单配置 + 值」做一次校验并取回表单值(无渲染)。
|
|
4464
|
+
*
|
|
4465
|
+
* `@tmagic/form/headless` 不支持 `dialog: true`。
|
|
4466
|
+
*/
|
|
4467
|
+
var submitForm$1 = async (options) => {
|
|
4468
|
+
throwIfDialog(options.dialog, "submitForm");
|
|
4469
|
+
const validated = await validateWithoutRender("submitForm", options);
|
|
4470
|
+
if (validated.error) throw new Error(validated.error);
|
|
4471
|
+
const values = options.native ? validated.values : cloneDeep(validated.values);
|
|
4472
|
+
return options.returnChangeRecords ? {
|
|
4473
|
+
values,
|
|
4474
|
+
changeRecords: []
|
|
4475
|
+
} : values;
|
|
4476
|
+
};
|
|
4477
|
+
/**
|
|
4478
|
+
* 以命令式方式对一份「表单配置 + 值」做一次静默校验(无渲染)。
|
|
4479
|
+
*
|
|
4480
|
+
* `@tmagic/form/headless` 不支持 `dialog: true`。
|
|
4481
|
+
*/
|
|
4482
|
+
var validateForm$1 = async (options) => {
|
|
4483
|
+
throwIfDialog(options.dialog, "validateForm");
|
|
4484
|
+
return (await validateWithoutRender("validateForm", options)).error;
|
|
3461
4485
|
};
|
|
3462
4486
|
//#endregion
|
|
3463
4487
|
//#region packages/form/src/utils/useAddField.ts
|
|
@@ -3492,67 +4516,156 @@
|
|
|
3492
4516
|
}
|
|
3493
4517
|
});
|
|
3494
4518
|
//#endregion
|
|
3495
|
-
//#region packages/form/src/utils/
|
|
3496
|
-
var
|
|
3497
|
-
var
|
|
3498
|
-
var
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
var fieldRegistry = /* @__PURE__ */ new Map();
|
|
3504
|
-
var registerField = (tagName, component) => {
|
|
3505
|
-
if (fieldRegistry.has(tagName)) return;
|
|
3506
|
-
fieldRegistry.set(tagName, component);
|
|
4519
|
+
//#region packages/form/src/utils/registerField.ts
|
|
4520
|
+
var extraComponents = /* @__PURE__ */ new Map();
|
|
4521
|
+
var builtInComponents = /* @__PURE__ */ new Map();
|
|
4522
|
+
var applyVueComponent = (type, component, app, builtIn, kind) => {
|
|
4523
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
4524
|
+
if (builtIn) builtInComponents.set(key, component);
|
|
4525
|
+
else extraComponents.set(key, component);
|
|
4526
|
+
app?.component(`m-${kind}-${key}`, component);
|
|
3507
4527
|
};
|
|
3508
|
-
var getField = (tagName) => fieldRegistry.get(tagName);
|
|
3509
|
-
var deleteField = (tagName) => fieldRegistry.delete(tagName);
|
|
3510
|
-
//#endregion
|
|
3511
|
-
//#region packages/form/src/utils/silentLeafFieldTypes.ts
|
|
3512
4528
|
/**
|
|
3513
|
-
*
|
|
4529
|
+
* 把多份字段登记表按 type 浅合并。后一份只覆盖自己带了的 key,未出现的 key 保留前一份。
|
|
3514
4530
|
*
|
|
3515
|
-
*
|
|
3516
|
-
* 字段值由初始化逻辑处理(包括 defaultValue),因此跳过不影响校验结果。
|
|
4531
|
+
* 安装插件时用:Node 侧只登记 `headless`,浏览器再补 `component` / `container`。
|
|
3517
4532
|
*
|
|
3518
|
-
*
|
|
4533
|
+
* @param tables - 待合并的登记表,`undefined` 会被跳过
|
|
4534
|
+
* @returns 合并后的登记表
|
|
3519
4535
|
*/
|
|
3520
|
-
var
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
"
|
|
3533
|
-
"
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
4536
|
+
var mergeFieldOptions = (...tables) => {
|
|
4537
|
+
const result = {};
|
|
4538
|
+
for (const table of tables) {
|
|
4539
|
+
if (!table) continue;
|
|
4540
|
+
for (const [type, options] of Object.entries(table)) result[type] = {
|
|
4541
|
+
...result[type],
|
|
4542
|
+
...pickDefinedFieldOptions(options)
|
|
4543
|
+
};
|
|
4544
|
+
}
|
|
4545
|
+
return result;
|
|
4546
|
+
};
|
|
4547
|
+
var FIELD_OPTION_KEYS = [
|
|
4548
|
+
"component",
|
|
4549
|
+
"container",
|
|
4550
|
+
"effect",
|
|
4551
|
+
"walk",
|
|
4552
|
+
"innerConfig",
|
|
4553
|
+
"typeMatch"
|
|
4554
|
+
];
|
|
4555
|
+
var pickDefinedFieldOptions = (options) => {
|
|
4556
|
+
if (!options) return {};
|
|
4557
|
+
const next = {};
|
|
4558
|
+
for (const key of FIELD_OPTION_KEYS) if (options[key] !== void 0) next[key] = options[key];
|
|
4559
|
+
return next;
|
|
4560
|
+
};
|
|
4561
|
+
var extraFieldOptions = /* @__PURE__ */ new Map();
|
|
4562
|
+
var builtInFieldOptions = /* @__PURE__ */ new Map();
|
|
4563
|
+
var removeFormComponent = (type) => {
|
|
4564
|
+
extraComponents.delete((0, _tmagic_utils.toLine)(type));
|
|
4565
|
+
};
|
|
4566
|
+
var clearFormComponents = () => {
|
|
4567
|
+
extraComponents.clear();
|
|
4568
|
+
};
|
|
3537
4569
|
/**
|
|
3538
|
-
*
|
|
4570
|
+
* 按字段 type 取已登记的渲染组件(`codeSelect` 与 `code-select` 等价)。
|
|
3539
4571
|
*
|
|
3540
|
-
*
|
|
4572
|
+
* @param type - 字段 type
|
|
4573
|
+
* @returns 已登记的 Vue 组件;未登记则为 `undefined`
|
|
3541
4574
|
*/
|
|
3542
|
-
var
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
4575
|
+
var getField = (type) => {
|
|
4576
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
4577
|
+
return extraComponents.get(key) ?? builtInComponents.get(key);
|
|
4578
|
+
};
|
|
4579
|
+
var registerFieldImpl = (type, options, app, builtIn) => {
|
|
4580
|
+
if (typeof type !== "string" || !type) return;
|
|
4581
|
+
const key = (0, _tmagic_utils.toLine)(type);
|
|
4582
|
+
const store = builtIn ? builtInFieldOptions : extraFieldOptions;
|
|
4583
|
+
const incoming = pickDefinedFieldOptions(options);
|
|
4584
|
+
const merged = {
|
|
4585
|
+
...store.get(key),
|
|
4586
|
+
...incoming
|
|
4587
|
+
};
|
|
4588
|
+
store.set(key, merged);
|
|
4589
|
+
if (incoming.walk && (incoming.innerConfig || typeof incoming.effect === "function")) console.warn(`[MForm] registerField("${key}"): walk is set together with innerConfig/effect; headless validation will use walk and innerConfig/effect will be ignored.`);
|
|
4590
|
+
if (incoming.component && incoming.container) console.warn(`[MForm] registerField("${key}"): component and container are both set; getField will use container, and both m-fields-* / m-form-* will be registered.`);
|
|
4591
|
+
if (merged.component) applyVueComponent(type, merged.component, app, builtIn, "fields");
|
|
4592
|
+
if (merged.container) applyVueComponent(type, merged.container, app, builtIn, "form");
|
|
4593
|
+
if (merged.typeMatch) registerTypeMatchRule(type, merged.typeMatch, builtIn);
|
|
4594
|
+
if (merged.walk) {
|
|
4595
|
+
registerContainerWalker(type, merged.walk, builtIn);
|
|
4596
|
+
if (!builtIn) {
|
|
4597
|
+
deleteLeafFieldType(type);
|
|
4598
|
+
deleteFieldInnerConfig(type);
|
|
4599
|
+
}
|
|
4600
|
+
return;
|
|
3546
4601
|
}
|
|
4602
|
+
if (!builtIn) deleteContainerWalker(type);
|
|
4603
|
+
if (merged.innerConfig) {
|
|
4604
|
+
registerFieldInnerConfig(type, merged.innerConfig, builtIn);
|
|
4605
|
+
if (typeof merged.effect === "function") registerLeafFieldType(type, merged.effect, builtIn);
|
|
4606
|
+
else if (!builtIn) deleteLeafFieldType(type);
|
|
4607
|
+
return;
|
|
4608
|
+
}
|
|
4609
|
+
if (merged.container && !merged.component && typeof merged.effect !== "function") {
|
|
4610
|
+
if (!builtIn) deleteLeafFieldType(type);
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4613
|
+
if (!builtIn) deleteFieldInnerConfig(type);
|
|
4614
|
+
registerLeafFieldType(type, merged.effect, builtIn);
|
|
3547
4615
|
};
|
|
3548
|
-
/**
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
4616
|
+
/**
|
|
4617
|
+
* 登记一个字段 type 在无渲染校验里的行为,以及可选的渲染组件。
|
|
4618
|
+
*
|
|
4619
|
+
* `type` 会按 Container 的规则归一化为中划线形式(`codeSelect` 与 `code-select` 等价)。
|
|
4620
|
+
* 对同一 type 重复登记按字段浅合并:后一次只覆盖自己传入的 key,未传入的 key 保留。
|
|
4621
|
+
* 传入 `app` 且带了 `component` / `container` 时,会同步 `app.component('m-fields-*'` / `'m-form-*')`。
|
|
4622
|
+
*
|
|
4623
|
+
* @param type - 字段 type
|
|
4624
|
+
* @param [options] - 登记项;省略或空对象视为叶子
|
|
4625
|
+
* @param [app] - Vue 应用;省略则不调用 `app.component`
|
|
4626
|
+
*/
|
|
4627
|
+
var registerField = (type, options, app) => {
|
|
4628
|
+
registerFieldImpl(type, options, app, false);
|
|
3552
4629
|
};
|
|
3553
|
-
/**
|
|
3554
|
-
|
|
3555
|
-
|
|
4630
|
+
/**
|
|
4631
|
+
* 批量登记字段。
|
|
4632
|
+
*
|
|
4633
|
+
* @param fields - type 到登记项的映射
|
|
4634
|
+
* @param [app] - Vue 应用;省略则不调用 `app.component`
|
|
4635
|
+
*/
|
|
4636
|
+
var registerFields = (fields, app) => {
|
|
4637
|
+
for (const [type, options] of Object.entries(fields)) registerFieldImpl(type, options, app, false);
|
|
4638
|
+
};
|
|
4639
|
+
/**
|
|
4640
|
+
* 登记内置字段(`clearFields` / `unregisterField` 不会清掉)。
|
|
4641
|
+
*
|
|
4642
|
+
* @param fields - type 到登记项的映射
|
|
4643
|
+
* @param [app] - Vue 应用;省略则不调用 `app.component`
|
|
4644
|
+
*/
|
|
4645
|
+
var registerBuiltInFields = (fields, app) => {
|
|
4646
|
+
for (const [type, options] of Object.entries(fields)) registerFieldImpl(type, options, app, true);
|
|
4647
|
+
};
|
|
4648
|
+
/**
|
|
4649
|
+
* 删除业务侧对指定 type 的登记(不影响内置;主要用于单测)。
|
|
4650
|
+
*
|
|
4651
|
+
* @param type - 字段 type
|
|
4652
|
+
*/
|
|
4653
|
+
var unregisterField = (type) => {
|
|
4654
|
+
extraFieldOptions.delete((0, _tmagic_utils.toLine)(type));
|
|
4655
|
+
deleteLeafFieldType(type);
|
|
4656
|
+
deleteFieldInnerConfig(type);
|
|
4657
|
+
deleteTypeMatchRule(type);
|
|
4658
|
+
deleteContainerWalker(type);
|
|
4659
|
+
removeFormComponent(type);
|
|
4660
|
+
};
|
|
4661
|
+
/** 清空业务侧登记(不影响内置;主要用于单测)。 */
|
|
4662
|
+
var clearFields = () => {
|
|
4663
|
+
extraFieldOptions.clear();
|
|
4664
|
+
clearLeafFieldTypes();
|
|
4665
|
+
clearFieldInnerConfigs();
|
|
4666
|
+
clearTypeMatchRules();
|
|
4667
|
+
clearContainerWalkers();
|
|
4668
|
+
clearFormComponents();
|
|
3556
4669
|
};
|
|
3557
4670
|
//#endregion
|
|
3558
4671
|
//#region packages/form/src/containers/FormLabel.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -3612,7 +4725,7 @@
|
|
|
3612
4725
|
};
|
|
3613
4726
|
var _hoisted_3$7 = ["innerHTML"];
|
|
3614
4727
|
var _hoisted_4$6 = ["innerHTML"];
|
|
3615
|
-
var _hoisted_5$
|
|
4728
|
+
var _hoisted_5$5 = ["innerHTML"];
|
|
3616
4729
|
var _hoisted_6$3 = ["innerHTML"];
|
|
3617
4730
|
var _hoisted_7$2 = ["innerHTML"];
|
|
3618
4731
|
var _hoisted_8$2 = ["innerHTML"];
|
|
@@ -3633,6 +4746,7 @@
|
|
|
3633
4746
|
prop: { default: "" },
|
|
3634
4747
|
disabled: { type: Boolean },
|
|
3635
4748
|
labelWidth: {},
|
|
4749
|
+
labelPosition: {},
|
|
3636
4750
|
expandMore: {
|
|
3637
4751
|
type: Boolean,
|
|
3638
4752
|
default: false
|
|
@@ -3668,20 +4782,8 @@
|
|
|
3668
4782
|
return !isEqual(curValue, lastValue);
|
|
3669
4783
|
});
|
|
3670
4784
|
const items = (0, vue.computed)(() => props.config.items);
|
|
3671
|
-
const itemProp = (0, vue.computed)(() =>
|
|
3672
|
-
|
|
3673
|
-
if (name.value) n = name.value;
|
|
3674
|
-
else return props.prop;
|
|
3675
|
-
if (typeof props.prop !== "undefined" && props.prop !== "") return `${props.prop}.${n}`;
|
|
3676
|
-
return `${n}`;
|
|
3677
|
-
});
|
|
3678
|
-
const type = (0, vue.computed)(() => {
|
|
3679
|
-
let type = "type" in props.config ? props.config.type : "";
|
|
3680
|
-
type = type && filterFunction(mForm, type, props);
|
|
3681
|
-
if (type === "form") return "";
|
|
3682
|
-
if (type === "container") return "";
|
|
3683
|
-
return type?.replace(/([A-Z])/g, "-$1").toLowerCase() || (items.value ? "" : "text");
|
|
3684
|
-
});
|
|
4785
|
+
const itemProp = (0, vue.computed)(() => getItemProp(props.prop, name.value));
|
|
4786
|
+
const type = (0, vue.computed)(() => resolveItemType(mForm, props.config, props));
|
|
3685
4787
|
const tagName = (0, vue.computed)(() => {
|
|
3686
4788
|
if (type.value === "component" && props.config.component) return props.config.component;
|
|
3687
4789
|
return getField(type.value || "container") || `m-${items.value ? "form" : "fields"}-${type.value}`;
|
|
@@ -3715,8 +4817,6 @@
|
|
|
3715
4817
|
return new Set(DEFAULT_SELF_DIFF_FIELD_TYPES);
|
|
3716
4818
|
});
|
|
3717
4819
|
const isSelfDiffField = (0, vue.computed)(() => effectiveSelfDiffFieldTypes.value.has(type.value));
|
|
3718
|
-
const silentMode = (0, vue.inject)(FORM_SILENT_MODE_KEY, false);
|
|
3719
|
-
const shouldRenderLeafField = (0, vue.computed)(() => !silentMode || !getSilentLeafFieldTypes().has(type.value));
|
|
3720
4820
|
const disabled = (0, vue.computed)(() => props.disabled || filterFunction(mForm, props.config.disabled, props));
|
|
3721
4821
|
const text = (0, vue.computed)(() => filterFunction(mForm, props.config.text, props));
|
|
3722
4822
|
const tooltip = (0, vue.computed)(() => {
|
|
@@ -3748,12 +4848,13 @@
|
|
|
3748
4848
|
const formItemProps = (0, vue.computed)(() => ({
|
|
3749
4849
|
prop: itemProp.value,
|
|
3750
4850
|
labelWidth: itemLabelWidth.value,
|
|
3751
|
-
labelPosition:
|
|
4851
|
+
labelPosition: itemLabelPosition.value,
|
|
3752
4852
|
rules: rule.value,
|
|
3753
4853
|
extra: filterFunction(mForm, props.config.extra, props),
|
|
3754
4854
|
extraTips: props.config.extraTips
|
|
3755
4855
|
}));
|
|
3756
4856
|
const itemLabelWidth = (0, vue.computed)(() => props.config.labelWidth ?? props.labelWidth);
|
|
4857
|
+
const itemLabelPosition = (0, vue.computed)(() => props.config.labelPosition ?? props.labelPosition);
|
|
3757
4858
|
(0, vue.watchEffect)(() => {
|
|
3758
4859
|
expand.value = props.expandMore;
|
|
3759
4860
|
});
|
|
@@ -3782,13 +4883,7 @@
|
|
|
3782
4883
|
};
|
|
3783
4884
|
const onAddDiffCount = () => emit("addDiffCount");
|
|
3784
4885
|
const hasModifyKey = (eventDataItem) => typeof eventDataItem?.modifyKey !== "undefined" && eventDataItem.modifyKey !== "";
|
|
3785
|
-
const isValidName = () =>
|
|
3786
|
-
const valueType = typeof name.value;
|
|
3787
|
-
if (valueType !== "string" && valueType !== "symbol" && valueType !== "number") return false;
|
|
3788
|
-
if (name.value === "") return false;
|
|
3789
|
-
if (typeof name.value === "number") return name.value >= 0;
|
|
3790
|
-
return true;
|
|
3791
|
-
};
|
|
4886
|
+
const isValidName$1 = () => isValidName(name.value);
|
|
3792
4887
|
const createModelProxy = (target, setModelFn, pathPrefix = "") => {
|
|
3793
4888
|
return new Proxy(target, {
|
|
3794
4889
|
get: (obj, key) => {
|
|
@@ -3880,6 +4975,7 @@
|
|
|
3880
4975
|
"step-active": __props.stepActive,
|
|
3881
4976
|
"expand-more": expand.value,
|
|
3882
4977
|
"label-width": itemLabelWidth.value,
|
|
4978
|
+
"label-position": itemLabelPosition.value,
|
|
3883
4979
|
style: __props.config.fieldStyle,
|
|
3884
4980
|
onChange: onChangeHandler,
|
|
3885
4981
|
onAddDiffCount
|
|
@@ -3890,9 +4986,10 @@
|
|
|
3890
4986
|
"step-active",
|
|
3891
4987
|
"expand-more",
|
|
3892
4988
|
"label-width",
|
|
4989
|
+
"label-position",
|
|
3893
4990
|
"style"
|
|
3894
4991
|
])) : 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 } }), {
|
|
3895
|
-
label: (0, vue.withCtx)(() => [
|
|
4992
|
+
label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
|
|
3896
4993
|
config: __props.config,
|
|
3897
4994
|
type: type.value,
|
|
3898
4995
|
text: text.value,
|
|
@@ -3910,8 +5007,8 @@
|
|
|
3910
5007
|
"use-label",
|
|
3911
5008
|
"label-title",
|
|
3912
5009
|
"text"
|
|
3913
|
-
]), __props.config.titleExtra &&
|
|
3914
|
-
default: (0, vue.withCtx)(() => [
|
|
5010
|
+
]), __props.config.titleExtra && itemLabelPosition.value === "top" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_2$8, (0, vue.toDisplayString)(__props.config.titleExtra), 1)) : (0, vue.createCommentVNode)("v-if", true)])]),
|
|
5011
|
+
default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
3915
5012
|
key: 0,
|
|
3916
5013
|
placement: tooltip.value.placement
|
|
3917
5014
|
}, {
|
|
@@ -3938,9 +5035,9 @@
|
|
|
3938
5035
|
"model",
|
|
3939
5036
|
"last-values",
|
|
3940
5037
|
"is-compare"
|
|
3941
|
-
]))]
|
|
5038
|
+
]))]),
|
|
3942
5039
|
_: 3
|
|
3943
|
-
}, 16, ["class"]),
|
|
5040
|
+
}, 16, ["class"]), __props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
3944
5041
|
key: 0,
|
|
3945
5042
|
placement: "top"
|
|
3946
5043
|
}, {
|
|
@@ -3960,7 +5057,7 @@
|
|
|
3960
5057
|
"tmagic-form-hidden": `${itemLabelWidth.value}` === "0" || !text.value,
|
|
3961
5058
|
"self-diff": true
|
|
3962
5059
|
} }), {
|
|
3963
|
-
label: (0, vue.withCtx)(() => [
|
|
5060
|
+
label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
|
|
3964
5061
|
config: __props.config,
|
|
3965
5062
|
type: type.value,
|
|
3966
5063
|
text: text.value,
|
|
@@ -3978,12 +5075,12 @@
|
|
|
3978
5075
|
"use-label",
|
|
3979
5076
|
"label-title",
|
|
3980
5077
|
"text"
|
|
3981
|
-
])]
|
|
3982
|
-
default: (0, vue.withCtx)(() => [
|
|
5078
|
+
])])]),
|
|
5079
|
+
default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
3983
5080
|
key: 0,
|
|
3984
5081
|
placement: tooltip.value.placement
|
|
3985
5082
|
}, {
|
|
3986
|
-
content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$
|
|
5083
|
+
content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$5)]),
|
|
3987
5084
|
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
|
|
3988
5085
|
model: __props.model,
|
|
3989
5086
|
"last-values": __props.lastValues,
|
|
@@ -4004,7 +5101,7 @@
|
|
|
4004
5101
|
"model",
|
|
4005
5102
|
"last-values",
|
|
4006
5103
|
"is-compare"
|
|
4007
|
-
]))]
|
|
5104
|
+
]))]),
|
|
4008
5105
|
_: 3
|
|
4009
5106
|
}, 16, ["class"])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [
|
|
4010
5107
|
(0, vue.createCommentVNode)(" 普通字段:渲染前后两份独立的组件用于对比 "),
|
|
@@ -4013,7 +5110,7 @@
|
|
|
4013
5110
|
"tmagic-form-hidden": `${itemLabelWidth.value}` === "0" || !text.value,
|
|
4014
5111
|
"show-before-diff": true
|
|
4015
5112
|
} }), {
|
|
4016
|
-
label: (0, vue.withCtx)(() => [
|
|
5113
|
+
label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
|
|
4017
5114
|
config: __props.config,
|
|
4018
5115
|
type: type.value,
|
|
4019
5116
|
text: text.value,
|
|
@@ -4031,8 +5128,8 @@
|
|
|
4031
5128
|
"use-label",
|
|
4032
5129
|
"label-title",
|
|
4033
5130
|
"text"
|
|
4034
|
-
])]
|
|
4035
|
-
default: (0, vue.withCtx)(() => [
|
|
5131
|
+
])])]),
|
|
5132
|
+
default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
4036
5133
|
key: 0,
|
|
4037
5134
|
placement: tooltip.value.placement
|
|
4038
5135
|
}, {
|
|
@@ -4045,10 +5142,10 @@
|
|
|
4045
5142
|
}, 8, ["placement"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
|
|
4046
5143
|
model: __props.lastValues,
|
|
4047
5144
|
onChange: onChangeHandler
|
|
4048
|
-
}), null, 16, ["model"]))]
|
|
5145
|
+
}), null, 16, ["model"]))]),
|
|
4049
5146
|
_: 3
|
|
4050
5147
|
}, 16, ["class"]),
|
|
4051
|
-
|
|
5148
|
+
__props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
4052
5149
|
key: 0,
|
|
4053
5150
|
placement: "top"
|
|
4054
5151
|
}, {
|
|
@@ -4070,7 +5167,7 @@
|
|
|
4070
5167
|
"show-after-diff": true
|
|
4071
5168
|
}
|
|
4072
5169
|
}), {
|
|
4073
|
-
label: (0, vue.withCtx)(() => [
|
|
5170
|
+
label: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "label", {
|
|
4074
5171
|
config: __props.config,
|
|
4075
5172
|
type: type.value,
|
|
4076
5173
|
text: text.value,
|
|
@@ -4088,8 +5185,8 @@
|
|
|
4088
5185
|
"use-label",
|
|
4089
5186
|
"label-title",
|
|
4090
5187
|
"text"
|
|
4091
|
-
])]
|
|
4092
|
-
default: (0, vue.withCtx)(() => [
|
|
5188
|
+
])])]),
|
|
5189
|
+
default: (0, vue.withCtx)(() => [tooltip.value.text ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
4093
5190
|
key: 0,
|
|
4094
5191
|
placement: tooltip.value.placement
|
|
4095
5192
|
}, {
|
|
@@ -4102,10 +5199,10 @@
|
|
|
4102
5199
|
}, 8, ["placement"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
|
|
4103
5200
|
model: __props.model,
|
|
4104
5201
|
onChange: onChangeHandler
|
|
4105
|
-
}), null, 16, ["model"]))]
|
|
5202
|
+
}), null, 16, ["model"]))]),
|
|
4106
5203
|
_: 3
|
|
4107
5204
|
}, 16, ["style", "class"]),
|
|
4108
|
-
|
|
5205
|
+
__props.config.tip && type.value === "checkbox" && !__props.config.useLabel ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
4109
5206
|
key: 1,
|
|
4110
5207
|
placement: "top"
|
|
4111
5208
|
}, {
|
|
@@ -4120,11 +5217,11 @@
|
|
|
4120
5217
|
_: 1
|
|
4121
5218
|
})) : (0, vue.createCommentVNode)("v-if", true)
|
|
4122
5219
|
], 64))
|
|
4123
|
-
], 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) => {
|
|
5220
|
+
], 64)) : items.value && display$3.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 4 }, [(isValidName$1() ? __props.model[name.value] : __props.model) ? ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, (0, vue.renderList)(items.value, (item) => {
|
|
4124
5221
|
return (0, vue.openBlock)(), (0, vue.createBlock)(_component_Container, {
|
|
4125
5222
|
key: key(item),
|
|
4126
|
-
model: isValidName() ? __props.model[name.value] : __props.model,
|
|
4127
|
-
"last-values": isValidName() ? __props.lastValues[name.value] || {} : __props.lastValues,
|
|
5223
|
+
model: isValidName$1() ? __props.model[name.value] : __props.model,
|
|
5224
|
+
"last-values": isValidName$1() ? __props.lastValues[name.value] || {} : __props.lastValues,
|
|
4128
5225
|
"is-compare": __props.isCompare,
|
|
4129
5226
|
config: item,
|
|
4130
5227
|
size: __props.size,
|
|
@@ -4132,6 +5229,7 @@
|
|
|
4132
5229
|
"step-active": __props.stepActive,
|
|
4133
5230
|
"expand-more": expand.value,
|
|
4134
5231
|
"label-width": itemLabelWidth.value,
|
|
5232
|
+
"label-position": itemLabelPosition.value,
|
|
4135
5233
|
prop: itemProp.value,
|
|
4136
5234
|
onChange: onChangeHandler,
|
|
4137
5235
|
onAddDiffCount
|
|
@@ -4149,6 +5247,7 @@
|
|
|
4149
5247
|
"step-active",
|
|
4150
5248
|
"expand-more",
|
|
4151
5249
|
"label-width",
|
|
5250
|
+
"label-position",
|
|
4152
5251
|
"prop"
|
|
4153
5252
|
]);
|
|
4154
5253
|
}), 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_10, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
@@ -4204,7 +5303,7 @@
|
|
|
4204
5303
|
type: Boolean,
|
|
4205
5304
|
default: true
|
|
4206
5305
|
},
|
|
4207
|
-
|
|
5306
|
+
context: {},
|
|
4208
5307
|
showDiff: {},
|
|
4209
5308
|
selfDiffFieldTypes: {},
|
|
4210
5309
|
theme: {}
|
|
@@ -4224,8 +5323,6 @@
|
|
|
4224
5323
|
const initialized = (0, vue.ref)(false);
|
|
4225
5324
|
const values = (0, vue.ref)({});
|
|
4226
5325
|
const lastValuesProcessed = (0, vue.ref)({});
|
|
4227
|
-
const fields = /* @__PURE__ */ new Map();
|
|
4228
|
-
const requestFuc = getConfig("request");
|
|
4229
5326
|
/**
|
|
4230
5327
|
* 当前表单生效的主题名称:
|
|
4231
5328
|
* - 优先用本组件自己的 `props.theme`;
|
|
@@ -4255,18 +5352,14 @@
|
|
|
4255
5352
|
* 2. `values` / `lastValuesProcessed` 是 ref,Vue 的 `reactive` 会自动解包,因此每次
|
|
4256
5353
|
* 访问 `formState.values` / `formState.lastValuesProcessed` 也都是当前 ref 值。
|
|
4257
5354
|
*
|
|
4258
|
-
* 3.
|
|
4259
|
-
*
|
|
4260
|
-
* set,触发依赖通知;`extendState` 同步段读到的响应式数据变化时会自动重跑,
|
|
4261
|
-
* 把最新值刷进 formState。
|
|
4262
|
-
* - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
|
|
4263
|
-
* 读时求值,每次读取都会重新执行 getter。
|
|
5355
|
+
* 3. 宿主业务上下文不再 merge 进 coreState,而是单独放在 `contextRef` 上,由读穿
|
|
5356
|
+
* Proxy 在 miss 时落到 context。核心字段结构性优先,`mForm.xxx` 永久兼容旧读法。
|
|
4264
5357
|
*
|
|
4265
5358
|
* 4. `popperClass` 会自动拼接 `themeClass`:调用方传入的 `popperClass` + 当前主题
|
|
4266
5359
|
* 修饰类(含祖先 `<MEditor>` provide 的主题)。这样所有透传到 Element Plus 弹层
|
|
4267
5360
|
* `popper-class` 的字段(Select / DateTime / Cascader 等)能自带主题作用域。
|
|
4268
5361
|
*/
|
|
4269
|
-
const
|
|
5362
|
+
const coreState = (0, vue.reactive)({
|
|
4270
5363
|
get keyProp() {
|
|
4271
5364
|
return props.keyProp;
|
|
4272
5365
|
},
|
|
@@ -4295,68 +5388,20 @@
|
|
|
4295
5388
|
values,
|
|
4296
5389
|
lastValuesProcessed,
|
|
4297
5390
|
$emit: emit,
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
$messageBox: _tmagic_design.tMagicMessageBox,
|
|
4303
|
-
$message: _tmagic_design.tMagicMessage,
|
|
4304
|
-
post: (options) => {
|
|
4305
|
-
if (requestFuc) return requestFuc({
|
|
4306
|
-
method: "POST",
|
|
4307
|
-
...options
|
|
4308
|
-
});
|
|
4309
|
-
}
|
|
5391
|
+
...createFormStateBase({
|
|
5392
|
+
$message: _tmagic_design.tMagicMessage,
|
|
5393
|
+
$messageBox: _tmagic_design.tMagicMessageBox
|
|
5394
|
+
})
|
|
4310
5395
|
});
|
|
5396
|
+
const ancestorContext = (0, vue.inject)(FORM_CONTEXT_KEY, void 0);
|
|
4311
5397
|
/**
|
|
4312
|
-
*
|
|
4313
|
-
*
|
|
4314
|
-
* 在 `extendState` 首次合并前捕获,`applyExtendState` 会据此禁止 `extendState`
|
|
4315
|
-
* 覆盖这些已有字段(只能新增字段),避免表单核心状态被外部意外改写。
|
|
4316
|
-
*
|
|
4317
|
-
* 之所以在此处(effect 之外)捕获而不是在 `applyExtendState` 内动态取:
|
|
4318
|
-
* `watchEffect` 会在依赖变化时重跑,若动态取,`extendState` 自己新增的字段在第二次
|
|
4319
|
-
* 合并时也会被当成「已有 key」而拒绝刷新;这里只锁定内置字段即可规避该问题。
|
|
4320
|
-
*/
|
|
4321
|
-
const reservedStateKeys = new Set(Reflect.ownKeys(formState));
|
|
4322
|
-
/**
|
|
4323
|
-
* `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
|
|
4324
|
-
* 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
|
|
4325
|
-
*
|
|
4326
|
-
* extendState: (formState) => ({
|
|
4327
|
-
* username: store.username, // 同步读 store,会被跟踪
|
|
4328
|
-
* env: store.env,
|
|
4329
|
-
* })
|
|
4330
|
-
*
|
|
4331
|
-
* 当 `store.username` 变化时,整个 effect 重跑,新值会被刷进 `formState`。
|
|
4332
|
-
*
|
|
4333
|
-
* prop 派生字段(initValues / config / ...)已经在上方用 getter 定义,
|
|
4334
|
-
* 这里不再重复同步;因此 `props.initValues` 这类高频变化也不会再触发
|
|
4335
|
-
* `extendState` 重跑(旧版的性能问题修复点)。
|
|
4336
|
-
*
|
|
4337
|
-
* 实现细节:合并逻辑统一收口在 `applyExtendState`(utils/form)——
|
|
4338
|
-
* data 描述符走 reactive proxy 的 set 触发依赖通知(与旧版「逐项赋值」语义等价),
|
|
4339
|
-
* accessor 描述符按原样 defineProperty 支持读时求值;
|
|
4340
|
-
* props 派生的只读 getter 字段(keyProp 等)以普通字段形式返回时会被跳过并告警。
|
|
5398
|
+
* 宿主业务上下文:`props.context` 覆盖祖先注入的同名字段。
|
|
5399
|
+
* 嵌套表单(Link / FormBox / FormDialog)通过下面的 provide 自动继承。
|
|
4341
5400
|
*/
|
|
4342
|
-
(0, vue.
|
|
4343
|
-
|
|
4344
|
-
if (typeof extendState !== "function") return;
|
|
4345
|
-
let stale = false;
|
|
4346
|
-
onCleanup(() => {
|
|
4347
|
-
stale = true;
|
|
4348
|
-
});
|
|
4349
|
-
let state = {};
|
|
4350
|
-
try {
|
|
4351
|
-
state = await extendState(formState) || {};
|
|
4352
|
-
} catch (e) {
|
|
4353
|
-
console.error("[MForm] extendState failed:", e);
|
|
4354
|
-
return;
|
|
4355
|
-
}
|
|
4356
|
-
if (stale) return;
|
|
4357
|
-
applyExtendState(formState, state, reservedStateKeys);
|
|
4358
|
-
});
|
|
5401
|
+
const contextRef = (0, vue.computed)(() => mergeFormContexts(ancestorContext?.value, props.context));
|
|
5402
|
+
const formState = createFormStateProxy(coreState, () => contextRef.value);
|
|
4359
5403
|
(0, vue.provide)("mForm", formState);
|
|
5404
|
+
(0, vue.provide)(FORM_CONTEXT_KEY, contextRef);
|
|
4360
5405
|
/**
|
|
4361
5406
|
* 把生效主题(自身或祖先)再 provide 出去,供 form 子树内含 `Teleport` 的组件
|
|
4362
5407
|
* (如 `TMagicPopover`)在传送目标上挂 `m-theme--<theme>` 类。
|
|
@@ -4373,14 +5418,24 @@
|
|
|
4373
5418
|
}
|
|
4374
5419
|
});
|
|
4375
5420
|
const changeRecords = (0, vue.shallowRef)([]);
|
|
4376
|
-
|
|
5421
|
+
/**
|
|
5422
|
+
* 两份配置的结构是否一致;函数一律视为相等。
|
|
5423
|
+
*
|
|
5424
|
+
* 宿主(如编辑器属性面板)往往在每次节点更新后整份重新生成配置,其中的
|
|
5425
|
+
* `display` / `options` / `onChange` 都是新闭包,深比较必然判不等。若据此把 `initialized`
|
|
5426
|
+
* 置 false,整棵表单会卸载重挂,滚动位置、展开态、输入焦点全部丢失。
|
|
5427
|
+
* 配置是响应式 prop,闭包换了照样生效,只有结构变化(增删字段、换组件类型)才需要重挂。
|
|
5428
|
+
*/
|
|
5429
|
+
const isSameConfigShape = (config, preConfig) => isEqualWith(config, preConfig, (a, b) => typeof a === "function" && typeof b === "function" ? true : void 0);
|
|
5430
|
+
(0, vue.watch)([() => props.config, () => props.initValues], async ([config], [preConfig]) => {
|
|
4377
5431
|
changeRecords.value = [];
|
|
4378
|
-
if (!
|
|
5432
|
+
if (!isSameConfigShape((0, vue.toRaw)(config), (0, vue.toRaw)(preConfig))) initialized.value = false;
|
|
4379
5433
|
initValue(formState, {
|
|
4380
5434
|
initValues: props.initValues,
|
|
4381
5435
|
config: props.config
|
|
4382
5436
|
}).then((value) => {
|
|
4383
5437
|
values.value = value;
|
|
5438
|
+
applyMountValueEffects(formState, props.config, values.value);
|
|
4384
5439
|
initialized.value = !props.isCompare;
|
|
4385
5440
|
if (props.validateOnInit) (0, vue.nextTick)(() => {
|
|
4386
5441
|
tMagicFormRef.value?.validate();
|
|
@@ -4391,6 +5446,7 @@
|
|
|
4391
5446
|
config: props.config
|
|
4392
5447
|
}).then((value) => {
|
|
4393
5448
|
lastValuesProcessed.value = value;
|
|
5449
|
+
applyMountValueEffects(formState, props.config, lastValuesProcessed.value);
|
|
4394
5450
|
initialized.value = true;
|
|
4395
5451
|
});
|
|
4396
5452
|
}, { immediate: true });
|
|
@@ -4408,51 +5464,17 @@
|
|
|
4408
5464
|
const submitHandler = (e) => {
|
|
4409
5465
|
if (props.preventSubmitDefault) e.preventDefault();
|
|
4410
5466
|
};
|
|
4411
|
-
|
|
4412
|
-
* 通过 name 从 config 中查找对应的 text
|
|
4413
|
-
* @param name - 字段名,支持点分隔的路径格式,如 'a.b.c'
|
|
4414
|
-
* @param config - 表单配置数组
|
|
4415
|
-
* @returns 找到的 text 值,如果未找到则返回 undefined
|
|
4416
|
-
*/
|
|
4417
|
-
const getTextByName = (name, config = props.config) => {
|
|
4418
|
-
if (!name || !Array.isArray(config)) return void 0;
|
|
4419
|
-
const nameParts = name.split(".");
|
|
4420
|
-
const findInConfig = (configs, parts) => {
|
|
4421
|
-
if (parts.length === 0) return void 0;
|
|
4422
|
-
const [currentPart, ...remainingParts] = parts;
|
|
4423
|
-
for (const item of configs) {
|
|
4424
|
-
if (item.name === currentPart) {
|
|
4425
|
-
if (remainingParts.length === 0) return typeof item.text === "string" ? item.text : void 0;
|
|
4426
|
-
if ("items" in item && Array.isArray(item.items)) {
|
|
4427
|
-
const result = findInConfig(item.items, remainingParts);
|
|
4428
|
-
if (result !== void 0) return result;
|
|
4429
|
-
}
|
|
4430
|
-
}
|
|
4431
|
-
if ("items" in item && Array.isArray(item.items)) {
|
|
4432
|
-
const result = findInConfig(item.items, parts);
|
|
4433
|
-
if (result !== void 0) return result;
|
|
4434
|
-
}
|
|
4435
|
-
}
|
|
4436
|
-
};
|
|
4437
|
-
return findInConfig(config, nameParts);
|
|
4438
|
-
};
|
|
5467
|
+
const getTextByName$1 = (name, config = props.config) => getTextByName(name, config);
|
|
4439
5468
|
/**
|
|
4440
5469
|
* 将校验返回的 invalidFields 汇总为可读的错误文案(多条以 `<br>` 拼接)。
|
|
4441
5470
|
*
|
|
4442
|
-
*
|
|
4443
|
-
*
|
|
5471
|
+
* 实现收口在 `utils/validateError`,供渲染式校验(本组件的 `submitForm` / `validate`)与
|
|
5472
|
+
* 无渲染校验(`validateValues`)共用,保证两条链路产出的错误文案格式完全一致。
|
|
4444
5473
|
*/
|
|
4445
|
-
const formatValidateError = (invalidFields) => {
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
const name = field || prop;
|
|
4450
|
-
const text = (props.useFieldTextInError ? getTextByName(name, props.config) : void 0) || name;
|
|
4451
|
-
error.push(`${text} -> ${message}`);
|
|
4452
|
-
});
|
|
4453
|
-
});
|
|
4454
|
-
return error.join("<br>");
|
|
4455
|
-
};
|
|
5474
|
+
const formatValidateError$1 = (invalidFields) => formatValidateError(invalidFields, {
|
|
5475
|
+
config: props.config,
|
|
5476
|
+
useFieldTextInError: props.useFieldTextInError
|
|
5477
|
+
});
|
|
4456
5478
|
__expose({
|
|
4457
5479
|
values,
|
|
4458
5480
|
lastValuesProcessed,
|
|
@@ -4472,7 +5494,7 @@
|
|
|
4472
5494
|
return native ? values.value : cloneDeep((0, vue.toRaw)(values.value));
|
|
4473
5495
|
} catch (invalidFields) {
|
|
4474
5496
|
emit("error", invalidFields);
|
|
4475
|
-
throw new Error(formatValidateError(invalidFields));
|
|
5497
|
+
throw new Error(formatValidateError$1(invalidFields));
|
|
4476
5498
|
}
|
|
4477
5499
|
},
|
|
4478
5500
|
/**
|
|
@@ -4497,10 +5519,10 @@
|
|
|
4497
5519
|
if (result !== true) throw result;
|
|
4498
5520
|
return "";
|
|
4499
5521
|
} catch (invalidFields) {
|
|
4500
|
-
return formatValidateError(invalidFields);
|
|
5522
|
+
return formatValidateError$1(invalidFields);
|
|
4501
5523
|
}
|
|
4502
5524
|
},
|
|
4503
|
-
getTextByName
|
|
5525
|
+
getTextByName: getTextByName$1
|
|
4504
5526
|
});
|
|
4505
5527
|
return (_ctx, _cache) => {
|
|
4506
5528
|
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicForm), {
|
|
@@ -4526,6 +5548,7 @@
|
|
|
4526
5548
|
"last-values": lastValuesProcessed.value,
|
|
4527
5549
|
"is-compare": __props.isCompare,
|
|
4528
5550
|
"label-width": item.labelWidth || __props.labelWidth,
|
|
5551
|
+
"label-position": item.labelPosition || __props.labelPosition,
|
|
4529
5552
|
"step-active": __props.stepActive,
|
|
4530
5553
|
size: __props.size,
|
|
4531
5554
|
onChange: changeHandler
|
|
@@ -4540,6 +5563,7 @@
|
|
|
4540
5563
|
"last-values",
|
|
4541
5564
|
"is-compare",
|
|
4542
5565
|
"label-width",
|
|
5566
|
+
"label-position",
|
|
4543
5567
|
"step-active",
|
|
4544
5568
|
"size"
|
|
4545
5569
|
]);
|
|
@@ -4558,38 +5582,29 @@
|
|
|
4558
5582
|
});
|
|
4559
5583
|
//#endregion
|
|
4560
5584
|
//#region packages/form/src/submitForm.ts
|
|
4561
|
-
/** 未指定或传入非正数 timeout 时的兜底超时(毫秒),保证非 debug 挂载始终能被清理 */
|
|
4562
|
-
var DEFAULT_MOUNT_TIMEOUT = 1e4;
|
|
4563
5585
|
/**
|
|
4564
|
-
* submitForm / validateForm 的公共脚手架:
|
|
5586
|
+
* `dialog: true` 时 submitForm / validateForm 的公共脚手架:
|
|
4565
5587
|
*
|
|
4566
|
-
* 创建临时容器 → 挂载一个 wrapper 组件(内含 MForm)→ 提供统一的 cleanup /
|
|
5588
|
+
* 创建临时容器 → 挂载一个 wrapper 组件(内含 MForm)→ 提供统一的 cleanup / appContext 继承 →
|
|
4567
5589
|
* 由 `createWrapper` 决定「何时调用 MForm 的哪个方法、如何 resolve/reject」。
|
|
4568
5590
|
*
|
|
4569
|
-
*
|
|
4570
|
-
* 容器创建、卸载、超时、上下文注入等模板代码在此统一收口。
|
|
5591
|
+
* 挂载出来的表单等待人工点击,因此没有超时兜底,靠「确定」/「取消」/`signal` 结束。
|
|
4571
5592
|
*/
|
|
4572
5593
|
var mountFormInstance = (options) => {
|
|
4573
|
-
const { formProps, appContext,
|
|
5594
|
+
const { formProps, appContext, signal, createWrapper } = options;
|
|
4574
5595
|
return new Promise((resolve, reject) => {
|
|
4575
5596
|
if (signal?.aborted) {
|
|
4576
5597
|
reject(signal.reason ?? /* @__PURE__ */ new Error("mountFormInstance aborted"));
|
|
4577
5598
|
return;
|
|
4578
5599
|
}
|
|
4579
5600
|
let cleaned = false;
|
|
4580
|
-
let timer = null;
|
|
4581
5601
|
let onAbort = null;
|
|
4582
5602
|
const instance = { app: null };
|
|
4583
5603
|
const container = document.createElement("div");
|
|
4584
|
-
if (hidden) container.style.display = "none";
|
|
4585
5604
|
document.body.appendChild(container);
|
|
4586
5605
|
const cleanup = () => {
|
|
4587
5606
|
if (cleaned) return;
|
|
4588
5607
|
cleaned = true;
|
|
4589
|
-
if (timer) {
|
|
4590
|
-
clearTimeout(timer);
|
|
4591
|
-
timer = null;
|
|
4592
|
-
}
|
|
4593
5608
|
if (signal && onAbort) {
|
|
4594
5609
|
signal.removeEventListener("abort", onAbort);
|
|
4595
5610
|
onAbort = null;
|
|
@@ -4609,53 +5624,16 @@
|
|
|
4609
5624
|
}
|
|
4610
5625
|
try {
|
|
4611
5626
|
const formRef = (0, vue.ref)(null);
|
|
4612
|
-
const
|
|
4613
|
-
const userWrapper = createWrapper({
|
|
5627
|
+
const wrapperComponent = createWrapper({
|
|
4614
5628
|
formRef,
|
|
4615
|
-
formProps
|
|
5629
|
+
formProps,
|
|
4616
5630
|
cleanup,
|
|
4617
5631
|
resolve,
|
|
4618
5632
|
reject
|
|
4619
5633
|
});
|
|
4620
|
-
const
|
|
4621
|
-
name: "MFormExtendStateInjector",
|
|
4622
|
-
setup() {
|
|
4623
|
-
(0, vue.watch)(() => formRef.value, (form) => {
|
|
4624
|
-
if (!form) return;
|
|
4625
|
-
let result;
|
|
4626
|
-
try {
|
|
4627
|
-
result = extendState(form.formState);
|
|
4628
|
-
} catch (e) {
|
|
4629
|
-
console.error("[MForm] extendState failed:", e);
|
|
4630
|
-
return;
|
|
4631
|
-
}
|
|
4632
|
-
const reservedStateKeys = new Set(Reflect.ownKeys(form.formState));
|
|
4633
|
-
const apply = (state) => applyExtendState(form.formState, state, reservedStateKeys);
|
|
4634
|
-
if (result && typeof result.then === "function") result.then(apply, (e) => console.error("[MForm] extendState failed:", e));
|
|
4635
|
-
else apply(result);
|
|
4636
|
-
}, {
|
|
4637
|
-
flush: "sync",
|
|
4638
|
-
immediate: true
|
|
4639
|
-
});
|
|
4640
|
-
return () => (0, vue.h)(userWrapper);
|
|
4641
|
-
}
|
|
4642
|
-
}) : userWrapper;
|
|
4643
|
-
const rootComponent = hidden ? (0, vue.defineComponent)({
|
|
4644
|
-
name: "MFormSilentProvider",
|
|
4645
|
-
setup() {
|
|
4646
|
-
(0, vue.provide)(FORM_SILENT_MODE_KEY, true);
|
|
4647
|
-
return () => (0, vue.h)(wrapperComponent);
|
|
4648
|
-
}
|
|
4649
|
-
}) : wrapperComponent;
|
|
4650
|
-
const app = (0, vue.createApp)(rootComponent);
|
|
5634
|
+
const app = (0, vue.createApp)(wrapperComponent);
|
|
4651
5635
|
instance.app = app;
|
|
4652
5636
|
if (appContext) Object.assign(app._context, appContext);
|
|
4653
|
-
if (!skipTimeout) timer = setTimeout(() => {
|
|
4654
|
-
if (!cleaned) {
|
|
4655
|
-
reject(new Error(timeoutMessage));
|
|
4656
|
-
cleanup();
|
|
4657
|
-
}
|
|
4658
|
-
}, timeout > 0 ? timeout : DEFAULT_MOUNT_TIMEOUT);
|
|
4659
5637
|
app.mount(container);
|
|
4660
5638
|
} catch (err) {
|
|
4661
5639
|
reject(err);
|
|
@@ -4664,12 +5642,12 @@
|
|
|
4664
5642
|
});
|
|
4665
5643
|
};
|
|
4666
5644
|
/**
|
|
4667
|
-
*
|
|
5645
|
+
* 构造可见弹层 wrapper:以 fixed 遮罩居中渲染 MForm,提供「确定 / 取消」按钮与错误展示区。
|
|
4668
5646
|
*
|
|
4669
|
-
* submitForm 与 validateForm
|
|
5647
|
+
* submitForm 与 validateForm 的弹层 UI 完全一致,仅「确定」时调用的实例方法、错误处理与取消文案不同,
|
|
4670
5648
|
* 这些差异通过 `onConfirm` / `onCancel` 注入,弹层结构在此统一收口。
|
|
4671
5649
|
*/
|
|
4672
|
-
var
|
|
5650
|
+
var createDialogWrapper = (options) => {
|
|
4673
5651
|
const { formRef, formProps, title, name, onConfirm, onCancel } = options;
|
|
4674
5652
|
const btnBase = {
|
|
4675
5653
|
padding: "8px 20px",
|
|
@@ -4752,57 +5730,17 @@
|
|
|
4752
5730
|
});
|
|
4753
5731
|
};
|
|
4754
5732
|
/**
|
|
4755
|
-
*
|
|
5733
|
+
* 可见弹层提交:把表单渲染在弹层里,点击「确定」才调用挂载实例的 `submitForm`。
|
|
4756
5734
|
*
|
|
4757
|
-
*
|
|
4758
|
-
* 一个不可见的 Form 组件实例,等待初始化完成后调用其 `submitForm` 方法,
|
|
4759
|
-
* 校验通过则 resolve 表单值,校验失败则 reject 错误信息,最后自动卸载实例。
|
|
4760
|
-
*
|
|
4761
|
-
* @example
|
|
4762
|
-
* ```ts
|
|
4763
|
-
* import { submitForm } from '@tmagic/form';
|
|
4764
|
-
*
|
|
4765
|
-
* try {
|
|
4766
|
-
* const values = await submitForm({
|
|
4767
|
-
* config: [...],
|
|
4768
|
-
* initValues: { name: 'foo' },
|
|
4769
|
-
* });
|
|
4770
|
-
* console.log(values);
|
|
4771
|
-
* } catch (e) {
|
|
4772
|
-
* console.error(e);
|
|
4773
|
-
* }
|
|
4774
|
-
*
|
|
4775
|
-
* // 需要同时获取变更记录时:
|
|
4776
|
-
* const { values, changeRecords } = await submitForm({
|
|
4777
|
-
* config: [...],
|
|
4778
|
-
* initValues: { name: 'foo' },
|
|
4779
|
-
* returnChangeRecords: true,
|
|
4780
|
-
* });
|
|
4781
|
-
*
|
|
4782
|
-
* // 调试模式:可见地渲染表单,点击「确定」才提交:
|
|
4783
|
-
* const values = await submitForm({
|
|
4784
|
-
* config: [...],
|
|
4785
|
-
* initValues: { name: 'foo' },
|
|
4786
|
-
* debug: true,
|
|
4787
|
-
* });
|
|
4788
|
-
* ```
|
|
5735
|
+
* 用于需要用户填写/确认的场景;默认路径仍是无渲染校验(见 `submitForm` 的说明)。
|
|
4789
5736
|
*/
|
|
4790
|
-
var
|
|
4791
|
-
const { native, appContext,
|
|
5737
|
+
var submitFormByDialogRender = (options) => {
|
|
5738
|
+
const { native, appContext, returnChangeRecords, signal, dialog, title, ...formProps } = options;
|
|
4792
5739
|
return mountFormInstance({
|
|
4793
5740
|
formProps,
|
|
4794
5741
|
appContext,
|
|
4795
|
-
timeout,
|
|
4796
5742
|
signal,
|
|
4797
|
-
hidden: !debug,
|
|
4798
|
-
skipTimeout: debug,
|
|
4799
|
-
timeoutMessage: `submitForm timeout after ${timeout}ms: form is not initialized.`,
|
|
4800
5743
|
createWrapper: ({ formRef, formProps, cleanup, resolve, reject }) => {
|
|
4801
|
-
/**
|
|
4802
|
-
* 执行一次提交:nextTick 等待子组件渲染 → 快照 changeRecords → 调用实例 submitForm → resolve。
|
|
4803
|
-
* 校验失败时交给 `onValidateError` 决定「保留弹层展示错误(debug)」还是「reject 并清理(普通)」,
|
|
4804
|
-
* 从而让 debug 与普通模式共享同一份提交逻辑。
|
|
4805
|
-
*/
|
|
4806
5744
|
const doSubmit = async (onValidateError) => {
|
|
4807
5745
|
try {
|
|
4808
5746
|
await (0, vue.nextTick)();
|
|
@@ -4817,39 +5755,19 @@
|
|
|
4817
5755
|
onValidateError(err);
|
|
4818
5756
|
}
|
|
4819
5757
|
};
|
|
4820
|
-
|
|
5758
|
+
return createDialogWrapper({
|
|
4821
5759
|
formRef,
|
|
4822
5760
|
formProps,
|
|
4823
5761
|
name: "MFormSubmitWrapper",
|
|
4824
|
-
title: "submitForm
|
|
5762
|
+
title: title ?? "submitForm",
|
|
4825
5763
|
onConfirm: (setError) => doSubmit((err) => {
|
|
4826
5764
|
setError(err instanceof Error ? err.message : String(err));
|
|
4827
5765
|
}),
|
|
4828
5766
|
onCancel: () => {
|
|
4829
|
-
reject(/* @__PURE__ */ new Error("submitForm canceled
|
|
5767
|
+
reject(/* @__PURE__ */ new Error("submitForm canceled."));
|
|
4830
5768
|
cleanup();
|
|
4831
5769
|
}
|
|
4832
5770
|
});
|
|
4833
|
-
return (0, vue.defineComponent)({
|
|
4834
|
-
name: "MFormSubmitWrapper",
|
|
4835
|
-
setup() {
|
|
4836
|
-
const stop = (0, vue.watch)(() => formRef.value?.initialized, (initialized) => {
|
|
4837
|
-
if (!initialized) return;
|
|
4838
|
-
stop();
|
|
4839
|
-
doSubmit((err) => {
|
|
4840
|
-
reject(err);
|
|
4841
|
-
cleanup();
|
|
4842
|
-
});
|
|
4843
|
-
}, {
|
|
4844
|
-
flush: "post",
|
|
4845
|
-
immediate: true
|
|
4846
|
-
});
|
|
4847
|
-
return () => (0, vue.h)(Form_default, {
|
|
4848
|
-
...formProps,
|
|
4849
|
-
ref: formRef
|
|
4850
|
-
});
|
|
4851
|
-
}
|
|
4852
|
-
});
|
|
4853
5771
|
}
|
|
4854
5772
|
});
|
|
4855
5773
|
};
|
|
@@ -4893,61 +5811,20 @@
|
|
|
4893
5811
|
return cloned;
|
|
4894
5812
|
};
|
|
4895
5813
|
/**
|
|
4896
|
-
*
|
|
4897
|
-
*
|
|
4898
|
-
*
|
|
4899
|
-
* 实例的 `validate` 方法,返回汇总后的错误文案,随后自动卸载实例。
|
|
4900
|
-
*
|
|
4901
|
-
* 与 `submitForm` 的区别:
|
|
4902
|
-
* - 「静默」:校验失败不抛异常、不触发 `error` 事件、不返回表单值;
|
|
4903
|
-
* - 仅用于「探测」配置是否合法,适合源码保存后校验、批量校验组件配置等场景。
|
|
4904
|
-
*
|
|
4905
|
-
* 由于每次都新建一个独立的 MForm 实例,调用方无需持有任何表单 ref,也不会污染
|
|
4906
|
-
* 页面上正在展示的表单状态。
|
|
4907
|
-
*
|
|
4908
|
-
* @returns 校验通过返回空字符串 `''`,否则返回以 `<br>` 拼接的错误文案。
|
|
4909
|
-
* 仅在初始化超时或挂载失败等异常情况下才会 reject。
|
|
4910
|
-
*
|
|
4911
|
-
* @example
|
|
4912
|
-
* ```ts
|
|
4913
|
-
* import { validateForm } from '@tmagic/form';
|
|
4914
|
-
*
|
|
4915
|
-
* const error = await validateForm({
|
|
4916
|
-
* config: [...],
|
|
4917
|
-
* initValues: { name: 'foo' },
|
|
4918
|
-
* appContext: getCurrentInstance()?.appContext,
|
|
4919
|
-
* });
|
|
4920
|
-
* if (error) {
|
|
4921
|
-
* // 配置不合法,error 为错误文案
|
|
4922
|
-
* }
|
|
4923
|
-
*
|
|
4924
|
-
* // 调试模式:可见地渲染表单,点击「确定」才校验,校验失败保留弹层可修正重试:
|
|
4925
|
-
* const error = await validateForm({
|
|
4926
|
-
* config: [...],
|
|
4927
|
-
* initValues: { name: 'foo' },
|
|
4928
|
-
* debug: true,
|
|
4929
|
-
* });
|
|
4930
|
-
* ```
|
|
5814
|
+
* 可见弹层校验:把表单渲染在弹层里,点击「确定」才调用挂载实例的 `validate`。
|
|
5815
|
+
*
|
|
5816
|
+
* 用于需要用户填写/确认的场景;默认路径仍是无渲染校验(见 `validateForm` 的说明)。
|
|
4931
5817
|
*/
|
|
4932
|
-
var
|
|
4933
|
-
const { appContext,
|
|
5818
|
+
var validateFormByDialogRender = (options) => {
|
|
5819
|
+
const { appContext, config, signal, dialog, title, ...rest } = options;
|
|
4934
5820
|
return mountFormInstance({
|
|
4935
5821
|
formProps: {
|
|
4936
5822
|
...rest,
|
|
4937
5823
|
config: stripTabItemsLazy(config)
|
|
4938
5824
|
},
|
|
4939
5825
|
appContext,
|
|
4940
|
-
timeout,
|
|
4941
5826
|
signal,
|
|
4942
|
-
hidden: !debug,
|
|
4943
|
-
skipTimeout: debug,
|
|
4944
|
-
timeoutMessage: `validateForm timeout after ${timeout}ms: form is not initialized.`,
|
|
4945
5827
|
createWrapper: ({ formRef, formProps, cleanup, resolve, reject }) => {
|
|
4946
|
-
/**
|
|
4947
|
-
* 执行一次校验:nextTick 等待子组件渲染 → 调用实例 validate → 通过则 resolve ''。
|
|
4948
|
-
* 校验失败(返回非空错误文案)时交给 `onInvalid` 决定「静默 resolve 错误文案(普通)」
|
|
4949
|
-
* 还是「在弹层展示错误并保留供重试(debug)」,从而让两种模式共享同一份校验逻辑。
|
|
4950
|
-
*/
|
|
4951
5828
|
const doValidate = async (onInvalid) => {
|
|
4952
5829
|
try {
|
|
4953
5830
|
await (0, vue.nextTick)();
|
|
@@ -4962,42 +5839,40 @@
|
|
|
4962
5839
|
cleanup();
|
|
4963
5840
|
}
|
|
4964
5841
|
};
|
|
4965
|
-
|
|
5842
|
+
return createDialogWrapper({
|
|
4966
5843
|
formRef,
|
|
4967
5844
|
formProps,
|
|
4968
5845
|
name: "MFormValidateWrapper",
|
|
4969
|
-
title: "validateForm
|
|
5846
|
+
title: title ?? "validateForm",
|
|
4970
5847
|
onConfirm: (setError) => doValidate((error) => {
|
|
4971
5848
|
setError(error);
|
|
4972
5849
|
}),
|
|
4973
5850
|
onCancel: () => {
|
|
4974
|
-
reject(/* @__PURE__ */ new Error("validateForm canceled
|
|
5851
|
+
reject(/* @__PURE__ */ new Error("validateForm canceled."));
|
|
4975
5852
|
cleanup();
|
|
4976
5853
|
}
|
|
4977
5854
|
});
|
|
4978
|
-
return (0, vue.defineComponent)({
|
|
4979
|
-
name: "MFormValidateWrapper",
|
|
4980
|
-
setup() {
|
|
4981
|
-
const stop = (0, vue.watch)(() => formRef.value?.initialized, (initialized) => {
|
|
4982
|
-
if (!initialized) return;
|
|
4983
|
-
stop();
|
|
4984
|
-
doValidate((error) => {
|
|
4985
|
-
resolve(error);
|
|
4986
|
-
cleanup();
|
|
4987
|
-
});
|
|
4988
|
-
}, {
|
|
4989
|
-
flush: "post",
|
|
4990
|
-
immediate: true
|
|
4991
|
-
});
|
|
4992
|
-
return () => (0, vue.h)(Form_default, {
|
|
4993
|
-
...formProps,
|
|
4994
|
-
ref: formRef
|
|
4995
|
-
});
|
|
4996
|
-
}
|
|
4997
|
-
});
|
|
4998
5855
|
}
|
|
4999
5856
|
});
|
|
5000
5857
|
};
|
|
5858
|
+
/**
|
|
5859
|
+
* 以命令式方式对一份「表单配置 + 值」做一次校验并取回表单值。
|
|
5860
|
+
*
|
|
5861
|
+
* 默认走无渲染实现(见 `@tmagic/form/headless`)。`dialog: true` 会把表单以弹层渲染出来。
|
|
5862
|
+
*/
|
|
5863
|
+
var submitForm = async (options) => {
|
|
5864
|
+
if (options.dialog) return submitFormByDialogRender(options);
|
|
5865
|
+
return submitForm$1(options);
|
|
5866
|
+
};
|
|
5867
|
+
/**
|
|
5868
|
+
* 以命令式方式对一份「表单配置 + 值」做一次静默校验。
|
|
5869
|
+
*
|
|
5870
|
+
* 默认走无渲染实现。`dialog: true` 的处理详见 `submitForm`。
|
|
5871
|
+
*/
|
|
5872
|
+
var validateForm = async (options) => {
|
|
5873
|
+
if (options.dialog) return validateFormByDialogRender(options);
|
|
5874
|
+
return validateForm$1(options);
|
|
5875
|
+
};
|
|
5001
5876
|
//#endregion
|
|
5002
5877
|
//#region packages/form/src/FormDialog.vue?vue&type=script&setup=true&lang.ts
|
|
5003
5878
|
var _hoisted_1$13 = { style: { "min-height": "1px" } };
|
|
@@ -5050,7 +5925,7 @@
|
|
|
5050
5925
|
type: Boolean,
|
|
5051
5926
|
default: true
|
|
5052
5927
|
},
|
|
5053
|
-
|
|
5928
|
+
context: {},
|
|
5054
5929
|
theme: {}
|
|
5055
5930
|
},
|
|
5056
5931
|
emits: [
|
|
@@ -5208,7 +6083,7 @@
|
|
|
5208
6083
|
"use-field-text-in-error": __props.useFieldTextInError,
|
|
5209
6084
|
"type-match-valid": __props.typeMatchValid,
|
|
5210
6085
|
"validate-on-init": __props.validateOnInit,
|
|
5211
|
-
|
|
6086
|
+
context: __props.context,
|
|
5212
6087
|
theme: effectiveTheme.value,
|
|
5213
6088
|
onChange: changeHandler
|
|
5214
6089
|
}, null, 8, [
|
|
@@ -5225,7 +6100,7 @@
|
|
|
5225
6100
|
"use-field-text-in-error",
|
|
5226
6101
|
"type-match-valid",
|
|
5227
6102
|
"validate-on-init",
|
|
5228
|
-
"
|
|
6103
|
+
"context",
|
|
5229
6104
|
"theme"
|
|
5230
6105
|
]), (0, vue.renderSlot)(_ctx.$slots, "default")], 4)) : (0, vue.createCommentVNode)("v-if", true)]),
|
|
5231
6106
|
_: 3
|
|
@@ -5280,7 +6155,7 @@
|
|
|
5280
6155
|
default: true
|
|
5281
6156
|
},
|
|
5282
6157
|
beforeClose: {},
|
|
5283
|
-
|
|
6158
|
+
context: {},
|
|
5284
6159
|
theme: {}
|
|
5285
6160
|
},
|
|
5286
6161
|
emits: [
|
|
@@ -5431,7 +6306,7 @@
|
|
|
5431
6306
|
"use-field-text-in-error": __props.useFieldTextInError,
|
|
5432
6307
|
"type-match-valid": __props.typeMatchValid,
|
|
5433
6308
|
"validate-on-init": __props.validateOnInit,
|
|
5434
|
-
|
|
6309
|
+
context: __props.context,
|
|
5435
6310
|
theme: effectiveTheme.value,
|
|
5436
6311
|
onChange: changeHandler
|
|
5437
6312
|
}, null, 8, [
|
|
@@ -5447,7 +6322,7 @@
|
|
|
5447
6322
|
"use-field-text-in-error",
|
|
5448
6323
|
"type-match-valid",
|
|
5449
6324
|
"validate-on-init",
|
|
5450
|
-
"
|
|
6325
|
+
"context",
|
|
5451
6326
|
"theme"
|
|
5452
6327
|
]), (0, vue.renderSlot)(_ctx.$slots, "default")], 512)) : (0, vue.createCommentVNode)("v-if", true)]),
|
|
5453
6328
|
_: 3
|
|
@@ -5493,7 +6368,7 @@
|
|
|
5493
6368
|
type: Boolean,
|
|
5494
6369
|
default: true
|
|
5495
6370
|
},
|
|
5496
|
-
|
|
6371
|
+
context: {}
|
|
5497
6372
|
},
|
|
5498
6373
|
emits: [
|
|
5499
6374
|
"change",
|
|
@@ -5557,7 +6432,7 @@
|
|
|
5557
6432
|
inline: __props.inline,
|
|
5558
6433
|
"prevent-submit-default": __props.preventSubmitDefault,
|
|
5559
6434
|
"use-field-text-in-error": __props.useFieldTextInError,
|
|
5560
|
-
|
|
6435
|
+
context: __props.context,
|
|
5561
6436
|
"type-match-valid": __props.typeMatchValid,
|
|
5562
6437
|
"validate-on-init": __props.validateOnInit,
|
|
5563
6438
|
onChange: changeHandler
|
|
@@ -5572,7 +6447,7 @@
|
|
|
5572
6447
|
"inline",
|
|
5573
6448
|
"prevent-submit-default",
|
|
5574
6449
|
"use-field-text-in-error",
|
|
5575
|
-
"
|
|
6450
|
+
"context",
|
|
5576
6451
|
"type-match-valid",
|
|
5577
6452
|
"validate-on-init"
|
|
5578
6453
|
]), (0, vue.renderSlot)(_ctx.$slots, "default")]),
|
|
@@ -5603,7 +6478,7 @@
|
|
|
5603
6478
|
var _hoisted_2$7 = ["innerHTML"];
|
|
5604
6479
|
var _hoisted_3$6 = { key: 1 };
|
|
5605
6480
|
var _hoisted_4$5 = ["innerHTML"];
|
|
5606
|
-
var _hoisted_5$
|
|
6481
|
+
var _hoisted_5$4 = ["innerHTML"];
|
|
5607
6482
|
var _hoisted_6$2 = {
|
|
5608
6483
|
key: 2,
|
|
5609
6484
|
style: { "display": "flex" }
|
|
@@ -5617,6 +6492,7 @@
|
|
|
5617
6492
|
__name: "Fieldset",
|
|
5618
6493
|
props: {
|
|
5619
6494
|
labelWidth: {},
|
|
6495
|
+
labelPosition: {},
|
|
5620
6496
|
prop: { default: "" },
|
|
5621
6497
|
size: {},
|
|
5622
6498
|
model: {},
|
|
@@ -5656,6 +6532,7 @@
|
|
|
5656
6532
|
if (props.config.items) return props.config.labelWidth || props.labelWidth;
|
|
5657
6533
|
return props.config.labelWidth || props.labelWidth || (props.config.text ? void 0 : "0");
|
|
5658
6534
|
});
|
|
6535
|
+
const lPosition = (0, vue.computed)(() => props.config.labelPosition || props.labelPosition);
|
|
5659
6536
|
const valueChangeHandler = (value) => {
|
|
5660
6537
|
emit("change", value, { modifyKey: checkboxName.value });
|
|
5661
6538
|
};
|
|
@@ -5692,7 +6569,7 @@
|
|
|
5692
6569
|
key: 0,
|
|
5693
6570
|
innerHTML: __props.config.extra,
|
|
5694
6571
|
class: "m-form-tip"
|
|
5695
|
-
}, null, 8, _hoisted_5$
|
|
6572
|
+
}, null, 8, _hoisted_5$4)) : (0, vue.createCommentVNode)("v-if", true)])), __props.config.schematic && show.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_6$2, [(0, vue.createElementVNode)("div", _hoisted_7$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (item, index) => {
|
|
5696
6573
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
5697
6574
|
key: key(item, index),
|
|
5698
6575
|
model: name.value ? __props.model[name.value] : __props.model,
|
|
@@ -5703,6 +6580,7 @@
|
|
|
5703
6580
|
prop: __props.prop,
|
|
5704
6581
|
disabled: __props.disabled,
|
|
5705
6582
|
labelWidth: lWidth.value,
|
|
6583
|
+
labelPosition: lPosition.value,
|
|
5706
6584
|
size: __props.size,
|
|
5707
6585
|
onChange: changeHandler,
|
|
5708
6586
|
onAddDiffCount: _cache[0] || (_cache[0] = ($event) => onAddDiffCount())
|
|
@@ -5715,6 +6593,7 @@
|
|
|
5715
6593
|
"prop",
|
|
5716
6594
|
"disabled",
|
|
5717
6595
|
"labelWidth",
|
|
6596
|
+
"labelPosition",
|
|
5718
6597
|
"size"
|
|
5719
6598
|
]);
|
|
5720
6599
|
}), 128))]), (0, vue.createElementVNode)("img", {
|
|
@@ -5730,6 +6609,7 @@
|
|
|
5730
6609
|
config: item,
|
|
5731
6610
|
prop: __props.prop,
|
|
5732
6611
|
labelWidth: lWidth.value,
|
|
6612
|
+
labelPosition: lPosition.value,
|
|
5733
6613
|
size: __props.size,
|
|
5734
6614
|
disabled: __props.disabled,
|
|
5735
6615
|
onChange: changeHandler,
|
|
@@ -5742,6 +6622,7 @@
|
|
|
5742
6622
|
"config",
|
|
5743
6623
|
"prop",
|
|
5744
6624
|
"labelWidth",
|
|
6625
|
+
"labelPosition",
|
|
5745
6626
|
"size",
|
|
5746
6627
|
"disabled"
|
|
5747
6628
|
]);
|
|
@@ -5761,6 +6642,7 @@
|
|
|
5761
6642
|
config: {},
|
|
5762
6643
|
name: {},
|
|
5763
6644
|
labelWidth: {},
|
|
6645
|
+
labelPosition: {},
|
|
5764
6646
|
prop: {},
|
|
5765
6647
|
size: {},
|
|
5766
6648
|
disabled: { type: Boolean }
|
|
@@ -5794,6 +6676,7 @@
|
|
|
5794
6676
|
size: __props.size,
|
|
5795
6677
|
disabled: __props.disabled,
|
|
5796
6678
|
"label-width": __props.config.labelWidth || __props.labelWidth,
|
|
6679
|
+
"label-position": __props.config.labelPosition || __props.labelPosition,
|
|
5797
6680
|
onChange: changeHandler,
|
|
5798
6681
|
onAddDiffCount: _cache[0] || (_cache[0] = ($event) => onAddDiffCount())
|
|
5799
6682
|
}, null, 8, [
|
|
@@ -5804,7 +6687,8 @@
|
|
|
5804
6687
|
"prop",
|
|
5805
6688
|
"size",
|
|
5806
6689
|
"disabled",
|
|
5807
|
-
"label-width"
|
|
6690
|
+
"label-width",
|
|
6691
|
+
"label-position"
|
|
5808
6692
|
]);
|
|
5809
6693
|
}), 128))], 4);
|
|
5810
6694
|
};
|
|
@@ -5823,7 +6707,7 @@
|
|
|
5823
6707
|
style: { "display": "flex" }
|
|
5824
6708
|
};
|
|
5825
6709
|
var _hoisted_4$4 = { style: { "flex": "1" } };
|
|
5826
|
-
var _hoisted_5$
|
|
6710
|
+
var _hoisted_5$3 = ["src"];
|
|
5827
6711
|
//#endregion
|
|
5828
6712
|
//#region packages/form/src/containers/Panel.vue
|
|
5829
6713
|
var Panel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
@@ -5836,6 +6720,7 @@
|
|
|
5836
6720
|
config: {},
|
|
5837
6721
|
name: {},
|
|
5838
6722
|
labelWidth: {},
|
|
6723
|
+
labelPosition: {},
|
|
5839
6724
|
prop: {},
|
|
5840
6725
|
size: {},
|
|
5841
6726
|
disabled: { type: Boolean },
|
|
@@ -5898,6 +6783,7 @@
|
|
|
5898
6783
|
size: __props.size,
|
|
5899
6784
|
disabled: __props.disabled,
|
|
5900
6785
|
"label-width": __props.config.labelWidth || __props.labelWidth,
|
|
6786
|
+
"label-position": __props.config.labelPosition || __props.labelPosition,
|
|
5901
6787
|
onChange: changeHandler,
|
|
5902
6788
|
onAddDiffCount: _cache[2] || (_cache[2] = ($event) => onAddDiffCount())
|
|
5903
6789
|
}, null, 8, [
|
|
@@ -5908,12 +6794,13 @@
|
|
|
5908
6794
|
"prop",
|
|
5909
6795
|
"size",
|
|
5910
6796
|
"disabled",
|
|
5911
|
-
"label-width"
|
|
6797
|
+
"label-width",
|
|
6798
|
+
"label-position"
|
|
5912
6799
|
]);
|
|
5913
6800
|
}), 128))]), (0, vue.createElementVNode)("img", {
|
|
5914
6801
|
class: "m-form-schematic",
|
|
5915
6802
|
src: __props.config.schematic
|
|
5916
|
-
}, null, 8, _hoisted_5$
|
|
6803
|
+
}, null, 8, _hoisted_5$3)])) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, (0, vue.renderList)(items.value, (item, index) => {
|
|
5917
6804
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
5918
6805
|
key: item[(0, vue.unref)(mForm)?.keyProp || "__key"] ?? index,
|
|
5919
6806
|
config: item,
|
|
@@ -5924,6 +6811,7 @@
|
|
|
5924
6811
|
size: __props.size,
|
|
5925
6812
|
disabled: __props.disabled,
|
|
5926
6813
|
"label-width": __props.config.labelWidth || __props.labelWidth,
|
|
6814
|
+
"label-position": __props.config.labelPosition || __props.labelPosition,
|
|
5927
6815
|
onChange: changeHandler,
|
|
5928
6816
|
onAddDiffCount: _cache[3] || (_cache[3] = ($event) => onAddDiffCount())
|
|
5929
6817
|
}, null, 8, [
|
|
@@ -5934,7 +6822,8 @@
|
|
|
5934
6822
|
"prop",
|
|
5935
6823
|
"size",
|
|
5936
6824
|
"disabled",
|
|
5937
|
-
"label-width"
|
|
6825
|
+
"label-width",
|
|
6826
|
+
"label-position"
|
|
5938
6827
|
]);
|
|
5939
6828
|
}), 128))])]),
|
|
5940
6829
|
_: 3
|
|
@@ -5953,6 +6842,7 @@
|
|
|
5953
6842
|
isCompare: { type: Boolean },
|
|
5954
6843
|
config: {},
|
|
5955
6844
|
labelWidth: {},
|
|
6845
|
+
labelPosition: {},
|
|
5956
6846
|
expandMore: { type: Boolean },
|
|
5957
6847
|
span: {},
|
|
5958
6848
|
size: {},
|
|
@@ -5977,6 +6867,7 @@
|
|
|
5977
6867
|
config: __props.config,
|
|
5978
6868
|
prop: __props.prop,
|
|
5979
6869
|
"label-width": __props.config.labelWidth || __props.labelWidth,
|
|
6870
|
+
"label-position": __props.config.labelPosition || __props.labelPosition,
|
|
5980
6871
|
"expand-more": __props.expandMore,
|
|
5981
6872
|
size: __props.size,
|
|
5982
6873
|
disabled: __props.disabled,
|
|
@@ -5990,6 +6881,7 @@
|
|
|
5990
6881
|
"config",
|
|
5991
6882
|
"prop",
|
|
5992
6883
|
"label-width",
|
|
6884
|
+
"label-position",
|
|
5993
6885
|
"expand-more",
|
|
5994
6886
|
"size",
|
|
5995
6887
|
"disabled"
|
|
@@ -6011,6 +6903,7 @@
|
|
|
6011
6903
|
config: {},
|
|
6012
6904
|
name: {},
|
|
6013
6905
|
labelWidth: {},
|
|
6906
|
+
labelPosition: {},
|
|
6014
6907
|
prop: {},
|
|
6015
6908
|
size: {},
|
|
6016
6909
|
expandMore: { type: Boolean },
|
|
@@ -6033,6 +6926,7 @@
|
|
|
6033
6926
|
span: col.span || __props.config.span || 24 / __props.config.items.length,
|
|
6034
6927
|
config: col,
|
|
6035
6928
|
labelWidth: __props.config.labelWidth || __props.labelWidth,
|
|
6929
|
+
labelPosition: __props.config.labelPosition || __props.labelPosition,
|
|
6036
6930
|
expandMore: __props.expandMore,
|
|
6037
6931
|
model: __props.name ? __props.model[__props.name] : __props.model,
|
|
6038
6932
|
lastValues: __props.name ? __props.lastValues[__props.name] : __props.lastValues,
|
|
@@ -6046,6 +6940,7 @@
|
|
|
6046
6940
|
"span",
|
|
6047
6941
|
"config",
|
|
6048
6942
|
"labelWidth",
|
|
6943
|
+
"labelPosition",
|
|
6049
6944
|
"expandMore",
|
|
6050
6945
|
"model",
|
|
6051
6946
|
"lastValues",
|
|
@@ -6076,6 +6971,7 @@
|
|
|
6076
6971
|
name: {},
|
|
6077
6972
|
size: {},
|
|
6078
6973
|
labelWidth: {},
|
|
6974
|
+
labelPosition: {},
|
|
6079
6975
|
prop: { default: "" },
|
|
6080
6976
|
expandMore: { type: Boolean },
|
|
6081
6977
|
disabled: { type: Boolean }
|
|
@@ -6152,12 +7048,15 @@
|
|
|
6152
7048
|
prop: props.prop,
|
|
6153
7049
|
config: props.config
|
|
6154
7050
|
});
|
|
7051
|
+
const tabsModel = props.model[props.name];
|
|
7052
|
+
if (Array.isArray(tabsModel) && Array.isArray(props.config.items)) for (const tab of tabsModel) applyMountValueEffects(mForm, props.config.items, tab);
|
|
6155
7053
|
emit("change", props.model[props.name]);
|
|
6156
7054
|
} else {
|
|
6157
7055
|
const newObj = await initValue(mForm, {
|
|
6158
7056
|
config: props.config.items,
|
|
6159
7057
|
initValues: {}
|
|
6160
7058
|
});
|
|
7059
|
+
applyMountValueEffects(mForm, props.config.items, newObj);
|
|
6161
7060
|
newObj.title = `标签${tabs.value.length + 1}`;
|
|
6162
7061
|
props.model[props.name].push(newObj);
|
|
6163
7062
|
emit("change", props.model[props.name], { changeRecords: [{
|
|
@@ -6227,6 +7126,7 @@
|
|
|
6227
7126
|
prop: __props.config.dynamic ? `${__props.prop}${__props.prop ? "." : ""}${String(tabIndex)}` : tab.name ? `${__props.prop}${__props.prop ? "." : ""}${tab.name}` : __props.prop,
|
|
6228
7127
|
size: __props.size,
|
|
6229
7128
|
"label-width": tab.labelWidth || __props.labelWidth,
|
|
7129
|
+
"label-position": tab.labelPosition || __props.labelPosition,
|
|
6230
7130
|
"expand-more": __props.expandMore,
|
|
6231
7131
|
onChange: changeHandler,
|
|
6232
7132
|
onAddDiffCount: ($event) => onAddDiffCount(Number(tabIndex))
|
|
@@ -6239,6 +7139,7 @@
|
|
|
6239
7139
|
"prop",
|
|
6240
7140
|
"size",
|
|
6241
7141
|
"label-width",
|
|
7142
|
+
"label-position",
|
|
6242
7143
|
"expand-more",
|
|
6243
7144
|
"onAddDiffCount"
|
|
6244
7145
|
]);
|
|
@@ -6254,12 +7155,14 @@
|
|
|
6254
7155
|
//#endregion
|
|
6255
7156
|
//#region packages/form/src/containers/GroupListItem.vue?vue&type=script&setup=true&lang.ts
|
|
6256
7157
|
var _hoisted_1$9 = { class: "m-fields-group-list-item-header" };
|
|
6257
|
-
var _hoisted_2$5 =
|
|
6258
|
-
var _hoisted_3$4 =
|
|
7158
|
+
var _hoisted_2$5 = { class: "m-fields-group-list-item-title" };
|
|
7159
|
+
var _hoisted_3$4 = ["innerHTML"];
|
|
7160
|
+
var _hoisted_4$3 = { class: "m-fields-group-list-item-actions" };
|
|
7161
|
+
var _hoisted_5$2 = { style: {
|
|
6259
7162
|
"text-align": "right",
|
|
6260
7163
|
"margin-top": "20px"
|
|
6261
7164
|
} };
|
|
6262
|
-
var
|
|
7165
|
+
var _hoisted_6$1 = ["innerHTML"];
|
|
6263
7166
|
//#endregion
|
|
6264
7167
|
//#region packages/form/src/containers/GroupListItem.vue
|
|
6265
7168
|
var GroupListItem_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
@@ -6272,6 +7175,7 @@
|
|
|
6272
7175
|
groupModel: {},
|
|
6273
7176
|
config: {},
|
|
6274
7177
|
labelWidth: {},
|
|
7178
|
+
labelPosition: {},
|
|
6275
7179
|
prop: {},
|
|
6276
7180
|
size: {},
|
|
6277
7181
|
index: {},
|
|
@@ -6290,13 +7194,8 @@
|
|
|
6290
7194
|
const mForm = (0, vue.inject)("mForm");
|
|
6291
7195
|
const defaultExpandQuantity = props.config.defaultExpandQuantity ?? 7;
|
|
6292
7196
|
const expand = (0, vue.ref)(props.config.expandAll || defaultExpandQuantity > props.index);
|
|
6293
|
-
const rowConfig = (0, vue.computed)(() => (
|
|
6294
|
-
|
|
6295
|
-
span: props.config.span || 24,
|
|
6296
|
-
items: props.config.items,
|
|
6297
|
-
labelWidth: props.config.labelWidth,
|
|
6298
|
-
[mForm?.keyProp || "__key"]: `${props.config[mForm?.keyProp || "__key"]}${String(props.index)}`
|
|
6299
|
-
}));
|
|
7197
|
+
const rowConfig = (0, vue.computed)(() => getGroupListRowConfig(props.config, props.index, mForm?.keyProp));
|
|
7198
|
+
const rowProp = (0, vue.computed)(() => appendProp(props.prop, props.index));
|
|
6300
7199
|
const title = (0, vue.computed)(() => {
|
|
6301
7200
|
if (props.config.titleKey && props.model[props.config.titleKey]) {
|
|
6302
7201
|
const { titlePrefix } = props.config;
|
|
@@ -6356,101 +7255,112 @@
|
|
|
6356
7255
|
})]),
|
|
6357
7256
|
_: 1
|
|
6358
7257
|
}, 8, ["disabled"]),
|
|
6359
|
-
(0, vue.createElementVNode)("
|
|
6360
|
-
|
|
6361
|
-
|
|
7258
|
+
(0, vue.createElementVNode)("div", _hoisted_2$5, [(0, vue.renderSlot)(_ctx.$slots, "title", {
|
|
7259
|
+
model: __props.model,
|
|
7260
|
+
index: __props.index,
|
|
7261
|
+
lastValues: __props.lastValues,
|
|
7262
|
+
prop: rowProp.value,
|
|
7263
|
+
title: title.value
|
|
7264
|
+
}, () => [(0, vue.createElementVNode)("span", { innerHTML: title.value }, null, 8, _hoisted_3$4)])]),
|
|
7265
|
+
(0, vue.createElementVNode)("div", _hoisted_4$3, [
|
|
7266
|
+
copyable.value && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
6362
7267
|
key: 0,
|
|
7268
|
+
link: "",
|
|
6363
7269
|
size: "default",
|
|
7270
|
+
type: "primary",
|
|
7271
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.DocumentCopy),
|
|
7272
|
+
disabled: __props.disabled,
|
|
7273
|
+
onClick: copyHandler
|
|
7274
|
+
}, {
|
|
7275
|
+
default: (0, vue.withCtx)(() => [..._cache[6] || (_cache[6] = [(0, vue.createTextVNode)("复制", -1)])]),
|
|
7276
|
+
_: 1
|
|
7277
|
+
}, 8, ["icon", "disabled"])) : (0, vue.createCommentVNode)("v-if", true),
|
|
7278
|
+
movable.value && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
6364
7279
|
link: "",
|
|
6365
|
-
|
|
6366
|
-
icon: (0, vue.unref)(_element_plus_icons_vue.Delete),
|
|
7280
|
+
size: "default",
|
|
6367
7281
|
disabled: __props.disabled,
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
link: "",
|
|
6375
|
-
size: "default",
|
|
6376
|
-
type: "primary",
|
|
6377
|
-
icon: (0, vue.unref)(_element_plus_icons_vue.DocumentCopy),
|
|
6378
|
-
disabled: __props.disabled,
|
|
6379
|
-
onClick: copyHandler
|
|
6380
|
-
}, {
|
|
6381
|
-
default: (0, vue.withCtx)(() => [..._cache[6] || (_cache[6] = [(0, vue.createTextVNode)("复制", -1)])]),
|
|
6382
|
-
_: 1
|
|
6383
|
-
}, 8, ["icon", "disabled"])) : (0, vue.createCommentVNode)("v-if", true),
|
|
6384
|
-
movable.value && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
6385
|
-
link: "",
|
|
6386
|
-
size: "default",
|
|
6387
|
-
disabled: __props.disabled,
|
|
6388
|
-
icon: (0, vue.unref)(_element_plus_icons_vue.Top),
|
|
6389
|
-
onClick: _cache[0] || (_cache[0] = ($event) => changeOrder(-1))
|
|
6390
|
-
}, {
|
|
6391
|
-
default: (0, vue.withCtx)(() => [..._cache[7] || (_cache[7] = [(0, vue.createTextVNode)("上移", -1)])]),
|
|
6392
|
-
_: 1
|
|
6393
|
-
}, 8, ["disabled", "icon"]), [[vue.vShow, __props.index !== 0]]), (0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
6394
|
-
link: "",
|
|
6395
|
-
size: "default",
|
|
6396
|
-
disabled: __props.disabled,
|
|
6397
|
-
icon: (0, vue.unref)(_element_plus_icons_vue.Bottom),
|
|
6398
|
-
onClick: _cache[1] || (_cache[1] = ($event) => changeOrder(1))
|
|
6399
|
-
}, {
|
|
6400
|
-
default: (0, vue.withCtx)(() => [..._cache[8] || (_cache[8] = [(0, vue.createTextVNode)("下移", -1)])]),
|
|
6401
|
-
_: 1
|
|
6402
|
-
}, 8, ["disabled", "icon"]), [[vue.vShow, __props.index !== length.value - 1]])], 64)) : (0, vue.createCommentVNode)("v-if", true),
|
|
6403
|
-
__props.config.moveSpecifyLocation && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicPopover), {
|
|
6404
|
-
key: 2,
|
|
6405
|
-
trigger: "click",
|
|
6406
|
-
placement: "top",
|
|
6407
|
-
width: "200",
|
|
6408
|
-
visible: moveSpecifyLocationVisible.value
|
|
6409
|
-
}, {
|
|
6410
|
-
reference: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7282
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.Top),
|
|
7283
|
+
onClick: _cache[0] || (_cache[0] = ($event) => changeOrder(-1))
|
|
7284
|
+
}, {
|
|
7285
|
+
default: (0, vue.withCtx)(() => [..._cache[7] || (_cache[7] = [(0, vue.createTextVNode)("上移", -1)])]),
|
|
7286
|
+
_: 1
|
|
7287
|
+
}, 8, ["disabled", "icon"]), [[vue.vShow, __props.index !== 0]]), (0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
6411
7288
|
link: "",
|
|
6412
|
-
size: "
|
|
6413
|
-
type: "primary",
|
|
6414
|
-
icon: (0, vue.unref)(_element_plus_icons_vue.Position),
|
|
7289
|
+
size: "default",
|
|
6415
7290
|
disabled: __props.disabled,
|
|
6416
|
-
|
|
7291
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.Bottom),
|
|
7292
|
+
onClick: _cache[1] || (_cache[1] = ($event) => changeOrder(1))
|
|
6417
7293
|
}, {
|
|
6418
|
-
default: (0, vue.withCtx)(() => [..._cache[
|
|
7294
|
+
default: (0, vue.withCtx)(() => [..._cache[8] || (_cache[8] = [(0, vue.createTextVNode)("下移", -1)])]),
|
|
6419
7295
|
_: 1
|
|
6420
|
-
}, 8, ["
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
size: "small",
|
|
6428
|
-
min: 1,
|
|
6429
|
-
disabled: __props.disabled
|
|
6430
|
-
}, null, 8, ["modelValue", "disabled"]),
|
|
6431
|
-
_cache[11] || (_cache[11] = (0, vue.createTextVNode)("行 ", -1))
|
|
6432
|
-
]), (0, vue.createElementVNode)("div", _hoisted_3$4, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
6433
|
-
size: "small",
|
|
6434
|
-
text: "",
|
|
6435
|
-
onClick: _cache[4] || (_cache[4] = ($event) => moveSpecifyLocationVisible.value = false)
|
|
7296
|
+
}, 8, ["disabled", "icon"]), [[vue.vShow, __props.index !== length.value - 1]])], 64)) : (0, vue.createCommentVNode)("v-if", true),
|
|
7297
|
+
__props.config.moveSpecifyLocation && !__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicPopover), {
|
|
7298
|
+
key: 2,
|
|
7299
|
+
trigger: "click",
|
|
7300
|
+
placement: "top",
|
|
7301
|
+
width: "200",
|
|
7302
|
+
visible: moveSpecifyLocationVisible.value
|
|
6436
7303
|
}, {
|
|
6437
|
-
|
|
7304
|
+
reference: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7305
|
+
link: "",
|
|
7306
|
+
size: "small",
|
|
7307
|
+
type: "primary",
|
|
7308
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.Position),
|
|
7309
|
+
disabled: __props.disabled,
|
|
7310
|
+
onClick: _cache[2] || (_cache[2] = ($event) => moveSpecifyLocationVisible.value = true)
|
|
7311
|
+
}, {
|
|
7312
|
+
default: (0, vue.withCtx)(() => [..._cache[9] || (_cache[9] = [(0, vue.createTextVNode)("移动至", -1)])]),
|
|
7313
|
+
_: 1
|
|
7314
|
+
}, 8, ["icon", "disabled"])]),
|
|
7315
|
+
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", null, [(0, vue.createElementVNode)("div", null, [
|
|
7316
|
+
_cache[10] || (_cache[10] = (0, vue.createTextVNode)(" 第", -1)),
|
|
7317
|
+
(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicInputNumber), {
|
|
7318
|
+
style: { "margin": "0 5px" },
|
|
7319
|
+
modelValue: moveSpecifyLocationIndex.value,
|
|
7320
|
+
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => moveSpecifyLocationIndex.value = $event),
|
|
7321
|
+
size: "small",
|
|
7322
|
+
min: 1,
|
|
7323
|
+
disabled: __props.disabled
|
|
7324
|
+
}, null, 8, ["modelValue", "disabled"]),
|
|
7325
|
+
_cache[11] || (_cache[11] = (0, vue.createTextVNode)("行 ", -1))
|
|
7326
|
+
]), (0, vue.createElementVNode)("div", _hoisted_5$2, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7327
|
+
size: "small",
|
|
7328
|
+
text: "",
|
|
7329
|
+
onClick: _cache[4] || (_cache[4] = ($event) => moveSpecifyLocationVisible.value = false)
|
|
7330
|
+
}, {
|
|
7331
|
+
default: (0, vue.withCtx)(() => [..._cache[12] || (_cache[12] = [(0, vue.createTextVNode)("取消", -1)])]),
|
|
7332
|
+
_: 1
|
|
7333
|
+
}), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7334
|
+
size: "small",
|
|
7335
|
+
type: "primary",
|
|
7336
|
+
onClick: moveSpecifyLocationHandler
|
|
7337
|
+
}, {
|
|
7338
|
+
default: (0, vue.withCtx)(() => [..._cache[13] || (_cache[13] = [(0, vue.createTextVNode)("确认", -1)])]),
|
|
7339
|
+
_: 1
|
|
7340
|
+
})])])]),
|
|
6438
7341
|
_: 1
|
|
6439
|
-
}
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
7342
|
+
}, 8, ["visible"])) : (0, vue.createCommentVNode)("v-if", true),
|
|
7343
|
+
(0, vue.createCommentVNode)(" v-if 必须挂在 Tooltip 上:子节点为 false 时 ElOnlyChild 会报 no valid child node found "),
|
|
7344
|
+
!__props.isCompare ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
7345
|
+
key: 3,
|
|
7346
|
+
content: `删除 ${title.value}`
|
|
6443
7347
|
}, {
|
|
6444
|
-
default: (0, vue.withCtx)(() => [
|
|
7348
|
+
default: (0, vue.withCtx)(() => [(0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7349
|
+
size: "default",
|
|
7350
|
+
link: "",
|
|
7351
|
+
class: "delete-button",
|
|
7352
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.Delete),
|
|
7353
|
+
disabled: __props.disabled,
|
|
7354
|
+
onClick: removeHandler
|
|
7355
|
+
}, null, 8, ["icon", "disabled"]), [[vue.vShow, showDelete.value]])]),
|
|
6445
7356
|
_: 1
|
|
6446
|
-
}
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
}, null, 8, _hoisted_4$3)) : (0, vue.createCommentVNode)("v-if", true)
|
|
7357
|
+
}, 8, ["content"])) : (0, vue.createCommentVNode)("v-if", true),
|
|
7358
|
+
itemExtra.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
7359
|
+
key: 4,
|
|
7360
|
+
innerHTML: itemExtra.value,
|
|
7361
|
+
class: "m-form-tip"
|
|
7362
|
+
}, null, 8, _hoisted_6$1)) : (0, vue.createCommentVNode)("v-if", true)
|
|
7363
|
+
])
|
|
6454
7364
|
])]),
|
|
6455
7365
|
default: (0, vue.withCtx)(() => [expand.value ? ((0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
6456
7366
|
key: 0,
|
|
@@ -6459,7 +7369,8 @@
|
|
|
6459
7369
|
lastValues: __props.lastValues,
|
|
6460
7370
|
"is-compare": __props.isCompare,
|
|
6461
7371
|
labelWidth: __props.labelWidth,
|
|
6462
|
-
|
|
7372
|
+
labelPosition: __props.labelPosition,
|
|
7373
|
+
prop: rowProp.value,
|
|
6463
7374
|
size: __props.size,
|
|
6464
7375
|
disabled: __props.disabled,
|
|
6465
7376
|
onChange: changeHandler,
|
|
@@ -6470,11 +7381,12 @@
|
|
|
6470
7381
|
"lastValues",
|
|
6471
7382
|
"is-compare",
|
|
6472
7383
|
"labelWidth",
|
|
7384
|
+
"labelPosition",
|
|
6473
7385
|
"prop",
|
|
6474
7386
|
"size",
|
|
6475
7387
|
"disabled"
|
|
6476
7388
|
])) : (0, vue.createCommentVNode)("v-if", true)]),
|
|
6477
|
-
_:
|
|
7389
|
+
_: 3
|
|
6478
7390
|
}, 8, ["flat", "body-style"]);
|
|
6479
7391
|
};
|
|
6480
7392
|
}
|
|
@@ -6488,11 +7400,7 @@
|
|
|
6488
7400
|
class: "el-table__empty-block"
|
|
6489
7401
|
};
|
|
6490
7402
|
var _hoisted_4$2 = { class: "el-table__empty-text t-table__empty" };
|
|
6491
|
-
var _hoisted_5$1 = {
|
|
6492
|
-
key: 3,
|
|
6493
|
-
class: "m-fields-group-list-footer"
|
|
6494
|
-
};
|
|
6495
|
-
var _hoisted_6$1 = { style: {
|
|
7403
|
+
var _hoisted_5$1 = { style: {
|
|
6496
7404
|
"display": "flex",
|
|
6497
7405
|
"justify-content": "flex-end",
|
|
6498
7406
|
"flex": "1"
|
|
@@ -6509,6 +7417,7 @@
|
|
|
6509
7417
|
config: {},
|
|
6510
7418
|
name: {},
|
|
6511
7419
|
labelWidth: {},
|
|
7420
|
+
labelPosition: {},
|
|
6512
7421
|
prop: {},
|
|
6513
7422
|
size: {},
|
|
6514
7423
|
disabled: { type: Boolean },
|
|
@@ -6537,7 +7446,23 @@
|
|
|
6537
7446
|
emit("change", props.model[props.name]);
|
|
6538
7447
|
};
|
|
6539
7448
|
const onAddDiffCount = () => emit("addDiffCount");
|
|
6540
|
-
const
|
|
7449
|
+
const asList = (value) => Array.isArray(value) ? value : [];
|
|
7450
|
+
const currentList = (0, vue.computed)(() => asList(props.model[props.name]));
|
|
7451
|
+
/** 对比时按当前/历史较长一侧对齐,已删除的项也能渲染出来 */
|
|
7452
|
+
const displayItems = (0, vue.computed)(() => {
|
|
7453
|
+
const current = currentList.value;
|
|
7454
|
+
if (!props.isCompare) return current.map((item, index) => ({
|
|
7455
|
+
item: item ?? {},
|
|
7456
|
+
last: {},
|
|
7457
|
+
index
|
|
7458
|
+
}));
|
|
7459
|
+
const last = asList(props.lastValues?.[props.name]);
|
|
7460
|
+
return Array.from({ length: Math.max(current.length, last.length) }, (_, index) => ({
|
|
7461
|
+
item: current[index] ?? {},
|
|
7462
|
+
last: last[index] ?? {},
|
|
7463
|
+
index
|
|
7464
|
+
}));
|
|
7465
|
+
});
|
|
6541
7466
|
return (_ctx, _cache) => {
|
|
6542
7467
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$8, [
|
|
6543
7468
|
__props.config.extra ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
@@ -6545,25 +7470,30 @@
|
|
|
6545
7470
|
innerHTML: __props.config.extra,
|
|
6546
7471
|
style: { "color": "rgba(0, 0, 0, 0.45)" }
|
|
6547
7472
|
}, null, 8, _hoisted_2$4)) : (0, vue.createCommentVNode)("v-if", true),
|
|
6548
|
-
!
|
|
7473
|
+
!displayItems.value.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_3$3, [(0, vue.createElementVNode)("span", _hoisted_4$2, "暂无" + (0, vue.toDisplayString)(__props.config.titlePrefix || "") + "数据", 1)])) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, (0, vue.renderList)(displayItems.value, (entry) => {
|
|
6549
7474
|
return (0, vue.openBlock)(), (0, vue.createBlock)(GroupListItem_default, {
|
|
6550
|
-
key: index,
|
|
6551
|
-
model: item,
|
|
6552
|
-
lastValues:
|
|
7475
|
+
key: entry.index,
|
|
7476
|
+
model: entry.item,
|
|
7477
|
+
lastValues: entry.last,
|
|
6553
7478
|
"is-compare": __props.isCompare,
|
|
6554
7479
|
config: __props.config,
|
|
6555
7480
|
prop: __props.prop,
|
|
6556
|
-
index:
|
|
7481
|
+
index: entry.index,
|
|
6557
7482
|
"label-width": __props.labelWidth,
|
|
7483
|
+
"label-position": __props.labelPosition,
|
|
6558
7484
|
size: __props.size,
|
|
6559
7485
|
disabled: __props.disabled,
|
|
6560
|
-
"group-model":
|
|
7486
|
+
"group-model": currentList.value,
|
|
6561
7487
|
onRemoveItem: removeHandler,
|
|
6562
7488
|
onCopyItem: copyHandler,
|
|
6563
7489
|
onSwapItem: swapHandler,
|
|
6564
7490
|
onChange: changeHandler,
|
|
6565
7491
|
onAddDiffCount: _cache[0] || (_cache[0] = ($event) => onAddDiffCount())
|
|
6566
|
-
},
|
|
7492
|
+
}, (0, vue.createSlots)({ _: 2 }, [_ctx.$slots.title ? {
|
|
7493
|
+
name: "title",
|
|
7494
|
+
fn: (0, vue.withCtx)((slotProps) => [(0, vue.renderSlot)(_ctx.$slots, "title", (0, vue.mergeProps)({ ref_for: true }, slotProps))]),
|
|
7495
|
+
key: "0"
|
|
7496
|
+
} : void 0]), 1032, [
|
|
6567
7497
|
"model",
|
|
6568
7498
|
"lastValues",
|
|
6569
7499
|
"is-compare",
|
|
@@ -6571,12 +7501,16 @@
|
|
|
6571
7501
|
"prop",
|
|
6572
7502
|
"index",
|
|
6573
7503
|
"label-width",
|
|
7504
|
+
"label-position",
|
|
6574
7505
|
"size",
|
|
6575
7506
|
"disabled",
|
|
6576
7507
|
"group-model"
|
|
6577
7508
|
]);
|
|
6578
7509
|
}), 128)),
|
|
6579
|
-
!__props.isCompare
|
|
7510
|
+
!__props.isCompare && (_ctx.$slots["toggle-button"] || _ctx.$slots["add-button"]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7511
|
+
key: 3,
|
|
7512
|
+
class: (0, vue.normalizeClass)(["m-fields-group-list-footer", { "is-sticky-full": Boolean(__props.config.addButtonConfig?.sticky) }])
|
|
7513
|
+
}, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div", _hoisted_5$1, [(0, vue.renderSlot)(_ctx.$slots, "add-button")])], 2)) : (0, vue.createCommentVNode)("v-if", true)
|
|
6580
7514
|
]);
|
|
6581
7515
|
};
|
|
6582
7516
|
}
|
|
@@ -6946,15 +7880,7 @@
|
|
|
6946
7880
|
if (typeof props.config.selection === "function") return props.config.selection(mForm, { model: props.model[modelName.value] });
|
|
6947
7881
|
return props.config.selection;
|
|
6948
7882
|
});
|
|
6949
|
-
const getProp = (index) =>
|
|
6950
|
-
return `${props.prop}${props.prop ? "." : ""}${index + 1 + currentPage.value * pageSize.value - 1}`;
|
|
6951
|
-
};
|
|
6952
|
-
const makeConfig = (config, row) => {
|
|
6953
|
-
const newConfig = cloneDeep(config);
|
|
6954
|
-
if (typeof config.itemsFunction === "function") newConfig.items = config.itemsFunction(row);
|
|
6955
|
-
delete newConfig.display;
|
|
6956
|
-
return newConfig;
|
|
6957
|
-
};
|
|
7883
|
+
const getProp = (index) => appendProp(props.prop, index + currentPage.value * pageSize.value);
|
|
6958
7884
|
const changeHandler = (v, eventData) => {
|
|
6959
7885
|
emit("change", props.model, eventData);
|
|
6960
7886
|
};
|
|
@@ -7033,7 +7959,7 @@
|
|
|
7033
7959
|
},
|
|
7034
7960
|
cell: ({ $index }) => (0, vue.h)("span", $index + 1 + currentPage.value * pageSize.value)
|
|
7035
7961
|
});
|
|
7036
|
-
for (const column of props.config.items) if (column
|
|
7962
|
+
for (const column of props.config.items) if (isTableColumnRendered(column, display$1)) {
|
|
7037
7963
|
const titleTipValue = titleTip(column.titleTip);
|
|
7038
7964
|
columns.push({
|
|
7039
7965
|
props: {
|
|
@@ -7049,7 +7975,7 @@
|
|
|
7049
7975
|
disabled: props.disabled,
|
|
7050
7976
|
prop: getProp($index),
|
|
7051
7977
|
rules: column.rules,
|
|
7052
|
-
config:
|
|
7978
|
+
config: makeTableColumnConfig(column, row),
|
|
7053
7979
|
model: row,
|
|
7054
7980
|
lastValues: lastData.value[$index],
|
|
7055
7981
|
isCompare: props.isCompare,
|
|
@@ -7081,7 +8007,7 @@
|
|
|
7081
8007
|
} };
|
|
7082
8008
|
var _hoisted_3$2 = { style: { "display": "flex" } };
|
|
7083
8009
|
var _hoisted_4$1 = {
|
|
7084
|
-
key:
|
|
8010
|
+
key: 2,
|
|
7085
8011
|
class: "bottom",
|
|
7086
8012
|
style: { "text-align": "right" }
|
|
7087
8013
|
};
|
|
@@ -7148,12 +8074,14 @@
|
|
|
7148
8074
|
style: { "color": "rgba(0, 0, 0, 0.45)" },
|
|
7149
8075
|
innerHTML: __props.config.extra
|
|
7150
8076
|
}, null, 8, _hoisted_1$7)) : (0, vue.createCommentVNode)("v-if", true),
|
|
7151
|
-
(0, vue.
|
|
8077
|
+
(0, vue.createCommentVNode)(" v-if 必须挂在 Tooltip 上:表格未就绪时 ElOnlyChild 会报 no valid child node found "),
|
|
8078
|
+
__props.model[modelName.value] ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
8079
|
+
key: 1,
|
|
7152
8080
|
content: "拖拽可排序",
|
|
7153
8081
|
placement: "left-start",
|
|
7154
8082
|
disabled: __props.config.dropSort !== true || __props.config.dropSortHandle
|
|
7155
8083
|
}, {
|
|
7156
|
-
default: (0, vue.withCtx)(() => [
|
|
8084
|
+
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTable), {
|
|
7157
8085
|
ref: "tMagicTable",
|
|
7158
8086
|
style: { "width": "100%" },
|
|
7159
8087
|
"show-header": "",
|
|
@@ -7175,9 +8103,9 @@
|
|
|
7175
8103
|
"max-height",
|
|
7176
8104
|
"onSelect",
|
|
7177
8105
|
"empty-text"
|
|
7178
|
-
]))
|
|
8106
|
+
]))]),
|
|
7179
8107
|
_: 1
|
|
7180
|
-
}, 8, ["disabled"]),
|
|
8108
|
+
}, 8, ["disabled"])) : (0, vue.createCommentVNode)("v-if", true),
|
|
7181
8109
|
(0, vue.renderSlot)(_ctx.$slots, "default"),
|
|
7182
8110
|
(0, vue.createElementVNode)("div", _hoisted_2$3, [(0, vue.createElementVNode)("div", _hoisted_3$2, [
|
|
7183
8111
|
!(0, vue.unref)(isFullscreen) ? (0, vue.renderSlot)(_ctx.$slots, "toggle-button", {}, void 0, void 0, 0) : (0, vue.createCommentVNode)("v-if", true),
|
|
@@ -7256,39 +8184,46 @@
|
|
|
7256
8184
|
const addable = (0, vue.computed)(() => {
|
|
7257
8185
|
const modelName = props.name || props.config.name || "";
|
|
7258
8186
|
if (!modelName) return false;
|
|
7259
|
-
if (
|
|
7260
|
-
if (typeof props.config.addable === "function") return props.config.addable(mForm, {
|
|
8187
|
+
if (typeof props.config.addable === "function") return Boolean(props.config.addable(mForm, {
|
|
7261
8188
|
model: props.model[modelName],
|
|
7262
8189
|
formValue: mForm?.values,
|
|
7263
8190
|
prop: props.prop,
|
|
7264
8191
|
config: props.config
|
|
7265
|
-
});
|
|
7266
|
-
|
|
8192
|
+
}));
|
|
8193
|
+
if (!props.model[modelName]?.length) return true;
|
|
8194
|
+
return typeof props.config.addable === "undefined" ? true : Boolean(props.config.addable);
|
|
7267
8195
|
});
|
|
8196
|
+
/**
|
|
8197
|
+
* 新增一项,返回新增后列表应有的长度;没有新增(超上限 / 被 beforeAddRow 拦下 / enum 用尽)返回 null。
|
|
8198
|
+
*
|
|
8199
|
+
* 只抛 change,不直接改 `props.model`:写回由 `MForm` 按 changeRecords 的 propPath 完成。
|
|
8200
|
+
* 返回长度是给调用方用的——新项要等写回后才出现在 DOM 里,靠它才能判断等到了没有。
|
|
8201
|
+
*/
|
|
7268
8202
|
const newHandler = async (row) => {
|
|
7269
|
-
const modelName = props.name || props.config.name || ""
|
|
7270
|
-
|
|
8203
|
+
const modelName = `${props.name || props.config.name || ""}`;
|
|
8204
|
+
const list = Array.isArray(props.model[modelName]) ? props.model[modelName] : [];
|
|
8205
|
+
if (props.config.max && list.length >= props.config.max) {
|
|
7271
8206
|
_tmagic_design.tMagicMessage.error(`最多新增配置不能超过${props.config.max}条`);
|
|
7272
|
-
return;
|
|
8207
|
+
return null;
|
|
7273
8208
|
}
|
|
7274
8209
|
if (typeof props.config.beforeAddRow === "function") {
|
|
7275
8210
|
if (!await props.config.beforeAddRow(mForm, {
|
|
7276
|
-
model:
|
|
8211
|
+
model: list,
|
|
7277
8212
|
formValue: mForm?.values,
|
|
7278
8213
|
prop: props.prop
|
|
7279
|
-
})) return;
|
|
8214
|
+
})) return null;
|
|
7280
8215
|
}
|
|
7281
8216
|
const columns = props.config.items;
|
|
7282
8217
|
const enumValues = props.config.enum || [];
|
|
7283
8218
|
let enumV = [];
|
|
7284
|
-
const { length } =
|
|
8219
|
+
const { length } = list;
|
|
7285
8220
|
const key = props.config.key || "id";
|
|
7286
8221
|
let inputs = {};
|
|
7287
8222
|
if (enumValues.length) {
|
|
7288
|
-
if (length >= enumValues.length) return;
|
|
8223
|
+
if (length >= enumValues.length) return null;
|
|
7289
8224
|
enumV = enumValues.filter((item) => {
|
|
7290
8225
|
let i = 0;
|
|
7291
|
-
for (; i < length; i++) if (item[key] ===
|
|
8226
|
+
for (; i < length; i++) if (item[key] === list[i][key]) break;
|
|
7292
8227
|
return i === length;
|
|
7293
8228
|
});
|
|
7294
8229
|
if (enumV.length > 0) inputs = enumV[0];
|
|
@@ -7297,7 +8232,7 @@
|
|
|
7297
8232
|
});
|
|
7298
8233
|
else {
|
|
7299
8234
|
if (typeof props.config.defaultAdd === "function") inputs = await props.config.defaultAdd(mForm, {
|
|
7300
|
-
model:
|
|
8235
|
+
model: list,
|
|
7301
8236
|
prop: props.prop,
|
|
7302
8237
|
formValue: mForm?.values
|
|
7303
8238
|
});
|
|
@@ -7307,11 +8242,13 @@
|
|
|
7307
8242
|
initValues: inputs
|
|
7308
8243
|
});
|
|
7309
8244
|
}
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
8245
|
+
applyMountValueEffects(mForm, columns, inputs);
|
|
8246
|
+
if (props.sortKey && length) inputs[props.sortKey] = list[length - 1][props.sortKey] - 1;
|
|
8247
|
+
emit("change", [...list, inputs], { changeRecords: [{
|
|
8248
|
+
propPath: `${props.prop}.${length}`,
|
|
7313
8249
|
value: inputs
|
|
7314
8250
|
}] });
|
|
8251
|
+
return length + 1;
|
|
7315
8252
|
};
|
|
7316
8253
|
return {
|
|
7317
8254
|
addable,
|
|
@@ -7319,6 +8256,76 @@
|
|
|
7319
8256
|
};
|
|
7320
8257
|
};
|
|
7321
8258
|
//#endregion
|
|
8259
|
+
//#region packages/form/src/containers/table-group-list/useScrollLastItemIntoView.ts
|
|
8260
|
+
var nextFrame = () => new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
8261
|
+
/** 滚动要用的列表根与最后一项;组件已卸载(宿主重建了整棵表单)时返回 null */
|
|
8262
|
+
var resolveScrollTarget = (listRef) => {
|
|
8263
|
+
const inst = listRef.value;
|
|
8264
|
+
const root = inst instanceof HTMLElement ? inst : inst?.$el;
|
|
8265
|
+
if (!(root instanceof HTMLElement)) return null;
|
|
8266
|
+
const items = root.querySelectorAll(":scope > .m-fields-group-list-item");
|
|
8267
|
+
const last = items[items.length - 1];
|
|
8268
|
+
return {
|
|
8269
|
+
root,
|
|
8270
|
+
last: last instanceof HTMLElement ? last : null,
|
|
8271
|
+
count: items.length
|
|
8272
|
+
};
|
|
8273
|
+
};
|
|
8274
|
+
/** 吸顶标题自身的高度:滚动后新项的标题不能被上一层标题压住 */
|
|
8275
|
+
var getStickyHeaderOffset = (item) => {
|
|
8276
|
+
const header = item.querySelector(":scope > .el-card__header, :scope > .t-card__header");
|
|
8277
|
+
if (!(header instanceof HTMLElement)) return 0;
|
|
8278
|
+
return Number.parseFloat(getComputedStyle(header).top) || 0;
|
|
8279
|
+
};
|
|
8280
|
+
/** 吸底「新增」按钮盖住的高度;嵌套列表的 footer 还用 bottom 给外层按钮留了位 */
|
|
8281
|
+
var getStickyFooterOffset = (root) => {
|
|
8282
|
+
const footer = root.querySelector(":scope > .m-fields-group-list-footer.is-sticky-full");
|
|
8283
|
+
if (!(footer instanceof HTMLElement)) return 0;
|
|
8284
|
+
return footer.getBoundingClientRect().height + (Number.parseFloat(getComputedStyle(footer).bottom) || 0);
|
|
8285
|
+
};
|
|
8286
|
+
/**
|
|
8287
|
+
* 等列表渲染出至少 `expectedCount` 项、且最后一项的 DOM 节点连续两帧不变再返回。
|
|
8288
|
+
*
|
|
8289
|
+
* 新增只抛 change,写回要经过宿主(如编辑器属性面板)的异步校验与表单值重建,
|
|
8290
|
+
* 新项不一定当帧就出现;期间宿主还可能自己再追加项,末尾节点会换掉。
|
|
8291
|
+
* 只判「节点不变」会滚到旧的最后一项上,所以先等够数量再等稳定。
|
|
8292
|
+
*/
|
|
8293
|
+
var waitForStableTarget = async (listRef, expectedCount, timeout = 600) => {
|
|
8294
|
+
const deadline = Date.now() + timeout;
|
|
8295
|
+
let previous = null;
|
|
8296
|
+
while (Date.now() < deadline) {
|
|
8297
|
+
const target = resolveScrollTarget(listRef);
|
|
8298
|
+
if (!target) return null;
|
|
8299
|
+
if (target.count >= expectedCount && target.last && target.last === previous) return target;
|
|
8300
|
+
previous = target.last;
|
|
8301
|
+
await nextFrame();
|
|
8302
|
+
}
|
|
8303
|
+
return resolveScrollTarget(listRef);
|
|
8304
|
+
};
|
|
8305
|
+
/**
|
|
8306
|
+
* 新增后把最后一项滚进视口,避开吸顶标题与吸底按钮。
|
|
8307
|
+
*
|
|
8308
|
+
* `enabled` 为 false(未开配置、或不在 group-list 形态)时直接返回。
|
|
8309
|
+
*/
|
|
8310
|
+
var useScrollLastItemIntoView = (listRef, enabled) => {
|
|
8311
|
+
const scrollLastItemIntoView = async (expectedCount) => {
|
|
8312
|
+
if (!enabled()) return;
|
|
8313
|
+
await (0, vue.nextTick)();
|
|
8314
|
+
const target = await waitForStableTarget(listRef, expectedCount);
|
|
8315
|
+
if (!target?.last) return;
|
|
8316
|
+
const { root, last } = target;
|
|
8317
|
+
const top = getStickyHeaderOffset(last);
|
|
8318
|
+
const bottom = getStickyFooterOffset(root);
|
|
8319
|
+
last.style.scrollMarginTop = top ? `${top}px` : "";
|
|
8320
|
+
last.style.scrollMarginBottom = bottom ? `${bottom}px` : "";
|
|
8321
|
+
last.scrollIntoView({
|
|
8322
|
+
behavior: "auto",
|
|
8323
|
+
block: "nearest"
|
|
8324
|
+
});
|
|
8325
|
+
};
|
|
8326
|
+
return { scrollLastItemIntoView };
|
|
8327
|
+
};
|
|
8328
|
+
//#endregion
|
|
7322
8329
|
//#region packages/form/src/containers/table-group-list/TableGroupList.vue
|
|
7323
8330
|
var TableGroupList_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
7324
8331
|
name: "MFormTableGroupList",
|
|
@@ -7332,6 +8339,7 @@
|
|
|
7332
8339
|
name: {},
|
|
7333
8340
|
prop: {},
|
|
7334
8341
|
labelWidth: {},
|
|
8342
|
+
labelPosition: {},
|
|
7335
8343
|
disabled: { type: Boolean },
|
|
7336
8344
|
size: {},
|
|
7337
8345
|
enableToggleMode: { type: Boolean },
|
|
@@ -7348,63 +8356,47 @@
|
|
|
7348
8356
|
const props = __props;
|
|
7349
8357
|
const emit = __emit;
|
|
7350
8358
|
const { addable, newHandler } = useAdd(props, emit);
|
|
7351
|
-
const isGroupListType = (type) => type === "groupList" || type === "group-list";
|
|
7352
8359
|
const displayMode = (0, vue.ref)(isGroupListType(props.config.type) ? "groupList" : "table");
|
|
7353
|
-
const
|
|
7354
|
-
|
|
7355
|
-
const zhLength = label.match(/[^\x00-\xff]/g)?.length || 0;
|
|
7356
|
-
const chLength = label.length - zhLength;
|
|
7357
|
-
return `${Math.max(chLength * 8 + zhLength * 20, 80)}px`;
|
|
7358
|
-
};
|
|
7359
|
-
const tableConfig = (0, vue.computed)(() => {
|
|
7360
|
-
if (!isGroupListType(props.config.type)) return props.config;
|
|
7361
|
-
const source = props.config;
|
|
7362
|
-
return {
|
|
7363
|
-
...props.config,
|
|
7364
|
-
type: "table",
|
|
7365
|
-
groupItems: source.items,
|
|
7366
|
-
items: source.tableItems || source.items.map((item) => ({
|
|
7367
|
-
...item,
|
|
7368
|
-
label: item.label || item.text,
|
|
7369
|
-
text: null
|
|
7370
|
-
}))
|
|
7371
|
-
};
|
|
7372
|
-
});
|
|
7373
|
-
const groupListConfig = (0, vue.computed)(() => {
|
|
7374
|
-
if (isGroupListType(props.config.type)) return props.config;
|
|
7375
|
-
const source = props.config;
|
|
7376
|
-
return {
|
|
7377
|
-
...props.config,
|
|
7378
|
-
type: "groupList",
|
|
7379
|
-
tableItems: source.items,
|
|
7380
|
-
items: source.groupItems || source.items.map((item) => {
|
|
7381
|
-
const text = item.text || item.label;
|
|
7382
|
-
return {
|
|
7383
|
-
...item,
|
|
7384
|
-
text,
|
|
7385
|
-
labelWidth: calcLabelWidth(text),
|
|
7386
|
-
span: item.span || 12
|
|
7387
|
-
};
|
|
7388
|
-
})
|
|
7389
|
-
};
|
|
7390
|
-
});
|
|
8360
|
+
const tableConfig = (0, vue.computed)(() => toTableConfig(props.config));
|
|
8361
|
+
const groupListConfig = (0, vue.computed)(() => toGroupListConfig(props.config));
|
|
7391
8362
|
const currentConfig = (0, vue.computed)(() => displayMode.value === "table" ? tableConfig.value : groupListConfig.value);
|
|
7392
8363
|
const addButtonSize = (0, vue.computed)(() => {
|
|
8364
|
+
if (currentConfig.value.addButtonConfig?.sticky) return "default";
|
|
7393
8365
|
if (displayMode.value === "table") return "small";
|
|
7394
8366
|
return props.config.enableToggleMode !== false ? "small" : "default";
|
|
7395
8367
|
});
|
|
8368
|
+
const addButtonProps = (0, vue.computed)(() => {
|
|
8369
|
+
const custom = currentConfig.value.addButtonConfig?.props;
|
|
8370
|
+
if (custom) return {
|
|
8371
|
+
type: "primary",
|
|
8372
|
+
...custom
|
|
8373
|
+
};
|
|
8374
|
+
if (displayMode.value === "table") return {
|
|
8375
|
+
type: "primary",
|
|
8376
|
+
plain: true
|
|
8377
|
+
};
|
|
8378
|
+
return {
|
|
8379
|
+
type: "primary",
|
|
8380
|
+
text: true
|
|
8381
|
+
};
|
|
8382
|
+
});
|
|
7396
8383
|
const toggleDisplayMode = () => {
|
|
7397
8384
|
displayMode.value = displayMode.value === "table" ? "groupList" : "table";
|
|
7398
8385
|
};
|
|
8386
|
+
const tableGroupListRef = (0, vue.useTemplateRef)("tableGroupList");
|
|
8387
|
+
const { scrollLastItemIntoView } = useScrollLastItemIntoView(tableGroupListRef, () => Boolean(currentConfig.value.scrollLastItemIntoView) && displayMode.value === "groupList");
|
|
8388
|
+
const handleAdd = async () => {
|
|
8389
|
+
const expectedCount = await newHandler();
|
|
8390
|
+
if (expectedCount !== null) await scrollLastItemIntoView(expectedCount);
|
|
8391
|
+
};
|
|
7399
8392
|
const onChange = (v, eventData) => emit("change", v, eventData);
|
|
7400
8393
|
const onSelect = (...args) => emit("select", ...args);
|
|
7401
8394
|
const onAddDiffCount = () => emit("addDiffCount");
|
|
7402
|
-
const onAdd = (rows) => {
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
8395
|
+
const onAdd = async (rows) => {
|
|
8396
|
+
let expectedCount = null;
|
|
8397
|
+
for (const row of rows) expectedCount = await newHandler(row) ?? expectedCount;
|
|
8398
|
+
if (expectedCount !== null) await scrollLastItemIntoView(expectedCount);
|
|
7406
8399
|
};
|
|
7407
|
-
const tableGroupListRef = (0, vue.useTemplateRef)("tableGroupList");
|
|
7408
8400
|
__expose({ toggleRowSelection: (row, selected) => tableGroupListRef.value?.toggleRowSelection?.(row, selected) });
|
|
7409
8401
|
return (_ctx, _cache) => {
|
|
7410
8402
|
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(displayMode.value === "table" ? Table_default : GroupList_default), (0, vue.mergeProps)({ ref: "tableGroupList" }, _ctx.$attrs, {
|
|
@@ -7417,6 +8409,7 @@
|
|
|
7417
8409
|
"last-values": __props.lastValues,
|
|
7418
8410
|
prop: __props.prop,
|
|
7419
8411
|
"label-width": __props.labelWidth,
|
|
8412
|
+
"label-position": __props.labelPosition,
|
|
7420
8413
|
"show-index": __props.showIndex,
|
|
7421
8414
|
"sort-key": __props.sortKey,
|
|
7422
8415
|
sort: __props.sort,
|
|
@@ -7424,39 +8417,43 @@
|
|
|
7424
8417
|
onSelect,
|
|
7425
8418
|
onAddDiffCount,
|
|
7426
8419
|
onAdd
|
|
7427
|
-
}), (0, vue.createSlots)({
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
"
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
8420
|
+
}), (0, vue.createSlots)({ _: 2 }, [
|
|
8421
|
+
__props.config.enableToggleMode || __props.enableToggleMode ? {
|
|
8422
|
+
name: "toggle-button",
|
|
8423
|
+
fn: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
8424
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.Grid),
|
|
8425
|
+
size: "small",
|
|
8426
|
+
onClick: toggleDisplayMode
|
|
8427
|
+
}, {
|
|
8428
|
+
default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(displayMode.value === "table" ? "展开配置" : "切换为表格"), 1)]),
|
|
8429
|
+
_: 1
|
|
8430
|
+
}, 8, ["icon"])]),
|
|
8431
|
+
key: "0"
|
|
8432
|
+
} : void 0,
|
|
8433
|
+
(0, vue.unref)(addable) ? {
|
|
8434
|
+
name: "add-button",
|
|
8435
|
+
fn: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), (0, vue.mergeProps)({
|
|
8436
|
+
class: displayMode.value === "table" ? "m-form-table-add-button" : "",
|
|
8437
|
+
size: addButtonSize.value,
|
|
8438
|
+
icon: (0, vue.unref)(_element_plus_icons_vue.Plus),
|
|
8439
|
+
disabled: __props.disabled
|
|
8440
|
+
}, addButtonProps.value, { onClick: handleAdd }), {
|
|
8441
|
+
default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(currentConfig.value.addButtonConfig?.text || (displayMode.value === "table" ? `新增一行${groupListConfig.value.titlePrefix || ""}` : `新增${groupListConfig.value.titlePrefix || ""}`)), 1)]),
|
|
8442
|
+
_: 1
|
|
8443
|
+
}, 16, [
|
|
8444
|
+
"class",
|
|
8445
|
+
"size",
|
|
8446
|
+
"icon",
|
|
8447
|
+
"disabled"
|
|
8448
|
+
])]),
|
|
8449
|
+
key: "1"
|
|
8450
|
+
} : void 0,
|
|
8451
|
+
_ctx.$slots.title ? {
|
|
8452
|
+
name: "title",
|
|
8453
|
+
fn: (0, vue.withCtx)((slotProps) => [(0, vue.renderSlot)(_ctx.$slots, "title", (0, vue.normalizeProps)((0, vue.guardReactiveProps)(slotProps)))]),
|
|
8454
|
+
key: "2"
|
|
8455
|
+
} : void 0
|
|
8456
|
+
]), 1040, [
|
|
7460
8457
|
"model",
|
|
7461
8458
|
"name",
|
|
7462
8459
|
"config",
|
|
@@ -7466,6 +8463,7 @@
|
|
|
7466
8463
|
"last-values",
|
|
7467
8464
|
"prop",
|
|
7468
8465
|
"label-width",
|
|
8466
|
+
"label-position",
|
|
7469
8467
|
"show-index",
|
|
7470
8468
|
"sort-key",
|
|
7471
8469
|
"sort"
|
|
@@ -7784,13 +8782,13 @@
|
|
|
7784
8782
|
}
|
|
7785
8783
|
});
|
|
7786
8784
|
//#endregion
|
|
7787
|
-
//#region packages/form/src/fields/NumberRange.vue?vue&type=script&setup=true&lang.ts
|
|
8785
|
+
//#region packages/form/src/fields/NumberRange/Index.vue?vue&type=script&setup=true&lang.ts
|
|
7788
8786
|
var _hoisted_1$5 = { class: "m-fields-number-range" };
|
|
7789
8787
|
//#endregion
|
|
7790
|
-
//#region packages/form/src/fields/NumberRange.vue
|
|
7791
|
-
var
|
|
8788
|
+
//#region packages/form/src/fields/NumberRange/Index.vue
|
|
8789
|
+
var Index_default$5 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
7792
8790
|
name: "MFormNumberRange",
|
|
7793
|
-
__name: "
|
|
8791
|
+
__name: "Index",
|
|
7794
8792
|
props: {
|
|
7795
8793
|
config: {},
|
|
7796
8794
|
model: {},
|
|
@@ -7820,7 +8818,6 @@
|
|
|
7820
8818
|
deep: true
|
|
7821
8819
|
});
|
|
7822
8820
|
useAddField(props.prop);
|
|
7823
|
-
if (!Array.isArray(props.model[props.name])) props.model[props.name] = [];
|
|
7824
8821
|
const minChangeHandler = (v) => {
|
|
7825
8822
|
emit("change", [Number(v), props.model[props.name][1]]);
|
|
7826
8823
|
};
|
|
@@ -7920,10 +8917,10 @@
|
|
|
7920
8917
|
}
|
|
7921
8918
|
});
|
|
7922
8919
|
//#endregion
|
|
7923
|
-
//#region packages/form/src/fields/Date.vue
|
|
7924
|
-
var
|
|
8920
|
+
//#region packages/form/src/fields/Date/Index.vue
|
|
8921
|
+
var Index_default$1 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
7925
8922
|
name: "MFormDate",
|
|
7926
|
-
__name: "
|
|
8923
|
+
__name: "Index",
|
|
7927
8924
|
props: {
|
|
7928
8925
|
config: {},
|
|
7929
8926
|
model: {},
|
|
@@ -7944,7 +8941,6 @@
|
|
|
7944
8941
|
const props = __props;
|
|
7945
8942
|
const emit = __emit;
|
|
7946
8943
|
useAddField(props.prop);
|
|
7947
|
-
props.model[props.name] = datetimeFormatter(props.model[props.name], "", props.config.valueFormat || "YYYY/MM/DD");
|
|
7948
8944
|
const changeHandler = (v) => {
|
|
7949
8945
|
emit("change", v);
|
|
7950
8946
|
};
|
|
@@ -7970,10 +8966,10 @@
|
|
|
7970
8966
|
}
|
|
7971
8967
|
});
|
|
7972
8968
|
//#endregion
|
|
7973
|
-
//#region packages/form/src/fields/DateTime.vue
|
|
7974
|
-
var
|
|
8969
|
+
//#region packages/form/src/fields/DateTime/Index.vue
|
|
8970
|
+
var Index_default$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
7975
8971
|
name: "MFormDateTime",
|
|
7976
|
-
__name: "
|
|
8972
|
+
__name: "Index",
|
|
7977
8973
|
props: {
|
|
7978
8974
|
config: {},
|
|
7979
8975
|
model: {},
|
|
@@ -7994,9 +8990,6 @@
|
|
|
7994
8990
|
const props = __props;
|
|
7995
8991
|
const emit = __emit;
|
|
7996
8992
|
useAddField(props.prop);
|
|
7997
|
-
const value = props.model?.[props.name]?.toString();
|
|
7998
|
-
if (props.model) if (!value || value === "Invalid Date") props.model[props.name] = "";
|
|
7999
|
-
else props.model[props.name] = datetimeFormatter(props.model[props.name], "", props.config.valueFormat || "YYYY/MM/DD HH:mm:ss");
|
|
8000
8993
|
const changeHandler = (v) => {
|
|
8001
8994
|
emit("change", v);
|
|
8002
8995
|
};
|
|
@@ -8426,10 +9419,10 @@
|
|
|
8426
9419
|
}
|
|
8427
9420
|
});
|
|
8428
9421
|
//#endregion
|
|
8429
|
-
//#region packages/form/src/fields/CheckboxGroup.vue
|
|
8430
|
-
var
|
|
9422
|
+
//#region packages/form/src/fields/CheckboxGroup/Index.vue
|
|
9423
|
+
var Index_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8431
9424
|
name: "MFormCheckGroup",
|
|
8432
|
-
__name: "
|
|
9425
|
+
__name: "Index",
|
|
8433
9426
|
props: {
|
|
8434
9427
|
config: {},
|
|
8435
9428
|
model: {},
|
|
@@ -8450,7 +9443,6 @@
|
|
|
8450
9443
|
const props = __props;
|
|
8451
9444
|
const emit = __emit;
|
|
8452
9445
|
useAddField(props.prop);
|
|
8453
|
-
if (props.model && !props.model[props.name]) props.model[props.name] = [];
|
|
8454
9446
|
const changeHandler = (v) => {
|
|
8455
9447
|
emit("change", v);
|
|
8456
9448
|
};
|
|
@@ -8571,13 +9563,13 @@
|
|
|
8571
9563
|
}
|
|
8572
9564
|
});
|
|
8573
9565
|
//#endregion
|
|
8574
|
-
//#region packages/form/src/fields/Display.vue?vue&type=script&setup=true&lang.ts
|
|
9566
|
+
//#region packages/form/src/fields/Display/Index.vue?vue&type=script&setup=true&lang.ts
|
|
8575
9567
|
var _hoisted_1$3 = { key: 0 };
|
|
8576
9568
|
//#endregion
|
|
8577
|
-
//#region packages/form/src/fields/Display.vue
|
|
8578
|
-
var
|
|
9569
|
+
//#region packages/form/src/fields/Display/Index.vue
|
|
9570
|
+
var Index_default$3 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8579
9571
|
name: "MFormDisplay",
|
|
8580
|
-
__name: "
|
|
9572
|
+
__name: "Index",
|
|
8581
9573
|
props: {
|
|
8582
9574
|
config: {},
|
|
8583
9575
|
model: {},
|
|
@@ -8596,7 +9588,6 @@
|
|
|
8596
9588
|
setup(__props) {
|
|
8597
9589
|
const props = __props;
|
|
8598
9590
|
const mForm = (0, vue.inject)("mForm");
|
|
8599
|
-
if (props.config.initValue && props.model) props.model[props.name] = props.config.initValue;
|
|
8600
9591
|
const text = (0, vue.computed)(() => {
|
|
8601
9592
|
if (props.config.displayText) return filterFunction(mForm, props.config.displayText, props);
|
|
8602
9593
|
return props.model[props.name];
|
|
@@ -8927,7 +9918,10 @@
|
|
|
8927
9918
|
prop: props.prop,
|
|
8928
9919
|
postOptions
|
|
8929
9920
|
});
|
|
8930
|
-
let initData
|
|
9921
|
+
let initData;
|
|
9922
|
+
try {
|
|
9923
|
+
initData = (0, _tmagic_utils.getValueByKeyPath)(initRoot || root, res);
|
|
9924
|
+
} catch {}
|
|
8931
9925
|
if (initData) {
|
|
8932
9926
|
if (!Array.isArray(initData)) initData = [initData];
|
|
8933
9927
|
if (typeof option.item === "function") options = option.item(initData);
|
|
@@ -8958,8 +9952,12 @@
|
|
|
8958
9952
|
const v = props.model[props.name];
|
|
8959
9953
|
if (Array.isArray(v) ? !v.length : typeof v === "undefined") return;
|
|
8960
9954
|
if (typeof v === "undefined" || hasOption(v)) return;
|
|
8961
|
-
|
|
8962
|
-
|
|
9955
|
+
try {
|
|
9956
|
+
const data = await getInitOption();
|
|
9957
|
+
setOptions(data);
|
|
9958
|
+
} catch {
|
|
9959
|
+
setOptions([]);
|
|
9960
|
+
}
|
|
8963
9961
|
};
|
|
8964
9962
|
(0, vue.watch)(() => props.model?.[props.name], () => {
|
|
8965
9963
|
initOption();
|
|
@@ -9054,7 +10052,7 @@
|
|
|
9054
10052
|
}), 128)) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, (0, vue.renderList)(options.value, (option) => {
|
|
9055
10053
|
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(optionComponent)?.component || "el-option"), (0, vue.mergeProps)({
|
|
9056
10054
|
class: "tmagic-design-option",
|
|
9057
|
-
key: __props.config.valueKey ? option.value[__props.config.valueKey] : option.value
|
|
10055
|
+
key: __props.config.valueKey ? option.value?.[__props.config.valueKey] : option.value
|
|
9058
10056
|
}, { ref_for: true }, (0, vue.unref)(optionComponent)?.props({
|
|
9059
10057
|
label: option.text,
|
|
9060
10058
|
value: option.value,
|
|
@@ -9204,13 +10202,50 @@
|
|
|
9204
10202
|
}
|
|
9205
10203
|
});
|
|
9206
10204
|
//#endregion
|
|
9207
|
-
//#region packages/form/src/fields/DynamicField.
|
|
10205
|
+
//#region packages/form/src/fields/DynamicField/effect.ts
|
|
10206
|
+
/**
|
|
10207
|
+
* 遍历动态字段列表,按「原值为空且声明了 defaultValue 则取默认值」求出每个字段当前的值。
|
|
10208
|
+
*
|
|
10209
|
+
* `isDefaultApplied` 为真表示该值来自 `defaultValue`,需要写回表单值
|
|
10210
|
+
* (组件通过 emit change 写回,初始化写入直接写 `values`)。
|
|
10211
|
+
*/
|
|
10212
|
+
var eachDynamicField = (fields, model, onField) => {
|
|
10213
|
+
for (const field of fields) {
|
|
10214
|
+
if (typeof field !== "object" || field?.name === void 0) continue;
|
|
10215
|
+
let value = model?.[field.name] || "";
|
|
10216
|
+
let isDefaultApplied = false;
|
|
10217
|
+
if (!value && field.defaultValue !== void 0) {
|
|
10218
|
+
value = field.defaultValue;
|
|
10219
|
+
isDefaultApplied = true;
|
|
10220
|
+
}
|
|
10221
|
+
onField(field, value, isDefaultApplied);
|
|
10222
|
+
}
|
|
10223
|
+
};
|
|
10224
|
+
/**
|
|
10225
|
+
* 同步 `returnFields` 的 defaultValue 按 prop 写入值根对象。
|
|
10226
|
+
*
|
|
10227
|
+
* 该组件读取的是同级 model,但写入走 Container 的 modifyKey 分支,落在 `${prop}.${key}`,
|
|
10228
|
+
* 这里保持与渲染一致(含这层不对称),避免两条链路产出不同的值。
|
|
10229
|
+
* 异步 returnFields 由组件挂载后的 watch 负责,此处不等待。
|
|
10230
|
+
*/
|
|
10231
|
+
var effect$5 = ({ config, model, prop, values }) => {
|
|
10232
|
+
const { returnFields, dynamicKey } = config;
|
|
10233
|
+
if (typeof returnFields !== "function" || !model) return;
|
|
10234
|
+
if (model[dynamicKey] === "") return;
|
|
10235
|
+
const result = returnFields(config, model, getConfig("request"));
|
|
10236
|
+
if (!result || typeof result.then === "function" || !Array.isArray(result)) return;
|
|
10237
|
+
eachDynamicField(result, model, (field, value, isDefaultApplied) => {
|
|
10238
|
+
if (isDefaultApplied) (0, _tmagic_utils.setValueByKeyPath)(`${prop}.${field.name}`, value, values || model);
|
|
10239
|
+
});
|
|
10240
|
+
};
|
|
10241
|
+
//#endregion
|
|
10242
|
+
//#region packages/form/src/fields/DynamicField/Index.vue?vue&type=script&setup=true&lang.ts
|
|
9208
10243
|
var _hoisted_1 = { class: "m-fields-dynamic-field" };
|
|
9209
10244
|
//#endregion
|
|
9210
|
-
//#region packages/form/src/fields/DynamicField.vue
|
|
9211
|
-
var
|
|
10245
|
+
//#region packages/form/src/fields/DynamicField/Index.vue
|
|
10246
|
+
var Index_default$4 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
9212
10247
|
name: "MFormDynamicField",
|
|
9213
|
-
__name: "
|
|
10248
|
+
__name: "Index",
|
|
9214
10249
|
props: {
|
|
9215
10250
|
config: {},
|
|
9216
10251
|
model: {},
|
|
@@ -9248,15 +10283,10 @@
|
|
|
9248
10283
|
const fields = await props.config.returnFields(props.config, props.model, request);
|
|
9249
10284
|
fieldMap.value = {};
|
|
9250
10285
|
fieldLabelMap.value = {};
|
|
9251
|
-
fields.
|
|
9252
|
-
if (
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
oldVal = v.defaultValue;
|
|
9256
|
-
emit("change", oldVal, { modifyKey: v.name });
|
|
9257
|
-
}
|
|
9258
|
-
fieldMap.value[v.name] = oldVal;
|
|
9259
|
-
fieldLabelMap.value[v.name] = v.label || "";
|
|
10286
|
+
eachDynamicField(fields, props.model, (field, value, isDefaultApplied) => {
|
|
10287
|
+
if (isDefaultApplied) emit("change", value, { modifyKey: field.name });
|
|
10288
|
+
fieldMap.value[field.name] = value;
|
|
10289
|
+
fieldLabelMap.value[field.name] = field.label || "";
|
|
9260
10290
|
});
|
|
9261
10291
|
};
|
|
9262
10292
|
const unwatch = (0, vue.watch)(() => props.model?.[props.config.dynamicKey], (val) => {
|
|
@@ -9295,146 +10325,245 @@
|
|
|
9295
10325
|
}
|
|
9296
10326
|
});
|
|
9297
10327
|
//#endregion
|
|
9298
|
-
//#region packages/form/src/
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
const stepClick = (index) => {
|
|
9323
|
-
active.value = index + 1;
|
|
9324
|
-
mForm?.$emit("update:stepActive", active.value);
|
|
9325
|
-
};
|
|
9326
|
-
const changeHandler = (v, eventData) => {
|
|
9327
|
-
emit("change", props.model, eventData);
|
|
9328
|
-
};
|
|
9329
|
-
const onAddDiffCount = () => emit("addDiffCount");
|
|
9330
|
-
return (_ctx, _cache) => {
|
|
9331
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", null, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicSteps), {
|
|
9332
|
-
active: active.value,
|
|
9333
|
-
"align-center": "",
|
|
9334
|
-
space: __props.config.space
|
|
9335
|
-
}, {
|
|
9336
|
-
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (item, index) => {
|
|
9337
|
-
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicStep), {
|
|
9338
|
-
key: item.__key,
|
|
9339
|
-
title: item.title,
|
|
9340
|
-
active: active.value,
|
|
9341
|
-
onClick: ($event) => stepClick(index)
|
|
9342
|
-
}, null, 8, [
|
|
9343
|
-
"title",
|
|
9344
|
-
"active",
|
|
9345
|
-
"onClick"
|
|
9346
|
-
]);
|
|
9347
|
-
}), 128))]),
|
|
9348
|
-
_: 1
|
|
9349
|
-
}, 8, ["active", "space"]), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (step, index) => {
|
|
9350
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(step.items, (item) => {
|
|
9351
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [item ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
9352
|
-
key: item[(0, vue.unref)(mForm)?.keyProp || "__key"],
|
|
9353
|
-
config: item,
|
|
9354
|
-
model: step.name ? __props.model[step.name] : __props.model,
|
|
9355
|
-
lastValues: step.name ? __props.lastValues[step.name] : __props.lastValues,
|
|
9356
|
-
"is-compare": __props.isCompare,
|
|
9357
|
-
prop: `${step.name}`,
|
|
9358
|
-
size: __props.size,
|
|
9359
|
-
disabled: __props.disabled,
|
|
9360
|
-
"label-width": __props.config.labelWidth || __props.labelWidth,
|
|
9361
|
-
onChange: changeHandler,
|
|
9362
|
-
onAddDiffCount: _cache[0] || (_cache[0] = ($event) => onAddDiffCount())
|
|
9363
|
-
}, null, 8, [
|
|
9364
|
-
"config",
|
|
9365
|
-
"model",
|
|
9366
|
-
"lastValues",
|
|
9367
|
-
"is-compare",
|
|
9368
|
-
"prop",
|
|
9369
|
-
"size",
|
|
9370
|
-
"disabled",
|
|
9371
|
-
"label-width"
|
|
9372
|
-
])), [[vue.vShow, active.value - 1 === index]]) : (0, vue.createCommentVNode)("v-if", true)], 64);
|
|
9373
|
-
}), 256))], 64);
|
|
9374
|
-
}), 256))]);
|
|
9375
|
-
};
|
|
10328
|
+
//#region packages/form/src/fields/CheckboxGroup/effect.ts
|
|
10329
|
+
/** 空值初始化为空数组。 */
|
|
10330
|
+
var effect$4 = ({ config, model }) => {
|
|
10331
|
+
const { name } = config;
|
|
10332
|
+
if (model && !model[name]) model[name] = [];
|
|
10333
|
+
};
|
|
10334
|
+
//#endregion
|
|
10335
|
+
//#region packages/form/src/fields/Date/effect.ts
|
|
10336
|
+
/** 按 `valueFormat` 归一化日期值。 */
|
|
10337
|
+
var effect$3 = ({ config, model }) => {
|
|
10338
|
+
if (!model) return;
|
|
10339
|
+
const { name, valueFormat } = config;
|
|
10340
|
+
model[name] = datetimeFormatter(model[name], "", valueFormat || "YYYY/MM/DD");
|
|
10341
|
+
};
|
|
10342
|
+
//#endregion
|
|
10343
|
+
//#region packages/form/src/fields/DateTime/effect.ts
|
|
10344
|
+
/** 按 `valueFormat` 归一化日期时间值,空值与非法值统一为空字符串。 */
|
|
10345
|
+
var effect$2 = ({ config, model }) => {
|
|
10346
|
+
if (!model) return;
|
|
10347
|
+
const { name, valueFormat } = config;
|
|
10348
|
+
const value = model[name]?.toString();
|
|
10349
|
+
if (!value || value === "Invalid Date") {
|
|
10350
|
+
model[name] = "";
|
|
10351
|
+
return;
|
|
9376
10352
|
}
|
|
9377
|
-
|
|
10353
|
+
model[name] = datetimeFormatter(model[name], "", valueFormat || "YYYY/MM/DD HH:mm:ss");
|
|
10354
|
+
};
|
|
10355
|
+
//#endregion
|
|
10356
|
+
//#region packages/form/src/fields/Display/effect.ts
|
|
10357
|
+
/** 把 `initValue` 写入 model。 */
|
|
10358
|
+
var effect$1 = ({ config, model }) => {
|
|
10359
|
+
const { initValue, name } = config;
|
|
10360
|
+
if (initValue && model) model[name] = initValue;
|
|
10361
|
+
};
|
|
10362
|
+
//#endregion
|
|
10363
|
+
//#region packages/form/src/fields/NumberRange/effect.ts
|
|
10364
|
+
/** 值不是数组时修正为空数组。 */
|
|
10365
|
+
var effect = ({ config, model }) => {
|
|
10366
|
+
const { name } = config;
|
|
10367
|
+
if (model && !Array.isArray(model[name])) model[name] = [];
|
|
10368
|
+
};
|
|
10369
|
+
//#endregion
|
|
10370
|
+
//#region packages/form/src/utils/builtInFields.ts
|
|
10371
|
+
/**
|
|
10372
|
+
* 内置字段的无渲染登记表(不含 Vue 组件)。
|
|
10373
|
+
*
|
|
10374
|
+
* 本模块只导出数据,不登记。调用方自行 `registerBuiltInFields(builtInFields)`,
|
|
10375
|
+
* 或 `app.use(MagicForm)`(install 里会登记叠上 Vue 组件后的表)。
|
|
10376
|
+
*/
|
|
10377
|
+
var builtInFields = {
|
|
10378
|
+
text: {},
|
|
10379
|
+
"img-upload": {},
|
|
10380
|
+
number: {},
|
|
10381
|
+
"number-range": { effect },
|
|
10382
|
+
textarea: {},
|
|
10383
|
+
hidden: {},
|
|
10384
|
+
date: { effect: effect$3 },
|
|
10385
|
+
datetime: { effect: effect$2 },
|
|
10386
|
+
daterange: {},
|
|
10387
|
+
timerange: {},
|
|
10388
|
+
time: {},
|
|
10389
|
+
checkbox: {},
|
|
10390
|
+
switch: {},
|
|
10391
|
+
"color-picker": {},
|
|
10392
|
+
"checkbox-group": { effect: effect$4 },
|
|
10393
|
+
"radio-group": {},
|
|
10394
|
+
display: { effect: effect$1 },
|
|
10395
|
+
link: {},
|
|
10396
|
+
select: {},
|
|
10397
|
+
cascader: {},
|
|
10398
|
+
"dynamic-field": { effect: effect$5 },
|
|
10399
|
+
component: {},
|
|
10400
|
+
tab: { walk: expandTab },
|
|
10401
|
+
row: { walk: expandRow },
|
|
10402
|
+
"flex-layout": { walk: expandRow },
|
|
10403
|
+
fieldset: { walk: expandFieldset },
|
|
10404
|
+
panel: { walk: expandPanel },
|
|
10405
|
+
step: { walk: expandStep },
|
|
10406
|
+
table: { walk: expandTableGroupList },
|
|
10407
|
+
"group-list": { walk: expandTableGroupList },
|
|
10408
|
+
"table-group-list": { walk: expandTableGroupList }
|
|
10409
|
+
};
|
|
9378
10410
|
//#endregion
|
|
9379
10411
|
//#region packages/form/src/plugin.ts
|
|
10412
|
+
var builtInFieldVue = {
|
|
10413
|
+
text: { component: Text_default },
|
|
10414
|
+
"img-upload": { component: Text_default },
|
|
10415
|
+
number: { component: Number_default },
|
|
10416
|
+
"number-range": { component: Index_default$5 },
|
|
10417
|
+
textarea: { component: Textarea_default },
|
|
10418
|
+
hidden: { component: Hidden_default },
|
|
10419
|
+
date: { component: Index_default$1 },
|
|
10420
|
+
datetime: { component: Index_default$2 },
|
|
10421
|
+
daterange: { component: Daterange_default },
|
|
10422
|
+
timerange: { component: Timerange_default },
|
|
10423
|
+
time: { component: Time_default },
|
|
10424
|
+
checkbox: { component: Checkbox_default },
|
|
10425
|
+
switch: { component: Switch_default },
|
|
10426
|
+
"color-picker": { component: ColorPicker_default },
|
|
10427
|
+
"checkbox-group": { component: Index_default },
|
|
10428
|
+
"radio-group": { component: RadioGroup_default },
|
|
10429
|
+
display: { component: Index_default$3 },
|
|
10430
|
+
link: { component: Link_default },
|
|
10431
|
+
select: { component: Select_default },
|
|
10432
|
+
cascader: { component: Cascader_default },
|
|
10433
|
+
"dynamic-field": { component: Index_default$4 },
|
|
10434
|
+
container: { container: Container_default },
|
|
10435
|
+
tab: { container: Tabs_default },
|
|
10436
|
+
row: { container: Row_default },
|
|
10437
|
+
"flex-layout": { container: FlexLayout_default },
|
|
10438
|
+
fieldset: { container: Fieldset_default },
|
|
10439
|
+
panel: { container: Panel_default },
|
|
10440
|
+
step: { container: /* @__PURE__ */ (0, vue.defineComponent)({
|
|
10441
|
+
name: "MFormStep",
|
|
10442
|
+
__name: "Step",
|
|
10443
|
+
props: {
|
|
10444
|
+
model: {},
|
|
10445
|
+
name: {},
|
|
10446
|
+
lastValues: {},
|
|
10447
|
+
isCompare: { type: Boolean },
|
|
10448
|
+
config: {},
|
|
10449
|
+
stepActive: { default: 1 },
|
|
10450
|
+
labelWidth: {},
|
|
10451
|
+
labelPosition: {},
|
|
10452
|
+
size: {},
|
|
10453
|
+
disabled: { type: Boolean }
|
|
10454
|
+
},
|
|
10455
|
+
emits: ["change", "addDiffCount"],
|
|
10456
|
+
setup(__props, { emit: __emit }) {
|
|
10457
|
+
const props = __props;
|
|
10458
|
+
const emit = __emit;
|
|
10459
|
+
const mForm = (0, vue.inject)("mForm");
|
|
10460
|
+
const active = (0, vue.ref)(1);
|
|
10461
|
+
(0, vue.watchEffect)(() => {
|
|
10462
|
+
active.value = props.stepActive;
|
|
10463
|
+
});
|
|
10464
|
+
const stepClick = (index) => {
|
|
10465
|
+
active.value = index + 1;
|
|
10466
|
+
mForm?.$emit("update:stepActive", active.value);
|
|
10467
|
+
};
|
|
10468
|
+
const changeHandler = (v, eventData) => {
|
|
10469
|
+
emit("change", props.model, eventData);
|
|
10470
|
+
};
|
|
10471
|
+
const onAddDiffCount = () => emit("addDiffCount");
|
|
10472
|
+
return (_ctx, _cache) => {
|
|
10473
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", null, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicSteps), {
|
|
10474
|
+
active: active.value,
|
|
10475
|
+
"align-center": "",
|
|
10476
|
+
space: __props.config.space
|
|
10477
|
+
}, {
|
|
10478
|
+
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (item, index) => {
|
|
10479
|
+
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicStep), {
|
|
10480
|
+
key: item.__key,
|
|
10481
|
+
title: item.title,
|
|
10482
|
+
active: active.value,
|
|
10483
|
+
onClick: ($event) => stepClick(index)
|
|
10484
|
+
}, null, 8, [
|
|
10485
|
+
"title",
|
|
10486
|
+
"active",
|
|
10487
|
+
"onClick"
|
|
10488
|
+
]);
|
|
10489
|
+
}), 128))]),
|
|
10490
|
+
_: 1
|
|
10491
|
+
}, 8, ["active", "space"]), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (step, index) => {
|
|
10492
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(step.items, (item) => {
|
|
10493
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [item ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
10494
|
+
key: item[(0, vue.unref)(mForm)?.keyProp || "__key"],
|
|
10495
|
+
config: item,
|
|
10496
|
+
model: step.name ? __props.model[step.name] : __props.model,
|
|
10497
|
+
lastValues: step.name ? __props.lastValues[step.name] : __props.lastValues,
|
|
10498
|
+
"is-compare": __props.isCompare,
|
|
10499
|
+
prop: `${step.name}`,
|
|
10500
|
+
size: __props.size,
|
|
10501
|
+
disabled: __props.disabled,
|
|
10502
|
+
"label-width": __props.config.labelWidth || __props.labelWidth,
|
|
10503
|
+
"label-position": __props.config.labelPosition || __props.labelPosition,
|
|
10504
|
+
onChange: changeHandler,
|
|
10505
|
+
onAddDiffCount: _cache[0] || (_cache[0] = ($event) => onAddDiffCount())
|
|
10506
|
+
}, null, 8, [
|
|
10507
|
+
"config",
|
|
10508
|
+
"model",
|
|
10509
|
+
"lastValues",
|
|
10510
|
+
"is-compare",
|
|
10511
|
+
"prop",
|
|
10512
|
+
"size",
|
|
10513
|
+
"disabled",
|
|
10514
|
+
"label-width",
|
|
10515
|
+
"label-position"
|
|
10516
|
+
])), [[vue.vShow, active.value - 1 === index]]) : (0, vue.createCommentVNode)("v-if", true)], 64);
|
|
10517
|
+
}), 256))], 64);
|
|
10518
|
+
}), 256))]);
|
|
10519
|
+
};
|
|
10520
|
+
}
|
|
10521
|
+
}) },
|
|
10522
|
+
table: { container: TableGroupList_default },
|
|
10523
|
+
"group-list": { container: TableGroupList_default },
|
|
10524
|
+
"table-group-list": { container: TableGroupList_default }
|
|
10525
|
+
};
|
|
9380
10526
|
var defaultInstallOpt = {};
|
|
9381
|
-
var plugin_default = {
|
|
9382
|
-
|
|
10527
|
+
var plugin_default = {
|
|
10528
|
+
/**
|
|
10529
|
+
* 安装 `@tmagic/form`:登记内置字段、挂载 `m-form` / `m-form-dialog` / `m-form-drawer`。
|
|
10530
|
+
*
|
|
10531
|
+
* @param app - Vue 应用
|
|
10532
|
+
* @param [opt] - 安装选项
|
|
10533
|
+
*/
|
|
10534
|
+
install(app, opt = {}) {
|
|
10535
|
+
const option = {
|
|
10536
|
+
...defaultInstallOpt,
|
|
10537
|
+
...opt
|
|
10538
|
+
};
|
|
9383
10539
|
app.config.globalProperties.$MAGIC_FORM = option;
|
|
9384
10540
|
setConfig(option);
|
|
9385
|
-
|
|
10541
|
+
registerBuiltInFields(builtInFields);
|
|
10542
|
+
registerBuiltInFields(builtInFieldVue, app);
|
|
10543
|
+
if (option.fields) registerFields(option.fields, app);
|
|
9386
10544
|
app.component("m-form", Form_default);
|
|
9387
10545
|
app.component("m-form-dialog", FormDialog_default);
|
|
9388
10546
|
app.component("m-form-drawer", FormDrawer_default);
|
|
9389
|
-
app.component("m-form-container", Container_default);
|
|
9390
|
-
app.component("m-form-fieldset", Fieldset_default);
|
|
9391
|
-
app.component("m-form-group-list", TableGroupList_default);
|
|
9392
|
-
app.component("m-form-panel", Panel_default);
|
|
9393
|
-
app.component("m-form-row", Row_default);
|
|
9394
|
-
app.component("m-form-step", Step_default);
|
|
9395
|
-
app.component("m-form-table", TableGroupList_default);
|
|
9396
|
-
app.component("m-form-tab", Tabs_default);
|
|
9397
|
-
app.component("m-form-flex-layout", FlexLayout_default);
|
|
9398
|
-
app.component("m-fields-text", Text_default);
|
|
9399
|
-
app.component("m-fields-img-upload", Text_default);
|
|
9400
|
-
app.component("m-fields-number", Number_default);
|
|
9401
|
-
app.component("m-fields-number-range", NumberRange_default);
|
|
9402
|
-
app.component("m-fields-textarea", Textarea_default);
|
|
9403
|
-
app.component("m-fields-hidden", Hidden_default);
|
|
9404
|
-
app.component("m-fields-date", Date_default);
|
|
9405
|
-
app.component("m-fields-datetime", DateTime_default);
|
|
9406
|
-
app.component("m-fields-daterange", Daterange_default);
|
|
9407
|
-
app.component("m-fields-timerange", Timerange_default);
|
|
9408
|
-
app.component("m-fields-time", Time_default);
|
|
9409
|
-
app.component("m-fields-checkbox", Checkbox_default);
|
|
9410
|
-
app.component("m-fields-switch", Switch_default);
|
|
9411
|
-
app.component("m-fields-color-picker", ColorPicker_default);
|
|
9412
|
-
app.component("m-fields-checkbox-group", CheckboxGroup_default);
|
|
9413
|
-
app.component("m-fields-radio-group", RadioGroup_default);
|
|
9414
|
-
app.component("m-fields-display", Display_default);
|
|
9415
|
-
app.component("m-fields-link", Link_default);
|
|
9416
|
-
app.component("m-fields-select", Select_default);
|
|
9417
|
-
app.component("m-fields-cascader", Cascader_default);
|
|
9418
|
-
app.component("m-fields-dynamic-field", DynamicField_default);
|
|
9419
10547
|
} };
|
|
9420
10548
|
//#endregion
|
|
9421
10549
|
//#region packages/form/src/index.ts
|
|
9422
10550
|
var createForm = (config) => config;
|
|
9423
10551
|
//#endregion
|
|
10552
|
+
exports.FORM_CONTEXT_KEY = FORM_CONTEXT_KEY;
|
|
9424
10553
|
exports.FORM_DIFF_CONFIG_KEY = FORM_DIFF_CONFIG_KEY;
|
|
9425
|
-
exports.FORM_SILENT_MODE_KEY = FORM_SILENT_MODE_KEY;
|
|
9426
10554
|
exports.FORM_TYPE_MATCH_VALID_KEY = FORM_TYPE_MATCH_VALID_KEY;
|
|
10555
|
+
exports.FieldInnerConfigError = FieldInnerConfigError;
|
|
9427
10556
|
exports.MAX_SUGGESTION_OPTIONS = MAX_SUGGESTION_OPTIONS;
|
|
9428
10557
|
exports.MCascader = Cascader_default;
|
|
9429
10558
|
exports.MCheckbox = Checkbox_default;
|
|
9430
|
-
exports.MCheckboxGroup =
|
|
10559
|
+
exports.MCheckboxGroup = Index_default;
|
|
9431
10560
|
exports.MColorPicker = ColorPicker_default;
|
|
9432
10561
|
exports.MContainer = Container_default;
|
|
9433
|
-
exports.MDate =
|
|
9434
|
-
exports.MDateTime =
|
|
10562
|
+
exports.MDate = Index_default$1;
|
|
10563
|
+
exports.MDateTime = Index_default$2;
|
|
9435
10564
|
exports.MDaterange = Daterange_default;
|
|
9436
|
-
exports.MDisplay =
|
|
9437
|
-
exports.MDynamicField =
|
|
10565
|
+
exports.MDisplay = Index_default$3;
|
|
10566
|
+
exports.MDynamicField = Index_default$4;
|
|
9438
10567
|
exports.MFieldset = Fieldset_default;
|
|
9439
10568
|
exports.MFlexLayout = FlexLayout_default;
|
|
9440
10569
|
exports.MForm = Form_default;
|
|
@@ -9445,7 +10574,7 @@
|
|
|
9445
10574
|
exports.MHidden = Hidden_default;
|
|
9446
10575
|
exports.MLink = Link_default;
|
|
9447
10576
|
exports.MNumber = Number_default;
|
|
9448
|
-
exports.MNumberRange =
|
|
10577
|
+
exports.MNumberRange = Index_default$5;
|
|
9449
10578
|
exports.MPanel = Panel_default;
|
|
9450
10579
|
exports.MRadioGroup = RadioGroup_default;
|
|
9451
10580
|
exports.MRow = Row_default;
|
|
@@ -9459,37 +10588,52 @@
|
|
|
9459
10588
|
exports.MTime = Time_default;
|
|
9460
10589
|
exports.MTimerange = Timerange_default;
|
|
9461
10590
|
exports.adaptFormValidator = adaptFormValidator;
|
|
9462
|
-
exports.
|
|
9463
|
-
exports.
|
|
10591
|
+
exports.appendProp = appendProp;
|
|
10592
|
+
exports.applyMountValueEffects = applyMountValueEffects;
|
|
10593
|
+
exports.builtInFields = builtInFields;
|
|
10594
|
+
exports.clearFields = clearFields;
|
|
9464
10595
|
exports.clearTypeMatchRules = clearTypeMatchRules;
|
|
10596
|
+
exports.collectValidatableFields = collectValidatableFields;
|
|
9465
10597
|
exports.createForm = createForm;
|
|
10598
|
+
exports.createFormStateBase = createFormStateBase;
|
|
10599
|
+
exports.createFormStateProxy = createFormStateProxy;
|
|
10600
|
+
exports.createHeadlessFormState = createHeadlessFormState;
|
|
9466
10601
|
exports.createObjectProp = createObjectProp;
|
|
9467
10602
|
exports.createValues = createValues;
|
|
9468
10603
|
exports.datetimeFormatter = datetimeFormatter;
|
|
9469
10604
|
exports.default = plugin_default;
|
|
9470
|
-
exports.deleteFormField = deleteField;
|
|
9471
10605
|
exports.deleteTypeMatchRule = deleteTypeMatchRule;
|
|
9472
10606
|
exports.display = display;
|
|
9473
10607
|
exports.filterFunction = filterFunction;
|
|
10608
|
+
exports.formatValidateError = formatValidateError;
|
|
9474
10609
|
exports.getDataByPage = getDataByPage;
|
|
9475
10610
|
exports.getFormField = getField;
|
|
10611
|
+
exports.getItemProp = getItemProp;
|
|
10612
|
+
exports.getNativeRules = getNativeRules;
|
|
9476
10613
|
exports.getRules = getRules;
|
|
9477
|
-
exports.
|
|
10614
|
+
exports.getTextByName = getTextByName;
|
|
9478
10615
|
exports.getTypeMatchRule = getTypeMatchRule;
|
|
9479
10616
|
exports.initValue = initValue;
|
|
10617
|
+
exports.isFieldInnerConfigError = isFieldInnerConfigError;
|
|
10618
|
+
exports.isLeafFieldType = isLeafFieldType;
|
|
10619
|
+
exports.isValidName = isValidName;
|
|
10620
|
+
exports.mergeFieldOptions = mergeFieldOptions;
|
|
10621
|
+
exports.mergeFormContexts = mergeFormContexts;
|
|
9480
10622
|
exports.optionSuggestion = optionSuggestion;
|
|
9481
|
-
exports.
|
|
9482
|
-
exports.
|
|
9483
|
-
exports.
|
|
9484
|
-
exports.
|
|
10623
|
+
exports.registerBuiltInFields = registerBuiltInFields;
|
|
10624
|
+
exports.registerField = registerField;
|
|
10625
|
+
exports.registerFields = registerFields;
|
|
10626
|
+
exports.resolveItemType = resolveItemType;
|
|
9485
10627
|
exports.sortArray = sortArray;
|
|
9486
10628
|
exports.sortChange = sortChange;
|
|
9487
10629
|
exports.stringifyExampleValue = stringifyExampleValue;
|
|
9488
10630
|
exports.stripTabItemsLazy = stripTabItemsLazy;
|
|
9489
10631
|
exports.submitForm = submitForm;
|
|
10632
|
+
exports.unregisterField = unregisterField;
|
|
9490
10633
|
exports.useAddField = useAddField;
|
|
9491
10634
|
exports.validateForm = validateForm;
|
|
9492
10635
|
exports.validateTypeMatch = validateTypeMatch;
|
|
10636
|
+
exports.validateValues = validateValues;
|
|
9493
10637
|
var _tmagic_form_schema = require("@tmagic/form-schema");
|
|
9494
10638
|
Object.keys(_tmagic_form_schema).forEach(function(k) {
|
|
9495
10639
|
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|