RuoYi
2024-12-04 e212a0ab75e1c59d0d030ac0b2f07048f6a0f9cf
支持开启暗黑模式
已修改13个文件
已删除1个文件
已添加2个文件
665 ■■■■■ 文件已修改
src/assets/icons/svg/moon.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/sunny.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/ruoyi.scss 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/sidebar.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/variables.module.scss 235 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Hamburger/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TopNav/index.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TreeSelect/index.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Settings/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Logo.vue 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/index.vue 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/index.vue 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/settings.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/moon.svg
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1733303018722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M368.832 67.2c51.328-16.384 89.216 34.112 75.712 76.416a346.816 346.816 0 0 0 435.84 435.84c42.304-13.44 92.8 24.384 76.48 75.712A467.968 467.968 0 1 1 368.832 67.2z m-35.776 122.688a368.832 368.832 0 1 0 501.056 501.056 445.952 445.952 0 0 1-501.056-501.056z" p-id="1448"></path></svg>
src/assets/icons/svg/sunny.svg
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1733303115132" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12397" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 890.432c18.432 0 33.408 14.976 33.408 33.408v66.752a33.408 33.408 0 0 1-66.816 0v-66.752c0-18.432 14.976-33.408 33.408-33.408z m-267.52-110.848a33.408 33.408 0 0 1 0 47.232l-47.296 47.232a33.408 33.408 0 0 1-47.232-47.232l47.232-47.232a33.408 33.408 0 0 1 47.232 0z m582.336 0l47.232 47.232a33.408 33.408 0 0 1-47.232 47.232l-47.232-47.232a33.408 33.408 0 1 1 47.232-47.232zM512 200.32a311.68 311.68 0 1 1 0 623.296 311.68 311.68 0 0 1 0-623.36z m0 66.752a244.864 244.864 0 1 0 0 489.728 244.864 244.864 0 0 0 0-489.728zM100.16 478.592a33.408 33.408 0 1 1 0 66.816H33.408a33.408 33.408 0 0 1 0-66.816h66.752z m890.432 0a33.408 33.408 0 0 1 0 66.816h-66.752a33.408 33.408 0 1 1 0-66.816h66.752zM197.184 149.952l47.232 47.232a33.408 33.408 0 1 1-47.232 47.232l-47.232-47.232a33.408 33.408 0 0 1 47.232-47.232z m676.864 0a33.408 33.408 0 0 1 0 47.232l-47.232 47.232a33.408 33.408 0 1 1-47.232-47.232l47.232-47.232a33.408 33.408 0 0 1 47.232 0zM512 0c18.432 0 33.408 14.976 33.408 33.408v66.752a33.408 33.408 0 1 1-66.816 0V33.408C478.592 14.976 493.568 0 512 0z" p-id="12398"></path></svg>
src/assets/styles/ruoyi.scss
@@ -1,4 +1,4 @@
 /**
/**
 * é€šç”¨css样式布局处理
 * Copyright (c) 2019 ruoyi
 */
@@ -102,38 +102,53 @@
/** è¡¨æ ¼å¸ƒå±€ **/
.pagination-container {
    position: relative;
    height: 32px;
    margin-bottom: 10px;
    margin-top: 15px;
    padding: 10px 20px !important;
  position: relative;
  height: 25px;
  margin-bottom: 10px;
  margin-top: 15px;
  padding: 10px 20px !important;
  background-color: transparent !important;
}
/* åˆ†é¡µå™¨å®šä½ */
.pagination-container .el-pagination {
  position: absolute;
  right: 0;
  top: 0;
}
/* å¼¹çª—中的分页器 */
.el-dialog .pagination-container {
    position: static !important;
  position: static !important;
  margin: 10px 0 0 0;
  padding: 0 !important;
  .el-pagination {
    position: static;
  }
}
/* ç§»åŠ¨ç«¯é€‚é… */
@media (max-width: 768px) {
  .pagination-container {
    .el-pagination {
      > .el-pagination__jump {
        display: none !important;
      }
      > .el-pagination__sizes {
        display: none !important;
      }
    }
  }
}
/* tree border */
.tree-border {
    margin-top: 5px;
    border: 1px solid #e5e6e7;
    background: #FFFFFF none;
    border: 1px solid var(--el-border-color-light, #e5e6e7);
    background: var(--el-bg-color, #FFFFFF) none;
    border-radius:4px;
    width: 100%;
}
.pagination-container .el-pagination {
    right: 0;
    position: absolute;
}
@media ( max-width : 768px) {
  .pagination-container .el-pagination > .el-pagination__jump {
    display: none !important;
  }
  .pagination-container .el-pagination > .el-pagination__sizes {
    display: none !important;
  }
}
.el-table .fixed-width .el-button--small {
@@ -282,6 +297,5 @@
/* åˆ†å‰²é¢æ¿æ ·å¼ */
.splitpanes.default-theme .splitpanes__pane {
    background-color: #fff!important;
  background-color: var(--splitpanes-default-bg) !important;
}
src/assets/styles/sidebar.scss
@@ -1,7 +1,7 @@
#app {
  .main-container {
    height: 100%;
    min-height: 100%;
    transition: margin-left .28s;
    margin-left: $base-sidebar-width;
    position: relative;
@@ -12,10 +12,8 @@
  }
  .sidebar-container {
    -webkit-transition: width .28s;
    transition: width 0.28s;
    width: $base-sidebar-width !important;
    background-color: $base-menu-background;
    height: 100%;
    position: fixed;
    font-size: 0px;
@@ -103,7 +101,7 @@
    & .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
    & .theme-dark .el-sub-menu .el-menu-item {
      background-color: $base-sub-menu-background !important;
      background-color: $base-sub-menu-background;
      &:hover {
        background-color: $base-sub-menu-hover !important;
src/assets/styles/variables.module.scss
@@ -8,58 +8,211 @@
$yellow: #FEC171;
$panGreen: #30B08F;
// é»˜è®¤èœå•主题风格
// é»˜è®¤ä¸»é¢˜å˜é‡
$menuText: #bfcbd9;
$menuActiveText: #409eff;
$menuBg: #304156;
$menuHover: #263445;
// æµ…色主题theme-light
$menuLightBg: #ffffff;
$menuLightHover: #f0f1f5;
$menuLightText: #303133;
$menuLightActiveText: #409EFF;
// åŸºç¡€å˜é‡
$base-sidebar-width: 200px;
$sideBarWidth: 200px;
// èœå•暗色变量
$base-menu-color: #bfcbd9;
$base-menu-color-active: #f4f4f5;
$base-menu-background: #304156;
$base-logo-title-color: #ffffff;
$base-menu-light-color: rgba(0, 0, 0, 0.7);
$base-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background: #1f2d3d;
$base-sub-menu-hover: #001528;
// è‡ªå®šä¹‰æš—色菜单风格
/**
$base-menu-color:hsla(0,0%,100%,.65);
$base-menu-color-active:#fff;
$base-menu-background:#001529;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
// ç»„件变量
$--color-primary: #409EFF;
$--color-success: #67C23A;
$--color-warning: #E6A23C;
$--color-danger: #F56C6C;
$--color-info: #909399;
$base-sidebar-width: 200px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
  menuColor: $base-menu-color;
  menuLightColor: $base-menu-light-color;
  menuColorActive: $base-menu-color-active;
  menuBackground: $base-menu-background;
  menuLightBackground: $base-menu-light-background;
  subMenuBackground: $base-sub-menu-background;
  subMenuHover: $base-sub-menu-hover;
  sideBarWidth: $base-sidebar-width;
  logoTitleColor: $base-logo-title-color;
  logoLightTitleColor: $base-logo-light-title-color;
  primaryColor: $--color-primary;
  successColor: $--color-success;
  dangerColor: $--color-danger;
  infoColor: $--color-info;
  warningColor: $--color-warning;
  menuText: $menuText;
  menuActiveText: $menuActiveText;
  menuBg: $menuBg;
  menuHover: $menuHover;
  menuLightBg: $menuLightBg;
  menuLightHover: $menuLightHover;
  menuLightText: $menuLightText;
  menuLightActiveText: $menuLightActiveText;
  sideBarWidth: $sideBarWidth;
  // å¯¼å‡ºåŸºç¡€é¢œè‰²
  blue: $blue;
  lightBlue: $light-blue;
  red: $red;
  pink: $pink;
  green: $green;
  tiffany: $tiffany;
  yellow: $yellow;
  panGreen: $panGreen;
  // å¯¼å‡ºç»„件颜色
  colorPrimary: $--color-primary;
  colorSuccess: $--color-success;
  colorWarning: $--color-warning;
  colorDanger: $--color-danger;
  colorInfo: $--color-info;
}
// CSS变量定义
:root {
  /* äº®è‰²æ¨¡å¼å˜é‡ */
  --sidebar-bg: #{$menuBg};
  --sidebar-text: #{$menuText};
  --menu-hover: #{$menuHover};
  --navbar-bg: #ffffff;
  --navbar-text: #303133;
  /* splitpanes default-theme å˜é‡ */
  --splitpanes-default-bg: #ffffff;
}
// æš—黑模式变量
html.dark {
  /* é»˜è®¤é€šç”¨ */
  --el-bg-color: #141414;
  --el-bg-color-overlay: #1d1e1f;
  --el-text-color-primary: #ffffff;
  --el-text-color-regular: #d0d0d0;
  --el-border-color: #434343;
  --el-border-color-light: #434343;
  /* ä¾§è¾¹æ  */
  --sidebar-bg: #141414;
  --sidebar-text: #ffffff;
  --menu-hover: #2d2d2d;
  --menu-active-text: #{$menuActiveText};
  /* é¡¶éƒ¨å¯¼èˆªæ  */
  --navbar-bg: #141414;
  --navbar-text: #ffffff;
  --navbar-hover: #141414;
  /* æ ‡ç­¾æ  */
  --tags-bg: #141414;
  --tags-item-bg: #1d1e1f;
  --tags-item-border: #303030;
  --tags-item-text: #d0d0d0;
  --tags-item-hover: #2d2d2d;
  --tags-close-hover: #64666a;
  /* splitpanes ç»„件暗黑模式变量 */
  --splitpanes-bg: #141414;
  --splitpanes-border: #303030;
  --splitpanes-splitter-bg: #1d1e1f;
  --splitpanes-splitter-hover-bg: #2d2d2d;
  /* blockquote æš—黑模式变量 */
  --blockquote-bg: #1d1e1f;
  --blockquote-border: #303030;
  --blockquote-text: #d0d0d0;
  /* Cron æ—¶é—´è¡¨è¾¾å¼ æ¨¡å¼å˜é‡ */
  --cron-border: #303030;
  /* splitpanes default-theme æš—黑模式变量 */
  --splitpanes-default-bg: #141414;
  /* ä¾§è¾¹æ èœå•覆盖 */
   .sidebar-container {
    & .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
    & .theme-dark .el-sub-menu .el-menu-item {
      background-color: var(--el-bg-color) !important;
    }
  }
  /* é¡¶éƒ¨æ æ èœå•覆盖 */
  .el-menu--horizontal {
    .el-menu-item {
      &:not(.is-disabled) {
        &:hover,
        &:focus {
          background-color: var(--navbar-hover) !important;
        }
      }
    }
  }
  /* åˆ†å‰²çª—格覆盖 */
  .splitpanes {
    background-color: var(--splitpanes-bg);
    .splitpanes__pane {
      background-color: var(--splitpanes-bg);
      border-color: var(--splitpanes-border);
    }
    .splitpanes__splitter {
      background-color: var(--splitpanes-splitter-bg);
      border-color: var(--splitpanes-border);
      &:hover {
        background-color: var(--splitpanes-splitter-hover-bg);
      }
      &:before,
      &:after {
        background-color: var(--splitpanes-border);
      }
    }
  }
  /* è¡¨æ ¼æ ·å¼è¦†ç›– */
  .el-table {
    --el-table-header-bg-color: var(--el-bg-color-overlay) !important;
    --el-table-header-text-color: var(--el-text-color-regular) !important;
    --el-table-border-color: var(--el-border-color-light) !important;
    --el-table-row-hover-bg-color: var(--el-bg-color-overlay) !important;
    .el-table__header-wrapper, .el-table__fixed-header-wrapper {
      th {
        background-color: var(--el-bg-color-overlay, #f8f8f9) !important;
        color: var(--el-text-color-regular, #515a6e);
      }
    }
  }
  /* æ ‘组件高亮样式覆盖 */
  .el-tree {
    .el-tree-node.is-current > .el-tree-node__content {
      background-color: var(--el-bg-color-overlay) !important;
      color: var(--el-color-primary);
    }
    .el-tree-node__content:hover {
      background-color: var(--el-bg-color-overlay);
    }
  }
  /* ä¸‹æ‹‰èœå•样式覆盖 */
  .el-dropdown-menu__item:not(.is-disabled):focus, .el-dropdown-menu__item:not(.is-disabled):hover{
    background-color: var(--navbar-hover) !important;
  }
  /* blockquote样式覆盖 */
  blockquote {
    background-color: var(--blockquote-bg) !important;
    border-left-color: var(--blockquote-border) !important;
    color: var(--blockquote-text) !important;
  }
  /* æ—¶é—´è¡¨è¾¾å¼æ ‡é¢˜æ ·å¼è¦†ç›– */
  .popup-result .title {
    background: var(--cron-border);
  }
}
src/components/Crontab/index.vue
@@ -251,7 +251,6 @@
.popup-main {
    position: relative;
    margin: 10px auto;
    background: #fff;
    border-radius: 5px;
    font-size: 12px;
    overflow: hidden;
src/components/Hamburger/index.vue
@@ -7,6 +7,7 @@
      xmlns="http://www.w3.org/2000/svg"
      width="64"
      height="64"
      fill="currentColor"
    >
      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
    </svg>
src/components/TopNav/index.vue
@@ -196,7 +196,7 @@
/* èƒŒæ™¯è‰²éšè— */
.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
  background-color: #ffffff !important;
  background-color: #ffffff;
}
/* å›¾æ ‡å³é—´è· */
@@ -211,4 +211,6 @@
  margin-left: 8px;
  margin-top: 0px;
}
</style>
src/components/TreeSelect/index.vue
ÎļþÒÑɾ³ý
src/layout/components/Navbar.vue
@@ -18,6 +18,13 @@
        <screenfull id="screenfull" class="right-menu-item hover-effect" />
        <el-tooltip content="主题模式" effect="dark" placement="bottom">
          <div class="right-menu-item hover-effect theme-switch-wrapper" @click="toggleTheme">
            <svg-icon v-if="settingsStore.isDark" icon-class="sunny" />
            <svg-icon v-if="!settingsStore.isDark" icon-class="moon" />
          </div>
        </el-tooltip>
        <el-tooltip content="布局大小" effect="dark" placement="bottom">
          <size-select id="size-select" class="right-menu-item hover-effect" />
        </el-tooltip>
@@ -98,6 +105,10 @@
function setLayout() {
  emits('setLayout');
}
function toggleTheme() {
  settingsStore.toggleTheme()
}
</script>
<style lang='scss' scoped>
@@ -105,7 +116,7 @@
  height: 50px;
  overflow: hidden;
  position: relative;
  background: #fff;
  background: var(--navbar-bg);
  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
  .hamburger-container {
@@ -150,7 +161,7 @@
      padding: 0 8px;
      height: 100%;
      font-size: 18px;
      color: #5a5e66;
      color: var(--navbar-text);
      vertical-align: text-bottom;
      &.hover-effect {
@@ -161,6 +172,19 @@
          background: rgba(0, 0, 0, 0.025);
        }
      }
      &.theme-switch-wrapper {
        display: flex;
        align-items: center;
        svg {
          transition: transform 0.3s;
          &:hover {
            transform: scale(1.15);
          }
        }
      }
    }
    .avatar-container {
src/layout/components/Settings/index.vue
@@ -149,13 +149,15 @@
<style lang='scss' scoped>
.setting-drawer-title {
  margin-bottom: 12px;
  color: rgba(0, 0, 0, 0.85);
  color: var(--el-text-color-primary, rgba(0, 0, 0, 0.85));
  line-height: 22px;
  font-weight: bold;
  .drawer-title {
    font-size: 14px;
  }
}
.setting-drawer-block-checbox {
  display: flex;
  justify-content: flex-start;
@@ -174,13 +176,6 @@
      height: 48px;
    }
    .custom-img {
      width: 48px;
      height: 38px;
      border-radius: 5px;
      box-shadow: 1px 1px 2px #898484;
    }
    .setting-drawer-block-checbox-selectIcon {
      position: absolute;
      top: 0;
@@ -197,7 +192,7 @@
}
.drawer-item {
  color: rgba(0, 0, 0, 0.65);
  color: var(--el-text-color-regular, rgba(0, 0, 0, 0.65));
  padding: 12px 0;
  font-size: 14px;
src/layout/components/Sidebar/Logo.vue
@@ -1,22 +1,22 @@
<template>
  <div class="sidebar-logo-container" :class="{ 'collapse': collapse }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
  <div class="sidebar-logo-container" :class="{ 'collapse': collapse }">
    <transition name="sidebarLogoFade">
      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
        <img v-if="logo" :src="logo" class="sidebar-logo" />
        <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
        <h1 v-else class="sidebar-title">{{ title }}</h1>
      </router-link>
      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
        <img v-if="logo" :src="logo" class="sidebar-logo" />
        <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
        <h1 class="sidebar-title">{{ title }}</h1>
      </router-link>
    </transition>
  </div>
</template>
<script setup>
import variables from '@/assets/styles/variables.module.scss'
import logo from '@/assets/logo/logo.png'
import useSettingsStore from '@/store/modules/settings'
import variables from '@/assets/styles/variables.module.scss'
defineProps({
  collapse: {
@@ -28,9 +28,27 @@
const title = import.meta.env.VITE_APP_TITLE;
const settingsStore = useSettingsStore();
const sideTheme = computed(() => settingsStore.sideTheme);
// èŽ·å–Logo背景色
const getLogoBackground = computed(() => {
  if (settingsStore.isDark) {
    return 'var(--sidebar-bg)';
  }
  return sideTheme.value === 'theme-dark' ? variables.menuBg : variables.menuLightBg;
});
// èŽ·å–Logo文字颜色
const getLogoTextColor = computed(() => {
  if (settingsStore.isDark) {
    return 'var(--sidebar-text)';
  }
  return sideTheme.value === 'theme-dark' ? '#fff' : variables.menuLightText;
});
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.module.scss';
.sidebarLogoFade-enter-active {
  transition: opacity 1.5s;
}
@@ -45,7 +63,7 @@
  width: 100%;
  height: 50px;
  line-height: 50px;
  background: #2b2f3a;
  background: v-bind(getLogoBackground);
  text-align: center;
  overflow: hidden;
@@ -63,7 +81,7 @@
    & .sidebar-title {
      display: inline-block;
      margin: 0;
      color: #fff;
      color: v-bind(getLogoTextColor);
      font-weight: 600;
      line-height: 50px;
      font-size: 14px;
src/layout/components/Sidebar/index.vue
@@ -1,16 +1,17 @@
<template>
  <div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
  <div :class="{ 'has-logo': showLogo }" class="sidebar-container">
    <logo v-if="showLogo" :collapse="isCollapse" />
    <el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
        :text-color="sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
        :background-color="getMenuBackground"
        :text-color="getMenuTextColor"
        :unique-opened="true"
        :active-text-color="theme"
        :collapse-transition="false"
        mode="vertical"
        :class="sideTheme"
      >
        <sidebar-item
          v-for="(route, index) in sidebarRouters"
@@ -36,19 +37,68 @@
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const sidebarRouters =  computed(() => permissionStore.sidebarRouters);
const sidebarRouters = computed(() => permissionStore.sidebarRouters);
const showLogo = computed(() => settingsStore.sidebarLogo);
const sideTheme = computed(() => settingsStore.sideTheme);
const theme = computed(() => settingsStore.theme);
const isCollapse = computed(() => !appStore.sidebar.opened);
// èŽ·å–èœå•èƒŒæ™¯è‰²
const getMenuBackground = computed(() => {
  if (settingsStore.isDark) {
    return 'var(--sidebar-bg)';
  }
  return sideTheme.value === 'theme-dark' ? variables.menuBg : variables.menuLightBg;
});
// èŽ·å–èœå•æ–‡å­—é¢œè‰²
const getMenuTextColor = computed(() => {
  if (settingsStore.isDark) {
    return 'var(--sidebar-text)';
  }
  return sideTheme.value === 'theme-dark' ? variables.menuText : variables.menuLightText;
});
const activeMenu = computed(() => {
  const { meta, path } = route;
  // if set path, the sidebar will highlight the path you set
  if (meta.activeMenu) {
    return meta.activeMenu;
  }
  return path;
})
});
</script>
<style lang="scss" scoped>
.sidebar-container {
  background-color: v-bind(getMenuBackground);
  .scrollbar-wrapper {
    background-color: v-bind(getMenuBackground);
  }
  .el-menu {
    border: none;
    height: 100%;
    width: 100% !important;
    .el-menu-item, .el-sub-menu__title {
      &:hover {
        background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
      }
    }
    .el-menu-item {
      color: v-bind(getMenuTextColor);
      &.is-active {
        color: var(--menu-active-text, #409eff);
        background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
      }
    }
    .el-sub-menu__title {
      color: v-bind(getMenuTextColor);
    }
  }
}
</style>
src/layout/components/TagsView/index.vue
@@ -257,13 +257,14 @@
}
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.tags-view-container {
  height: 34px;
  width: 100%;
  background: #fff;
  border-bottom: 1px solid #d8dce5;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
  background: var(--tags-bg, #fff);
  border-bottom: 1px solid var(--tags-item-border, #d8dce5);
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
  .tags-view-wrapper {
    .tags-view-item {
      display: inline-block;
@@ -271,25 +272,29 @@
      cursor: pointer;
      height: 26px;
      line-height: 26px;
      border: 1px solid #d8dce5;
      color: #495060;
      background: #fff;
      border: 1px solid var(--tags-item-border, #d8dce5);
      color: var(--tags-item-text, #495060);
      background: var(--tags-item-bg, #fff);
      padding: 0 8px;
      font-size: 12px;
      margin-left: 5px;
      margin-top: 4px;
      &:first-of-type {
        margin-left: 15px;
      }
      &:last-of-type {
        margin-right: 15px;
      }
      &.active {
        background-color: #42b983;
        color: #fff;
        border-color: #42b983;
        &::before {
          content: "";
          content: '';
          background: #fff;
          display: inline-block;
          width: 8px;
@@ -301,9 +306,10 @@
      }
    }
  }
  .contextmenu {
    margin: 0;
    background: #fff;
    background: var(--el-bg-color-overlay, #fff);
    z-index: 3000;
    position: absolute;
    list-style-type: none;
@@ -311,14 +317,17 @@
    border-radius: 4px;
    font-size: 12px;
    font-weight: 400;
    color: #333;
    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
    color: var(--tags-item-text, #333);
    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
    border: 1px solid var(--el-border-color-light, #e4e7ed);
    li {
      margin: 0;
      padding: 7px 16px;
      cursor: pointer;
      &:hover {
        background: #eee;
        background: var(--tags-item-hover, #eee);
      }
    }
  }
@@ -335,15 +344,17 @@
      vertical-align: 2px;
      border-radius: 50%;
      text-align: center;
      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
      transition: all .3s cubic-bezier(.645, .045, .355, 1);
      transform-origin: 100% 50%;
      &:before {
        transform: scale(0.6);
        transform: scale(.6);
        display: inline-block;
        vertical-align: -3px;
      }
      &:hover {
        background-color: #b4bccc;
        background-color: var(--tags-close-hover, #b4bccc);
        color: #fff;
        width: 12px !important;
        height: 12px !important;
src/main.js
@@ -4,6 +4,7 @@
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css
@@ -39,8 +40,6 @@
import ImageUpload from "@/components/ImageUpload"
// å›¾ç‰‡é¢„览组件
import ImagePreview from "@/components/ImagePreview"
// è‡ªå®šä¹‰æ ‘选择组件
import TreeSelect from '@/components/TreeSelect'
// å­—典标签组件
import DictTag from '@/components/DictTag'
@@ -59,7 +58,6 @@
// å…¨å±€ç»„件挂载
app.component('DictTag', DictTag)
app.component('Pagination', Pagination)
app.component('TreeSelect', TreeSelect)
app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
src/store/modules/settings.js
@@ -1,5 +1,9 @@
import defaultSettings from '@/settings'
import { useDark, useToggle } from '@vueuse/core'
import { useDynamicTitle } from '@/utils/dynamicTitle'
const isDark = useDark()
const toggleDark = useToggle(isDark)
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
@@ -17,7 +21,8 @@
      tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
      fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
      sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
      dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
      dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle,
      isDark: isDark.value
    }),
    actions: {
      // ä¿®æ”¹å¸ƒå±€è®¾ç½®
@@ -30,7 +35,12 @@
      // è®¾ç½®ç½‘页标题
      setTitle(title) {
        this.title = title
        useDynamicTitle();
        useDynamicTitle()
      },
      // åˆ‡æ¢æš—黑模式
      toggleTheme() {
        this.isDark = !this.isDark
        toggleDark()
      }
    }
  })