diff --git a/frontend/admin/src/App.vue b/frontend/admin/src/App.vue index fd0442f9e..6baf3ade6 100644 --- a/frontend/admin/src/App.vue +++ b/frontend/admin/src/App.vue @@ -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); } diff --git a/frontend/admin/src/layout/navBars/breadcrumb/setings.vue b/frontend/admin/src/layout/navBars/breadcrumb/setings.vue index a6656f462..72f49935f 100644 --- a/frontend/admin/src/layout/navBars/breadcrumb/setings.vue +++ b/frontend/admin/src/layout/navBars/breadcrumb/setings.vue @@ -176,12 +176,12 @@ - + {{ $t('message.layout.fiveTitle') }}
@@ -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)); } // 布局配置弹窗打开 diff --git a/frontend/admin/src/layout/navBars/breadcrumb/theme.js b/frontend/admin/src/layout/navBars/breadcrumb/theme.js index e60d7df34..03405b8aa 100644 --- a/frontend/admin/src/layout/navBars/breadcrumb/theme.js +++ b/frontend/admin/src/layout/navBars/breadcrumb/theme.js @@ -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', }, }; diff --git a/frontend/admin/src/main.js b/frontend/admin/src/main.js index 8fe548fca..904600c74 100644 --- a/frontend/admin/src/main.js +++ b/frontend/admin/src/main.js @@ -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'; diff --git a/frontend/admin/src/theme/dark.scss b/frontend/admin/src/theme/dark.scss index 1cb102046..392bb4d63 100644 --- a/frontend/admin/src/theme/dark.scss +++ b/frontend/admin/src/theme/dark.scss @@ -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); } diff --git a/frontend/admin/src/utils/theme.js b/frontend/admin/src/utils/theme.js index 36343ba4d..5f7ec9447 100644 --- a/frontend/admin/src/utils/theme.js +++ b/frontend/admin/src/utils/theme.js @@ -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 颜色