Răsfoiți Sursa

feat: 🎸 layout三种布局重构完成

chenkl 4 ani în urmă
părinte
comite
429e42809c
90 a modificat fișierele cu 3926 adăugiri și 4680 ștergeri
  1. 2 2
      package.json
  2. 6 6
      src/components/Editor/props.ts
  3. 0 243
      src/components/Image/index.vue
  4. 1 1
      src/components/Logo/index.vue
  5. 4 8
      src/components/Preview/index.vue
  6. 0 128
      src/components/Scrollbar/Bar.vue
  7. 0 254
      src/components/Scrollbar/index.vue
  8. 0 14
      src/components/Scrollbar/types.ts
  9. 0 49
      src/components/Scrollbar/util.ts
  10. 105 157
      src/components/Search/index.vue
  11. 135 64
      src/components/Setting/index.vue
  12. 0 94
      src/components/Table/Table.tsx
  13. 0 53
      src/components/Table/TableItem.vue
  14. 35 0
      src/components/Table/components/Slot.vue
  15. 84 0
      src/components/Table/components/TableColumn.vue
  16. 0 3
      src/components/Table/index.ts
  17. 81 19
      src/components/Table/index.vue
  18. 3 3
      src/directives/clipboard/index.ts
  19. 6 0
      src/libs/element.ts
  20. 1 1
      src/pages/index/axios-config/axios.ts
  21. 2 37
      src/pages/index/axios-config/config/index.ts
  22. 9 0
      src/pages/index/axios-config/config/types.d.ts
  23. 4 4
      src/pages/index/axios-config/request.ts
  24. 0 16
      src/pages/index/config/types.d.ts
  25. 0 77
      src/pages/index/layout/components/Logo.vue
  26. 0 75
      src/pages/index/layout/components/Navbar.vue
  27. 0 34
      src/pages/index/layout/components/Silder/Item.vue
  28. 0 92
      src/pages/index/layout/components/Silder/hooks/setSidebarItem.ts
  29. 0 10
      src/pages/index/layout/components/Silder/hooks/types.d.ts
  30. 0 10
      src/pages/index/layout/components/Silder/index.less
  31. 0 3
      src/pages/index/layout/components/Silder/index.ts
  32. 0 176
      src/pages/index/layout/components/Silder/index.tsx
  33. 0 377
      src/pages/index/layout/components/TagsView.vue
  34. 0 68
      src/pages/index/layout/components/UserInfo.vue
  35. 11 14
      src/pages/index/layout/index.vue
  36. 219 80
      src/pages/index/layout/modules/Classic.vue
  37. 279 133
      src/pages/index/layout/modules/LeftTop.vue
  38. 256 93
      src/pages/index/layout/modules/Top.vue
  39. 1 1
      src/pages/index/main.ts
  40. 3 5
      src/pages/index/permission.ts
  41. 298 275
      src/pages/index/router/index.ts
  42. 13 1
      src/pages/index/store/modules/app.ts
  43. 25 25
      src/pages/index/views/components-demo/button/index.vue
  44. 34 27
      src/pages/index/views/components-demo/count-to/index.vue
  45. 17 11
      src/pages/index/views/components-demo/echarts/index.vue
  46. 7 1
      src/pages/index/views/components-demo/editor/index.vue
  47. 0 141
      src/pages/index/views/components-demo/image/index.vue
  48. 7 1
      src/pages/index/views/components-demo/markdown/index.vue
  49. 33 9
      src/pages/index/views/components-demo/preview/index.vue
  50. 3 3
      src/pages/index/views/components-demo/scroll/index.vue
  51. 75 73
      src/pages/index/views/components-demo/search/classic-data.ts
  52. 28 4
      src/pages/index/views/components-demo/search/index.vue
  53. 0 64
      src/pages/index/views/dashboard/index.vue
  54. 29 11
      src/pages/index/views/directives-demo/clipboard/index.vue
  55. 14 12
      src/pages/index/views/hooks-demo/useScrollTo/index.vue
  56. 10 4
      src/pages/index/views/hooks-demo/useWatermark/index.vue
  57. 2 5
      src/pages/index/views/icons/index.vue
  58. 2 2
      src/pages/index/views/login/index.vue
  59. 73 0
      src/pages/index/views/table-demo/basic-table/index.vue
  60. 0 118
      src/pages/index/views/table-demo/basic-usage/index.vue
  61. 78 0
      src/pages/index/views/table-demo/border-table/index.vue
  62. 111 0
      src/pages/index/views/table-demo/custom-header/index.vue
  63. 0 198
      src/pages/index/views/table-demo/custom-menu/index.vue
  64. 0 98
      src/pages/index/views/table-demo/edit-cell/EditableCell.vue
  65. 0 104
      src/pages/index/views/table-demo/edit-cell/index.vue
  66. 0 141
      src/pages/index/views/table-demo/edit-row/index.vue
  67. 140 0
      src/pages/index/views/table-demo/expand-row/index.vue
  68. 166 0
      src/pages/index/views/table-demo/fixed-column-header/index.vue
  69. 133 0
      src/pages/index/views/table-demo/fixed-column/index.vue
  70. 70 32
      src/pages/index/views/table-demo/fixed-header/index.vue
  71. 164 0
      src/pages/index/views/table-demo/fluid-height/index.vue
  72. 162 0
      src/pages/index/views/table-demo/multi-header/index.vue
  73. 102 0
      src/pages/index/views/table-demo/multiple-choice/index.vue
  74. 130 0
      src/pages/index/views/table-demo/screen-table/index.vue
  75. 96 0
      src/pages/index/views/table-demo/single-choice/index.vue
  76. 82 0
      src/pages/index/views/table-demo/sort-table/index.vue
  77. 100 0
      src/pages/index/views/table-demo/state-table/index.vue
  78. 78 0
      src/pages/index/views/table-demo/stripe-table/index.vue
  79. 0 87
      src/pages/index/views/table-demo/table-border/index.vue
  80. 0 102
      src/pages/index/views/table-demo/table-ellipsis/index.vue
  81. 0 66
      src/pages/index/views/table-demo/table-expanded/index.vue
  82. 0 107
      src/pages/index/views/table-demo/table-load/index.vue
  83. 0 151
      src/pages/index/views/table-demo/table-merge/index.vue
  84. 0 124
      src/pages/index/views/table-demo/table-tree/index.vue
  85. 4 4
      src/pages/index/views/table-demo/test/table.vue
  86. 167 0
      src/pages/index/views/table-demo/total-table/index.vue
  87. 181 0
      src/pages/index/views/table-demo/tree-and-load/index.vue
  88. 0 234
      src/styles/sidebar.less
  89. 41 37
      src/styles/sider.less
  90. 4 4
      yarn.lock

+ 2 - 2
package.json

@@ -1,5 +1,5 @@
 {
-  "name": "vue-element-admin-webpack",
+  "name": "vue-element-plus-admin-webpack",
   "version": "0.1.0",
   "private": true,
   "scripts": {
@@ -19,7 +19,7 @@
     "clipboard": "^2.0.6",
     "core-js": "^3.6.5",
     "echarts": "^4.9.0",
-    "element-plus": "^1.0.1-beta.8",
+    "element-plus": "1.0.1-beta.10",
     "highlight.js": "^10.4.0",
     "lodash-es": "^4.17.15",
     "mockjs": "^1.1.0",

+ 6 - 6
src/components/Editor/props.ts

@@ -1,5 +1,5 @@
 import { PropType } from 'vue'
-import { message } from 'ant-design-vue'
+import { ElMessage } from 'element-plus'
 import { oneOf } from '@/utils'
 
 import { Config } from './types'
@@ -18,19 +18,19 @@ export const editorProps = {
         customAlert: (s: string, t: string) => {
           switch (t) {
           case 'success':
-            message.success(s)
+            ElMessage.success(s)
             break
           case 'info':
-            message.info(s)
+            ElMessage.info(s)
             break
           case 'warning':
-            message.warning(s)
+            ElMessage.warning(s)
             break
           case 'error':
-            message.error(s)
+            ElMessage.error(s)
             break
           default:
-            message.info(s)
+            ElMessage.info(s)
             break
           }
         },

+ 0 - 243
src/components/Image/index.vue

@@ -1,243 +0,0 @@
-<template>
-  <div ref="imageRef" class="image">
-    <slot v-if="loading" name="placeholder">
-      <div class="image__placeholder" />
-    </slot>
-    <slot v-else-if="error" name="error">
-      <div class="image__error">加载失败</div>
-    </slot>
-    <img
-      v-else
-      v-bind="$attrs"
-      :src="src"
-      :style="imageStyle"
-      :class="{ 'image__inner--center': alignCenter }"
-      class="image__inner"
-    >
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, PropType, ref, computed, watch, onMounted, onBeforeUnmount, getCurrentInstance, unref } from 'vue'
-import { on, off, getScrollContainer, isInContainer } from '@/utils/dom-utils'
-import { isString, isElement } from '@/utils/is'
-import throttle from 'lodash-es/throttle'
-
-const isSupportObjectFit = () => document.documentElement.style.objectFit !== undefined
-
-const ObjectFit = {
-  NONE: 'none',
-  CONTAIN: 'contain',
-  COVER: 'cover',
-  FILL: 'fill',
-  SCALE_DOWN: 'scale-down'
-}
-
-export default defineComponent({
-  name: 'Image',
-  // inheritAttrs: false,
-  props: {
-    src: {
-      type: String as PropType<string>,
-      default: ''
-    },
-    fit: {
-      type: String as PropType<string>,
-      default: ''
-    },
-    lazy: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    scrollContainer: {
-      type: Object as PropType<any>,
-      default: null
-    }
-  },
-  emits: ['error'],
-  setup(props, { emit }) {
-    const { ctx } = getCurrentInstance() as any
-
-    const imageRef = ref<HTMLElement | null>(null)
-
-    const loading = ref<boolean>(true)
-    const error = ref<boolean>(false)
-    const show = ref<boolean>(!props.lazy)
-    const imageWidth = ref<number>(0)
-    const imageHeight = ref<number>(0)
-    const imageStyle = computed((): any => {
-      const { fit } = props
-      // if (!isServer && fit) {
-      if (fit) {
-        return isSupportObjectFit()
-          ? { 'object-fit': fit }
-          : getImageStyle(fit)
-      }
-      return {}
-    })
-    const alignCenter = computed((): boolean => {
-      const { fit } = props
-      // return !isServer && !isSupportObjectFit() && fit !== ObjectFit.FILL
-      return !isSupportObjectFit() && fit !== ObjectFit.FILL
-    })
-
-    let _scrollContainer: any = null
-    let _lazyLoadHandler: any = null
-
-    watch(
-      () => show.value,
-      (show: boolean) => {
-        show && loadImage()
-      }
-    )
-
-    watch(
-      () => props.src,
-      () => {
-        show.value && loadImage()
-      }
-    )
-
-    onMounted(() => {
-      if (props.lazy) {
-        addLazyLoadListener()
-      } else {
-        loadImage()
-      }
-    })
-
-    onBeforeUnmount(() => {
-      props.lazy && removeLazyLoadListener()
-    })
-
-    function loadImage(): void {
-      // reset status
-      loading.value = true
-      error.value = false
-
-      const img = new Image()
-      img.onload = (e: any) => handleLoad(e, img)
-      img.onerror = (e: any) => handleError(e)
-
-      // bind html attrs
-      // so it can behave consistently
-      Object.keys(ctx.$attrs)
-        .forEach((key) => {
-          const value = ctx.$attrs[key]
-          img.setAttribute(key, value)
-        })
-      img.src = props.src
-    }
-
-    function handleLoad(e: any, img: any): void {
-      imageWidth.value = img.width
-      imageHeight.value = img.height
-      loading.value = false
-    }
-
-    function handleError(e: any): void {
-      loading.value = false
-      error.value = true
-      emit('error', e)
-    }
-
-    function handleLazyLoad(): void {
-      const imageRefWrap = unref(imageRef) as any
-      if (isInContainer(imageRefWrap, _scrollContainer)) {
-        show.value = true
-        removeLazyLoadListener()
-      }
-    }
-
-    function addLazyLoadListener(): void {
-      // if (isServer) return
-
-      const { scrollContainer } = props
-      let __scrollContainer = null
-
-      if (isElement(scrollContainer)) {
-        __scrollContainer = scrollContainer
-      } else if (isString(scrollContainer)) {
-        __scrollContainer = document.querySelector(scrollContainer as any)
-      } else {
-        const imageRefWrap = unref(imageRef) as any
-        __scrollContainer = getScrollContainer(imageRefWrap)
-      }
-      if (__scrollContainer) {
-        _scrollContainer = __scrollContainer
-        _lazyLoadHandler = throttle(handleLazyLoad, 200)
-        on(__scrollContainer, 'scroll', _lazyLoadHandler)
-        handleLazyLoad()
-      }
-    }
-
-    function removeLazyLoadListener(): void {
-      // if (isServer || !_scrollContainer || !_lazyLoadHandler) return
-      if (!_scrollContainer || !_lazyLoadHandler) return
-
-      off(_scrollContainer, 'scroll', _lazyLoadHandler)
-      _scrollContainer = null
-      _lazyLoadHandler = null
-    }
-
-    /**
-     * simulate object-fit behavior to compatible with IE11 and other browsers which not support object-fit
-     */
-    function getImageStyle(fit: string): object {
-      const imageRefWrap = unref(imageRef) as any
-      const {
-        clientWidth: containerWidth,
-        clientHeight: containerHeight
-      } = imageRefWrap
-
-      if (!imageWidth.value || !imageHeight.value || !containerWidth || !containerHeight) return {}
-
-      const vertical: boolean = imageWidth.value / imageHeight.value < 1
-
-      if (fit === ObjectFit.SCALE_DOWN) {
-        const isSmaller: boolean = imageWidth.value < containerWidth && imageHeight.value < containerHeight
-        fit = isSmaller ? ObjectFit.NONE : ObjectFit.CONTAIN
-      }
-
-      switch (fit) {
-      case ObjectFit.NONE:
-        return { width: 'auto', height: 'auto' }
-      case ObjectFit.CONTAIN:
-        return vertical ? { width: 'auto' } : { height: 'auto' }
-      case ObjectFit.COVER:
-        return vertical ? { height: 'auto' } : { width: 'auto' }
-      default:
-        return {}
-      }
-    }
-
-    return {
-      imageRef,
-      loading, error, show,
-      imageStyle, alignCenter
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.image {
-  position: relative;
-  display: inline-block;
-  overflow: hidden;
-  .image__placeholder {
-    background: #f5f7fa;
-  }
-  .image__error {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 14px;
-    color: #c0c4cc;
-    vertical-align: middle;
-    height: 100%;
-    height: 100%;
-    background: #f5f7fa;
-  }
-}
-</style>

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

@@ -19,7 +19,7 @@ export default defineComponent({
   },
   setup(props) {
     const show = ref<boolean>(true)
-    const title = computed(() => appStore.title)
+    const title = computed(() => appStore.logoTitle)
     const layout = computed(() => appStore.layout)
     watch(
       () => props.collapsed,

+ 4 - 8
src/components/Preview/index.vue

@@ -10,7 +10,7 @@
       <div class="image-viewer__mask" />
       <!-- CLOSE -->
       <span class="image-viewer__btn image-viewer__close" @click="hide">
-        <CloseCircleOutlined class="iconfont" />
+        <i class="el-icon-circle-close iconfont" />
       </span>
       <!-- ARROW -->
       <template v-if="!isSingle">
@@ -19,14 +19,14 @@
           :class="{ 'is-disabled': !infinite && isFirst }"
           @click="prev"
         >
-          <LeftOutlined class="iconfont" />
+          <i class="el-icon-arrow-left iconfont" />
         </span>
         <span
           class="image-viewer__btn image-viewer__next"
           :class="{ 'is-disabled': !infinite && isLast }"
           @click="next"
         >
-          <RightOutlined class="iconfont" />
+          <i class="el-icon-arrow-right iconfont" />
         </span>
       </template>
       <!-- ACTIONS -->
@@ -63,15 +63,11 @@ import { isFirefox } from '@/utils/is'
 import { on, off } from '@/utils/dom-utils'
 import throttle from 'lodash-es/throttle'
 import SvgIcon from '_c/SvgIcon/index.vue'
-import { CloseCircleOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons-vue'
 const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
 export default defineComponent({
   name: 'Preview',
   components: {
-    SvgIcon,
-    CloseCircleOutlined,
-    LeftOutlined,
-    RightOutlined
+    SvgIcon
   },
   props: previewProps,
   setup(props) {

+ 0 - 128
src/components/Scrollbar/Bar.vue

@@ -1,128 +0,0 @@
-<template>
-  <div
-    ref="elRef"
-    :class="['scrollbar__bar', 'is-' + bar.key]"
-    @mousedown="clickTrackHandler"
-  >
-    <div
-      ref="thumbRef"
-      class="scrollbar__thumb"
-      :style="renderThumbStyle({ size, move, bar })"
-      @mousedown="clickThumbHandler"
-    />
-  </div>
-</template>
-
-<script lang="ts">
-import type { PropType } from 'vue'
-import { defineComponent, computed, unref, inject, Ref, reactive, ref, onBeforeUnmount } from 'vue'
-import { renderThumbStyle, BAR_MAP } from './util'
-import { on, off } from '@/utils/dom-utils'
-export default defineComponent({
-  name: 'Bar',
-  props: {
-    vertical: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    size: {
-      type: String as PropType<string>,
-      default: ''
-    },
-    move: {
-      type: Number as PropType<number>,
-      default: 0
-    }
-  },
-  setup(props) {
-    const thumbRef = ref<HTMLElement | null>(null)
-    const elRef = ref<HTMLElement | null>(null)
-    const commonState = reactive<any>({})
-    const getBarRef = computed(() => {
-      return BAR_MAP[props.vertical ? 'vertical' : 'horizontal']
-    })
-    const bar = unref(getBarRef)
-    const parentElRef = inject('scroll-bar-wrap') as Ref<HTMLElement>
-
-    function clickThumbHandler(e: any) {
-      const { ctrlKey, button, currentTarget } = e
-      // prevent click event of right button
-      if (ctrlKey || button === 2 || !currentTarget) {
-        return
-      }
-      startDrag(e)
-      const bar = unref(getBarRef)
-      commonState[bar.axis] =
-        currentTarget[bar.offset] -
-        (e[bar.client as keyof typeof e] - currentTarget.getBoundingClientRect()[bar.direction])
-    }
-
-    function clickTrackHandler(e: any) {
-      const bar = unref(getBarRef)
-      const offset = Math.abs(e.target.getBoundingClientRect()[bar.direction] - e[bar.client])
-      const thumbEl = unref(thumbRef) as any
-      const parentEl = unref(parentElRef) as any
-      const el = unref(elRef) as any
-      if (!thumbEl || !el || !parentEl) return
-      const thumbHalf = thumbEl[bar.offset] / 2
-      const thumbPositionPercentage = ((offset - thumbHalf) * 100) / el[bar.offset]
-      parentEl[bar.scroll] = (thumbPositionPercentage * parentEl[bar.scrollSize]) / 100
-    }
-
-    function startDrag(e: Event) {
-      e.stopImmediatePropagation()
-      commonState.cursorDown = true
-
-      on(document, 'mousemove', mouseMoveDocumentHandler)
-      on(document, 'mouseup', mouseUpDocumentHandler)
-      document.onselectstart = () => false
-    }
-
-    function mouseMoveDocumentHandler(e: any) {
-      if (commonState.cursorDown === false) return
-      const bar = unref(getBarRef)
-      const prevPage = commonState[bar.axis]
-      const el = unref(elRef) as any
-      const parentEl = unref(parentElRef) as any
-      const thumbEl = unref(thumbRef) as any
-      if (!prevPage || !el || !thumbEl || !parentEl) return
-      const rect = el.getBoundingClientRect() as any
-      const offset = (rect[bar.direction] - e[bar.client]) * -1
-      const thumbClickPosition = thumbEl[bar.offset] - prevPage
-      const thumbPositionPercentage = ((offset - thumbClickPosition) * 100) / el[bar.offset]
-
-      parentEl[bar.scroll] = (thumbPositionPercentage * parentEl[bar.scrollSize]) / 100
-    }
-
-    function mouseUpDocumentHandler() {
-      const bar = unref(getBarRef)
-      commonState.cursorDown = false
-      commonState[bar.axis] = 0
-      off(document, 'mousemove', mouseMoveDocumentHandler)
-      document.onselectstart = null
-    }
-
-    onBeforeUnmount(() => {
-      off(document, 'mouseup', mouseUpDocumentHandler)
-    })
-
-    return {
-      thumbRef,
-      elRef,
-      bar,
-      clickThumbHandler,
-      clickTrackHandler,
-      renderThumbStyle
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.scrollbar__bar.is-vertical>div {
-  width: 100%;
-}
-.scrollbar__bar.is-horizontal>div {
-  height: 100%;
-}
-</style>

+ 0 - 254
src/components/Scrollbar/index.vue

@@ -1,254 +0,0 @@
-<template>
-  <div class="scrollbar">
-    <template v-if="!native">
-      <div
-        ref="wrapElRef"
-        :style="style"
-        :class="[wrapClass, 'scrollbar__wrap', gutter ? '' : 'scrollbar__wrap--hidden-default']"
-        @scroll="handleScroll"
-      >
-        <div
-          ref="resizeRef"
-          :class="['scrollbar__view', viewClass]"
-          :style="viewStyle"
-        >
-          <slot />
-        </div>
-      </div>
-      <bar v-if="showX" :move="state.moveX" :size="state.sizeWidth" />
-      <bar v-if="showY" vertical :move="state.moveY" :size="state.sizeHeight" />
-    </template>
-    <template v-else>
-      <div
-        ref="wrap"
-        :class="[wrapClass, 'scrollbar__wrap']"
-        :style="style"
-      >
-        <div
-          ref="resizeRef"
-          :class="['scrollbar__view', viewClass]"
-          :style="viewStyle"
-        >
-          <slot />
-        </div>
-      </div>
-    </template>
-  </div>
-</template>
-
-<script lang="ts">
-import {
-  defineComponent,
-  PropType,
-  unref,
-  reactive,
-  ref,
-  toRef,
-  provide,
-  onMounted,
-  nextTick,
-  onBeforeUnmount,
-  getCurrentInstance
-} from 'vue'
-import { addResizeListener, removeResizeListener } from '@/utils/event/resize-event'
-import scrollbarWidth from '@/utils/scrollbar-width'
-import { isString } from '@/utils/is'
-import { toObject } from './util'
-import Bar from './Bar.vue'
-export default defineComponent({
-  name: 'Scrollbar',
-  components: {
-    Bar
-  },
-  props: {
-    native: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    wrapStyle: {
-      type: Object as PropType<any>,
-      default: () => null
-    },
-    wrapClass: {
-      type: String as PropType<string>, required: false,
-      default: ''
-    },
-    viewClass: {
-      type: String as PropType<string>,
-      default: ''
-    },
-    viewStyle: {
-      type: Object as PropType<any>,
-      default: () => {}
-    },
-    noresize: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    showX: {
-      type: Boolean as PropType<boolean>,
-      default: true
-    },
-    showY: {
-      type: Boolean as PropType<boolean>,
-      default: true
-    }
-    // tag: {
-    //   type: String as PropType<string>,
-    //   default: 'div'
-    // }
-  },
-  setup(props) {
-    const resizeRef = ref<HTMLElement | null>(null)
-    const wrapElRef = ref<HTMLElement | null>(null)
-    provide('scroll-bar-wrap', wrapElRef)
-    const state = reactive({
-      sizeWidth: '0',
-      sizeHeight: '0',
-      moveX: 0,
-      moveY: 0
-    })
-    let style: any = toRef(props, 'wrapStyle')
-    const gutter = scrollbarWidth()
-    if (gutter) {
-      const gutterWith = `-${gutter}px`
-      const gutterStyle = `margin-bottom: ${gutterWith}; margin-right: ${gutterWith};`
-
-      if (Array.isArray(props.wrapStyle)) {
-        style = toObject(props.wrapStyle)
-        style.value.marginRight = style.value.marginBottom = gutterWith
-      } else if (isString(props.wrapStyle)) {
-        style.value += gutterStyle
-      } else {
-        style = gutterStyle
-      }
-    }
-
-    function handleScroll() {
-      const warpEl = unref(wrapElRef)
-      if (!warpEl) return
-      const { scrollTop, scrollLeft, clientHeight, clientWidth } = warpEl
-
-      state.moveY = (scrollTop * 100) / clientHeight
-      state.moveX = (scrollLeft * 100) / clientWidth
-    }
-    function update() {
-      const warpEl = unref(wrapElRef)
-      if (!warpEl) return
-      const { scrollHeight, scrollWidth, clientHeight, clientWidth } = warpEl
-      const heightPercentage = (clientHeight * 100) / scrollHeight
-      const widthPercentage = (clientWidth * 100) / scrollWidth
-
-      state.sizeHeight = heightPercentage < 100 ? heightPercentage + '%' : ''
-      state.sizeWidth = widthPercentage < 100 ? widthPercentage + '%' : ''
-    }
-
-    onMounted(() => {
-      const instance = getCurrentInstance() as any
-      if (instance) {
-        instance.wrap = unref(wrapElRef)
-      }
-
-      const { native, noresize } = props
-      const resizeEl = unref(resizeRef)
-      const warpEl = unref(wrapElRef)
-      if (native || !resizeEl || !warpEl) return
-      nextTick(update)
-      if (!noresize) {
-        addResizeListener(resizeEl, update)
-        addResizeListener(warpEl, update)
-      }
-    })
-    onBeforeUnmount(() => {
-      const { native, noresize } = props
-      const resizeEl = unref(resizeRef)
-      const warpEl = unref(wrapElRef)
-      if (native || !resizeEl || !warpEl) return
-      if (!noresize) {
-        removeResizeListener(resizeEl, update)
-        removeResizeListener(warpEl, update)
-      }
-    })
-
-    return {
-      resizeRef, wrapElRef,
-      state, gutter, style,
-      handleScroll
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.scrollbar {
-  position: relative;
-  overflow: hidden;
-  height: 100%;
-
-  &__wrap {
-    height: 100%;
-    overflow: scroll;
-    overflow-x: hidden;
-
-    &--hidden-default {
-      scrollbar-width: none;
-
-      &::-webkit-scrollbar {
-        width: 0;
-        height: 0;
-      }
-    }
-  }
-
-  @{deep}(&__thumb) {
-    position: relative;
-    display: block;
-    width: 0;
-    height: 0;
-    cursor: pointer;
-    background-color: rgba(144, 147, 153, 0.3);
-    border-radius: inherit;
-    transition: 0.3s background-color;
-
-    &:hover {
-      background-color: rgba(144, 147, 153, 0.5);
-    }
-  }
-
-  &__bar {
-    position: absolute;
-    right: 2px;
-    bottom: 2px;
-    z-index: 1;
-    border-radius: 4px;
-    opacity: 0;
-    -webkit-transition: opacity 120ms ease-out;
-    transition: opacity 120ms ease-out;
-
-    &.is-vertical {
-      top: 2px;
-      width: 6px;
-
-      & > div {
-        width: 100%;
-      }
-    }
-
-    &.is-horizontal {
-      left: 2px;
-      height: 6px;
-
-      & > div {
-        height: 100%;
-      }
-    }
-  }
-}
-
-.scrollbar:active > .scrollbar__bar,
-.scrollbar:focus > .scrollbar__bar,
-.scrollbar:hover > .scrollbar__bar {
-  opacity: 1;
-  transition: opacity 280ms ease-out;
-}
-</style>

+ 0 - 14
src/components/Scrollbar/types.ts

@@ -1,14 +0,0 @@
-export interface BarMapItem {
-  offset: string
-  scroll: string
-  scrollSize: string
-  size: string
-  key: string
-  axis: string
-  client: string
-  direction: string
-}
-export interface BarMap {
-  vertical: BarMapItem
-  horizontal: BarMapItem
-}

+ 0 - 49
src/components/Scrollbar/util.ts

@@ -1,49 +0,0 @@
-import type { BarMap } from './types'
-export const BAR_MAP: BarMap = {
-  vertical: {
-    offset: 'offsetHeight',
-    scroll: 'scrollTop',
-    scrollSize: 'scrollHeight',
-    size: 'height',
-    key: 'vertical',
-    axis: 'Y',
-    client: 'clientY',
-    direction: 'top'
-  },
-  horizontal: {
-    offset: 'offsetWidth',
-    scroll: 'scrollLeft',
-    scrollSize: 'scrollWidth',
-    size: 'width',
-    key: 'horizontal',
-    axis: 'X',
-    client: 'clientX',
-    direction: 'left'
-  }
-}
-
-export function renderThumbStyle({ move, size, bar }: any) {
-  const style = {} as any
-  const translate = `translate${bar.axis}(${move}%)`
-
-  style[bar.size] = size
-  style.transform = translate
-  style.msTransform = translate
-  style.webkitTransform = translate
-
-  return style
-}
-
-function extend<T, K>(to: T, _from: K): T & K {
-  return Object.assign(to, _from)
-}
-
-export function toObject<T>(arr: Array<T>): Record<string, T> {
-  const res = {}
-  for (let i = 0; i < arr.length; i++) {
-    if (arr[i]) {
-      extend(res, arr[i])
-    }
-  }
-  return res
-}

+ 105 - 157
src/components/Search/index.vue

@@ -1,96 +1,86 @@
 <template>
   <div :class="{ search__col: layout === 'right' }">
-    <a-row :gutter="20">
-      <a-col :span="layout === 'right' ? 22 : 24">
-        <a-form
+    <el-row :gutter="20">
+      <el-col :span="layout === 'right' ? 22 : 24">
+        <el-form
           ref="ruleForm"
-          layout="inline"
+          inline
           :model="formInline"
           :rules="rules"
-          :label-col="labelCol"
-          :wrapper-col="wrapperCol"
-          :label-align="labelAlign"
-          :hide-required-mark="hideRequiredMark"
+          :label-width="labelWidth"
+          :label-position="labelPosition"
+          :hide-required-asterisk="hideRequiredAsterisk"
           @submit.prevent
         >
-          <a-form-item
+          <el-form-item
             v-for="(item, $index) in data"
             :key="$index"
             :label="item.label"
-            :name="item.field"
+            :prop="item.field"
             :rules="item.rules"
           >
-            <template v-if="item.type === 'switch'">
-              <a-switch
-                v-model:checked="formInline[item.field]"
-                :size="item.size"
-                :checked-children="item.checkedChildren"
-                :un-checked-children="item.unCheckedChildren"
+            <template v-if="item.itemType === 'switch'">
+              <el-switch
+                v-model="formInline[item.field]"
+                v-bind="{...bindValue(item)}"
                 @change="((val) => {changeVal(val, item)})"
               />
             </template>
 
-            <template v-if="item.type === 'input'">
-              <a-input
-                v-model:value="formInline[item.field]"
-                :size="item.size"
-                :maxlength="item.maxlength"
-                :placeholder="item.placeholder"
-                :addon-before="item.addonBefore"
-                :addon-after="item.addonAfter"
-                :allow-clear="item.allowClear"
+            <template v-if="item.itemType === 'input'">
+              <el-input
+                v-model="formInline[item.field]"
+                v-bind="{...bindValue(item)}"
                 @change="((val) => {changeVal(val, item)})"
               />
             </template>
 
-            <template v-if="item.type === 'select'">
-              <a-select
-                v-model:value="formInline[item.field]"
-                :size="item.size"
-                :placeholder="item.placeholder"
-                :allow-clear="item.allowClear"
-                style="min-width: 201px;"
+            <template v-if="item.itemType === 'select'">
+              <el-select
+                v-model="formInline[item.field]"
+                v-bind="{...bindValue(item)}"
                 @change="((val) => {changeVal(val, item)})"
               >
-                <a-select-option
+                <el-option
                   v-for="v in item.options"
                   :key="item.optionValue ? v[item.optionValue] : v.value"
                   :value="item.optionValue ? v[item.optionValue] : v.value"
-                >
-                  {{ item.optionLabel ? v[item.optionLabel] : v.title }}
-                </a-select-option>
-              </a-select>
+                  :label="item.optionLabel ? v[item.optionLabel] : v.title"
+                />
+              </el-select>
             </template>
 
-            <template v-if="item.type === 'radio'">
-              <a-radio-group
-                v-model:value="formInline[item.field]"
-                :size="item.size"
+            <template v-if="item.itemType === 'radio'">
+              <el-radio-group
+                v-model="formInline[item.field]"
                 @change="((val) => {changeVal(val, item)})"
               >
                 <template v-if="item.radioType === 'radio'">
-                  <a-radio
+                  <el-radio
                     v-for="v in item.options"
                     :key="item.optionValue ? v[item.optionValue] : v.value"
-                    :value="item.optionValue ? v[item.optionValue] : v.value"
+                    v-bind="{...bindValue(item)}"
+                    :label="item.optionValue ? v[item.optionValue] : v.value"
                   >
                     {{ item.optionLabel ? v[item.optionLabel] : v.label }}
-                  </a-radio>
+                  </el-radio>
                 </template>
                 <template v-else-if="item.radioType === 'button'">
-                  <a-radio-button
+                  <el-radio-button
                     v-for="v in item.options"
                     :key="item.optionValue ? v[item.optionValue] : v.value"
-                    :value="item.optionValue ? v[item.optionValue] : v.value"
+                    v-bind="{...bindValue(item)}"
+                    :label="item.optionValue ? v[item.optionValue] : v.value"
                   >
                     {{ item.optionLabel ? v[item.optionLabel] : v.label }}
-                  </a-radio-button>
+                  </el-radio-button>
                 </template>
-              </a-radio-group>
+              </el-radio-group>
             </template>
 
-            <template v-if="item.type === 'treeSelect'">
-              <a-tree-select
+            <!-- element近期会新增treeSelect组件,所以不打算在自己维护一套。等待ing -->
+            <!-- <template v-if="item.itemType === 'treeSelect'">
+              <el-tree-select
                 v-model:value="formInline[item.field]"
                 :size="item.size"
                 :dropdown-style="item.dropdownStyle"
@@ -106,161 +96,102 @@
                 <template #title="{ title }">
                   <span>{{ title }}</span>
                 </template>
-              </a-tree-select>
-            </template>
+              </el-tree-select>
+            </template> -->
 
-            <template v-if="item.type === 'datePicker'">
-              <a-date-picker
-                v-model:value="formInline[item.field]"
-                :format="item.format"
-                :mode="item.mode"
-                :value-format="item.valueFormat"
-                :placeholder="item.placeholder"
-                :size="item.size"
-                :allow-clear="item.allowClear"
-                :disabled-date="item.disabledDate"
-                :disabled-time="item.disabledDateTime"
-                :show-time="item.showTime"
+            <template v-if="item.itemType === 'timePicker'">
+              <el-time-picker
+                v-model="formInline[item.field]"
+                v-bind="{...bindValue(item)}"
                 @change="((val) => {changeVal(val, item)})"
               />
             </template>
 
-            <template v-if="item.type === 'monthPicker'">
-              <a-month-picker
-                v-model:value="formInline[item.field]"
-                :format="item.format"
-                :mode="item.mode"
-                :value-format="item.valueFormat"
-                :placeholder="item.placeholder"
-                :size="item.size"
-                :allow-clear="item.allowClear"
-                :disabled-date="item.disabledDate"
-                :disabled-time="item.disabledDateTime"
-                :show-time="item.showTime"
+            <template v-if="item.itemType === 'timeSelect'">
+              <el-time-select
+                v-model="formInline[item.field]"
+                v-bind="{...bindValue(item)}"
                 @change="((val) => {changeVal(val, item)})"
               />
             </template>
 
-            <template v-if="item.type === 'rangePicker'">
-              <a-range-picker
-                v-model:value="formInline[item.field]"
-                :format="item.format"
-                :mode="item.mode"
-                :value-format="item.valueFormat"
-                :placeholder="item.placeholder"
-                :size="item.size"
-                :allow-clear="item.allowClear"
-                :disabled-date="item.disabledDate"
-                :disabled-time="item.disabledDateTime"
-                :show-time="item.showTime"
-                :ranges="item.ranges"
-                @change="((val) => {changeVal(val, item)})"
-              />
-            </template>
-
-            <template v-if="item.type === 'weekPicker'">
-              <a-week-picker
-                v-model:value="formInline[item.field]"
-                :format="item.format"
-                :mode="item.mode"
-                :value-format="item.valueFormat"
-                :placeholder="item.placeholder"
-                :size="item.size"
-                :allow-clear="item.allowClear"
-                :disabled-date="item.disabledDate"
-                :disabled-time="item.disabledDateTime"
-                :show-time="item.showTime"
+            <template v-if="item.itemType === 'datePicker' || item.itemType === 'dateTimePicker'">
+              <el-date-picker
+                v-model="formInline[item.field]"
+                v-bind="{...bindValue(item)}"
                 @change="((val) => {changeVal(val, item)})"
               />
             </template>
-          </a-form-item>
-          <a-form-item v-if="data.length > 0 && layout === 'classic'">
-            <a-button
+          </el-form-item>
+          <el-form-item v-if="data.length > 0 && layout === 'classic'">
+            <el-button
               type="primary"
+              icon="el-icon-search"
               @click="submitForm"
             >
-              <template #icon>
-                <SearchOutlined />
-              </template>
               查询
-            </a-button>
-            <a-button
+            </el-button>
+            <el-button
               v-if="showReset"
+              icon="el-icon-refresh-right"
               @click="resetForm"
             >
-              <template #icon>
-                <ReloadOutlined />
-              </template>
               重置
-            </a-button>
-          </a-form-item>
-        </a-form>
-      </a-col>
-      <a-col :span="layout === 'right' ? 2 : 24">
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-col>
+      <el-col :span="layout === 'right' ? 2 : 24">
         <div
           v-if="data.length > 0 && (layout === 'bottom' || layout === 'right')"
           class="search__bottom"
           :class="{ 'search__bottom--col': layout === 'right' }"
         >
           <div class="search__bottom--button">
-            <a-button
+            <el-button
               type="primary"
+              icon="el-icon-search"
               @click="submitForm"
             >
-              <template #icon>
-                <SearchOutlined />
-              </template>
               查询
-            </a-button>
+            </el-button>
           </div>
           <div class="search__bottom--button">
-            <a-button
+            <el-button
               v-if="showReset"
               :style="{
                 'margin-left': layout !== 'right' ? '15px' : '0',
                 'margin-top': layout === 'right' ? '27px' : '0'
               }"
+              icon="el-icon-refresh-right"
               @click="resetForm"
             >
-              <template #icon>
-                <ReloadOutlined />
-              </template>
               重置
-            </a-button>
+            </el-button>
           </div>
         </div>
-      </a-col>
-    </a-row>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, PropType, watch, ref, unref } from 'vue'
-import { SearchOutlined, ReloadOutlined } from '@ant-design/icons-vue'
+import { deepClone } from '@/utils'
 export default defineComponent({
   name: 'Search',
-  components: {
-    SearchOutlined,
-    ReloadOutlined
-  },
   props: {
-    // label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12}
-    labelCol: {
-      type: Object as PropType<{ span: number }>,
-      default: () => {}
+    // 表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 auto。
+    labelWidth: {
+      type: String as PropType<string>,
+      default: ''
     },
-    // 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol
-    wrapperCol: {
-      type: Object as PropType<{ span: number }>,
-      default: () => {}
-    },
-    // label 标签的文本对齐方式
-    labelAlign: {
-      type: String as PropType<'left' | 'right'>,
+    labelPosition: {
+      type: String as PropType<'right' | 'left' | 'top'>,
       default: 'right'
     },
     // 隐藏所有表单项的必选标记
-    hideRequiredMark: {
+    hideRequiredAsterisk: {
       type: Boolean as PropType<boolean>,
       default: true
     },
@@ -305,6 +236,17 @@ export default defineComponent({
       }
     )
 
+    function bindValue(item: any) {
+      const delArr: string[] = ['label', 'itemType', 'value', 'field']
+      const obj = deepClone(item)
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      return obj
+    }
+
     function initForm(data: any): void {
       for (const v of data) {
         formInline.value[v.field] = formInline.value[v.field] || v.value
@@ -315,10 +257,15 @@ export default defineComponent({
       const form = unref(ruleForm) as any
       if (!form) return
       try {
-        const data = await form.validate()
-        if (data) {
-          emit('search-submit', data)
-        }
+        form.validate((valid: boolean) => {
+          if (valid) {
+            console.log(valid)
+            emit('search-submit', unref(formInline))
+          } else {
+            console.log('error submit!!')
+            return false
+          }
+        })
       } catch (err) {
         console.log(err)
       }
@@ -328,19 +275,20 @@ export default defineComponent({
       const form = unref(ruleForm) as any
       if (!form) return
       await form.resetFields()
-      emit('reset-submit', formInline.value)
+      emit('reset-submit', unref(formInline))
     }
 
     function changeVal(val: any, item: any): void {
       if (item.onChange) {
         emit('change', {
           field: item.field,
-          value: formInline.value[item.field]
+          value: unref(formInline.value[item.field])
         })
       }
     }
 
     return {
+      bindValue,
       ruleForm,
       formInline,
       submitForm,

+ 135 - 64
src/components/Setting/index.vue

@@ -1,72 +1,101 @@
 <template>
-  <div class="setting__content">
-    <div class="setting__title">导航栏布局</div>
-    <div class="icon__wrap">
-      <span :class="{'icon--active': layout==='Classic'}" @click="setLayout('Classic')">
-        <el-tooltip effect="dark" content="经典布局" placement="bottom">
-          <svg-icon icon-class="layout-classic" class="setting-svg-icon" />
-        </el-tooltip>
-      </span>
-      <span :class="{'icon--active': layout==='LeftTop'}" @click="setLayout('LeftTop')">
-        <el-tooltip effect="dark" content="左侧顶部布局" placement="bottom">
-          <svg-icon icon-class="layout-topLeft" class="setting-svg-icon" />
-        </el-tooltip>
-      </span>
-      <span :class="{'icon--active': layout==='Top'}" @click="setLayout('Top')">
-        <el-tooltip effect="dark" content="顶部布局" placement="bottom">
-          <svg-icon icon-class="layout-top" class="setting-svg-icon" />
-        </el-tooltip>
-      </span>
-    </div>
+  <div class="setting__wrap" @click="toggleClick">
+    <i class="el-icon-setting" />
+  </div>
+  <el-drawer
+    v-model="drawer"
+    direction="rtl"
+    size="20%"
+  >
+    <template #title>
+      <div class="setting__title">项目配置</div>
+    </template>
+    <div class="setting__content">
+      <div class="setting__title">导航栏布局</div>
+      <div class="icon__wrap">
+        <span :class="{'icon--active': layout==='Classic'}" @click="setLayout('Classic')">
+          <el-tooltip effect="dark" content="经典布局" placement="bottom">
+            <svg-icon icon-class="layout-classic" class="setting-svg-icon" />
+          </el-tooltip>
+        </span>
+        <span :class="{'icon--active': layout==='LeftTop'}" @click="setLayout('LeftTop')">
+          <el-tooltip effect="dark" content="左侧顶部布局" placement="bottom">
+            <svg-icon icon-class="layout-topLeft" class="setting-svg-icon" />
+          </el-tooltip>
+        </span>
+        <span :class="{'icon--active': layout==='Top'}" @click="setLayout('Top')">
+          <el-tooltip effect="dark" content="顶部布局" placement="bottom">
+            <svg-icon icon-class="layout-top" class="setting-svg-icon" />
+          </el-tooltip>
+        </span>
+      </div>
 
-    <div class="setting__title">侧边菜单主题</div>
+      <!--      <div class="setting__title">侧边菜单主题</div>
 
-    <div class="setting__title">顶部菜单主题</div>
+      <div class="setting__title">顶部菜单主题</div> -->
 
-    <div class="setting__title">界面功能</div>
-    <!-- <div class="setting__item">
-      <span>固定顶部操作栏</span>
-      <el-switch v-model="fixedNavbar" @change="setFixedNavbar" />
-    </div>
-    <div class="setting__item">
-      <span>固定标签页</span>
-      <el-switch v-model="fixedTags" @change="setFixedTags" />
-    </div> -->
-    <div class="setting__item">
-      <span>固定Header</span>
-      <el-switch v-model="fixedHeader" @change="setFixedHeader" />
-    </div>
+      <!-- <div class="setting__title">界面功能</div> -->
+      <!-- <div class="setting__item">
+        <span>固定顶部操作栏</span>
+        <el-switch v-model="fixedNavbar" @change="setFixedNavbar" />
+      </div>
+      <div class="setting__item">
+        <span>固定标签页</span>
+        <el-switch v-model="fixedTags" @change="setFixedTags" />
+      </div> -->
 
-    <div class="setting__title">界面显示</div>
-    <div v-if="layout !== 'Top'" class="setting__item">
-      <span>顶部操作栏</span>
-      <el-switch v-model="navbar" @change="setNavbar" />
-    </div>
-    <div v-if="layout !== 'Top'" class="setting__item">
-      <span>侧边栏缩收</span>
-      <el-switch v-model="hamburger" @change="setHamburger" />
-    </div>
-    <div v-if="layout !== 'Top'" class="setting__item">
-      <span>面包屑</span>
-      <el-switch v-model="breadcrumb" @change="setBreadcrumb" />
-    </div>
-    <div class="setting__item">
-      <span>全屏按钮</span>
-      <el-switch v-model="screenfull" @change="setScreenfull" />
-    </div>
-    <div class="setting__item">
-      <span>用户头像</span>
-      <el-switch v-model="userInfo" @change="setUserInfo" />
-    </div>
-    <div class="setting__item">
-      <span>标签页</span>
-      <el-switch v-model="tagsView" @change="setTagsView" />
-    </div>
-    <div class="setting__item">
-      <span>LOGO</span>
-      <el-switch v-model="logo" @change="setLogo" />
+      <div class="setting__title">界面显示</div>
+      <div class="setting__item">
+        <span>固定Header</span>
+        <el-switch v-model="fixedHeader" @change="setFixedHeader" />
+      </div>
+
+      <div v-if="layout !== 'Top'" class="setting__item">
+        <span>顶部操作栏</span>
+        <el-switch v-model="navbar" @change="setNavbar" />
+      </div>
+
+      <div v-if="layout !== 'Top'" class="setting__item">
+        <span>侧边栏缩收</span>
+        <el-switch v-model="hamburger" @change="setHamburger" />
+      </div>
+
+      <div v-if="layout !== 'Top'" class="setting__item">
+        <span>面包屑</span>
+        <el-switch v-model="breadcrumb" @change="setBreadcrumb" />
+      </div>
+
+      <div class="setting__item">
+        <span>全屏按钮</span>
+        <el-switch v-model="screenfull" @change="setScreenfull" />
+      </div>
+
+      <div class="setting__item">
+        <span>用户头像</span>
+        <el-switch v-model="userInfo" @change="setUserInfo" />
+      </div>
+
+      <div class="setting__item">
+        <span>标签页</span>
+        <el-switch v-model="tagsView" @change="setTagsView" />
+      </div>
+
+      <div class="setting__item">
+        <span>LOGO</span>
+        <el-switch v-model="logo" @change="setLogo" />
+      </div>
+
+      <div class="setting__item">
+        <span>页面标题</span>
+        <el-input v-model="title" size="mini" @change="setTitle" />
+      </div>
+
+      <div class="setting__item">
+        <span>LOGO标题</span>
+        <el-input v-model="logoTitle" size="mini" @change="setLogoTitle" />
+      </div>
     </div>
-  </div>
+  </el-drawer>
 </template>
 
 <script lang="ts">
@@ -75,6 +104,11 @@ import { appStore } from '_p/index/store/modules/app'
 export default defineComponent({
   name: 'Setting',
   setup() {
+    const drawer = ref<boolean>(false)
+    function toggleClick(): void {
+      drawer.value = !drawer.value
+    }
+
     const layout = computed(() => appStore.layout)
     function setLayout(mode: 'Classic' | 'LeftTop' | 'Top' | 'Test') {
       if (mode === layout.value) return
@@ -132,7 +166,18 @@ export default defineComponent({
       appStore.SetShowLogo(logo)
     }
 
+    const title = ref<string>(appStore.title)
+    function setTitle(title: string) {
+      appStore.SetTitle(title)
+    }
+
+    const logoTitle = ref<string>(appStore.logoTitle)
+    function setLogoTitle(logoTitle: string) {
+      appStore.SetLogoTitle(logoTitle)
+    }
+
     return {
+      drawer, toggleClick,
       layout, setLayout,
       // fixedNavbar, setFixedNavbar,
       // fixedTags, setFixedTags,
@@ -143,13 +188,35 @@ export default defineComponent({
       screenfull, setScreenfull,
       userInfo, setUserInfo,
       tagsView, setTagsView,
-      logo, setLogo
+      logo, setLogo,
+      title, setTitle,
+      logoTitle, setLogoTitle
     }
   }
 })
 </script>
 
 <style lang="less" scoped>
+// 项目配置
+.setting__wrap {
+  position: fixed;
+  top: 45%;
+  right: 0;
+  z-index: 10;
+  display: flex;
+  padding: 10px;
+  color: #fff;
+  cursor: pointer;
+  background: #018ffb;
+  border-radius: 6px 0 0 6px;
+  justify-content: center;
+  align-items: center;
+}
+.setting__title {
+  font-weight: bold;
+  color: black;
+}
+// 项目配置
 .setting__content {
   background: @appBg;
   padding: 0 20px;
@@ -181,6 +248,10 @@ export default defineComponent({
     display: flex;
     justify-content: space-between;
     margin: 16px 0;
+    align-items: center;
+    &>span {
+      min-width: 100px;
+    }
   }
 }
 </style>

+ 0 - 94
src/components/Table/Table.tsx

@@ -1,94 +0,0 @@
-import { defineComponent, PropType, computed } from 'vue'
-import { Table } from 'ant-design-vue'
-
-export default defineComponent({
-  name: 'ComTable',
-  props: {
-    columns: {
-      type: Array as PropType<any[]>,
-      default: () => []
-    }
-  },
-  setup(props, { attrs, slots }) {
-    const getBindValue = computed((): any => {
-      const bindValue = { ...attrs, ...props }
-      delete bindValue.columns
-      return bindValue
-    })
-    
-    function renderTabelItem(columns: any[]) {
-      return columns.map((v: any) => {
-        const vSlots: any = v.slots || {}
-        if (v.children) {
-          const slotData = {
-            title: () => vSlots.title && slots[vSlots.title] && slots[vSlots.title]!(),
-            default: () => {renderTabelItem(v.children)}
-          }
-          if (!vSlots.title) {
-            delete slotData.title
-          }
-          return (
-            <Table.ColumnGroup
-              v-slots={{...slotData}}
-            >
-            </Table.ColumnGroup>
-          )
-        } else {
-          const slotData = {
-            title: () => vSlots.title && slots[vSlots.title] && slots[vSlots.title]!(),
-            default: ({ text, record, index, column }: any) => {
-              if (vSlots.customRender) {
-                return slots[vSlots.customRender] && slots[vSlots.customRender]!({ text, record, index, column })
-              } else {
-                return text
-              }
-            },
-            filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, column }: any) => vSlots.filterDropdown && slots[vSlots.filterDropdown] && slots[vSlots.filterDropdown]!({ setSelectedKeys, selectedKeys, confirm, clearFilters, column }),
-            filterIcon: (filtered: any) => vSlots.filterIcon && slots[vSlots.filterIcon] && slots[vSlots.filterIcon]!(filtered)
-            }
-          if (!vSlots.title) {
-            delete slotData.title
-          }
-          if (!vSlots.filterDropdown) {
-            delete slotData.filterDropdown
-          }
-          if (!vSlots.filterIcon) {
-            delete slotData.filterIcon
-          }
-          return (
-            <Table.Column
-              {...v}
-              v-slots={{...slotData}}
-            >
-            </Table.Column>
-          )
-        }
-      })
-    }
-    
-    return () => {
-      const tableSlot = {
-        title: (currentPageData: any) => slots.title && slots.title(currentPageData),
-        footer: (currentPageData: any) => slots.footer && slots.footer(currentPageData),
-        expandedRowRender: ({ record, index, indent, expanded }: any) => slots.expandedRowRender && slots.expandedRowRender({ record, index, indent, expanded }),
-      }
-      if (!slots.title) {
-        delete tableSlot.title
-      }
-      if (!slots.footer) {
-        delete tableSlot.footer
-      }
-      if (!slots.expandedRowRender) {
-        delete tableSlot.expandedRowRender
-      }
-      return (
-        <Table
-          {...(getBindValue as any)}
-          v-slots={tableSlot}
-        >
-          {renderTabelItem(props.columns)}
-        </Table>
-      )
-    }
-  }
-})

+ 0 - 53
src/components/Table/TableItem.vue

@@ -1,53 +0,0 @@
-<template>
-  <template v-if="item.children" />
-  <template v-else>
-    <a-table-column
-      v-bind="getItemBindValue(item)"
-    >
-      <!-- title slot -->
-      <template v-if="item.slots && item.slots.title" #title>
-        <slot :name="item.slots.title" />
-      </template>
-      <!-- default slot -->
-      <template v-if="item.slots && item.slots.customRender" #default="{ text, record, index, column }">
-        <slot :name="item.slots.customRender" :text="text" :record="record" :index="index" :column="column" />
-      </template>
-      <!-- filterDropdown slot -->
-      <template v-if="item.slots && item.slots.filterDropdown" #filterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
-        <slot :name="item.slots.filterDropdown" :setSelectedKeys="setSelectedKeys" :selectedKeys="selectedKeys" :confirm="confirm" :clearFilters="clearFilters" :column="column" />
-      </template>
-      <!-- filterIcon slot -->
-      <template v-if="item.slots && item.slots.filterIcon" #filterIcon="filtered">
-        <slot :name="item.slots.filterIcon" :filtered="filtered" />
-      </template>
-    </a-table-column>
-  </template>
-</template>
-
-<script lang="ts">
-import { defineComponent, PropType, computed } from 'vue'
-export default defineComponent({
-  name: 'TableItem',
-  functional: true,
-  props: {
-    item: {
-      type: Object as PropType<object>,
-      required: true
-    }
-  },
-  setup(props, { attrs }) {
-    alert(',,,,')
-    const getItemBindValue = computed(() => {
-      return function(item: any) {
-        return { ...item, ...attrs, ...props }
-      }
-    })
-    return {
-      getItemBindValue
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 35 - 0
src/components/Table/components/Slot.vue

@@ -0,0 +1,35 @@
+<script lang="ts">
+import { defineComponent, inject, h, PropType } from 'vue'
+export default defineComponent({
+  name: 'Slot',
+  props: {
+    row: {
+      type: Object as PropType<object>,
+      default: () => null
+    },
+    index: {
+      type: Number as PropType<number>,
+      default: null
+    },
+    column: {
+      type: Object as PropType<object>,
+      default: () => null
+    },
+    slotName: {
+      type: String as PropType<string>,
+      default: ''
+    }
+  },
+  render(props: any) {
+    const _this: any = inject('tableRoot')
+    return h('div', _this.slots[props.slotName]({
+      row: props.row,
+      column: props.column,
+      index: props.index
+    }))
+  }
+})
+</script>
+
+<style>
+</style>

+ 84 - 0
src/components/Table/components/TableColumn.vue

@@ -0,0 +1,84 @@
+<template>
+  <el-table-column v-bind="{...bindValue(child)}" :prop="child.key">
+    <template v-for="item in child.children">
+      <!-- 树型数据 -->
+      <template v-if="item.children && item.children.length">
+        <table-column
+          :key="item[item.key]"
+          :child="item"
+        />
+      </template>
+
+      <template v-else>
+        <el-table-column
+          :key="item[item.key]"
+          v-bind="{...bindValue(item)}"
+          :prop="item.key"
+        >
+          <!-- 表头插槽 -->
+          <template v-if="item.slots && item.slots.header" #header="scope">
+            <table-slot
+              v-if="item.slots && item.slots.header"
+              :slot-name="item.slots.header"
+              :row="scope.row"
+              :column="item"
+              :index="scope.$index"
+            />
+          </template>
+          <!-- 表格内容插槽自定义 -->
+          <template #default="scope">
+            <table-slot
+              v-if="item.slots && item.slots.default"
+              :slot-name="item.slots.default"
+              :row="scope.row"
+              :column="item"
+              :index="scope.$index"
+            />
+            <!-- 不需要插槽 -->
+            <div v-else style="display: inline-block;">
+              {{ scope.row[item.key] }}
+            </div>
+          </template>
+        </el-table-column>
+      </template>
+    </template>
+  </el-table-column>
+</template>
+
+<script lang="ts">
+import { defineComponent, PropType } from 'vue'
+import TableSlot from './Slot.vue'
+import { deepClone } from '@/utils'
+export default defineComponent({
+  name: 'TableColumn',
+  components: {
+    TableSlot
+  },
+  props: {
+    child: {
+      type: Object as PropType<object>,
+      default: () => null,
+      required: true
+    }
+  },
+  setup() {
+    function bindValue(item: any) {
+      const delArr: string[] = ['children']
+      const obj = deepClone(item)
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      return obj
+    }
+
+    return {
+      bindValue
+    }
+  }
+})
+</script>
+
+<style>
+</style>

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

@@ -1,3 +0,0 @@
-import Table from './Table'
-
-export default Table

+ 81 - 19
src/components/Table/index.vue

@@ -1,47 +1,109 @@
 <template>
-  <a-table v-bind="getBindValue">
-    <table-item
-      v-for="item in columns"
-      :key="item.key || item.dataIndex"
-      :item="item"
+  <el-table ref="elTable" v-bind="getBindValue">
+    <!-- 多选 -->
+    <el-table-column
+      v-if="selection"
+      type="selection"
+      width="55"
     />
-    <template v-if="slots.title" #title="currentPageData">
-      <slot name="title" :currentPageData="currentPageData" />
-    </template>
-    <!-- <template v-for="item in columns" :key="item.key || item.dataIndex"> -->
+    <template v-for="item in columns">
+      <!-- 树型数据 -->
+      <template v-if="item.children && item.children.length">
+        <table-column
+          :key="item[item.key]"
+          :child="item"
+        />
+      </template>
+
+      <template v-else>
+        <el-table-column
+          :key="item[item.key]"
+          v-bind="{...bindValue(item)}"
+          :prop="item.key"
+        >
+          <!-- 表头插槽 -->
+          <template v-if="item.slots && item.slots.header" #header="scope">
+            <table-slot
+              v-if="item.slots && item.slots.header"
+              :slot-name="item.slots.header"
+              :row="scope.row"
+              :column="item"
+              :index="scope.$index"
+            />
+          </template>
 
-    <!-- </template> -->
-    <template v-if="slots.footer" #footer="currentPageData">
-      <slot name="footer" :currentPageData="currentPageData" />
+          <!-- 表格内容插槽自定义 -->
+          <template #default="scope">
+            <table-slot
+              v-if="item.slots && item.slots.default"
+              :slot-name="item.slots.default"
+              :row="scope.row"
+              :column="item"
+              :index="scope.$index"
+            />
+            <!-- 不需要插槽 -->
+            <div v-else style="display: inline-block;">
+              {{ scope.row[item.key] }}
+            </div>
+          </template>
+        </el-table-column>
+      </template>
     </template>
-  </a-table>
+  </el-table>
 </template>
 
 <script lang="ts">
-import { defineComponent, PropType, computed } from 'vue'
-import TableItem from './TableItem.vue'
+import { defineComponent, PropType, computed, provide, getCurrentInstance, ref, unref } from 'vue'
+import { deepClone } from '@/utils'
+import TableColumn from './components/TableColumn.vue'
+import TableSlot from './components/Slot.vue'
 export default defineComponent({
   name: 'ComTable',
   components: {
-    TableItem
+    TableSlot,
+    TableColumn
   },
   props: {
     columns: {
       type: Array as PropType<any[]>,
       default: () => []
+    },
+    selection: {
+      type: Boolean as PropType<boolean>,
+      default: false
     }
   },
   setup(props, { attrs, slots }) {
-    console.log(TableItem)
+    const elTable = ref<HTMLElement | null>(null)
+    function getTableRef() {
+      return unref(elTable as any)
+    }
+
+    const _this = getCurrentInstance() as any
+    provide('tableRoot', _this)
+
     const getBindValue = computed((): any => {
       const bindValue = { ...attrs, ...props }
       delete bindValue.columns
       return bindValue
     })
 
+    function bindValue(item: any) {
+      const delArr: string[] = []
+      const obj = deepClone(item)
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      return obj
+    }
+
     return {
-      getBindValue,
-      slots
+      elTable,
+      getBindValue, bindValue,
+      slots,
+      getTableRef
     }
   }
 })

+ 3 - 3
src/directives/clipboard/index.ts

@@ -1,6 +1,6 @@
 import Clipboard from 'clipboard'
 import { Directive, DirectiveBinding } from 'vue'
-import { message } from 'ant-design-vue'
+import { ElMessage } from 'element-plus'
 
 if (!Clipboard) {
   throw new Error('you should npm install `clipboard` --save at first ')
@@ -47,7 +47,7 @@ function createdClipboard(el: HTMLElement | any, arg: string | undefined, value:
       if (callback) {
         callback(e)
       } else {
-        message.success('复制成功')
+        ElMessage.success('复制成功')
       }
     })
     clipboard.on('error', e => {
@@ -55,7 +55,7 @@ function createdClipboard(el: HTMLElement | any, arg: string | undefined, value:
       if (callback) {
         callback(e)
       } else {
-        message.success('复制失败')
+        ElMessage.success('复制失败')
       }
     })
     el._v_clipboard = clipboard

+ 6 - 0
src/libs/element.ts

@@ -92,6 +92,12 @@ import {
   ElNotification
 } from 'element-plus'
 
+import locale from 'element-plus/lib/locale'
+import lang from 'element-plus/lib/locale/lang/zh-cn'
+
+// 设置语言
+locale.use(lang)
+
 const components = [
   ElAlert,
   ElAside,

+ 1 - 1
src/pages/index/axios-config/axios.ts

@@ -1,6 +1,6 @@
 import request from './request'
 
-import config from '../config'
+import config from './config'
 
 import { AxiosPromise, ResponseType } from 'axios'
 

+ 2 - 37
src/pages/index/config/index.ts → src/pages/index/axios-config/config/index.ts

@@ -1,39 +1,9 @@
 /**
- * 全局配置
+ * request全局配置
  */
 import { ConfigOptions } from './types'
 
 const config: ConfigOptions = {
-  /**
-   * 配置显示在浏览器标签的title
-   */
-  title: 'vue-antdv-admin',
-
-  /**
-   * 是否显示标签页
-   */
-  has_tags: true,
-
-  /**
-   * 是否显示logo
-   */
-  show_logo: true,
-
-  /**
-   * logo标题
-   */
-  logo_title: 'vue-antdv-admin',
-
-  /**
-   * 横纵布局 Classic(经典) Top(头部) LeftTop(左侧顶部)
-   */
-  layout: 'Test',
-
-  /**
-   * 主题色 light(明亮) dark(暗黑)
-   */
-  theme: 'dark',
-
   /**
    * api请求基础路径
    */
@@ -61,12 +31,7 @@ const config: ConfigOptions = {
    * 默认接口请求类型
    * 可选值:application/x-www-form-urlencoded multipart/form-data
    */
-  default_headers: 'application/json',
-
-  /**
-   * 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
-   */
-  user_info: 'userInfo'
+  default_headers: 'application/json'
 }
 
 export default config

+ 9 - 0
src/pages/index/axios-config/config/types.d.ts

@@ -0,0 +1,9 @@
+/**
+ * request配置
+ */
+export interface ConfigOptions {
+  base_url: object
+  result_code: number | string
+  default_headers: string
+  request_timeout: number
+}

+ 4 - 4
src/pages/index/axios-config/request.ts

@@ -1,10 +1,10 @@
 import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
 
-import { message } from 'ant-design-vue'
+import { ElMessage } from 'element-plus'
 
 import qs from 'qs'
 
-import config from '../config'
+import config from './config'
 
 const { result_code, base_url } = config
 
@@ -37,12 +37,12 @@ service.interceptors.response.use(
     if (response.data.code === result_code) {
       return response.data
     } else {
-      message.error(response.data.message)
+      ElMessage.error(response.data.message)
     }
   },
   (error: AxiosError) => {
     console.log('err' + error) // for debug
-    message.error(error.message)
+    ElMessage.error(error.message)
     return Promise.reject(error)
   }
 )

+ 0 - 16
src/pages/index/config/types.d.ts

@@ -1,16 +0,0 @@
-/**
- * 全局配置
- */
-export interface ConfigOptions {
-  title?: string
-  has_tags: boolean
-  show_logo: boolean
-  logo_title: string
-  base_url: object
-  result_code: number | string
-  default_headers: string
-  request_timeout: number
-  user_info: string
-  layout: 'Classic' | 'Top' | 'LeftTop' | 'Test'
-  theme: 'light' | 'dark'
-}

+ 0 - 77
src/pages/index/layout/components/Logo.vue

@@ -1,77 +0,0 @@
-<template>
-  <router-link :class="['app-logo', 'app-logo-' + theme]" to="/">
-    <img :src="require('@/assets/img/logo.png')">
-    <div v-if="show" class="sidebar-title">{{ title }}</div>
-  </router-link>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref, watch, PropType } from 'vue'
-import config from '_p/index/config'
-
-export default defineComponent({
-  name: 'Logo',
-  props: {
-    collapsed: {
-      type: Boolean as PropType<boolean>,
-      required: true
-    },
-    theme: {
-      type: String as PropType<'light' | 'dark'>,
-      default: 'dark'
-    }
-  },
-  setup(props) {
-    const show = ref<boolean>(true)
-    watch(
-      () => props.collapsed,
-      (collapsed: boolean) => {
-        if (!collapsed) {
-          setTimeout(() => {
-            show.value = !collapsed
-          }, 400)
-        } else {
-          show.value = !collapsed
-        }
-      }
-    )
-    return {
-      show,
-      title: config.title
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.app-logo {
-  display: flex;
-  align-items: center;
-  padding-left: 18px;
-  cursor: pointer;
-  height: @topSilderHeight;
-  max-width: 200px;
-  img {
-    width: 37px;
-    height: 37px;
-  }
-  .sidebar-title {
-    font-size: 14px;
-    font-weight: 700;
-    transition: .5s;
-    margin-left: 12px;
-  }
-}
-.app-logo-dark {
-  background-color: @menuBg;
-  .sidebar-title {
-    color: #fff;
-  }
-}
-.app-logo-light {
-  background-color: #fff;
-  .sidebar-title {
-    color: #000;
-  }
-}
-</style>

+ 0 - 75
src/pages/index/layout/components/Navbar.vue

@@ -1,75 +0,0 @@
-<template>
-  <div class="navbar">
-    <hamburger :collapsed="collapsed" class="hamburger-container" @toggleClick="setCollapsed" />
-    <breadcrumb class="breadcrumb-container" />
-
-    <div class="right-menu">
-      <screenfull class="right-menu-item hover-effect" />
-
-      <user-info class="right-menu-item hover-effect" />
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, computed } from 'vue'
-import Hamburger from '_c/Hamburger/index.vue'
-import Breadcrumb from '_c/Breadcrumb/index.vue'
-import Screenfull from '_c/Screenfull/index.vue'
-import UserInfo from './UserInfo.vue'
-import { appStore } from '_p/index/store/modules/app'
-export default defineComponent({
-  name: 'Navbar',
-  components: {
-    Hamburger,
-    Breadcrumb,
-    Screenfull,
-    UserInfo
-  },
-  setup() {
-    const collapsed = computed(() => appStore.collapsed)
-
-    function setCollapsed(collapsed: boolean): void {
-      appStore.SetCollapsed(collapsed)
-    }
-
-    return {
-      collapsed,
-      setCollapsed
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.navbar {
-  .hamburger-container {
-    line-height: @navbarHeight;
-    float: left;
-    cursor: pointer;
-    margin-left: 15px;
-    &:hover {
-      background: rgba(0, 0, 0, .025);
-    }
-  }
-  .breadcrumb-container {
-    float: left;
-  }
-  .right-menu {
-    float: right;
-    height: 100%;
-    line-height: @navbarHeight;
-    &:focus {
-      outline: none;
-    }
-    .right-menu-item {
-      display: inline-block;
-      padding: 0 8px;
-      height: 100%;
-      font-size: 18px;
-      color: #5a5e66;
-      vertical-align: text-bottom;
-    }
-  }
-}
-</style>

+ 0 - 34
src/pages/index/layout/components/Silder/Item.vue

@@ -1,34 +0,0 @@
-<template>
-  <div>
-    <i v-if="icon.includes('el-icon')" :class="[icon, 'sub-el-icon', 'anticon']" />
-    <svg-icon v-else :icon-class="icon" class="anticon" />
-    <slot name="title">
-      <span class="anticon-item">{{ title }}</span>
-    </slot>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, PropType } from 'vue'
-
-export default defineComponent({
-  name: 'Item',
-  props: {
-    icon: {
-      type: String as PropType<string>,
-      default: ''
-    },
-    title: {
-      type: String as PropType<string>,
-      default: ''
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.anticon-item {
-  opacity: 1;
-  transition: opacity .3s cubic-bezier(.645,.045,.355,1),width .3s cubic-bezier(.645,.045,.355,1);
-}
-</style>

+ 0 - 92
src/pages/index/layout/components/Silder/hooks/setSidebarItem.ts

@@ -1,92 +0,0 @@
-import { ref } from 'vue'
-import type { RouteRecordRaw } from 'vue-router'
-import path from 'path'
-import { isExternal } from '@/utils/validate'
-// import { setSidebarItem } from './types'
-
-export function setSidebarItem() {
-  const onlyOneChild = ref<any>(null)
-
-  function hasOneShowingChild(children: RouteRecordRaw[] = [], parent: RouteRecordRaw): boolean {
-    const showingChildren: RouteRecordRaw[] = children.filter((item: RouteRecordRaw) => {
-      if (item.meta && item.meta.hidden) {
-        return false
-      } else {
-        // Temp set(will be used if only has one showing child)
-        onlyOneChild.value = item
-        return true
-      }
-    })
-
-    // When there is only one child router, the child router is displayed by default
-    if (showingChildren.length === 1) {
-      return true
-    }
-
-    // Show parent if there are no child router to display
-    if (showingChildren.length === 0) {
-      onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
-      return true
-    }
-    return false
-  }
-
-  function resolvePath(basePath: string, routePath: string): string {
-    if (isExternal(routePath)) {
-      return routePath
-    }
-    return path.resolve(basePath, routePath)
-  }
-
-  function treeFindRouter(tree: any[], func: Function, result: RouteRecordRaw[] = []): RouteRecordRaw[] {
-    if (!tree) return []
-    for (const data of tree) {
-      result.push(data)
-      if (func(data)) return result
-      if (data.children) {
-        const findChildren = treeFindRouter(data.children, func, result)
-        if (findChildren.length) return findChildren
-      }
-      result.pop()
-    }
-    return []
-  }
-
-  function getFullPath(arr: string[]): string[] {
-    const result: string[] = []
-    let basePath = '/'
-    for (let i = 0; i < arr.length; i++) {
-      if (i === arr.length) {
-        continue
-      }
-      result.push(resolvePath(basePath, arr[i]))
-      basePath = resolvePath(basePath, arr[i])
-    }
-    return result
-  }
-
-  function findCurrentRoute(routers: RouteRecordRaw[], path: string, basePath = '/', result: Array<any> = []): any {
-    for (const item of routers) {
-      if (!item.meta?.hidden) {
-        const _basePath = resolvePath(basePath, item.path)
-        if (_basePath === path && !item.children) {
-          result.push(item)
-        } else {
-          if (item.children) {
-            findCurrentRoute(item.children, path, _basePath, result)
-          }
-        }
-      }
-    }
-    return result ? result[0] : null
-  }
-
-  return {
-    onlyOneChild,
-    hasOneShowingChild,
-    resolvePath,
-    treeFindRouter,
-    getFullPath,
-    findCurrentRoute
-  }
-}

+ 0 - 10
src/pages/index/layout/components/Silder/hooks/types.d.ts

@@ -1,10 +0,0 @@
-import type { Ref } from 'vue'
-import ref from 'vue'
-
-export interface setSidebarItem = {
-  onlyOneChild: Ref<any | null>
-  hasOneShowingChild: Function<boolean>
-  resolvePath: Function<string>
-  treeFindPath: Function<string[]>
-  getFullPath: Function<string[]>
-}

+ 0 - 10
src/pages/index/layout/components/Silder/index.less

@@ -1,10 +0,0 @@
-.sidebar-container {
-  height: 100%;
-}
-.has-logo {
-  height: calc(~"100% - @{topSilderHeight}");
-}
-.menu-wrap {
-  height: 100%;
-  overflow: hidden;
-}

+ 0 - 3
src/pages/index/layout/components/Silder/index.ts

@@ -1,3 +0,0 @@
-import Silder from './index'
-
-export default Silder

+ 0 - 176
src/pages/index/layout/components/Silder/index.tsx

@@ -1,176 +0,0 @@
-import { ref, defineComponent, PropType, computed, watch } from 'vue'
-// import { Menu } from 'element-plus'
-import { useRouter } from 'vue-router'
-import type { RouteRecordRaw, RouteLocationNormalizedLoaded } from 'vue-router'
-import Scrollbar from '_c/Scrollbar/index.vue'
-import Item from './Item.vue'
-import { permissionStore } from '_p/index/store/modules/permission'
-import { setSidebarItem } from './hooks/setSidebarItem'
-import { isExternal } from '@/utils/validate'
-import { findIndex } from '@/utils'
-import config from '_p/index/config'
-const { show_logo } = config
-
-import './index.less'
-
-export default defineComponent({
-  name: 'Silder',
-  components: {
-    Scrollbar,
-    Item
-  },
-  props: {
-    collapsed: {
-      type: Boolean as PropType<boolean>,
-      default: true
-    },
-    inlineIndent: {
-      type: Number as PropType<number>,
-      default: 24
-    },
-    forceSubMenuRender: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    mode: {
-      type: String as PropType<'vertical' | 'horizontal' | 'vertical-right' | 'inline'>,
-      default: 'inline'
-    },
-    theme: {
-      type: String as PropType<'light' | 'dark'>,
-      default: 'dark'
-    }
-  },
-  setup(props) {
-    const { currentRoute, push } = useRouter()
-    const { resolvePath, treeFindRouter, getFullPath, findCurrentRoute } = setSidebarItem()
-    const routers = computed((): RouteRecordRaw[] => {
-      return permissionStore.routers
-    })
-    const selectedKeys = ref<string[]>([])
-    const openKeys = ref<string[]>([])
-    const activeMenuName = ref<string>('')
-
-    watch(
-      () => currentRoute.value,
-      (route: RouteLocationNormalizedLoaded) => {
-        setSelectedKeys(route)
-      },
-      {
-        immediate: true
-      }
-    )
-
-    watch(
-      () => props.collapsed,
-      (collapsed: boolean) => {
-        setOpenKeys(currentRoute.value, collapsed)
-      },
-      {
-        immediate: true
-      }
-    )
-
-    function handleOpenChange(keyArr: string[]) {
-      // 需要自己管理openKeys
-      openKeys.value = keyArr
-    }
-
-    function setOpenKeys(route: RouteLocationNormalizedLoaded, collapsed: boolean) {
-      let currentRoute: any = null
-      if (route.meta.activeMenu) {
-        currentRoute = findCurrentRoute(routers.value, route.meta.activeMenu)
-      } else {
-        currentRoute = route
-      }
-      const parentRoute: RouteRecordRaw[] = treeFindRouter(permissionStore.routers, (data: any) => data.name === currentRoute.name)
-      openKeys.value = collapsed ? [] : getFullPath(parentRoute.map((v: RouteRecordRaw) => v.path))
-    }
-
-    function setSelectedKeys(route: RouteLocationNormalizedLoaded) {
-      const { meta, path, name } = route
-      activeMenuName.value = name as string
-      if (meta.activeMenu) {
-        selectedKeys.value = [meta.activeMenu]
-        return
-      }
-      selectedKeys.value = [path]
-    }
-
-    function highlightMenu(className: string, basePath: string) {
-      const parentRoute: RouteRecordRaw[] = treeFindRouter(permissionStore.routers, (data: any) => data.name === currentRoute.value.name)
-      const parentFullPath: string[] = getFullPath(parentRoute.map((v: RouteRecordRaw) => v.path))
-      return findIndex(parentFullPath, (item: string) => item === basePath) !== -1 ? className : ''
-    }
-
-    function handleMenuClick({ key }: any) {
-      console.log(key)
-      if (isExternal(key)) {
-        window.open(key)
-      } else {
-        push({ path: key })
-      }
-    }
-
-    // function renderMenu(routers: RouteRecordRaw[], basePath = '/') {
-    //   if (routers && routers.length) {
-    //     return routers.map((item: RouteRecordRaw) => {
-    //       if (!item.meta?.hidden) {
-    //         const _basePath = resolvePath(basePath, item.path)
-    //         const { onlyOneChild, hasOneShowingChild } = setSidebarItem()
-    //         if (hasOneShowingChild(item.children, item) && (!onlyOneChild.value.children || onlyOneChild.value.noShowingChildren) && !item.meta?.alwaysShow) {
-    //           return (
-    //             <Menu.Item key={resolvePath(_basePath, onlyOneChild.value.path)} v-slots={{
-    //               default: () => [
-    //                 <Item
-    //                   icon={onlyOneChild.value.meta && onlyOneChild.value.meta.icon}
-    //                   title={onlyOneChild.value.meta?.title}
-    //                 />
-    //               ]
-    //             }}>
-    //             </Menu.Item>
-    //           )
-    //         } else {
-    //           return (
-    //             <Menu.SubMenu
-    //               key={_basePath}
-    //               class={highlightMenu(props.theme + '-active-item', _basePath)}
-    //               popupClassName={highlightMenu(props.theme + '-popup-active-item', _basePath)}
-    //               v-slots={{
-    //                 title: () => [
-    //                   <Item
-    //                     icon={item.meta && item.meta.icon}
-    //                     title={item.meta?.title}
-    //                   />
-    //                 ]
-    //               }}
-    //             >
-    //               {renderMenu(item.children as any, _basePath)}
-    //             </Menu.SubMenu>
-    //           )
-    //         }
-    //       }
-    //     })
-    //   }
-    // }
-
-    // return () => {
-    //   return (
-    //     // <div class={{ 'has-logo': show_logo, 'sidebar-container': true }}>
-    //     //   <scrollbar class='menu-wrap'>
-    //     //     <Menu
-    //     //       selectedKeys={selectedKeys.value}
-    //     //       openKeys={openKeys.value}
-    //     //       theme={props.theme}
-    //     //       mode={props.mode}
-    //     //       onClick={handleMenuClick}
-    //     //       onOpenChange={handleOpenChange}
-    //     //     >
-    //     //       {renderMenu(routers.value)}
-    //     //     </Menu>
-    //     //   </scrollbar>
-    //     // </div>
-    //   )
-    // }
-  }
-})

+ 0 - 377
src/pages/index/layout/components/TagsView.vue

@@ -1,377 +0,0 @@
-<template>
-  <div ref="wrapper" class="tags-view-container">
-    <span class="move-btn prev-btn">
-      <a-button @click="move(-200)">
-        <template #icon><LeftOutlined /></template>
-      </a-button>
-    </span>
-    <scroll-pane ref="scrollPane" class="tags-view-wrapper">
-      <div>
-        <router-link
-          v-for="tag in visitedViews"
-          :ref="setTagRef"
-          :key="tag.path"
-          :class="isActive(tag) ? 'active' : ''"
-          :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
-          tag="span"
-          class="tags-view-item"
-          @click.middle="closeSelectedTag(tag)"
-          @contextmenu.prevent="openMenu(tag, $event)"
-        >
-          {{ tag.title }}
-          <CloseOutlined v-if="!tag.meta.affix" class="icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
-        </router-link>
-      </div>
-    </scroll-pane>
-    <span class="move-btn next-btn">
-      <a-button @click="move(200)">
-        <template #icon><RightOutlined /></template>
-      </a-button>
-    </span>
-    <ul v-show="visible" :style="{left: left + 'px', top: top + 'px'}" class="contextmenu">
-      <li @click="refreshSelectedTag(selectedTag)">
-        刷新
-      </li>
-      <li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">
-        关闭
-      </li>
-      <li @click="closeOthersTags">
-        关闭其他
-      </li>
-      <li @click="closeAllTags(selectedTag)">
-        关闭全部
-      </li>
-    </ul>
-  </div>
-</template>
-
-<script lang="ts">
-import ScrollPane from '_c/ScrollPane/index.vue'
-import path from 'path'
-import { defineComponent, ref, unref, computed, watch, onMounted, nextTick } from 'vue'
-import { tagsViewStore } from '_p/index/store/modules/tagsView'
-import { permissionStore } from '_p/index/store/modules/permission'
-import { useRouter } from 'vue-router'
-import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
-// import { LeftOutlined, RightOutlined, CloseOutlined } from '@ant-design/icons-vue'
-
-export default defineComponent({
-  name: 'TagsView',
-  components: {
-    ScrollPane,
-    // CloseOutlined,
-    // LeftOutlined,
-    // RightOutlined
-  },
-  setup() {
-    const { currentRoute, push, replace } = useRouter()
-    const wrapper = ref<HTMLElement | null>(null)
-    const scrollPane = ref<HTMLElement | null>(null)
-    const visible = ref<boolean>(false)
-    const top = ref<number>(0)
-    const left = ref<number>(0)
-    const selectedTag = ref<any>({})
-    const affixTags = ref<any[]>([])
-    const visitedViews = computed(() => tagsViewStore.visitedViews)
-    const routers = computed(() => permissionStore.routers)
-
-    const tagRefs = ref<any[]>([])
-
-    function setTagRef(el: any): void {
-      tagRefs.value.push(el)
-    }
-
-    function isActive(route: RouteLocationNormalizedLoaded): boolean {
-      return route.path === currentRoute.value.path
-    }
-
-    function filterAffixTags(routes: RouteRecordRaw[], basePath = '/'): any[] {
-      let tags: any[] = []
-      routes.forEach((route: RouteRecordRaw) => {
-        if (route.meta && route.meta.affix) {
-          const tagPath = path.resolve(basePath, route.path)
-          tags.push({
-            fullPath: tagPath,
-            path: tagPath,
-            name: route.name,
-            meta: { ...route.meta }
-          })
-        }
-        if (route.children) {
-          const tempTags: any[] = filterAffixTags(route.children, route.path)
-          if (tempTags.length >= 1) {
-            tags = [...tags, ...tempTags]
-          }
-        }
-      })
-
-      return tags
-    }
-
-    function initTags(): void {
-      affixTags.value = filterAffixTags(routers.value)
-      const affixTagArr: any[] = affixTags.value
-      for (const tag of affixTagArr) {
-        // Must have tag name
-        if (tag.name) {
-          tagsViewStore.addVisitedView(tag)
-        }
-      }
-    }
-
-    function addTags(): void | boolean {
-      const { name } = currentRoute.value
-      if (name) {
-        tagsViewStore.addView(currentRoute.value)
-      }
-      return false
-    }
-
-    function moveToCurrentTag() {
-      // TODO 要手动清除tagRefs,不然会一直重复,后续看看有没有什么解决办法
-      tagRefs.value = []
-      const tags = unref(tagRefs)
-      nextTick(() => {
-        for (const tag of tags) {
-          if (tag && tag.to.path === currentRoute.value.path) {
-            (unref(scrollPane) as any).moveToTarget(tag)
-            // when query is different then update
-            if (tag.to.fullPath !== currentRoute.value.fullPath) {
-              tagsViewStore.updateVisitedView(currentRoute.value)
-            }
-
-            break
-          }
-        }
-      })
-    }
-
-    async function refreshSelectedTag(view: RouteLocationNormalizedLoaded) {
-      await tagsViewStore.delCachedView()
-      const { fullPath } = view
-      nextTick(() => {
-        replace({
-          path: '/redirect' + fullPath
-        })
-      })
-    }
-
-    async function closeSelectedTag(view: RouteLocationNormalizedLoaded) {
-      const views: any = await tagsViewStore.delView(view)
-      if (isActive(view)) {
-        toLastView(views.visitedViews)
-      }
-    }
-
-    function closeOthersTags() {
-      push(selectedTag.value)
-      tagsViewStore.delOthersViews(selectedTag.value).then(() => {
-        moveToCurrentTag()
-      })
-    }
-
-    async function closeAllTags(view: RouteLocationNormalizedLoaded) {
-      const views: any = await tagsViewStore.delAllViews()
-      if (affixTags.value.some(tag => tag.path === view.path)) {
-        return
-      }
-      toLastView(views.visitedViews)
-    }
-
-    function toLastView(visitedViews: RouteLocationNormalizedLoaded[]) {
-      const latestView = visitedViews.slice(-1)[0]
-      setTimeout(() => {
-        if (latestView) {
-          push(latestView)
-        } else {
-          // You can set another route
-          push('/')
-        }
-      }, 100)
-    }
-
-    function openMenu(tag: RouteLocationNormalizedLoaded, e: any) {
-      const menuMinWidth = 105
-      const offsetLeft: number = (unref(wrapper) as any).getBoundingClientRect().left // container margin left
-      const offsetWidth: number = (unref(wrapper) as any).offsetWidth // container width
-      const maxLeft: number = offsetWidth - menuMinWidth// left boundary
-      const itemLeft: number = e.clientX - offsetLeft + 4
-
-      if (itemLeft > maxLeft) {
-        left.value = maxLeft
-      } else {
-        left.value = itemLeft
-      }
-      top.value = e.offsetY
-
-      visible.value = true
-      selectedTag.value = tag
-    }
-
-    function closeMenu() {
-      visible.value = false
-    }
-
-    function move(to: number) {
-      (unref(scrollPane) as any).moveTo(to)
-    }
-
-    onMounted(() => {
-      initTags()
-      addTags()
-    })
-
-    watch(
-      () => currentRoute.value,
-      () => {
-        addTags()
-        moveToCurrentTag()
-      }
-    )
-
-    watch(
-      () => visible.value,
-      (visible: boolean) => {
-        if (visible) {
-          document.body.addEventListener('click', closeMenu)
-        } else {
-          document.body.removeEventListener('click', closeMenu)
-        }
-      }
-    )
-
-    return {
-      wrapper, scrollPane,
-      visible, top, left,
-      selectedTag, affixTags,
-      visitedViews, routers,
-      tagRefs, setTagRef,
-      isActive,
-      filterAffixTags,
-      initTags,
-      addTags,
-      moveToCurrentTag,
-      refreshSelectedTag,
-      closeSelectedTag,
-      closeOthersTags,
-      closeAllTags,
-      toLastView,
-      openMenu,
-      closeMenu,
-      move
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.tags-view-container {
-  height: @tagsViewHeight;
-  width: 100%;
-  background: #fff;
-  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
-  position: relative;
-  display: flex;
-  z-index: 100;
-  &::after {
-    content: "";
-    width: 100%;
-    height: 1px;
-    border-top: #d8dce5;
-    position: absolute;
-    left: 0;
-    bottom: 0;
-  }
-  .move-btn {
-    display: inline-block;
-    width: @tagsViewHeight;
-    height: @tagsViewHeight;
-    line-height: @tagsViewHeight;
-    text-align: center;
-    .ant-btn {
-      width: @tagsViewHeight;
-      height: @tagsViewHeight;
-      line-height: @tagsViewHeight;
-    }
-  }
-  .tags-view-wrapper {
-    width: calc(~"100% - 78px");
-    .tags-view-item {
-      display: inline-block;
-      position: relative;
-      cursor: pointer;
-      height: 30px;
-      line-height: 30px;
-      border: 1px solid #d8dce5;
-      color: #495060;
-      background: #fff;
-      padding: 0 8px;
-      font-size: 12px;
-      margin-left: 5px;
-      &:last-of-type {
-        margin-right: 4px;
-      }
-      &.active {
-        background-color: #304156;
-        color: #fff;
-        border-color: #304156;
-        &::before {
-          content: '';
-          background: #fff;
-          display: inline-block;
-          width: 8px;
-          height: 8px;
-          border-radius: 50%;
-          position: relative;
-          margin-right: 5px;
-        }
-      }
-      .icon-close {
-        width: 16px;
-        height: 16px;
-        border-radius: 50%;
-        text-align: center;
-        line-height: 16px;
-        transition: all .3s cubic-bezier(.645, .045, .355, 1);
-        transform-origin: 100% 50%;
-        margin-left: 5px;
-        position: relative;
-        top: -1px;
-        &:before {
-          transform: scale(.6);
-          display: inline-block;
-        }
-        &:hover {
-          background-color: #b4bccc;
-          color: #fff;
-        }
-      }
-    }
-  }
-  .contextmenu {
-    margin: 0;
-    background: #fff;
-    z-index: 200;
-    position: absolute;
-    list-style-type: none;
-    padding: 5px 0;
-    border-radius: 4px;
-    font-size: 12px;
-    font-weight: 400;
-    color: #333;
-    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
-    li {
-      margin: 0;
-      padding: 7px 16px;
-      cursor: pointer;
-      &:hover {
-        background: #eee;
-      }
-    }
-  }
-}
-@{deep}(.scrollbar__view) {
-  height: @tagsViewHeight;
-  line-height: @tagsViewHeight;
-}
-</style>

+ 0 - 68
src/pages/index/layout/components/UserInfo.vue

@@ -1,68 +0,0 @@
-<template>
-  <el-dropdown class="avatar-container" :trigger="['hover']">
-    <div>
-      <div class="avatar-wrapper">
-        <img :src="require('@/assets/img/avatar.gif')" class="user-avatar">
-        <span class="name-item">管理员</span>
-      </div>
-    </div>
-    <template #dropdown>
-      <el-dropdown-menu>
-        <el-dropdown-item key="1">
-          <router-link to="/">
-            首页
-          </router-link>
-        </el-dropdown-item>
-        <el-dropdown-item key="2">
-          <span style="display: block;" @click="loginOut">退出登录</span>
-        </el-dropdown-item>
-      </el-dropdown-menu>
-    </template>
-  </el-dropdown>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue'
-import { resetRouter } from '_p/index/router'
-import wsCache from '@/cache'
-import { useRouter } from 'vue-router'
-export default defineComponent({
-  name: 'UserInfo',
-  setup() {
-    const { replace } = useRouter()
-    async function loginOut(): Promise<void> {
-      wsCache.clear()
-      await resetRouter() // 重置静态路由表
-      // this.$store.dispatch('delAllViews') // 删除所有的tags标签页
-      replace('/login')
-    }
-    return {
-      loginOut
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.avatar-container {
-  margin-right: 30px;
-  padding: 0 10px;
-  .avatar-wrapper {
-    display: flex;
-    align-items: center;
-    height: 100%;
-    cursor: pointer;
-    .user-avatar {
-      width: 30px;
-      height: 30px;
-      border-radius: 10px;
-    }
-    .name-item {
-      font-size: 14px;
-      font-weight: 600;
-      display: inline-block;
-      margin-left: 5px;
-    }
-  }
-}
-</style>

+ 11 - 14
src/pages/index/layout/index.vue

@@ -1,29 +1,26 @@
 <template>
   <div class="app-wrapper">
-    <component :is="component" />
+    <component :is="layout" />
   </div>
 </template>
 
 <script lang="ts">
-// import Classic from './modules/Classic.vue'
-// import Top from './modules/Top.vue'
-// import LeftTop from './modules/LeftTop.vue'
-import Test from './modules/Test.vue'
-import { defineComponent, ref } from 'vue'
-import config from '_p/index/config'
+import { defineComponent, computed } from 'vue'
+import Classic from './modules/Classic.vue'
+import Top from './modules/Top.vue'
+import LeftTop from './modules/LeftTop.vue'
+import { appStore } from '_p/index/store/modules/app'
 export default defineComponent({
   name: 'Layout',
   components: {
-    // Classic,
-    // Top,
-    // LeftTop,
-    Test
+    Classic,
+    Top,
+    LeftTop
   },
   setup() {
-    const { layout } = config
-    const component = ref<string>(layout)
+    const layout = computed(() => appStore.layout)
     return {
-      component
+      layout
     }
   }
 })

+ 219 - 80
src/pages/index/layout/modules/Classic.vue

@@ -1,112 +1,251 @@
 <template>
-  <a-layout class="app-wrapper">
-    <a-layout-sider
-      v-model:collapsed="collapsed"
-      :trigger="null"
-      collapsible
-      :class="'ant-layout-sider--' + theme"
-      class="sidebar-container-wrap"
+  <div :class="classObj" class="app__wrap">
+    <!-- Classic -->
+    <div
+      class="sidebar__wrap"
+      :class="{'sidebar__wrap--collapsed': collapsed}"
     >
       <logo
-        v-if="show_logo"
+        v-if="showLogo && layout === 'Classic'"
         :collapsed="collapsed"
-        :theme="theme"
       />
-      <silder
-        :collapsed="collapsed"
-        :theme="theme"
-      />
-    </a-layout-sider>
-    <a-layout>
-      <a-layout-header :class="{'ant-layout-header-collapsed': collapsed}">
-        <navbar />
-      </a-layout-header>
-      <a-layout-content :class="{'layout-content-has-tags':has_tags}">
-        <scrollbar class="main-wrap">
-          <tags-view :class="{'has-tags':has_tags, 'has-tags-collapsed': collapsed && has_tags}" />
-          <app-main class="classic-module--wrap" />
-        </scrollbar>
-      </a-layout-content>
-    </a-layout>
-  </a-layout>
+      <sider :layout="layout" mode="vertical" />
+    </div>
+
+    <div
+      class="main__wrap"
+      :class="{
+        'main__wrap--collapsed': collapsed
+      }"
+    >
+      <el-scrollbar
+        class="main__wrap--content"
+        :class="{
+          'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
+          'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
+          'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
+        }"
+      >
+        <div
+          class="header__wrap"
+          :class="{
+            'header__wrap--fixed': fixedHeader,
+            'header__wrap--collapsed': fixedHeader && collapsed
+          }"
+        >
+          <div
+            v-if="showNavbar"
+            class="navbar__wrap"
+          >
+            <hamburger
+              v-if="showHamburger"
+              :collapsed="collapsed"
+              class="hover-container"
+              @toggleClick="setCollapsed"
+            />
+            <breadcrumb v-if="showBreadcrumb" />
+            <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
+              <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
+              <user-info v-if="showUserInfo" class="hover-container user-container" />
+            </div>
+          </div>
+          <div
+            v-if="showTags"
+            class="tags__wrap"
+          >
+            <tags-view />
+          </div>
+        </div>
+        <app-main />
+      </el-scrollbar>
+    </div>
+
+    <!-- setting -->
+    <setting />
+    <!-- setting -->
+  </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, computed, PropType } from 'vue'
+import { defineComponent, computed } from 'vue'
 import { appStore } from '_p/index/store/modules/app'
-import Silder from '../components/Silder'
-import Navbar from '../components/Navbar.vue'
+
 import AppMain from '../components/AppMain.vue'
-import TagsView from '../components/TagsView.vue'
-import Logo from '../components/Logo.vue'
-import Scrollbar from '_c/Scrollbar/index.vue'
-import config from '_p/index/config'
-const { show_logo, has_tags, theme } = config
+import TagsView from '_c/TagsView/index.vue'
+import Logo from '_c/Logo/index.vue'
+import Sider from '_c/Sider/index.vue'
+import Hamburger from '_c/Hamburger/index.vue'
+import Breadcrumb from '_c/Breadcrumb/index.vue'
+import Screenfull from '_c/Screenfull/index.vue'
+import UserInfo from '_c/UserInfo/index.vue'
+
+import Setting from '_c/Setting/index.vue'
 export default defineComponent({
   name: 'Classic',
   components: {
-    Silder,
-    Navbar,
+    Sider,
+    Hamburger,
+    Breadcrumb,
+    Screenfull,
+    UserInfo,
     AppMain,
     TagsView,
     Logo,
-    Scrollbar
-  },
-  props: {
-    theme: {
-      type: String as PropType<'light' | 'dark'>,
-      default: theme
-    }
+    Setting
   },
   setup() {
+    const layout = computed(() => appStore.layout)
     const collapsed = computed(() => appStore.collapsed)
+    const showLogo = computed(() => appStore.showLogo)
+    const showTags = computed(() => appStore.showTags)
+    const showBreadcrumb = computed(() => appStore.showBreadcrumb)
+    const showHamburger = computed(() => appStore.showHamburger)
+    const showScreenfull = computed(() => appStore.showScreenfull)
+    const showUserInfo = computed(() => appStore.showUserInfo)
+    const showNavbar = computed(() => appStore.showNavbar)
+    // const fixedNavbar = computed(() => appStore.fixedNavbar)
+    // const fixedTags = computed(() => appStore.fixedTags)
+    const fixedHeader = computed(() => appStore.fixedHeader)
+
+    const classObj = computed(() => {
+      const obj = {}
+      obj[`app__wrap--${layout.value}`] = true
+      return obj
+    })
+
+    function setCollapsed(collapsed: boolean): void {
+      appStore.SetCollapsed(collapsed)
+    }
 
     return {
+      classObj,
+      layout,
       collapsed,
-      show_logo,
-      has_tags
+      showLogo,
+      showTags,
+      showBreadcrumb,
+      showHamburger,
+      showScreenfull,
+      showUserInfo,
+      showNavbar,
+      fixedHeader,
+      // fixedNavbar,
+      // fixedTags,
+      setCollapsed
     }
   }
 })
 </script>
 
 <style lang="less" scoped>
-@{deep}(.ant-layout-header) {
-  line-height: @navbarHeight;
-  height: @navbarHeight;
-  position: fixed;
-  top: 0;
-  left: @menuWidth;
-  width: calc(~"100% - @{menuWidth}");
-  padding: 0;
-  background: #fff;
-  transition: all 0.2s;
-}
-.ant-layout-sider--light {
-  background: @menuLightBg;
-}
-.ant-layout-sider--dark {
-  background: @menuBg;
-}
-.ant-layout-content {
-  margin-top: @navbarHeight;
-  .mian-wrap {
-    background-color: @contentBg;
+.app__wrap {
+  position: relative;
+  height: 100%;
+  width: 100%;
+  .sidebar__wrap {
+    position: fixed;
+    width: @menuWidth;
+    top: 0;
+    left: 0;
+    height: 100%;
+    transition: width 0.2s;
+  }
+  .sidebar__wrap--collapsed {
+    width: @menuMinWidth;
+    @{deep}(.anticon-item) {
+      display: none;
+    }
+  }
+  .main__wrap {
+    position: absolute;
+    width: calc(~"100% - @{menuWidth}");
+    height: 100%;
+    top: 0;
+    left: @menuWidth;
+    transition: all 0.2s;
+    z-index: 1;
+    .header__wrap {
+      transition: all 0.2s;
+      .navbar__wrap {
+        display: flex;
+        align-items: center;
+        height: @navbarHeight;
+        padding: 0 20px 0 15px;
+        position: relative;
+        background: @contentBg;
+        &:after {
+          content: "";
+          width: 100%;
+          height: 1px;
+          border-top: 1px solid #d8dce5;
+          position: absolute;
+          bottom: 0;
+          left: 0;
+        }
+        @{deep}(.hover-container) {
+          transition: background 0.2s;
+          height: 100%;
+          line-height: @navbarHeight + 5px;
+          padding: 0 5px;
+          text-align: center;
+          &:hover {
+            background: #f6f6f6;
+          }
+        }
+        .navbar__wrap--right {
+          display: flex;
+          align-items: center;
+          height: @navbarHeight;
+          position: absolute;
+          top: 0;
+          right: 20px;
+          @{deep}(.screenfull-container),
+          @{deep}(.user-container) {
+            line-height: @navbarHeight !important;
+          }
+        }
+      }
+    }
+
+    // content样式
+    .main__wrap--content {
+      height: 100%;
+      @{deep}(.el-scrollbar__wrap) {
+        overflow-x: hidden;
+      }
+    }
+    // content样式
+  }
+  .main__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}");
+    left: @menuMinWidth;
   }
 }
-.layout-content-has-tags {
-  margin-top: @navbarHeight + @tagsViewHeight;
-}
-.has-tags {
-  position: fixed;
-  top: @navbarHeight;
-  left: @menuWidth;
-  width: calc(~"100% - @{menuWidth}");
-  transition: all 0.2s;
-}
-.ant-layout-header-collapsed,
-.has-tags-collapsed {
-  left: 80px;
-  width: calc(~"100% - 80px");
+
+// 经典模式
+.app__wrap--Classic {
+  .main__wrap--fixed--all {
+    margin-top: @navbarHeight + @tagsViewHeight !important;
+    height: calc(~"100% - @{navbarHeight} - @{tagsViewHeight}") !important;
+  }
+  .main__wrap--fixed--nav {
+    margin-top: @navbarHeight !important;
+    height: calc(~"100% - @{navbarHeight}") !important;
+  }
+  .main__wrap--fixed--tags {
+    margin-top: @tagsViewHeight !important;
+    height: calc(~"100% - @{tagsViewHeight}") !important;
+  }
+  .header__wrap--fixed {
+    position: fixed !important;
+    width: calc(~"100% - @{menuWidth}") !important;
+    top: 0 !important;
+    left: @menuWidth !important;
+    z-index: 200;
+  }
+  .header__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}") !important;
+    left: @menuMinWidth !important;
+  }
 }
 </style>

+ 279 - 133
src/pages/index/layout/modules/LeftTop.vue

@@ -1,97 +1,157 @@
 <template>
-  <a-layout>
-    <a-layout-header :class="'ant-layout-header--' + silderTheme">
+  <div :class="classObj" class="app__wrap">
+    <!-- Classic -->
+    <div
+      class="sidebar__wrap"
+      :class="{'sidebar__wrap--collapsed': collapsed}"
+    >
       <logo
-        v-if="show_logo"
-        :theme="silderTheme"
+        v-if="showLogo && layout === 'Classic'"
+        :collapsed="collapsed"
       />
-      <silder
-        :theme="silderTheme"
-        mode="horizontal"
-        class="header-silder--wrap"
-      />
-      <div class="right-menu">
-        <screenfull class="right-menu-item hover-effect screenfull-item" />
+      <sider :layout="layout" mode="vertical" />
+    </div>
+    <!-- Classic -->
 
-        <user-info class="right-menu-item hover-effect" />
-      </div>
-    </a-layout-header>
-    <a-layout class="layout-content">
-      <a-layout-sider
-        v-model:collapsed="collapsed"
-        :trigger="null"
-        collapsible
-        :class="'ant-layout-sider--' + theme"
-        class="sidebar-container-wrap"
-      >
-        <silder
+    <!-- Top -->
+    <div v-if="layout !== 'Classic'" class="sidebar__wrap--Top">
+      <div>
+        <logo
+          v-if="showLogo"
           :collapsed="collapsed"
-          :theme="theme"
-          class="left-sider-wrap"
         />
-      </a-layout-sider>
-      <a-layout>
-        <div class="navbar-wrap">
-          <hamburger :collapsed="collapsed" class="hamburger-container" @toggleClick="setCollapsed" />
-          <breadcrumb class="breadcrumb-container" />
+      </div>
+      <div v-if="layout === 'Top'" class="sidebar__item--Top">
+        <sider :layout="layout" mode="horizontal" />
+      </div>
+      <div>
+        <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
+          <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
+          <user-info v-if="showUserInfo" class="hover-container user-container" />
         </div>
-        <a-layout-content :class="{'layout-content-has-tags':has_tags}">
-          <scrollbar class="main-wrap">
-            <tags-view :class="{'has-tags':has_tags, 'has-tags-collapsed': collapsed && has_tags}" />
-            <app-main class="classic-module--wrap" />
-          </scrollbar>
-        </a-layout-content>
-      </a-layout>
-    </a-layout>
-  </a-layout>
+      </div>
+    </div>
+    <!-- Top -->
+
+    <div
+      class="main__wrap"
+      :class="{
+        'main__wrap--collapsed': collapsed
+      }"
+    >
+      <el-scrollbar
+        class="main__wrap--content"
+        :class="{
+          'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
+          'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
+          'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
+        }"
+      >
+        <div
+          class="header__wrap"
+          :class="{
+            'header__wrap--fixed': fixedHeader,
+            'header__wrap--collapsed': fixedHeader && collapsed
+          }"
+        >
+          <div
+            v-if="showNavbar && layout !== 'Top'"
+            class="navbar__wrap"
+          >
+            <hamburger
+              v-if="showHamburger"
+              :collapsed="collapsed"
+              class="hover-container"
+              @toggleClick="setCollapsed"
+            />
+            <breadcrumb v-if="showBreadcrumb" />
+            <!-- <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
+              <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
+              <user-info v-if="showUserInfo" class="hover-container user-container" />
+            </div> -->
+          </div>
+          <div
+            v-if="showTags"
+            class="tags__wrap"
+          >
+            <tags-view />
+          </div>
+        </div>
+        <app-main />
+      </el-scrollbar>
+    </div>
+
+    <!-- setting -->
+    <setting />
+    <!-- setting -->
+  </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, PropType, computed } from 'vue'
-import Logo from '../components/Logo.vue'
-import Silder from '../components/Silder'
-import UserInfo from '../components/UserInfo.vue'
-import TagsView from '../components/TagsView.vue'
+import { defineComponent, computed } from 'vue'
+import { appStore } from '_p/index/store/modules/app'
+
 import AppMain from '../components/AppMain.vue'
-import Screenfull from '_c/Screenfull/index.vue'
-import Scrollbar from '_c/Scrollbar/index.vue'
+import TagsView from '_c/TagsView/index.vue'
+import Logo from '_c/Logo/index.vue'
+import Sider from '_c/Sider/index.vue'
 import Hamburger from '_c/Hamburger/index.vue'
 import Breadcrumb from '_c/Breadcrumb/index.vue'
-import { appStore } from '_p/index/store/modules/app'
-import config from '_p/index/config'
-const { show_logo, has_tags, theme } = config
+import Screenfull from '_c/Screenfull/index.vue'
+import UserInfo from '_c/UserInfo/index.vue'
+
+import Setting from '_c/Setting/index.vue'
 export default defineComponent({
   name: 'LeftTop',
   components: {
-    Logo,
-    Silder,
+    Sider,
+    Hamburger,
+    Breadcrumb,
+    Screenfull,
     UserInfo,
-    TagsView,
     AppMain,
-    Screenfull,
-    Scrollbar,
-    Hamburger,
-    Breadcrumb
-  },
-  props: {
-    theme: {
-      type: String as PropType<'light' | 'dark'>,
-      default: theme
-    },
-    silderTheme: {
-      type: String as PropType<'light' | 'dark'>,
-      default: 'light'
-    }
+    TagsView,
+    Logo,
+    Setting
   },
   setup() {
+    const layout = computed(() => appStore.layout)
     const collapsed = computed(() => appStore.collapsed)
+    const showLogo = computed(() => appStore.showLogo)
+    const showTags = computed(() => appStore.showTags)
+    const showBreadcrumb = computed(() => appStore.showBreadcrumb)
+    const showHamburger = computed(() => appStore.showHamburger)
+    const showScreenfull = computed(() => appStore.showScreenfull)
+    const showUserInfo = computed(() => appStore.showUserInfo)
+    const showNavbar = computed(() => appStore.showNavbar)
+    // const fixedNavbar = computed(() => appStore.fixedNavbar)
+    // const fixedTags = computed(() => appStore.fixedTags)
+    const fixedHeader = computed(() => appStore.fixedHeader)
+
+    const classObj = computed(() => {
+      const obj = {}
+      obj[`app__wrap--${layout.value}`] = true
+      return obj
+    })
+
     function setCollapsed(collapsed: boolean): void {
       appStore.SetCollapsed(collapsed)
     }
+
     return {
+      classObj,
+      layout,
       collapsed,
-      show_logo,
-      has_tags,
+      showLogo,
+      showTags,
+      showBreadcrumb,
+      showHamburger,
+      showScreenfull,
+      showUserInfo,
+      showNavbar,
+      fixedHeader,
+      // fixedNavbar,
+      // fixedTags,
       setCollapsed
     }
   }
@@ -99,87 +159,173 @@ export default defineComponent({
 </script>
 
 <style lang="less" scoped>
-@{deep}(.ant-layout-header) {
-  height: @topSilderHeight;
-  display: flex;
-  flex-direction: row;
-  justify-content: space-between;
-  position: fixed;
+.app__wrap {
+  position: relative;
+  height: 100%;
   width: 100%;
-  top: 0;
-  left: 0;
-  z-index: 20;
-  &--light {
-    background: @menuLightBg;
+  .sidebar__wrap {
+    position: fixed;
+    width: @menuWidth;
+    top: 0;
+    left: 0;
+    height: 100%;
+    transition: width 0.2s;
   }
-  &--dark {
-    background: @menuBg;
-    .screenfull-item,
-    .name-item {
-      color: #fff;
+  .sidebar__wrap--collapsed {
+    width: @menuMinWidth;
+    @{deep}(.anticon-item) {
+      display: none;
     }
   }
-  .header-silder--wrap {
-    flex: 1;
-    margin: 0 50px;
-    height: 100% !important;
-    .ant-menu-horizontal {
-      height: @topSilderHeight;
-      line-height: @topSilderHeight;
-      border-bottom: 0;
+  .main__wrap {
+    position: absolute;
+    width: calc(~"100% - @{menuWidth}");
+    height: 100%;
+    top: 0;
+    left: @menuWidth;
+    transition: all 0.2s;
+    z-index: 1;
+    .header__wrap {
+      transition: all 0.2s;
+      .navbar__wrap {
+        display: flex;
+        align-items: center;
+        height: @navbarHeight;
+        padding: 0 20px 0 15px;
+        position: relative;
+        background: @contentBg;
+        &:after {
+          content: "";
+          width: 100%;
+          height: 1px;
+          border-top: 1px solid #d8dce5;
+          position: absolute;
+          bottom: 0;
+          left: 0;
+        }
+        @{deep}(.hover-container) {
+          transition: background 0.2s;
+          height: 100%;
+          line-height: @navbarHeight + 5px;
+          padding: 0 5px;
+          text-align: center;
+          &:hover {
+            background: #f6f6f6;
+          }
+        }
+        .navbar__wrap--right {
+          display: flex;
+          align-items: center;
+          height: @navbarHeight;
+          position: absolute;
+          top: 0;
+          right: 20px;
+          @{deep}(.screenfull-container),
+          @{deep}(.user-container) {
+            line-height: @navbarHeight !important;
+          }
+        }
+      }
     }
-    .ant-menu-light {
-      height: calc(~"@{topSilderHeight} - 4px");
-      line-height: calc(~"@{topSilderHeight} - 2px");
+
+    // content样式
+    .main__wrap--content {
+      height: 100%;
+      @{deep}(.el-scrollbar__wrap) {
+        overflow-x: hidden;
+      }
     }
+    // content样式
   }
-  .right-menu {
-    display: flex;
-    .screenfull-item {
-      line-height: @topSilderHeight;
-    }
-    .avatar-container {
-      margin-right: 0;
-    }
+  .main__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}");
+    left: @menuMinWidth;
   }
 }
-.ant-layout-sider--light {
-  background: @menuLightBg;
-}
-.ant-layout-sider--dark {
-  background: @menuBg;
+
+// LeftTop模式
+.app__wrap--LeftTop {
+  .main__wrap--fixed--all {
+    margin-top: @navbarHeight + @tagsViewHeight !important;
+    height: calc(~"100% - @{navbarHeight} - @{tagsViewHeight}") !important;
+  }
+  .main__wrap--fixed--nav {
+    margin-top: @navbarHeight !important;
+    height: calc(~"100% - @{navbarHeight}") !important;
+  }
+  .main__wrap--fixed--tags {
+    margin-top: @tagsViewHeight !important;
+    height: calc(~"100% - @{tagsViewHeight}") !important;
+  }
+  .header__wrap--fixed {
+    position: fixed !important;
+    width: calc(~"100% - @{menuWidth}") !important;
+    top: @topSiderHeight !important;
+    left: @menuWidth !important;
+    z-index: 200;
+  }
+  .header__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}") !important;
+    left: @menuMinWidth !important;
+  }
 }
-.layout-content {
-  margin-top: @topSilderHeight;
-  height: calc(~"100vh - @{topSilderHeight}");
-  .navbar-wrap {
-    background: #fff;
-    padding: 0 20px;
-    border-top: 1px solid #f0f0f0;
-    height: @navbarHeight;
-    line-height: @navbarHeight;
+
+// 顶部模式
+.app__wrap--LeftTop {
+  .sidebar__wrap--Top {
+    height: @topSiderHeight;
     display: flex;
-  }
-  .layout-content-has-tags {
-    margin-top: @tagsViewHeight;
-    .mian-wrap {
-      background-color: @contentBg;
+    flex-direction: row;
+    justify-content: space-between;
+    padding: 0 20px;
+    background-color: @topMenuBg;
+    position: relative;
+    &:after {
+      content: "";
+      width: 100%;
+      height: 1px;
+      border-top: 1px solid #d8dce5;
+      position: absolute;
+      bottom: 0;
+      left: 0;
+    }
+    .sidebar__item--Top {
+      flex: 1;
+      margin: 0 50px;
+    }
+    .navbar__wrap--right {
+      display: flex;
+      align-items: center;
+      height: @topSiderHeight;
+      @{deep}(.hover-container) {
+        transition: background 0.2s;
+        height: 100%;
+        line-height: @topSiderHeight;
+        padding: 0 5px;
+        text-align: center;
+        &:hover {
+          background: #f6f6f6;
+        }
+      }
     }
   }
-  .left-sider-wrap {
-    height: 100%;
+}
+
+.app__wrap--LeftTop {
+  .sidebar__wrap {
+    top: @topSiderHeight;
+    left: 0;
+    height: calc(~"100% - @{topSiderHeight}");
   }
-  .has-tags {
-    position: fixed;
-    top: @topSilderHeight + @navbarHeight;
-    left: @menuWidth;
+  .main__wrap {
     width: calc(~"100% - @{menuWidth}");
-    z-index: 20;
-    transition: all 0.2s;
+    left: @menuWidth;
+    height: calc(~"100% - @{topSiderHeight}");
+    top: @topSiderHeight;
   }
-  .has-tags-collapsed {
-    left: 80px;
-    width: calc(~"100% - 80px");
+  .main__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}");
+    left: @menuMinWidth;
   }
 }
 </style>

+ 256 - 93
src/pages/index/layout/modules/Top.vue

@@ -1,128 +1,291 @@
 <template>
-  <a-layout>
-    <a-layout-header :class="'ant-layout-header--' + theme">
-      <logo
-        v-if="show_logo"
-        :theme="theme"
-      />
-      <silder
-        :theme="theme"
-        mode="horizontal"
-        class="header-silder--wrap"
-      />
-      <div class="right-menu">
-        <screenfull class="right-menu-item hover-effect screenfull-item" />
-
-        <user-info class="right-menu-item hover-effect" />
+  <div :class="classObj" class="app__wrap">
+    <!-- Top -->
+    <div class="sidebar__wrap--Top">
+      <div>
+        <logo
+          v-if="showLogo"
+          :collapsed="collapsed"
+        />
+      </div>
+      <div class="sidebar__item--Top">
+        <sider :layout="layout" mode="horizontal" />
       </div>
-    </a-layout-header>
-    <a-layout-content :class="{'layout-content-has-tags':has_tags}">
-      <scrollbar class="main-wrap">
-        <tags-view :class="{'has-tags':has_tags}" />
-        <app-main class="top-module--wrap" />
-      </scrollbar>
-    </a-layout-content>
-  </a-layout>
+      <div>
+        <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
+          <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
+          <user-info v-if="showUserInfo" class="hover-container user-container" />
+        </div>
+      </div>
+    </div>
+    <!-- Top -->
+
+    <div
+      class="main__wrap"
+      :class="{
+        'main__wrap--collapsed': collapsed
+      }"
+    >
+      <el-scrollbar
+        class="main__wrap--content"
+        :class="{
+          'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
+          'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
+          'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
+        }"
+      >
+        <div
+          class="header__wrap"
+          :class="{
+            'header__wrap--fixed': fixedHeader,
+            'header__wrap--collapsed': fixedHeader && collapsed
+          }"
+        >
+          <!-- <div
+            v-if="showNavbar && layout !== 'Top'"
+            class="navbar__wrap"
+          >
+            <hamburger
+              v-if="showHamburger"
+              :collapsed="collapsed"
+              class="hover-container"
+              @toggleClick="setCollapsed"
+            />
+            <breadcrumb v-if="showBreadcrumb" />
+            <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
+              <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
+              <user-info v-if="showUserInfo" class="hover-container user-container" />
+            </div>
+          </div> -->
+          <div
+            v-if="showTags"
+            class="tags__wrap"
+          >
+            <tags-view />
+          </div>
+        </div>
+        <app-main />
+      </el-scrollbar>
+    </div>
+
+    <!-- setting -->
+    <setting />
+    <!-- setting -->
+  </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, PropType } from 'vue'
-import Logo from '../components/Logo.vue'
-import Silder from '../components/Silder'
-import UserInfo from '../components/UserInfo.vue'
-import TagsView from '../components/TagsView.vue'
+import { defineComponent, computed } from 'vue'
+import { appStore } from '_p/index/store/modules/app'
+
 import AppMain from '../components/AppMain.vue'
+import TagsView from '_c/TagsView/index.vue'
+import Logo from '_c/Logo/index.vue'
+import Sider from '_c/Sider/index.vue'
+// import Hamburger from '_c/Hamburger/index.vue'
+// import Breadcrumb from '_c/Breadcrumb/index.vue'
 import Screenfull from '_c/Screenfull/index.vue'
-import Scrollbar from '_c/Scrollbar/index.vue'
-import config from '_p/index/config'
-const { show_logo, has_tags, theme } = config
+import UserInfo from '_c/UserInfo/index.vue'
+
+import Setting from '_c/Setting/index.vue'
 export default defineComponent({
   name: 'Top',
   components: {
-    Logo,
-    Silder,
+    Sider,
+    // Hamburger,
+    // Breadcrumb,
+    Screenfull,
     UserInfo,
-    TagsView,
     AppMain,
-    Screenfull,
-    Scrollbar
-  },
-  props: {
-    theme: {
-      type: String as PropType<'light' | 'dark'>,
-      default: theme
-    }
+    TagsView,
+    Logo,
+    Setting
   },
   setup() {
+    const layout = computed(() => appStore.layout)
+    const collapsed = computed(() => appStore.collapsed)
+    const showLogo = computed(() => appStore.showLogo)
+    const showTags = computed(() => appStore.showTags)
+    const showBreadcrumb = computed(() => appStore.showBreadcrumb)
+    const showHamburger = computed(() => appStore.showHamburger)
+    const showScreenfull = computed(() => appStore.showScreenfull)
+    const showUserInfo = computed(() => appStore.showUserInfo)
+    const showNavbar = computed(() => appStore.showNavbar)
+    // const fixedNavbar = computed(() => appStore.fixedNavbar)
+    // const fixedTags = computed(() => appStore.fixedTags)
+    const fixedHeader = computed(() => appStore.fixedHeader)
+
+    const classObj = computed(() => {
+      const obj = {}
+      obj[`app__wrap--${layout.value}`] = true
+      return obj
+    })
+
+    function setCollapsed(collapsed: boolean): void {
+      appStore.SetCollapsed(collapsed)
+    }
+
     return {
-      show_logo,
-      has_tags
+      classObj,
+      layout,
+      collapsed,
+      showLogo,
+      showTags,
+      showBreadcrumb,
+      showHamburger,
+      showScreenfull,
+      showUserInfo,
+      showNavbar,
+      fixedHeader,
+      // fixedNavbar,
+      // fixedTags,
+      setCollapsed
     }
   }
 })
 </script>
 
 <style lang="less" scoped>
-@{deep}(.ant-layout-header) {
-  height: @topSilderHeight;
-  display: flex;
-  flex-direction: row;
-  justify-content: space-between;
-  position: fixed;
+.app__wrap {
+  position: relative;
+  height: 100%;
   width: 100%;
-  top: 0;
-  left: 0;
-  z-index: 20;
-  &--light {
-    background: @menuLightBg;
+  .sidebar__wrap {
+    position: fixed;
+    width: @menuWidth;
+    top: 0;
+    left: 0;
+    height: 100%;
+    transition: width 0.2s;
   }
-  &--dark {
-    background: @menuBg;
-    .screenfull-item,
-    .name-item {
-      color: #fff;
+  .sidebar__wrap--collapsed {
+    width: @menuMinWidth;
+    @{deep}(.anticon-item) {
+      display: none;
     }
   }
-  .header-silder--wrap {
-    flex: 1;
-    margin: 0 50px;
-    height: 100% !important;
-    .ant-menu-horizontal {
-      height: @topSilderHeight;
-      line-height: @topSilderHeight;
-      border-bottom: 0;
+  .main__wrap {
+    position: absolute;
+    width: calc(~"100% - @{menuWidth}");
+    height: 100%;
+    top: 0;
+    left: @menuWidth;
+    transition: all 0.2s;
+    z-index: 1;
+    .header__wrap {
+      transition: all 0.2s;
+      .navbar__wrap {
+        display: flex;
+        align-items: center;
+        height: @navbarHeight;
+        padding: 0 20px 0 15px;
+        position: relative;
+        background: @contentBg;
+        &:after {
+          content: "";
+          width: 100%;
+          height: 1px;
+          border-top: 1px solid #d8dce5;
+          position: absolute;
+          bottom: 0;
+          left: 0;
+        }
+        @{deep}(.hover-container) {
+          transition: background 0.2s;
+          height: 100%;
+          line-height: @navbarHeight + 5px;
+          padding: 0 5px;
+          text-align: center;
+          &:hover {
+            background: #f6f6f6;
+          }
+        }
+        .navbar__wrap--right {
+          display: flex;
+          align-items: center;
+          height: @navbarHeight;
+          position: absolute;
+          top: 0;
+          right: 20px;
+          @{deep}(.screenfull-container),
+          @{deep}(.user-container) {
+            line-height: @navbarHeight !important;
+          }
+        }
+      }
     }
-    .ant-menu-light {
-      height: calc(~"@{topSilderHeight} - 4px");
-      line-height: calc(~"@{topSilderHeight} - 4px");
+
+    // content样式
+    .main__wrap--content {
+      height: 100%;
+      @{deep}(.el-scrollbar__wrap) {
+        overflow-x: hidden;
+      }
     }
+    // content样式
+  }
+  .main__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}");
+    left: @menuMinWidth;
   }
-  .right-menu {
+}
+
+// 顶部模式
+.app__wrap--Top {
+  .sidebar__wrap--Top {
+    height: @topSiderHeight;
     display: flex;
-    .screenfull-item {
-      line-height: @topSilderHeight;
+    flex-direction: row;
+    justify-content: space-between;
+    padding: 0 20px;
+    background-color: @topMenuBg;
+    position: relative;
+    &:after {
+      content: "";
+      width: 100%;
+      height: 1px;
+      border-top: 1px solid #d8dce5;
+      position: absolute;
+      bottom: 0;
+      left: 0;
     }
-    .avatar-container {
-      margin-right: 0;
+    .sidebar__item--Top {
+      flex: 1;
+      margin: 0 50px;
+    }
+    .navbar__wrap--right {
+      display: flex;
+      align-items: center;
+      height: @topSiderHeight;
+      @{deep}(.hover-container) {
+        transition: background 0.2s;
+        height: 100%;
+        line-height: @topSiderHeight;
+        padding: 0 5px;
+        text-align: center;
+        &:hover {
+          background: #f6f6f6;
+        }
+      }
     }
   }
-}
-.ant-layout-content {
-  margin-top: @topSilderHeight;
-  height: calc(~"100vh - @{topSilderHeight}");
-  .main-wrap {
-    background-color: @contentBg;
+  .header__wrap--fixed {
+    position: fixed !important;
+    width: 100% !important;
+    top: @topSiderHeight !important;
+    left: 0 !important;
+    z-index: 200;
+  }
+  .main__wrap {
+    width: 100%;
+    left: 0;
+    height: calc(~"100% - @{topSiderHeight}");
+    top: @topSiderHeight;
+  }
+  .main__wrap--fixed--all,
+  .main__wrap--fixed--tags {
+    margin-top: @navbarHeight !important;
+    height: calc(~"100% - @{navbarHeight}") !important;
   }
-}
-.layout-content-has-tags {
-  margin-top: @topSilderHeight + @tagsViewHeight;
-  height: calc(~"100vh - @{topSilderHeight} - @{tagsViewHeight}");
-}
-.has-tags {
-  position: fixed;
-  top: @topSilderHeight;
-  left: 0;
-  width: 100%;
-  z-index: 20;
 }
 </style>

+ 1 - 1
src/pages/index/main.ts

@@ -47,7 +47,7 @@ setupSvgIcon(app) // 全局注册svgIcon组件
 
 setupGlobCom(app) // 注册全局公用组件
 
-// setupDirectives(app) // 注册全局自定义指令
+setupDirectives(app) // 注册全局自定义指令
 
 // mockXHR() // mock注册
 

+ 3 - 5
src/pages/index/permission.ts

@@ -4,9 +4,7 @@ import NProgress from 'nprogress' // 引入进度条
 
 import 'nprogress/nprogress.css' // 进度条样式
 
-import config from './config'
-
-const { user_info, title } = config
+import { appStore } from '_p/index/store/modules/app'
 
 import wsCache from '@/cache'
 
@@ -20,7 +18,7 @@ import type { RouteRecordRaw } from 'vue-router'
 
 const whiteList: string[] = ['/login'] // 不重定向白名单
 router.beforeEach((to, from, next) => {
-  if (wsCache.get(user_info)) {
+  if (wsCache.get(appStore.userInfo)) {
     if (to.path === '/login') {
       next({ path: '/' })
     } else {
@@ -55,6 +53,6 @@ router.beforeEach((to, from, next) => {
 })
 
 router.afterEach((to) => {
-  document.title = getPageTitle(to.meta.title, title)
+  document.title = getPageTitle(to.meta.title, appStore.title)
   NProgress.done() // 结束进度条
 })

+ 298 - 275
src/pages/index/router/index.ts

@@ -6,8 +6,6 @@ import { getParentLayout } from './utils'
 
 /* Layout */
 const Layout = () => import('../layout/index.vue')
-/* ParentView */
-import ParentView from '_c/ParentView/index.vue'
 
 /**
 * redirect: noredirect        当设置 noredirect 的时候该路由在面包屑导航中不可被点击
@@ -50,7 +48,8 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
     name: 'NoFind',
     meta: {
       hidden: true,
-      title: '404'
+      title: '404',
+      noTagsView: true
     }
   },
   {
@@ -83,281 +82,305 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
       }
     ]
   },
-  // {
-  //   path: '/external-link',
-  //   component: Layout,
-  //   meta: {},
-  //   children: [
-  //     {
-  //       path: 'http://192.168.169.57/ue/2019/doc/vue-standard/dist/',
-  //       meta: { title: '文档', icon: 'documentation' }
-  //     }
-  //   ]
-  // }
+  {
+    path: '/external-link',
+    component: Layout,
+    meta: {},
+    children: [
+      {
+        path: 'http://192.168.169.57/ue/2019/doc/vue-standard/dist/',
+        meta: { title: '文档', icon: 'documentation' }
+      }
+    ]
+  }
 ]
 
 export const asyncRouterMap: AppRouteRecordRaw[] = [
-  // {
-  //   path: '/components-demo',
-  //   component: Layout,
-  //   redirect: '/components-demo/echarts',
-  //   name: 'ComponentsDemo',
-  //   meta: {
-  //     title: '功能组件',
-  //     icon: 'component',
-  //     alwaysShow: true
-  //   },
-  //   children: [
-  //     {
-  //       path: 'echarts',
-  //       component: () => import('_p/index/views/components-demo/echarts/index.vue'),
-  //       name: 'EchartsDemo',
-  //       meta: {
-  //         title: '图表'
-  //       }
-  //     },
-  //     {
-  //       path: 'image',
-  //       component: () => import('_p/index/views/components-demo/image/index.vue'),
-  //       name: 'ImageDemo',
-  //       meta: {
-  //         title: '图片'
-  //       }
-  //     },
-  //     {
-  //       path: 'preview',
-  //       component: () => import('_p/index/views/components-demo/preview/index.vue'),
-  //       name: 'PreviewDemo',
-  //       meta: {
-  //         title: '图片预览'
-  //       }
-  //     },
-  //     {
-  //       path: 'scroll',
-  //       component: () => import('_p/index/views/components-demo/scroll/index.vue'),
-  //       name: 'ScrollDemo',
-  //       meta: {
-  //         title: '滚动'
-  //       }
-  //     },
-  //     {
-  //       path: 'count-to',
-  //       component: () => import('_p/index/views/components-demo/count-to/index.vue'),
-  //       name: 'CountToDemo',
-  //       meta: {
-  //         title: '数字动画'
-  //       }
-  //     },
-  //     {
-  //       path: 'search',
-  //       component: () => import('_p/index/views/components-demo/search/index.vue'),
-  //       name: 'SearchDemo',
-  //       meta: {
-  //         title: '查询'
-  //       }
-  //     },
-  //     {
-  //       path: 'button',
-  //       component: () => import('_p/index/views/components-demo/button/index.vue'),
-  //       name: 'ButtonDemo',
-  //       meta: {
-  //         title: '按钮'
-  //       }
-  //     },
-  //     {
-  //       path: 'editor',
-  //       component: () => import('_p/index/views/components-demo/editor/index.vue'),
-  //       name: 'EditorDemo',
-  //       meta: {
-  //         title: '富文本编辑器'
-  //       }
-  //     },
-  //     {
-  //       path: 'markdown',
-  //       component: () => import('_p/index/views/components-demo/markdown/index.vue'),
-  //       name: 'MarkdownDemo',
-  //       meta: {
-  //         title: 'markdown编辑器'
-  //       }
-  //     }
-  //   ]
-  // },
-  // // {
-  // //   path: '/table-demo',
-  // //   component: Layout,
-  // //   redirect: '/table-demo/basic-usage',
-  // //   name: 'TableDemo',
-  // //   meta: {
-  // //     title: '表格',
-  // //     icon: 'table',
-  // //     alwaysShow: true
-  // //   },
-  // //   children: [
-  // //     // {
-  // //     //   path: 'test',
-  // //     //   component: () => import('_p/index/views/table-demo/test'),
-  // //     //   name: 'test',
-  // //     //   meta: {
-  // //     //     title: 'test'
-  // //     //   }
-  // //     // },
-  // //     {
-  // //       path: 'basic-usage',
-  // //       component: () => import('_p/index/views/table-demo/basic-usage/index.vue'),
-  // //       name: 'BasicUsage',
-  // //       meta: {
-  // //         title: '基础用法'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'table-ellipsis',
-  // //       component: () => import('_p/index/views/table-demo/table-ellipsis/index.vue'),
-  // //       name: 'TableEllipsis',
-  // //       meta: {
-  // //         title: '单元格自动省略'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'table-load',
-  // //       component: () => import('_p/index/views/table-demo/table-load/index.vue'),
-  // //       name: 'TableLoad',
-  // //       meta: {
-  // //         title: '远程加载数据'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'table-border',
-  // //       component: () => import('_p/index/views/table-demo/table-border/index.vue'),
-  // //       name: 'TableBorder',
-  // //       meta: {
-  // //         title: '带边框'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'table-merge',
-  // //       component: () => import('_p/index/views/table-demo/table-merge/index.vue'),
-  // //       name: 'TableMerge',
-  // //       meta: {
-  // //         title: '表格行/列合并'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'custom-menu',
-  // //       component: () => import('_p/index/views/table-demo/custom-menu/index.vue'),
-  // //       name: 'CustomMenu',
-  // //       meta: {
-  // //         title: '自定义筛选菜单'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'edit-cell',
-  // //       component: () => import('_p/index/views/table-demo/edit-cell/index.vue'),
-  // //       name: 'EditCell',
-  // //       meta: {
-  // //         title: '可编辑单元格'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'edit-row',
-  // //       component: () => import('_p/index/views/table-demo/edit-row/index.vue'),
-  // //       name: 'EditRow',
-  // //       meta: {
-  // //         title: '可编辑行'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'table-tree',
-  // //       component: () => import('_p/index/views/table-demo/table-tree/index.vue'),
-  // //       name: 'TableTree',
-  // //       meta: {
-  // //         title: '树形数据展示'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'table-expanded',
-  // //       component: () => import('_p/index/views/table-demo/table-expanded/index.vue'),
-  // //       name: 'TableExpanded',
-  // //       meta: {
-  // //         title: '可展开'
-  // //       }
-  // //     },
-  // //     {
-  // //       path: 'fixed-header',
-  // //       component: () => import('_p/index/views/table-demo/fixed-header/index.vue'),
-  // //       name: 'FixedHeader',
-  // //       meta: {
-  // //         title: '固定头和列'
-  // //       }
-  // //     }
-  // //   ]
-  // // },
-  // {
-  //   path: '/directives-demo',
-  //   component: Layout,
-  //   redirect: '/directives-demo/clipboard',
-  //   name: 'DirectivesDemo',
-  //   meta: {
-  //     title: '自定义指令',
-  //     icon: 'clipboard',
-  //     alwaysShow: true
-  //   },
-  //   children: [
-  //     {
-  //       path: 'clipboard',
-  //       component: () => import('_p/index/views/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('_p/index/views/hooks-demo/useWatermark/index.vue'),
-  //       name: 'UseWatermarkDemo',
-  //       meta: {
-  //         title: 'UseWaterMark'
-  //       }
-  //     },
-  //     {
-  //       path: 'useScrollTo',
-  //       component: () => import('_p/index/views/hooks-demo/useScrollTo/index.vue'),
-  //       name: 'UseScrollToDemo',
-  //       meta: {
-  //         title: 'UseScrollTo'
-  //       }
-  //     }
-  //   ]
-  // },
-  // {
-  //   path: '/icon',
-  //   component: Layout,
-  //   name: 'IconsDemo',
-  //   meta: {},
-  //   children: [
-  //     {
-  //       path: 'index',
-  //       component: () => import('_p/index/views/icons/index.vue'),
-  //       name: 'Icons',
-  //       meta: {
-  //         title: '图标',
-  //         icon: 'icon'
-  //       }
-  //     }
-  //   ]
-  // },
+  {
+    path: '/components-demo',
+    component: Layout,
+    redirect: '/components-demo/echarts',
+    name: 'ComponentsDemo',
+    meta: {
+      title: '功能组件',
+      icon: 'component',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'echarts',
+        component: () => import('_p/index/views/components-demo/echarts/index.vue'),
+        name: 'EchartsDemo',
+        meta: {
+          title: '图表'
+        }
+      },
+      {
+        path: 'preview',
+        component: () => import('_p/index/views/components-demo/preview/index.vue'),
+        name: 'PreviewDemo',
+        meta: {
+          title: '图片预览'
+        }
+      },
+      {
+        path: 'count-to',
+        component: () => import('_p/index/views/components-demo/count-to/index.vue'),
+        name: 'CountToDemo',
+        meta: {
+          title: '数字动画'
+        }
+      },
+      {
+        path: 'search',
+        component: () => import('_p/index/views/components-demo/search/index.vue'),
+        name: 'SearchDemo',
+        meta: {
+          title: '查询'
+        }
+      },
+      {
+        path: 'editor',
+        component: () => import('_p/index/views/components-demo/editor/index.vue'),
+        name: 'EditorDemo',
+        meta: {
+          title: '富文本编辑器'
+        }
+      },
+      {
+        path: 'markdown',
+        component: () => import('_p/index/views/components-demo/markdown/index.vue'),
+        name: 'MarkdownDemo',
+        meta: {
+          title: 'markdown编辑器'
+        }
+      }
+    ]
+  },
+  {
+    path: '/table-demo',
+    component: Layout,
+    redirect: '/table-demo/basic-usage',
+    name: 'TableDemo',
+    meta: {
+      title: '表格',
+      icon: 'table',
+      alwaysShow: true
+    },
+    children: [
+      // {
+      //   path: 'test',
+      //   component: () => import('_p/index/views/table-demo/test'),
+      //   name: 'test',
+      //   meta: {
+      //     title: 'test'
+      //   }
+      // },
+      {
+        path: 'basic-table',
+        component: () => import('_p/index/views/table-demo/basic-table/index.vue'),
+        name: 'BasicTable',
+        meta: {
+          title: '基础表格'
+        }
+      },
+      {
+        path: 'stripe-table',
+        component: () => import('_p/index/views/table-demo/stripe-table/index.vue'),
+        name: 'StripeTable',
+        meta: {
+          title: '带斑马纹表格'
+        }
+      },
+      {
+        path: 'border-table',
+        component: () => import('_p/index/views/table-demo/border-table/index.vue'),
+        name: 'BorderTable',
+        meta: {
+          title: '带边框表格'
+        }
+      },
+      {
+        path: 'state-table',
+        component: () => import('_p/index/views/table-demo/state-table/index.vue'),
+        name: 'StateTable',
+        meta: {
+          title: '带状态表格'
+        }
+      },
+      {
+        path: 'fixed-header',
+        component: () => import('_p/index/views/table-demo/fixed-header/index.vue'),
+        name: 'FixedHeader',
+        meta: {
+          title: '固定表头'
+        }
+      },
+      {
+        path: 'fixed-column',
+        component: () => import('_p/index/views/table-demo/fixed-column/index.vue'),
+        name: 'FixedColumn',
+        meta: {
+          title: '固定列'
+        }
+      },
+      {
+        path: 'fixed-column-header',
+        component: () => import('_p/index/views/table-demo/fixed-column-header/index.vue'),
+        name: 'FixedColumnHeader',
+        meta: {
+          title: '固定列和表头'
+        }
+      },
+      {
+        path: 'fluid-height',
+        component: () => import('_p/index/views/table-demo/fluid-height/index.vue'),
+        name: 'FluidHeight',
+        meta: {
+          title: '流体高度'
+        }
+      },
+      {
+        path: 'multi-header',
+        component: () => import('_p/index/views/table-demo/multi-header/index.vue'),
+        name: 'MultiHeader',
+        meta: {
+          title: '多级表头'
+        }
+      },
+      {
+        path: 'single-choice',
+        component: () => import('_p/index/views/table-demo/single-choice/index.vue'),
+        name: 'SingleChoice',
+        meta: {
+          title: '单选'
+        }
+      },
+      {
+        path: 'multiple-choice',
+        component: () => import('_p/index/views/table-demo/multiple-choice/index.vue'),
+        name: 'MultipleChoice',
+        meta: {
+          title: '多选'
+        }
+      },
+      {
+        path: 'sort-table',
+        component: () => import('_p/index/views/table-demo/sort-table/index.vue'),
+        name: 'SortTable',
+        meta: {
+          title: '排序'
+        }
+      },
+      {
+        path: 'screen-table',
+        component: () => import('_p/index/views/table-demo/screen-table/index.vue'),
+        name: 'ScreenTable',
+        meta: {
+          title: '筛选'
+        }
+      },
+      {
+        path: 'expand-row',
+        component: () => import('_p/index/views/table-demo/expand-row/index.vue'),
+        name: 'ExpandRow',
+        meta: {
+          title: '展开行'
+        }
+      },
+      {
+        path: 'tree-and-load',
+        component: () => import('_p/index/views/table-demo/tree-and-load/index.vue'),
+        name: 'TreeAndLoad',
+        meta: {
+          title: '树形数据与懒加载'
+        }
+      },
+      {
+        path: 'custom-header',
+        component: () => import('_p/index/views/table-demo/custom-header/index.vue'),
+        name: 'CustomHeader',
+        meta: {
+          title: '自定义表头'
+        }
+      },
+      {
+        path: 'total-table',
+        component: () => import('_p/index/views/table-demo/total-table/index.vue'),
+        name: 'TotalTable',
+        meta: {
+          title: '表尾合计行'
+        }
+      },
+    ]
+  },
+  {
+    path: '/directives-demo',
+    component: Layout,
+    redirect: '/directives-demo/clipboard',
+    name: 'DirectivesDemo',
+    meta: {
+      title: '自定义指令',
+      icon: 'clipboard',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'clipboard',
+        component: () => import('_p/index/views/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('_p/index/views/hooks-demo/useWatermark/index.vue'),
+        name: 'UseWatermarkDemo',
+        meta: {
+          title: 'UseWaterMark'
+        }
+      },
+      {
+        path: 'useScrollTo',
+        component: () => import('_p/index/views/hooks-demo/useScrollTo/index.vue'),
+        name: 'UseScrollToDemo',
+        meta: {
+          title: 'UseScrollTo'
+        }
+      }
+    ]
+  },
+  {
+    path: '/icon',
+    component: Layout,
+    name: 'IconsDemo',
+    meta: {},
+    children: [
+      {
+        path: 'index',
+        component: () => import('_p/index/views/icons/index.vue'),
+        name: 'Icons',
+        meta: {
+          title: '图标',
+          icon: 'icon'
+        }
+      }
+    ]
+  },
   {
     path: '/level',
     component: Layout,

+ 13 - 1
src/pages/index/store/modules/app.ts

@@ -15,6 +15,8 @@ export interface AppState {
   showScreenfull: Boolean
   showUserInfo: Boolean
   title: String
+  logoTitle: String
+  userInfo: String
 }
 
 @Module({ dynamic: true, namespaced: true, store, name: 'app' })
@@ -31,7 +33,9 @@ class App extends VuexModule implements AppState {
   public showHamburger = true // 是否显示侧边栏缩收按钮
   public showScreenfull = true // 是否全屏按钮
   public showUserInfo = true // 是否显示用户头像
-  public title = 'vue-antdv-admin' // 标题
+  public title = 'vue-element-plus-admin' // 标题
+  public logoTitle = 'vue-ElPlus-admin' // logo标题
+  public userInfo = 'userInfo' // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
 
   @Mutation
   private SET_COLLAPSED(collapsed: boolean): void {
@@ -85,6 +89,10 @@ class App extends VuexModule implements AppState {
   private SET_TITLE(title: string): void {
     this.title = title
   }
+  @Mutation
+  private SET_LOGOTITLE(logoTitle: string): void {
+    this.logoTitle = logoTitle
+  }
 
   @Action
   public SetCollapsed(collapsed: boolean): void {
@@ -138,6 +146,10 @@ class App extends VuexModule implements AppState {
   public SetTitle(title: string): void {
     this.SET_TITLE(title)
   }
+  @Action
+  public SetLogoTitle(logoTitle: string): void {
+    this.SET_LOGOTITLE(logoTitle)
+  }
 }
 
 export const appStore = getModule<App>(App)

+ 25 - 25
src/pages/index/views/components-demo/button/index.vue

@@ -1,47 +1,47 @@
 <template>
   <div>
-    <a-alert message="扩展 antdv 的 Button 组件,实现 primary、success、warning、info、default 等主题样式。" style="margin-bottom: 20px;" />
+    <el-alert message="扩展 antdv 的 Button 组件,实现 primary、success、warning、info、default 等主题样式。" style="margin-bottom: 20px;" />
     <div class="btn__wrap">default</div>
     <div class="btn__item">
-      <a-button>默认按钮</a-button>
-      <a-button shape="round">默认按钮</a-button>
-      <a-button loading>默认按钮</a-button>
-      <a-button disabled>默认按钮</a-button>
+      <el-button>默认按钮</el-button>
+      <el-button shape="round">默认按钮</el-button>
+      <el-button loading>默认按钮</el-button>
+      <el-button disabled>默认按钮</el-button>
     </div>
     <div class="btn__wrap">primary</div>
     <div class="btn__item">
-      <a-button type="primary">主要按钮</a-button>
-      <a-button type="primary" shape="round">主要按钮</a-button>
-      <a-button type="primary" loading>主要按钮</a-button>
-      <a-button type="primary" disabled>主要按钮</a-button>
+      <el-button type="primary">主要按钮</el-button>
+      <el-button type="primary" shape="round">主要按钮</el-button>
+      <el-button type="primary" loading>主要按钮</el-button>
+      <el-button type="primary" disabled>主要按钮</el-button>
     </div>
     <div class="btn__wrap">success</div>
     <div class="btn__item">
-      <a-button type="success">成功按钮</a-button>
-      <a-button type="success" shape="round">成功按钮</a-button>
-      <a-button type="success" loading>成功按钮</a-button>
-      <a-button type="success" disabled>成功按钮</a-button>
+      <el-button type="success">成功按钮</el-button>
+      <el-button type="success" shape="round">成功按钮</el-button>
+      <el-button type="success" loading>成功按钮</el-button>
+      <el-button type="success" disabled>成功按钮</el-button>
     </div>
     <div class="btn__wrap">warning</div>
     <div class="btn__item">
-      <a-button type="warning">警告按钮</a-button>
-      <a-button type="warning" shape="round">警告按钮</a-button>
-      <a-button type="warning" loading>警告按钮</a-button>
-      <a-button type="warning" disabled>警告按钮</a-button>
+      <el-button type="warning">警告按钮</el-button>
+      <el-button type="warning" shape="round">警告按钮</el-button>
+      <el-button type="warning" loading>警告按钮</el-button>
+      <el-button type="warning" disabled>警告按钮</el-button>
     </div>
     <div class="btn__wrap">danger</div>
     <div class="btn__item">
-      <a-button type="danger">危险按钮</a-button>
-      <a-button type="danger" shape="round">危险按钮</a-button>
-      <a-button type="danger" loading>危险按钮</a-button>
-      <a-button type="danger" disabled>危险按钮</a-button>
+      <el-button type="danger">危险按钮</el-button>
+      <el-button type="danger" shape="round">危险按钮</el-button>
+      <el-button type="danger" loading>危险按钮</el-button>
+      <el-button type="danger" disabled>危险按钮</el-button>
     </div>
     <div class="btn__wrap">info</div>
     <div class="btn__item">
-      <a-button type="info">信息按钮</a-button>
-      <a-button type="info" shape="round">信息按钮</a-button>
-      <a-button type="info" loading>信息按钮</a-button>
-      <a-button type="info" disabled>信息按钮</a-button>
+      <el-button type="info">信息按钮</el-button>
+      <el-button type="info" shape="round">信息按钮</el-button>
+      <el-button type="info" loading>信息按钮</el-button>
+      <el-button type="info" disabled>信息按钮</el-button>
     </div>
   </div>
 </template>

+ 34 - 27
src/pages/index/views/components-demo/count-to/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div>
-    <a-alert message="基于 vue-count-to 进行改造,支持所有 vue-count-to 参数。" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 vue-count-to 进行改造,支持所有 vue-count-to 参数。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
 
     <div class="count-to">
       <count-to
@@ -17,44 +23,44 @@
       />
     </div>
     <div class="action">
-      <a-row :gutter="20">
-        <a-col :span="8">
+      <el-row :gutter="20">
+        <el-col :span="8">
           <div class="action__item">
-            <span>startVal:</span><a-input-number v-model:value="startVal" :min="0" />
+            <span>startVal:</span><el-input-number v-model="startVal" :min="0" />
           </div>
-        </a-col>
-        <a-col :span="8">
+        </el-col>
+        <el-col :span="8">
           <div class="action__item">
-            <span>endVal:</span><a-input-number v-model:value="endVal" :min="1" />
+            <span>endVal:</span><el-input-number v-model="endVal" :min="1" />
           </div>
-        </a-col>
-        <a-col :span="8">
+        </el-col>
+        <el-col :span="8">
           <div class="action__item">
-            <span>duration:</span><a-input-number v-model:value="duration" :min="1000" />
+            <span>duration:</span><el-input-number v-model="duration" :min="1000" />
           </div>
-        </a-col>
-        <a-col :span="8">
+        </el-col>
+        <el-col :span="8">
           <div class="action__item">
-            <span>separator:</span><a-input v-model:value="separator" />
+            <span>separator:</span><el-input v-model="separator" />
           </div>
-        </a-col>
-        <a-col :span="8">
+        </el-col>
+        <el-col :span="8">
           <div class="action__item">
-            <span>prefix:</span><a-input v-model:value="prefix" />
+            <span>prefix:</span><el-input v-model="prefix" />
           </div>
-        </a-col>
-        <a-col :span="8">
+        </el-col>
+        <el-col :span="8">
           <div class="action__item">
-            <span>suffix:</span><a-input v-model:value="suffix" />
+            <span>suffix:</span><el-input v-model="suffix" />
           </div>
-        </a-col>
-        <a-col :span="24">
+        </el-col>
+        <el-col :span="24">
           <div style="text-align: center;margin-top: 20px;">
-            <a-button type="primary" @click="start">start</a-button>
-            <a-button style="margin-left: 10px;" @click="pauseResume">pause/resume</a-button>
+            <el-button type="primary" @click="start">start</el-button>
+            <el-button style="margin-left: 10px;" @click="pauseResume">pause/resume</el-button>
           </div>
-        </a-col>
-      </a-row>
+        </el-col>
+      </el-row>
     </div>
   </div>
 </template>
@@ -121,10 +127,11 @@ export default defineComponent({
     align-items: center;
     margin-bottom: 10px;
     &>span {
-      width: 100px;
+      display: inline-block;
+      width: 120px;
       text-align: center;
     }
-    @{deep}(.ant-input-number) {
+    @{deep}(.el-input-number) {
       width: 100%;
     }
   }

+ 17 - 11
src/pages/index/views/components-demo/echarts/index.vue

@@ -1,29 +1,35 @@
 <template>
   <div>
-    <a-alert message="统一封装 Echart 组件,自适应宽度,只需传入 options 与 height 属性即可展示对应的图表。" type="info" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="统一封装 Echart 组件,自适应宽度,只需传入 options 与 height 属性即可展示对应的图表。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
 
-    <a-row :gutter="20">
-      <a-col :span="10">
+    <el-row :gutter="20">
+      <el-col :span="10">
         <div class="chart-wrap">
           <echart :options="pieOptions" :height="'300px'" />
         </div>
-      </a-col>
-      <a-col :span="14">
+      </el-col>
+      <el-col :span="14">
         <div class="chart-wrap">
           <echart :options="barOptions" :height="'300px'" />
         </div>
-      </a-col>
-      <a-col :span="14">
+      </el-col>
+      <el-col :span="14">
         <div class="chart-wrap">
           <echart :options="lineOptions" :height="'300px'" />
         </div>
-      </a-col>
-      <a-col :span="10">
+      </el-col>
+      <el-col :span="10">
         <div class="chart-wrap">
           <echart :options="pieOptions2" :height="'300px'" />
         </div>
-      </a-col>
-    </a-row>
+      </el-col>
+    </el-row>
   </div>
 </template>
 

+ 7 - 1
src/pages/index/views/components-demo/editor/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div>
-    <a-alert message="基于 wangeditor 封装的 富文本 组件。" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 wangeditor 封装的 富文本 组件。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
     <editor v-model:value="html" />
   </div>
 </template>

+ 0 - 141
src/pages/index/views/components-demo/image/index.vue

@@ -1,141 +0,0 @@
-<template>
-  <div>
-    <a-alert message="抽取于 Element 的 Image 组件进行改造,在保留原生img的特性下,支持懒加载,自定义占位、加载失败等。" style="margin-bottom: 20px;" />
-    <div class="demo-image">
-      <div v-for="fit in fits" :key="fit" class="block">
-        <span class="demonstration">{{ fit }}</span>
-        <c-image
-          :src="url"
-          :fit="fit"
-          style="width: 100px; height: 100px"
-        />
-      </div>
-    </div>
-
-    <a-alert message="占位内容" style="margin-bottom: 20px;margin-top: 20px;" />
-    <div class="demo-image__placeholder">
-      <div class="block">
-        <span class="demonstration">默认</span>
-        <c-image :src="src" style="width: 300px; height: 200px" />
-      </div>
-      <div class="block">
-        <span class="demonstration">自定义</span>
-        <c-image :src="src" style="width: 300px; height: 200px">
-          <template #placeholder>
-            <div class="image-slot">
-              加载中...
-            </div>
-          </template>
-        </c-image>
-      </div>
-    </div>
-
-    <a-alert message="加载失败" style="margin-bottom: 20px;margin-top: 20px;" />
-    <div class="demo-image__error">
-      <div class="block">
-        <span class="demonstration">默认</span>
-        <c-image style="width: 300px; height: 200px" />
-      </div>
-      <div class="block">
-        <span class="demonstration">自定义</span>
-        <c-image style="width: 300px; height: 200px">
-          <template #error>
-            <div class="image-slot">
-              <PictureOutlined />
-            </div>
-          </template>
-        </c-image>
-      </div>
-    </div>
-
-    <a-alert message="懒加载" style="margin-bottom: 20px;margin-top: 20px;" />
-    <div class="demo-image__lazy">
-      <c-image
-        v-for="url in urls"
-        :key="url"
-        :src="url"
-        lazy
-        style="display: block;min-height: 200px;margin-bottom: 10px;"
-      />
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue'
-import CImage from '_c/Image/index.vue'
-import { PictureOutlined } from '@ant-design/icons-vue'
-export default defineComponent({
-  // name: 'Image',
-  components: {
-    CImage,
-    PictureOutlined
-  },
-  setup() {
-    const fits = ref<string[]>(['fill', 'contain', 'cover', 'none', 'scale-down'])
-    const url = ref<string>('https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg')
-    const src = ref<string>('https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg')
-    const urls = ref<string[]>([
-      'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
-      'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
-      'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
-      'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
-      'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
-      'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
-      'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
-    ])
-    return {
-      fits,
-      url,
-      src,
-      urls
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.demo-image,
-.demo-image__placeholder,
-.demo-image__error {
-  background: #fff;
-}
-.demo-image .block,
-.demo-image__error .block,
-.demo-image__placeholder .block {
-  padding: 30px 0;
-  text-align: center;
-  border-right: 1px solid #eff2f6;
-  display: inline-block;
-  width: 20%;
-  box-sizing: border-box;
-  vertical-align: top;
-  .demonstration {
-    display: block;
-    margin-bottom: 5px;
-  }
-  .image__error,
-  .image-slot {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 14px;
-    color: #c0c4cc;
-    vertical-align: middle;
-    height: 100%;
-    height: 100%;
-    background: #f5f7fa;
-  }
-}
-.demo-image__error .block,
-.demo-image__placeholder .block {
-  text-align: center;
-  width: 49%;
-}
-
-.demo-image__lazy {
-  width: 800px;
-  height: 400px;
-  overflow-y: auto;
-}
-</style>

+ 7 - 1
src/pages/index/views/components-demo/markdown/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div>
-    <a-alert message="基于 vditor 封装的 Markdown编辑器 组件。" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 vditor 封装的 Markdown编辑器 组件。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
     <markdown v-model:value="html" />
   </div>
 </template>

+ 33 - 9
src/pages/index/views/components-demo/preview/index.vue

@@ -1,8 +1,20 @@
 <template>
   <div>
-    <a-alert message="抽取于 Element 的图片预览组件进行改造,实现函数式调用组件,无需基于图片进行点击预览。" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="抽取于 Element 的图片预览组件进行改造,实现函数式调用组件,无需基于图片进行点击预览。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
 
-    <a-alert message="有底图预览" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="有底图预览。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
     <div class="img-wrap">
       <div
         v-for="(item, $index) in imgList"
@@ -14,18 +26,30 @@
       </div>
     </div>
 
-    <a-alert message="无底图预览" style="margin-bottom: 20px; margin-top: 20px;" />
-    <a-button type="primary" @click="showNoImg">点击预览</a-button>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="无底图预览。"
+      type="info"
+      style="margin-bottom: 20px; margin-top: 20px;"
+    />
+    <el-button type="primary" @click="showNoImg">点击预览</el-button>
 
-    <a-alert message="点击事件,包含图片点击事件以及关闭事件。" style="margin-bottom: 20px; margin-top: 20px;" />
-    <a-button type="primary" @click="showImg">点击预览</a-button>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="点击事件,包含图片点击事件以及关闭事件。。"
+      type="info"
+      style="margin-bottom: 20px; margin-top: 20px;"
+    />
+    <el-button type="primary" @click="showImg">点击预览</el-button>
   </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, ref } from 'vue'
 import { createImgPreview } from '_c/Preview/functional'
-import { message } from 'ant-design-vue'
+import { ElMessage } from 'element-plus'
 export default defineComponent({
   // name: 'PreviewDemo',
   setup() {
@@ -59,10 +83,10 @@ export default defineComponent({
         show: true,
         index: 0,
         onSelect: (i: number) => {
-          message.info('当前点击的图片索引:' + i)
+          ElMessage.info('当前点击的图片索引:' + i)
         },
         onClose: (i: number) => {
-          message.info('关闭之后的图片索引:' + i)
+          ElMessage.info('关闭之后的图片索引:' + i)
         }
       })
     }

+ 3 - 3
src/pages/index/views/components-demo/scroll/index.vue

@@ -1,8 +1,8 @@
 <template>
   <div>
-    <a-alert message="抽取于 Element 的 Scrollbar 组件进行改造统一美化各个浏览器滚动条,保持一致性。" style="margin-bottom: 20px;" />
+    <el-alert message="抽取于 Element 的 Scrollbar 组件进行改造统一美化各个浏览器滚动条,保持一致性。" style="margin-bottom: 20px;" />
 
-    <a-alert message="横向滚动,外围容器需要设置固定宽度。" style="margin-bottom: 20px;" />
+    <el-alert message="横向滚动,外围容器需要设置固定宽度。" style="margin-bottom: 20px;" />
     <div class="deom__wrap deom__wrap--horizontal">
       <scrollbar>
         <ul class="deom-ul__wrap">
@@ -11,7 +11,7 @@
       </scrollbar>
     </div>
 
-    <a-alert message="纵向滚动,外围容器需要设置固定高度。" style="margin-bottom: 20px;margin-top: 20px;" />
+    <el-alert message="纵向滚动,外围容器需要设置固定高度。" style="margin-bottom: 20px;margin-top: 20px;" />
     <div class="deom__wrap deom__wrap--vertical">
       <scrollbar>
         <ul class="deom-ul__wrap">

+ 75 - 73
src/pages/index/views/components-demo/search/classic-data.ts

@@ -2,16 +2,16 @@ export const classicData = [
   {
     label: '即时配送',
     value: true,
-    type: 'switch',
+    itemType: 'switch',
     field: 'delivery'
   },
   {
     label: '活动名称',
     value: '',
-    type: 'input',
-    placeholder: '活动名称',
+    itemType: 'input',
     field: 'name',
-    allowClear: true,
+    placeholder: '活动名称',
+    clearable: true,
     rules: [
       {
         required: true,
@@ -21,11 +21,11 @@ export const classicData = [
   },
   {
     label: '活动区域',
-    value: undefined,
-    type: 'select',
+    value: '',
+    itemType: 'select',
     placeholder: '活动区域',
+    clearable: true,
     field: 'region',
-    allowClear: true,
     options: [
       {
         title: '区域一',
@@ -38,7 +38,7 @@ export const classicData = [
     ],
     rules: [
       {
-        type: 'string',
+        itemType: 'string',
         required: true,
         message: '请选择活动区域'
       }
@@ -47,7 +47,7 @@ export const classicData = [
   {
     label: '特殊资源',
     value: '2',
-    type: 'radio',
+    itemType: 'radio',
     field: 'resource',
     radioType: 'button', // button or radio
     options: [
@@ -61,87 +61,89 @@ export const classicData = [
       }
     ]
   },
-  {
-    label: '组织机构',
-    value: [],
-    type: 'treeSelect',
-    field: 'company',
-    allowClear: true,
-    placeholder: '请选择组织机构',
-    treeCheckable: false,
-    maxTagCount: 2,
-    options: [
-      {
-        title: 'Node1',
-        value: '0-0',
-        key: '0-0',
-        children: [
-          {
-            title: 'Child Node1',
-            value: '0-0-0',
-            key: '0-0-0'
-          }
-        ]
-      },
-      {
-        title: 'Node2',
-        value: '0-1',
-        key: '0-1',
-        children: [
-          {
-            title: 'Child Node3',
-            value: '0-1-0',
-            key: '0-1-0',
-            disabled: true
-          },
-          {
-            title: 'Child Node4',
-            value: '0-1-1',
-            key: '0-1-1'
-          },
-          {
-            title: 'Child Node5',
-            value: '0-1-2',
-            key: '0-1-2'
-          }
-        ]
-      }
-    ]
-  },
+  // {
+  //   label: '组织机构',
+  //   value: [],
+  //   itemType: 'treeSelect',
+  //   field: 'company',
+  //   allowClear: true,
+  //   placeholder: '请选择组织机构',
+  //   treeCheckable: false,
+  //   maxTagCount: 2,
+  //   options: [
+  //     {
+  //       title: 'Node1',
+  //       value: '0-0',
+  //       key: '0-0',
+  //       children: [
+  //         {
+  //           title: 'Child Node1',
+  //           value: '0-0-0',
+  //           key: '0-0-0'
+  //         }
+  //       ]
+  //     },
+  //     {
+  //       title: 'Node2',
+  //       value: '0-1',
+  //       key: '0-1',
+  //       children: [
+  //         {
+  //           title: 'Child Node3',
+  //           value: '0-1-0',
+  //           key: '0-1-0',
+  //           disabled: true
+  //         },
+  //         {
+  //           title: 'Child Node4',
+  //           value: '0-1-1',
+  //           key: '0-1-1'
+  //         },
+  //         {
+  //           title: 'Child Node5',
+  //           value: '0-1-2',
+  //           key: '0-1-2'
+  //         }
+  //       ]
+  //     }
+  //   ]
+  // },
   {
     label: '日选择器',
-    value: null,
-    type: 'datePicker',
+    value: '',
+    itemType: 'datePicker',
     field: 'date1',
-    allowClear: true,
-    valueFormat: 'YYYY-MM-DD',
+    clearable: true,
+    format: 'YYYY-MM-DD',
     placeholder: '请选择日期'
   },
   {
     label: '月选择器',
-    value: null,
-    type: 'monthPicker',
+    value: '',
+    itemType: 'datePicker',
     field: 'date2',
-    valueFormat: 'YYYY-MM',
-    allowClear: true,
+    clearable: true,
+    format: 'YYYY-MM',
     placeholder: '请选择日期'
   },
   {
     label: '范围选择器',
-    value: null,
-    type: 'rangePicker',
-    valueFormat: 'YYYY-MM-DD',
+    value: [],
+    itemType: 'datePicker',
     field: 'date3',
-    allowClear: true,
-    placeholder: ['请选择日期', '请选择日期']
+    clearable: true,
+    type: 'daterange',
+    rangeSeparator: '至',
+    startPlaceholder: '开始日期',
+    endPlaceholder: '结束日期'
   },
   {
     label: '周选择器',
-    value: null,
-    type: 'weekPicker',
+    value: '',
+    itemType: 'datePicker',
     field: 'date4',
-    valueFormat: 'YYYY-MM-DD',
-    allowClear: true,
+    type: 'week',
+    clearable: true,
     placeholder: '请选择日期'
   }
 ]

+ 28 - 4
src/pages/index/views/components-demo/search/index.vue

@@ -1,7 +1,19 @@
 <template>
   <div>
-    <a-alert message="封装 antdv 的 Form 组件,实现查询、重置等功能,并提供了三种布局风格。" style="margin-bottom: 20px;" />
-    <a-alert message="经典风格" style="margin-bottom: 20px;margin-top: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="封装 Element 的 Form 组件,实现查询、重置等功能,并提供了三种布局风格。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="经典风格。"
+      type="info"
+      style="margin-bottom: 20px;margin-top: 20px;"
+    />
     <div class="searh">
       <search
         :data="classicData"
@@ -13,7 +25,13 @@
       </div>
     </div>
 
-    <a-alert message="底部操作按钮风格" style="margin-bottom: 20px;margin-top: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="底部操作按钮风格。"
+      type="info"
+      style="margin-bottom: 20px;margin-top: 20px;"
+    />
     <div class="searh">
       <search
         layout="bottom"
@@ -26,7 +44,13 @@
       </div>
     </div>
 
-    <a-alert message="右侧操作按钮风格" style="margin-bottom: 20px;margin-top: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="右侧操作按钮风格。"
+      type="info"
+      style="margin-bottom: 20px;margin-top: 20px;"
+    />
     <div class="searh">
       <search
         layout="right"

+ 0 - 64
src/pages/index/views/dashboard/index.vue

@@ -16,70 +16,6 @@
     <div class="chart__wrap">
       <echart :options="lineEchatOptions" :height="'300px'" />
     </div>
-    <panel-group />
-    <el-row :gutter="20">
-      <el-col :span="10">
-        <div class="chart__wrap">
-          <echart :options="pieEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-      <el-col :span="14">
-        <div class="chart__wrap">
-          <echart :options="barEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-    </el-row>
-    <div class="chart__wrap">
-      <echart :options="lineEchatOptions" :height="'300px'" />
-    </div>
-    <panel-group />
-    <el-row :gutter="20">
-      <el-col :span="10">
-        <div class="chart__wrap">
-          <echart :options="pieEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-      <el-col :span="14">
-        <div class="chart__wrap">
-          <echart :options="barEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-    </el-row>
-    <div class="chart__wrap">
-      <echart :options="lineEchatOptions" :height="'300px'" />
-    </div>
-    <panel-group />
-    <el-row :gutter="20">
-      <el-col :span="10">
-        <div class="chart__wrap">
-          <echart :options="pieEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-      <el-col :span="14">
-        <div class="chart__wrap">
-          <echart :options="barEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-    </el-row>
-    <div class="chart__wrap">
-      <echart :options="lineEchatOptions" :height="'300px'" />
-    </div>
-    <panel-group />
-    <el-row :gutter="20">
-      <el-col :span="10">
-        <div class="chart__wrap">
-          <echart :options="pieEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-      <el-col :span="14">
-        <div class="chart__wrap">
-          <echart :options="barEchatOptions" :height="'300px'" />
-        </div>
-      </el-col>
-    </el-row>
-    <div class="chart__wrap">
-      <echart :options="lineEchatOptions" :height="'300px'" />
-    </div>
   </div>
 </template>
 

+ 29 - 11
src/pages/index/views/directives-demo/clipboard/index.vue

@@ -1,38 +1,56 @@
 <template>
   <div>
-    <a-alert message="自定义指令:v-clipboard,用于复制文本。" style="margin-bottom: 20px;" />
-    <a-alert message="基础示例" style="margin-bottom: 20px;margin-top: 20px;" />
+    <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-bottom: 20px;margin-top: 20px;"
+    />
     <div class="input__wrap">
-      <a-input v-model:value="inputVal1" placeholder="请输入要复制的文本" />
-      <a-button v-clipboard="inputVal1" type="primary">复制</a-button>
+      <el-input v-model="inputVal1" placeholder="请输入要复制的文本" />
+      <el-button v-clipboard="inputVal1" type="primary">复制</el-button>
     </div>
 
-    <a-alert message="自定义回调方法" style="margin-bottom: 20px;margin-top: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="自定义回调方法。"
+      type="info"
+      style="margin-bottom: 20px;margin-top: 20px;"
+    />
     <div class="input__wrap">
-      <a-input v-model:value="inputVal2" placeholder="请输入要复制的文本" />
-      <a-button
+      <el-input v-model="inputVal2" placeholder="请输入要复制的文本" />
+      <el-button
         v-clipboard="inputVal2"
         v-clipboard:success="clipboardSuccess"
         v-clipboard:error="clipboardSuccess"
         type="primary"
-      >复制</a-button>
+      >复制</el-button>
     </div>
   </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, ref } from 'vue'
-import { message } from 'ant-design-vue'
+import { ElMessage } from 'element-plus'
 export default defineComponent({
   // name: 'Clipboard'
   setup() {
     const inputVal1 = ref<string>('')
     const inputVal2 = ref<string>('')
     function clipboardSuccess(val: any) {
-      message.success('我是自定义成功回调:' + val.text)
+      ElMessage.success('我是自定义成功回调:' + val.text)
     }
     function clipboardError() {
-      message.error('我是自定义失败回调')
+      ElMessage.error('我是自定义失败回调')
     }
     return {
       inputVal1, inputVal2,

+ 14 - 12
src/pages/index/views/hooks-demo/useScrollTo/index.vue

@@ -1,18 +1,24 @@
 <template>
   <div>
-    <a-alert message="useScrollTo,提供JS滚动过渡动画功能。" style="margin-bottom: 20px;" />
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="useScrollTo,提供JS滚动过渡动画功能。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
     <div class="button__wrap">
-      <a-button type="primary" @click="scrollTo(100, 'scrollTop')">垂直滚动100px</a-button>
-      <a-button type="primary" @click="scrollTo(800, 'scrollTop')">垂直滚动800px</a-button>
-      <a-button type="primary" @click="scrollTo(100, 'scrollLeft')">水平滚动100px</a-button>
-      <a-button type="primary" @click="scrollTo(500, 'scrollLeft')">水平滚动500px</a-button>
+      <el-button type="primary" @click="scrollTo(100, 'scrollTop')">垂直滚动100px</el-button>
+      <el-button type="primary" @click="scrollTo(800, 'scrollTop')">垂直滚动800px</el-button>
+      <el-button type="primary" @click="scrollTo(100, 'scrollLeft')">水平滚动100px</el-button>
+      <el-button type="primary" @click="scrollTo(500, 'scrollLeft')">水平滚动500px</el-button>
     </div>
     <div class="deom__wrap">
-      <scrollbar ref="scrollContainer">
+      <el-scrollbar ref="scrollContainer">
         <ul class="deom-ul__wrap">
           <li v-for="i in 100" :key="i">{{ i }}</li>
         </ul>
-      </scrollbar>
+      </el-scrollbar>
     </div>
   </div>
 </template>
@@ -20,17 +26,13 @@
 <script lang="ts">
 import { defineComponent, ref, unref } from 'vue'
 import { useScrollTo } from '@/hooks/useScrollTo'
-import Scrollbar from '_c/Scrollbar/index.vue'
 export default defineComponent({
   // name: 'UseScrollToDemo',
-  components: {
-    Scrollbar
-  },
   setup() {
     const scrollContainer = ref<HTMLElement | null>(null)
 
     function scrollTo(to: number, position: string): void {
-      const $scrollWrapper: any = (unref(scrollContainer) as any).$.wrap
+      const $scrollWrapper: any = (unref(scrollContainer) as any).wrap
       const { start } = useScrollTo({
         el: $scrollWrapper,
         position: position,

+ 10 - 4
src/pages/index/views/hooks-demo/useWatermark/index.vue

@@ -1,9 +1,15 @@
 <template>
   <div>
-    <a-alert message="useWatermark,为整个系统提供水印功能。" style="margin-bottom: 20px;" />
-    <a-button type="primary" @click="setWatermark('vue-antdv-admin')">创建水印</a-button>
-    <a-button type="danger" @click="clear">清除水印</a-button>
-    <a-button type="warning" @click="setWatermark('vue-antdv-admin-new')">重置水印</a-button>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="useWatermark,为整个系统提供水印功能。"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <el-button type="primary" @click="setWatermark('vue-antdv-admin')">创建水印</el-button>
+    <el-button type="danger" @click="clear">清除水印</el-button>
+    <el-button type="warning" @click="setWatermark('vue-antdv-admin-new')">重置水印</el-button>
   </div>
 </template>
 

+ 2 - 5
src/pages/index/views/icons/index.vue

@@ -5,15 +5,12 @@
       :key="item"
       v-clipboard="generateIconCode(item)"
     >
-      <a-tooltip placement="top">
-        <template #title>
-          {{ generateIconCode(item) }}
-        </template>
+      <el-tooltip placement="top" :content="generateIconCode(item)">
         <div class="icon-item">
           <svg-icon :icon-class="item" class-name="disabled" />
           <span>{{ item }}</span>
         </div>
-      </a-tooltip>
+      </el-tooltip>
     </div>
   </div>
 </template>

+ 2 - 2
src/pages/index/views/login/index.vue

@@ -61,7 +61,7 @@ import { defineComponent, ref, unref, reactive, watch } from 'vue'
 import { useRouter } from 'vue-router'
 import type { RouteRecordRaw } from 'vue-router'
 import { permissionStore } from '_p/index/store/modules/permission'
-import config from '_p/index/config'
+import { appStore } from '_p/index/store/modules/app'
 import wsCache from '@/cache'
 
 interface FormModule {
@@ -106,7 +106,7 @@ export default defineComponent({
               permissionStore.addRouters.forEach(async(route: RouteRecordRaw) => {
                 await addRoute(route.name!, route) // 动态添加可访问路由表
               })
-              wsCache.set(config.user_info, form)
+              wsCache.set(appStore.userInfo, form)
               permissionStore.SetIsAddRouters(true)
               push({ path: redirect.value || '/' })
             })

+ 73 - 0
src/pages/index/views/table-demo/basic-table/index.vue

@@ -0,0 +1,73 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 基础表格"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table v-loading="loading" :columns="columns" :data="tableData" />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'BasicTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+    return {
+      columns,
+      tableData,
+      loading
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 0 - 118
src/pages/index/views/table-demo/basic-usage/index.vue

@@ -1,118 +0,0 @@
-<template>
-  <div>
-    <com-table
-      :loading="loading"
-      :columns="columns"
-      :data-source="data"
-    >
-      <template #name="{ text }">
-        <a>{{ text }}</a>
-      </template>
-      <template #customTitle>
-        <span><smile-outlined /> Name</span>
-      </template>
-      <template #tags="{ text: tags }">
-        <span>
-          <a-tag
-            v-for="tag in tags"
-            :key="tag"
-            :color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
-          >
-            {{ tag.toUpperCase() }}
-          </a-tag>
-        </span>
-      </template>
-      <template #action="{ record }">
-        <span>
-          <a>Invite -- {{ record.name }}</a>
-          <a-divider type="vertical" />
-          <a>Delete</a>
-          <a-divider type="vertical" />
-          <a class="ant-dropdown-link"> More actions <down-outlined /> </a>
-        </span>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue'
-import ComTable from '_c/Table'
-import { SmileOutlined, DownOutlined } from '@ant-design/icons-vue'
-
-const columns = [
-  {
-    dataIndex: 'name',
-    key: 'name',
-    slots: { title: 'customTitle', customRender: 'name' }
-  },
-  {
-    title: 'Age',
-    dataIndex: 'age',
-    key: 'age'
-  },
-  {
-    title: 'Address',
-    dataIndex: 'address',
-    key: 'address'
-  },
-  {
-    title: 'Tags',
-    key: 'tags',
-    dataIndex: 'tags',
-    slots: { customRender: 'tags' }
-  },
-  {
-    title: 'Action',
-    key: 'action',
-    slots: { customRender: 'action' }
-  }
-]
-
-const data = [
-  {
-    key: '1',
-    name: 'John Brown',
-    age: 32,
-    address: 'New York No. 1 Lake Park',
-    tags: ['nice', 'developer']
-  },
-  {
-    key: '2',
-    name: 'Jim Green',
-    age: 42,
-    address: 'London No. 1 Lake Park',
-    tags: ['loser']
-  },
-  {
-    key: '3',
-    name: 'Joe Black',
-    age: 32,
-    address: 'Sidney No. 1 Lake Park',
-    tags: ['cool', 'teacher']
-  }
-]
-
-export default defineComponent({
-  // name: 'BasicUsage',
-  components: {
-    ComTable,
-    SmileOutlined,
-    DownOutlined
-  },
-  setup() {
-    const loading = ref<boolean>(true)
-    setTimeout(() => {
-      loading.value = false
-    }, 1000)
-    return {
-      loading,
-      columns,
-      data
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 78 - 0
src/pages/index/views/table-demo/border-table/index.vue

@@ -0,0 +1,78 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带边框表格"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      border
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'BorderTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+    return {
+      columns,
+      tableData,
+      loading
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 111 - 0
src/pages/index/views/table-demo/custom-header/index.vue

@@ -0,0 +1,111 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 自定义表头"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))"
+    >
+      <template #actionHeader>
+        <el-input
+          v-model="search"
+          size="mini"
+          placeholder="输入关键字搜索"
+        />
+      </template>
+      <template #action="scope">
+        <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>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'action',
+    slots: {
+      header: 'actionHeader',
+      default: 'action'
+    }
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎1',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎2',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎3',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎4',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'CustomHeader',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    const search = ref<string>('')
+
+    function handleEdit(index: number, row: any) {
+      console.log(index, row)
+    }
+    function handleDelete(index: number, row: any) {
+      console.log(index, row)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      search,
+      handleEdit, handleDelete
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 0 - 198
src/pages/index/views/table-demo/custom-menu/index.vue

@@ -1,198 +0,0 @@
-<template>
-  <div>
-    <com-table :data-source="data" :columns="columns">
-      <template #filterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
-        <div style="padding: 8px">
-          <a-input
-            :ref="c => (searchInput = c)"
-            v-model:value="selectedKeys[0]"
-            :placeholder="`Search ${column.dataIndex}`"
-            style="width: 188px; margin-bottom: 8px; display: block;"
-            @change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
-            @pressEnter="handleSearch(selectedKeys, confirm, column.dataIndex)"
-          />
-          <a-button
-            type="primary"
-            size="small"
-            style="width: 90px; margin-right: 8px"
-            @click="handleSearch(selectedKeys, confirm, column.dataIndex)"
-          >
-            <template #icon><SearchOutlined /></template>
-            Search
-          </a-button>
-          <a-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
-            Reset
-          </a-button>
-        </div>
-      </template>
-      <template #filterIcon="filtered">
-        <search-outlined :style="{ color: filtered ? '#108ee9' : undefined }" />
-      </template>
-      <template #customRender="{ text, column }">
-        <span v-if="searchText && searchedColumn === column.dataIndex">
-          <template
-            v-for="(fragment, i) in text
-              .toString()
-              .split(new RegExp(`(?<=${searchText})|(?=${searchText})`, 'i'))"
-            :key="i"
-          >
-            <mark v-if="fragment.toLowerCase() === searchText.toLowerCase()" class="highlight">
-              {{ fragment }}
-            </mark>
-            <template v-else>{{ fragment }}</template>
-          </template>
-        </span>
-        <template v-else>
-          {{ text }}
-        </template>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref, getCurrentInstance } from 'vue'
-import ComTable from '_c/Table'
-import { SearchOutlined } from '@ant-design/icons-vue'
-
-const data = [
-  {
-    key: '1',
-    name: 'John Brown',
-    age: 32,
-    address: 'New York No. 1 Lake Park'
-  },
-  {
-    key: '2',
-    name: 'Joe Black',
-    age: 42,
-    address: 'London No. 1 Lake Park'
-  },
-  {
-    key: '3',
-    name: 'Jim Green',
-    age: 32,
-    address: 'Sidney No. 1 Lake Park'
-  },
-  {
-    key: '4',
-    name: 'Jim Red',
-    age: 32,
-    address: 'London No. 2 Lake Park'
-  }
-]
-
-export default defineComponent({
-  // name: 'CustomMenu',
-  components: {
-    ComTable,
-    SearchOutlined
-  },
-  setup() {
-    const { ctx } = getCurrentInstance() as any
-
-    const searchText = ref<string>('')
-    const searchInput = ref<any>(null)
-    const searchedColumn = ref<string>('')
-
-    const columns = ref<any[]>([
-      {
-        title: 'Name',
-        dataIndex: 'name',
-        key: 'name',
-        slots: {
-          filterDropdown: 'filterDropdown',
-          filterIcon: 'filterIcon',
-          customRender: 'customRender'
-        },
-        onFilter: (value: string, record: any) =>
-          record.name
-            .toString()
-            .toLowerCase()
-            .includes(value.toLowerCase()),
-        onFilterDropdownVisibleChange: (visible: boolean) => {
-          if (visible) {
-            setTimeout(() => {
-              console.log(searchInput.value)
-              searchInput.value.focus()
-            }, 0)
-          }
-        }
-      },
-      {
-        title: 'Age',
-        dataIndex: 'age',
-        key: 'age',
-        slots: {
-          filterDropdown: 'filterDropdown',
-          filterIcon: 'filterIcon',
-          customRender: 'customRender'
-        },
-        onFilter: (value: string, record: any) =>
-          record.age
-            .toString()
-            .toLowerCase()
-            .includes(value.toLowerCase()),
-        onFilterDropdownVisibleChange: (visible: boolean) => {
-          if (visible) {
-            setTimeout(() => {
-              searchInput.value.focus()
-            })
-          }
-        }
-      },
-      {
-        title: 'Address',
-        dataIndex: 'address',
-        key: 'address',
-        slots: {
-          filterDropdown: 'filterDropdown',
-          filterIcon: 'filterIcon',
-          customRender: 'customRender'
-        },
-        onFilter: (value: string, record: any) =>
-          record.address
-            .toString()
-            .toLowerCase()
-            .includes(value.toLowerCase()),
-        onFilterDropdownVisibleChange: (visible: boolean) => {
-          if (visible) {
-            setTimeout(() => {
-              searchInput.value.focus()
-            })
-          }
-        }
-      }
-    ])
-
-    function handleSearch(selectedKeys: string[], confirm: Function, dataIndex: string) {
-      confirm()
-      searchText.value = selectedKeys[0]
-      searchedColumn.value = dataIndex
-      ctx.$forceUpdate()
-    }
-
-    function handleReset(clearFilters: Function) {
-      clearFilters()
-      searchText.value = ''
-    }
-
-    return {
-      data,
-      columns,
-      searchText,
-      searchInput,
-      searchedColumn,
-      handleSearch,
-      handleReset
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-@{deep}(.highlight) {
-  background-color: rgb(255, 192, 105);
-  padding: 0px;
-}
-</style>

+ 0 - 98
src/pages/index/views/table-demo/edit-cell/EditableCell.vue

@@ -1,98 +0,0 @@
-<template>
-  <div class="editable-cell">
-    <div v-if="editable" class="editable-cell-input-wrapper">
-      <a-input v-model:value="value" @pressEnter="check" />
-      <check-outlined class="editable-cell-icon-check" @click="check" />
-    </div>
-    <div v-else class="editable-cell-text-wrapper">
-      {{ value || ' ' }}
-      <edit-outlined class="editable-cell-icon" @click="edit" />
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-import { CheckOutlined, EditOutlined } from '@ant-design/icons-vue'
-import { defineComponent, PropType, ref } from 'vue'
-export default defineComponent({
-  name: 'EditableCell',
-  components: {
-    CheckOutlined,
-    EditOutlined
-  },
-  props: {
-    text: {
-      type: String as PropType<string>,
-      default: ''
-    },
-    onChange: {
-      type: Function as PropType<Function | null>,
-      default: null
-    }
-  },
-  setup(props, { emit }) {
-    const value = ref<string>(props.text)
-    const editable = ref<boolean>(false)
-
-    function handleChange(e: any) {
-      const value = e.target.value
-      value.value = value
-    }
-    function check() {
-      editable.value = false
-      emit('change', value.value)
-    }
-    function edit() {
-      editable.value = true
-    }
-
-    return {
-      value, editable,
-      check, edit
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.editable-cell {
-  position: relative;
-  .editable-cell-input-wrapper,
-  .editable-cell-text-wrapper {
-    padding-right: 24px;
-  }
-
-  .editable-cell-text-wrapper {
-    padding: 5px 24px 5px 5px;
-  }
-
-  .editable-cell-icon,
-  .editable-cell-icon-check {
-    position: absolute;
-    right: 0;
-    width: 20px;
-    cursor: pointer;
-  }
-
-  .editable-cell-icon {
-    line-height: 18px;
-    display: none;
-  }
-
-  .editable-cell-icon-check {
-    line-height: 28px;
-  }
-
-  .editable-cell-icon:hover,
-  .editable-cell-icon-check:hover {
-    color: #108ee9;
-  }
-
-  .editable-add-btn {
-    margin-bottom: 8px;
-  }
-}
-.editable-cell:hover .editable-cell-icon {
-  display: inline-block;
-}
-</style>

+ 0 - 104
src/pages/index/views/table-demo/edit-cell/index.vue

@@ -1,104 +0,0 @@
-<template>
-  <div>
-    <a-button class="editable-add-btn" @click="handleAdd">
-      Add
-    </a-button>
-    <com-table bordered :data-source="dataSource" :columns="columns">
-      <template #name="{ text, record }">
-        <editable-cell :text="text" @change="val => onCellChange(record.key, 'name', val)" />
-      </template>
-      <template #operation="{ record }">
-        <a-popconfirm
-          v-if="dataSource.length"
-          title="Sure to delete?"
-          @confirm="onDelete(record.key)"
-        >
-          <a>Delete</a>
-        </a-popconfirm>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue'
-import ComTable from '_c/Table'
-import EditableCell from './EditableCell.vue'
-export default defineComponent({
-  // name: 'EditCell',
-  components: {
-    ComTable,
-    EditableCell
-  },
-  setup() {
-    const count = ref<number>(2)
-    const dataSource = ref<any[]>([
-      {
-        key: '0',
-        name: 'Edward King 0',
-        age: '32',
-        address: 'London, Park Lane no. 0'
-      },
-      {
-        key: '1',
-        name: 'Edward King 1',
-        age: '32',
-        address: 'London, Park Lane no. 1'
-      }
-    ])
-
-    const columns = ref<any[]>([
-      {
-        title: 'name',
-        dataIndex: 'name',
-        width: '30%',
-        slots: { customRender: 'name' }
-      },
-      {
-        title: 'age',
-        dataIndex: 'age'
-      },
-      {
-        title: 'address',
-        dataIndex: 'address'
-      },
-      {
-        title: 'operation',
-        dataIndex: 'operation',
-        slots: { customRender: 'operation' }
-      }
-    ])
-
-    function onCellChange(key: string, dataIndex: string, value: string) {
-      const newDataSource = [...dataSource.value]
-      const target: any[] = newDataSource.find((item: any) => item.key === key)
-      if (target) {
-        target[dataIndex] = value
-        dataSource.value = newDataSource
-      }
-    }
-    function onDelete(key: string) {
-      const newDataSource = [...dataSource.value]
-      dataSource.value = newDataSource.filter((item: any) => item.key !== key)
-    }
-    function handleAdd() {
-      const newData = {
-        key: count.value,
-        name: `Edward King ${count.value}`,
-        age: 32,
-        address: `London, Park Lane no. ${count.value}`
-      }
-      dataSource.value = [...dataSource.value, newData]
-      count.value = count.value + 1
-    }
-
-    return {
-      count, dataSource, columns,
-      onCellChange, onDelete, handleAdd
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 0 - 141
src/pages/index/views/table-demo/edit-row/index.vue

@@ -1,141 +0,0 @@
-<template>
-  <div>
-    <com-table :columns="columns" :data-source="data" bordered>
-      <template v-for="col in ['name', 'age', 'address']" #[col]="{ text, record }" :key="col">
-        <div :key="col">
-          <a-input
-            v-if="record.editable"
-            style="margin: -5px 0"
-            :value="text"
-            @change="e => handleChange(e.target.value, record.key, col)"
-          />
-          <template v-else>
-            {{ text }}
-          </template>
-        </div>
-      </template>
-      <template #operation="{ record }">
-        <div class="editable-row-operations">
-          <span v-if="record.editable">
-            <a @click="save(record.key)">Save</a>
-            <a-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)">
-              <a>Cancel</a>
-            </a-popconfirm>
-          </span>
-          <span v-else>
-            <a v-bind="editingKey !== '' ? { disabled: 'disabled' } : {}" @click="edit(record.key)">
-              Edit
-            </a>
-          </span>
-        </div>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue'
-import ComTable from '_c/Table'
-
-const columns = [
-  {
-    title: 'name',
-    dataIndex: 'name',
-    width: '25%',
-    slots: { customRender: 'name' }
-  },
-  {
-    title: 'age',
-    dataIndex: 'age',
-    width: '15%',
-    slots: { customRender: 'age' }
-  },
-  {
-    title: 'address',
-    dataIndex: 'address',
-    width: '40%',
-    slots: { customRender: 'address' }
-  },
-  {
-    title: 'operation',
-    dataIndex: 'operation',
-    slots: { customRender: 'operation' }
-  }
-]
-
-const dataList: any[] = []
-for (let i = 0; i < 100; i++) {
-  dataList.push({
-    key: i.toString(),
-    name: `Edrward ${i}`,
-    age: 32,
-    address: `London Park no. ${i}`
-  })
-}
-
-export default defineComponent({
-  // name: 'EditRow',
-  components: {
-    ComTable
-  },
-  setup() {
-    const cacheData = ref<any[]>(dataList.map(item => ({ ...item })))
-    const editingKey = ref<string>('')
-    const data = ref<any[]>(dataList)
-
-    function handleChange(value: string, key: string, column: string) {
-      const newData = [...data.value]
-      const target: any[] = newData.filter((item: any) => key === item.key)[0]
-      if (target) {
-        target[column] = value
-        data.value = newData
-      }
-    }
-    function edit(key: string) {
-      const newData = [...data.value]
-      const target: any = newData.filter((item: any) => key === item.key)[0]
-      editingKey.value = key
-      if (target) {
-        target.editable = true
-        data.value = newData
-      }
-    }
-    function save(key: string) {
-      const newData = [...data.value]
-      const newCacheData = [...cacheData.value]
-      const target: any = newData.filter((item: any) => key === item.key)[0]
-      const targetCache: any[] = newCacheData.filter((item: any) => key === item.key)[0]
-      if (target && targetCache) {
-        delete target.editable
-        data.value = newData
-        Object.assign(targetCache, target)
-        cacheData.value = newCacheData
-      }
-      editingKey.value = ''
-    }
-    function cancel(key: string) {
-      const newData = [...data.value]
-      const target: any = newData.filter((item: any) => key === item.key)[0]
-      editingKey.value = ''
-      if (target) {
-        Object.assign(target, cacheData.value.filter((item: any) => key === item.key)[0])
-        delete target.editable
-        data.value = newData
-      }
-    }
-
-    return {
-      columns,
-      data,
-      editingKey,
-      handleChange, edit, save, cancel
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-.editable-row-operations a {
-  margin-right: 8px;
-}
-</style>

+ 140 - 0
src/pages/index/views/table-demo/expand-row/index.vue

@@ -0,0 +1,140 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 展开行"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      ref="multipleTable"
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+    >
+      <template #id="scope">
+        <el-form label-position="left" inline class="demo-table-expand">
+          <el-form-item label="商品名称">
+            <span>{{ scope.row.name }}</span>
+          </el-form-item>
+          <el-form-item label="所属店铺">
+            <span>{{ scope.row.shop }}</span>
+          </el-form-item>
+          <el-form-item label="商品 ID">
+            <span>{{ scope.row.id }}</span>
+          </el-form-item>
+          <el-form-item label="店铺 ID">
+            <span>{{ scope.row.shopId }}</span>
+          </el-form-item>
+          <el-form-item label="商品分类">
+            <span>{{ scope.row.category }}</span>
+          </el-form-item>
+          <el-form-item label="店铺地址">
+            <span>{{ scope.row.address }}</span>
+          </el-form-item>
+          <el-form-item label="商品描述">
+            <span>{{ scope.row.desc }}</span>
+          </el-form-item>
+        </el-form>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'id',
+    type: 'expand',
+    slots: {
+      default: 'id'
+    }
+  },
+  {
+    key: 'id',
+    label: '商品ID'
+  },
+  {
+    key: 'name',
+    label: '商品名称'
+  },
+  {
+    key: 'desc',
+    label: '描述'
+  }
+]
+
+const tableData = [
+  {
+    id: '12987122',
+    name: '好滋好味鸡蛋仔',
+    category: '江浙小吃、小吃零食',
+    desc: '荷兰优质淡奶,奶香浓而不腻',
+    address: '上海市普陀区真北路',
+    shop: '王小虎夫妻店',
+    shopId: '10333'
+  }, {
+    id: '12987123',
+    name: '好滋好味鸡蛋仔',
+    category: '江浙小吃、小吃零食',
+    desc: '荷兰优质淡奶,奶香浓而不腻',
+    address: '上海市普陀区真北路',
+    shop: '王小虎夫妻店',
+    shopId: '10333'
+  }, {
+    id: '12987125',
+    name: '好滋好味鸡蛋仔',
+    category: '江浙小吃、小吃零食',
+    desc: '荷兰优质淡奶,奶香浓而不腻',
+    address: '上海市普陀区真北路',
+    shop: '王小虎夫妻店',
+    shopId: '10333'
+  }, {
+    id: '12987126',
+    name: '好滋好味鸡蛋仔',
+    category: '江浙小吃、小吃零食',
+    desc: '荷兰优质淡奶,奶香浓而不腻',
+    address: '上海市普陀区真北路',
+    shop: '王小虎夫妻店',
+    shopId: '10333'
+  }
+]
+
+export default defineComponent({
+  // name: 'ExpandRow',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    return {
+      columns,
+      tableData,
+      loading
+    }
+  }
+})
+</script>
+
+<style lang="less" scoped>
+@{deep}(.demo-table-expand) {
+  font-size: 0;
+  label {
+    width: 90px;
+    color: #99a9bf;
+  }
+  .el-form-item {
+    margin-right: 0;
+    margin-bottom: 0;
+    width: 50%;
+  }
+}
+</style>

+ 166 - 0
src/pages/index/views/table-demo/fixed-column-header/index.vue

@@ -0,0 +1,166 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定列和表头"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      border
+      height="250"
+      style="width: 820px;"
+    >
+      <template #action="scope">
+        <el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
+        <el-button type="text" size="small">编辑</el-button>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期',
+    fixed: true,
+    width: '150'
+  },
+  {
+    key: 'name',
+    label: '姓名',
+    width: '120'
+  },
+  {
+    key: 'province',
+    label: '省份',
+    width: '120'
+  },
+  {
+    key: 'city',
+    label: '市区',
+    width: '120'
+  },
+  {
+    key: 'address',
+    label: '地址',
+    width: '300'
+  },
+  {
+    key: 'zip',
+    label: '邮编',
+    width: '120'
+  },
+  {
+    key: 'action',
+    label: '操作',
+    width: '100',
+    fixed: 'right',
+    slots: {
+      default: 'action'
+    }
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1518 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-04',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1517 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-01',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1519 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-03',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1516 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1518 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-04',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1517 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-01',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1519 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-03',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1516 弄',
+    zip: 200333
+  }
+]
+
+export default defineComponent({
+  // name: 'FixedColumnHeader',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function handleClick(row: any) {
+      console.log(row)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      handleClick
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 133 - 0
src/pages/index/views/table-demo/fixed-column/index.vue

@@ -0,0 +1,133 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定列"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      border
+      style="width: 820px;"
+    >
+      <template #action="scope">
+        <el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
+        <el-button type="text" size="small">编辑</el-button>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期',
+    fixed: true,
+    width: '150'
+  },
+  {
+    key: 'name',
+    label: '姓名',
+    width: '120'
+  },
+  {
+    key: 'province',
+    label: '省份',
+    width: '120'
+  },
+  {
+    key: 'city',
+    label: '市区',
+    width: '120'
+  },
+  {
+    key: 'address',
+    label: '地址',
+    width: '300'
+  },
+  {
+    key: 'zip',
+    label: '邮编',
+    width: '120'
+  },
+  {
+    key: 'action',
+    label: '操作',
+    width: '100',
+    fixed: 'right',
+    slots: {
+      default: 'action'
+    }
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1518 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-04',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1517 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-01',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1519 弄',
+    zip: 200333
+  },
+  {
+    date: '2016-05-03',
+    name: '王小虎',
+    province: '上海',
+    city: '普陀区',
+    address: '上海市普陀区金沙江路 1516 弄',
+    zip: 200333
+  }
+]
+
+export default defineComponent({
+  // name: 'FixedColumn',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function handleClick(row: any) {
+      console.log(row)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      handleClick
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 70 - 32
src/pages/index/views/table-demo/fixed-header/index.vue

@@ -1,46 +1,78 @@
 <template>
   <div>
-    <com-table :columns="columns" :data-source="data" :scroll="{ x: 1500, y: 300 }">
-      <template #action>
-        <a>action</a>
-      </template>
-    </com-table>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定表头"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      height="250"
+      border
+    />
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent } from 'vue'
-import ComTable from '_c/Table'
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
 
 const columns = [
-  { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
-  { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
-  { title: 'Column 1', dataIndex: 'address', key: '1', width: 6000 },
-  { title: 'Column 2', dataIndex: 'address', key: '2', width: 150 },
-  { title: 'Column 3', dataIndex: 'address', key: '3', width: 150 },
-  { title: 'Column 4', dataIndex: 'address', key: '4', width: 150 },
-  { title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
-  { title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
-  { title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
-  { title: 'Column 8', dataIndex: 'address', key: '8' },
   {
-    title: 'Action',
-    key: 'operation',
-    fixed: 'right',
-    width: 100,
-    slots: { customRender: 'action' }
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
   }
 ]
 
-const data: any[] = []
-for (let i = 0; i < 100; i++) {
-  data.push({
-    key: i,
-    name: `Edrward ${i}`,
-    age: 32,
-    address: `London Park no. ${i}`
-  })
-}
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  },
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  },
+  {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
 
 export default defineComponent({
   // name: 'FixedHeader',
@@ -48,9 +80,15 @@ export default defineComponent({
     ComTable
   },
   setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
     return {
       columns,
-      data
+      tableData,
+      loading
     }
   }
 })

+ 164 - 0
src/pages/index/views/table-demo/fluid-height/index.vue

@@ -0,0 +1,164 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 流体高度"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      border
+      max-height="250"
+      style="width: 820px;"
+    >
+      <template #action="scope">
+        <el-button type="text" size="small" @click="deleteRow(scope.$index)">移除</el-button>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期',
+    fixed: true,
+    width: '150'
+  },
+  {
+    key: 'name',
+    label: '姓名',
+    width: '120'
+  },
+  {
+    key: 'province',
+    label: '省份',
+    width: '120'
+  },
+  {
+    key: 'city',
+    label: '市区',
+    width: '120'
+  },
+  {
+    key: 'address',
+    label: '地址',
+    width: '300'
+  },
+  {
+    key: 'zip',
+    label: '邮编',
+    width: '120'
+  },
+  {
+    key: 'action',
+    label: '操作',
+    width: '100',
+    fixed: 'right',
+    slots: {
+      default: 'action'
+    }
+  }
+]
+export default defineComponent({
+  // name: 'FluidHeight',
+  components: {
+    ComTable
+  },
+  setup() {
+    const tableData = ref<any[]>([
+      {
+        date: '2016-05-02',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-04',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1517 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-01',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1519 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-03',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1516 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-02',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-04',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1517 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-01',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1519 弄',
+        zip: 200333
+      },
+      {
+        date: '2016-05-03',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1516 弄',
+        zip: 200333
+      }
+    ])
+
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function deleteRow(index: number) {
+      tableData.value.splice(index, 1)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      deleteRow
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 162 - 0
src/pages/index/views/table-demo/multi-header/index.vue

@@ -0,0 +1,162 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 多级表头"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+    >
+      <template #address="scope">
+        地址是: {{ scope.row.address }}
+      </template>
+      <template #action="scope">
+        <el-button type="text" size="small" @click="deleteRow(scope.$index)">移除</el-button>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期',
+    fixed: true,
+    width: '150'
+  },
+  {
+    label: '配送信息',
+    children: [
+      {
+        key: 'name',
+        label: '姓名',
+        width: '120'
+      },
+      {
+        label: '地址',
+        children: [
+          {
+            key: 'province',
+            label: '省份',
+            width: '120'
+          },
+          {
+            key: 'city',
+            label: '市区',
+            width: '120'
+          },
+          {
+            key: 'address',
+            label: '地址',
+            slots: {
+              default: 'address'
+            }
+          },
+          {
+            key: 'zip',
+            label: '邮编',
+            width: '120'
+          }
+        ]
+      }
+    ]
+  },
+  {
+    key: 'action',
+    label: '操作',
+    width: '100',
+    slots: {
+      default: 'action'
+    }
+  }
+]
+
+export default defineComponent({
+  // name: 'MultiHeader',
+  components: {
+    ComTable
+  },
+  setup() {
+    const tableData = ref<any[]>([
+      {
+        date: '2016-05-03',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }, {
+        date: '2016-05-02',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }, {
+        date: '2016-05-04',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }, {
+        date: '2016-05-01',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }, {
+        date: '2016-05-08',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }, {
+        date: '2016-05-06',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }, {
+        date: '2016-05-07',
+        name: '王小虎',
+        province: '上海',
+        city: '普陀区',
+        address: '上海市普陀区金沙江路 1518 弄',
+        zip: 200333
+      }
+    ])
+
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function deleteRow(index: number) {
+      tableData.value.splice(index, 1)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      deleteRow
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 102 - 0
src/pages/index/views/table-demo/multiple-choice/index.vue

@@ -0,0 +1,102 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 多选"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      ref="multipleTable"
+      v-loading="loading"
+      selection
+      :columns="columns"
+      :data="tableData"
+      @selection-change="handleSelectionChange"
+    />
+
+    <div style="margin-top: 20px">
+      <el-button @click="toggleSelection([tableData[1], tableData[2]])">切换第二、第三行的选中状态</el-button>
+      <el-button @click="toggleSelection()">取消选择</el-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref, unref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'MultipleChoice',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    const multipleTable = ref<HTMLElement | null>(null)
+    function toggleSelection(rows: any[]) {
+      const multipleTableRef = unref(multipleTable as any).getTableRef()
+      if (rows) {
+        rows.forEach(row => {
+          multipleTableRef.toggleRowSelection(row)
+        })
+      } else {
+        multipleTableRef.clearSelection()
+      }
+    }
+    function handleSelectionChange(val: any) {
+      console.log(val)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      multipleTable, toggleSelection, handleSelectionChange
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 130 - 0
src/pages/index/views/table-demo/screen-table/index.vue

@@ -0,0 +1,130 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 筛选"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <el-button @click="resetDateFilter">清除日期过滤器</el-button>
+    <el-button @click="clearFilter">清除所有过滤器</el-button>
+    <com-table
+      ref="filterTable"
+      v-loading="loading"
+      row-key="date"
+      :columns="columns"
+      :data="tableData"
+      :default-sort="{prop: 'date', order: 'descending'}"
+    >
+      <template #tag="scope">
+        <el-tag
+          :type="scope.row.tag === '家' ? 'primary' : 'success'"
+          disable-transitions
+        >{{ scope.row.tag }}</el-tag>
+      </template>
+    </com-table>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref, unref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄',
+    tag: '家'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄',
+    tag: '公司'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄',
+    tag: '家'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄',
+    tag: '公司'
+  }
+]
+
+export default defineComponent({
+  // name: 'ScreenTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const filterTable = ref<HTMLElement | null>(null)
+
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    const columns = ref<any[]>([
+      {
+        key: 'date',
+        label: '日期',
+        sortable: true,
+        width: '180',
+        columnKey: 'date',
+        filters: [{ text: '2016-05-01', value: '2016-05-01' }, { text: '2016-05-02', value: '2016-05-02' }, { text: '2016-05-03', value: '2016-05-03' }, { text: '2016-05-04', value: '2016-05-04' }],
+        filterMethod: filterHandler
+      },
+      {
+        key: 'name',
+        label: '姓名',
+        sortable: true
+      },
+      {
+        key: 'address',
+        label: '地址'
+      },
+      {
+        key: 'tag',
+        label: '标签',
+        filters: [{ text: '家', value: '家' }, { text: '公司', value: '公司' }],
+        filterMethod: filterTag,
+        filterPlacement: 'bottom-end',
+        slots: {
+          default: 'tag'
+        }
+      }
+    ])
+
+    function resetDateFilter() {
+      const filterTableRef = unref(filterTable as any).getTableRef()
+      filterTableRef.clearFilter('date')
+    }
+    function clearFilter() {
+      const filterTableRef = unref(filterTable as any).getTableRef()
+      filterTableRef.clearFilter()
+    }
+    function filterTag(value: string, row: any) {
+      return row.tag === value
+    }
+    function filterHandler(value: string, row: any, column: any) {
+      const property = column['property']
+      return row[property] === value
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      filterTable,
+      resetDateFilter, clearFilter, filterTag, filterHandler
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 96 - 0
src/pages/index/views/table-demo/single-choice/index.vue

@@ -0,0 +1,96 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 单选"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      ref="singleTable"
+      v-loading="loading"
+      highlight-current-row
+      :columns="columns"
+      :data="tableData"
+      @current-change="handleCurrentChange"
+    />
+
+    <div style="margin-top: 20px">
+      <el-button @click="setCurrent(tableData[1])">选中第二行</el-button>
+      <el-button @click="setCurrent()">取消选择</el-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref, unref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'SingleChoice',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    const singleTable = ref<HTMLElement | null>(null)
+    function setCurrent(row: any) {
+      const singleTableRef = unref(singleTable as any).getTableRef()
+      singleTableRef.setCurrentRow(row)
+    }
+    function handleCurrentChange(val: any) {
+      console.log(val)
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      singleTable, setCurrent, handleCurrentChange
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 82 - 0
src/pages/index/views/table-demo/sort-table/index.vue

@@ -0,0 +1,82 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 排序"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      ref="multipleTable"
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      :default-sort="{prop: 'date', order: 'descending'}"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期',
+    sortable: true
+  },
+  {
+    key: 'name',
+    label: '姓名',
+    sortable: true
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'SortTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    return {
+      columns,
+      tableData,
+      loading
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 100 - 0
src/pages/index/views/table-demo/state-table/index.vue

@@ -0,0 +1,100 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带状态表格"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      :row-class-name="tableRowClassName"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'StateTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function tableRowClassName({ rowIndex }: any) {
+      if (rowIndex === 1) {
+        return 'warning-row'
+      } else if (rowIndex === 3) {
+        return 'success-row'
+      }
+      return ''
+    }
+
+    return {
+      columns,
+      tableData,
+      loading,
+      tableRowClassName
+    }
+  }
+})
+</script>
+
+<style lang="less" scoped>
+@{deep}(.el-table) {
+  .warning-row {
+    background: oldlace;
+  }
+}
+
+@{deep}(.el-table) {
+  .success-row {
+    background: #f0f9eb;
+  }
+}
+</style>

+ 78 - 0
src/pages/index/views/table-demo/stripe-table/index.vue

@@ -0,0 +1,78 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带斑马纹表格"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      stripe
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  }, {
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  }, {
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄'
+  }, {
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'StripeTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+    return {
+      columns,
+      tableData,
+      loading
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 0 - 87
src/pages/index/views/table-demo/table-border/index.vue

@@ -1,87 +0,0 @@
-<template>
-  <div>
-    <com-table
-      :columns="columns"
-      :data-source="data"
-      bordered
-    >
-      <template #name="{ text }">
-        <a>{{ text }}</a>
-      </template>
-      <template #title>
-        Header
-      </template>
-      <template #footer>
-        Footer
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue'
-import ComTable from '_c/Table'
-
-const columns = [
-  {
-    title: 'Name',
-    dataIndex: 'name',
-    slots: { customRender: 'name' }
-  },
-  {
-    title: 'Cash Assets',
-    className: 'column-money',
-    dataIndex: 'money'
-  },
-  {
-    title: 'Address',
-    dataIndex: 'address'
-  }
-]
-
-const data = [
-  {
-    key: '1',
-    name: 'John Brown',
-    money: '¥300,000.00',
-    address: 'New York No. 1 Lake Park'
-  },
-  {
-    key: '2',
-    name: 'Jim Green',
-    money: '¥1,256,000.00',
-    address: 'London No. 1 Lake Park'
-  },
-  {
-    key: '3',
-    name: 'Joe Black',
-    money: '¥120,000.00',
-    address: 'Sidney No. 1 Lake Park'
-  }
-]
-
-export default defineComponent({
-  // name: 'TableBorder',
-  components: {
-    ComTable
-  },
-  setup() {
-    const loading = ref<boolean>(true)
-    setTimeout(() => {
-      loading.value = false
-    }, 1000)
-    return {
-      loading,
-      columns,
-      data
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-@{deep}(th.column-money),
-@{deep}(td.column-money) {
-  text-align: right;
-}
-</style>

+ 0 - 102
src/pages/index/views/table-demo/table-ellipsis/index.vue

@@ -1,102 +0,0 @@
-<template>
-  <div>
-    <com-table
-      :loading="loading"
-      :columns="columns"
-      :data-source="data"
-    >
-      <template #name="{text}">
-        <a>{{ text }}</a>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue'
-import ComTable from '_c/Table'
-
-const columns = [
-  {
-    title: 'Name',
-    dataIndex: 'name',
-    key: 'name',
-    slots: { customRender: 'name' }
-  },
-  {
-    title: 'Age',
-    dataIndex: 'age',
-    key: 'age',
-    width: 80
-  },
-  {
-    title: 'Address',
-    dataIndex: 'address',
-    key: 'address 1',
-    ellipsis: true
-  },
-  {
-    title: 'Long Column Long Column Long Column',
-    dataIndex: 'address',
-    key: 'address 2',
-    ellipsis: true
-  },
-  {
-    title: 'Long Column Long Column',
-    dataIndex: 'address',
-    key: 'address 3',
-    ellipsis: true
-  },
-  {
-    title: 'Long Column',
-    dataIndex: 'address',
-    key: 'address 4',
-    ellipsis: true
-  }
-]
-
-const data = [
-  {
-    key: '1',
-    name: 'John Brown',
-    age: 32,
-    address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
-    tags: ['nice', 'developer']
-  },
-  {
-    key: '2',
-    name: 'Jim Green',
-    age: 42,
-    address: 'London No. 2 Lake Park, London No. 2 Lake Park',
-    tags: ['loser']
-  },
-  {
-    key: '3',
-    name: 'Joe Black',
-    age: 32,
-    address: 'Sidney No. 1 Lake Park, Sidney No. 1 Lake Park',
-    tags: ['cool', 'teacher']
-  }
-]
-
-export default defineComponent({
-  // name: 'TableEllipsis',
-  components: {
-    ComTable
-  },
-  setup() {
-    const loading = ref<boolean>(true)
-    setTimeout(() => {
-      loading.value = false
-    }, 1000)
-    return {
-      loading,
-      columns,
-      data
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 0 - 66
src/pages/index/views/table-demo/table-expanded/index.vue

@@ -1,66 +0,0 @@
-<template>
-  <div>
-    <com-table :columns="columns" :data-source="data">
-      <template #action>
-        <a>Delete</a>
-      </template>
-      <template #expandedRowRender="{ record }">
-        <p style="margin: 0">
-          {{ record.description }}
-        </p>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue'
-import ComTable from '_c/Table'
-
-const columns = [
-  { title: 'Name', dataIndex: 'name', key: 'name' },
-  { title: 'Age', dataIndex: 'age', key: 'age' },
-  { title: 'Address', dataIndex: 'address', key: 'address' },
-  { title: 'Action', dataIndex: '', key: 'x', slots: { customRender: 'action' }}
-]
-
-const data = [
-  {
-    key: 1,
-    name: 'John Brown',
-    age: 32,
-    address: 'New York No. 1 Lake Park',
-    description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'
-  },
-  {
-    key: 2,
-    name: 'Jim Green',
-    age: 42,
-    address: 'London No. 1 Lake Park',
-    description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
-  },
-  {
-    key: 3,
-    name: 'Joe Black',
-    age: 32,
-    address: 'Sidney No. 1 Lake Park',
-    description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'
-  }
-]
-
-export default defineComponent({
-  // name: 'TableExpanded',
-  components: {
-    ComTable
-  },
-  setup() {
-    return {
-      columns,
-      data
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 0 - 107
src/pages/index/views/table-demo/table-load/index.vue

@@ -1,107 +0,0 @@
-<template>
-  <div>
-    <com-table
-      :columns="columns"
-      :row-key="record => record.sid"
-      :data-source="data"
-      :pagination="pagination"
-      :loading="loading"
-      @change="handleTableChange"
-    >
-      <template #name="{ text }"> {{ text }} </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref, onMounted } from 'vue'
-import ComTable from '_c/Table'
-import api from '_p/index/api'
-
-const columns = [
-  {
-    title: 'Name',
-    dataIndex: 'name',
-    sorter: true,
-    // sortDirections: ['ascend', 'descend'],
-    width: '20%',
-    slots: { customRender: 'name' }
-  },
-  {
-    title: 'Text',
-    dataIndex: 'text',
-    filters: [
-      { text: 'Male', value: 'male' },
-      { text: 'Female', value: 'female' }
-    ],
-    width: '60%'
-  },
-  {
-    title: 'Passtime',
-    dataIndex: 'passtime'
-  }
-]
-
-export default defineComponent({
-  // name: 'TableLoad',
-  components: {
-    ComTable
-  },
-  setup() {
-    const loading = ref<boolean>(true)
-    const data = ref<any[]>([])
-    const pagination = ref<Object>({})
-
-    onMounted(() => {
-      fetch()
-    })
-
-    function handleTableChange(pagination: any, filters: any, sorter: any) {
-      console.log(sorter)
-      const pager: any = { ...pagination }
-      pager.current = pagination.current
-      pagination.value = pager
-      fetch({
-        count: pagination.pageSize,
-        page: pagination.current,
-        sortField: sorter.field,
-        sortOrder: sorter.order,
-        ...filters
-      })
-    }
-
-    async function fetch(params = {
-      page: 1,
-      count: 10
-    }) {
-      try {
-        loading.value = true
-        const res = await api.common.getList({
-          params
-        })
-        if (res) {
-          const pager: any = { ...pagination.value }
-          pager.total = 200
-          data.value = res.result
-          pagination.value = pager
-        }
-      } catch (e) {
-        console.log(e)
-      } finally {
-        loading.value = false
-      }
-    }
-
-    return {
-      loading,
-      columns,
-      data,
-      pagination,
-      handleTableChange
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 0 - 151
src/pages/index/views/table-demo/table-merge/index.vue

@@ -1,151 +0,0 @@
-<template>
-  <div>
-    <com-table
-      :columns="columns"
-      :data-source="data"
-      bordered
-    >
-      <template #name="{ text }">
-        <a>{{ text }}</a>
-      </template>
-    </com-table>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref, h } from 'vue'
-import ComTable from '_c/Table'
-
-const renderContent = ({ text, index }: any) => {
-  const obj: any = {
-    children: text,
-    props: {}
-  }
-  if (index === 4) {
-    obj.props.colSpan = 0
-  }
-  return obj
-}
-
-const data = [
-  {
-    key: '1',
-    name: 'John Brown',
-    age: 32,
-    tel: '0571-22098909',
-    phone: 18889898989,
-    address: 'New York No. 1 Lake Park'
-  },
-  {
-    key: '2',
-    name: 'Jim Green',
-    tel: '0571-22098333',
-    phone: 18889898888,
-    age: 42,
-    address: 'London No. 1 Lake Park'
-  },
-  {
-    key: '3',
-    name: 'Joe Black',
-    age: 32,
-    tel: '0575-22098909',
-    phone: 18900010002,
-    address: 'Sidney No. 1 Lake Park'
-  },
-  {
-    key: '4',
-    name: 'Jim Red',
-    age: 18,
-    tel: '0575-22098909',
-    phone: 18900010002,
-    address: 'London No. 2 Lake Park'
-  },
-  {
-    key: '5',
-    name: 'Jake White',
-    age: 18,
-    tel: '0575-22098909',
-    phone: 18900010002,
-    address: 'Dublin No. 2 Lake Park'
-  }
-]
-
-export default defineComponent({
-  // name: 'TableMerge',
-  components: {
-    ComTable
-  },
-  setup() {
-    const columns = ref<any[]>([
-      {
-        title: 'Name',
-        dataIndex: 'name',
-        customRender: ({ text, index }: any) => {
-          if (index < 4) {
-            return h('a', {
-              attrs: {
-                href: 'javascript:;'
-              }
-            }, text)
-          }
-          return {
-            children: h('a', {
-              attrs: {
-                href: 'javascript:;'
-              }
-            }, text),
-            props: {
-              colSpan: 5
-            }
-          }
-        }
-      },
-      {
-        title: 'Age',
-        dataIndex: 'age',
-        customRender: renderContent
-      },
-      {
-        title: 'Home phone',
-        colSpan: 2,
-        dataIndex: 'tel',
-        customRender: ({ text, index }: any) => {
-          const obj: any = {
-            children: text,
-            props: {}
-          }
-          if (index === 2) {
-            obj.props.rowSpan = 2
-          }
-          // These two are merged into above cell
-          if (index === 3) {
-            obj.props.rowSpan = 0
-          }
-          if (index === 4) {
-            obj.props.colSpan = 0
-          }
-          return obj
-        }
-      },
-      {
-        title: 'Phone',
-        colSpan: 0,
-        dataIndex: 'phone',
-        customRender: renderContent
-      },
-      {
-        title: 'Address',
-        dataIndex: 'address',
-        customRender: renderContent
-      }
-    ])
-    return {
-      data,
-      columns
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 0 - 124
src/pages/index/views/table-demo/table-tree/index.vue

@@ -1,124 +0,0 @@
-<template>
-  <div>
-    <com-table :columns="columns" :data-source="data" :row-selection="rowSelection" />
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue'
-import ComTable from '_c/Table'
-
-const columns = [
-  {
-    title: 'Name',
-    dataIndex: 'name',
-    key: 'name'
-  },
-  {
-    title: 'Age',
-    dataIndex: 'age',
-    key: 'age',
-    width: '12%'
-  },
-  {
-    title: 'Address',
-    dataIndex: 'address',
-    width: '30%',
-    key: 'address'
-  }
-]
-
-const data = [
-  {
-    key: 1,
-    name: 'John Brown sr.',
-    age: 60,
-    address: 'New York No. 1 Lake Park',
-    children: [
-      {
-        key: 11,
-        name: 'John Brown',
-        age: 42,
-        address: 'New York No. 2 Lake Park'
-      },
-      {
-        key: 12,
-        name: 'John Brown jr.',
-        age: 30,
-        address: 'New York No. 3 Lake Park',
-        children: [
-          {
-            key: 121,
-            name: 'Jimmy Brown',
-            age: 16,
-            address: 'New York No. 3 Lake Park'
-          }
-        ]
-      },
-      {
-        key: 13,
-        name: 'Jim Green sr.',
-        age: 72,
-        address: 'London No. 1 Lake Park',
-        children: [
-          {
-            key: 131,
-            name: 'Jim Green',
-            age: 42,
-            address: 'London No. 2 Lake Park',
-            children: [
-              {
-                key: 1311,
-                name: 'Jim Green jr.',
-                age: 25,
-                address: 'London No. 3 Lake Park'
-              },
-              {
-                key: 1312,
-                name: 'Jimmy Green sr.',
-                age: 18,
-                address: 'London No. 4 Lake Park'
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    key: 2,
-    name: 'Joe Black',
-    age: 32,
-    address: 'Sidney No. 1 Lake Park'
-  }
-]
-
-const rowSelection = {
-  onChange: (selectedRowKeys: any, selectedRows: any) => {
-    console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows)
-  },
-  onSelect: (record: any, selected: any, selectedRows: any) => {
-    console.log(record, selected, selectedRows)
-  },
-  onSelectAll: (selected: any, selectedRows: any, changeRows: any) => {
-    console.log(selected, selectedRows, changeRows)
-  }
-}
-
-export default defineComponent({
-  // name: 'TableTree',
-  components: {
-    ComTable
-  },
-  setup() {
-    return {
-      columns,
-      data,
-      rowSelection
-    }
-  }
-})
-</script>
-
-<style>
-</style>

+ 4 - 4
src/pages/index/views/table-demo/test/table.vue

@@ -10,7 +10,7 @@
           @change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
           @pressEnter="handleSearch(selectedKeys, confirm, column.dataIndex)"
         />
-        <a-button
+        <el-button
           type="primary"
           size="small"
           style="width: 90px; margin-right: 8px"
@@ -18,10 +18,10 @@
         >
           <template #icon><SearchOutlined /></template>
           Search
-        </a-button>
-        <a-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
+        </el-button>
+        <el-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
           Reset
-        </a-button>
+        </el-button>
       </div>
     </template>
     <template #filterIcon="filtered">

+ 167 - 0
src/pages/index/views/table-demo/total-table/index.vue

@@ -0,0 +1,167 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 表尾合计行"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      border
+      show-summary
+    />
+
+    <com-table
+      v-loading="loading"
+      :columns="columns1"
+      :data="tableData"
+      border
+      height="200"
+      :summary-method="getSummaries"
+      show-summary
+      style="margin-top: 20px;"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'id',
+    label: 'ID'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'amount1',
+    label: '数值1',
+    sortable: true
+  },
+  {
+    key: 'amount2',
+    label: '数值2',
+    sortable: true
+  },
+  {
+    key: 'amount3',
+    label: '数值4',
+    sortable: true
+  }
+]
+
+const columns1 = [
+  {
+    key: 'id',
+    label: 'ID'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'amount1',
+    label: '数值1(元)'
+  },
+  {
+    key: 'amount2',
+    label: '数值2(元)'
+  },
+  {
+    key: 'amount3',
+    label: '数值4(元)'
+  }
+]
+
+const tableData = [
+  {
+    id: '12987122',
+    name: '王小虎',
+    amount1: '234',
+    amount2: '3.2',
+    amount3: 10
+  }, {
+    id: '12987123',
+    name: '王小虎',
+    amount1: '165',
+    amount2: '4.43',
+    amount3: 12
+  }, {
+    id: '12987124',
+    name: '王小虎',
+    amount1: '324',
+    amount2: '1.9',
+    amount3: 9
+  }, {
+    id: '12987125',
+    name: '王小虎',
+    amount1: '621',
+    amount2: '2.2',
+    amount3: 17
+  }, {
+    id: '12987126',
+    name: '王小虎',
+    amount1: '539',
+    amount2: '4.1',
+    amount3: 15
+  }
+]
+
+export default defineComponent({
+  // name: 'TotalTable',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function getSummaries(param: any) {
+      const { columns, data } = param
+      const sums: any[] = []
+      columns.forEach((column: any, index: number) => {
+        if (index === 0) {
+          sums[index] = '总价'
+          return
+        }
+        const values = data.map((item: any) => Number(item[column.property]))
+        if (!values.every((value: number) => isNaN(value))) {
+          sums[index] = values.reduce((prev: number, curr: number) => {
+            const value = Number(curr)
+            if (!isNaN(value)) {
+              return prev + curr
+            } else {
+              return prev
+            }
+          }, 0)
+          sums[index] += ' 元'
+        } else {
+          sums[index] = 'N/A'
+        }
+      })
+
+      return sums
+    }
+
+    return {
+      columns, columns1,
+      tableData,
+      loading,
+      getSummaries
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 181 - 0
src/pages/index/views/table-demo/tree-and-load/index.vue

@@ -0,0 +1,181 @@
+<template>
+  <div>
+    <el-alert
+      effect="dark"
+      :closable="false"
+      title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 树形数据与懒加载"
+      type="info"
+      style="margin-bottom: 20px;"
+    />
+    <com-table
+      v-loading="loading"
+      :columns="columns"
+      :data="tableData"
+      row-key="id"
+      border
+      default-expand-all
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    />
+
+    <com-table
+      v-loading="loading"
+      :columns="columns1"
+      :data="tableData1"
+      row-key="id"
+      border
+      lazy
+      :load="load"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+      style="margin-top: 20px;"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import ComTable from '_c/Table/index.vue'
+
+const columns = [
+  {
+    key: 'date',
+    label: '日期',
+    sortable: true
+  },
+  {
+    key: 'name',
+    label: '姓名',
+    sortable: true
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const columns1 = [
+  {
+    key: 'date',
+    label: '日期'
+  },
+  {
+    key: 'name',
+    label: '姓名'
+  },
+  {
+    key: 'address',
+    label: '地址'
+  }
+]
+
+const tableData = [
+  {
+    id: 1,
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  },
+  {
+    id: 2,
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  },
+  {
+    id: 3,
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄',
+    children: [
+      {
+        id: 31,
+        date: '2016-05-01',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1519 弄'
+      },
+      {
+        id: 32,
+        date: '2016-05-01',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1519 弄'
+      }
+    ]
+  },
+  {
+    id: 4,
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+const tableData1 = [
+  {
+    id: 1,
+    date: '2016-05-02',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1518 弄'
+  },
+  {
+    id: 2,
+    date: '2016-05-04',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1517 弄'
+  },
+  {
+    id: 3,
+    date: '2016-05-01',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1519 弄',
+    hasChildren: true
+  },
+  {
+    id: 4,
+    date: '2016-05-03',
+    name: '王小虎',
+    address: '上海市普陀区金沙江路 1516 弄'
+  }
+]
+
+export default defineComponent({
+  // name: 'TreeAndLoad',
+  components: {
+    ComTable
+  },
+  setup() {
+    const loading = ref<boolean>(true)
+    setTimeout(() => {
+      loading.value = false
+    }, 2000)
+
+    function load(tree: any, treeNode: any, resolve: Function) {
+      setTimeout(() => {
+        resolve([
+          {
+            id: 31,
+            date: '2016-05-01',
+            name: '王小虎',
+            address: '上海市普陀区金沙江路 1519 弄'
+          }, {
+            id: 32,
+            date: '2016-05-01',
+            name: '王小虎',
+            address: '上海市普陀区金沙江路 1519 弄'
+          }
+        ])
+      }, 1000)
+    }
+
+    return {
+      columns,
+      columns1,
+      tableData,
+      tableData1,
+      loading,
+      load
+    }
+  }
+})
+</script>
+
+<style>
+</style>

+ 0 - 234
src/styles/sidebar.less

@@ -1,234 +0,0 @@
-#app {
-
-  // 主体区域 Main container
-  .main-container {
-    min-height: 100%;
-    transition: margin-left .28s;
-    margin-left: @menuWidth;
-    position: relative;
-  }
-
-  // 侧边栏 Sidebar container
-  .sidebar-container {
-    transition: width 0.28s;
-    width: @menuWidth !important;
-    height: 100%;
-    position: fixed;
-    font-size: 0px;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    z-index: 1001;
-    overflow: hidden;
-
-    //reset element-ui css
-    .horizontal-collapse-transition {
-      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
-    }
-
-    .scrollbar-wrapper {
-      overflow-x: hidden !important;
-
-      .el-scrollbar__view {
-        height: 100%;
-      }
-    }
-
-    .el-scrollbar__bar.is-vertical {
-      right: 0px;
-    }
-    
-    .el-scrollbar {
-      height: 100%;
-    }
-    
-    &.has-logo {
-      .el-scrollbar {
-        height: calc(100% - 70px);
-      }
-    }
-
-    .is-horizontal {
-      display: none;
-    }
-
-    a {
-      display: inline-block;
-      width: 100%;
-      overflow: hidden;
-    }
-
-    .svg-icon {
-      margin-right: 16px;
-    }
-
-    .el-menu {
-      border: none;
-      height: 100%;
-      width: 100% !important;
-    }
-
-    // menu hover
-    .submenu-title-noDropdown,
-    .el-submenu__title {
-      color: hsla(0,0%,100%,.7) !important;
-      &:hover {
-        // background-color: @menuHover !important;
-        color: @subMenuActiveText !important;
-      }
-    }
-    
-    .is-active>.el-submenu__title {
-      color: @subMenuActiveText !important;
-    }
-
-    .is-active {
-      color: @subMenuActiveText !important;
-      background-color: @menuActiveBg !important;
-      &:hover {
-        color: @subMenuActiveText !important;
-        background-color: @menuActiveBg !important;
-      }
-      & .el-menu-item {
-        background-color: @menuActiveBg !important;
-        &:hover {
-          color: @subMenuActiveText !important;
-        }
-      }
-    }
-
-    & .nest-menu .el-submenu>.el-submenu__title,
-    & .el-submenu .el-menu-item {
-      min-width: @menuWidth !important;
-      background-color: @subMenuBg !important;
-
-      &:hover {
-        color: @subMenuActiveText !important;
-        background-color: @subMenuHover !important;
-      }
-    }
-    
-    & .nest-menu {
-      & .is-active {
-        background-color: @menuActiveBg !important;
-        &:hover {
-          color: @subMenuActiveText !important;
-          background-color: @menuActiveBg !important;
-        }
-      }
-    }
-  }
-
-  .hideSidebar {
-    .sidebar-container {
-      width: 36px !important;
-    }
-
-    .main-container {
-      margin-left: 36px;
-    }
-
-    .submenu-title-noDropdown {
-      padding-left: 10px !important;
-      position: relative;
-
-      .el-tooltip {
-        padding: 0 10px !important;
-      }
-    }
-
-    .el-submenu {
-      overflow: hidden;
-
-      &>.el-submenu__title {
-        padding-left: 10px !important;
-
-        .el-submenu__icon-arrow {
-          display: none;
-        }
-      }
-    }
-
-    .el-menu--collapse {
-      .el-submenu {
-        &>.el-submenu__title {
-          &>span {
-            height: 0;
-            width: 0;
-            overflow: hidden;
-            visibility: hidden;
-            display: inline-block;
-          }
-        }
-      }
-    }
-  }
-
-  .el-menu--collapse .el-menu .el-submenu {
-    min-width: @menuWidth !important;
-  }
-
-  // 适配移动端, Mobile responsive
-  .mobile {
-    .main-container {
-      margin-left: 0px;
-    }
-
-    .sidebar-container {
-      transition: transform .28s;
-      width: @menuWidth !important;
-    }
-
-    &.hideSidebar {
-      .sidebar-container {
-        pointer-events: none;
-        transition-duration: 0.3s;
-        transform: translate3d(-@menuWidth, 0, 0);
-      }
-    }
-  }
-
-  .withoutAnimation {
-
-    .main-container,
-    .sidebar-container {
-      transition: none;
-    }
-  }
-}
-
-// when menu collapsed
-.el-menu--vertical {
-  &>.el-menu {
-    .svg-icon {
-      margin-right: 16px;
-    }
-  }
-
-  .nest-menu .el-submenu>.el-submenu__title,
-  .el-menu-item {
-    &:hover {
-      // you can use @subMenuHover
-      // background-color: @menuHover !important;
-    }
-  }
-
-  // the scroll bar appears when the subMenu is too long
-  >.el-menu--popup {
-    max-height: 100vh;
-    overflow-y: auto;
-
-    &::-webkit-scrollbar-track-piece {
-      background: #d3dce6;
-    }
-
-    &::-webkit-scrollbar {
-      width: 6px;
-    }
-
-    &::-webkit-scrollbar-thumb {
-      background: #99a9bf;
-      border-radius: 20px;
-    }
-  }
-}

+ 41 - 37
src/styles/sider.less

@@ -35,24 +35,6 @@
           }
         }
       }
-      
-      .is-active {
-        color: @menuActiveText !important;
-        background-color: @subMenuHover !important;
-        &>.el-submenu__title {
-          color: @menuActiveText !important;
-        }
-      }
-      
-      .nest-menu {
-        background-color: @subMenuBg !important;
-        .el-submenu>.el-submenu__title {
-          background-color: @subMenuBg !important;
-        }
-        .is-active {
-          background-color: @subMenuHover !important;
-        }
-      }
       // menu hover
       .submenu-title-noDropdown,
       .el-submenu__title {
@@ -65,6 +47,28 @@
         color: @subMenuActiveText !important;
         // background-color: @subMenuHover !important;
       }
+      .is-active {
+        color: @menuActiveText !important;
+        background-color: @subMenuHover !important;
+        &:hover {
+          color: @subMenuActiveText !important;
+          background-color: @subMenuHover !important;
+        }
+        &>.el-submenu__title {
+          color: @menuActiveText !important;
+        }
+      }
+      
+      // .nest-menu {
+      //   background-color: @subMenuBg !important;
+      //   .el-submenu>.el-submenu__title {
+      //     background-color: @subMenuBg !important;
+      //   }
+      //   .is-active {
+      //     background-color: @subMenuHover !important;
+      //   }
+      // }
+      
     }
     .el-menu--collapse {
       &>div>.el-submenu {
@@ -103,11 +107,11 @@
       }
     }
       
-    .nest-menu {
-      .is-active {
-        background-color: @subMenuHover !important;
-      }
-    }
+    // .nest-menu {
+    //   .is-active {
+    //     background-color: @subMenuHover !important;
+    //   }
+    // }
     // menu hover
     .submenu-title-noDropdown,
     .el-submenu__title {
@@ -149,15 +153,15 @@
         }
       }
       
-      .nest-menu {
-        background-color: @subMenuBg !important;
-        .el-submenu>.el-submenu__title {
-          background-color: @subMenuBg !important;
-        }
-        .is-active {
-          background-color: @subMenuHover !important;
-        }
-      }
+      // .nest-menu {
+      //   background-color: @subMenuBg !important;
+      //   .el-submenu>.el-submenu__title {
+      //     background-color: @subMenuBg !important;
+      //   }
+      //   .is-active {
+      //     background-color: @subMenuHover !important;
+      //   }
+      // }
       // menu hover
       .submenu-title-noDropdown,
       .el-submenu__title {
@@ -191,11 +195,11 @@
       }
     }
       
-    .nest-menu {
-      .is-active {
-        // background-color: @subMenuHover !important;
-      }
-    }
+    // .nest-menu {
+    //   .is-active {
+    //     // background-color: @subMenuHover !important;
+    //   }
+    // }
     // menu hover
     .submenu-title-noDropdown,
     .el-submenu__title {

+ 4 - 4
yarn.lock

@@ -3990,10 +3990,10 @@ electron-to-chromium@^1.3.621:
   resolved "https://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.622.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.622.tgz#9726bd2e67a5462154750ce9701ca6af07d07877"
   integrity sha1-lya9LmelRiFUdQzpcBymrwfQeHc=
 
-element-plus@^1.0.1-beta.8:
-  version "1.0.1-beta.8"
-  resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.1-beta.8.tgz#d64ead88cff37274262bfd9196fe4657f55149ed"
-  integrity sha512-D1u65HYMnT44U3cmll66W4mEhxLPZTqcziJtaWwdtl6VIEjrUwnrkCScnH5mVw3w/3NwRHW6XiqZCFxqafUvhw==
+element-plus@1.0.1-beta.10:
+  version "1.0.1-beta.10"
+  resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.1-beta.10.tgz#3fdc914c4a888b899d701642e13d1904ccae01f0"
+  integrity sha512-yjiU9Nnt8VyKJR6L2JoSa59W9pMX4A/Q6csXbd3OJ2ZcakalCP1iDGhAWmp6WQOkgmJFhhhyLENDd5HH1d5Zdw==
   dependencies:
     "@popperjs/core" "^2.4.4"
     async-validator "^3.4.0"