diff --git a/src/components/Form/index.ts b/src/components/Form/index.ts index c25195371..a9c5efc55 100644 --- a/src/components/Form/index.ts +++ b/src/components/Form/index.ts @@ -1,8 +1,14 @@ import Form from './src/Form.vue' +import { ElForm } from 'element-plus' export interface FormExpose { - setValues: (data: FormSetValuesType[]) => void + setValues: (data: Recordable) => void + setProps: (props: Recordable) => void + delSchema: (field: string) => void + addSchema: (formSchema: FormSchema, index?: number) => void + setSchema: (schemaProps: FormSetPropsType[]) => void formModel: Recordable + getElFormRef: () => ComponentRef } export { Form } diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index f464c7d6a..c15c3a414 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -16,6 +16,8 @@ import { useRenderSelect } from './components/useRenderSelect' import { useRenderRadio } from './components/useRenderRadio' import { useRenderChcekbox } from './components/useRenderChcekbox' import { useDesign } from '@/hooks/web/useDesign' +import { findIndex } from '@/utils' +import { set } from 'lodash-es' const { getPrefixCls } = useDesign() @@ -27,7 +29,6 @@ export default defineComponent({ // 生成Form的布局结构数组 schema: { type: Array as PropType, - required: true, default: () => [] }, // 是否需要栅格布局 @@ -42,43 +43,73 @@ export default defineComponent({ // 是否自定义内容 isCustom: propTypes.bool.def(false), // 表单label宽度 - labelWidth: propTypes.oneOfType([String, Number]).def(130) + labelWidth: propTypes.oneOfType([String, Number]).def('auto') }, emits: ['register'], setup(props, { slots, expose, emit }) { // element form 实例 const elFormRef = ref>() - const getProps = computed(() => props) + + // useForm传入的props + const outsideProps = ref({}) + + const getProps = computed(() => Object.assign({ ...props }, unref(outsideProps))) + const { schema, isCol, isCustom, autoSetPlaceholder } = unref(getProps) + // 表单数据 const formModel = ref({}) - watch( - () => formModel.value, - (formModel: Recordable) => { - console.log(formModel) - }, - { - deep: true - } - ) onMounted(() => { emit('register', elFormRef.value?.$parent, elFormRef.value) }) // 对表单赋值 - const setValues = (data: FormSetValuesType[]) => { - if (!data.length) return - const formData: Recordable = {} - for (const v of data) { - formData[v.field] = v.value + const setValues = (data: Recordable = {}) => { + formModel.value = Object.assign(unref(formModel), data) + } + + const setProps = (props: Recordable) => { + outsideProps.value = props + } + + const delSchema = (field: string) => { + const index = findIndex(schema, (v: FormSchema) => v.field === field) + if (index > -1) { + schema.splice(index, 1) + } + } + + const addSchema = (formSchema: FormSchema, index?: number) => { + if (index !== void 0) { + schema.splice(index, 0, formSchema) + return } - formModel.value = Object.assign(unref(formModel), formData) + schema.push(formSchema) + } + + const setSchema = (schemaProps: FormSetPropsType[]) => { + for (const v of schema) { + for (const item of schemaProps) { + if (v.field === item.field) { + set(v, item.path, item.value) + } + } + } + } + + const getElFormRef = (): ComponentRef => { + return unref(elFormRef) as ComponentRef } expose({ setValues, - formModel + formModel, + setProps, + delSchema, + addSchema, + setSchema, + getElFormRef }) // 监听表单结构化数组,重新生成formModel diff --git a/src/hooks/web/useForm.ts b/src/hooks/web/useForm.ts index e104a493c..ec0e76606 100644 --- a/src/hooks/web/useForm.ts +++ b/src/hooks/web/useForm.ts @@ -29,17 +29,19 @@ export const useForm = () => { // 一些内置的方法 const methods: { - setValues: (data: FormSetValuesType[]) => void - getFormData: () => Promise - setSchema: (schemaProps: FormSetValuesType[]) => void + setProps: (props: Recordable) => void + setValues: (data: Recordable) => void + getFormData: () => Promise + setSchema: (schemaProps: FormSetPropsType[]) => void addSchema: (formSchema: FormSchema, index?: number) => void - delSchema: (index: number) => void + delSchema: (field: string) => void } = { - /** - * @param field 字段 - * @param value 值 - */ - setValues: async (data: FormSetValuesType[]) => { + setProps: async (props: Recordable = {}) => { + const form = await getForm() + form?.setProps(props) + }, + + setValues: async (data: Recordable) => { const form = await getForm() form?.setValues(data) }, @@ -62,19 +64,19 @@ export const useForm = () => { }, /** - * @param index 删除哪个数据 + * @param field 删除哪个数据 */ - delSchema: async (index: number) => { + delSchema: async (field: string) => { const form = await getForm() - form?.delSchema(index) + form?.delSchema(field) }, /** * @returns form data */ - getFormData: async (): Promise => { + getFormData: async (): Promise => { const form = await getForm() - return form?.formModel || undefined + return form?.formModel as T } } diff --git a/src/locales/en.ts b/src/locales/en.ts index bdfe11ace..6d9e3ef1c 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -93,7 +93,9 @@ export default { watermark: 'Watermark', qrcode: 'Qrcode', highlight: 'Highlight', - infotip: 'Infotip' + infotip: 'Infotip', + form: 'Form', + defaultForm: 'All examples' }, analysis: { newUser: 'New user', @@ -193,7 +195,24 @@ export default { timePicker: 'Time Picker', timeSelect: 'Time Select', inputPassword: 'input Password', - passwordStrength: 'Password Strength' + passwordStrength: 'Password Strength', + defaultForm: 'All examples', + formDes: + 'The secondary encapsulation of form components based on ElementPlus realizes data-driven and supports all Form parameters', + example: 'example', + operate: 'Operate', + change: 'Change', + restore: 'Restore', + disabled: 'Disabled', + disablement: 'Disablement', + delete: 'Delete', + add: 'Add', + setValue: 'Set value', + resetValue: 'Reset value', + set: 'Set', + subitem: 'Subitem', + formValidation: 'Form validation', + verifyReset: 'Verify reset' }, guideDemo: { guide: 'Guide', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 7d3ba7626..d6ce482ad 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -93,7 +93,9 @@ export default { watermark: '水印', qrcode: '二维码', highlight: '高亮', - infotip: '信息提示' + infotip: '信息提示', + form: '表单', + defaultForm: '全部示例' }, analysis: { newUser: '新增用户', @@ -193,7 +195,23 @@ export default { timePicker: '时间选择器', timeSelect: '时间选择', inputPassword: '密码输入框', - passwordStrength: '密码强度' + passwordStrength: '密码强度', + defaultForm: '全部示例', + formDes: '基于 ElementPlus 的 Form 组件二次封装,实现数据驱动,支持所有 Form 参数', + example: '示例', + operate: '操作', + change: '更改', + restore: '还原', + disabled: '禁用', + disablement: '解除禁用', + delete: '删除', + add: '添加', + setValue: '设置值', + resetValue: '重置值', + set: '设置', + subitem: '子项', + formValidation: '表单验证', + verifyReset: '验证重置' }, guideDemo: { guide: '引导页', diff --git a/src/router/index.ts b/src/router/index.ts index 03e98cdb5..339d860cd 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -96,6 +96,41 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ alwaysShow: true }, children: [ + { + path: 'form', + component: getParentLayout(), + name: 'Form', + meta: { + title: t('router.form'), + alwaysShow: true + }, + children: [ + { + path: 'default-form', + component: () => import('@/views/Components/Form/DefaultForm.vue'), + name: 'DefaultForm', + meta: { + title: t('router.defaultForm') + } + }, + { + path: 'use-form', + component: () => import('@/views/Components/Form/UseFormDemo.vue'), + name: 'UseForm', + meta: { + title: 'useForm' + } + }, + { + path: 'ref-form', + component: () => import('@/views/Components/Form/RefForm.vue'), + name: 'RefForm', + meta: { + title: 'refForm' + } + } + ] + }, { path: 'icon', component: () => import('@/views/Components/Icon.vue'), diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue new file mode 100644 index 000000000..238dd066f --- /dev/null +++ b/src/views/Components/Form/DefaultForm.vue @@ -0,0 +1,1127 @@ + + + + + diff --git a/src/views/Components/Form/RefForm.vue b/src/views/Components/Form/RefForm.vue new file mode 100644 index 000000000..5b6485d9d --- /dev/null +++ b/src/views/Components/Form/RefForm.vue @@ -0,0 +1,249 @@ + + + diff --git a/src/views/Components/Form/UseFormDemo.vue b/src/views/Components/Form/UseFormDemo.vue new file mode 100644 index 000000000..dec15eb2e --- /dev/null +++ b/src/views/Components/Form/UseFormDemo.vue @@ -0,0 +1,256 @@ + + + diff --git a/src/views/Dashboard/Workplace.vue b/src/views/Dashboard/Workplace.vue index db300ed6b..16aa010a3 100644 --- a/src/views/Dashboard/Workplace.vue +++ b/src/views/Dashboard/Workplace.vue @@ -172,14 +172,14 @@ const { t } = useI18n() - - - + + + - - + + - - - + + +
- - + + - - - + + + - - + + - - - + + + - - + + - - - + + +
@@ -284,8 +284,8 @@ const { t } = useI18n()
-
-
+ +
diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index ea48347a4..0d964b279 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -117,7 +117,7 @@ const signIn = async () => { if (validate) { loading.value = true const { getFormData } = methods - const formData = (await getFormData()) as UserLoginType + const formData = await getFormData() const res = await loginApi(formData) .catch(() => {}) diff --git a/types/componentType/form.d.ts b/types/componentType/form.d.ts index e80b7e4c7..269068d3a 100644 --- a/types/componentType/form.d.ts +++ b/types/componentType/form.d.ts @@ -84,11 +84,6 @@ declare global { hidden?: boolean } - declare type FormSetValuesType = { - field: string - value: FormValueType - } - declare type FormSetPropsType = { field: string path: string