feat: 添加表单钩子
parent
a2c263cef7
commit
71baafecc7
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { InjectionKey } from "vue";
|
||||||
|
import { FormRef } from "./useFormRef";
|
||||||
|
import { FormSubmit } from "./useFormSubmit";
|
||||||
|
import { FormItems } from "./useFormItems";
|
||||||
|
import { FormModel } from "./useFormModel";
|
||||||
|
|
||||||
|
export type FormContextInterface = FormModel & FormItems & FormRef & FormSubmit;
|
||||||
|
|
||||||
|
export const FormContext = Symbol("FormKey") as InjectionKey<FormContextInterface>;
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Ref } from "vue";
|
||||||
|
import { FormItem } from "../hooks/types/FormItem";
|
||||||
|
|
||||||
|
export function useFormItems(items: Ref<FormItem[]>, model: Ref<Recordable>) {
|
||||||
|
const getItem = (field: string) => {
|
||||||
|
return items.value.find((i) => i.field === field);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getItemOptions = (field: string) => {
|
||||||
|
const item = getItem(field);
|
||||||
|
if (item) {
|
||||||
|
return (item.nodeProps as any)?.options;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const initItemOptions = (field: string) => {
|
||||||
|
const item = getItem(field);
|
||||||
|
item && item.initial?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initItems = () => {
|
||||||
|
for (const item of items.value) {
|
||||||
|
item.initial?.(item, model);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const initItem = (field: string) => {
|
||||||
|
const item = getItem(field);
|
||||||
|
item && item.initial(item, model);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initItems();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
items,
|
||||||
|
getItem,
|
||||||
|
initItem,
|
||||||
|
initItems,
|
||||||
|
getItemOptions,
|
||||||
|
initItemOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormItems = ReturnType<typeof useFormItems>;
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { cloneDeep } from "lodash-es";
|
||||||
|
import { Ref } from "vue";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据管理
|
||||||
|
* @param initial 初始值
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function useFormModel(model: Ref<Recordable>) {
|
||||||
|
const initial = cloneDeep(model.value);
|
||||||
|
|
||||||
|
const resetModel = () => {
|
||||||
|
model.value = cloneDeep(initial);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInitialModel = () => {
|
||||||
|
return initial;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setModel = (data: Recordable) => {
|
||||||
|
for (const key of Object.keys(model.value)) {
|
||||||
|
model.value[key] = data[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModel = () => {
|
||||||
|
return formatModel(model.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
model,
|
||||||
|
getInitialModel,
|
||||||
|
resetModel,
|
||||||
|
setModel,
|
||||||
|
getModel,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormModel = ReturnType<typeof useFormModel>;
|
||||||
|
|
||||||
|
function formatModel(model: Recordable) {
|
||||||
|
const data: Recordable = {};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(model)) {
|
||||||
|
if (/^\[.+\]$/.test(key)) {
|
||||||
|
formatModelArray(key, value, data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (/^\{.+\}$/.test(key)) {
|
||||||
|
formatModelObject(key, value, data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
data[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatModelArray(key: string, value: any, data: Recordable) {
|
||||||
|
let field = key.replaceAll(/\s/g, "");
|
||||||
|
field = field.match(/^\[(.+)\]$/)?.[1] ?? "";
|
||||||
|
|
||||||
|
if (!field) {
|
||||||
|
data[key] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = field.split(",");
|
||||||
|
keys.forEach((k, i) => {
|
||||||
|
if (/(.+)?:number$/.test(k)) {
|
||||||
|
k = k.replace(/:number$/, "");
|
||||||
|
data[k] = value?.[i] && Number(value[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (/(.+)?:boolean$/.test(k)) {
|
||||||
|
k = k.replace(/:boolean$/, "");
|
||||||
|
data[k] = value?.[i] && Boolean(value[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[k] = value?.[i];
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatModelObject(key: string, value: any, data: Recordable) {
|
||||||
|
let field = key.replaceAll(/\s/g, "");
|
||||||
|
field = field.match(/^\{(.+)\}$/)?.[1] ?? "";
|
||||||
|
|
||||||
|
if (!field) {
|
||||||
|
data[key] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = field.split(",");
|
||||||
|
keys.forEach((k, i) => {
|
||||||
|
if (/(.+)?:number$/.test(k)) {
|
||||||
|
k = k.replace(/:number$/, "");
|
||||||
|
data[k] = value?.[i] && Number(value[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (/(.+)?:boolean$/.test(k)) {
|
||||||
|
k = k.replace(/:boolean$/, "");
|
||||||
|
data[k] = value?.[i] && Boolean(value[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[k] = value?.[i];
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { FormInstance } from "@arco-design/web-vue";
|
||||||
|
|
||||||
|
export function useFormRef() {
|
||||||
|
/**
|
||||||
|
* 原始表单实例
|
||||||
|
*/
|
||||||
|
const formRef = ref<FormInstance | null>(null);
|
||||||
|
|
||||||
|
type Validate = FormInstance["validate"];
|
||||||
|
type ValidateField = FormInstance["validateField"];
|
||||||
|
type ResetFields = FormInstance["resetFields"];
|
||||||
|
type ClearValidate = FormInstance["clearValidate"];
|
||||||
|
type SetFields = FormInstance["setFields"];
|
||||||
|
type ScrollToField = FormInstance["scrollToField"];
|
||||||
|
|
||||||
|
const validate: Validate = async (...args) => formRef.value?.validate(...args);
|
||||||
|
const validateField: ValidateField = async (...args) => formRef.value?.validateField(...args);
|
||||||
|
const resetFields: ResetFields = (...args) => formRef.value?.resetFields(...args);
|
||||||
|
const clearValidate: ClearValidate = (...args) => formRef.value?.clearValidate(...args);
|
||||||
|
const setFields: SetFields = (...args) => formRef.value?.setFields(...args);
|
||||||
|
const scrollToField: ScrollToField = (...args) => formRef.value?.scrollToField(...args);
|
||||||
|
|
||||||
|
return {
|
||||||
|
formRef,
|
||||||
|
validate,
|
||||||
|
validateField,
|
||||||
|
resetFields,
|
||||||
|
clearValidate,
|
||||||
|
setFields,
|
||||||
|
scrollToField,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormRef = ReturnType<typeof useFormRef>;
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { Ref } from "vue";
|
||||||
|
import { FormItem } from "../hooks/types/FormItem";
|
||||||
|
import { FormInstance, Message } from "@arco-design/web-vue";
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
items: Ref<FormItem[]>;
|
||||||
|
model: Ref<Recordable>;
|
||||||
|
submit: Ref<Function | undefined>;
|
||||||
|
validate: FormInstance["validate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useFormSubmit(options: Options) {
|
||||||
|
const { model, items, submit, validate } = options;
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置loading
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
|
const setLoading = (value: boolean) => {
|
||||||
|
loading.value = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交表单
|
||||||
|
*/
|
||||||
|
const submitForm = async () => {
|
||||||
|
if (await validate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await submit.value?.(model.value, items.value);
|
||||||
|
const msg = res?.data?.message;
|
||||||
|
msg && Message.success(`提示: ${msg}`);
|
||||||
|
} catch {
|
||||||
|
console.log();
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消提交
|
||||||
|
*/
|
||||||
|
const cancelForm = () => {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
setLoading,
|
||||||
|
submitForm,
|
||||||
|
cancelForm,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormSubmit = ReturnType<typeof useFormSubmit>;
|
||||||
Loading…
Reference in New Issue