@tmagic/form 1.8.0-beta.10 → 1.8.0-beta.11
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/submitForm.js +99 -8
- package/dist/tmagic-form.umd.cjs +99 -8
- package/package.json +4 -4
- package/src/submitForm.ts +166 -17
- package/types/index.d.ts +16 -0
package/dist/es/submitForm.js
CHANGED
|
@@ -28,13 +28,20 @@ import { createApp, defineComponent, h, nextTick, ref, watch } from "vue";
|
|
|
28
28
|
* initValues: { name: 'foo' },
|
|
29
29
|
* returnChangeRecords: true,
|
|
30
30
|
* });
|
|
31
|
+
*
|
|
32
|
+
* // 调试模式:可见地渲染表单,点击「确定」才提交:
|
|
33
|
+
* const values = await submitForm({
|
|
34
|
+
* config: [...],
|
|
35
|
+
* initValues: { name: 'foo' },
|
|
36
|
+
* debug: true,
|
|
37
|
+
* });
|
|
31
38
|
* ```
|
|
32
39
|
*/
|
|
33
40
|
var submitForm = (options) => {
|
|
34
|
-
const { native, appContext, timeout = 1e4, returnChangeRecords, ...formProps } = options;
|
|
41
|
+
const { native, appContext, timeout = 1e4, returnChangeRecords, debug = false, ...formProps } = options;
|
|
35
42
|
return new Promise((resolve, reject) => {
|
|
36
43
|
const container = document.createElement("div");
|
|
37
|
-
container.style.display = "none";
|
|
44
|
+
if (!debug) container.style.display = "none";
|
|
38
45
|
document.body.appendChild(container);
|
|
39
46
|
let cleaned = false;
|
|
40
47
|
let timer = null;
|
|
@@ -42,22 +49,106 @@ var submitForm = (options) => {
|
|
|
42
49
|
name: "MFormSubmitWrapper",
|
|
43
50
|
setup() {
|
|
44
51
|
const formRef = ref(null);
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
stop();
|
|
52
|
+
const errorMsg = ref("");
|
|
53
|
+
const doSubmit = async () => {
|
|
48
54
|
try {
|
|
49
55
|
await nextTick();
|
|
50
|
-
const changeRecords = [...formRef.value
|
|
56
|
+
const changeRecords = [...formRef.value?.changeRecords ?? []];
|
|
51
57
|
const result = await formRef.value.submitForm(native);
|
|
52
58
|
resolve(returnChangeRecords ? {
|
|
53
59
|
values: result,
|
|
54
60
|
changeRecords
|
|
55
61
|
} : result);
|
|
62
|
+
cleanup();
|
|
56
63
|
} catch (err) {
|
|
64
|
+
if (debug) {
|
|
65
|
+
errorMsg.value = err instanceof Error ? err.message : String(err);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
57
68
|
reject(err);
|
|
58
|
-
} finally {
|
|
59
69
|
cleanup();
|
|
60
70
|
}
|
|
71
|
+
};
|
|
72
|
+
if (debug) {
|
|
73
|
+
const handleCancel = () => {
|
|
74
|
+
reject(/* @__PURE__ */ new Error("submitForm canceled in debug mode."));
|
|
75
|
+
cleanup();
|
|
76
|
+
};
|
|
77
|
+
const btnBase = {
|
|
78
|
+
padding: "8px 20px",
|
|
79
|
+
fontSize: "14px",
|
|
80
|
+
lineHeight: "1",
|
|
81
|
+
border: "1px solid #dcdfe6",
|
|
82
|
+
borderRadius: "4px",
|
|
83
|
+
cursor: "pointer"
|
|
84
|
+
};
|
|
85
|
+
return () => h("div", { style: {
|
|
86
|
+
position: "fixed",
|
|
87
|
+
inset: "0",
|
|
88
|
+
zIndex: "10000",
|
|
89
|
+
display: "flex",
|
|
90
|
+
alignItems: "center",
|
|
91
|
+
justifyContent: "center",
|
|
92
|
+
background: "rgba(0, 0, 0, 0.5)"
|
|
93
|
+
} }, [h("div", { style: {
|
|
94
|
+
display: "flex",
|
|
95
|
+
flexDirection: "column",
|
|
96
|
+
width: "600px",
|
|
97
|
+
maxWidth: "90vw",
|
|
98
|
+
maxHeight: "85vh",
|
|
99
|
+
background: "#fff",
|
|
100
|
+
borderRadius: "8px",
|
|
101
|
+
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.2)",
|
|
102
|
+
overflow: "hidden"
|
|
103
|
+
} }, [
|
|
104
|
+
h("div", { style: {
|
|
105
|
+
padding: "16px 20px",
|
|
106
|
+
fontSize: "16px",
|
|
107
|
+
fontWeight: "600",
|
|
108
|
+
borderBottom: "1px solid #ebeef5"
|
|
109
|
+
} }, "submitForm 调试"),
|
|
110
|
+
h("div", { style: {
|
|
111
|
+
flex: "1",
|
|
112
|
+
padding: "20px",
|
|
113
|
+
overflow: "auto"
|
|
114
|
+
} }, [h(Form_default, {
|
|
115
|
+
...formProps,
|
|
116
|
+
ref: formRef
|
|
117
|
+
}), errorMsg.value ? h("div", {
|
|
118
|
+
style: {
|
|
119
|
+
marginTop: "12px",
|
|
120
|
+
color: "#f56c6c",
|
|
121
|
+
fontSize: "13px",
|
|
122
|
+
lineHeight: "1.5"
|
|
123
|
+
},
|
|
124
|
+
innerHTML: errorMsg.value
|
|
125
|
+
}) : null]),
|
|
126
|
+
h("div", { style: {
|
|
127
|
+
display: "flex",
|
|
128
|
+
justifyContent: "flex-end",
|
|
129
|
+
gap: "12px",
|
|
130
|
+
padding: "12px 20px",
|
|
131
|
+
borderTop: "1px solid #ebeef5"
|
|
132
|
+
} }, [h("button", {
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: handleCancel,
|
|
135
|
+
style: { ...btnBase }
|
|
136
|
+
}, "取消"), h("button", {
|
|
137
|
+
type: "button",
|
|
138
|
+
onClick: doSubmit,
|
|
139
|
+
style: {
|
|
140
|
+
...btnBase,
|
|
141
|
+
color: "#fff",
|
|
142
|
+
background: "#409eff",
|
|
143
|
+
borderColor: "#409eff"
|
|
144
|
+
}
|
|
145
|
+
}, "确定")])
|
|
146
|
+
])]);
|
|
147
|
+
}
|
|
148
|
+
const stop = watch(() => formRef.value?.initialized, (initialized) => {
|
|
149
|
+
if (!initialized) return;
|
|
150
|
+
stop();
|
|
151
|
+
doSubmit();
|
|
61
152
|
}, {
|
|
62
153
|
flush: "post",
|
|
63
154
|
immediate: true
|
|
@@ -81,7 +172,7 @@ var submitForm = (options) => {
|
|
|
81
172
|
} catch {}
|
|
82
173
|
container.parentNode?.removeChild(container);
|
|
83
174
|
};
|
|
84
|
-
if (timeout > 0) timer = setTimeout(() => {
|
|
175
|
+
if (timeout > 0 && !debug) timer = setTimeout(() => {
|
|
85
176
|
if (!cleaned) {
|
|
86
177
|
reject(/* @__PURE__ */ new Error(`submitForm timeout after ${timeout}ms: form is not initialized.`));
|
|
87
178
|
cleanup();
|
package/dist/tmagic-form.umd.cjs
CHANGED
|
@@ -3760,13 +3760,20 @@
|
|
|
3760
3760
|
* initValues: { name: 'foo' },
|
|
3761
3761
|
* returnChangeRecords: true,
|
|
3762
3762
|
* });
|
|
3763
|
+
*
|
|
3764
|
+
* // 调试模式:可见地渲染表单,点击「确定」才提交:
|
|
3765
|
+
* const values = await submitForm({
|
|
3766
|
+
* config: [...],
|
|
3767
|
+
* initValues: { name: 'foo' },
|
|
3768
|
+
* debug: true,
|
|
3769
|
+
* });
|
|
3763
3770
|
* ```
|
|
3764
3771
|
*/
|
|
3765
3772
|
var submitForm = (options) => {
|
|
3766
|
-
const { native, appContext, timeout = 1e4, returnChangeRecords, ...formProps } = options;
|
|
3773
|
+
const { native, appContext, timeout = 1e4, returnChangeRecords, debug = false, ...formProps } = options;
|
|
3767
3774
|
return new Promise((resolve, reject) => {
|
|
3768
3775
|
const container = document.createElement("div");
|
|
3769
|
-
container.style.display = "none";
|
|
3776
|
+
if (!debug) container.style.display = "none";
|
|
3770
3777
|
document.body.appendChild(container);
|
|
3771
3778
|
let cleaned = false;
|
|
3772
3779
|
let timer = null;
|
|
@@ -3774,22 +3781,106 @@
|
|
|
3774
3781
|
name: "MFormSubmitWrapper",
|
|
3775
3782
|
setup() {
|
|
3776
3783
|
const formRef = (0, vue.ref)(null);
|
|
3777
|
-
const
|
|
3778
|
-
|
|
3779
|
-
stop();
|
|
3784
|
+
const errorMsg = (0, vue.ref)("");
|
|
3785
|
+
const doSubmit = async () => {
|
|
3780
3786
|
try {
|
|
3781
3787
|
await (0, vue.nextTick)();
|
|
3782
|
-
const changeRecords = [...formRef.value
|
|
3788
|
+
const changeRecords = [...formRef.value?.changeRecords ?? []];
|
|
3783
3789
|
const result = await formRef.value.submitForm(native);
|
|
3784
3790
|
resolve(returnChangeRecords ? {
|
|
3785
3791
|
values: result,
|
|
3786
3792
|
changeRecords
|
|
3787
3793
|
} : result);
|
|
3794
|
+
cleanup();
|
|
3788
3795
|
} catch (err) {
|
|
3796
|
+
if (debug) {
|
|
3797
|
+
errorMsg.value = err instanceof Error ? err.message : String(err);
|
|
3798
|
+
return;
|
|
3799
|
+
}
|
|
3789
3800
|
reject(err);
|
|
3790
|
-
} finally {
|
|
3791
3801
|
cleanup();
|
|
3792
3802
|
}
|
|
3803
|
+
};
|
|
3804
|
+
if (debug) {
|
|
3805
|
+
const handleCancel = () => {
|
|
3806
|
+
reject(/* @__PURE__ */ new Error("submitForm canceled in debug mode."));
|
|
3807
|
+
cleanup();
|
|
3808
|
+
};
|
|
3809
|
+
const btnBase = {
|
|
3810
|
+
padding: "8px 20px",
|
|
3811
|
+
fontSize: "14px",
|
|
3812
|
+
lineHeight: "1",
|
|
3813
|
+
border: "1px solid #dcdfe6",
|
|
3814
|
+
borderRadius: "4px",
|
|
3815
|
+
cursor: "pointer"
|
|
3816
|
+
};
|
|
3817
|
+
return () => (0, vue.h)("div", { style: {
|
|
3818
|
+
position: "fixed",
|
|
3819
|
+
inset: "0",
|
|
3820
|
+
zIndex: "10000",
|
|
3821
|
+
display: "flex",
|
|
3822
|
+
alignItems: "center",
|
|
3823
|
+
justifyContent: "center",
|
|
3824
|
+
background: "rgba(0, 0, 0, 0.5)"
|
|
3825
|
+
} }, [(0, vue.h)("div", { style: {
|
|
3826
|
+
display: "flex",
|
|
3827
|
+
flexDirection: "column",
|
|
3828
|
+
width: "600px",
|
|
3829
|
+
maxWidth: "90vw",
|
|
3830
|
+
maxHeight: "85vh",
|
|
3831
|
+
background: "#fff",
|
|
3832
|
+
borderRadius: "8px",
|
|
3833
|
+
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.2)",
|
|
3834
|
+
overflow: "hidden"
|
|
3835
|
+
} }, [
|
|
3836
|
+
(0, vue.h)("div", { style: {
|
|
3837
|
+
padding: "16px 20px",
|
|
3838
|
+
fontSize: "16px",
|
|
3839
|
+
fontWeight: "600",
|
|
3840
|
+
borderBottom: "1px solid #ebeef5"
|
|
3841
|
+
} }, "submitForm 调试"),
|
|
3842
|
+
(0, vue.h)("div", { style: {
|
|
3843
|
+
flex: "1",
|
|
3844
|
+
padding: "20px",
|
|
3845
|
+
overflow: "auto"
|
|
3846
|
+
} }, [(0, vue.h)(Form_default, {
|
|
3847
|
+
...formProps,
|
|
3848
|
+
ref: formRef
|
|
3849
|
+
}), errorMsg.value ? (0, vue.h)("div", {
|
|
3850
|
+
style: {
|
|
3851
|
+
marginTop: "12px",
|
|
3852
|
+
color: "#f56c6c",
|
|
3853
|
+
fontSize: "13px",
|
|
3854
|
+
lineHeight: "1.5"
|
|
3855
|
+
},
|
|
3856
|
+
innerHTML: errorMsg.value
|
|
3857
|
+
}) : null]),
|
|
3858
|
+
(0, vue.h)("div", { style: {
|
|
3859
|
+
display: "flex",
|
|
3860
|
+
justifyContent: "flex-end",
|
|
3861
|
+
gap: "12px",
|
|
3862
|
+
padding: "12px 20px",
|
|
3863
|
+
borderTop: "1px solid #ebeef5"
|
|
3864
|
+
} }, [(0, vue.h)("button", {
|
|
3865
|
+
type: "button",
|
|
3866
|
+
onClick: handleCancel,
|
|
3867
|
+
style: { ...btnBase }
|
|
3868
|
+
}, "取消"), (0, vue.h)("button", {
|
|
3869
|
+
type: "button",
|
|
3870
|
+
onClick: doSubmit,
|
|
3871
|
+
style: {
|
|
3872
|
+
...btnBase,
|
|
3873
|
+
color: "#fff",
|
|
3874
|
+
background: "#409eff",
|
|
3875
|
+
borderColor: "#409eff"
|
|
3876
|
+
}
|
|
3877
|
+
}, "确定")])
|
|
3878
|
+
])]);
|
|
3879
|
+
}
|
|
3880
|
+
const stop = (0, vue.watch)(() => formRef.value?.initialized, (initialized) => {
|
|
3881
|
+
if (!initialized) return;
|
|
3882
|
+
stop();
|
|
3883
|
+
doSubmit();
|
|
3793
3884
|
}, {
|
|
3794
3885
|
flush: "post",
|
|
3795
3886
|
immediate: true
|
|
@@ -3813,7 +3904,7 @@
|
|
|
3813
3904
|
} catch {}
|
|
3814
3905
|
container.parentNode?.removeChild(container);
|
|
3815
3906
|
};
|
|
3816
|
-
if (timeout > 0) timer = setTimeout(() => {
|
|
3907
|
+
if (timeout > 0 && !debug) timer = setTimeout(() => {
|
|
3817
3908
|
if (!cleaned) {
|
|
3818
3909
|
reject(/* @__PURE__ */ new Error(`submitForm timeout after ${timeout}ms: form is not initialized.`));
|
|
3819
3910
|
cleanup();
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.11",
|
|
3
3
|
"name": "@tmagic/form",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"vue": "^3.5.38",
|
|
54
54
|
"typescript": "^6.0.3",
|
|
55
|
-
"@tmagic/form-schema": "1.8.0-beta.
|
|
56
|
-
"@tmagic/
|
|
57
|
-
"@tmagic/
|
|
55
|
+
"@tmagic/form-schema": "1.8.0-beta.11",
|
|
56
|
+
"@tmagic/design": "1.8.0-beta.11",
|
|
57
|
+
"@tmagic/utils": "1.8.0-beta.11"
|
|
58
58
|
},
|
|
59
59
|
"peerDependenciesMeta": {
|
|
60
60
|
"typescript": {
|
package/src/submitForm.ts
CHANGED
|
@@ -65,6 +65,15 @@ export interface SubmitFormOptions {
|
|
|
65
65
|
appContext?: AppContext | null;
|
|
66
66
|
/** 等待表单初始化的最长时间(毫秒),超时将以错误 reject。默认 10000ms */
|
|
67
67
|
timeout?: number;
|
|
68
|
+
/**
|
|
69
|
+
* 调试模式。默认 `false`。
|
|
70
|
+
*
|
|
71
|
+
* - `false`:表单以隐藏方式挂载,初始化完成后自动提交(原有行为)。
|
|
72
|
+
* - `true`:将表单以弹层形式可见地渲染在页面上,需手动点击「确定」才会触发校验/提交,
|
|
73
|
+
* 点击「取消」则以 reject 中断;校验失败时保留弹层并展示错误信息,便于修正后重试。
|
|
74
|
+
* 调试模式下 `timeout` 不生效(等待人工操作)。
|
|
75
|
+
*/
|
|
76
|
+
debug?: boolean;
|
|
68
77
|
}
|
|
69
78
|
// #endregion SubmitFormOptions
|
|
70
79
|
|
|
@@ -107,14 +116,24 @@ export interface SubmitFormResult {
|
|
|
107
116
|
* initValues: { name: 'foo' },
|
|
108
117
|
* returnChangeRecords: true,
|
|
109
118
|
* });
|
|
119
|
+
*
|
|
120
|
+
* // 调试模式:可见地渲染表单,点击「确定」才提交:
|
|
121
|
+
* const values = await submitForm({
|
|
122
|
+
* config: [...],
|
|
123
|
+
* initValues: { name: 'foo' },
|
|
124
|
+
* debug: true,
|
|
125
|
+
* });
|
|
110
126
|
* ```
|
|
111
127
|
*/
|
|
112
128
|
export const submitForm = (options: SubmitFormOptions): Promise<any> => {
|
|
113
|
-
const { native, appContext, timeout = 10000, returnChangeRecords, ...formProps } = options;
|
|
129
|
+
const { native, appContext, timeout = 10000, returnChangeRecords, debug = false, ...formProps } = options;
|
|
114
130
|
|
|
115
131
|
return new Promise((resolve, reject) => {
|
|
116
132
|
const container = document.createElement('div');
|
|
117
|
-
|
|
133
|
+
// 调试模式下需要把表单展示出来,普通模式则隐藏挂载
|
|
134
|
+
if (!debug) {
|
|
135
|
+
container.style.display = 'none';
|
|
136
|
+
}
|
|
118
137
|
document.body.appendChild(container);
|
|
119
138
|
|
|
120
139
|
let cleaned = false;
|
|
@@ -124,25 +143,154 @@ export const submitForm = (options: SubmitFormOptions): Promise<any> => {
|
|
|
124
143
|
name: 'MFormSubmitWrapper',
|
|
125
144
|
setup() {
|
|
126
145
|
const formRef = ref<any>(null);
|
|
146
|
+
// 调试模式下用于展示校验失败信息
|
|
147
|
+
const errorMsg = ref('');
|
|
127
148
|
|
|
149
|
+
const doSubmit = async () => {
|
|
150
|
+
try {
|
|
151
|
+
// 等待子组件(FormItem 等)完成首次渲染,确保 validate 能拿到所有字段
|
|
152
|
+
await nextTick();
|
|
153
|
+
// submitForm 校验通过后会清空 changeRecords,需在调用前先做快照
|
|
154
|
+
const changeRecords: ChangeRecord[] = [...(formRef.value?.changeRecords ?? [])];
|
|
155
|
+
const result = await formRef.value.submitForm(native);
|
|
156
|
+
resolve(returnChangeRecords ? { values: result, changeRecords } : result);
|
|
157
|
+
cleanup();
|
|
158
|
+
} catch (err) {
|
|
159
|
+
// 调试模式下校验失败时保留弹层并展示错误,便于修正后重新提交
|
|
160
|
+
if (debug) {
|
|
161
|
+
errorMsg.value = err instanceof Error ? err.message : String(err);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
reject(err);
|
|
165
|
+
cleanup();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// 调试模式:可见地渲染表单,点击「确定」才提交,点击「取消」则中断
|
|
170
|
+
if (debug) {
|
|
171
|
+
const handleCancel = () => {
|
|
172
|
+
reject(new Error('submitForm canceled in debug mode.'));
|
|
173
|
+
cleanup();
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const btnBase = {
|
|
177
|
+
padding: '8px 20px',
|
|
178
|
+
fontSize: '14px',
|
|
179
|
+
lineHeight: '1',
|
|
180
|
+
border: '1px solid #dcdfe6',
|
|
181
|
+
borderRadius: '4px',
|
|
182
|
+
cursor: 'pointer',
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
return () =>
|
|
186
|
+
h(
|
|
187
|
+
'div',
|
|
188
|
+
{
|
|
189
|
+
style: {
|
|
190
|
+
position: 'fixed',
|
|
191
|
+
inset: '0',
|
|
192
|
+
zIndex: '10000',
|
|
193
|
+
display: 'flex',
|
|
194
|
+
alignItems: 'center',
|
|
195
|
+
justifyContent: 'center',
|
|
196
|
+
background: 'rgba(0, 0, 0, 0.5)',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
[
|
|
200
|
+
h(
|
|
201
|
+
'div',
|
|
202
|
+
{
|
|
203
|
+
style: {
|
|
204
|
+
display: 'flex',
|
|
205
|
+
flexDirection: 'column',
|
|
206
|
+
width: '600px',
|
|
207
|
+
maxWidth: '90vw',
|
|
208
|
+
maxHeight: '85vh',
|
|
209
|
+
background: '#fff',
|
|
210
|
+
borderRadius: '8px',
|
|
211
|
+
boxShadow: '0 8px 24px rgba(0, 0, 0, 0.2)',
|
|
212
|
+
overflow: 'hidden',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
[
|
|
216
|
+
h(
|
|
217
|
+
'div',
|
|
218
|
+
{
|
|
219
|
+
style: {
|
|
220
|
+
padding: '16px 20px',
|
|
221
|
+
fontSize: '16px',
|
|
222
|
+
fontWeight: '600',
|
|
223
|
+
borderBottom: '1px solid #ebeef5',
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
'submitForm 调试',
|
|
227
|
+
),
|
|
228
|
+
h(
|
|
229
|
+
'div',
|
|
230
|
+
{
|
|
231
|
+
style: {
|
|
232
|
+
flex: '1',
|
|
233
|
+
padding: '20px',
|
|
234
|
+
overflow: 'auto',
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
[
|
|
238
|
+
h(Form as Component, { ...formProps, ref: formRef }),
|
|
239
|
+
errorMsg.value
|
|
240
|
+
? h('div', {
|
|
241
|
+
style: {
|
|
242
|
+
marginTop: '12px',
|
|
243
|
+
color: '#f56c6c',
|
|
244
|
+
fontSize: '13px',
|
|
245
|
+
lineHeight: '1.5',
|
|
246
|
+
},
|
|
247
|
+
innerHTML: errorMsg.value,
|
|
248
|
+
})
|
|
249
|
+
: null,
|
|
250
|
+
],
|
|
251
|
+
),
|
|
252
|
+
h(
|
|
253
|
+
'div',
|
|
254
|
+
{
|
|
255
|
+
style: {
|
|
256
|
+
display: 'flex',
|
|
257
|
+
justifyContent: 'flex-end',
|
|
258
|
+
gap: '12px',
|
|
259
|
+
padding: '12px 20px',
|
|
260
|
+
borderTop: '1px solid #ebeef5',
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
[
|
|
264
|
+
h('button', { type: 'button', onClick: handleCancel, style: { ...btnBase } }, '取消'),
|
|
265
|
+
h(
|
|
266
|
+
'button',
|
|
267
|
+
{
|
|
268
|
+
type: 'button',
|
|
269
|
+
onClick: doSubmit,
|
|
270
|
+
style: {
|
|
271
|
+
...btnBase,
|
|
272
|
+
color: '#fff',
|
|
273
|
+
background: '#409eff',
|
|
274
|
+
borderColor: '#409eff',
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
'确定',
|
|
278
|
+
),
|
|
279
|
+
],
|
|
280
|
+
),
|
|
281
|
+
],
|
|
282
|
+
),
|
|
283
|
+
],
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 普通模式:表单初始化完成后自动提交
|
|
128
288
|
const stop = watch(
|
|
129
289
|
() => formRef.value?.initialized,
|
|
130
|
-
|
|
290
|
+
(initialized) => {
|
|
131
291
|
if (!initialized) return;
|
|
132
292
|
stop();
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
// 等待子组件(FormItem 等)完成首次渲染,确保 validate 能拿到所有字段
|
|
136
|
-
await nextTick();
|
|
137
|
-
// submitForm 校验通过后会清空 changeRecords,需在调用前先做快照
|
|
138
|
-
const changeRecords: ChangeRecord[] = [...(formRef.value.changeRecords ?? [])];
|
|
139
|
-
const result = await formRef.value.submitForm(native);
|
|
140
|
-
resolve(returnChangeRecords ? { values: result, changeRecords } : result);
|
|
141
|
-
} catch (err) {
|
|
142
|
-
reject(err);
|
|
143
|
-
} finally {
|
|
144
|
-
cleanup();
|
|
145
|
-
}
|
|
293
|
+
doSubmit();
|
|
146
294
|
},
|
|
147
295
|
{ flush: 'post', immediate: true },
|
|
148
296
|
);
|
|
@@ -173,7 +321,8 @@ export const submitForm = (options: SubmitFormOptions): Promise<any> => {
|
|
|
173
321
|
container.parentNode?.removeChild(container);
|
|
174
322
|
};
|
|
175
323
|
|
|
176
|
-
|
|
324
|
+
// 调试模式等待人工操作,不应用超时
|
|
325
|
+
if (timeout > 0 && !debug) {
|
|
177
326
|
timer = setTimeout(() => {
|
|
178
327
|
if (!cleaned) {
|
|
179
328
|
reject(new Error(`submitForm timeout after ${timeout}ms: form is not initialized.`));
|
package/types/index.d.ts
CHANGED
|
@@ -107,6 +107,15 @@ interface SubmitFormOptions {
|
|
|
107
107
|
appContext?: AppContext | null;
|
|
108
108
|
/** 等待表单初始化的最长时间(毫秒),超时将以错误 reject。默认 10000ms */
|
|
109
109
|
timeout?: number;
|
|
110
|
+
/**
|
|
111
|
+
* 调试模式。默认 `false`。
|
|
112
|
+
*
|
|
113
|
+
* - `false`:表单以隐藏方式挂载,初始化完成后自动提交(原有行为)。
|
|
114
|
+
* - `true`:将表单以弹层形式可见地渲染在页面上,需手动点击「确定」才会触发校验/提交,
|
|
115
|
+
* 点击「取消」则以 reject 中断;校验失败时保留弹层并展示错误信息,便于修正后重试。
|
|
116
|
+
* 调试模式下 `timeout` 不生效(等待人工操作)。
|
|
117
|
+
*/
|
|
118
|
+
debug?: boolean;
|
|
110
119
|
}
|
|
111
120
|
/**
|
|
112
121
|
* 开启 `returnChangeRecords` 时 submitForm 的返回结果
|
|
@@ -144,6 +153,13 @@ interface SubmitFormResult {
|
|
|
144
153
|
* initValues: { name: 'foo' },
|
|
145
154
|
* returnChangeRecords: true,
|
|
146
155
|
* });
|
|
156
|
+
*
|
|
157
|
+
* // 调试模式:可见地渲染表单,点击「确定」才提交:
|
|
158
|
+
* const values = await submitForm({
|
|
159
|
+
* config: [...],
|
|
160
|
+
* initValues: { name: 'foo' },
|
|
161
|
+
* debug: true,
|
|
162
|
+
* });
|
|
147
163
|
* ```
|
|
148
164
|
*/
|
|
149
165
|
declare const submitForm: (options: SubmitFormOptions) => Promise<any>;
|