Prechádzať zdrojové kódy

style: adjust the layout

xiaoxian521 4 rokov pred
rodič
commit
14728b3ed6

+ 110 - 2
src/layout/components/setting/index.vue

@@ -23,6 +23,24 @@
         </vxe-radio-group>
       </li>
     </ul>
+
+    <el-divider>主题风格</el-divider>
+    <ul class="theme-stley">
+      <el-tooltip class="item" effect="dark" content="暗色主题" placement="bottom">
+        <li :class="dataTheme === 'dark' ? 'is-select' : ''" ref="firstTheme" @click="onDark">
+          <div></div>
+          <div></div>
+        </li>
+      </el-tooltip>
+
+      <el-tooltip class="item" effect="dark" content="亮色主题" placement="bottom">
+        <li :class="dataTheme === 'light' ? 'is-select' : ''" ref="secondTheme" @click="onLight">
+          <div></div>
+          <div></div>
+        </li>
+      </el-tooltip>
+    </ul>
+
     <el-divider />
     <vxe-button
       status="danger"
@@ -41,6 +59,8 @@ import { storageLocal } from "/@/utils/storage";
 import { toggleClass } from "/@/utils/operate";
 import { emitter } from "/@/utils/mitt";
 import { useRouter } from "vue-router";
+import { templateRef } from "@vueuse/core";
+let isSelect = "is-select";
 
 export default {
   name: "setting",
@@ -120,6 +140,31 @@ export default {
       emitter.emit("tagViewsShowModel", label);
     }
 
+    const firstTheme = templateRef<HTMLElement | null>("firstTheme", null);
+    const secondTheme = templateRef<HTMLElement | null>("secondTheme", null);
+
+    const dataTheme = ref(storageLocal.getItem("data-theme") || "dark");
+    if (dataTheme) {
+      storageLocal.setItem("data-theme", unref(dataTheme));
+      window.document.body.setAttribute("data-theme", unref(dataTheme));
+    }
+
+    // dark主题
+    function onDark() {
+      storageLocal.setItem("data-theme", "dark");
+      window.document.body.setAttribute("data-theme", "dark");
+      toggleClass(true, isSelect, unref(firstTheme));
+      toggleClass(false, isSelect, unref(secondTheme));
+    }
+
+    // light主题
+    function onLight() {
+      storageLocal.setItem("data-theme", "light");
+      window.document.body.setAttribute("data-theme", "light");
+      toggleClass(false, isSelect, unref(firstTheme));
+      toggleClass(true, isSelect, unref(secondTheme));
+    }
+
     return {
       ...toRefs(settings),
       localOperate,
@@ -128,7 +173,10 @@ export default {
       tagsChange,
       onReset,
       markValue,
-      onChange
+      onChange,
+      onDark,
+      onLight,
+      dataTheme
     };
   }
 };
@@ -141,11 +189,71 @@ export default {
     display: flex;
     justify-content: space-between;
     align-items: center;
-    margin: 16px;
+    margin: 25px;
   }
 }
 :deep(.el-divider__text) {
   font-size: 16px;
   font-weight: 700;
 }
+.theme-stley {
+  margin-top: 25px;
+  width: 100%;
+  height: 60px;
+  display: flex;
+  justify-content: space-around;
+  li {
+    width: 30%;
+    height: 100%;
+    background: #f0f2f5;
+    position: relative;
+    overflow: hidden;
+    cursor: pointer;
+    background-color: #f0f2f5;
+    border-radius: 4px;
+    box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
+    &:nth-child(1) {
+      div {
+        &:nth-child(1) {
+          width: 30%;
+          height: 100%;
+          background: #1b2a47;
+        }
+        &:nth-child(2) {
+          width: 70%;
+          height: 30%;
+          top: 0;
+          right: 0;
+          background-color: #fff;
+          box-shadow: 0 0 1px #888888;
+          position: absolute;
+        }
+      }
+    }
+
+    &:nth-child(2) {
+      div {
+        &:nth-child(1) {
+          width: 30%;
+          height: 100%;
+          box-shadow: 0 0 1px #888888;
+          background-color: #fff;
+          border-radius: 4px 0 0 4px;
+        }
+        &:nth-child(2) {
+          width: 70%;
+          height: 30%;
+          top: 0;
+          right: 0;
+          background-color: #fff;
+          box-shadow: 0 0 1px #888888;
+          position: absolute;
+        }
+      }
+    }
+  }
+}
+.is-select {
+  border: 2px solid #0960bd;
+}
 </style>

+ 0 - 3
src/layout/components/sidebar/index.vue

@@ -3,10 +3,7 @@
     <el-menu
       :default-active="activeMenu"
       :collapse="isCollapse"
-      background-color="#fff"
       unique-opened
-      text-color="#000"
-      active-text-color="#409eff"
       :collapse-transition="false"
       mode="vertical"
       @select="menuSelect"

+ 1 - 1
src/layout/components/tag/index.vue

@@ -164,7 +164,7 @@ export default {
     // 初始化页面刷新保证当前路由tabview存在
     let stop = watchEffect(() => {
       let parentPath = route.path.slice(0, route.path.lastIndexOf("/"));
-      dynamicRouteTags(route.path, parentPath);
+      dynamicRouteTags(route.path, parentPath, route);
     });
 
     setTimeout(() => {

+ 1 - 1
src/layout/components/tag/tagsHook.ts

@@ -90,7 +90,7 @@ export function useDynamicRoutesHook() {
    * @param value any 当前删除tag路由
    * @param current objct 当前激活路由对象
    */
-  const deleteDynamicTag = async (obj: any, current: object): Promise<any> => {
+  const deleteDynamicTag = async (obj: any, current: any): Promise<any> => {
     let valueIndex: number = dynamic.dRoutes.findIndex((item: any) => {
       return item.path === obj.path;
     });

+ 1 - 0
src/layout/index.vue

@@ -48,6 +48,7 @@ import { toggleClass, removeClass } from "/@/utils/operate";
 let hiddenMainContainer = "hidden-main-container";
 import options from "/@/settings";
 import { useRouter, useRoute } from "vue-router";
+import { storageLocal } from "/@/utils/storage";
 
 interface setInter {
   sidebar: any;

+ 6 - 0
src/plugins/element-plus/index.ts

@@ -23,6 +23,9 @@ import {
   ElForm,
   ElFormItem,
   ElLoading,
+  ElPopover,
+  ElPopper,
+  ElTooltip,
 } from "element-plus";
 
 const components = [
@@ -48,6 +51,9 @@ const components = [
   ElInput,
   ElForm,
   ElFormItem,
+  ElPopover,
+  ElPopper,
+  ElTooltip,
 ];
 
 const plugins = [ElLoading];

+ 10 - 2
src/style/element-ui.scss

@@ -15,7 +15,6 @@
   display: none;
 }
 
-
 .el-dialog {
   transform: none;
   left: 0;
@@ -38,7 +37,7 @@
 // dropdown
 .el-dropdown-menu {
   a {
-    display: block
+    display: block;
   }
 }
 
@@ -46,3 +45,12 @@
 .el-range-separator {
   box-sizing: content-box;
 }
+
+.el-loading-mask {
+  z-index: -1;
+}
+
+// el-tooltip,的权重
+.is-dark {
+  z-index: 99999 !important;
+}

+ 0 - 5
src/style/index.scss

@@ -1,4 +1,3 @@
-@import "./variables.scss";
 @import "./mixin.scss";
 @import "./transition.scss";
 @import "./element-ui.scss";
@@ -123,10 +122,6 @@ ul {
   -o-filter: invert(80%);
 }
 
-.el-loading-mask {
-  z-index: -1;
-}
-
 .pc-spacing {
   margin: 10px;
 }

+ 304 - 27
src/style/sidebar.scss

@@ -1,4 +1,19 @@
-#app {
+// 暗色主题
+body[data-theme="dark"] {
+  $menuText: #7a80b4;
+  $menuActiveText: #7a80b4;
+  $subMenuActiveText: #f4f4f5;
+  $sideBarWidth: 210px;
+
+  //菜单背景
+  $menuBg: #1b2a47;
+  // 鼠标覆盖菜单时的背景
+  $menuHover: #2a395b;
+  // 子菜单背景
+  $subMenuBg: #1f2d3d;
+  // 鼠标覆盖子菜单时的背景
+  $subMenuHover: #001528;
+
   .main-container {
     min-height: 100%;
     transition: margin-left 0.28s;
@@ -61,16 +76,33 @@
       // width: 100% !important;
     }
 
+    .el-menu-item,
+    .el-submenu__title {
+      color: $menuText;
+    }
+
+    .el-menu {
+      background-color: transparent;
+    }
+
     // menu hover
     .submenu-title-noDropdown,
     .el-submenu__title {
       &:hover {
         background-color: $menuHover !important;
       }
+      background: $menuBg;
     }
 
     .is-active > .el-submenu__title,
-    .is-active > .el-submenu__title i {
+    .is-active.submenu-title-noDropdown {
+      color: $subMenuActiveText !important;
+      i {
+        color: $subMenuActiveText !important;
+      }
+    }
+
+    .is-active {
       transition: color 0.3s;
       color: $subMenuActiveText !important;
     }
@@ -130,6 +162,51 @@
     }
   }
 
+  // 菜单折叠
+  .el-menu--vertical {
+    .el-menu--popup {
+      background-color: $subMenuBg !important;
+      .el-menu-item {
+        color: $menuText;
+        background-color: $subMenuBg;
+        &:hover {
+          background-color: $subMenuHover;
+        }
+      }
+    }
+    & > .el-menu {
+      i {
+        margin-right: 16px;
+      }
+    }
+
+    .is-active > .el-submenu__title,
+    .is-active.submenu-title-noDropdown {
+      color: $subMenuActiveText !important;
+      i {
+        color: $subMenuActiveText !important;
+      }
+    }
+
+    .is-active {
+      transition: color 0.3s;
+      color: $subMenuActiveText !important;
+    }
+
+    .nest-menu .el-submenu > .el-submenu__title,
+    .el-menu-item {
+      &:hover {
+        // you can use $subMenuHover
+        background-color: $menuHover !important;
+      }
+    }
+  }
+
+  .el-scrollbar__wrap {
+    overflow: auto;
+    height: 100%;
+  }
+
   .el-menu--collapse .el-menu .el-submenu {
     min-width: $sideBarWidth !important;
   }
@@ -162,43 +239,243 @@
   }
 }
 
-// when menu collapsed
-.el-menu--vertical {
-  & > .el-menu {
-    i {
-      margin-right: 16px;
+// 亮色主题
+body[data-theme="light"] {
+  $menuText: #7a80b4;
+  $menuActiveText: #7a80b4;
+  $subMenuActiveText: #409eff;
+  $sideBarWidth: 210px;
+
+  //菜单背景
+  $menuBg: #fff;
+  // 鼠标覆盖菜单时的背景
+  $menuHover: #e0ebf6;
+  // 子菜单背景
+  $subMenuBg: #fff;
+  // 鼠标覆盖子菜单时的背景
+  $subMenuHover: #e0ebf6;
+
+  .main-container {
+    min-height: 100%;
+    transition: margin-left 0.28s;
+    margin-left: $sideBarWidth;
+    position: relative;
+  }
+
+  .sidebar-container {
+    transition: width 0.28s;
+    width: $sideBarWidth !important;
+    background-color: $menuBg;
+    height: 100%;
+    position: fixed;
+    font-size: 0px;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 1001;
+    overflow: hidden;
+    box-shadow: 0 0 1px #888888;
+
+    // reset element-plus 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__bar.is-vertical {
+      right: 0px;
+    }
+
+    .el-scrollbar {
+      height: 100%;
+    }
+
+    &.has-logo {
+      .el-scrollbar {
+        height: calc(100% - 50px);
+      }
+    }
+
+    .is-horizontal {
+      display: none;
+    }
+
+    a {
+      display: inline-block;
+      width: 100%;
+      overflow: hidden;
+    }
+
+    .el-menu {
+      border: none;
+      height: 100%;
+      // background-color: $menuBg !important;
+      // width: 100% !important;
+    }
+
+    .el-menu-item,
+    .el-submenu__title {
+      color: $menuText;
+    }
+
+    .el-menu {
+      background-color: transparent;
+    }
+
+    // menu hover
+    .submenu-title-noDropdown,
+    .el-submenu__title {
+      &:hover {
+        background-color: $menuHover !important;
+      }
+      background: $menuBg;
+    }
+
+    .is-active > .el-submenu__title,
+    .is-active.submenu-title-noDropdown {
+      color: $subMenuActiveText !important;
+      i {
+        color: $subMenuActiveText !important;
+      }
+    }
+
+    .is-active {
+      transition: color 0.3s;
+      color: $subMenuActiveText !important;
+    }
+
+    & .nest-menu .el-submenu > .el-submenu__title,
+    & .el-submenu .el-menu-item {
+      font-size: 12px;
+      min-width: $sideBarWidth !important;
+      background-color: $subMenuBg !important;
+
+      &:hover {
+        background-color: $subMenuHover !important;
+      }
+    }
+  }
+
+  .hideSidebar {
+    .sidebar-container {
+      width: 54px !important;
+    }
+
+    .main-container {
+      margin-left: 54px;
+    }
+
+    .submenu-title-noDropdown {
+      padding: 0 !important;
+      position: relative;
+
+      .el-tooltip {
+        padding: 0 !important;
+      }
+    }
+
+    .el-submenu {
+      overflow: hidden;
+      & > .el-submenu__title {
+        .el-submenu__icon-arrow {
+          display: none;
+        }
+      }
+    }
+
+    .el-menu--collapse {
+      margin-left: -5px; //需优化的地方
+      .el-submenu {
+        & > .el-submenu__title {
+          & > span {
+            height: 0;
+            width: 0;
+            overflow: hidden;
+            visibility: hidden;
+            display: inline-block;
+          }
+        }
+      }
     }
   }
 
-  .nest-menu .el-submenu > .el-submenu__title,
-  .el-menu-item {
-    &:hover {
-      // you can use $subMenuHover
-      background-color: $menuHover !important;
+  // 菜单折叠
+  .el-menu--vertical {
+    .el-menu--popup {
+      background-color: $subMenuBg !important;
+      .el-menu-item {
+        color: $menuText;
+        background-color: $subMenuBg;
+        &:hover {
+          background-color: $subMenuHover;
+        }
+      }
+    }
+    & > .el-menu {
+      i {
+        margin-right: 16px;
+      }
+    }
+
+    .is-active > .el-submenu__title,
+    .is-active.submenu-title-noDropdown {
+      color: $subMenuActiveText !important;
+      i {
+        color: $subMenuActiveText !important;
+      }
+    }
+
+    .is-active {
+      transition: color 0.3s;
+      color: $subMenuActiveText !important;
     }
+
+    .nest-menu .el-submenu > .el-submenu__title,
+    .el-menu-item {
+      &:hover {
+        // you can use $subMenuHover
+        background-color: $menuHover !important;
+      }
+    }
+  }
+
+  .el-scrollbar__wrap {
+    overflow: auto;
+    height: 100%;
   }
 
-  // the scroll bar appears when the subMenu is too long
-  > .el-menu--popup {
-    max-height: 100vh;
-    overflow-y: auto;
+  .el-menu--collapse .el-menu .el-submenu {
+    min-width: $sideBarWidth !important;
+  }
 
-    &::-webkit-scrollbar-track-piece {
-      background: #d3dce6;
+  // mobile responsive
+  .mobile {
+    .main-container {
+      margin-left: 0px;
     }
 
-    &::-webkit-scrollbar {
-      width: 6px;
+    .sidebar-container {
+      transition: transform 0.28s;
+      width: $sideBarWidth !important;
     }
 
-    &::-webkit-scrollbar-thumb {
-      background: #99a9bf;
-      border-radius: 20px;
+    &.hideSidebar {
+      .sidebar-container {
+        pointer-events: none;
+        transition-duration: 0.3s;
+        transform: translate3d(-$sideBarWidth, 0, 0);
+      }
     }
   }
-}
 
-.el-scrollbar__wrap {
-  overflow: auto;
-  height: 100%;
+  .withoutAnimation {
+    .main-container,
+    .sidebar-container {
+      transition: none;
+    }
+  }
 }

+ 0 - 39
src/style/variables.scss

@@ -1,39 +0,0 @@
-// sidebar
-$menuText: #7a80b4;
-$menuActiveText: #7a80b4;
-$subMenuActiveText: #409eff;
-
-// dark样式
-//菜单背景
-// $menuBg: #1b2a47;
-// // 鼠标覆盖菜单时的背景
-// $menuHover: #2a395b;
-
-// 子菜单背景
-// $subMenuBg: #1f2d3d;
-// // 鼠标覆盖子菜单时的背景
-// $subMenuHover: #001528;
-
-// night样式
-//菜单背景
-$menuBg: #fff;
-// 鼠标覆盖菜单时的背景
-$menuHover: #e0ebf6;
-
-// 子菜单背景
-$subMenuBg: #fff;
-// 鼠标覆盖子菜单时的背景
-$subMenuHover: #e0ebf6;
-
-$sideBarWidth: 210px;
-
-:export {
-  menuText: $menuText;
-  menuActiveText: $menuActiveText;
-  subMenuActiveText: $subMenuActiveText;
-  menuBg: $menuBg;
-  menuHover: $menuHover;
-  subMenuBg: $subMenuBg;
-  subMenuHover: $subMenuHover;
-  sideBarWidth: $sideBarWidth;
-}

+ 25 - 17
src/utils/operate/index.ts

@@ -1,30 +1,38 @@
 export const hasClass = (ele: Element, cls: string): any => {
-  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
-}
+  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
+};
 
 export const addClass = (ele: Element, cls: string, extracls?: string): any => {
-  if (!hasClass(ele, cls)) ele.className += (' ' + cls)
+  if (!hasClass(ele, cls)) ele.className += " " + cls;
   if (extracls) {
-    if (!hasClass(ele, extracls)) ele.className += ' ' + extracls
+    if (!hasClass(ele, extracls)) ele.className += " " + extracls;
   }
-}
+};
 
-export const removeClass = (ele: Element, cls: string, extracls?: string): any => {
+export const removeClass = (
+  ele: Element,
+  cls: string,
+  extracls?: string
+): any => {
   if (hasClass(ele, cls)) {
-    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
-    ele.className = ele.className.replace(reg, ' ').trim()
+    const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
+    ele.className = ele.className.replace(reg, " ").trim();
   }
   if (extracls) {
     if (hasClass(ele, extracls)) {
-      const regs = new RegExp('(\\s|^)' + extracls + '(\\s|$)')
-      ele.className = ele.className.replace(regs, ' ').trim()
+      const regs = new RegExp("(\\s|^)" + extracls + "(\\s|$)");
+      ele.className = ele.className.replace(regs, " ").trim();
     }
   }
-}
+};
 
-export const toggleClass = (flag: boolean, clsName: string, target?: HTMLElement): any => {
-  const targetEl = target || document.body
-  let { className } = targetEl
-  className = className.replace(clsName, "")
-  targetEl.className = flag ? `${className} ${clsName} ` : className
-}
+export const toggleClass = (
+  flag: boolean,
+  clsName: string,
+  target?: HTMLElement
+): any => {
+  const targetEl = target || document.body;
+  let { className } = targetEl;
+  className = className.replace(clsName, "");
+  targetEl.className = flag ? `${className} ${clsName} ` : className;
+};