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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/es/Form.vue_vue_type_script_setup_true_lang.js +2 -2
  2. package/dist/es/FormBox.vue_vue_type_script_setup_true_lang.js +5 -2
  3. package/dist/es/FormDialog.vue_vue_type_script_setup_true_lang.js +5 -2
  4. package/dist/es/FormDrawer.vue_vue_type_script_setup_true_lang.js +5 -2
  5. package/dist/es/containers/Container.vue_vue_type_script_setup_true_lang.js +2 -2
  6. package/dist/es/containers/table-group-list/useAdd.js +1 -1
  7. package/dist/es/fields/Cascader.vue_vue_type_script_setup_true_lang.js +1 -1
  8. package/dist/es/fields/CheckboxGroup.vue_vue_type_script_setup_true_lang.js +1 -1
  9. package/dist/es/fields/Date.vue_vue_type_script_setup_true_lang.js +1 -1
  10. package/dist/es/fields/DateTime.vue_vue_type_script_setup_true_lang.js +1 -1
  11. package/dist/es/fields/Daterange.vue_vue_type_script_setup_true_lang.js +1 -1
  12. package/dist/es/fields/Display.vue_vue_type_script_setup_true_lang.js +1 -1
  13. package/dist/es/fields/Select.vue_vue_type_script_setup_true_lang.js +26 -9
  14. package/dist/es/fields/Text.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/es/fields/Timerange.vue_vue_type_script_setup_true_lang.js +2 -2
  16. package/dist/es/index.js +3 -2
  17. package/dist/es/submitForm.js +87 -0
  18. package/dist/es/utils/form.js +2 -2
  19. package/dist/tmagic-form.umd.cjs +177 -66
  20. package/package.json +4 -4
  21. package/src/FormBox.vue +3 -1
  22. package/src/FormDialog.vue +4 -1
  23. package/src/FormDrawer.vue +4 -1
  24. package/src/containers/table-group-list/useAdd.ts +1 -1
  25. package/src/fields/Select.vue +35 -8
  26. package/src/index.ts +1 -0
  27. package/src/submitForm.ts +161 -0
  28. package/types/index.d.ts +91 -29
@@ -1,15 +1,15 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue"), require("dayjs"), require("dayjs/plugin/utc"), require("@tmagic/utils"), require("@tmagic/design"), require("@element-plus/icons-vue"), require("@popperjs/core")) : typeof define === "function" && define.amd ? define([
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue"), require("@tmagic/design"), require("@tmagic/utils"), require("@element-plus/icons-vue"), require("dayjs"), require("dayjs/plugin/utc"), require("@popperjs/core")) : typeof define === "function" && define.amd ? define([
3
3
  "exports",
4
4
  "vue",
5
- "dayjs",
6
- "dayjs/plugin/utc",
7
- "@tmagic/utils",
8
5
  "@tmagic/design",
6
+ "@tmagic/utils",
9
7
  "@element-plus/icons-vue",
8
+ "dayjs",
9
+ "dayjs/plugin/utc",
10
10
  "@popperjs/core"
11
- ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.TMagicForm = {}, global.Vue, global.dayjs, global.dayjs_plugin_utc, global._tmagic_utils, global._tmagic_design, global._element_plus_icons_vue, global._popperjs_core));
12
- })(this, function(exports, vue, dayjs, dayjs_plugin_utc, _tmagic_utils, _tmagic_design, _element_plus_icons_vue, _popperjs_core) {
11
+ ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.TMagicForm = {}, global.Vue, global._tmagic_design, global._tmagic_utils, global._element_plus_icons_vue, global.dayjs, global.dayjs_plugin_utc, global._popperjs_core));
12
+ })(this, function(exports, vue, _tmagic_design, _tmagic_utils, _element_plus_icons_vue, dayjs, dayjs_plugin_utc, _popperjs_core) {
13
13
  Object.defineProperties(exports, {
14
14
  __esModule: { value: true },
15
15
  [Symbol.toStringTag]: { value: "Module" }
@@ -2617,6 +2617,52 @@
2617
2617
  return baseIsEqual(value, other);
2618
2618
  }
2619
2619
  //#endregion
2620
+ //#region packages/form/src/utils/useAddField.ts
2621
+ var useAddField = (prop) => {
2622
+ if (!prop) return;
2623
+ const mForm = (0, vue.inject)("mForm");
2624
+ const instance = (0, vue.getCurrentInstance)();
2625
+ (0, vue.watch)(() => instance?.proxy, (vm) => {
2626
+ if (vm) mForm?.setField(prop, vm);
2627
+ else mForm?.deleteField(prop);
2628
+ }, { immediate: true });
2629
+ };
2630
+ //#endregion
2631
+ //#region packages/form/src/fields/Hidden.vue
2632
+ var Hidden_default = /* @__PURE__ */ (0, vue.defineComponent)({
2633
+ name: "MFormHidden",
2634
+ __name: "Hidden",
2635
+ props: {
2636
+ model: {},
2637
+ name: {},
2638
+ prop: {}
2639
+ },
2640
+ setup(__props) {
2641
+ useAddField(__props.prop);
2642
+ return (_ctx, _cache) => {
2643
+ return __props.model ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
2644
+ key: 0,
2645
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => __props.model[__props.name] = $event),
2646
+ type: "hidden"
2647
+ }, null, 512)), [[vue.vModelText, __props.model[__props.name]]]) : (0, vue.createCommentVNode)("v-if", true);
2648
+ };
2649
+ }
2650
+ });
2651
+ //#endregion
2652
+ //#region packages/form/src/utils/config.ts
2653
+ var $MAGIC_FORM = {};
2654
+ var setConfig = (option) => {
2655
+ $MAGIC_FORM = option;
2656
+ };
2657
+ var getConfig = (key) => $MAGIC_FORM[key];
2658
+ var fieldRegistry = /* @__PURE__ */ new Map();
2659
+ var registerField = (tagName, component) => {
2660
+ if (fieldRegistry.has(tagName)) return;
2661
+ fieldRegistry.set(tagName, component);
2662
+ };
2663
+ var getField = (tagName) => fieldRegistry.get(tagName);
2664
+ var deleteField = (tagName) => fieldRegistry.delete(tagName);
2665
+ //#endregion
2620
2666
  //#region packages/form/src/utils/form.ts
2621
2667
  var TABLE_SELECT_TYPES = new Set(["table-select", "tableSelect"]);
2622
2668
  var isTableSelect = (type) => typeof type === "string" && TABLE_SELECT_TYPES.has(type);
@@ -2786,52 +2832,6 @@
2786
2832
  return `${[...itemPath, key].join(".")}`;
2787
2833
  };
2788
2834
  //#endregion
2789
- //#region packages/form/src/utils/useAddField.ts
2790
- var useAddField = (prop) => {
2791
- if (!prop) return;
2792
- const mForm = (0, vue.inject)("mForm");
2793
- const instance = (0, vue.getCurrentInstance)();
2794
- (0, vue.watch)(() => instance?.proxy, (vm) => {
2795
- if (vm) mForm?.setField(prop, vm);
2796
- else mForm?.deleteField(prop);
2797
- }, { immediate: true });
2798
- };
2799
- //#endregion
2800
- //#region packages/form/src/fields/Hidden.vue
2801
- var Hidden_default = /* @__PURE__ */ (0, vue.defineComponent)({
2802
- name: "MFormHidden",
2803
- __name: "Hidden",
2804
- props: {
2805
- model: {},
2806
- name: {},
2807
- prop: {}
2808
- },
2809
- setup(__props) {
2810
- useAddField(__props.prop);
2811
- return (_ctx, _cache) => {
2812
- return __props.model ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
2813
- key: 0,
2814
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => __props.model[__props.name] = $event),
2815
- type: "hidden"
2816
- }, null, 512)), [[vue.vModelText, __props.model[__props.name]]]) : (0, vue.createCommentVNode)("v-if", true);
2817
- };
2818
- }
2819
- });
2820
- //#endregion
2821
- //#region packages/form/src/utils/config.ts
2822
- var $MAGIC_FORM = {};
2823
- var setConfig = (option) => {
2824
- $MAGIC_FORM = option;
2825
- };
2826
- var getConfig = (key) => $MAGIC_FORM[key];
2827
- var fieldRegistry = /* @__PURE__ */ new Map();
2828
- var registerField = (tagName, component) => {
2829
- if (fieldRegistry.has(tagName)) return;
2830
- fieldRegistry.set(tagName, component);
2831
- };
2832
- var getField = (tagName) => fieldRegistry.get(tagName);
2833
- var deleteField = (tagName) => fieldRegistry.delete(tagName);
2834
- //#endregion
2835
2835
  //#region packages/form/src/containers/FormLabel.vue?vue&type=script&setup=true&lang.ts
2836
2836
  var _hoisted_1$15 = {
2837
2837
  key: 0,
@@ -3537,6 +3537,90 @@
3537
3537
  }
3538
3538
  });
3539
3539
  //#endregion
3540
+ //#region packages/form/src/submitForm.ts
3541
+ /**
3542
+ * 以命令式方式调用 Form.vue 完成一次表单校验/提交。
3543
+ *
3544
+ * 类似 ElMessage 的用法:传入 props(包含 `config`/`initValues` 等),函数内部会临时挂载
3545
+ * 一个不可见的 Form 组件实例,等待初始化完成后调用其 `submitForm` 方法,
3546
+ * 校验通过则 resolve 表单值,校验失败则 reject 错误信息,最后自动卸载实例。
3547
+ *
3548
+ * @example
3549
+ * ```ts
3550
+ * import { submitForm } from '@tmagic/form';
3551
+ *
3552
+ * try {
3553
+ * const values = await submitForm({
3554
+ * config: [...],
3555
+ * initValues: { name: 'foo' },
3556
+ * });
3557
+ * console.log(values);
3558
+ * } catch (e) {
3559
+ * console.error(e);
3560
+ * }
3561
+ * ```
3562
+ */
3563
+ var submitForm = (options) => {
3564
+ const { native, appContext, timeout = 1e4, ...formProps } = options;
3565
+ return new Promise((resolve, reject) => {
3566
+ const container = document.createElement("div");
3567
+ container.style.display = "none";
3568
+ document.body.appendChild(container);
3569
+ let cleaned = false;
3570
+ let timer = null;
3571
+ const app = (0, vue.createApp)((0, vue.defineComponent)({
3572
+ name: "MFormSubmitWrapper",
3573
+ setup() {
3574
+ const formRef = (0, vue.ref)(null);
3575
+ const stop = (0, vue.watch)(() => formRef.value?.initialized, async (initialized) => {
3576
+ if (!initialized) return;
3577
+ stop();
3578
+ try {
3579
+ await (0, vue.nextTick)();
3580
+ resolve(await formRef.value.submitForm(native));
3581
+ } catch (err) {
3582
+ reject(err);
3583
+ } finally {
3584
+ cleanup();
3585
+ }
3586
+ }, {
3587
+ flush: "post",
3588
+ immediate: true
3589
+ });
3590
+ return () => (0, vue.h)(Form_default, {
3591
+ ...formProps,
3592
+ ref: formRef
3593
+ });
3594
+ }
3595
+ }));
3596
+ if (appContext) Object.assign(app._context, appContext);
3597
+ const cleanup = () => {
3598
+ if (cleaned) return;
3599
+ cleaned = true;
3600
+ if (timer) {
3601
+ clearTimeout(timer);
3602
+ timer = null;
3603
+ }
3604
+ try {
3605
+ app.unmount();
3606
+ } catch {}
3607
+ container.parentNode?.removeChild(container);
3608
+ };
3609
+ if (timeout > 0) timer = setTimeout(() => {
3610
+ if (!cleaned) {
3611
+ reject(/* @__PURE__ */ new Error(`submitForm timeout after ${timeout}ms: form is not initialized.`));
3612
+ cleanup();
3613
+ }
3614
+ }, timeout);
3615
+ try {
3616
+ app.mount(container);
3617
+ } catch (err) {
3618
+ reject(err);
3619
+ cleanup();
3620
+ }
3621
+ });
3622
+ };
3623
+ //#endregion
3540
3624
  //#region packages/form/src/FormDialog.vue?vue&type=script&setup=true&lang.ts
3541
3625
  var _hoisted_1$13 = { style: { "min-height": "1px" } };
3542
3626
  //#endregion
@@ -3578,7 +3662,8 @@
3578
3662
  showCancel: {
3579
3663
  type: Boolean,
3580
3664
  default: true
3581
- }
3665
+ },
3666
+ extendState: {}
3582
3667
  },
3583
3668
  emits: [
3584
3669
  "close",
@@ -3728,6 +3813,7 @@
3728
3813
  "label-position": __props.labelPosition,
3729
3814
  inline: __props.inline,
3730
3815
  "prevent-submit-default": __props.preventSubmitDefault,
3816
+ "extend-state": __props.extendState,
3731
3817
  onChange: changeHandler
3732
3818
  }, null, 8, [
3733
3819
  "modelValue",
@@ -3739,7 +3825,8 @@
3739
3825
  "label-width",
3740
3826
  "label-position",
3741
3827
  "inline",
3742
- "prevent-submit-default"
3828
+ "prevent-submit-default",
3829
+ "extend-state"
3743
3830
  ]), (0, vue.renderSlot)(_ctx.$slots, "default")], 4)) : (0, vue.createCommentVNode)("v-if", true)]),
3744
3831
  _: 3
3745
3832
  }, 8, [
@@ -3782,7 +3869,8 @@
3782
3869
  inline: { type: Boolean },
3783
3870
  labelPosition: {},
3784
3871
  preventSubmitDefault: { type: Boolean },
3785
- beforeClose: {}
3872
+ beforeClose: {},
3873
+ extendState: {}
3786
3874
  },
3787
3875
  emits: [
3788
3876
  "close",
@@ -3906,6 +3994,7 @@
3906
3994
  "label-position": __props.labelPosition,
3907
3995
  inline: __props.inline,
3908
3996
  "prevent-submit-default": __props.preventSubmitDefault,
3997
+ "extend-state": __props.extendState,
3909
3998
  onChange: changeHandler
3910
3999
  }, null, 8, [
3911
4000
  "size",
@@ -3916,7 +4005,8 @@
3916
4005
  "label-width",
3917
4006
  "label-position",
3918
4007
  "inline",
3919
- "prevent-submit-default"
4008
+ "prevent-submit-default",
4009
+ "extend-state"
3920
4010
  ]), (0, vue.renderSlot)(_ctx.$slots, "default")], 512)) : (0, vue.createCommentVNode)("v-if", true)]),
3921
4011
  _: 3
3922
4012
  }, 8, [
@@ -3950,7 +4040,8 @@
3950
4040
  confirmText: { default: "确定" },
3951
4041
  inline: { type: Boolean },
3952
4042
  labelPosition: {},
3953
- preventSubmitDefault: { type: Boolean }
4043
+ preventSubmitDefault: { type: Boolean },
4044
+ extendState: {}
3954
4045
  },
3955
4046
  emits: [
3956
4047
  "change",
@@ -4012,6 +4103,7 @@
4012
4103
  "label-position": __props.labelPosition,
4013
4104
  inline: __props.inline,
4014
4105
  "prevent-submit-default": __props.preventSubmitDefault,
4106
+ "extend-state": __props.extendState,
4015
4107
  onChange: changeHandler
4016
4108
  }, null, 8, [
4017
4109
  "size",
@@ -4022,7 +4114,8 @@
4022
4114
  "label-width",
4023
4115
  "label-position",
4024
4116
  "inline",
4025
- "prevent-submit-default"
4117
+ "prevent-submit-default",
4118
+ "extend-state"
4026
4119
  ]), (0, vue.renderSlot)(_ctx.$slots, "default")]),
4027
4120
  _: 3
4028
4121
  })], 4), (0, vue.createElementVNode)("div", {
@@ -5666,7 +5759,7 @@
5666
5759
  const addable = (0, vue.computed)(() => {
5667
5760
  const modelName = props.name || props.config.name || "";
5668
5761
  if (!modelName) return false;
5669
- if (!props.model[modelName].length) return true;
5762
+ if (!props.model[modelName]?.length) return true;
5670
5763
  if (typeof props.config.addable === "function") return props.config.addable(mForm, {
5671
5764
  model: props.model[modelName],
5672
5765
  formValue: mForm?.values,
@@ -7078,6 +7171,18 @@
7078
7171
  }
7079
7172
  return value === v;
7080
7173
  };
7174
+ const hasOption = (value) => {
7175
+ const { config } = props;
7176
+ if (Array.isArray(value) && !value.length) return true;
7177
+ if (config.group) {
7178
+ const groups = options.value;
7179
+ if (config.multiple && Array.isArray(value)) return value.every((v) => groups.some((group) => group.options.some((item) => equalValue(item.value, v))));
7180
+ return groups.some((group) => group.options.some((item) => equalValue(item.value, value)));
7181
+ }
7182
+ const opts = options.value;
7183
+ if (config.multiple && Array.isArray(value)) return value.every((v) => opts.some((item) => equalValue(item.value, v)));
7184
+ return opts.some((item) => equalValue(item.value, value));
7185
+ };
7081
7186
  const mapOptions = (data) => {
7082
7187
  const { option = {
7083
7188
  text: "text",
@@ -7240,13 +7345,18 @@
7240
7345
  else if (Array.isArray(props.config.options)) (0, vue.watchEffect)(() => {
7241
7346
  setOptions(props.config.options);
7242
7347
  });
7243
- else if (props.config.option) (0, vue.onBeforeMount)(() => {
7244
- if (!props.model) return;
7245
- const v = props.model[props.name];
7246
- if (Array.isArray(v) ? v.length : typeof v !== "undefined") getInitOption().then((data) => {
7247
- setOptions(data);
7248
- });
7249
- });
7348
+ else if (props.config.option) {
7349
+ const initOption = async () => {
7350
+ if (!props.model) return;
7351
+ const v = props.model[props.name];
7352
+ if (Array.isArray(v) ? !v.length : typeof v === "undefined") return;
7353
+ if (typeof v === "undefined" || hasOption(v)) return;
7354
+ setOptions(await getInitOption());
7355
+ };
7356
+ (0, vue.watch)(() => props.model?.[props.name], () => {
7357
+ initOption();
7358
+ }, { immediate: true });
7359
+ }
7250
7360
  if (props.config.remote) {
7251
7361
  const unWatch = (0, vue.watch)(() => tMagicSelect.value?.scrollbarWrap, (scrollbarWrap) => {
7252
7362
  if (!scrollbarWrap) return;
@@ -7741,6 +7851,7 @@
7741
7851
  exports.registerFormField = registerField;
7742
7852
  exports.sortArray = sortArray;
7743
7853
  exports.sortChange = sortChange;
7854
+ exports.submitForm = submitForm;
7744
7855
  exports.useAddField = useAddField;
7745
7856
  var _tmagic_form_schema = require("@tmagic/form-schema");
7746
7857
  Object.keys(_tmagic_form_schema).forEach(function(k) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.14-beta.2",
2
+ "version": "1.8.0-beta.0",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -52,9 +52,9 @@
52
52
  "peerDependencies": {
53
53
  "vue": "^3.5.34",
54
54
  "typescript": "^6.0.3",
55
- "@tmagic/design": "1.7.14-beta.2",
56
- "@tmagic/utils": "1.7.14-beta.2",
57
- "@tmagic/form-schema": "1.7.14-beta.2"
55
+ "@tmagic/utils": "1.8.0-beta.0",
56
+ "@tmagic/design": "1.8.0-beta.0",
57
+ "@tmagic/form-schema": "1.8.0-beta.0"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "typescript": {
package/src/FormBox.vue CHANGED
@@ -13,6 +13,7 @@
13
13
  :label-position="labelPosition"
14
14
  :inline="inline"
15
15
  :prevent-submit-default="preventSubmitDefault"
16
+ :extend-state="extendState"
16
17
  @change="changeHandler"
17
18
  ></Form>
18
19
  <slot></slot>
@@ -40,7 +41,7 @@ import { computed, ref, watchEffect } from 'vue';
40
41
  import { TMagicButton, TMagicScrollbar } from '@tmagic/design';
41
42
 
42
43
  import Form from './Form.vue';
43
- import type { ContainerChangeEventData, FormConfig, FormValue } from './schema';
44
+ import type { ContainerChangeEventData, FormConfig, FormState, FormValue } from './schema';
44
45
 
45
46
  defineOptions({
46
47
  name: 'MFormBox',
@@ -60,6 +61,7 @@ const props = withDefaults(
60
61
  inline?: boolean;
61
62
  labelPosition?: string;
62
63
  preventSubmitDefault?: boolean;
64
+ extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
63
65
  }>(),
64
66
  {
65
67
  config: () => [],
@@ -31,6 +31,7 @@
31
31
  :label-position="labelPosition"
32
32
  :inline="inline"
33
33
  :prevent-submit-default="preventSubmitDefault"
34
+ :extend-state="extendState"
34
35
  @change="changeHandler"
35
36
  ></Form>
36
37
  <slot></slot>
@@ -68,7 +69,7 @@ import { computed, ref } from 'vue';
68
69
  import { TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
69
70
 
70
71
  import Form from './Form.vue';
71
- import { ContainerChangeEventData, FormConfig, FormValue, StepConfig } from './schema';
72
+ import { ContainerChangeEventData, FormConfig, FormState, FormValue, StepConfig } from './schema';
72
73
 
73
74
  defineOptions({
74
75
  name: 'MFormDialog',
@@ -95,6 +96,8 @@ const props = withDefaults(
95
96
  destroyOnClose?: boolean;
96
97
  showClose?: boolean;
97
98
  showCancel?: boolean;
99
+ /** 透传给内部 `MForm`,用于扩展 `formState`(如注入 `$message` / `$store` 等) */
100
+ extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
98
101
  }>(),
99
102
  {
100
103
  config: () => [],
@@ -28,6 +28,7 @@
28
28
  :label-position="labelPosition"
29
29
  :inline="inline"
30
30
  :prevent-submit-default="preventSubmitDefault"
31
+ :extend-state="extendState"
31
32
  @change="changeHandler"
32
33
  ></Form>
33
34
  <slot></slot>
@@ -59,7 +60,7 @@ import { ref, watchEffect } from 'vue';
59
60
  import { TMagicButton, TMagicCol, TMagicDrawer, TMagicRow } from '@tmagic/design';
60
61
 
61
62
  import Form from './Form.vue';
62
- import type { ContainerChangeEventData, FormConfig, FormValue } from './schema';
63
+ import type { ContainerChangeEventData, FormConfig, FormState, FormValue } from './schema';
63
64
 
64
65
  defineOptions({
65
66
  name: 'MFormDialog',
@@ -83,6 +84,8 @@ withDefaults(
83
84
  preventSubmitDefault?: boolean;
84
85
  /** 关闭前的回调,会暂停 Drawer 的关闭; done 是个 function type 接受一个 boolean 参数, 执行 done 使用 true 参数或不提供参数将会终止关闭 */
85
86
  beforeClose?: (_done: (_cancel?: boolean) => void) => void;
87
+ /** 透传给内部 `MForm`,用于扩展 `formState`(如注入 `$message` / `$store` 等) */
88
+ extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
86
89
  }>(),
87
90
  {
88
91
  closeOnPressEscape: true,
@@ -22,7 +22,7 @@ export const useAdd = (
22
22
 
23
23
  if (!modelName) return false;
24
24
 
25
- if (!props.model[modelName].length) {
25
+ if (!props.model[modelName]?.length) {
26
26
  return true;
27
27
  }
28
28
 
@@ -78,7 +78,7 @@
78
78
  </template>
79
79
 
80
80
  <script lang="ts" setup>
81
- import { inject, nextTick, onBeforeMount, ref, watch, watchEffect } from 'vue';
81
+ import { inject, nextTick, ref, watch, watchEffect } from 'vue';
82
82
 
83
83
  import { getDesignConfig, TMagicSelect } from '@tmagic/design';
84
84
  import { getValueByKeyPath } from '@tmagic/utils';
@@ -123,6 +123,26 @@ const equalValue = (value: any, v: any): boolean => {
123
123
  return value === v;
124
124
  };
125
125
 
126
+ const hasOption = (value: any): boolean => {
127
+ const { config } = props;
128
+
129
+ if (Array.isArray(value) && !value.length) return true;
130
+
131
+ if (config.group) {
132
+ const groups = options.value as SelectGroupOption[];
133
+ if (config.multiple && Array.isArray(value)) {
134
+ return value.every((v) => groups.some((group) => group.options.some((item) => equalValue(item.value, v))));
135
+ }
136
+ return groups.some((group) => group.options.some((item) => equalValue(item.value, value)));
137
+ }
138
+
139
+ const opts = options.value as SelectOption[];
140
+ if (config.multiple && Array.isArray(value)) {
141
+ return value.every((v) => opts.some((item) => equalValue(item.value, v)));
142
+ }
143
+ return opts.some((item) => equalValue(item.value, value));
144
+ };
145
+
126
146
  const mapOptions = (data: any[]) => {
127
147
  const {
128
148
  option = {
@@ -392,15 +412,22 @@ if (typeof props.config.options === 'function') {
392
412
  setOptions(props.config.options as SelectOption[] | SelectGroupOption[]);
393
413
  });
394
414
  } else if (props.config.option) {
395
- onBeforeMount(() => {
415
+ const initOption = async () => {
396
416
  if (!props.model) return;
397
417
  const v = props.model[props.name];
398
- if (Array.isArray(v) ? v.length : typeof v !== 'undefined') {
399
- getInitOption().then((data) => {
400
- setOptions(data);
401
- });
402
- }
403
- });
418
+ if (Array.isArray(v) ? !v.length : typeof v === 'undefined') return;
419
+ if (typeof v === 'undefined' || hasOption(v)) return;
420
+ const data = await getInitOption();
421
+ setOptions(data);
422
+ };
423
+
424
+ watch(
425
+ () => props.model?.[props.name],
426
+ () => {
427
+ void initOption();
428
+ },
429
+ { immediate: true },
430
+ );
404
431
  }
405
432
 
406
433
  if (props.config.remote) {
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@
19
19
  import type { FormConfig } from './schema';
20
20
 
21
21
  export * from './schema';
22
+ export * from './submitForm';
22
23
  export * from './utils/form';
23
24
  export * from './utils/useAddField';
24
25