Quellcode durchsuchen

feat: 部门管理

kailong321200875 vor 1 Jahr
Ursprung
Commit
28d0785be8

+ 85 - 6
mock/department/index.ts

@@ -14,36 +14,65 @@ for (let i = 0; i < 5; i++) {
     // 部门名称
     departmentName: citys[i],
     id: toAnyString(),
+    createTime: '@datetime',
+    // 状态
+    status: Mock.Random.integer(0, 1),
+    // 备注
+    remark: '@cword(10, 15)',
     children: [
       {
         // 部门名称
         departmentName: '研发部',
-        id: toAnyString()
+        createTime: '@datetime',
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
       },
       {
         // 部门名称
         departmentName: '产品部',
-        id: toAnyString()
+        createTime: '@datetime',
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
       },
       {
         // 部门名称
         departmentName: '运营部',
-        id: toAnyString()
+        createTime: '@datetime',
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
       },
       {
         // 部门名称
         departmentName: '市场部',
-        id: toAnyString()
+        createTime: '@datetime',
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
       },
       {
         // 部门名称
         departmentName: '销售部',
-        id: toAnyString()
+        createTime: '@datetime',
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
       },
       {
         // 部门名称
         departmentName: '客服部',
-        id: toAnyString()
+        createTime: '@datetime',
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
       }
     ]
   })
@@ -65,6 +94,21 @@ export default [
       }
     }
   },
+  {
+    url: '/department/table/list',
+    method: 'get',
+    response: () => {
+      return {
+        data: {
+          code: code,
+          data: {
+            list: departmentList,
+            total: 5
+          }
+        }
+      }
+    }
+  },
   {
     url: '/department/users',
     method: 'get',
@@ -136,5 +180,40 @@ export default [
         }
       }
     }
+  },
+  // 保存接口
+  {
+    url: '/department/save',
+    method: 'post',
+    timeout: 1000,
+    response: () => {
+      return {
+        data: {
+          code: code,
+          data: 'success'
+        }
+      }
+    }
+  },
+  // 删除接口
+  {
+    url: '/department/delete',
+    method: 'post',
+    response: ({ body }) => {
+      const ids = body.ids
+      if (!ids) {
+        return {
+          code: '500',
+          message: '请选择需要删除的数据'
+        }
+      } else {
+        return {
+          data: {
+            code: code,
+            data: 'success'
+          }
+        }
+      }
+    }
   }
 ] as MockMethod[]

+ 12 - 0
src/api/department/index.ts

@@ -16,3 +16,15 @@ export const deleteUserByIdApi = (ids: string[] | number[]) => {
 export const saveUserApi = (data: any) => {
   return request.post({ url: '/department/user/save', data })
 }
+
+export const saveDepartmentApi = (data: any) => {
+  return request.post({ url: '/department/save', data })
+}
+
+export const deleteDepartmentApi = (ids: string[] | number[]) => {
+  return request.post({ url: '/department/delete', data: { ids } })
+}
+
+export const getDepartmentTableApi = (params: any) => {
+  return request.get({ url: '/department/table/list', params })
+}

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

@@ -24,7 +24,7 @@ import { useRenderRadio } from './components/useRenderRadio'
 import { useRenderCheckbox } from './components/useRenderCheckbox'
 import { useDesign } from '@/hooks/web/useDesign'
 import { findIndex } from '@/utils'
-import { set } from 'lodash-es'
+import { get, set } from 'lodash-es'
 import { FormProps } from './types'
 import {
   FormSchema,
@@ -319,18 +319,18 @@ export default defineComponent({
 
             const Comp = () => {
               // 如果field是多层路径,需要转换成对象
-              const fields = item.field.split('.')
-              // 循环fields,绑定v-model
-              const vModel = fields.reduce((prev, next, index) => {
-                if (index === 0) {
-                  return formModel.value[next]
+              const itemVal = computed({
+                get: () => {
+                  return get(formModel.value, item.field)
+                },
+                set: (val) => {
+                  set(formModel.value, item.field, val)
                 }
-                return prev[next]
-              }, {})
+              })
 
               return (
                 <Com
-                  vModel={vModel}
+                  vModel={itemVal.value}
                   ref={(el: any) => setComponentRefMap(el, item.field)}
                   {...(autoSetPlaceholder && setTextPlaceholder(item))}
                   {...setComponentProps(item)}

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

@@ -150,7 +150,11 @@ export const initModel = (schema: FormSchema[], formModel: Recordable) => {
       // const hasField = Reflect.has(model, v.field)
       const hasField = get(model, v.field)
       // 如果先前已经有值存在,则不进行重新赋值,而是采用现有的值
-      set(model, v.field, hasField ? get(model, v.field) : v.value !== void 0 ? v.value : undefined)
+      set(
+        model,
+        v.field,
+        hasField !== void 0 ? get(model, v.field) : v.value !== void 0 ? v.value : undefined
+      )
       // model[v.field] = hasField ? model[v.field] : v.value !== void 0 ? v.value : undefined
     }
   })

+ 16 - 5
src/components/Search/src/Search.vue

@@ -9,6 +9,7 @@ import { initModel } from '@/components/Form/src/helper'
 import ActionButton from './components/ActionButton.vue'
 import { SearchProps } from './types'
 import { FormItemProp } from 'element-plus'
+import { isObject, isEmptyVal } from '@/utils/is'
 
 const props = defineProps({
   // 生成Form的布局结构数组
@@ -130,12 +131,22 @@ watch(
 
 const filterModel = async () => {
   const model = await getFormData()
-  unref(getProps).removeNoValueItem &&
-    Object.keys(model).forEach((key) => {
-      if (model[key] === void 0 || model[key] === '') {
-        delete model[key]
+  if (unref(getProps).removeNoValueItem) {
+    // 使用reduce过滤空值,并返回一个新对象
+    return Object.keys(model).reduce((prev, next) => {
+      const value = model[next]
+      if (!isEmptyVal(value)) {
+        if (isObject(value)) {
+          if (Object.keys(value).length > 0) {
+            prev[next] = value
+          }
+        } else {
+          prev[next] = value
+        }
       }
-    })
+      return prev
+    }, {})
+  }
   return model
 }
 

+ 8 - 2
src/locales/en.ts

@@ -160,7 +160,8 @@ export default {
     inputPassword: 'InputPassword',
     sticky: 'Sticky',
     treeTable: 'Tree table',
-    PicturePreview: 'Table Image Preview'
+    PicturePreview: 'Table Image Preview',
+    department: 'Department management'
   },
   permission: {
     hasPermission: 'Please set the operation permission value'
@@ -496,7 +497,12 @@ export default {
     email: 'Email',
     createTime: 'Create time',
     // 所属部门
-    department: 'Department'
+    department: 'Department',
+    departmentName: 'Department name',
+    status: 'Status',
+    enable: 'Enable',
+    disable: 'Disable',
+    superiorDepartment: 'Superior department'
   },
   inputPasswordDemo: {
     title: 'InputPassword',

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

@@ -160,7 +160,8 @@ export default {
     inputPassword: '密码输入框',
     sticky: '黏性',
     treeTable: '树形表格',
-    PicturePreview: '表格图片预览'
+    PicturePreview: '表格图片预览',
+    department: '部门管理'
   },
   permission: {
     hasPermission: '请设置操作权限值'
@@ -488,7 +489,15 @@ export default {
     email: '邮箱',
     createTime: '创建时间',
     // 所属部门
-    department: '所属部门'
+    department: '所属部门',
+    departmentName: '部门名称',
+    status: '状态',
+    // 启用
+    enable: '启用',
+    // 禁用
+    disable: '禁用',
+    // 上级部门
+    superiorDepartment: '上级部门'
   },
   inputPasswordDemo: {
     title: '密码输入框',

+ 9 - 1
src/router/index.ts

@@ -519,7 +519,7 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
     children: [
       {
         path: 'user',
-        component: () => import('@/views/Authorization/User.vue'),
+        component: () => import('@/views/Authorization/User/User.vue'),
         name: 'User',
         meta: {
           title: t('router.user')
@@ -532,6 +532,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
         meta: {
           title: t('router.role')
         }
+      },
+      {
+        path: 'department',
+        component: () => import('@/views/Authorization/Department/Department.vue'),
+        name: 'Department',
+        meta: {
+          title: t('router.department')
+        }
       }
     ]
   }

+ 4 - 0
src/utils/is.ts

@@ -108,3 +108,7 @@ export const isDark = (): boolean => {
 export const isImgPath = (path: string): boolean => {
   return /(https?:\/\/|data:image\/).*?\.(png|jpg|jpeg|gif|svg|webp|ico)/gi.test(path)
 }
+
+export const isEmptyVal = (val: any): boolean => {
+  return val === '' || val === null || val === undefined
+}

+ 337 - 0
src/views/Authorization/Department/Department.vue

@@ -0,0 +1,337 @@
+<script setup lang="tsx">
+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 {
+  getDepartmentApi,
+  getDepartmentTableApi,
+  saveDepartmentApi,
+  deleteDepartmentApi
+} from '@/api/department'
+import { useTable } from '@/hooks/web/useTable'
+import { TableData } from '@/api/table/types'
+import { ref, unref, reactive } from 'vue'
+import Write from './components/Write.vue'
+import Detail from './components/Detail.vue'
+import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
+
+const ids = ref<string[]>([])
+
+const { tableRegister, tableState, tableMethods } = useTable({
+  fetchDataApi: async () => {
+    const { currentPage, pageSize } = tableState
+    const res = await getDepartmentTableApi({
+      pageIndex: unref(currentPage),
+      pageSize: unref(pageSize),
+      ...unref(searchParams)
+    })
+    return {
+      list: res.data.list,
+      total: res.data.total
+    }
+  },
+  fetchDelApi: async () => {
+    const res = await deleteDepartmentApi(unref(ids))
+    return !!res
+  }
+})
+const { loading, dataList, total, currentPage, pageSize } = tableState
+const { getList, getElTableExpose, delList } = tableMethods
+
+const searchParams = ref({})
+const setSearchParams = (params: any) => {
+  searchParams.value = params
+  getList()
+}
+
+const { t } = useI18n()
+
+const crudSchemas = reactive<CrudSchema[]>([
+  {
+    field: 'selection',
+    search: {
+      hidden: true
+    },
+    form: {
+      hidden: true
+    },
+    detail: {
+      hidden: true
+    },
+    table: {
+      type: 'selection'
+    }
+  },
+  {
+    field: 'index',
+    label: t('tableDemo.index'),
+    type: 'index',
+    search: {
+      hidden: true
+    },
+    form: {
+      hidden: true
+    },
+    detail: {
+      hidden: true
+    }
+  },
+  {
+    field: 'id',
+    label: t('userDemo.departmentName'),
+    table: {
+      slots: {
+        default: (data: any) => {
+          return <>{data[0].row.departmentName}</>
+        }
+      }
+    },
+    form: {
+      component: 'TreeSelect',
+      componentProps: {
+        nodeKey: 'id',
+        props: {
+          label: 'departmentName'
+        }
+      },
+      optionApi: async () => {
+        const res = await getDepartmentApi()
+        return res.data.list
+      }
+    },
+    detail: {
+      slots: {
+        default: (data: any) => {
+          return <>{data.departmentName}</>
+        }
+      }
+    }
+  },
+  {
+    field: 'status',
+    label: t('userDemo.status'),
+    search: {
+      hidden: true
+    },
+    table: {
+      slots: {
+        default: (data: any) => {
+          const status = data[0].row.status
+          return (
+            <>
+              <ElTag type={status === 0 ? 'danger' : 'success'}>
+                {status === 1 ? t('userDemo.enable') : t('userDemo.disable')}
+              </ElTag>
+            </>
+          )
+        }
+      }
+    },
+    form: {
+      component: 'Select',
+      componentProps: {
+        options: [
+          {
+            value: 0,
+            label: t('userDemo.disable')
+          },
+          {
+            value: 1,
+            label: t('userDemo.enable')
+          }
+        ]
+      }
+    },
+    detail: {
+      slots: {
+        default: (data: any) => {
+          return (
+            <>
+              <ElTag type={data.status === 0 ? 'danger' : 'success'}>
+                {data.status === 1 ? t('userDemo.enable') : t('userDemo.disable')}
+              </ElTag>
+            </>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'createTime',
+    label: t('tableDemo.displayTime'),
+    search: {
+      hidden: true
+    },
+    form: {
+      component: 'DatePicker',
+      componentProps: {
+        type: 'datetime',
+        valueFormat: 'YYYY-MM-DD HH:mm:ss'
+      }
+    }
+  },
+  {
+    field: 'remark',
+    label: t('userDemo.remark'),
+    search: {
+      hidden: true
+    },
+    form: {
+      component: 'Input',
+      componentProps: {
+        type: 'textarea',
+        rows: 5
+      },
+      colProps: {
+        span: 24
+      }
+    },
+    detail: {
+      slots: {
+        default: (data: any) => {
+          return <>{data.remark}</>
+        }
+      }
+    }
+  },
+  {
+    field: 'action',
+    width: '260px',
+    label: t('tableDemo.action'),
+    search: {
+      hidden: true
+    },
+    form: {
+      hidden: true
+    },
+    detail: {
+      hidden: true
+    },
+    table: {
+      slots: {
+        default: (data: any) => {
+          return (
+            <>
+              <ElButton type="primary" onClick={() => action(data[0].row, 'edit')}>
+                {t('exampleDemo.edit')}
+              </ElButton>
+              <ElButton type="success" onClick={() => action(data[0].row, 'detail')}>
+                {t('exampleDemo.detail')}
+              </ElButton>
+              <ElButton type="danger" onClick={() => delData(data[0].row)}>
+                {t('exampleDemo.del')}
+              </ElButton>
+            </>
+          )
+        }
+      }
+    }
+  }
+])
+
+// @ts-ignore
+const { allSchemas } = useCrudSchemas(crudSchemas)
+
+const dialogVisible = ref(false)
+const dialogTitle = ref('')
+
+const currentRow = ref<TableData | null>(null)
+const actionType = ref('')
+
+const AddAction = () => {
+  dialogTitle.value = t('exampleDemo.add')
+  currentRow.value = null
+  dialogVisible.value = true
+  actionType.value = ''
+}
+
+const delLoading = ref(false)
+
+const delData = async (row: TableData | null) => {
+  const elTableExpose = await getElTableExpose()
+  ids.value = row ? [row.id] : elTableExpose?.getSelectionRows().map((v: TableData) => v.id) || []
+  delLoading.value = true
+  await delList(unref(ids).length).finally(() => {
+    delLoading.value = false
+  })
+}
+
+const action = (row: TableData, type: string) => {
+  dialogTitle.value = t(type === 'edit' ? 'exampleDemo.edit' : 'exampleDemo.detail')
+  actionType.value = type
+  currentRow.value = row
+  dialogVisible.value = true
+}
+
+const writeRef = ref<ComponentRef<typeof Write>>()
+
+const saveLoading = ref(false)
+
+const save = async () => {
+  const write = unref(writeRef)
+  const formData = await write?.submit()
+  if (formData) {
+    saveLoading.value = true
+    const res = await saveDepartmentApi(formData)
+      .catch(() => {})
+      .finally(() => {
+        saveLoading.value = false
+      })
+    if (res) {
+      dialogVisible.value = false
+      currentPage.value = 1
+      getList()
+    }
+  }
+}
+</script>
+
+<template>
+  <ContentWrap>
+    <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
+
+    <div class="mb-10px">
+      <ElButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</ElButton>
+      <ElButton :loading="delLoading" type="danger" @click="delData(null)">
+        {{ t('exampleDemo.del') }}
+      </ElButton>
+    </div>
+
+    <Table
+      v-model:pageSize="pageSize"
+      v-model:currentPage="currentPage"
+      :columns="allSchemas.tableColumns"
+      :data="dataList"
+      :loading="loading"
+      :pagination="{
+        total: total
+      }"
+      @register="tableRegister"
+    />
+  </ContentWrap>
+
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
+    <Write
+      v-if="actionType !== 'detail'"
+      ref="writeRef"
+      :form-schema="allSchemas.formSchema"
+      :current-row="currentRow"
+    />
+
+    <Detail
+      v-if="actionType === 'detail'"
+      :detail-schema="allSchemas.detailSchema"
+      :current-row="currentRow"
+    />
+
+    <template #footer>
+      <ElButton v-if="actionType !== 'detail'" type="primary" :loading="saveLoading" @click="save">
+        {{ t('exampleDemo.save') }}
+      </ElButton>
+      <ElButton @click="dialogVisible = false">{{ t('dialogDemo.close') }}</ElButton>
+    </template>
+  </Dialog>
+</template>

+ 20 - 0
src/views/Authorization/Department/components/Detail.vue

@@ -0,0 +1,20 @@
+<script setup lang="ts">
+import { PropType } from 'vue'
+import type { TableData } from '@/api/table/types'
+import { Descriptions, DescriptionsSchema } from '@/components/Descriptions'
+
+defineProps({
+  currentRow: {
+    type: Object as PropType<Nullable<TableData>>,
+    default: () => null
+  },
+  detailSchema: {
+    type: Array as PropType<DescriptionsSchema[]>,
+    default: () => []
+  }
+})
+</script>
+
+<template>
+  <Descriptions :schema="detailSchema" :data="currentRow || {}" />
+</template>

+ 61 - 0
src/views/Authorization/Department/components/Write.vue

@@ -0,0 +1,61 @@
+<script setup lang="ts">
+import { Form, FormSchema } from '@/components/Form'
+import { useForm } from '@/hooks/web/useForm'
+import { PropType, reactive, watch } from 'vue'
+import { TableData } from '@/api/table/types'
+import { useValidator } from '@/hooks/web/useValidator'
+
+const { required } = useValidator()
+
+const props = defineProps({
+  currentRow: {
+    type: Object as PropType<Nullable<TableData>>,
+    default: () => null
+  },
+  formSchema: {
+    type: Array as PropType<FormSchema[]>,
+    default: () => []
+  }
+})
+
+const rules = reactive({
+  id: [required()],
+  status: [required()],
+  createTime: [required()],
+  remark: [required()]
+})
+
+const { formRegister, formMethods } = useForm()
+const { setValues, getFormData, getElFormExpose } = formMethods
+
+const submit = async () => {
+  const elForm = await getElFormExpose()
+  const valid = await elForm?.validate().catch((err) => {
+    console.log(err)
+  })
+  if (valid) {
+    const formData = getFormData()
+    return formData
+  }
+}
+
+watch(
+  () => props.currentRow,
+  (currentRow) => {
+    if (!currentRow) return
+    setValues(currentRow)
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
+
+defineExpose({
+  submit
+})
+</script>
+
+<template>
+  <Form :rules="rules" @register="formRegister" :schema="formSchema" />
+</template>

+ 0 - 0
src/views/Authorization/User.vue → src/views/Authorization/User/User.vue


+ 0 - 0
src/views/Authorization/components/Detail.vue → src/views/Authorization/User/components/Detail.vue


+ 0 - 0
src/views/Authorization/components/Write.vue → src/views/Authorization/User/components/Write.vue


+ 26 - 16
src/views/Example/Dialog/ExampleDialog.vue

@@ -4,11 +4,11 @@ import { Search } from '@/components/Search'
 import { Dialog } from '@/components/Dialog'
 import { useI18n } from '@/hooks/web/useI18n'
 import { ElButton, ElTag } from 'element-plus'
-import { Table, TableColumn } from '@/components/Table'
+import { Table } from '@/components/Table'
 import { getTableListApi, saveTableApi, delTableListApi } from '@/api/table'
 import { useTable } from '@/hooks/web/useTable'
 import { TableData } from '@/api/table/types'
-import { h, ref, unref, reactive } from 'vue'
+import { ref, unref, reactive } from 'vue'
 import Write from './components/Write.vue'
 import Detail from './components/Detail.vue'
 import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
@@ -47,6 +47,9 @@ const { t } = useI18n()
 const crudSchemas = reactive<CrudSchema[]>([
   {
     field: 'selection',
+    search: {
+      hidden: true
+    },
     form: {
       hidden: true
     },
@@ -61,6 +64,9 @@ const crudSchemas = reactive<CrudSchema[]>([
     field: 'index',
     label: t('tableDemo.index'),
     type: 'index',
+    search: {
+      hidden: true
+    },
     form: {
       hidden: true
     },
@@ -86,11 +92,17 @@ const crudSchemas = reactive<CrudSchema[]>([
   },
   {
     field: 'author',
-    label: t('tableDemo.author')
+    label: t('tableDemo.author'),
+    search: {
+      hidden: true
+    }
   },
   {
     field: 'display_time',
     label: t('tableDemo.displayTime'),
+    search: {
+      hidden: true
+    },
     form: {
       component: 'DatePicker',
       componentProps: {
@@ -102,19 +114,8 @@ const crudSchemas = reactive<CrudSchema[]>([
   {
     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')
-      )
+    search: {
+      hidden: true
     },
     form: {
       component: 'Select',
@@ -161,6 +162,9 @@ const crudSchemas = reactive<CrudSchema[]>([
   {
     field: 'pageviews',
     label: t('tableDemo.pageviews'),
+    search: {
+      hidden: true
+    },
     form: {
       component: 'InputNumber',
       value: 0
@@ -169,6 +173,9 @@ const crudSchemas = reactive<CrudSchema[]>([
   {
     field: 'content',
     label: t('exampleDemo.content'),
+    search: {
+      hidden: true
+    },
     table: {
       show: false
     },
@@ -191,6 +198,9 @@ const crudSchemas = reactive<CrudSchema[]>([
     field: 'action',
     width: '260px',
     label: t('tableDemo.action'),
+    search: {
+      hidden: true
+    },
     form: {
       hidden: true
     },

+ 52 - 18
src/views/Example/Page/ExamplePage.vue

@@ -3,11 +3,11 @@ import { ContentWrap } from '@/components/ContentWrap'
 import { Search } from '@/components/Search'
 import { useI18n } from '@/hooks/web/useI18n'
 import { ElButton, ElTag } from 'element-plus'
-import { Table, TableColumn } from '@/components/Table'
+import { Table } from '@/components/Table'
 import { getTableListApi, delTableListApi } from '@/api/table'
 import { useTable } from '@/hooks/web/useTable'
 import { TableData } from '@/api/table/types'
-import { h, reactive, ref, unref } from 'vue'
+import { reactive, ref, unref } from 'vue'
 import { useRouter } from 'vue-router'
 import { useEmitt } from '@/hooks/event/useEmitt'
 import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
@@ -64,6 +64,9 @@ const { t } = useI18n()
 const crudSchemas = reactive<CrudSchema[]>([
   {
     field: 'selection',
+    search: {
+      hidden: true
+    },
     form: {
       hidden: true
     },
@@ -78,6 +81,9 @@ const crudSchemas = reactive<CrudSchema[]>([
     field: 'index',
     label: t('tableDemo.index'),
     type: 'index',
+    search: {
+      hidden: true
+    },
     form: {
       hidden: true
     },
@@ -103,11 +109,17 @@ const crudSchemas = reactive<CrudSchema[]>([
   },
   {
     field: 'author',
-    label: t('tableDemo.author')
+    label: t('tableDemo.author'),
+    search: {
+      hidden: true
+    }
   },
   {
     field: 'display_time',
     label: t('tableDemo.displayTime'),
+    search: {
+      hidden: true
+    },
     form: {
       component: 'DatePicker',
       componentProps: {
@@ -119,19 +131,8 @@ const crudSchemas = reactive<CrudSchema[]>([
   {
     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')
-      )
+    search: {
+      hidden: true
     },
     form: {
       component: 'Select',
@@ -154,11 +155,33 @@ const crudSchemas = reactive<CrudSchema[]>([
           }
         ]
       }
+    },
+    detail: {
+      slots: {
+        default: (data: any) => {
+          return (
+            <ElTag
+              type={
+                data.importance === 1 ? 'success' : data.importance === 2 ? 'warning' : 'danger'
+              }
+            >
+              {data.importance === 1
+                ? t('tableDemo.important')
+                : data.importance === 2
+                ? t('tableDemo.good')
+                : t('tableDemo.commonly')}
+            </ElTag>
+          )
+        }
+      }
     }
   },
   {
     field: 'pageviews',
     label: t('tableDemo.pageviews'),
+    search: {
+      hidden: true
+    },
     form: {
       component: 'InputNumber',
       value: 0
@@ -167,9 +190,12 @@ const crudSchemas = reactive<CrudSchema[]>([
   {
     field: 'content',
     label: t('exampleDemo.content'),
-    table: {
+    search: {
       hidden: true
     },
+    table: {
+      show: false
+    },
     form: {
       component: 'Editor',
       colProps: {
@@ -177,13 +203,21 @@ const crudSchemas = reactive<CrudSchema[]>([
       }
     },
     detail: {
-      span: 24
+      span: 24,
+      slots: {
+        default: (data: any) => {
+          return <div innerHTML={data.content}></div>
+        }
+      }
     }
   },
   {
     field: 'action',
     width: '260px',
     label: t('tableDemo.action'),
+    search: {
+      hidden: true
+    },
     form: {
       hidden: true
     },