mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 21:40:50 +00:00
feat(管理端): 深色模式接入 Element Plus 官方深色变量并动态计算主色色阶
This commit is contained in:
parent
a632aafaf9
commit
e815e1714f
@ -22,6 +22,7 @@ import config from '../package.json';
|
||||
import bus from '@/utils/bus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { useThemeConfigStore } from '@/store/module/themeConfig';
|
||||
import { filterThemeCssText } from '@/utils/theme.js';
|
||||
|
||||
defineOptions({ name: 'app' });
|
||||
|
||||
@ -69,7 +70,9 @@ function onOpenSetingsDrawer() {
|
||||
function getLayoutThemeConfig() {
|
||||
if (Local.get('themeConfigPrev')) {
|
||||
themeConfigStore.setThemeConfig(Local.get('themeConfigPrev'));
|
||||
document.documentElement.style.cssText = Local.get('themeConfigStyle');
|
||||
// 恢复时过滤主色浅/深阶(历史脏数据清洗):这些变量由样式表 color-mix 动态计算,
|
||||
// 行内持久化会压过 dark.scss 暗色档,导致深色模式表头/浅底仍为浅色
|
||||
document.documentElement.style.cssText = filterThemeCssText(Local.get('themeConfigStyle'));
|
||||
} else {
|
||||
Local.set('themeConfigPrev', themeConfigStore.themeConfig);
|
||||
}
|
||||
|
||||
@ -176,12 +176,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 暗黑模式 -->
|
||||
<!-- <div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsDark') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="getThemeConfig.isIsDark" :width="35" @change="onAddDarkChange"> </el-switch>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<!-- 其它设置 -->
|
||||
<el-divider :content-position="contentPosotion">{{ $t('message.layout.fiveTitle') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
@ -243,7 +243,7 @@ import { ref, computed, nextTick, onMounted } from 'vue';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Local } from '@/utils/storage.js';
|
||||
import { useChangeColor } from '@/utils/theme.js';
|
||||
import { filterThemeCssText } from '@/utils/theme.js';
|
||||
import config from '../../../../package.json';
|
||||
import { themeList } from './theme';
|
||||
import bus from '@/utils/bus';
|
||||
@ -279,16 +279,9 @@ function onLayoutMobileResize(res) {
|
||||
|
||||
// 全局主题
|
||||
function onColorPickerChange() {
|
||||
// if (!getThemeConfig.value.primary) return;
|
||||
// 颜色加深
|
||||
// document.documentElement.style.setProperty('--prev-color-primary', getThemeConfig.value.primary);
|
||||
// 颜色变浅
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
document.documentElement.style.setProperty(
|
||||
`--prev-color-primary-light-${i}`,
|
||||
`${useChangeColor().getLightColor(getThemeConfig.value.primary, i / 10)}`,
|
||||
);
|
||||
}
|
||||
// 主色浅色阶不再写行内样式:app.scss 的 color-mix 表达式引用 --prev-color-primary,
|
||||
// 换肤只改主色即可全档自动重算;此前行内写死向白混色,会压过 dark.scss 的深色档,
|
||||
// 导致深色模式下表头/选中行/标签浅底仍是刺眼浅蓝
|
||||
setLocalThemeConfig();
|
||||
}
|
||||
|
||||
@ -455,8 +448,14 @@ function onMenuBgColorChange() {
|
||||
// 深色模式
|
||||
function onAddDarkChange() {
|
||||
const body = document.documentElement;
|
||||
if (getThemeConfig.value.isIsDark) body.setAttribute('data-theme', 'dark');
|
||||
const isDark = getThemeConfig.value.isIsDark;
|
||||
if (isDark) body.setAttribute('data-theme', 'dark');
|
||||
else body.setAttribute('data-theme', '');
|
||||
// Element Plus 官方深色变量表挂在 html.dark 上(main.js 引入的 dark/css-vars.css),同步切换
|
||||
body.classList.toggle('dark', isDark);
|
||||
// vxe-table / vxe-pc-ui 自带深色主题挂 data-vxe-ui-theme 属性(树形表格等 vxe 组件),同步切换
|
||||
if (isDark) body.setAttribute('data-vxe-ui-theme', 'dark');
|
||||
else body.removeAttribute('data-vxe-ui-theme');
|
||||
setLocalThemeConfig();
|
||||
}
|
||||
|
||||
@ -485,7 +484,8 @@ function setLocalThemeConfig() {
|
||||
|
||||
// 存储布局配置全局主题样式(html根标签)
|
||||
function setLocalThemeConfigStyle() {
|
||||
Local.set('themeConfigStyle', document.documentElement.style.cssText);
|
||||
// 过滤主色浅/深阶:由样式表 color-mix 动态计算,行内持久化会压过深色暗色档
|
||||
Local.set('themeConfigStyle', filterThemeCssText(document.documentElement.style.cssText));
|
||||
}
|
||||
|
||||
// 布局配置弹窗打开
|
||||
|
||||
@ -11,7 +11,6 @@ export const themeList = {
|
||||
'--prev-bg-columnsMenuBarColor': '#fff',
|
||||
'--prev-MenuActiveColor': '#0256FF',
|
||||
'--prev-tag-active-color': '#0256FF',
|
||||
'--prev-color-primary-light-9': '#e5eeff',
|
||||
'--prev-bg-columnsMenuActiveColor': '#fff',
|
||||
},
|
||||
'theme-2': {
|
||||
@ -28,7 +27,6 @@ export const themeList = {
|
||||
'--prev-MenuActiveColor': '#0256FF',
|
||||
'--prev-bg-columnsMenuActiveBgColor': '#0256FF',
|
||||
'--prev-tag-active-color': '#0256FF',
|
||||
'--prev-color-primary-light-9': '#e5eeff',
|
||||
},
|
||||
'theme-3': {
|
||||
'--prev-bg-menuBar': '#282c34',
|
||||
@ -42,9 +40,7 @@ export const themeList = {
|
||||
'--prev-bg-columnsMenuBarColor': '#fff',
|
||||
'--prev-bg-columnsMenuActiveColor': '#fff',
|
||||
'--prev-MenuActiveColor': '#41b584',
|
||||
'--prev-color-primary-light-9': '#ecf8f3',
|
||||
'--prev-tag-active-color': '#41b584',
|
||||
'--prev-color-primary-light-9': '#ecf8f3',
|
||||
},
|
||||
'theme-4': {
|
||||
'--prev-bg-menuBar': '#ffffff',
|
||||
@ -60,7 +56,6 @@ export const themeList = {
|
||||
'--prev-MenuActiveColor': '#41b584',
|
||||
|
||||
'--prev-tag-active-color': '#41b584',
|
||||
'--prev-color-primary-light-9': '#ecf8f3',
|
||||
},
|
||||
'theme-5': {
|
||||
'--prev-bg-menuBar': '#282c34',
|
||||
@ -74,7 +69,6 @@ export const themeList = {
|
||||
'--prev-bg-columnsMenuBarColor': '#fff',
|
||||
'--prev-bg-columnsMenuActiveColor': '#fff',
|
||||
'--prev-MenuActiveColor': '#6954f0',
|
||||
'--prev-color-primary-light-9': '#f0eefe',
|
||||
'--prev-tag-active-color': '#6954f0',
|
||||
},
|
||||
'theme-6': {
|
||||
@ -89,7 +83,6 @@ export const themeList = {
|
||||
'--prev-bg-columnsMenuBarColor': '#515a6e',
|
||||
'--prev-bg-columnsMenuActiveColor': '#fff',
|
||||
'--prev-MenuActiveColor': '#6954f0',
|
||||
'--prev-color-primary-light-9': '#f0eefe',
|
||||
'--prev-tag-active-color': '#6954f0',
|
||||
},
|
||||
'theme-7': {
|
||||
@ -117,7 +110,6 @@ export const themeList = {
|
||||
'--prev-bg-columnsMenuBar': '#fff',
|
||||
'--prev-bg-columnsMenuBarColor': '#515a6e',
|
||||
'--prev-bg-columnsMenuActiveColor': '#fff',
|
||||
'--prev-color-primary-light-9': '#feedeb',
|
||||
'--prev-MenuActiveColor': '#f34d37',
|
||||
'--prev-tag-active-color': '#f34d37',
|
||||
},
|
||||
@ -134,6 +126,5 @@ export const themeList = {
|
||||
'--prev-bg-columnsMenuActiveColor': '#fff',
|
||||
'--prev-tag-active-color': '#0256FF',
|
||||
'--prev-MenuActiveColor': '#0256FF',
|
||||
'--prev-color-primary-light-9': '#e5eeff',
|
||||
},
|
||||
};
|
||||
|
||||
@ -27,6 +27,9 @@ import timeOptions from '@/libs/timeOptions';
|
||||
import ElementPlus, { ElMessage } from 'element-plus';
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
import 'element-plus/dist/index.css';
|
||||
// Element Plus 官方深色变量表(挂 html.dark,由 setings.vue 的 onAddDarkChange 切换);
|
||||
// 须在 @/theme/index.scss 之前引入,保证同特异性时项目主题层(dark.scss 重桥接)后加载胜出
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css';
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
|
||||
// element-ui 字体图标类名兼容层(CSS mask 方案,自动生成)
|
||||
import './styles/el-icon-compat.css';
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
--prev-bg-topBarColor: #dadada !important;
|
||||
--prev-bg-columnsMenuBar: #191919 !important;
|
||||
--prev-bg-columnsMenuBarColor: #dadada !important;
|
||||
/* 换肤(setLocalTheme)会按主题行内写入浅色 hover 底(#e5eeff/#ecf8f3 等),深色下需压制 */
|
||||
--prev-bg-menu-hover-ba-color: rgba(255, 255, 255, 0.1) !important;
|
||||
--prev-bg-main-color: #1f1f1f !important;
|
||||
--prev-bg-color: rgba(0, 0, 0, 0.3) !important;
|
||||
--prev-bg-white: #191919 !important;
|
||||
@ -24,6 +26,20 @@
|
||||
--prev-border-color-lighter: #333333 !important;
|
||||
--prev-border-color-extra-light: #333333 !important;
|
||||
|
||||
/* 主色浅色阶暗色档:与 app.scss 浅色档同算法(color-mix),混色底由白色换成暗底
|
||||
#141414(Element Plus 官方深色变量同款底色)。表头(app.scss 的
|
||||
--el-table-header-bg-color)、选中行、标签浅底等引用方自动跟随;
|
||||
行内主色换肤时 color-mix 同样自动重算,无需 JS 参与 */
|
||||
--prev-color-primary-light-1: color-mix(in srgb, var(--prev-color-primary) 90%, #141414);
|
||||
--prev-color-primary-light-2: color-mix(in srgb, var(--prev-color-primary) 80%, #141414);
|
||||
--prev-color-primary-light-3: color-mix(in srgb, var(--prev-color-primary) 70%, #141414);
|
||||
--prev-color-primary-light-4: color-mix(in srgb, var(--prev-color-primary) 60%, #141414);
|
||||
--prev-color-primary-light-5: color-mix(in srgb, var(--prev-color-primary) 50%, #141414);
|
||||
--prev-color-primary-light-6: color-mix(in srgb, var(--prev-color-primary) 40%, #141414);
|
||||
--prev-color-primary-light-7: color-mix(in srgb, var(--prev-color-primary) 30%, #141414);
|
||||
--prev-color-primary-light-8: color-mix(in srgb, var(--prev-color-primary) 20%, #141414);
|
||||
--prev-color-primary-light-9: color-mix(in srgb, var(--prev-color-primary) 10%, #141414);
|
||||
|
||||
// menu
|
||||
.layout-aside {
|
||||
border-right: 1px solid var(--prev-border-color-lighter) !important;
|
||||
@ -112,4 +128,63 @@
|
||||
.el-calendar {
|
||||
border: 1px solid var(--prev-border-color-lighter);
|
||||
}
|
||||
|
||||
// 底部固定提交卡:浅色为白色毛玻璃,深色换黑色毛玻璃(style.scss 同规则带 !important,
|
||||
// 此处块内选择器特异性更高,可覆盖)
|
||||
.fixed-card {
|
||||
background-color: rgba(25, 25, 25, 0.6) !important;
|
||||
}
|
||||
|
||||
// AI 对话工作台:会话面板底改不透明层次色。
|
||||
// 浅色档 --prev-bg-color 是实色,深色档是 rgba(0,0,0,0.3) 半透明,
|
||||
// 面板用半透明底会随下垫内容/页面底色变化产生观感分层
|
||||
.conversation-panel {
|
||||
background-color: #202020;
|
||||
}
|
||||
|
||||
// form-create 上传占位框(elm-frame/elm-upload 组件默认 #fff 底 + #c0ccda 边)
|
||||
._fc-frame ._fc-upload-btn,
|
||||
._fc-frame ._fc-files,
|
||||
._fc-upload ._fc-upload-btn,
|
||||
._fc-upload ._fc-files {
|
||||
background-color: var(--prev-bg-white) !important;
|
||||
border-color: var(--prev-border-color-base) !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Element Plus 官方深色变量重桥接
|
||||
------------------------------- */
|
||||
/* main.js 引入的官方 dark/css-vars.css 挂在 html.dark(特异性 0,1,1)上,会:
|
||||
1. 把主色系接管为 EP 默认蓝 #409eff,与项目主色(默认 #0256FF)漂移;
|
||||
2. 把 --el-bg-color 系接管为 #141414 体系,与本项目 #191919 深色体系并存两种黑。
|
||||
此处以同特异性 html[data-theme='dark'] 重桥接回 --prev-* 体系(本文件后于官方
|
||||
文件加载,同特异性按源顺序胜出);未列出的官方深色值(语义色 light 阶、遮罩、
|
||||
阴影、fill-color/-lighter 等)保持官方值兜底 */
|
||||
html[data-theme='dark'] {
|
||||
/* 背景体系:统一回 #191919(卡片/弹层/表格行底/输入框内底) */
|
||||
--el-bg-color: var(--prev-bg-white);
|
||||
--el-bg-color-overlay: var(--prev-bg-white);
|
||||
--el-fill-color-blank: var(--prev-bg-white);
|
||||
--el-fill-color-light: var(--prev-color-hover);
|
||||
|
||||
/* 文本体系 */
|
||||
--el-text-color-primary: var(--prev-color-text-primary);
|
||||
--el-text-color-regular: var(--prev-color-text-regular);
|
||||
--el-text-color-secondary: var(--prev-color-text-secondary);
|
||||
--el-text-color-placeholder: var(--prev-color-text-placeholder);
|
||||
|
||||
/* 边框体系 */
|
||||
--el-border-color: var(--prev-border-color-base);
|
||||
--el-border-color-light: var(--prev-border-color-light);
|
||||
--el-border-color-lighter: var(--prev-border-color-lighter);
|
||||
--el-border-color-extra-light: var(--prev-border-color-extra-light);
|
||||
|
||||
/* 主色系:浅色阶向暗底 #141414 混色(同 EP 官方深色算法),保持项目主色不漂移 */
|
||||
--el-color-primary: var(--prev-color-primary);
|
||||
--el-color-primary-light-3: color-mix(in srgb, var(--prev-color-primary) 70%, #141414);
|
||||
--el-color-primary-light-5: color-mix(in srgb, var(--prev-color-primary) 50%, #141414);
|
||||
--el-color-primary-light-7: color-mix(in srgb, var(--prev-color-primary) 30%, #141414);
|
||||
--el-color-primary-light-8: color-mix(in srgb, var(--prev-color-primary) 20%, #141414);
|
||||
--el-color-primary-light-9: color-mix(in srgb, var(--prev-color-primary) 10%, #141414);
|
||||
--el-color-primary-dark-2: color-mix(in srgb, var(--prev-color-primary) 80%, #000000);
|
||||
}
|
||||
|
||||
@ -1,5 +1,27 @@
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
/**
|
||||
* 过滤主题行内样式中的主色浅/深阶变量
|
||||
*
|
||||
* 主色浅色阶/深色阶由样式表 color-mix 表达式动态计算(亮色档在 theme/app.scss,
|
||||
* 暗色档在 theme/dark.scss),引用 --prev-color-primary,换肤时自动重算。
|
||||
* 这类变量不允许持久化为行内样式:行内样式优先级最高,会压过深色模式的暗色档,
|
||||
* 导致深色下表头/选中行/标签浅底仍是刺眼浅色(2026-09 深色模式适配遗留问题)。
|
||||
* @param {string} cssText document.documentElement.style.cssText
|
||||
* @returns {string} 过滤后的 cssText
|
||||
*/
|
||||
export function filterThemeCssText(cssText) {
|
||||
if (!cssText) return '';
|
||||
const dynamicVarRe = /^--(prev|el)-color-primary-(light|dark)-\d+$/;
|
||||
return cssText
|
||||
.split(';')
|
||||
.filter((item) => {
|
||||
const name = (item.split(':')[0] || '').trim();
|
||||
return name && !dynamicVarRe.test(name);
|
||||
})
|
||||
.join(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* 颜色转换函数
|
||||
* @method hexToRgb hex 颜色转 rgb 颜色
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user