支持开启暗黑模式

This commit is contained in:
RuoYi 2024-12-04 20:32:06 +08:00
parent 535c5bd814
commit e212a0ab75
16 changed files with 392 additions and 273 deletions

View File

@ -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>

After

Width:  |  Height:  |  Size: 619 B

View File

@ -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>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,4 +1,4 @@
/** /**
* 通用css样式布局处理 * 通用css样式布局处理
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
*/ */
@ -102,40 +102,55 @@
/** 表格布局 **/ /** 表格布局 **/
.pagination-container { .pagination-container {
position: relative; position: relative;
height: 32px; height: 25px;
margin-bottom: 10px; margin-bottom: 10px;
margin-top: 15px; margin-top: 15px;
padding: 10px 20px !important; padding: 10px 20px !important;
background-color: transparent !important;
} }
/* 分页器定位 */
.pagination-container .el-pagination {
position: absolute;
right: 0;
top: 0;
}
/* 弹窗中的分页器 */
.el-dialog .pagination-container { .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 */
.tree-border { .tree-border {
margin-top: 5px; margin-top: 5px;
border: 1px solid #e5e6e7; border: 1px solid var(--el-border-color-light, #e5e6e7);
background: #FFFFFF none; background: var(--el-bg-color, #FFFFFF) none;
border-radius:4px; border-radius:4px;
width: 100%; 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 { .el-table .fixed-width .el-button--small {
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
@ -282,6 +297,5 @@
/* 分割面板样式 */ /* 分割面板样式 */
.splitpanes.default-theme .splitpanes__pane { .splitpanes.default-theme .splitpanes__pane {
background-color: #fff!important; background-color: var(--splitpanes-default-bg) !important;
} }

View File

@ -1,7 +1,7 @@
#app { #app {
.main-container { .main-container {
height: 100%; min-height: 100%;
transition: margin-left .28s; transition: margin-left .28s;
margin-left: $base-sidebar-width; margin-left: $base-sidebar-width;
position: relative; position: relative;
@ -12,10 +12,8 @@
} }
.sidebar-container { .sidebar-container {
-webkit-transition: width .28s;
transition: width 0.28s; transition: width 0.28s;
width: $base-sidebar-width !important; width: $base-sidebar-width !important;
background-color: $base-menu-background;
height: 100%; height: 100%;
position: fixed; position: fixed;
font-size: 0px; font-size: 0px;
@ -103,7 +101,7 @@
& .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title, & .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
& .theme-dark .el-sub-menu .el-menu-item { & .theme-dark .el-sub-menu .el-menu-item {
background-color: $base-sub-menu-background !important; background-color: $base-sub-menu-background;
&:hover { &:hover {
background-color: $base-sub-menu-hover !important; background-color: $base-sub-menu-hover !important;

View File

@ -8,58 +8,211 @@ $tiffany: #4AB7BD;
$yellow: #FEC171; $yellow: #FEC171;
$panGreen: #30B08F; $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: #bfcbd9;
$base-menu-color-active: #f4f4f5; $base-menu-color-active: #f4f4f5;
$base-menu-background: #304156; $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-background: #1f2d3d;
$base-sub-menu-hover: #001528; $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-primary: #409EFF;
$--color-success: #67C23A; $--color-success: #67C23A;
$--color-warning: #E6A23C; $--color-warning: #E6A23C;
$--color-danger: #F56C6C; $--color-danger: #F56C6C;
$--color-info: #909399; $--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 { :export {
menuColor: $base-menu-color; menuText: $menuText;
menuLightColor: $base-menu-light-color; menuActiveText: $menuActiveText;
menuColorActive: $base-menu-color-active; menuBg: $menuBg;
menuBackground: $base-menu-background; menuHover: $menuHover;
menuLightBackground: $base-menu-light-background; menuLightBg: $menuLightBg;
subMenuBackground: $base-sub-menu-background; menuLightHover: $menuLightHover;
subMenuHover: $base-sub-menu-hover; menuLightText: $menuLightText;
sideBarWidth: $base-sidebar-width; menuLightActiveText: $menuLightActiveText;
logoTitleColor: $base-logo-title-color; sideBarWidth: $sideBarWidth;
logoLightTitleColor: $base-logo-light-title-color; // 导出基础颜色
primaryColor: $--color-primary; blue: $blue;
successColor: $--color-success; lightBlue: $light-blue;
dangerColor: $--color-danger; red: $red;
infoColor: $--color-info; pink: $pink;
warningColor: $--color-warning; 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);
}
}

View File

@ -251,7 +251,6 @@ onMounted(() => {
.popup-main { .popup-main {
position: relative; position: relative;
margin: 10px auto; margin: 10px auto;
background: #fff;
border-radius: 5px; border-radius: 5px;
font-size: 12px; font-size: 12px;
overflow: hidden; overflow: hidden;

View File

@ -7,6 +7,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="64" width="64"
height="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" /> <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> </svg>

View File

@ -196,7 +196,7 @@ onMounted(() => {
/* 背景色隐藏 */ /* 背景色隐藏 */
.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 { .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 @@ onMounted(() => {
margin-left: 8px; margin-left: 8px;
margin-top: 0px; margin-top: 0px;
} }
</style> </style>

View File

@ -1,156 +0,0 @@
<template>
<div class="el-tree-select">
<el-select
style="width: 100%"
v-model="valueId"
ref="treeSelect"
:filterable="true"
:clearable="true"
@clear="clearHandle"
:filter-method="selectFilterData"
:placeholder="placeholder"
>
<el-option :value="valueId" :label="valueTitle">
<el-tree
id="tree-option"
ref="selectTree"
:accordion="accordion"
:data="options"
:props="objMap"
:node-key="objMap.value"
:expand-on-click-node="false"
:default-expanded-keys="defaultExpandedKey"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
></el-tree>
</el-option>
</el-select>
</div>
</template>
<script setup>
const { proxy } = getCurrentInstance();
const props = defineProps({
/* 配置项 */
objMap: {
type: Object,
default: () => {
return {
value: 'id', // ID
label: 'label', //
children: 'children' //
}
}
},
/* 自动收起 */
accordion: {
type: Boolean,
default: () => {
return false
}
},
/**当前双向数据绑定的值 */
value: {
type: [String, Number],
default: ''
},
/**当前的数据 */
options: {
type: Array,
default: () => []
},
/**输入框内部的文字 */
placeholder: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:value']);
const valueId = computed({
get: () => props.value,
set: (val) => {
emit('update:value', val)
}
});
const valueTitle = ref('');
const defaultExpandedKey = ref([]);
function initHandle() {
nextTick(() => {
const selectedValue = valueId.value;
if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
const node = proxy.$refs.selectTree.getNode(selectedValue)
if (node) {
valueTitle.value = node.data[props.objMap.label]
proxy.$refs.selectTree.setCurrentKey(selectedValue) //
defaultExpandedKey.value = [selectedValue] //
}
} else {
clearHandle()
}
})
}
function handleNodeClick(node) {
valueTitle.value = node[props.objMap.label]
valueId.value = node[props.objMap.value];
defaultExpandedKey.value = [];
proxy.$refs.treeSelect.blur()
selectFilterData('')
}
function selectFilterData(val) {
proxy.$refs.selectTree.filter(val)
}
function filterNode(value, data) {
if (!value) return true
return data[props.objMap['label']].indexOf(value) !== -1
}
function clearHandle() {
valueTitle.value = ''
valueId.value = ''
defaultExpandedKey.value = [];
clearSelected()
}
function clearSelected() {
const allNode = document.querySelectorAll('#tree-option .el-tree-node')
allNode.forEach((element) => element.classList.remove('is-current'))
}
onMounted(() => {
initHandle()
})
watch(valueId, () => {
initHandle();
})
</script>
<style lang='scss' scoped>
@import "@/assets/styles/variables.module.scss";
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
padding: 0;
background-color: #fff;
height: auto;
}
.el-select-dropdown__item.selected {
font-weight: normal;
}
ul li .el-tree .el-tree-node__content {
height: auto;
padding: 0 20px;
box-sizing: border-box;
}
:deep(.el-tree-node__content:hover),
:deep(.el-tree-node__content:active),
:deep(.is-current > div:first-child),
:deep(.el-tree-node__content:focus) {
background-color: mix(#fff, $--color-primary, 90%);
color: $--color-primary;
}
</style>

View File

@ -18,6 +18,13 @@
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <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"> <el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" /> <size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
@ -98,6 +105,10 @@ const emits = defineEmits(['setLayout'])
function setLayout() { function setLayout() {
emits('setLayout'); emits('setLayout');
} }
function toggleTheme() {
settingsStore.toggleTheme()
}
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
@ -105,7 +116,7 @@ function setLayout() {
height: 50px; height: 50px;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
background: #fff; background: var(--navbar-bg);
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container { .hamburger-container {
@ -150,7 +161,7 @@ function setLayout() {
padding: 0 8px; padding: 0 8px;
height: 100%; height: 100%;
font-size: 18px; font-size: 18px;
color: #5a5e66; color: var(--navbar-text);
vertical-align: text-bottom; vertical-align: text-bottom;
&.hover-effect { &.hover-effect {
@ -161,6 +172,19 @@ function setLayout() {
background: rgba(0, 0, 0, 0.025); 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 { .avatar-container {

View File

@ -149,13 +149,15 @@ defineExpose({
<style lang='scss' scoped> <style lang='scss' scoped>
.setting-drawer-title { .setting-drawer-title {
margin-bottom: 12px; 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; line-height: 22px;
font-weight: bold; font-weight: bold;
.drawer-title { .drawer-title {
font-size: 14px; font-size: 14px;
} }
} }
.setting-drawer-block-checbox { .setting-drawer-block-checbox {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
@ -174,13 +176,6 @@ defineExpose({
height: 48px; height: 48px;
} }
.custom-img {
width: 48px;
height: 38px;
border-radius: 5px;
box-shadow: 1px 1px 2px #898484;
}
.setting-drawer-block-checbox-selectIcon { .setting-drawer-block-checbox-selectIcon {
position: absolute; position: absolute;
top: 0; top: 0;
@ -197,7 +192,7 @@ defineExpose({
} }
.drawer-item { .drawer-item {
color: rgba(0, 0, 0, 0.65); color: var(--el-text-color-regular, rgba(0, 0, 0, 0.65));
padding: 12px 0; padding: 12px 0;
font-size: 14px; font-size: 14px;

View File

@ -1,22 +1,22 @@
<template> <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"> <transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" /> <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>
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> <router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" /> <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> </router-link>
</transition> </transition>
</div> </div>
</template> </template>
<script setup> <script setup>
import variables from '@/assets/styles/variables.module.scss'
import logo from '@/assets/logo/logo.png' import logo from '@/assets/logo/logo.png'
import useSettingsStore from '@/store/modules/settings' import useSettingsStore from '@/store/modules/settings'
import variables from '@/assets/styles/variables.module.scss'
defineProps({ defineProps({
collapse: { collapse: {
@ -28,9 +28,27 @@ defineProps({
const title = import.meta.env.VITE_APP_TITLE; const title = import.meta.env.VITE_APP_TITLE;
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
const sideTheme = computed(() => settingsStore.sideTheme); 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/styles/variables.module.scss';
.sidebarLogoFade-enter-active { .sidebarLogoFade-enter-active {
transition: opacity 1.5s; transition: opacity 1.5s;
} }
@ -45,7 +63,7 @@ const sideTheme = computed(() => settingsStore.sideTheme);
width: 100%; width: 100%;
height: 50px; height: 50px;
line-height: 50px; line-height: 50px;
background: #2b2f3a; background: v-bind(getLogoBackground);
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
@ -63,7 +81,7 @@ const sideTheme = computed(() => settingsStore.sideTheme);
& .sidebar-title { & .sidebar-title {
display: inline-block; display: inline-block;
margin: 0; margin: 0;
color: #fff; color: v-bind(getLogoTextColor);
font-weight: 600; font-weight: 600;
line-height: 50px; line-height: 50px;
font-size: 14px; font-size: 14px;

View File

@ -1,16 +1,17 @@
<template> <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" /> <logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper"> <el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu <el-menu
:default-active="activeMenu" :default-active="activeMenu"
:collapse="isCollapse" :collapse="isCollapse"
:background-color="sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground" :background-color="getMenuBackground"
:text-color="sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor" :text-color="getMenuTextColor"
:unique-opened="true" :unique-opened="true"
:active-text-color="theme" :active-text-color="theme"
:collapse-transition="false" :collapse-transition="false"
mode="vertical" mode="vertical"
:class="sideTheme"
> >
<sidebar-item <sidebar-item
v-for="(route, index) in sidebarRouters" v-for="(route, index) in sidebarRouters"
@ -36,19 +37,68 @@ const appStore = useAppStore()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore() const permissionStore = usePermissionStore()
const sidebarRouters = computed(() => permissionStore.sidebarRouters); const sidebarRouters = computed(() => permissionStore.sidebarRouters);
const showLogo = computed(() => settingsStore.sidebarLogo); const showLogo = computed(() => settingsStore.sidebarLogo);
const sideTheme = computed(() => settingsStore.sideTheme); const sideTheme = computed(() => settingsStore.sideTheme);
const theme = computed(() => settingsStore.theme); const theme = computed(() => settingsStore.theme);
const isCollapse = computed(() => !appStore.sidebar.opened); 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 activeMenu = computed(() => {
const { meta, path } = route; const { meta, path } = route;
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) { if (meta.activeMenu) {
return meta.activeMenu; return meta.activeMenu;
} }
return path; return path;
}) });
</script> </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>

View File

@ -257,13 +257,14 @@ function handleScroll() {
} }
</script> </script>
<style lang='scss' scoped> <style lang="scss" scoped>
.tags-view-container { .tags-view-container {
height: 34px; height: 34px;
width: 100%; width: 100%;
background: #fff; background: var(--tags-bg, #fff);
border-bottom: 1px solid #d8dce5; border-bottom: 1px solid var(--tags-item-border, #d8dce5);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); 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-wrapper {
.tags-view-item { .tags-view-item {
display: inline-block; display: inline-block;
@ -271,25 +272,29 @@ function handleScroll() {
cursor: pointer; cursor: pointer;
height: 26px; height: 26px;
line-height: 26px; line-height: 26px;
border: 1px solid #d8dce5; border: 1px solid var(--tags-item-border, #d8dce5);
color: #495060; color: var(--tags-item-text, #495060);
background: #fff; background: var(--tags-item-bg, #fff);
padding: 0 8px; padding: 0 8px;
font-size: 12px; font-size: 12px;
margin-left: 5px; margin-left: 5px;
margin-top: 4px; margin-top: 4px;
&:first-of-type { &:first-of-type {
margin-left: 15px; margin-left: 15px;
} }
&:last-of-type { &:last-of-type {
margin-right: 15px; margin-right: 15px;
} }
&.active { &.active {
background-color: #42b983; background-color: #42b983;
color: #fff; color: #fff;
border-color: #42b983; border-color: #42b983;
&::before { &::before {
content: ""; content: '';
background: #fff; background: #fff;
display: inline-block; display: inline-block;
width: 8px; width: 8px;
@ -301,9 +306,10 @@ function handleScroll() {
} }
} }
} }
.contextmenu { .contextmenu {
margin: 0; margin: 0;
background: #fff; background: var(--el-bg-color-overlay, #fff);
z-index: 3000; z-index: 3000;
position: absolute; position: absolute;
list-style-type: none; list-style-type: none;
@ -311,14 +317,17 @@ function handleScroll() {
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
color: #333; color: var(--tags-item-text, #333);
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
border: 1px solid var(--el-border-color-light, #e4e7ed);
li { li {
margin: 0; margin: 0;
padding: 7px 16px; padding: 7px 16px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: #eee; background: var(--tags-item-hover, #eee);
} }
} }
} }
@ -335,15 +344,17 @@ function handleScroll() {
vertical-align: 2px; vertical-align: 2px;
border-radius: 50%; border-radius: 50%;
text-align: center; 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%; transform-origin: 100% 50%;
&:before { &:before {
transform: scale(0.6); transform: scale(.6);
display: inline-block; display: inline-block;
vertical-align: -3px; vertical-align: -3px;
} }
&:hover { &:hover {
background-color: #b4bccc; background-color: var(--tags-close-hover, #b4bccc);
color: #fff; color: #fff;
width: 12px !important; width: 12px !important;
height: 12px !important; height: 12px !important;

View File

@ -4,6 +4,7 @@ import Cookies from 'js-cookie'
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css' 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 locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css import '@/assets/styles/index.scss' // global css
@ -39,8 +40,6 @@ import FileUpload from "@/components/FileUpload"
import ImageUpload from "@/components/ImageUpload" import ImageUpload from "@/components/ImageUpload"
// 图片预览组件 // 图片预览组件
import ImagePreview from "@/components/ImagePreview" import ImagePreview from "@/components/ImagePreview"
// 自定义树选择组件
import TreeSelect from '@/components/TreeSelect'
// 字典标签组件 // 字典标签组件
import DictTag from '@/components/DictTag' import DictTag from '@/components/DictTag'
@ -59,7 +58,6 @@ app.config.globalProperties.selectDictLabels = selectDictLabels
// 全局组件挂载 // 全局组件挂载
app.component('DictTag', DictTag) app.component('DictTag', DictTag)
app.component('Pagination', Pagination) app.component('Pagination', Pagination)
app.component('TreeSelect', TreeSelect)
app.component('FileUpload', FileUpload) app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload) app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview) app.component('ImagePreview', ImagePreview)

View File

@ -1,6 +1,10 @@
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
import { useDark, useToggle } from '@vueuse/core'
import { useDynamicTitle } from '@/utils/dynamicTitle' import { useDynamicTitle } from '@/utils/dynamicTitle'
const isDark = useDark()
const toggleDark = useToggle(isDark)
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
@ -17,7 +21,8 @@ const useSettingsStore = defineStore(
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, 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: { actions: {
// 修改布局设置 // 修改布局设置
@ -30,7 +35,12 @@ const useSettingsStore = defineStore(
// 设置网页标题 // 设置网页标题
setTitle(title) { setTitle(title) {
this.title = title this.title = title
useDynamicTitle(); useDynamicTitle()
},
// 切换暗黑模式
toggleTheme() {
this.isDark = !this.isDark
toggleDark()
} }
} }
}) })