Browse Source

feat: Table组件重构

陈凯龙 3 years ago
parent
commit
07adefb89b

+ 1 - 1
.gitignore

@@ -3,4 +3,4 @@ node_modules
 dist
 dist
 dist-ssr
 dist-ssr
 *.local
 *.local
-components.d.ts
+/components.d.ts

+ 6 - 10
components.d.ts

@@ -5,11 +5,12 @@
 declare module 'vue' {
 declare module 'vue' {
   export interface GlobalComponents {
   export interface GlobalComponents {
     404: typeof import('./src/components/Error/404.vue')['default']
     404: typeof import('./src/components/Error/404.vue')['default']
-    Aa: typeof import('E:/HBuilderProjects/element-plus-admin/src/components/aa.vue')['default']
     Avatars: typeof import('./src/components/Avatars/index.vue')['default']
     Avatars: typeof import('./src/components/Avatars/index.vue')['default']
+    ComDetail: typeof import('./src/components/ComDetail/index.vue')['default']
+    ComDialog: typeof import('./src/components/ComDialog/index.vue')['default']
+    ComSearch: typeof import('./src/components/ComSearch/index.vue')['default']
+    ComTable: typeof import('./src/components/ComTable/index.vue')['default']
     CountTo: typeof import('./src/components/CountTo/index.vue')['default']
     CountTo: typeof import('./src/components/CountTo/index.vue')['default']
-    Detail: typeof import('./src/components/Detail/index.vue')['default']
-    Dialog: typeof import('./src/components/Dialog/index.vue')['default']
     Echart: typeof import('./src/components/Echart/index.vue')['default']
     Echart: typeof import('./src/components/Echart/index.vue')['default']
     Editor: typeof import('./src/components/Editor/index.vue')['default']
     Editor: typeof import('./src/components/Editor/index.vue')['default']
     ElAlert: typeof import('element-plus/es')['ElAlert']
     ElAlert: typeof import('element-plus/es')['ElAlert']
@@ -21,8 +22,6 @@ declare module 'vue' {
     ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition']
     ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
-    ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
-    ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
@@ -52,17 +51,14 @@ declare module 'vue' {
     ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
     ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
     ElTimeSelect: typeof import('element-plus/es')['ElTimeSelect']
     ElTimeSelect: typeof import('element-plus/es')['ElTimeSelect']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
-    Highlight: typeof import('E:/HBuilderProjects/element-plus-admin/src/components/Highlight/index.vue')['default']
     Loading: typeof import('element-plus/es')['ElLoadingDirective']
     Loading: typeof import('element-plus/es')['ElLoadingDirective']
     ParentView: typeof import('./src/components/ParentView/index.vue')['default']
     ParentView: typeof import('./src/components/ParentView/index.vue')['default']
     Preview: typeof import('./src/components/Preview/index.vue')['default']
     Preview: typeof import('./src/components/Preview/index.vue')['default']
     Qrcode: typeof import('./src/components/Qrcode/index.vue')['default']
     Qrcode: typeof import('./src/components/Qrcode/index.vue')['default']
     Redirect: typeof import('./src/components/Redirect/index.vue')['default']
     Redirect: typeof import('./src/components/Redirect/index.vue')['default']
-    Search: typeof import('./src/components/Search/index.vue')['default']
-    Slot: typeof import('./src/components/Table/components/Slot.vue')['default']
+    Slot: typeof import('./src/components/ComTable/components/Slot.vue')['default']
     SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
     SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
-    Table: typeof import('./src/components/Table/index.vue')['default']
-    TableColumn: typeof import('./src/components/Table/components/TableColumn.vue')['default']
+    TableColumn: typeof import('./src/components/ComTable/components/TableColumn.vue')['default']
   }
   }
 }
 }
 
 

BIN
src/assets/logo.png


+ 5 - 1
src/components/Detail/index.vue → src/components/ComDetail/index.vue

@@ -37,7 +37,7 @@
   </div>
   </div>
 </template>
 </template>
 
 
-<script setup lang="ts" name="Detail">
+<script setup lang="ts" name="ComDetail">
 import { PropType, ref, computed } from 'vue'
 import { PropType, ref, computed } from 'vue'
 import { SchemaConfig } from './types'
 import { SchemaConfig } from './types'
 
 
@@ -65,11 +65,15 @@ const props = defineProps({
   // 需要展示的数据
   // 需要展示的数据
   data: {
   data: {
     type: Object as PropType<IObj>,
     type: Object as PropType<IObj>,
+    default: () => {
+      return {}
+    },
     required: true
     required: true
   },
   },
   // 布局展示的数据
   // 布局展示的数据
   schema: {
   schema: {
     type: Array as PropType<SchemaConfig[]>,
     type: Array as PropType<SchemaConfig[]>,
+    default: () => [],
     required: true
     required: true
   },
   },
   // 是否标题和内容各占一行 垂直布局
   // 是否标题和内容各占一行 垂直布局

+ 0 - 0
src/components/Detail/types.ts → src/components/ComDetail/types.ts


+ 1 - 1
src/components/Dialog/index.vue → src/components/ComDialog/index.vue

@@ -41,7 +41,7 @@
   </el-dialog>
   </el-dialog>
 </template>
 </template>
 
 
-<script setup lang="ts" name="Dialog">
+<script setup lang="ts" name="ComDialog">
 import { ref, computed, PropType, nextTick, unref, useAttrs, useSlots } from 'vue'
 import { ref, computed, PropType, nextTick, unref, useAttrs, useSlots } from 'vue'
 import SvgIcon from '@/components/SvgIcon/index.vue'
 import SvgIcon from '@/components/SvgIcon/index.vue'
 
 

+ 1 - 1
src/components/Search/index.vue → src/components/ComSearch/index.vue

@@ -187,7 +187,7 @@
   </div>
   </div>
 </template>
 </template>
 
 
-<script setup lang="ts" name="Search">
+<script setup lang="ts" name="ComSearch">
 import { PropType, watch, ref, unref } from 'vue'
 import { PropType, watch, ref, unref } from 'vue'
 import { deepClone } from '@/utils'
 import { deepClone } from '@/utils'
 
 

+ 3 - 3
src/components/Table/components/Slot.vue → src/components/ComTable/components/Slot.vue

@@ -4,7 +4,7 @@ export default defineComponent({
   name: 'Slot',
   name: 'Slot',
   props: {
   props: {
     row: {
     row: {
-      type: Object as PropType<object>,
+      type: Object as PropType<IObj>,
       default: () => null
       default: () => null
     },
     },
     index: {
     index: {
@@ -12,7 +12,7 @@ export default defineComponent({
       default: null
       default: null
     },
     },
     column: {
     column: {
-      type: Object as PropType<object>,
+      type: Object as PropType<IObj>,
       default: () => null
       default: () => null
     },
     },
     slotName: {
     slotName: {
@@ -20,7 +20,7 @@ export default defineComponent({
       default: ''
       default: ''
     }
     }
   },
   },
-  render(props: any) {
+  render(props) {
     const _this: any = inject('tableRoot')
     const _this: any = inject('tableRoot')
     return h(
     return h(
       'span',
       'span',

+ 0 - 0
src/components/Table/components/TableColumn.vue → src/components/ComTable/components/TableColumn.vue


+ 159 - 0
src/components/ComTable/index.vue

@@ -0,0 +1,159 @@
+<template>
+  <div>
+    <el-table ref="tableRef" :border="true" v-bind="getBindValue" @header-dragend="headerDragend">
+      <!-- 多选 -->
+      <el-table-column
+        v-if="selection"
+        type="selection"
+        :reserve-selection="reserveSelection"
+        width="40"
+      />
+      <template v-for="item in columns">
+        <!-- 自定义索引 -->
+        <template v-if="item.type === 'index'">
+          <el-table-column
+            :key="item[item.field]"
+            v-bind="{ ...getItemBindValue(item) }"
+            type="index"
+            :index="item.index"
+          />
+        </template>
+
+        <!-- 树型数据 -->
+        <template v-else-if="item.children && item.children.length">
+          <table-column :key="item[item.field]" :child="item" />
+        </template>
+
+        <template v-else>
+          <el-table-column
+            :key="item[item.field]"
+            v-bind="{ ...getItemBindValue(item) }"
+            :prop="item.field"
+          >
+            <!-- 表头插槽 -->
+            <template v-if="item.slots && item.slots.header" #header="scope">
+              <table-slot
+                v-if="item.slots && item.slots.header"
+                :slot-name="item.slots.header"
+                :column="item"
+                :index="scope.$index"
+              />
+            </template>
+
+            <!-- 表格内容插槽自定义 -->
+            <template v-if="item.slots && item.slots.default" #default="scope">
+              <table-slot
+                v-if="item.slots && item.slots.default"
+                :slot-name="item.slots.default"
+                :row="scope.row"
+                :column="item"
+                :index="scope.$index"
+              />
+            </template>
+          </el-table-column>
+        </template>
+      </template>
+    </el-table>
+
+    <div v-if="pagination" class="pagination__wrap">
+      <el-pagination
+        :style="paginationStyle"
+        :page-sizes="[10, 20, 30, 40, 50, 100]"
+        layout="total, sizes, prev, pager, next, jumper"
+        v-bind="getPaginationBindValue"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts" name="ComTable">
+import { PropType, computed, useAttrs, ref, getCurrentInstance, provide } from 'vue'
+import { deepClone } from '@/utils'
+import { isObject } from '@/utils/validate'
+import TableColumn from './components/TableColumn.vue'
+import TableSlot from './components/Slot.vue'
+
+const props = defineProps({
+  // 表头
+  columns: {
+    type: Array as PropType<IObj[]>,
+    default: () => []
+  },
+  // 是否多选
+  selection: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  },
+  // 是否展示分页
+  pagination: {
+    type: [Boolean, Object] as PropType<boolean | IObj>,
+    default: false
+  },
+  // 仅对 type=selection 的列有效,类型为 Boolean,为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key)
+  reserveSelection: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  }
+})
+
+const attrs = useAttrs()
+
+const tableRef = ref<HTMLElement | null>(null)
+function getTableRef() {
+  return tableRef.value as any
+}
+
+const _this = getCurrentInstance()
+provide('tableRoot', _this)
+
+const getBindValue = computed((): IObj => {
+  const bindValue = { ...attrs, ...props } as IObj
+  delete bindValue.columns
+  return bindValue
+})
+
+function getItemBindValue(item: IObj) {
+  const delArr: string[] = []
+  const obj = deepClone(item)
+  for (const key in obj) {
+    if (delArr.indexOf(key) !== -1) {
+      delete obj[key]
+    }
+  }
+  return obj
+}
+
+const getPaginationBindValue = computed((): IObj => {
+  const PaginationBindValue =
+    props.pagination && isObject(props.pagination) ? { ...props.pagination } : {}
+  return PaginationBindValue
+})
+
+const paginationStyle = computed(() => {
+  return {
+    textAlign: (props.pagination && (props.pagination as IObj).position) || 'right'
+  }
+})
+
+function headerDragend(newWidth: number, _: number, column: IObj) {
+  // 不懂为啥无法自动计算宽度,只能手动去计算了。。失望ing,到时候看看能不能优化吧。
+  const htmlArr = document.getElementsByClassName(column.id)
+  for (const v of htmlArr as any) {
+    if (v.firstElementChild) {
+      ;(v.firstElementChild as any).style.width = newWidth + 'px'
+    }
+  }
+}
+
+defineExpose({
+  getTableRef
+})
+</script>
+
+<style lang="less" scoped>
+.pagination__wrap {
+  padding: 10px;
+  margin-top: 15px;
+  background: #fff;
+}
+</style>

+ 1 - 1
src/components/Preview/index.vue

@@ -65,7 +65,7 @@ import { ref, reactive, computed, watch, nextTick, unref } from 'vue'
 import { previewProps } from './props'
 import { previewProps } from './props'
 import { isFirefox } from '@/utils/validate'
 import { isFirefox } from '@/utils/validate'
 import { on, off } from '@/utils/dom-utils'
 import { on, off } from '@/utils/dom-utils'
-import throttle from 'lodash-es/throttle'
+import { throttle } from 'lodash-es'
 import SvgIcon from '_c/SvgIcon/index.vue'
 import SvgIcon from '_c/SvgIcon/index.vue'
 const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
 const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
 
 

+ 0 - 170
src/components/Table/index.vue

@@ -1,170 +0,0 @@
-<template>
-  <el-table ref="elTable" :border="true" v-bind="getBindValue" @header-dragend="headerDragend">
-    <!-- 多选 -->
-    <el-table-column
-      v-if="selection"
-      type="selection"
-      :reserve-selection="reserveSelection"
-      width="40"
-    />
-    <template v-for="item in columns">
-      <!-- 自定义索引 -->
-      <template v-if="item.type === 'index'">
-        <el-table-column
-          :key="item[item.field]"
-          v-bind="{ ...getItemBindValue(item) }"
-          type="index"
-          :index="item.index"
-        />
-      </template>
-
-      <!-- 树型数据 -->
-      <template v-else-if="item.children && item.children.length">
-        <table-column :key="item[item.field]" :child="item" />
-      </template>
-
-      <template v-else>
-        <el-table-column
-          :key="item[item.field]"
-          v-bind="{ ...getItemBindValue(item) }"
-          :prop="item.field"
-        >
-          <!-- 表头插槽 -->
-          <template v-if="item.slots && item.slots.header" #header="scope">
-            <table-slot
-              v-if="item.slots && item.slots.header"
-              :slot-name="item.slots.header"
-              :column="item"
-              :index="scope.$index"
-            />
-          </template>
-
-          <!-- 表格内容插槽自定义 -->
-          <template v-if="item.slots && item.slots.default" #default="scope">
-            <table-slot
-              v-if="item.slots && item.slots.default"
-              :slot-name="item.slots.default"
-              :row="scope.row"
-              :column="item"
-              :index="scope.$index"
-            />
-          </template>
-        </el-table-column>
-      </template>
-    </template>
-  </el-table>
-
-  <div v-if="pagination" class="pagination__wrap">
-    <el-pagination
-      :style="paginationStyle"
-      :page-sizes="[10, 20, 30, 40, 50, 100]"
-      layout="total, sizes, prev, pager, next, jumper"
-      v-bind="getPaginationBindValue"
-      @size-change="sizeChange"
-      @current-change="currentChange"
-    />
-  </div>
-</template>
-
-<script setup lang="ts" name="ComTable">
-import { PropType, computed, ref, unref, useAttrs } from 'vue'
-import { deepClone } from '@/utils'
-import { isObject } from '@/utils/validate'
-import TableColumn from './components/TableColumn.vue'
-import TableSlot from './components/Slot.vue'
-
-const props = defineProps({
-  // 表头
-  columns: {
-    type: Array as PropType<IObj[]>,
-    default: () => []
-  },
-  // 是否多选
-  selection: {
-    type: Boolean as PropType<boolean>,
-    default: false
-  },
-  // 是否展示分页
-  pagination: {
-    type: [Boolean, Object] as PropType<boolean | IObj>,
-    default: false
-  },
-  // 仅对 type=selection 的列有效,类型为 Boolean,为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key)
-  reserveSelection: {
-    type: Boolean as PropType<boolean>,
-    default: false
-  }
-})
-
-const attrs = useAttrs()
-
-const elTable = ref<HTMLElement | null>(null)
-function getTableRef() {
-  return unref(elTable as any)
-}
-
-// const _this = getCurrentInstance()
-// provide('tableRoot', _this)
-
-const getBindValue = computed((): IObj => {
-  const bindValue = { ...attrs, ...props } as IObj
-  delete bindValue.columns
-  return bindValue
-})
-
-function getItemBindValue(item: IObj) {
-  const delArr: string[] = []
-  const obj = deepClone(item)
-  for (const key in obj) {
-    if (delArr.indexOf(key) !== -1) {
-      delete obj[key]
-    }
-  }
-  return obj
-}
-
-const getPaginationBindValue = computed((): IObj => {
-  const PaginationBindValue =
-    props.pagination && isObject(props.pagination) ? { ...props.pagination } : {}
-  return PaginationBindValue
-})
-
-const paginationStyle = computed(() => {
-  return {
-    textAlign: (props.pagination && (props.pagination as IObj).position) || 'right'
-  }
-})
-
-function headerDragend(newWidth: number, _: number, column: IObj) {
-  // 不懂为啥无法自动计算宽度,只能手动去计算了。。失望ing,到时候看看能不能优化吧。
-  const htmlArr = document.getElementsByClassName(column.id)
-  for (const v of htmlArr as any) {
-    if (v.firstElementChild) {
-      ;(v.firstElementChild as any).style.width = newWidth + 'px'
-    }
-  }
-}
-
-function sizeChange(val: number) {
-  if (props.pagination && (props.pagination as IObj).onSizeChange) {
-    ;(props.pagination as IObj).onSizeChange(val)
-  }
-}
-
-function currentChange(val: number) {
-  if (props.pagination && (props.pagination as IObj).onCurrentChange) {
-    ;(props.pagination as IObj).onCurrentChange(val)
-  }
-}
-defineExpose({
-  getTableRef
-})
-</script>
-
-<style lang="less" scoped>
-.pagination__wrap {
-  padding: 10px;
-  margin-top: 15px;
-  background: #fff;
-}
-</style>

+ 4 - 4
src/components/index.ts

@@ -1,9 +1,9 @@
 import type { App } from 'vue'
 import type { App } from 'vue'
 import SvgIcon from './SvgIcon/index.vue' // svg组件
 import SvgIcon from './SvgIcon/index.vue' // svg组件
-import ComSearch from './Search/index.vue' // search组件
-import ComDialog from './Dialog/index.vue' // dialog组件
-import ComDetail from './Detail/index.vue' // detail组件
-import ComTable from './Table/index.vue' // table组件
+import ComSearch from './ComSearch/index.vue' // search组件
+import ComDialog from './ComDialog/index.vue' // dialog组件
+import ComDetail from './ComDetail/index.vue' // detail组件
+import ComTable from './ComTable/index.vue' // table组件
 
 
 export function setupGlobCom(app: App<Element>): void {
 export function setupGlobCom(app: App<Element>): void {
   app.component('SvgIcon', SvgIcon)
   app.component('SvgIcon', SvgIcon)

+ 190 - 219
src/router/index.ts

@@ -245,228 +245,199 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
         meta: {
         meta: {
           title: '基础表格'
           title: '基础表格'
         }
         }
+      },
+      {
+        path: 'page-table',
+        component: () => import('_v/table-demo/page-table/index.vue'),
+        name: 'PageTable',
+        meta: {
+          title: '分页表格'
+        }
+      },
+      {
+        path: 'stripe-table',
+        component: () => import('_v/table-demo/stripe-table/index.vue'),
+        name: 'StripeTable',
+        meta: {
+          title: '带斑马纹表格'
+        }
+      },
+      {
+        path: 'border-table',
+        component: () => import('_v/table-demo/border-table/index.vue'),
+        name: 'BorderTable',
+        meta: {
+          title: '带边框表格'
+        }
+      },
+      {
+        path: 'state-table',
+        component: () => import('_v/table-demo/state-table/index.vue'),
+        name: 'StateTable',
+        meta: {
+          title: '带状态表格'
+        }
+      },
+      {
+        path: 'fixed-header',
+        component: () => import('_v/table-demo/fixed-header/index.vue'),
+        name: 'FixedHeader',
+        meta: {
+          title: '固定表头'
+        }
+      },
+      {
+        path: 'fixed-column',
+        component: () => import('_v/table-demo/fixed-column/index.vue'),
+        name: 'FixedColumn',
+        meta: {
+          title: '固定列'
+        }
+      },
+      {
+        path: 'fixed-column-header',
+        component: () => import('_v/table-demo/fixed-column-header/index.vue'),
+        name: 'FixedColumnHeader',
+        meta: {
+          title: '固定列和表头'
+        }
+      },
+      {
+        path: 'fluid-height',
+        component: () => import('_v/table-demo/fluid-height/index.vue'),
+        name: 'FluidHeight',
+        meta: {
+          title: '流体高度'
+        }
+      },
+      {
+        path: 'multi-header',
+        component: () => import('_v/table-demo/multi-header/index.vue'),
+        name: 'MultiHeader',
+        meta: {
+          title: '多级表头'
+        }
+      },
+      {
+        path: 'single-choice',
+        component: () => import('_v/table-demo/single-choice/index.vue'),
+        name: 'SingleChoice',
+        meta: {
+          title: '单选'
+        }
+      },
+      {
+        path: 'multiple-choice',
+        component: () => import('_v/table-demo/multiple-choice/index.vue'),
+        name: 'MultipleChoice',
+        meta: {
+          title: '多选'
+        }
+      },
+      {
+        path: 'sort-table',
+        component: () => import('_v/table-demo/sort-table/index.vue'),
+        name: 'SortTable',
+        meta: {
+          title: '排序'
+        }
+      },
+      {
+        path: 'screen-table',
+        component: () => import('_v/table-demo/screen-table/index.vue'),
+        name: 'ScreenTable',
+        meta: {
+          title: '筛选'
+        }
+      },
+      {
+        path: 'expand-row',
+        component: () => import('_v/table-demo/expand-row/index.vue'),
+        name: 'ExpandRow',
+        meta: {
+          title: '展开行'
+        }
+      },
+      {
+        path: 'tree-and-load',
+        component: () => import('_v/table-demo/tree-and-load/index.vue'),
+        name: 'TreeAndLoad',
+        meta: {
+          title: '树形数据与懒加载'
+        }
+      },
+      {
+        path: 'custom-header',
+        component: () => import('_v/table-demo/custom-header/index.vue'),
+        name: 'CustomHeader',
+        meta: {
+          title: '自定义表头'
+        }
+      },
+      {
+        path: 'total-table',
+        component: () => import('_v/table-demo/total-table/index.vue'),
+        name: 'TotalTable',
+        meta: {
+          title: '表尾合计行'
+        }
+      },
+      {
+        path: 'merge-table',
+        component: () => import('_v/table-demo/merge-table/index.vue'),
+        name: 'MergeTable',
+        meta: {
+          title: '合并行或列'
+        }
+      },
+      {
+        path: 'custom-index',
+        component: () => import('_v/table-demo/custom-index/index.vue'),
+        name: 'CustomIndex',
+        meta: {
+          title: '自定义索引'
+        }
+      }
+    ]
+  },
+  {
+    path: '/directives-demo',
+    component: Layout,
+    redirect: '/directives-demo/clipboard',
+    name: 'DirectivesDemo',
+    meta: {
+      title: '自定义指令',
+      icon: 'clipboard',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'clipboard',
+        component: () => import('_v/directives-demo/clipboard/index.vue'),
+        name: 'ClipboardDemo',
+        meta: {
+          title: 'Clipboard'
+        }
+      }
+    ]
+  },
+  {
+    path: '/icon',
+    component: Layout,
+    name: 'IconsDemo',
+    meta: {},
+    children: [
+      {
+        path: 'index',
+        component: () => import('_v/icons/index.vue'),
+        name: 'Icons',
+        meta: {
+          title: '图标',
+          icon: 'icon'
+        }
       }
       }
-      // {
-      //   path: 'page-table',
-      //   component: () => import('_v/table-demo/page-table/index.vue'),
-      //   name: 'PageTable',
-      //   meta: {
-      //     title: '分页表格'
-      //   }
-      // },
-      // {
-      //   path: 'stripe-table',
-      //   component: () => import('_v/table-demo/stripe-table/index.vue'),
-      //   name: 'StripeTable',
-      //   meta: {
-      //     title: '带斑马纹表格'
-      //   }
-      // },
-      // {
-      //   path: 'border-table',
-      //   component: () => import('_v/table-demo/border-table/index.vue'),
-      //   name: 'BorderTable',
-      //   meta: {
-      //     title: '带边框表格'
-      //   }
-      // },
-      // {
-      //   path: 'state-table',
-      //   component: () => import('_v/table-demo/state-table/index.vue'),
-      //   name: 'StateTable',
-      //   meta: {
-      //     title: '带状态表格'
-      //   }
-      // },
-      // {
-      //   path: 'fixed-header',
-      //   component: () => import('_v/table-demo/fixed-header/index.vue'),
-      //   name: 'FixedHeader',
-      //   meta: {
-      //     title: '固定表头'
-      //   }
-      // },
-      // {
-      //   path: 'fixed-column',
-      //   component: () => import('_v/table-demo/fixed-column/index.vue'),
-      //   name: 'FixedColumn',
-      //   meta: {
-      //     title: '固定列'
-      //   }
-      // },
-      // {
-      //   path: 'fixed-column-header',
-      //   component: () => import('_v/table-demo/fixed-column-header/index.vue'),
-      //   name: 'FixedColumnHeader',
-      //   meta: {
-      //     title: '固定列和表头'
-      //   }
-      // },
-      // {
-      //   path: 'fluid-height',
-      //   component: () => import('_v/table-demo/fluid-height/index.vue'),
-      //   name: 'FluidHeight',
-      //   meta: {
-      //     title: '流体高度'
-      //   }
-      // },
-      // {
-      //   path: 'multi-header',
-      //   component: () => import('_v/table-demo/multi-header/index.vue'),
-      //   name: 'MultiHeader',
-      //   meta: {
-      //     title: '多级表头'
-      //   }
-      // },
-      // {
-      //   path: 'single-choice',
-      //   component: () => import('_v/table-demo/single-choice/index.vue'),
-      //   name: 'SingleChoice',
-      //   meta: {
-      //     title: '单选'
-      //   }
-      // },
-      // {
-      //   path: 'multiple-choice',
-      //   component: () => import('_v/table-demo/multiple-choice/index.vue'),
-      //   name: 'MultipleChoice',
-      //   meta: {
-      //     title: '多选'
-      //   }
-      // },
-      // {
-      //   path: 'sort-table',
-      //   component: () => import('_v/table-demo/sort-table/index.vue'),
-      //   name: 'SortTable',
-      //   meta: {
-      //     title: '排序'
-      //   }
-      // },
-      // {
-      //   path: 'screen-table',
-      //   component: () => import('_v/table-demo/screen-table/index.vue'),
-      //   name: 'ScreenTable',
-      //   meta: {
-      //     title: '筛选'
-      //   }
-      // },
-      // {
-      //   path: 'expand-row',
-      //   component: () => import('_v/table-demo/expand-row/index.vue'),
-      //   name: 'ExpandRow',
-      //   meta: {
-      //     title: '展开行'
-      //   }
-      // },
-      // {
-      //   path: 'tree-and-load',
-      //   component: () => import('_v/table-demo/tree-and-load/index.vue'),
-      //   name: 'TreeAndLoad',
-      //   meta: {
-      //     title: '树形数据与懒加载'
-      //   }
-      // },
-      // {
-      //   path: 'custom-header',
-      //   component: () => import('_v/table-demo/custom-header/index.vue'),
-      //   name: 'CustomHeader',
-      //   meta: {
-      //     title: '自定义表头'
-      //   }
-      // },
-      // {
-      //   path: 'total-table',
-      //   component: () => import('_v/table-demo/total-table/index.vue'),
-      //   name: 'TotalTable',
-      //   meta: {
-      //     title: '表尾合计行'
-      //   }
-      // },
-      // {
-      //   path: 'merge-table',
-      //   component: () => import('_v/table-demo/merge-table/index.vue'),
-      //   name: 'MergeTable',
-      //   meta: {
-      //     title: '合并行或列'
-      //   }
-      // },
-      // {
-      //   path: 'custom-index',
-      //   component: () => import('_v/table-demo/custom-index/index.vue'),
-      //   name: 'CustomIndex',
-      //   meta: {
-      //     title: '自定义索引'
-      //   }
-      // }
     ]
     ]
   },
   },
-  // {
-  //   path: '/directives-demo',
-  //   component: Layout,
-  //   redirect: '/directives-demo/clipboard',
-  //   name: 'DirectivesDemo',
-  //   meta: {
-  //     title: '自定义指令',
-  //     icon: 'clipboard',
-  //     alwaysShow: true
-  //   },
-  //   children: [
-  //     {
-  //       path: 'clipboard',
-  //       component: () => import('_v/directives-demo/clipboard/index.vue'),
-  //       name: 'ClipboardDemo',
-  //       meta: {
-  //         title: 'Clipboard'
-  //       }
-  //     }
-  //   ]
-  // },
-  // {
-  //   path: '/hooks-demo',
-  //   component: Layout,
-  //   redirect: '/hooks-demo/watermark',
-  //   name: 'HooksDemo',
-  //   meta: {
-  //     title: 'Hooks',
-  //     icon: 'international',
-  //     alwaysShow: true
-  //   },
-  //   children: [
-  //     {
-  //       path: 'watermark',
-  //       component: () => import('_v/hooks-demo/useWatermark/index.vue'),
-  //       name: 'UseWatermarkDemo',
-  //       meta: {
-  //         title: 'UseWaterMark'
-  //       }
-  //     },
-  //     {
-  //       path: 'useScrollTo',
-  //       component: () => import('_v/hooks-demo/useScrollTo/index.vue'),
-  //       name: 'UseScrollToDemo',
-  //       meta: {
-  //         title: 'UseScrollTo'
-  //       }
-  //     }
-  //   ]
-  // },
-  // {
-  //   path: '/icon',
-  //   component: Layout,
-  //   name: 'IconsDemo',
-  //   meta: {},
-  //   children: [
-  //     {
-  //       path: 'index',
-  //       component: () => import('_v/icons/index.vue'),
-  //       name: 'Icons',
-  //       meta: {
-  //         title: '图标',
-  //         icon: 'icon'
-  //       }
-  //     }
-  //   ]
-  // },
   {
   {
     path: '/level',
     path: '/level',
     component: Layout,
     component: Layout,

+ 1 - 1
src/store/modules/permission.ts

@@ -12,7 +12,7 @@ import { store } from '../index'
 import { useAppStoreWithOut } from '@/store/modules/app'
 import { useAppStoreWithOut } from '@/store/modules/app'
 const appStore = useAppStoreWithOut()
 const appStore = useAppStoreWithOut()
 
 
-const modules = import.meta.glob('../views/*/*.vue')
+const modules = import.meta.glob('./src/views/*/*.vue')
 
 
 /* Layout */
 /* Layout */
 const Layout = () => import('@/layout/index.vue')
 const Layout = () => import('@/layout/index.vue')

+ 3 - 2
src/views/components-demo/detail/index.vue

@@ -113,6 +113,7 @@
 
 
 <script setup lang="ts" name="DetailDemo">
 <script setup lang="ts" name="DetailDemo">
 import { reactive, ref, unref } from 'vue'
 import { reactive, ref, unref } from 'vue'
+import { SchemaConfig } from '_c/ComDetail/types'
 
 
 const formRef = ref<Nullable<any>>(null)
 const formRef = ref<Nullable<any>>(null)
 
 
@@ -135,7 +136,7 @@ const data = reactive<IObj>({
   certy: '35058319940712xxxx'
   certy: '35058319940712xxxx'
 })
 })
 
 
-const schema = reactive<IObj[]>([
+const schema = reactive<SchemaConfig[]>([
   {
   {
     field: 'username',
     field: 'username',
     label: '用户名'
     label: '用户名'
@@ -159,7 +160,7 @@ const schema = reactive<IObj[]>([
   }
   }
 ])
 ])
 
 
-const fromSchema = reactive<IObj[]>([
+const fromSchema = reactive<SchemaConfig[]>([
   {
   {
     field: 'title',
     field: 'title',
     label: '标题',
     label: '标题',

+ 61 - 0
src/views/directives-demo/clipboard/index.vue

@@ -0,0 +1,61 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="自定义指令:v-clipboard,用于复制文本。"
+      type="info"
+      style="margin-bottom: 20px"
+    />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基础示例。"
+      type="info"
+      style="margin-top: 20px; margin-bottom: 20px"
+    />
+    <div class="input__wrap">
+      <el-input v-model="inputVal1" placeholder="请输入要复制的文本" />
+      <el-button v-clipboard="inputVal1" type="primary">复制</el-button>
+    </div>
+
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="自定义回调方法。"
+      type="info"
+      style="margin-top: 20px; margin-bottom: 20px"
+    />
+    <div class="input__wrap">
+      <el-input v-model="inputVal2" placeholder="请输入要复制的文本" />
+      <el-button
+        v-clipboard="inputVal2"
+        v-clipboard:success="clipboardSuccess"
+        v-clipboard:error="clipboardError"
+        type="primary"
+        >复制</el-button
+      >
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts" name="DirectivesDemo">
+import { ref } from 'vue'
+import { Message } from '_c/Message'
+const inputVal1 = ref<string>('')
+const inputVal2 = ref<string>('')
+function clipboardSuccess(val: any) {
+  Message.success('我是自定义成功回调:' + val.text)
+}
+function clipboardError() {
+  Message.error('我是自定义失败回调')
+}
+</script>
+
+<style lang="less" scoped>
+.input__wrap {
+  display: flex;
+  padding: 20px;
+  background: #fff;
+}
+</style>

+ 58 - 0
src/views/icons/index.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="icons-container">
+    <div v-for="item of svgIcons" :key="item" v-clipboard="generateIconCode(item)">
+      <el-tooltip placement="top" :content="generateIconCode(item)">
+        <div class="icon-item">
+          <svg-icon :icon-class="item" class-name="disabled" />
+          <span>{{ item }}</span>
+        </div>
+      </el-tooltip>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import svgIcons from './svg-icons'
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+  // name: 'Icons',
+  setup() {
+    function generateIconCode(symbol: string) {
+      return `<svg-icon icon-class="${symbol}" />`
+    }
+    return {
+      svgIcons,
+      generateIconCode
+    }
+  }
+})
+</script>
+
+<style lang="less" scoped>
+.icons-container {
+  overflow: hidden;
+  background: #fff;
+
+  .icon-item {
+    float: left;
+    width: 100px;
+    height: 85px;
+    margin: 20px;
+    font-size: 30px;
+    color: #24292e;
+    text-align: center;
+    cursor: pointer;
+  }
+
+  span {
+    display: block;
+    margin-top: 10px;
+    font-size: 16px;
+  }
+
+  .disabled {
+    pointer-events: none;
+  }
+}
+</style>

+ 9 - 0
src/views/icons/svg-icons.ts

@@ -0,0 +1,9 @@
+const modules = import.meta.glob('../../assets/icons/*.svg')
+
+const svgIcons: string[] = []
+
+for (const key in modules) {
+  svgIcons.push(key.split('../../assets/icons/')[1].split('.')[0])
+}
+
+export default svgIcons

+ 3 - 3
src/views/table-demo/custom-header/index.vue

@@ -21,9 +21,9 @@
       </template>
       </template>
       <template #action="scope">
       <template #action="scope">
         <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">Edit</el-button>
         <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">Edit</el-button>
-        <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)"
-          >Delete</el-button
-        >
+        <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">
+          Delete
+        </el-button>
       </template>
       </template>
     </com-table>
     </com-table>
   </div>
   </div>

+ 3 - 3
src/views/table-demo/multiple-choice/index.vue

@@ -17,9 +17,9 @@
     />
     />
 
 
     <div style="margin-top: 20px">
     <div style="margin-top: 20px">
-      <el-button @click="toggleSelection([tableData[1], tableData[2]])"
-        >切换第二、第三行的选中状态</el-button
-      >
+      <el-button @click="toggleSelection([tableData[1], tableData[2]])">
+        切换第二、第三行的选中状态
+      </el-button>
       <el-button @click="toggleSelection()">取消选择</el-button>
       <el-button @click="toggleSelection()">取消选择</el-button>
     </div>
     </div>
   </div>
   </div>