Browse Source

feat: Descriptions组件重构

kailong321200875 2 years ago
parent
commit
49e415d277

+ 2 - 0
src/components/ConfigGlobal/index.ts

@@ -1,3 +1,5 @@
 import ConfigGlobal from './src/ConfigGlobal.vue'
 
+export type { ConfigGlobalTypes } from './src/types'
+
 export { ConfigGlobal }

+ 2 - 0
src/components/ContextMenu/index.ts

@@ -2,6 +2,8 @@ import ContextMenu from './src/ContextMenu.vue'
 import { ElDropdown } from 'element-plus'
 import type { RouteLocationNormalizedLoaded } from 'vue-router'
 
+export type { ContextMenuSchema } from './src/types'
+
 export interface ContextMenuExpose {
   elDropdownMenuRef: ComponentRef<typeof ElDropdown>
   tagItem: RouteLocationNormalizedLoaded

+ 3 - 3
src/components/ContextMenu/src/ContextMenu.vue

@@ -4,7 +4,7 @@ import { PropType, ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useDesign } from '@/hooks/web/useDesign'
 import type { RouteLocationNormalizedLoaded } from 'vue-router'
-import { contextMenuSchema } from './types'
+import { ContextMenuSchema } from './types'
 const { getPrefixCls } = useDesign()
 
 const prefixCls = getPrefixCls('context-menu')
@@ -15,7 +15,7 @@ const emit = defineEmits(['visibleChange'])
 
 const props = defineProps({
   schema: {
-    type: Array as PropType<contextMenuSchema[]>,
+    type: Array as PropType<ContextMenuSchema[]>,
     default: () => []
   },
   trigger: {
@@ -28,7 +28,7 @@ const props = defineProps({
   }
 })
 
-const command = (item: contextMenuSchema) => {
+const command = (item: ContextMenuSchema) => {
   item.command && item.command(item)
 }
 

+ 2 - 2
src/components/ContextMenu/src/types/index.ts

@@ -1,7 +1,7 @@
-export type contextMenuSchema = {
+export interface ContextMenuSchema {
   disabled?: boolean
   divided?: boolean
   icon?: string
   label: string
-  command?: (item: contextMenuSchema) => void
+  command?: (item: ContextMenuSchema) => void
 }

+ 2 - 0
src/components/Descriptions/index.ts

@@ -1,3 +1,5 @@
 import Descriptions from './src/Descriptions.vue'
 
+export type { DescriptionsSchema } from './src/types'
+
 export { Descriptions }

+ 112 - 107
src/components/Descriptions/src/Descriptions.vue

@@ -1,130 +1,135 @@
-<script setup lang="ts">
+<script lang="tsx">
 import { ElCollapseTransition, ElDescriptions, ElDescriptionsItem, ElTooltip } from 'element-plus'
 import { useDesign } from '@/hooks/web/useDesign'
 import { propTypes } from '@/utils/propTypes'
-import { ref, unref, PropType, computed, useAttrs, useSlots } from 'vue'
+import { ref, unref, PropType, computed, defineComponent } from 'vue'
 import { useAppStore } from '@/store/modules/app'
 import { DescriptionsSchema } from './types'
+import { Icon } from '@/components/Icon'
 
 const appStore = useAppStore()
 
 const mobile = computed(() => appStore.getMobile)
 
-const attrs = useAttrs()
-
-const slots = useSlots()
-
-const props = defineProps({
-  title: propTypes.string.def(''),
-  message: propTypes.string.def(''),
-  collapse: propTypes.bool.def(true),
-  schema: {
-    type: Array as PropType<DescriptionsSchema[]>,
-    default: () => []
-  },
-  data: {
-    type: Object as PropType<any>,
-    default: () => ({})
-  }
-})
-
 const { getPrefixCls } = useDesign()
 
 const prefixCls = getPrefixCls('descriptions')
 
-const getBindValue = computed(() => {
-  const delArr: string[] = ['title', 'message', 'collapse', 'schema', 'data', 'class']
-  const obj = { ...attrs, ...props }
-  for (const key in obj) {
-    if (delArr.indexOf(key) !== -1) {
-      delete obj[key]
+export default defineComponent({
+  name: 'Descriptions',
+  props: {
+    title: propTypes.string.def(''),
+    message: propTypes.string.def(''),
+    collapse: propTypes.bool.def(true),
+    border: propTypes.bool.def(true),
+    column: propTypes.number.def(2),
+    size: propTypes.oneOf(['large', 'default', 'small']).def('default'),
+    direction: propTypes.oneOf(['horizontal', 'vertical']).def('horizontal'),
+    extra: propTypes.string.def(''),
+    schema: {
+      type: Array as PropType<DescriptionsSchema[]>,
+      default: () => []
+    },
+    data: {
+      type: Object as PropType<any>,
+      default: () => ({})
     }
-  }
-  return obj
-})
-
-const getBindItemValue = (item: DescriptionsSchema) => {
-  const delArr: string[] = ['field']
-  const obj = { ...item }
-  for (const key in obj) {
-    if (delArr.indexOf(key) !== -1) {
-      delete obj[key]
+  },
+  setup(props, { slots, attrs }) {
+    const getBindValue = computed((): any => {
+      const delArr: string[] = ['title', 'message', 'collapse', 'schema', 'data', 'class']
+      const obj = { ...attrs, ...props }
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      if (unref(mobile)) {
+        obj.direction = 'vertical'
+      }
+      return obj
+    })
+
+    const getBindItemValue = (item: DescriptionsSchema) => {
+      const delArr: string[] = ['field']
+      const obj = { ...item }
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      return obj
     }
-  }
-  return obj
-}
 
-// 折叠
-const show = ref(true)
+    // 折叠
+    const show = ref(true)
 
-const toggleClick = () => {
-  if (props.collapse) {
-    show.value = !unref(show)
-  }
-}
-</script>
-
-<template>
-  <div
-    :class="[
-      prefixCls,
-      'bg-[var(--el-color-white)] dark:bg-[var(--el-bg-color)] dark:border-[var(--el-border-color)] dark:border-1px'
-    ]"
-  >
-    <div
-      v-if="title"
-      :class="[
-        `${prefixCls}-header`,
-        'h-50px flex justify-between items-center b-b-1 border-solid border-[var(--tags-view-border-color)] px-10px cursor-pointer dark:border-[var(--el-border-color)]'
-      ]"
-      @click="toggleClick"
-    >
-      <div :class="[`${prefixCls}-header__title`, 'relative font-18px font-bold ml-10px']">
-        <div class="flex items-center">
-          {{ title }}
-          <ElTooltip v-if="message" :content="message" placement="right">
-            <Icon icon="ep:warning" class="ml-5px" />
-          </ElTooltip>
-        </div>
-      </div>
-      <Icon v-if="collapse" :icon="show ? 'ep:arrow-down' : 'ep:arrow-up'" />
-    </div>
+    const toggleClick = () => {
+      if (props.collapse) {
+        show.value = !unref(show)
+      }
+    }
 
-    <ElCollapseTransition>
-      <div v-show="show" :class="[`${prefixCls}-content`, 'p-10px']">
-        <ElDescriptions
-          :column="2"
-          border
-          :direction="mobile ? 'vertical' : 'horizontal'"
-          v-bind="getBindValue"
+    return () => {
+      return (
+        <div
+          class={[
+            prefixCls,
+            'bg-[var(--el-color-white)] dark:bg-[var(--el-bg-color)] dark:border-[var(--el-border-color)] dark:border-1px'
+          ]}
         >
-          <template v-if="slots['extra']" #extra>
-            <slot name="extra"></slot>
-          </template>
-          <ElDescriptionsItem
-            v-for="item in schema"
-            :key="item.field"
-            v-bind="getBindItemValue(item)"
-          >
-            <template #label>
-              <slot
-                :name="`${item.field}-label`"
-                :row="{
-                  label: item.label
-                }"
-                >{{ item.label }}</slot
-              >
-            </template>
-
-            <template #default>
-              <slot :name="item.field" :row="data">{{ data[item.field] }}</slot>
-            </template>
-          </ElDescriptionsItem>
-        </ElDescriptions>
-      </div>
-    </ElCollapseTransition>
-  </div>
-</template>
+          {props.title ? (
+            <div
+              class={[
+                `${prefixCls}-header`,
+                'relative h-50px flex justify-between items-center layout-border__bottom px-10px cursor-pointer'
+              ]}
+              onClick={toggleClick}
+            >
+              <div class={[`${prefixCls}-header__title`, 'relative font-18px font-bold ml-10px']}>
+                <div class="flex items-center">
+                  {props.title}
+                  {props.message ? (
+                    <ElTooltip content={props.message} placement="right">
+                      <Icon icon="bi:question-circle-fill" class="ml-5px" size={14} />
+                    </ElTooltip>
+                  ) : null}
+                </div>
+              </div>
+              {props.collapse ? <Icon icon={show.value ? 'ep:arrow-down' : 'ep:arrow-up'} /> : null}
+            </div>
+          ) : null}
+
+          <ElCollapseTransition>
+            <div v-show={unref(show)} class={[`${prefixCls}-content`, 'p-10px']}>
+              <ElDescriptions {...unref(getBindValue)}>
+                {{
+                  extra: () => (slots['extra'] ? slots['extra']() : props.extra),
+                  default: () => {
+                    return props.schema.map((item) => {
+                      return (
+                        <ElDescriptionsItem key={item.field} {...getBindItemValue(item)}>
+                          {{
+                            label: () => (item.slots?.label ? item.slots?.label(item) : item.label),
+                            default: () =>
+                              item.slots?.default
+                                ? item.slots?.default(item)
+                                : props.data[item.field]
+                          }}
+                        </ElDescriptionsItem>
+                      )
+                    })
+                  }
+                }}
+              </ElDescriptions>
+            </div>
+          </ElCollapseTransition>
+        </div>
+      )
+    }
+  }
+})
+</script>
 
 <style lang="less" scoped>
 @prefix-cls: ~'@{namespace}-descriptions';

+ 4 - 0
src/components/Descriptions/src/types/index.ts

@@ -8,4 +8,8 @@ export interface DescriptionsSchema {
   labelAlign?: 'left' | 'center' | 'right'
   className?: string
   labelClassName?: string
+  slots?: {
+    default?: (...args: any[]) => JSX.Element | null
+    label?: (...args: any[]) => JSX.Element | null
+  }
 }

+ 0 - 1
src/components/Form/src/types/index.ts

@@ -8,7 +8,6 @@ import {
   CascaderValue,
   FormItemRule
 } from 'element-plus'
-import type { AxiosPromise } from 'axios'
 import { IEditorConfig } from '@wangeditor/editor'
 
 export interface PlaceholderModel {

+ 1 - 1
src/components/Search/src/components/ActionButton.vue

@@ -50,7 +50,7 @@ const onExpand = () => {
   </ElButton>
   <ElButton
     v-if="showExpand"
-    :icon="useIcon({ icon: visible ? 'ant-design:up-outlined' : 'ant-design:down-outlined' })"
+    :icon="useIcon({ icon: visible ? 'ep:arrow-down' : 'ep:arrow-up' })"
     text
     @click="onExpand"
   >

+ 1 - 1
src/components/Setting/src/Setting.vue

@@ -202,7 +202,7 @@ const clear = () => {
 <template>
   <div
     :class="prefixCls"
-    class="fixed top-[45%] right-0 w-40px h-40px flex items-center justify-center bg-[var(--el-color-primary)] cursor-pointer"
+    class="fixed top-[45%] right-0 w-40px h-40px flex items-center justify-center bg-[var(--el-color-primary)] cursor-pointer z-10"
     @click="drawer = true"
   >
     <Icon icon="ant-design:setting-outlined" color="#fff" />

+ 1 - 1
src/hooks/web/useConfigGlobal.ts

@@ -1,4 +1,4 @@
-import { ConfigGlobalTypes } from '@/components/ConfigGlobal/src/types'
+import { ConfigGlobalTypes } from '@/components/ConfigGlobal'
 import { inject } from 'vue'
 
 export const useConfigGlobal = () => {

+ 16 - 16
src/router/index.ts

@@ -222,24 +222,24 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
         meta: {
           title: t('router.search')
         }
+      },
+      {
+        path: 'descriptions',
+        component: () => import('@/views/Components/Descriptions.vue'),
+        name: 'Descriptions',
+        meta: {
+          title: t('router.descriptions')
+        }
+      },
+      {
+        path: 'image-viewer',
+        component: () => import('@/views/Components/ImageViewer.vue'),
+        name: 'ImageViewer',
+        meta: {
+          title: t('router.imageViewer')
+        }
       }
       // {
-      //   path: 'descriptions',
-      //   component: () => import('@/views/Components/Descriptions.vue'),
-      //   name: 'Descriptions',
-      //   meta: {
-      //     title: t('router.descriptions')
-      //   }
-      // },
-      // {
-      //   path: 'image-viewer',
-      //   component: () => import('@/views/Components/ImageViewer.vue'),
-      //   name: 'ImageViewer',
-      //   meta: {
-      //     title: t('router.imageViewer')
-      //   }
-      // },
-      // {
       //   path: 'dialog',
       //   component: () => import('@/views/Components/Dialog.vue'),
       //   name: 'Dialog',

+ 99 - 52
src/views/Components/Descriptions.vue

@@ -1,12 +1,12 @@
-<script setup lang="ts">
+<script setup lang="tsx">
 import { Descriptions } from '@/components/Descriptions'
 import { useI18n } from '@/hooks/web/useI18n'
-import { reactive, unref } from 'vue'
+import { reactive } from 'vue'
 import { Form } from '@/components/Form'
 import { ElFormItem, ElInput, ElButton } from 'element-plus'
 import { useValidator } from '@/hooks/web/useValidator'
 import { useForm } from '@/hooks/web/useForm'
-import { DescriptionsSchema } from '@/types/descriptions'
+import { DescriptionsSchema } from '@/components/Descriptions'
 
 const { required } = useValidator()
 
@@ -40,10 +40,92 @@ const schema = reactive<DescriptionsSchema[]>([
     field: 'email',
     label: t('descriptionsDemo.email')
   },
+  {
+    field: 'addr',
+    label: t('descriptionsDemo.addr')
+  }
+])
+
+const schema2 = reactive<DescriptionsSchema[]>([
+  {
+    field: 'username',
+    label: t('descriptionsDemo.username'),
+    slots: {
+      label: (row) => {
+        return <span class="is-required--item">{row.label}</span>
+      },
+      default: () => {
+        return (
+          <ElFormItem prop="username">
+            <ElInput v-model={form.username} />
+          </ElFormItem>
+        )
+      }
+    }
+  },
+  {
+    field: 'nickName',
+    label: t('descriptionsDemo.nickName'),
+    slots: {
+      label: (row) => {
+        return <span class="is-required--item">{row.label}</span>
+      },
+      default: () => {
+        return (
+          <ElFormItem prop="nickName">
+            <ElInput v-model={form.nickName} />
+          </ElFormItem>
+        )
+      }
+    }
+  },
+  {
+    field: 'phone',
+    label: t('descriptionsDemo.phone'),
+    slots: {
+      label: (row) => {
+        return <span class="is-required--item">{row.label}</span>
+      },
+      default: () => {
+        return (
+          <ElFormItem prop="phone">
+            <ElInput v-model={form.phone} />
+          </ElFormItem>
+        )
+      }
+    }
+  },
+  {
+    field: 'email',
+    label: t('descriptionsDemo.email'),
+    slots: {
+      label: (row) => {
+        return <span class="is-required--item">{row.label}</span>
+      },
+      default: () => {
+        return (
+          <ElFormItem prop="email">
+            <ElInput v-model={form.email} />
+          </ElFormItem>
+        )
+      }
+    }
+  },
   {
     field: 'addr',
     label: t('descriptionsDemo.addr'),
-    span: 24
+    slots: {
+      label: (row) => {
+        return <span class="is-required--item">{row.label}</span>
+      },
+      default: () => {
+        return (
+          <ElFormItem prop="addr">
+            <ElInput v-model={form.addr} />
+          </ElFormItem>
+        )
+      }
+    }
   }
 ])
 
@@ -63,10 +145,12 @@ const rules = reactive({
   addr: [required()]
 })
 
-const { register, elFormRef } = useForm()
+const { formRegister, formMethods } = useForm()
+const { getElFormExpose } = formMethods
 
-const formValidation = () => {
-  unref(elFormRef)!.validate((isValid) => {
+const formValidation = async () => {
+  const elFormExpose = await getElFormExpose()
+  elFormExpose?.validate((isValid) => {
     console.log(isValid)
   })
 }
@@ -80,50 +164,13 @@ const formValidation = () => {
     :schema="schema"
   />
 
-  <Form is-custom :model="form" :rules="rules" @register="register">
-    <Descriptions :title="t('descriptionsDemo.form')" :data="data" :schema="schema" class="mt-20px">
-      <template #username-label="{ row }">
-        <span class="is-required--item">{{ row.label }}</span>
-      </template>
-      <template #nickName-label="{ row }">
-        <span class="is-required--item">{{ row.label }}</span>
-      </template>
-      <template #phone-label="{ row }">
-        <span class="is-required--item">{{ row.label }}</span>
-      </template>
-      <template #email-label="{ row }">
-        <span class="is-required--item">{{ row.label }}</span>
-      </template>
-      <template #addr-label="{ row }">
-        <span class="is-required--item">{{ row.label }}</span>
-      </template>
-
-      <template #username>
-        <ElFormItem prop="username">
-          <ElInput v-model="form.username" />
-        </ElFormItem>
-      </template>
-      <template #nickName>
-        <ElFormItem prop="nickName">
-          <ElInput v-model="form.nickName" />
-        </ElFormItem>
-      </template>
-      <template #phone>
-        <ElFormItem prop="phone">
-          <ElInput v-model="form.phone" />
-        </ElFormItem>
-      </template>
-      <template #email>
-        <ElFormItem prop="email">
-          <ElInput v-model="form.email" />
-        </ElFormItem>
-      </template>
-      <template #addr>
-        <ElFormItem prop="addr">
-          <ElInput v-model="form.addr" />
-        </ElFormItem>
-      </template>
-    </Descriptions>
+  <Form is-custom :model="form" :rules="rules" @register="formRegister">
+    <Descriptions
+      :title="t('descriptionsDemo.form')"
+      :data="data"
+      :schema="schema2"
+      class="mt-20px"
+    />
     <div class="text-center mt-10px">
       <ElButton @click="formValidation"> {{ t('formDemo.formValidation') }} </ElButton>
     </div>
@@ -131,7 +178,7 @@ const formValidation = () => {
 </template>
 
 <style lang="less" scoped>
-.is-required--item {
+:deep(.is-required--item) {
   position: relative;
 
   &::before {

+ 4 - 4
uno.config.ts

@@ -40,7 +40,7 @@ ${selector}:before {
   width: 1px;
   height: 100%;
   background-color: var(--layout-border-color);
-  z-index: 10;
+  z-index: 3;
 }
 `
       }
@@ -58,7 +58,7 @@ ${selector}:after {
   width: 1px;
   height: 100%;
   background-color: var(--layout-border-color);
-  z-index: 10;
+  z-index: 3;
 }
 `
       }
@@ -76,7 +76,7 @@ ${selector}:before {
   width: 100%;
   height: 1px;
   background-color: var(--layout-border-color);
-  z-index: 10;
+  z-index: 3;
 }
 `
       }
@@ -94,7 +94,7 @@ ${selector}:after {
   width: 100%;
   height: 1px;
   background-color: var(--layout-border-color);
-  z-index: 10;
+  z-index: 3;
 }
 `
       }