Browse Source

wip: example demo developing

陈凯龙 3 years ago
parent
commit
ef35bde801

+ 33 - 2
mock/table/index.ts

@@ -12,7 +12,7 @@ const count = 100
 const baseContent =
   '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
 
-const List: {
+let List: {
   id: string
   author: string
   title: string
@@ -39,7 +39,7 @@ for (let i = 0; i < count; i++) {
 }
 
 export default [
-  // 登录接口
+  // 列表接口
   {
     url: '/example/list',
     method: 'get',
@@ -61,5 +61,36 @@ export default [
         }
       }
     }
+  },
+  // 保存接口
+  {
+    url: '/example/save',
+    method: 'post',
+    timeout,
+    response: ({ body }) => {
+      if (!body.id) {
+        List = [
+          Object.assign(body, {
+            id: toAnyString()
+          })
+        ].concat(List)
+        return {
+          code: result_code,
+          data: 'success'
+        }
+      } else {
+        List.map((item) => {
+          if (item.id === body.id) {
+            for (const key in item) {
+              item[key] = body[key]
+            }
+          }
+        })
+        return {
+          code: result_code,
+          data: 'success'
+        }
+      }
+    }
   }
 ] as MockMethod[]

+ 4 - 0
src/api/table/index.ts

@@ -9,3 +9,7 @@ export const getTableListApi = ({ params }: AxiosConfig) => {
     list: TableData[]
   }>({ url: '/example/list', method: 'get', params })
 }
+
+export const saveTableApi = ({ data }: AxiosConfig) => {
+  return request({ url: '/example/save', method: 'post', data })
+}

+ 3 - 1
src/components/Form/src/componentMap.ts

@@ -19,6 +19,7 @@ import {
   ElDivider
 } from 'element-plus'
 import { InputPassword } from '@/components/InputPassword'
+import { Editor } from '@/components/Editor'
 
 const componentMap: Recordable<Component, ComponentName> = {
   Radio: ElRadioGroup,
@@ -40,7 +41,8 @@ const componentMap: Recordable<Component, ComponentName> = {
   TimeSelect: ElTimeSelect,
   SelectV2: ElSelectV2,
   RadioButton: ElRadioGroup,
-  InputPassword: InputPassword
+  InputPassword: InputPassword,
+  Editor: Editor
 }
 
 export { componentMap }

+ 1 - 1
src/components/Form/src/helper.ts

@@ -57,7 +57,7 @@ export const setGridProp = (col: ColProps = {}): ColProps => {
           sm: 12,
           md: 12,
           lg: 12,
-          xl: 8
+          xl: 12
         }),
     ...col
   }

+ 2 - 2
src/components/Search/src/Search.vue

@@ -112,7 +112,7 @@ const setVisible = () => {
           <Icon icon="ep:refresh-right" class="mr-5px" />
           {{ t('common.reset') }}
         </ElButton>
-        <ElButton v-if="showReset" type="text" @click="setVisible">
+        <ElButton v-if="expand" type="text" @click="setVisible">
           {{ t(visible ? 'common.shrink' : 'common.expand') }}
           <Icon :icon="visible ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
         </ElButton>
@@ -130,7 +130,7 @@ const setVisible = () => {
         <Icon icon="ep:refresh-right" class="mr-5px" />
         {{ t('common.reset') }}
       </ElButton>
-      <ElButton v-if="showReset" type="text" @click="setVisible">
+      <ElButton v-if="expand" type="text" @click="setVisible">
         {{ t(visible ? 'common.shrink' : 'common.expand') }}
         <Icon :icon="visible ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
       </ElButton>

+ 2 - 3
src/components/Table/src/Table.vue

@@ -259,13 +259,12 @@ export default defineComponent({
     }
 
     return () => (
-      <>
+      <div v-loading={unref(getProps).loading}>
         <ElTable
           // @ts-ignore
           ref={elTableRef}
           data={unref(getProps).data}
           {...getBindValue}
-          v-loading={unref(getProps).loading}
         >
           {{
             default: () => rnderTableColumn(),
@@ -281,7 +280,7 @@ export default defineComponent({
             {...unref(pagination)}
           ></ElPagination>
         ) : undefined}
-      </>
+      </div>
     )
   }
 })

+ 20 - 1
src/hooks/web/useTable.ts

@@ -22,6 +22,8 @@ interface TableObject<K, L> {
   tableList: K[]
   parmasObj: L
   loading: boolean
+  dialogVisible: boolean
+  currentRow: Nullable<K>
 }
 
 export const useTable = <T, K, L extends AxiosConfig = AxiosConfig>(
@@ -39,7 +41,11 @@ export const useTable = <T, K, L extends AxiosConfig = AxiosConfig>(
     // AxiosConfig 配置
     parmasObj: {} as L,
     // 加载中
-    loading: true
+    loading: true,
+    // 弹窗
+    dialogVisible: false,
+    // 当前行的数据
+    currentRow: null
   })
 
   const parmasObj = computed(() => {
@@ -93,6 +99,7 @@ export const useTable = <T, K, L extends AxiosConfig = AxiosConfig>(
     setProps: (props: Recordable) => void
     getList: () => Promise<void>
     setColumn: (columnProps: TableSetPropsType[]) => void
+    setSearchParmas: (data: Recordable) => void
   } = {
     getList: async () => {
       tableObject.loading = true
@@ -114,6 +121,18 @@ export const useTable = <T, K, L extends AxiosConfig = AxiosConfig>(
     setColumn: async (columnProps: TableSetPropsType[]) => {
       const table = await getTable()
       table?.setColumn(columnProps)
+    },
+    // 与Search组件结合
+    setSearchParmas: (data: Recordable) => {
+      tableObject.currentPage = 1
+      tableObject.parmasObj = Object.assign(tableObject.parmasObj, {
+        params: {
+          pageSize: tableObject.pageSize,
+          pageIndex: tableObject.currentPage,
+          ...data
+        }
+      })
+      methods.getList()
     }
   }
 

+ 16 - 1
src/locales/en.ts

@@ -107,7 +107,9 @@ export default {
     richText: 'Rich text',
     dialog: 'Dialog',
     imageViewer: 'Image viewer',
-    descriptions: 'Descriptions'
+    descriptions: 'Descriptions',
+    example: 'Example',
+    exampleDialog: 'Example dialog'
   },
   analysis: {
     newUser: 'New user',
@@ -360,5 +362,18 @@ export default {
     email: 'Email',
     addr: 'Address',
     form: 'Combined with Form component'
+  },
+  exampleDemo: {
+    title: 'Title',
+    add: 'Add',
+    del: 'Delete',
+    edit: 'Edit',
+    author: 'Author',
+    displayTime: 'Display time',
+    importance: 'Importance',
+    pageviews: 'Pageviews',
+    important: 'Important',
+    content: 'Content',
+    save: 'Save'
   }
 }

+ 16 - 1
src/locales/zh-CN.ts

@@ -107,7 +107,9 @@ export default {
     richText: '富文本',
     dialog: '弹窗',
     imageViewer: '图片预览',
-    descriptions: '描述'
+    descriptions: '描述',
+    example: '综合示例',
+    exampleDialog: '综合示例 - 弹窗'
   },
   analysis: {
     newUser: '新增用户',
@@ -357,5 +359,18 @@ export default {
     email: '邮箱',
     addr: '地址',
     form: '与 Form 组件组合'
+  },
+  exampleDemo: {
+    title: '标题',
+    add: '新增',
+    del: '删除',
+    edit: '编辑',
+    author: '作者',
+    displayTime: '创建时间',
+    importance: '重要性',
+    pageviews: '阅读数',
+    important: '重要',
+    content: '内容',
+    save: '保存'
   }
 }

+ 21 - 0
src/router/index.ts

@@ -333,6 +333,27 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
         }
       }
     ]
+  },
+  {
+    path: '/example',
+    component: Layout,
+    redirect: '/example/example-dialog',
+    name: 'Example',
+    meta: {
+      title: t('router.example'),
+      icon: 'ep:management',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'example-dialog',
+        component: () => import('@/views/Example/Dialog/ExampleDialog.vue'),
+        name: 'ExampleDialog',
+        meta: {
+          title: t('router.exampleDialog')
+        }
+      }
+    ]
   }
 ]
 

+ 170 - 0
src/views/Example/Dialog/ExampleDialog.vue

@@ -0,0 +1,170 @@
+<script setup lang="ts">
+import { ContentWrap } from '@/components/ContentWrap'
+import { Search } from '@/components/Search'
+import { Dialog } from '@/components/Dialog'
+import { useI18n } from '@/hooks/web/useI18n'
+import { ElButton, ElTag } from 'element-plus'
+import { Table } from '@/components/Table'
+import { getTableListApi, saveTableApi } from '@/api/table'
+import { useTable } from '@/hooks/web/useTable'
+import { TableData } from '@/api/table/types'
+import { h, reactive, ref, unref } from 'vue'
+import Write from './components/Write.vue'
+
+const { register, tableObject, methods } = useTable<
+  {
+    total: number
+    list: TableData[]
+  },
+  TableData
+>({
+  getListApi: getTableListApi,
+  response: {
+    list: 'list',
+    total: 'total'
+  }
+})
+
+const { getList, setSearchParmas } = methods
+
+getList()
+
+const { t } = useI18n()
+
+const searchData: FormSchema[] = [
+  {
+    label: t('exampleDemo.title'),
+    value: '',
+    component: 'Input',
+    field: 'title'
+  }
+]
+
+const columns = reactive<TableColumn[]>([
+  {
+    field: 'index',
+    label: t('tableDemo.index'),
+    type: 'index'
+  },
+  {
+    field: 'content',
+    label: t('tableDemo.header'),
+    children: [
+      {
+        field: 'title',
+        label: t('tableDemo.title')
+      },
+      {
+        field: 'author',
+        label: t('tableDemo.author')
+      },
+      {
+        field: 'display_time',
+        label: t('tableDemo.displayTime')
+      },
+      {
+        field: 'importance',
+        label: t('tableDemo.importance'),
+        formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
+          return h(
+            ElTag,
+            {
+              type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
+            },
+            () =>
+              cellValue === 1
+                ? t('tableDemo.important')
+                : cellValue === 2
+                ? t('tableDemo.good')
+                : t('tableDemo.commonly')
+          )
+        }
+      },
+      {
+        field: 'pageviews',
+        label: t('tableDemo.pageviews')
+      }
+    ]
+  },
+  {
+    field: 'action',
+    label: t('tableDemo.action')
+  }
+])
+
+const AddAction = () => {
+  tableObject.currentRow = null
+  tableObject.dialogVisible = true
+}
+
+const editAction = (row: TableData) => {
+  tableObject.currentRow = row
+  tableObject.dialogVisible = true
+}
+
+const writeRef = ref<ComponentRef<typeof Write>>()
+
+const loading = ref(false)
+
+const save = async () => {
+  loading.value = true
+  const write = unref(writeRef)
+  const validate = await write?.elFormRef?.validate()?.catch(() => {})
+  if (validate) {
+    const data = await write?.getFormData()
+
+    const res = await saveTableApi({
+      data
+    })
+      .catch(() => {})
+      .finally(() => {
+        loading.value = false
+      })
+    if (res) {
+      tableObject.dialogVisible = false
+      tableObject.currentPage = 1
+      getList()
+    }
+  }
+}
+</script>
+
+<template>
+  <ContentWrap>
+    <Search :schema="searchData" @search="setSearchParmas" @reset="setSearchParmas" />
+
+    <div class="mb-10px">
+      <ElButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</ElButton>
+      <ElButton type="danger">{{ t('exampleDemo.del') }}</ElButton>
+    </div>
+
+    <Table
+      v-model:pageSize="tableObject.pageSize"
+      v-model:currentPage="tableObject.currentPage"
+      :columns="columns"
+      :data="tableObject.tableList"
+      :loading="tableObject.loading"
+      :pagination="{
+        total: tableObject.total
+      }"
+      @register="register"
+    >
+      <template #action="{ row }">
+        <ElButton type="primary" @click="editAction(row)">
+          {{ t('exampleDemo.edit') }}
+        </ElButton>
+      </template>
+    </Table>
+  </ContentWrap>
+
+  <Dialog v-model="tableObject.dialogVisible" :title="t('exampleDemo.add')">
+    <Write ref="writeRef" :current-row="tableObject.currentRow" />
+
+    <template #footer>
+      <ElButton type="primary" :loading="loading" @click="save">
+        {{ t('exampleDemo.save') }}
+      </ElButton>
+      <ElButton @click="tableObject.dialogVisible = false">{{ t('dialogDemo.close') }}</ElButton>
+    </template>
+  </Dialog>
+</template>

+ 136 - 0
src/views/Example/Dialog/components/Write.vue

@@ -0,0 +1,136 @@
+<script setup lang="ts">
+import { Form } from '@/components/Form'
+import { useForm } from '@/hooks/web/useForm'
+import { PropType, reactive } from 'vue'
+import { TableData } from '@/api/table/types'
+import { useI18n } from '@/hooks/web/useI18n'
+import { required } from '@/utils/formRules'
+import { IDomEditor } from '@wangeditor/editor'
+
+const props = defineProps({
+  currentRow: {
+    type: Object as PropType<Nullable<TableData>>,
+    default: () => null
+  }
+})
+
+const { t } = useI18n()
+
+const schema = reactive<FormSchema[]>([
+  {
+    field: 'title',
+    label: t('exampleDemo.title'),
+    component: 'Input',
+    formItemProps: {
+      rules: [required]
+    },
+    colProps: {
+      span: 24
+    }
+  },
+  {
+    field: 'author',
+    label: t('exampleDemo.author'),
+    component: 'Input',
+    formItemProps: {
+      rules: [required]
+    }
+  },
+  {
+    field: 'display_time',
+    label: t('exampleDemo.displayTime'),
+    component: 'DatePicker',
+    componentProps: {
+      type: 'datetime',
+      valueFormat: 'YYYY-MM-DD HH:mm:ss'
+    },
+    formItemProps: {
+      rules: [required]
+    }
+  },
+  {
+    field: 'importance',
+    label: t('exampleDemo.importance'),
+    component: 'Select',
+    formItemProps: {
+      rules: [required]
+    },
+    componentProps: {
+      options: [
+        {
+          label: '重要',
+          value: 3
+        },
+        {
+          label: '良好',
+          value: 2
+        },
+        {
+          label: '一般',
+          value: 1
+        }
+      ]
+    }
+  },
+  {
+    field: 'pageviews',
+    label: t('exampleDemo.pageviews'),
+    component: 'InputNumber',
+    value: 0,
+    formItemProps: {
+      rules: [required]
+    }
+  },
+  {
+    field: 'content',
+    component: 'Editor',
+    colProps: {
+      span: 24
+    },
+    componentProps: {
+      defaultHtml: '',
+      onChange: (edit: IDomEditor) => {
+        const { setValues } = methods
+        setValues({
+          content: edit.getHtml()
+        })
+      }
+    },
+    label: t('exampleDemo.content')
+  }
+])
+
+const rules = reactive({
+  title: [required],
+  author: [required],
+  importance: [required],
+  pageviews: [required],
+  display_time: [required],
+  content: [required]
+})
+
+const { register, methods, elFormRef } = useForm({
+  schema
+})
+
+if (props.currentRow) {
+  const { setValues, setSchema } = methods
+  setValues(props.currentRow)
+  setSchema([
+    {
+      field: 'content',
+      path: 'componentProps.defaultHtml',
+      value: props.currentRow.content
+    }
+  ])
+}
+
+defineExpose({
+  elFormRef,
+  getFormData: methods.getFormData
+})
+</script>
+
+<template>
+  <Form :rules="rules" @register="register" />
+</template>

+ 1 - 0
types/componentType/form.d.ts

@@ -22,6 +22,7 @@ declare global {
     | 'TimeSelect'
     | 'SelectV2'
     | 'InputPassword'
+    | 'Editor'
 
   declare type ColProps = {
     span?: number