feat: Add form demo

This commit is contained in:
陈凯龙 2022-01-27 16:41:29 +08:00
parent dbf3b0f5a3
commit 7795d2a4fe
12 changed files with 1823 additions and 85 deletions

View File

@ -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<typeof ElForm>
}
export { Form }

View File

@ -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<FormSchema[]>,
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<ComponentRef<typeof ElForm>>()
const getProps = computed(() => props)
// useFormprops
const outsideProps = ref<Recordable>({})
const getProps = computed(() => Object.assign({ ...props }, unref(outsideProps)))
const { schema, isCol, isCustom, autoSetPlaceholder } = unref(getProps)
//
const formModel = ref<Recordable>({})
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)
}
formModel.value = Object.assign(unref(formModel), formData)
}
const addSchema = (formSchema: FormSchema, index?: number) => {
if (index !== void 0) {
schema.splice(index, 0, formSchema)
return
}
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<typeof ElForm> => {
return unref(elFormRef) as ComponentRef<typeof ElForm>
}
expose({
setValues,
formModel
formModel,
setProps,
delSchema,
addSchema,
setSchema,
getElFormRef
})
// formModel

View File

@ -29,17 +29,19 @@ export const useForm = () => {
// 一些内置的方法
const methods: {
setValues: (data: FormSetValuesType[]) => void
getFormData: () => Promise<Recordable | undefined>
setSchema: (schemaProps: FormSetValuesType[]) => void
setProps: (props: Recordable) => void
setValues: (data: Recordable) => void
getFormData: <T = Recordable | undefined>() => Promise<T>
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<Recordable | undefined> => {
getFormData: async <T = Recordable>(): Promise<T> => {
const form = await getForm()
return form?.formModel || undefined
return form?.formModel as T
}
}

View File

@ -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',

View File

@ -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: '引导页',

View File

@ -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'),

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
<script setup lang="ts">
import { Form, FormExpose } from '@/components/Form'
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { reactive, unref, ref } from 'vue'
import { ElButton } from 'element-plus'
import { required } from '@/utils/formRules'
const { t } = useI18n()
const schema = reactive<FormSchema[]>([
{
field: 'field1',
label: t('formDemo.input'),
component: 'Input',
formItemProps: {
rules: [required]
}
},
{
field: 'field2',
label: t('formDemo.select'),
component: 'Select',
componentProps: {
options: [
{
label: 'option1',
value: '1'
},
{
label: 'option2',
value: '2'
}
]
}
},
{
field: 'field3',
label: t('formDemo.radio'),
component: 'Radio',
componentProps: {
options: [
{
label: 'option-1',
value: '1'
},
{
label: 'option-2',
value: '2'
}
]
}
},
{
field: 'field4',
label: t('formDemo.checkbox'),
component: 'Checkbox',
value: [],
componentProps: {
options: [
{
label: 'option-1',
value: '1'
},
{
label: 'option-2',
value: '2'
},
{
label: 'option-3',
value: '3'
}
]
}
},
{
field: 'field5',
component: 'DatePicker',
label: t('formDemo.datePicker'),
componentProps: {
type: 'date'
}
},
{
field: 'field6',
component: 'TimeSelect',
label: t('formDemo.timeSelect')
}
])
const formRef = ref<FormExpose>()
const changeLabelWidth = (width: number | string) => {
unref(formRef)?.setProps({
labelWidth: width
})
}
const changeSize = (size: string) => {
unref(formRef)?.setProps({
size
})
}
const changeDisabled = (bool: boolean) => {
unref(formRef)?.setProps({
disabled: bool
})
}
const changeSchema = (del: boolean) => {
if (del) {
unref(formRef)?.delSchema('field2')
} else if (!del && schema[1].field !== 'field2') {
unref(formRef)?.addSchema(
{
field: 'field2',
label: t('formDemo.select'),
component: 'Select',
componentProps: {
options: [
{
label: 'option1',
value: '1'
},
{
label: 'option2',
value: '2'
}
]
}
},
1
)
}
}
const setValue = (reset: boolean) => {
const elFormRef = unref(formRef)?.getElFormRef()
if (reset) {
elFormRef?.resetFields()
} else {
unref(formRef)?.setValues({
field1: 'field1',
field2: '2',
field3: '2',
field4: ['1', '3'],
field5: '2022-01-27',
field6: '17:00'
})
}
}
const index = ref(7)
const setLabel = () => {
unref(formRef)?.setSchema([
{
field: 'field2',
path: 'label',
value: `${t('formDemo.select')} ${index.value}`
},
{
field: 'field2',
path: 'componentProps.options',
value: [
{
label: 'option-1',
value: '1'
},
{
label: 'option-2',
value: '2'
},
{
label: 'option-3',
value: '3'
}
]
}
])
index.value++
}
const addItem = () => {
if (unref(index) % 2 === 0) {
unref(formRef)?.addSchema({
field: `field${unref(index)}`,
label: `${t('formDemo.input')}${unref(index)}`,
component: 'Input'
})
} else {
unref(formRef)?.addSchema(
{
field: `field${unref(index)}`,
label: `${t('formDemo.input')}${unref(index)}`,
component: 'Input'
},
unref(index)
)
}
index.value++
}
const formValidation = () => {
const elFormRef = unref(formRef)?.getElFormRef()
elFormRef?.validate()?.catch(() => {})
}
const verifyReset = () => {
const elFormRef = unref(formRef)?.getElFormRef()
elFormRef?.resetFields()
}
</script>
<template>
<ContentWrap :title="`refForm${t('formDemo.operate')}`">
<ElButton @click="changeLabelWidth(150)">{{ t('formDemo.change') }} labelWidth</ElButton>
<ElButton @click="changeLabelWidth('auto')">{{ t('formDemo.restore') }} labelWidth</ElButton>
<ElButton @click="changeSize('large')">{{ t('formDemo.change') }} size</ElButton>
<ElButton @click="changeSize('default')">{{ t('formDemo.restore') }} size</ElButton>
<ElButton @click="changeDisabled(true)">{{ t('formDemo.disabled') }}</ElButton>
<ElButton @click="changeDisabled(false)">{{ t('formDemo.disablement') }}</ElButton>
<ElButton @click="changeSchema(true)">
{{ t('formDemo.delete') }} {{ t('formDemo.select') }}
</ElButton>
<ElButton @click="changeSchema(false)">
{{ t('formDemo.add') }} {{ t('formDemo.select') }}
</ElButton>
<ElButton @click="setValue(false)">{{ t('formDemo.setValue') }}</ElButton>
<ElButton @click="setValue(true)">{{ t('formDemo.resetValue') }}</ElButton>
<ElButton @click="setLabel">
{{ t('formDemo.set') }} {{ t('formDemo.select') }} label
</ElButton>
<ElButton @click="addItem"> {{ t('formDemo.add') }} {{ t('formDemo.subitem') }} </ElButton>
<ElButton @click="formValidation"> {{ t('formDemo.formValidation') }} </ElButton>
<ElButton @click="verifyReset"> {{ t('formDemo.verifyReset') }} </ElButton>
</ContentWrap>
<ContentWrap :title="`useForm${t('formDemo.example')}`">
<Form :schema="schema" ref="formRef" />
</ContentWrap>
</template>

View File

@ -0,0 +1,256 @@
<script setup lang="ts">
import { Form } from '@/components/Form'
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { useForm } from '@/hooks/web/useForm'
import { reactive, unref, ref } from 'vue'
import { ElButton } from 'element-plus'
import { required } from '@/utils/formRules'
const { t } = useI18n()
const schema = reactive<FormSchema[]>([
{
field: 'field1',
label: t('formDemo.input'),
component: 'Input',
formItemProps: {
rules: [required]
}
},
{
field: 'field2',
label: t('formDemo.select'),
component: 'Select',
componentProps: {
options: [
{
label: 'option1',
value: '1'
},
{
label: 'option2',
value: '2'
}
]
}
},
{
field: 'field3',
label: t('formDemo.radio'),
component: 'Radio',
componentProps: {
options: [
{
label: 'option-1',
value: '1'
},
{
label: 'option-2',
value: '2'
}
]
}
},
{
field: 'field4',
label: t('formDemo.checkbox'),
component: 'Checkbox',
value: [],
componentProps: {
options: [
{
label: 'option-1',
value: '1'
},
{
label: 'option-2',
value: '2'
},
{
label: 'option-3',
value: '3'
}
]
}
},
{
field: 'field5',
component: 'DatePicker',
label: t('formDemo.datePicker'),
componentProps: {
type: 'date'
}
},
{
field: 'field6',
component: 'TimeSelect',
label: t('formDemo.timeSelect')
}
])
const { register, methods, elFormRef } = useForm()
const changeLabelWidth = (width: number | string) => {
const { setProps } = methods
setProps({
labelWidth: width
})
}
const changeSize = (size: string) => {
const { setProps } = methods
setProps({
size
})
}
const changeDisabled = (bool: boolean) => {
const { setProps } = methods
setProps({
disabled: bool
})
}
const changeSchema = (del: boolean) => {
const { delSchema, addSchema } = methods
if (del) {
delSchema('field2')
} else if (!del && schema[1].field !== 'field2') {
addSchema(
{
field: 'field2',
label: t('formDemo.select'),
component: 'Select',
componentProps: {
options: [
{
label: 'option1',
value: '1'
},
{
label: 'option2',
value: '2'
}
]
}
},
1
)
}
}
const setValue = (reset: boolean) => {
const { setValues } = methods
if (reset) {
unref(elFormRef)?.resetFields()
} else {
setValues({
field1: 'field1',
field2: '2',
field3: '2',
field4: ['1', '3'],
field5: '2022-01-27',
field6: '17:00'
})
}
}
const index = ref(7)
const setLabel = () => {
const { setSchema } = methods
setSchema([
{
field: 'field2',
path: 'label',
value: `${t('formDemo.select')} ${index.value}`
},
{
field: 'field2',
path: 'componentProps.options',
value: [
{
label: 'option-1',
value: '1'
},
{
label: 'option-2',
value: '2'
},
{
label: 'option-3',
value: '3'
}
]
}
])
index.value++
}
const addItem = () => {
const { addSchema } = methods
if (unref(index) % 2 === 0) {
addSchema({
field: `field${unref(index)}`,
label: `${t('formDemo.input')}${unref(index)}`,
component: 'Input'
})
} else {
addSchema(
{
field: `field${unref(index)}`,
label: `${t('formDemo.input')}${unref(index)}`,
component: 'Input'
},
unref(index)
)
}
index.value++
}
const formValidation = () => {
unref(elFormRef)
?.validate()
?.catch(() => {})
}
const verifyReset = () => {
unref(elFormRef)?.resetFields()
}
</script>
<template>
<ContentWrap :title="`useForm${t('formDemo.operate')}`">
<ElButton @click="changeLabelWidth(150)">{{ t('formDemo.change') }} labelWidth</ElButton>
<ElButton @click="changeLabelWidth('auto')">{{ t('formDemo.restore') }} labelWidth</ElButton>
<ElButton @click="changeSize('large')">{{ t('formDemo.change') }} size</ElButton>
<ElButton @click="changeSize('default')">{{ t('formDemo.restore') }} size</ElButton>
<ElButton @click="changeDisabled(true)">{{ t('formDemo.disabled') }}</ElButton>
<ElButton @click="changeDisabled(false)">{{ t('formDemo.disablement') }}</ElButton>
<ElButton @click="changeSchema(true)">
{{ t('formDemo.delete') }} {{ t('formDemo.select') }}
</ElButton>
<ElButton @click="changeSchema(false)">
{{ t('formDemo.add') }} {{ t('formDemo.select') }}
</ElButton>
<ElButton @click="setValue(false)">{{ t('formDemo.setValue') }}</ElButton>
<ElButton @click="setValue(true)">{{ t('formDemo.resetValue') }}</ElButton>
<ElButton @click="setLabel">
{{ t('formDemo.set') }} {{ t('formDemo.select') }} label
</ElButton>
<ElButton @click="addItem"> {{ t('formDemo.add') }} {{ t('formDemo.subitem') }} </ElButton>
<ElButton @click="formValidation"> {{ t('formDemo.formValidation') }} </ElButton>
<ElButton @click="verifyReset"> {{ t('formDemo.verifyReset') }} </ElButton>
</ContentWrap>
<ContentWrap :title="`useForm${t('formDemo.example')}`">
<Form :schema="schema" @register="register" />
</ContentWrap>
</template>

View File

@ -172,14 +172,14 @@ const { t } = useI18n()
<ElRow class="mt-20px" :gutter="20" justify="space-between">
<ElCol :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-20px">
<ElSkeleton :loading="loading" animated>
<ElCard shadow="never">
<template #header>
<div class="flex justify-between">
<span>{{ t('workplace.project') }}</span>
<ElLink type="primary" :underline="false">{{ t('workplace.more') }}</ElLink>
</div>
</template>
<ElCard shadow="never">
<template #header>
<div class="flex justify-between">
<span>{{ t('workplace.project') }}</span>
<ElLink type="primary" :underline="false">{{ t('workplace.more') }}</ElLink>
</div>
</template>
<ElSkeleton :loading="loading" animated>
<ElRow>
<ElCol
v-for="(item, index) in projects"
@ -203,17 +203,17 @@ const { t } = useI18n()
</ElCard>
</ElCol>
</ElRow>
</ElCard>
</ElSkeleton>
</ElSkeleton>
</ElCard>
<ElSkeleton :loading="loading" animated>
<ElCard shadow="never" class="mt-20px">
<template #header>
<div class="flex justify-between">
<span>{{ t('workplace.dynamic') }}</span>
<ElLink type="primary" :underline="false">{{ t('workplace.more') }}</ElLink>
</div>
</template>
<ElCard shadow="never" class="mt-20px">
<template #header>
<div class="flex justify-between">
<span>{{ t('workplace.dynamic') }}</span>
<ElLink type="primary" :underline="false">{{ t('workplace.more') }}</ElLink>
</div>
</template>
<ElSkeleton :loading="loading" animated>
<div v-for="(item, index) in dynamics" :key="`dynamics-${index}`">
<div class="flex items-center">
<img
@ -234,15 +234,15 @@ const { t } = useI18n()
</div>
<ElDivider />
</div>
</ElCard>
</ElSkeleton>
</ElSkeleton>
</ElCard>
</ElCol>
<ElCol :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-20px">
<ElSkeleton :loading="loading" animated>
<ElCard shadow="never">
<template #header>
<span>{{ t('workplace.shortcutOperation') }}</span>
</template>
<ElCard shadow="never">
<template #header>
<span>{{ t('workplace.shortcutOperation') }}</span>
</template>
<ElSkeleton :loading="loading" animated>
<ElCol
v-for="item in 9"
:key="`card-${item}`"
@ -257,23 +257,23 @@ const { t } = useI18n()
{{ t('workplace.operation') }}{{ item }}
</ElLink>
</ElCol>
</ElCard>
</ElSkeleton>
</ElSkeleton>
</ElCard>
<ElSkeleton :loading="loading" animated>
<ElCard shadow="never" class="mt-20px">
<template #header>
<span>xx{{ t('workplace.index') }}</span>
</template>
<ElCard shadow="never" class="mt-20px">
<template #header>
<span>xx{{ t('workplace.index') }}</span>
</template>
<ElSkeleton :loading="loading" animated>
<Echart :options="radarOptionData" :height="400" />
</ElCard>
</ElSkeleton>
</ElSkeleton>
</ElCard>
<ElSkeleton :loading="loading" animated>
<ElCard shadow="never" class="mt-20px">
<template #header>
<span>{{ t('workplace.team') }}</span>
</template>
<ElCard shadow="never" class="mt-20px">
<template #header>
<span>{{ t('workplace.team') }}</span>
</template>
<ElSkeleton :loading="loading" animated>
<ElRow>
<ElCol v-for="item in team" :key="`team-${item.name}`" :span="12" class="mb-20px">
<div class="flex items-center">
@ -284,8 +284,8 @@ const { t } = useI18n()
</div>
</ElCol>
</ElRow>
</ElCard>
</ElSkeleton>
</ElSkeleton>
</ElCard>
</ElCol>
</ElRow>
</template>

View File

@ -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<UserLoginType>()
const res = await loginApi(formData)
.catch(() => {})

View File

@ -84,11 +84,6 @@ declare global {
hidden?: boolean
}
declare type FormSetValuesType = {
field: string
value: FormValueType
}
declare type FormSetPropsType = {
field: string
path: string