Эх сурвалжийг харах

feat: Add Search component and add search demo

陈凯龙 3 жил өмнө
parent
commit
33eca8a97d

+ 9 - 3
src/components/Form/src/Form.vue

@@ -52,10 +52,16 @@ export default defineComponent({
     const elFormRef = ref<ComponentRef<typeof ElForm>>()
 
     // useForm传入的props
-    const outsideProps = ref<FormProps>({ ...props })
+    const outsideProps = ref<FormProps>({})
 
     const getProps = computed(() => {
-      return { ...props, ...unref(outsideProps) }
+      const propsObj = { ...props }
+      for (const key in unref(outsideProps)) {
+        if (Reflect.has(propsObj, key)) {
+          propsObj[key] = unref(outsideProps)[key]
+        }
+      }
+      return propsObj
     })
 
     // 表单数据
@@ -71,7 +77,7 @@ export default defineComponent({
     }
 
     const setProps = (props: FormProps = {}) => {
-      outsideProps.value = Object.assign(unref(formModel), props)
+      outsideProps.value = props
     }
 
     const delSchema = (field: string) => {

+ 3 - 0
src/components/Search/index.ts

@@ -0,0 +1,3 @@
+import Search from './src/Search.vue'
+
+export { Search }

+ 106 - 0
src/components/Search/src/Search.vue

@@ -0,0 +1,106 @@
+<script setup lang="ts">
+import { Form } from '@/components/Form'
+import { PropType, computed, unref, CSSProperties } from 'vue'
+import { propTypes } from '@/utils/propTypes'
+import { ElButton } from 'element-plus'
+import { useI18n } from '@/hooks/web/useI18n'
+import { useForm } from '@/hooks/web/useForm'
+
+const { t } = useI18n()
+
+const props = defineProps({
+  // 生成Form的布局结构数组
+  schema: {
+    type: Array as PropType<FormSchema[]>,
+    default: () => []
+  },
+  // 是否需要栅格布局
+  isCol: propTypes.bool.def(false),
+  // 表单label宽度
+  labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
+  // 操作按钮风格位置
+  layout: propTypes.string.validate((v: string) => ['inline', 'bottom'].includes(v)).def('inline'),
+  // 底部按钮的对齐方式
+  buttomPosition: propTypes.string
+    .validate((v: string) => ['left', 'center', 'right'].includes(v))
+    .def('center'),
+  showSearch: propTypes.bool.def(true),
+  showReset: propTypes.bool.def(true)
+})
+
+const emit = defineEmits(['search', 'reset'])
+
+const newSchema = computed(() => {
+  if (props.layout === 'inline') {
+    return props.schema.concat([
+      {
+        field: 'action',
+        formItemProps: {
+          labelWidth: '0px'
+        }
+      }
+    ])
+  } else {
+    return props.schema
+  }
+})
+
+const { register, elFormRef, methods } = useForm()
+
+const search = async () => {
+  const res = await unref(elFormRef)
+    ?.validate()
+    ?.catch(() => {})
+  if (res) {
+    const { getFormData } = methods
+    const model = await getFormData()
+    emit('search', model)
+  }
+}
+
+const reset = async () => {
+  unref(elFormRef)?.resetFields()
+  const { getFormData } = methods
+  const model = await getFormData()
+  emit('reset', model)
+}
+
+const bottonButtonStyle = computed(() => {
+  return {
+    textAlign: props.buttomPosition
+  }
+}) as CSSProperties
+</script>
+
+<template>
+  <Form
+    :is-custom="false"
+    :label-width="labelWidth"
+    hide-required-asterisk
+    inline
+    :is-col="isCol"
+    :schema="newSchema"
+    @register="register"
+  >
+    <template v-if="layout === 'inline'" #action>
+      <ElButton v-if="showSearch" type="primary" @click="search">
+        <Icon icon="ep:search" class="mr-5px" />
+        {{ t('common.query') }}
+      </ElButton>
+      <ElButton v-if="showReset" @click="reset">
+        <Icon icon="ep:refresh-right" class="mr-5px" />
+        {{ t('common.reset') }}
+      </ElButton>
+    </template>
+  </Form>
+  <div v-if="layout === 'bottom'" :style="bottonButtonStyle">
+    <ElButton v-if="showSearch" type="primary" @click="search">
+      <Icon icon="ep:search" class="mr-5px" />
+      {{ t('common.query') }}
+    </ElButton>
+    <ElButton v-if="showReset" @click="reset">
+      <Icon icon="ep:refresh-right" class="mr-5px" />
+      {{ t('common.reset') }}
+    </ElButton>
+  </div>
+</template>

+ 0 - 1
src/hooks/web/useForm.ts

@@ -39,7 +39,6 @@ export const useForm = (props?: FormProps) => {
   } = {
     setProps: async (props: FormProps = {}) => {
       const form = await getForm()
-      console.log(form)
       form?.setProps(props)
     },
 

+ 21 - 2
src/locales/en.ts

@@ -29,7 +29,9 @@ export default {
     tagsView: 'Tags view',
     tagsViewDes: 'Used to record routing history',
     tool: 'Tool',
-    toolDes: 'Used to set up custom systems'
+    toolDes: 'Used to set up custom systems',
+    query: 'Query',
+    reset: 'Reset'
   },
   setting: {
     projectSetting: 'Project setting',
@@ -95,7 +97,8 @@ export default {
     highlight: 'Highlight',
     infotip: 'Infotip',
     form: 'Form',
-    defaultForm: 'All examples'
+    defaultForm: 'All examples',
+    search: 'Search'
   },
   analysis: {
     newUser: 'New user',
@@ -280,5 +283,21 @@ export default {
   },
   levelDemo: {
     menu: 'Multi level menu cache'
+  },
+  searchDemo: {
+    search: 'Search',
+    searchDes:
+      'Based on the secondary encapsulation of form components, the functions of query and reset are realized',
+    operate: 'operate',
+    change: 'Change',
+    grid: 'grid',
+    button: 'Button',
+    restore: 'Restore',
+    inline: 'inline',
+    bottom: 'Bottom',
+    position: 'position',
+    left: 'left',
+    center: 'center',
+    right: 'right'
   }
 }

+ 20 - 2
src/locales/zh-CN.ts

@@ -29,7 +29,9 @@ export default {
     tagsView: '标签页',
     tagsViewDes: '用于记录路由历史记录',
     tool: '工具',
-    toolDes: '用于设置定制系统'
+    toolDes: '用于设置定制系统',
+    query: '查询',
+    reset: '重置'
   },
   setting: {
     projectSetting: '项目配置',
@@ -95,7 +97,8 @@ export default {
     highlight: '高亮',
     infotip: '信息提示',
     form: '表单',
-    defaultForm: '全部示例'
+    defaultForm: '全部示例',
+    search: '查询'
   },
   analysis: {
     newUser: '新增用户',
@@ -278,5 +281,20 @@ export default {
   },
   levelDemo: {
     menu: '多级菜单缓存'
+  },
+  searchDemo: {
+    search: '查询',
+    searchDes: '基于 Form 组件二次封装,实现查询、重置功能',
+    operate: '操作',
+    change: '更改',
+    grid: '栅格',
+    button: '按钮',
+    restore: '还原',
+    inline: '内联',
+    bottom: '底部',
+    position: '位置',
+    left: '左',
+    center: '中',
+    right: '右'
   }
 }

+ 8 - 0
src/router/index.ts

@@ -131,6 +131,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
           }
         ]
       },
+      {
+        path: 'search',
+        component: () => import('@/views/Components/Search.vue'),
+        name: 'Search',
+        meta: {
+          title: t('router.search')
+        }
+      },
       {
         path: 'icon',
         component: () => import('@/views/Components/Icon.vue'),

+ 114 - 0
src/views/Components/Search.vue

@@ -0,0 +1,114 @@
+<script setup lang="ts">
+import { ContentWrap } from '@/components/ContentWrap'
+import { useI18n } from '@/hooks/web/useI18n'
+import { Search } from '@/components/Search'
+import { reactive, ref, unref } from 'vue'
+import { required } from '@/utils/formRules'
+import { ElButton } from 'element-plus'
+
+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: 'field5',
+    component: 'DatePicker',
+    label: t('formDemo.datePicker'),
+    componentProps: {
+      type: 'date'
+    }
+  },
+  {
+    field: 'field6',
+    component: 'TimeSelect',
+    label: t('formDemo.timeSelect')
+  }
+])
+
+const isGrid = ref(false)
+
+const changeGrid = (grid: boolean) => {
+  isGrid.value = grid
+}
+
+const layout = ref('inline')
+
+const changeLayout = () => {
+  layout.value = unref(layout) === 'inline' ? 'bottom' : 'inline'
+}
+
+const buttomPosition = ref('left')
+
+const changePosition = (position: string) => {
+  layout.value = 'bottom'
+  buttomPosition.value = position
+}
+</script>
+
+<template>
+  <ContentWrap :title="`${t('searchDemo.search')} ${t('searchDemo.operate')}`">
+    <ElButton @click="changeGrid(true)">{{ t('searchDemo.grid') }}</ElButton>
+    <ElButton @click="changeGrid(false)">
+      {{ t('searchDemo.restore') }} {{ t('searchDemo.grid') }}
+    </ElButton>
+
+    <ElButton @click="changeLayout">
+      {{ t('searchDemo.button') }} {{ t('searchDemo.position') }}
+    </ElButton>
+
+    <ElButton @click="changePosition('left')">
+      {{ t('searchDemo.bottom') }} {{ t('searchDemo.position') }}-{{ t('searchDemo.left') }}
+    </ElButton>
+    <ElButton @click="changePosition('center')">
+      {{ t('searchDemo.bottom') }} {{ t('searchDemo.position') }}-{{ t('searchDemo.center') }}
+    </ElButton>
+    <ElButton @click="changePosition('right')">
+      {{ t('searchDemo.bottom') }} {{ t('searchDemo.position') }}-{{ t('searchDemo.right') }}
+    </ElButton>
+  </ContentWrap>
+
+  <ContentWrap :title="t('searchDemo.search')" :message="t('searchDemo.searchDes')">
+    <Search :schema="schema" :is-col="isGrid" :layout="layout" :buttom-position="buttomPosition" />
+  </ContentWrap>
+</template>