mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-10-14 05:00:10 +00:00
refactor(captcha): 调整验证码字体大小并增强验证码生成逻辑
- 修改验证码字体大小从40调整为35 - 增加验证码生成的难度参数,支持不同难度级别的运算 - 优化验证码图像生成逻辑,增加随机噪点和干扰线,提升安全性和可读性
This commit is contained in:
@@ -103,7 +103,6 @@
|
||||
:border="true"
|
||||
:max-height="250"
|
||||
:row-key="pk"
|
||||
:highlight-current-row="true"
|
||||
:class="{ radio: !isMultiple }"
|
||||
@select="handleSelect"
|
||||
@select-all="handleSelectAll"
|
||||
|
||||
@@ -27,7 +27,7 @@ defineProps({
|
||||
.logo {
|
||||
width: 100%;
|
||||
height: $navbar-height;
|
||||
background-color: var(--sidebar-logo-background);
|
||||
background-color: var(--layout-logo-bg);
|
||||
|
||||
.title {
|
||||
max-width: 100px;
|
||||
@@ -36,7 +36,7 @@ defineProps({
|
||||
text-overflow: ellipsis;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: var(--sidebar-logo-text-color);
|
||||
color: var(--layout-logo-text);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ defineProps({
|
||||
background-color: transparent !important;
|
||||
|
||||
.title {
|
||||
color: var(--sidebar-logo-text-color);
|
||||
color: var(--layout-logo-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ const appMainHeight = computed(() => {
|
||||
.app-main {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
background-color: var(--el-bg-color);
|
||||
background-color: var(--layout-content-canvas, var(--el-bg-color-page));
|
||||
|
||||
/* 布局切换动画优化 */
|
||||
/* fade */
|
||||
|
||||
@@ -33,7 +33,6 @@ import type { RouteRecordRaw } from "vue-router";
|
||||
import { useSettingsStore, useAppStore } from "@/store";
|
||||
import { isExternal } from "@/utils/index";
|
||||
import MenuItem from "./components/MenuItem.vue";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -64,13 +63,13 @@ const expandedMenuIndexes = ref<string[]>([]);
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
|
||||
// 菜单主题属性
|
||||
// 顶栏横向菜单背景由布局 CSS 设为 transparent;若此处传 CSS 变量,EP 内部 TinyColor 无法解析会退成 #000,hover 背景发黑
|
||||
const menuThemeProps = computed(() => {
|
||||
const isDark = theme.value === "dark";
|
||||
|
||||
const isHorizontal = props.menuMode === "horizontal";
|
||||
return {
|
||||
backgroundColor: isDark ? variables["menu-background"] : undefined,
|
||||
textColor: isDark ? variables["menu-text"] : undefined,
|
||||
activeTextColor: isDark ? variables["menu-active-text"] : undefined,
|
||||
backgroundColor: isHorizontal ? "" : "var(--layout-sidebar-bg)",
|
||||
textColor: "var(--layout-sidebar-text)",
|
||||
activeTextColor: "var(--layout-sidebar-active-text)",
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
<el-menu
|
||||
mode="horizontal"
|
||||
:default-active="activeTopMenuPath"
|
||||
:background-color="theme === 'dark' ? variables['menu-background'] : undefined"
|
||||
:text-color="theme === 'dark' ? variables['menu-text'] : undefined"
|
||||
:active-text-color="theme === 'dark' ? variables['menu-active-text'] : undefined"
|
||||
text-color="var(--layout-menu-text)"
|
||||
active-text-color="var(--layout-menu-active-text)"
|
||||
@select="handleTopMenuSelect"
|
||||
>
|
||||
<el-menu-item v-for="item in topMenuItems" :key="item.path" :index="item.path">
|
||||
@@ -22,16 +21,12 @@ defineOptions({
|
||||
});
|
||||
|
||||
import { LocationQueryRaw, RouteRecordRaw } from "vue-router";
|
||||
import { usePermissionStore, useAppStore, useSettingsStore } from "@/store";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
import { usePermissionStore, useAppStore } from "@/store";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
// 获取主题
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
|
||||
// 顶部菜单列表
|
||||
const topMenus = ref<RouteRecordRaw[]>([]);
|
||||
@@ -120,10 +115,7 @@ const activeTopMenuPath = computed(() => appStore.activeTopMenuPath);
|
||||
onMounted(() => {
|
||||
topMenus.value = permissionStore.routes.filter((item) => !item.meta || !item.meta.hidden);
|
||||
// 初始化顶部菜单
|
||||
const currentTopMenuPath =
|
||||
useRoute().path.split("/").filter(Boolean).length > 1
|
||||
? useRoute().path.match(/^\/[^/]+/)?.[0] || "/"
|
||||
: "/";
|
||||
const currentTopMenuPath = getTopMenuPath(route.path);
|
||||
appStore.activeTopMenu(currentTopMenuPath); // 设置激活的顶部菜单
|
||||
permissionStore.setMixLayoutSideMenus(currentTopMenuPath); // 设置混合布局左侧菜单
|
||||
});
|
||||
@@ -133,15 +125,17 @@ watch(
|
||||
() => router.currentRoute.value.path,
|
||||
(newPath) => {
|
||||
if (newPath) {
|
||||
// 提取顶级路径
|
||||
const topMenuPath =
|
||||
newPath.split("/").filter(Boolean).length > 1 ? newPath.match(/^\/[^/]+/)?.[0] || "/" : "/";
|
||||
const topMenuPath = getTopMenuPath(newPath);
|
||||
|
||||
// 使用公共方法更新菜单状态,但跳过导航(因为路由已经变化)
|
||||
updateMenuState(topMenuPath, true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function getTopMenuPath(path: string): string {
|
||||
return path.split("/").filter(Boolean).length > 1 ? path.match(/^\/[^/]+/)?.[0] || "/" : "/";
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -182,17 +182,17 @@ function resolvePath(routePath: string) {
|
||||
|
||||
html.dark {
|
||||
.el-menu-item:hover {
|
||||
background-color: var(--menu-hover);
|
||||
background-color: var(--layout-menu-hover);
|
||||
}
|
||||
}
|
||||
|
||||
// 激活菜单项样式 - 只有文字变色,无背景色
|
||||
.el-menu-item.is-active {
|
||||
font-weight: 500;
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-dark-2)) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-dark-2)) !important;
|
||||
|
||||
.menu-icon {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-dark-2)) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-dark-2)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,44 +200,44 @@ html.dark {
|
||||
.el-sub-menu {
|
||||
// 当父菜单包含激活子菜单时的样式
|
||||
&.has-active-child .el-sub-menu__title {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-dark-2)) !important;
|
||||
background-color: var(--sidebar-active-bg) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-dark-2)) !important;
|
||||
background-color: var(--layout-sidebar-active-bg) !important;
|
||||
|
||||
.menu-icon {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-dark-2)) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-dark-2)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.has-active-child .el-sub-menu__title:hover {
|
||||
background-color: var(--sidebar-active-hover-bg) !important;
|
||||
background-color: var(--layout-sidebar-active-hover-bg) !important;
|
||||
}
|
||||
|
||||
// 深蓝色侧边栏配色下的父菜单激活状态
|
||||
html.sidebar-color-blue &.has-active-child .el-sub-menu__title {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-light-3)) !important;
|
||||
background-color: var(--sidebar-active-bg) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-light-3)) !important;
|
||||
background-color: var(--layout-sidebar-active-bg) !important;
|
||||
|
||||
.menu-icon {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-light-3)) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-light-3)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
html.sidebar-color-blue &.has-active-child .el-sub-menu__title:hover {
|
||||
background-color: var(--sidebar-active-hover-bg) !important;
|
||||
background-color: var(--layout-sidebar-active-hover-bg) !important;
|
||||
}
|
||||
|
||||
// 深色主题下的父菜单激活状态
|
||||
html.dark &.has-active-child .el-sub-menu__title {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-light-3)) !important;
|
||||
background-color: var(--sidebar-active-bg) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-light-3)) !important;
|
||||
background-color: var(--layout-sidebar-active-bg) !important;
|
||||
|
||||
.menu-icon {
|
||||
color: var(--sidebar-active-text-color, var(--el-color-primary-light-3)) !important;
|
||||
color: var(--layout-sidebar-active-text, var(--el-color-primary-light-3)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark &.has-active-child .el-sub-menu__title:hover {
|
||||
background-color: var(--sidebar-active-hover-bg) !important;
|
||||
background-color: var(--layout-sidebar-active-hover-bg) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,10 +26,7 @@ const isSidebarOpened = computed(() => appStore.sidebar.opened);
|
||||
|
||||
// 切换侧边栏展开/折叠状态
|
||||
function toggleSideBar() {
|
||||
console.log("🔄 Hamburger clicked! Current state:", isSidebarOpened.value);
|
||||
console.log("🔄 Device type:", appStore.device);
|
||||
appStore.toggleSidebar();
|
||||
console.log("🔄 New state:", appStore.sidebar.opened);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ const layoutOptions: LayoutOption[] = [
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
// 主题颜色选择器相关
|
||||
const displayColorPresets = computed(() => themeColorPresets.slice(0, 7)); // 只显示前9个预设颜色
|
||||
const displayColorPresets = computed(() => themeColorPresets.slice(0, 9)); // 只显示前9个预设颜色
|
||||
const allColorPresets = themeColorPresets; // 所有颜色预设,用于自定义颜色选择器
|
||||
|
||||
const isDark = ref<boolean>(settingsStore.theme === ThemeMode.DARK);
|
||||
@@ -651,11 +651,11 @@ const handleCloseDrawer = () => {
|
||||
/* 主题颜色选择器样式 */
|
||||
.theme-color-selector {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
align-items: stretch;
|
||||
|
||||
.color-label {
|
||||
flex-shrink: 0;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
|
||||
@@ -785,10 +785,11 @@ onUnmounted(() => {
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: $tags-view-height;
|
||||
background-color: var(--bg-primary);
|
||||
border-top: 1px solid var(--el-border-color-light);
|
||||
border-bottom: 1px solid var(--el-border-color-light);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
|
||||
/* 与 theme.ts layoutTagsBg 一致;介于顶栏与主内容之间的桥接层 */
|
||||
background-color: var(--layout-tags-bg, var(--el-bg-color-overlay));
|
||||
border-top: 1px solid var(--layout-tags-border);
|
||||
border-bottom: 1px solid var(--layout-tags-border);
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
@@ -797,11 +798,11 @@ onUnmounted(() => {
|
||||
width: $tags-view-height;
|
||||
height: $tags-view-height;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border: 1px solid var(--layout-tags-border);
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
background-color: var(--el-fill-color-light);
|
||||
background-color: var(--layout-tags-item-hover-bg, var(--layout-tags-item-bg));
|
||||
|
||||
.el-icon {
|
||||
transform: scale(1.1);
|
||||
@@ -826,12 +827,24 @@ onUnmounted(() => {
|
||||
padding: 0 8px;
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
line-height: 26px;
|
||||
color: var(--el-text-color-primary);
|
||||
background: var(--el-bg-color);
|
||||
border: 1px solid var(--el-border-color);
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
color: var(--layout-tags-item-text);
|
||||
background: var(--layout-tags-item-bg);
|
||||
border: 1px solid var(--layout-tags-border);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
/* 与激活态同宽占位,避免仅 active 有圆点导致整条标签行垂直错位 */
|
||||
&::before {
|
||||
flex-shrink: 0;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 6px;
|
||||
content: "";
|
||||
background: transparent;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 5px;
|
||||
}
|
||||
@@ -839,13 +852,19 @@ onUnmounted(() => {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-fill-color);
|
||||
&:hover:not(.active) {
|
||||
background-color: var(--layout-tags-item-hover-bg, var(--layout-tags-item-bg));
|
||||
border-color: var(--layout-tags-item-hover-border, var(--layout-tags-border));
|
||||
}
|
||||
|
||||
:deep(.el-dropdown) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.tag-close-btn {
|
||||
@@ -869,21 +888,16 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--layout-tags-item-active-bg);
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
&::before {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 2px;
|
||||
content: "";
|
||||
background: var(--el-color-primary);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
color: var(--layout-tags-item-active-text);
|
||||
}
|
||||
|
||||
.tag-close-btn {
|
||||
|
||||
@@ -55,7 +55,7 @@ const { routes } = useLayoutMenu();
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
width: $sidebar-width;
|
||||
background-color: var(--menu-background);
|
||||
background-color: var(--layout-sidebar-bg);
|
||||
transition: width 0.28s;
|
||||
|
||||
&--collapsed {
|
||||
@@ -65,7 +65,7 @@ const { routes } = useLayoutMenu();
|
||||
.layout-sidebar {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background-color: var(--menu-background);
|
||||
background-color: var(--layout-sidebar-bg);
|
||||
transition: width 0.28s;
|
||||
|
||||
&.has-logo {
|
||||
@@ -95,7 +95,9 @@ const { routes } = useLayoutMenu();
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 9;
|
||||
background-color: var(--bg-secondary);
|
||||
color: var(--layout-header-text);
|
||||
background-color: var(--layout-header-bg);
|
||||
border-bottom: 1px solid var(--layout-header-border);
|
||||
transition: width 0.28s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
:collapse="!isSidebarOpen"
|
||||
:collapse-transition="false"
|
||||
:unique-opened="false"
|
||||
:background-color="variables['menu-background']"
|
||||
:text-color="variables['menu-text']"
|
||||
:active-text-color="variables['menu-active-text']"
|
||||
background-color="var(--layout-menu-bg)"
|
||||
text-color="var(--layout-menu-text)"
|
||||
active-text-color="var(--layout-menu-active-text)"
|
||||
>
|
||||
<MenuItem
|
||||
v-for="item in sideMenuRoutes"
|
||||
@@ -70,7 +70,6 @@ import TagsView from "../components/TagsView/index.vue";
|
||||
import AppMain from "../components/AppMain/index.vue";
|
||||
import MenuItem from "../components/Menu/components/MenuItem.vue";
|
||||
import Hamburger from "@/components/Hamburger/index.vue";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
import { isExternal } from "@/utils/index";
|
||||
import { computed, watch } from "vue";
|
||||
import { useAppStore, usePermissionStore } from "@/store";
|
||||
@@ -148,7 +147,9 @@ watch(
|
||||
z-index: 999;
|
||||
width: 100%;
|
||||
height: $navbar-height;
|
||||
background-color: var(--menu-background);
|
||||
color: var(--layout-header-text);
|
||||
background-color: var(--layout-header-bg);
|
||||
border-bottom: 1px solid var(--layout-header-border);
|
||||
|
||||
&-content {
|
||||
display: flex;
|
||||
@@ -190,8 +191,9 @@ watch(
|
||||
border-bottom: none;
|
||||
|
||||
&.is-active {
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
border-bottom: 2px solid var(--el-color-primary);
|
||||
color: var(--layout-menu-active-text);
|
||||
background-color: var(--layout-menu-active-bg);
|
||||
border-bottom: 2px solid var(--layout-menu-active-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,7 +216,7 @@ watch(
|
||||
position: relative;
|
||||
width: $sidebar-width;
|
||||
height: 100%;
|
||||
background-color: var(--menu-background);
|
||||
background-color: var(--layout-menu-bg);
|
||||
transition: width 0.28s;
|
||||
|
||||
&.layout__sidebar--collapsed {
|
||||
@@ -239,7 +241,7 @@ watch(
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background-color: var(--menu-background);
|
||||
background-color: var(--layout-menu-bg);
|
||||
box-shadow: 0 0 6px -2px var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
@@ -250,6 +252,7 @@ watch(
|
||||
height: 100%;
|
||||
margin-left: 0;
|
||||
overflow-y: auto;
|
||||
background-color: var(--layout-content-canvas, var(--layout-content-bg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,9 @@ const isLogoCollapsed = computed(() => width.value < 768);
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: $navbar-height;
|
||||
background-color: var(--menu-background);
|
||||
color: var(--layout-header-text);
|
||||
background-color: var(--layout-header-bg);
|
||||
border-bottom: 1px solid var(--layout-header-border);
|
||||
|
||||
&-left {
|
||||
display: flex;
|
||||
@@ -124,11 +126,11 @@ const isLogoCollapsed = computed(() => width.value < 768);
|
||||
|
||||
&.has-active-child {
|
||||
.el-sub-menu__title {
|
||||
color: var(--el-color-primary) !important;
|
||||
border-bottom: 2px solid var(--el-color-primary) !important;
|
||||
color: var(--layout-menu-active-text) !important;
|
||||
border-bottom: 2px solid var(--layout-menu-active-text) !important;
|
||||
|
||||
.menu-icon {
|
||||
color: var(--el-color-primary) !important;
|
||||
color: var(--layout-menu-active-text) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,6 +154,7 @@ const isLogoCollapsed = computed(() => width.value < 768);
|
||||
&__main {
|
||||
height: calc(100vh - $navbar-height);
|
||||
overflow-y: auto;
|
||||
background-color: var(--layout-content-canvas, var(--layout-content-bg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { createTerminal } from "vue-web-terminal";
|
||||
import "element-plus/theme-chalk/dark/css-vars.css";
|
||||
import "element-plus/dist/index.css";
|
||||
// 主题变量(包含亮色和暗黑模式)
|
||||
import "@/styles/index.scss";
|
||||
import "./styles/index.scss";
|
||||
|
||||
import "uno.css";
|
||||
|
||||
|
||||
@@ -66,64 +66,13 @@ export const defaultSettings: AppSettings = {
|
||||
*/
|
||||
export const themeColorPresets = [
|
||||
// ==================== 精选推荐 - 最受欢迎的颜色 ====================
|
||||
"#5dc0ff", // 淡蓝色 - 清新明亮,亮暗主题皆宜
|
||||
"#3b82f6", // 现代蓝 - 默认主题色,专业稳重
|
||||
"#5dc0ff", // 淡蓝色 - 清新明亮,亮暗主题皆宜
|
||||
"#10b981", // 翡翠绿 - 清新自然,活力健康
|
||||
"#8b5cf6", // 紫罗兰 - 创意优雅,现代时尚
|
||||
"#f59e0b", // 琥珀橙 - 温暖活力,积极向上
|
||||
"#06b6d4", // 青蓝色 - 科技清新,年轻活力
|
||||
"#ef4444", // 鲜红色 - 醒目强烈,热情奔放
|
||||
"#ec4899", // 玫瑰粉 - 浪漫温馨,时尚个性
|
||||
"#14b8a6", // 青绿色 - 清新自然,平和舒适
|
||||
|
||||
// ==================== 蓝色系 - 科技与专业 ====================
|
||||
"#60a5fa", // 天空蓝 - 清新明亮,轻松愉悦
|
||||
"#3b82f6", // 现代蓝 - 专业稳重,值得信赖
|
||||
"#2563eb", // 深蓝色 - 商务专业,稳重大气
|
||||
"#1d4ed8", // 皇家蓝 - 高端商务,权威专业
|
||||
"#1e40af", // 深海蓝 - 商务精英,深沉内敛
|
||||
|
||||
// ==================== 绿色系 - 自然与活力 ====================
|
||||
"#34d399", // 浅绿色 - 清新明亮,生机盎然
|
||||
"#10b981", // 翡翠绿 - 清新自然,活力健康
|
||||
"#22c55e", // 草绿色 - 健康活力,积极向上
|
||||
"#16a34a", // 森林绿 - 生态环保,自然和谐
|
||||
"#15803d", // 深绿色 - 稳重大气,成熟稳重
|
||||
|
||||
// ==================== 紫色系 - 创意与优雅 ====================
|
||||
"#a78bfa", // 浅紫色 - 时尚现代,温柔浪漫
|
||||
"#8b5cf6", // 紫罗兰 - 创意优雅,现代时尚
|
||||
"#7c3aed", // 葡萄紫 - 创意无限,神秘优雅
|
||||
"#6d28d9", // 深紫色 - 神秘高端,独特个性
|
||||
"#5b21b6", // 皇家紫 - 王者风范,尊贵典雅
|
||||
|
||||
// ==================== 橙色系 - 温暖与活力 ====================
|
||||
"#fb923c", // 浅橙色 - 温暖亲切,阳光开朗
|
||||
"#f59e0b", // 琥珀橙 - 温暖活力,积极向上
|
||||
"#f97316", // 火橙色 - 热情奔放,活力四射
|
||||
"#ea580c", // 深橙色 - 阳光活力,热情洋溢
|
||||
|
||||
// ==================== 青色系 - 科技与清新 ====================
|
||||
"#22d3ee", // 浅青色 - 清新明亮,年轻活力
|
||||
"#06b6d4", // 青蓝色 - 科技清新,年轻活力
|
||||
"#14b8a6", // 青绿色 - 清新自然,平和舒适
|
||||
"#0891b2", // 天蓝色 - 清新自然,专业科技
|
||||
"#0e7490", // 深青色 - 专业科技,沉稳内敛
|
||||
|
||||
// ==================== 红色系 - 激情与警示 ====================
|
||||
"#f87171", // 浅红色 - 柔和温暖,亲和力强
|
||||
"#ef4444", // 鲜红色 - 醒目强烈,热情奔放
|
||||
"#dc2626", // 猩红色 - 激情四射,力量感强
|
||||
"#b91c1c", // 深红色 - 庄重严肃,权威感强
|
||||
|
||||
// ==================== 粉色系 - 温柔与时尚 ====================
|
||||
"#f472b6", // 浅粉色 - 柔美可爱,青春活力
|
||||
"#ec4899", // 玫瑰粉 - 浪漫温馨,时尚个性
|
||||
"#db2777", // 玫瑰红 - 浪漫优雅,热情奔放
|
||||
"#be185d", // 深粉色 - 高贵典雅,成熟魅力
|
||||
|
||||
// ==================== 灰色系 - 简约与现代 ====================
|
||||
"#9ca3af", // 浅灰色 - 简约现代,低调内敛
|
||||
"#6b7280", // 经典灰 - 中性稳重,专业可靠
|
||||
"#4b5563", // 深灰色 - 商务专业,成熟稳重
|
||||
];
|
||||
|
||||
@@ -98,7 +98,6 @@ export const useSettingsStore = defineStore("setting", () => {
|
||||
const themeColor = useStorage<string>(SETTINGS_KEYS.THEME_COLOR, defaultSettings.themeColor);
|
||||
// 主题模式
|
||||
const theme = useStorage<ThemeMode>(SETTINGS_KEYS.THEME, defaultSettings.theme);
|
||||
|
||||
// 是否开启灰色模式
|
||||
const grayMode = useStorage<boolean>(SETTINGS_KEYS.GRAY_MODE, defaultSettings.grayMode);
|
||||
// 是否开启AI助手
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
/* 暗黑模式通过 CSS 自定义变量,官方链接:https://element-plus.org/zh-CN/guide/dark-mode.html#%E9%80%9A%E8%BF%87-css */
|
||||
/**
|
||||
* Element Plus 主题最小回退变量(合并版)
|
||||
*
|
||||
* === 配色层级(同一主色:哪里深、哪里浅)===
|
||||
* L0 页面画布:--el-bg-color / --el-bg-color-page / --layout-content-canvas(最浅透气,大面积)
|
||||
* L1 内容区块:--layout-content-bg(与 L0 略分阶)
|
||||
* L2 卡片/表格容器面:--el-bg-color-overlay(抬升中性面)
|
||||
* L3 表头/侧栏条:color-mix(primary, fill) 明显高于 L2(表格见下文「表格」)
|
||||
* L4 浮层(下拉/弹窗):面板底 = overlay,不用整板灌主色;强调在选项/按钮/focus
|
||||
* L5 再嵌套浅填充:--el-fill-color-light(hover 槽、禁用底等)
|
||||
* 标签栏 TagsView:介于顶栏与内容区 — 整条背景 = --layout-tags-bg(theme.ts blend);pill 默认/激活
|
||||
* = --layout-tags-item-bg / --layout-tags-item-active-*;非激活 hover = 下文 --layout-tags-item-hover-*
|
||||
* 主色强度:点线控件(按钮、focus、选中字)用实色 primary;面状 hover/范围/斑马只用 color-mix 低比例
|
||||
*
|
||||
* === 本文区块 ===
|
||||
* :root 亮色 / html.dark 暗色 / 运行时 theme.ts 覆盖
|
||||
* 弹层、浮层 Popper、Select 选项、DatePicker 范围、级联、表格见对应注释
|
||||
* 其余排期:Message、图表取 CSS 变量、登录全屏页;Tabs border-card 顶条 / Steps simple / Progress 轨道见下文
|
||||
*/
|
||||
|
||||
:root {
|
||||
/* 品牌与语义 */
|
||||
--el-color-primary: #1677ff;
|
||||
--el-color-success: #10b981;
|
||||
--el-color-warning: #f59e0b;
|
||||
--el-color-danger: #ef4444;
|
||||
--el-color-info: #2f86ff;
|
||||
|
||||
/* 基础中性色 */
|
||||
--el-bg-color: #f5f7fb;
|
||||
--el-bg-color-page: #f5f7fb;
|
||||
--el-bg-color-overlay: #ffffff;
|
||||
--el-fill-color: #eef3fb;
|
||||
--el-fill-color-light: #f7f9fd;
|
||||
--el-border-color: #d8e2f0;
|
||||
--el-border-color-light: #e7edf5;
|
||||
--el-text-color-primary: #0f172a;
|
||||
--el-text-color-regular: #334155;
|
||||
--el-text-color-secondary: #64748b;
|
||||
--el-text-color-placeholder: #94a3b8;
|
||||
|
||||
/* 阴影/遮罩 */
|
||||
--el-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
--el-box-shadow-light: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-overlay-color: rgba(15, 23, 42, 0.5);
|
||||
--el-overlay-color-light: rgba(15, 23, 42, 0.3);
|
||||
--el-overlay-color-lighter: rgba(15, 23, 42, 0.15);
|
||||
|
||||
/* 菜单 hover 兼容 */
|
||||
--el-menu-hover-bg-color: #f3f6fb;
|
||||
|
||||
/* 主内容区画布:组件间隙可见区域,随 --el-color-primary / --el-bg-color-page(theme.ts)变化 */
|
||||
--layout-content-canvas: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 3.5%,
|
||||
var(--el-bg-color-page)
|
||||
);
|
||||
/* 搜索区等与间隙呼应的分割线 */
|
||||
--layout-block-border-themed: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 18%,
|
||||
var(--el-border-color-light)
|
||||
);
|
||||
|
||||
/* TagsView:未激活标签 hover(theme 只算默认/激活底,hover 在此补主色透气) */
|
||||
--layout-tags-item-hover-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 9%,
|
||||
var(--layout-tags-item-bg)
|
||||
);
|
||||
--layout-tags-item-hover-border: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 22%,
|
||||
var(--layout-tags-border)
|
||||
);
|
||||
|
||||
/* Select / TreeSelect 选项行(EP 默认 hover=fill-light、选中无底,与主题脱节) */
|
||||
--el-select-option-hover-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 11%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
--el-select-option-selected-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 18%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
|
||||
/* DatePicker 区间内底(EP 默认 inrange≈极浅灰,与主题脱节) */
|
||||
--el-datepicker-range-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 10%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
--el-datepicker-range-hover-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 16%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
|
||||
/*
|
||||
* 弹层
|
||||
* - 遮罩:--el-overlay-color
|
||||
* - 面板底:纯中性 overlay(不要混主色);主题色交给内部 primary 按钮、表单 focus、链接等
|
||||
* - Drawer 继承 --el-dialog-bg-color;Dialog 见下方 html .el-dialog(压过 EP 的 var(--el-bg-color))
|
||||
*/
|
||||
--el-dialog-bg-color: var(--el-bg-color-overlay);
|
||||
--el-popover-bg-color: var(--el-dialog-bg-color);
|
||||
--el-popup-modal-bg-color: var(--el-overlay-color);
|
||||
--el-popup-modal-opacity: 1;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
/* 品牌与语义 */
|
||||
--el-color-primary: #1677ff;
|
||||
--el-color-success: #10b981;
|
||||
--el-color-warning: #f59e0b;
|
||||
--el-color-danger: #ef4444;
|
||||
--el-color-info: #2f86ff;
|
||||
|
||||
/* 基础中性色 */
|
||||
--el-bg-color: #0b1220;
|
||||
--el-bg-color-page: #0b1220;
|
||||
--el-bg-color-overlay: #111a2c;
|
||||
--el-fill-color: #141f33;
|
||||
--el-fill-color-light: #1b2a45;
|
||||
--el-border-color: #253858;
|
||||
--el-border-color-light: #31486b;
|
||||
--el-text-color-primary: #f8fafc;
|
||||
--el-text-color-regular: #e2e8f0;
|
||||
--el-text-color-secondary: #94a3b8;
|
||||
--el-text-color-placeholder: #64748b;
|
||||
|
||||
/* 阴影/遮罩 */
|
||||
--el-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24);
|
||||
--el-box-shadow-light: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-overlay-color: rgba(0, 0, 0, 0.7);
|
||||
--el-overlay-color-light: rgba(0, 0, 0, 0.5);
|
||||
--el-overlay-color-lighter: rgba(0, 0, 0, 0.3);
|
||||
|
||||
/* 菜单 hover 兼容 */
|
||||
--el-menu-hover-bg-color: #1b2a45;
|
||||
|
||||
--layout-content-canvas: color-mix(in srgb, var(--el-color-primary) 7%, var(--el-bg-color-page));
|
||||
--layout-block-border-themed: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 24%,
|
||||
var(--el-border-color-light)
|
||||
);
|
||||
|
||||
--layout-tags-item-hover-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 14%,
|
||||
var(--layout-tags-item-bg)
|
||||
);
|
||||
--layout-tags-item-hover-border: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 30%,
|
||||
var(--layout-tags-border)
|
||||
);
|
||||
|
||||
--el-select-option-hover-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 14%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
--el-select-option-selected-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 24%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
|
||||
--el-datepicker-range-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 13%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
--el-datepicker-range-hover-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 20%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
|
||||
--el-dialog-bg-color: var(--el-bg-color-overlay);
|
||||
--el-popover-bg-color: var(--el-dialog-bg-color);
|
||||
--el-popup-modal-bg-color: var(--el-overlay-color);
|
||||
--el-popup-modal-opacity: 1;
|
||||
}
|
||||
|
||||
/* Dialog:EP 在 .el-dialog 上写死 --el-dialog-bg-color: var(--el-bg-color),改为抬升中性底 */
|
||||
html .el-dialog {
|
||||
--el-dialog-bg-color: var(--el-bg-color-overlay);
|
||||
}
|
||||
|
||||
/*
|
||||
* 浮层 Popper(与弹窗同一 token:--el-dialog-bg-color,现为中性 overlay)
|
||||
* EP 部分组件写死 --el-bg-color-overlay;显式统一到 --el-dialog-bg-color 便于后续改一处全局同步。
|
||||
*/
|
||||
html .el-cascader {
|
||||
--el-cascader-menu-fill: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
html .el-mention {
|
||||
--el-mention-bg-color: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
html .el-select__popper.el-popper,
|
||||
html .el-tree-select__popper.el-popper,
|
||||
html .el-dropdown__popper.el-popper,
|
||||
html .el-autocomplete__popper.el-popper,
|
||||
html .el-mention__popper.el-popper,
|
||||
html .el-picker__popper.el-popper {
|
||||
background: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
html .el-select__popper.el-popper .el-popper__arrow:before,
|
||||
html .el-tree-select__popper.el-popper .el-popper__arrow:before,
|
||||
html .el-dropdown__popper.el-popper .el-popper__arrow:before,
|
||||
html .el-autocomplete__popper.el-popper .el-popper__arrow:before,
|
||||
html .el-mention__popper.el-popper .el-popper__arrow:before,
|
||||
html .el-picker__popper.el-popper .el-popper__arrow:before {
|
||||
background: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
html .el-picker-panel {
|
||||
background: var(--el-dialog-bg-color);
|
||||
--el-datepicker-inrange-bg-color: var(--el-datepicker-range-bg);
|
||||
--el-datepicker-inrange-hover-bg-color: var(--el-datepicker-range-hover-bg);
|
||||
}
|
||||
|
||||
html .el-dropdown-menu {
|
||||
background-color: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
html .el-color-picker-panel {
|
||||
background: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
html .el-transfer-panel {
|
||||
background: var(--el-dialog-bg-color);
|
||||
}
|
||||
|
||||
/* Select / TreeSelect:选项 hover、选中背景随主色(浮层底仍为 overlay) */
|
||||
html .el-select__popper .el-select-dropdown__item.is-hovering,
|
||||
html .el-tree-select__popper .el-select-dropdown__item.is-hovering {
|
||||
background-color: var(--el-select-option-hover-bg);
|
||||
}
|
||||
|
||||
html .el-select__popper .el-select-dropdown__item.is-selected,
|
||||
html .el-tree-select__popper .el-select-dropdown__item.is-selected {
|
||||
background-color: var(--el-select-option-selected-bg);
|
||||
}
|
||||
|
||||
/* 级联面板节点 hover 与 Select 一致(面板内自带 --el-cascader-node-background-hover) */
|
||||
html .el-cascader-panel {
|
||||
--el-cascader-node-background-hover: var(--el-select-option-hover-bg);
|
||||
}
|
||||
|
||||
/* Skeleton 动画条:终点色带一点主色,避免纯灰与整站脱节 */
|
||||
html .el-skeleton {
|
||||
--el-skeleton-to-color: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 12%,
|
||||
var(--el-fill-color-darker)
|
||||
);
|
||||
}
|
||||
|
||||
/* Tabs border-card:顶栏略混主色(active 条与字仍用 EP 的 --el-color-primary) */
|
||||
html .el-tabs--border-card > .el-tabs__header {
|
||||
background: color-mix(in srgb, var(--el-color-primary) 5%, var(--el-fill-color-light));
|
||||
}
|
||||
|
||||
html.dark .el-tabs--border-card > .el-tabs__header {
|
||||
background: color-mix(in srgb, var(--el-color-primary) 8%, var(--el-fill-color));
|
||||
}
|
||||
|
||||
/* Steps 简约模式底条 */
|
||||
html .el-steps--simple {
|
||||
background: color-mix(in srgb, var(--el-color-primary) 6%, var(--el-fill-color-light));
|
||||
}
|
||||
|
||||
html.dark .el-steps--simple {
|
||||
background: color-mix(in srgb, var(--el-color-primary) 9%, var(--el-fill-color));
|
||||
}
|
||||
|
||||
/* Progress:轨道由极浅灰改为主色轻混,与已填充段同一系 */
|
||||
html .el-progress-bar__outer {
|
||||
background-color: color-mix(in srgb, var(--el-color-primary) 8%, var(--el-fill-color-light));
|
||||
}
|
||||
|
||||
html.dark .el-progress-bar__outer {
|
||||
background-color: color-mix(in srgb, var(--el-color-primary) 11%, var(--el-fill-color-darker));
|
||||
}
|
||||
|
||||
/* ---------- Element Plus 表格(随 :root / html.dark 与 theme.ts 主色变) ---------- */
|
||||
html .el-table {
|
||||
--el-table-bg-color: var(--el-bg-color-overlay);
|
||||
--el-table-tr-bg-color: var(--el-bg-color-overlay);
|
||||
--el-table-header-bg-color: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 28%,
|
||||
var(--el-fill-color-light)
|
||||
);
|
||||
--el-table-striped-row-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 12%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
--el-table-row-hover-bg-color: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 5%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
}
|
||||
|
||||
html.dark .el-table {
|
||||
--el-table-header-bg-color: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 24%,
|
||||
var(--el-fill-color-light)
|
||||
);
|
||||
--el-table-striped-row-bg: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 14%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
--el-table-row-hover-bg-color: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 7%,
|
||||
var(--el-bg-color-overlay)
|
||||
);
|
||||
}
|
||||
|
||||
html .el-table.el-table--striped {
|
||||
--el-fill-color-lighter: var(--el-table-striped-row-bg);
|
||||
}
|
||||
|
||||
html .el-table .el-table__body tr.hover-row > td.el-table__cell.el-table-fixed-column--left,
|
||||
html .el-table .el-table__body tr.hover-row > td.el-table__cell.el-table-fixed-column--right {
|
||||
background-color: var(--el-table-row-hover-bg-color) !important;
|
||||
}
|
||||
|
||||
html
|
||||
.el-table.el-table--striped
|
||||
.el-table__body
|
||||
tr:not(.el-table__row--striped)
|
||||
> td.el-table__cell.el-table-fixed-column--left,
|
||||
html
|
||||
.el-table.el-table--striped
|
||||
.el-table__body
|
||||
tr:not(.el-table__row--striped)
|
||||
> td.el-table__cell.el-table-fixed-column--right {
|
||||
background-color: var(--el-table-tr-bg-color) !important;
|
||||
}
|
||||
|
||||
html .el-table .el-table__header-wrapper tr th.el-table-fixed-column--left,
|
||||
html .el-table .el-table__header-wrapper tr th.el-table-fixed-column--right {
|
||||
background-color: var(--el-table-header-bg-color) !important;
|
||||
}
|
||||
|
||||
html .el-table td.el-table__fixed-right-patch,
|
||||
html .el-table th.el-table__fixed-right-patch {
|
||||
background-color: var(--el-table-bg-color) !important;
|
||||
}
|
||||
@@ -2,11 +2,8 @@
|
||||
// 1. 项目自定义变量(侧边栏、布局等)
|
||||
@use "./variables";
|
||||
|
||||
// 2. Element Plus 亮色模式变量
|
||||
@use "./theme/element-light";
|
||||
|
||||
// 3. Element Plus 暗黑模式变量
|
||||
@use "./theme/element-dark";
|
||||
// 2. 暗黑模式变量(合并)
|
||||
@use "./dark/css-vars";
|
||||
|
||||
// ==================== 基础样式 ====================
|
||||
@use "./reset";
|
||||
@@ -22,41 +19,99 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
// 主滚动区域滚动条与主题弱对齐(Firefox scrollbar-color + WebKit)
|
||||
html,
|
||||
.app-main,
|
||||
.layout__main,
|
||||
.chat-messages {
|
||||
scrollbar-color: color-mix(in srgb, var(--el-color-primary) 32%, var(--el-border-color))
|
||||
var(--el-fill-color-light);
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
html.dark,
|
||||
html.dark .app-main,
|
||||
html.dark .layout__main,
|
||||
html.dark .chat-messages {
|
||||
scrollbar-color: color-mix(in srgb, var(--el-color-primary) 26%, var(--el-border-color-light))
|
||||
var(--el-bg-color);
|
||||
}
|
||||
|
||||
.app-main,
|
||||
.layout__main,
|
||||
.chat-messages {
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--el-fill-color-light);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: color-mix(in srgb, var(--el-color-primary) 30%, var(--el-border-color));
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background-color: color-mix(in srgb, var(--el-color-primary) 42%, var(--el-border-color));
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .app-main,
|
||||
html.dark .layout__main,
|
||||
html.dark .chat-messages {
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条颜色
|
||||
#nprogress .bar {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
// ==================== 混合布局左侧菜单的hover样式 ====================
|
||||
.layout__sidebar .el-menu {
|
||||
.el-menu-item:hover,
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: var(--layout-sidebar-hover, #f3f6fb) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-mix .layout__sidebar--left .el-menu {
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
// 极简白主题:使用浅灰色背景
|
||||
background-color: var(--el-fill-color-light) !important;
|
||||
background-color: var(--layout-menu-hover, var(--el-fill-color-light)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu__title {
|
||||
&:hover {
|
||||
// 极简白主题:使用浅灰色背景
|
||||
background-color: var(--el-fill-color-light) !important;
|
||||
background-color: var(--layout-menu-hover, var(--el-fill-color-light)) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .layout__sidebar .el-menu {
|
||||
.el-menu-item:hover,
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: var(--layout-sidebar-hover, #1b2a45) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 深色主题下的左侧菜单hover样式
|
||||
html.dark .layout-mix .layout__sidebar--left .el-menu {
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
// 深色背景:使用CSS变量
|
||||
background-color: var(--menu-hover) !important;
|
||||
background-color: var(--layout-sidebar-hover, #1b2a45) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu__title {
|
||||
&:hover {
|
||||
// 深色背景:使用CSS变量
|
||||
background-color: var(--menu-hover) !important;
|
||||
background-color: var(--layout-sidebar-hover, #1b2a45) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,7 +146,7 @@ html.dark .layout-mix .layout__sidebar--left .el-menu {
|
||||
.search-container {
|
||||
padding: 18px 16px 0;
|
||||
margin-top: 16px;
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border: 1px solid var(--layout-block-border-themed, var(--el-border-color-light));
|
||||
|
||||
.search-buttons {
|
||||
margin-right: 0;
|
||||
|
||||
@@ -1,343 +0,0 @@
|
||||
/**
|
||||
* Element Plus 暗黑模式主题变量
|
||||
*
|
||||
* 注意:主题色变体(light-1 到 light-9, dark-2)由 theme.ts 动态生成
|
||||
* 此文件仅提供默认基础值和组件特定样式
|
||||
*/
|
||||
|
||||
html.dark {
|
||||
--el-color-primary: #3b82f6;
|
||||
--el-color-success: #10b981;
|
||||
--el-color-warning: #f59e0b;
|
||||
--el-color-danger: #ef4444;
|
||||
--el-color-info: #64748b;
|
||||
|
||||
--el-bg-color: #020617;
|
||||
--el-bg-color-page: #020617;
|
||||
--el-bg-color-overlay: #0f172a;
|
||||
--el-fill-color-blank: #020617;
|
||||
|
||||
--el-fill-color: #0f172a;
|
||||
--el-fill-color-light: #1e293b;
|
||||
--el-fill-color-lighter: #0f172a;
|
||||
--el-fill-color-extra-light: #020617;
|
||||
--el-fill-color-dark: #334155;
|
||||
--el-fill-color-darker: #475569;
|
||||
|
||||
--el-text-color-primary: #f8fafc;
|
||||
--el-text-color-regular: #e2e8f0;
|
||||
--el-text-color-secondary: #94a3b8;
|
||||
--el-text-color-placeholder: #64748b;
|
||||
|
||||
--el-border-color: #1e293b;
|
||||
--el-border-color-light: #334155;
|
||||
--el-border-color-lighter: #475569;
|
||||
--el-border-color-extra-light: #64748b;
|
||||
--el-border-color-dark: #0f172a;
|
||||
--el-border-color-darker: #020617;
|
||||
|
||||
--el-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24);
|
||||
--el-box-shadow-light: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-box-shadow-lighter: 0 1px 1px 0 rgba(0, 0, 0, 0.12);
|
||||
--el-box-shadow-dark: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.24);
|
||||
|
||||
--el-disabled-bg-color: #0f172a;
|
||||
--el-disabled-text-color: #475569;
|
||||
--el-disabled-border-color: #1e293b;
|
||||
|
||||
--el-overlay-color: rgba(0, 0, 0, 0.7);
|
||||
--el-overlay-color-light: rgba(0, 0, 0, 0.5);
|
||||
--el-overlay-color-lighter: rgba(0, 0, 0, 0.3);
|
||||
|
||||
--el-scrollbar-bg-color: #0f172a;
|
||||
--el-scrollbar-thumb-color: #334155;
|
||||
--el-scrollbar-thumb-hover-color: #475569;
|
||||
|
||||
--el-table-bg-color: var(--el-fill-color-extra-light);
|
||||
--el-table-tr-bg-color: var(--el-fill-color-extra-light);
|
||||
--el-table-header-bg-color: var(--el-fill-color-light);
|
||||
--el-table-row-hover-bg-color: var(--el-fill-color);
|
||||
--el-table-border-color: var(--el-border-color);
|
||||
|
||||
--el-dialog-width: 50%;
|
||||
--el-dialog-margin-top: 15vh;
|
||||
--el-dialog-bg-color: var(--el-fill-color);
|
||||
--el-dialog-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24);
|
||||
--el-dialog-title-font-size: 18px;
|
||||
--el-dialog-content-font-size: 14px;
|
||||
--el-dialog-font-line-height: 1.5;
|
||||
--el-dialog-padding-primary: 16px;
|
||||
--el-dialog-border-radius: 4px;
|
||||
|
||||
--el-drawer-bg-color: var(--el-fill-color);
|
||||
--el-drawer-padding-primary: 20px;
|
||||
|
||||
--el-dropdown-menu-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-dropdown-menuItem-hover-fill: var(--el-fill-color-light);
|
||||
--el-dropdown-menuItem-hover-color: var(--el-color-primary);
|
||||
--el-dropdown-menu-index: 10;
|
||||
|
||||
--el-popover-bg-color: var(--el-fill-color);
|
||||
--el-popover-font-size: 14px;
|
||||
--el-popover-border-color: var(--el-border-color);
|
||||
--el-popover-padding: 12px;
|
||||
--el-popover-padding-large: 18px 20px;
|
||||
--el-popover-title-font-size: 16px;
|
||||
--el-popover-title-text-color: #f8fafc;
|
||||
--el-popover-border-radius: 4px;
|
||||
|
||||
--el-popper-border-radius: 4px;
|
||||
|
||||
--el-card-border-color: var(--el-border-color);
|
||||
--el-card-border-radius: 4px;
|
||||
--el-card-padding: 20px;
|
||||
--el-card-bg-color: var(--el-fill-color);
|
||||
|
||||
--el-badge-bg-color: var(--el-color-danger);
|
||||
--el-badge-radius: 10px;
|
||||
--el-badge-font-size: 12px;
|
||||
--el-badge-padding: 6px;
|
||||
--el-badge-size: 18px;
|
||||
|
||||
--el-segmented-color: #e2e8f0;
|
||||
--el-segmented-bg-color: var(--el-fill-color);
|
||||
--el-segmented-padding: 2px;
|
||||
--el-segmented-item-selected-color: #f8fafc;
|
||||
--el-segmented-item-selected-bg-color: var(--el-color-primary);
|
||||
--el-segmented-item-selected-disabled-bg-color: var(--el-fill-color);
|
||||
--el-segmented-item-hover-color: #f8fafc;
|
||||
--el-segmented-item-hover-bg-color: var(--el-fill-color-light);
|
||||
--el-segmented-item-active-bg-color: var(--el-fill-color-dark);
|
||||
--el-segmented-item-disabled-color: #64748b;
|
||||
|
||||
--el-tour-width: 520px;
|
||||
--el-tour-padding-primary: 12px;
|
||||
--el-tour-font-line-height: 1.5;
|
||||
--el-tour-title-font-size: 16px;
|
||||
--el-tour-title-text-color: #f8fafc;
|
||||
--el-tour-title-font-weight: 400;
|
||||
--el-tour-close-color: #94a3b8;
|
||||
--el-tour-font-size: 14px;
|
||||
--el-tour-color: #f8fafc;
|
||||
--el-tour-bg-color: var(--el-fill-color);
|
||||
--el-tour-border-radius: 4px;
|
||||
|
||||
--el-anchor-bg-color: var(--el-fill-color);
|
||||
--el-anchor-padding-indent: 14px;
|
||||
--el-anchor-line-height: 22px;
|
||||
--el-anchor-font-size: 12px;
|
||||
--el-anchor-color: #94a3b8;
|
||||
--el-anchor-active-color: var(--el-color-primary);
|
||||
--el-anchor-marker-bg-color: var(--el-color-primary);
|
||||
|
||||
--el-mention-font-size: 14px;
|
||||
--el-mention-bg-color: var(--el-fill-color);
|
||||
--el-mention-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-mention-border: 1px solid var(--el-border-color);
|
||||
--el-mention-option-color: #e2e8f0;
|
||||
--el-mention-option-height: 34px;
|
||||
--el-mention-option-min-width: 100px;
|
||||
--el-mention-option-hover-background: var(--el-fill-color-light);
|
||||
--el-mention-option-selected-color: var(--el-color-primary);
|
||||
--el-mention-option-disabled-color: #64748b;
|
||||
--el-mention-option-loading-color: #94a3b8;
|
||||
--el-mention-option-loading-padding: 10px 0;
|
||||
--el-mention-max-height: 174px;
|
||||
--el-mention-padding: 6px 0;
|
||||
--el-mention-header-padding: 10px;
|
||||
--el-mention-footer-padding: 10px;
|
||||
|
||||
--el-skeleton-color: var(--el-fill-color);
|
||||
--el-skeleton-to-color: var(--el-fill-color-dark);
|
||||
|
||||
--el-alert-padding: 8px 16px;
|
||||
--el-alert-border-radius-base: 4px;
|
||||
--el-alert-title-font-size: 14px;
|
||||
--el-alert-title-with-description-font-size: 16px;
|
||||
--el-alert-description-font-size: 14px;
|
||||
--el-alert-close-font-size: 16px;
|
||||
--el-alert-close-customed-font-size: 14px;
|
||||
--el-alert-icon-size: 16px;
|
||||
--el-alert-icon-large-size: 28px;
|
||||
|
||||
--el-messagebox-title-color: #f8fafc;
|
||||
--el-messagebox-width: 420px;
|
||||
--el-messagebox-border-radius: 4px;
|
||||
--el-messagebox-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24);
|
||||
--el-messagebox-font-size: 18px;
|
||||
--el-messagebox-content-font-size: 14px;
|
||||
--el-messagebox-content-color: #e2e8f0;
|
||||
--el-messagebox-error-font-size: 12px;
|
||||
--el-messagebox-padding-primary: 12px;
|
||||
--el-messagebox-font-line-height: 1.5;
|
||||
|
||||
--el-message-bg-color: var(--el-fill-color-light);
|
||||
--el-message-border-color: var(--el-border-color);
|
||||
--el-message-padding: 11px 15px;
|
||||
--el-message-close-size: 16px;
|
||||
--el-message-close-icon-color: #94a3b8;
|
||||
--el-message-close-hover-color: #64748b;
|
||||
|
||||
--el-notification-width: 330px;
|
||||
--el-notification-padding: 14px 26px 14px 13px;
|
||||
--el-notification-radius: 8px;
|
||||
--el-notification-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-notification-border-color: var(--el-border-color);
|
||||
--el-notification-icon-size: 24px;
|
||||
--el-notification-close-font-size: 16px;
|
||||
--el-notification-group-margin-left: 13px;
|
||||
--el-notification-group-margin-right: 8px;
|
||||
--el-notification-content-font-size: 14px;
|
||||
--el-notification-content-color: #e2e8f0;
|
||||
--el-notification-title-font-size: 16px;
|
||||
--el-notification-title-color: #f8fafc;
|
||||
--el-notification-close-color: #94a3b8;
|
||||
--el-notification-close-hover-color: #64748b;
|
||||
|
||||
--el-input-text-color: #e2e8f0;
|
||||
--el-input-border: 1px solid var(--el-border-color);
|
||||
--el-input-hover-border: 1px solid var(--el-border-color-light);
|
||||
--el-input-focus-border: 1px solid var(--el-color-primary);
|
||||
--el-input-transparent-border: 0 0 0 1px transparent inset;
|
||||
--el-input-border-color: var(--el-border-color);
|
||||
--el-input-border-radius: 4px;
|
||||
--el-input-bg-color: var(--el-fill-color);
|
||||
--el-input-icon-color: #64748b;
|
||||
--el-input-placeholder-color: #64748b;
|
||||
--el-input-hover-border-color: var(--el-border-color-light);
|
||||
--el-input-clear-hover-color: #94a3b8;
|
||||
--el-input-focus-border-color: var(--el-color-primary);
|
||||
--el-input-width: 100%;
|
||||
|
||||
--el-input-disabled-fill: var(--el-fill-color);
|
||||
--el-input-disabled-border: var(--el-border-color);
|
||||
--el-input-disabled-text-color: #64748b;
|
||||
--el-input-disabled-placeholder-color: #64748b;
|
||||
|
||||
--el-select-border-color-hover: var(--el-border-color-light);
|
||||
--el-select-disabled-color: #64748b;
|
||||
--el-select-disabled-border: var(--el-border-color);
|
||||
--el-select-font-size: 14px;
|
||||
--el-select-close-hover-color: #94a3b8;
|
||||
--el-select-input-color: #64748b;
|
||||
--el-select-multiple-input-color: #e2e8f0;
|
||||
--el-select-input-focus-border-color: var(--el-color-primary);
|
||||
--el-select-input-font-size: 14px;
|
||||
--el-select-width: 100%;
|
||||
|
||||
--el-select-option-text-color: #e2e8f0;
|
||||
--el-select-option-disabled-color: #64748b;
|
||||
--el-select-option-height: 34px;
|
||||
--el-select-option-hover-background: var(--el-fill-color-light);
|
||||
--el-select-option-selected-text-color: var(--el-color-primary);
|
||||
|
||||
--el-select-group-text-color: #94a3b8;
|
||||
--el-select-group-height: 34px;
|
||||
--el-select-group-font-size: 12px;
|
||||
|
||||
--el-select-dropdown-bg-color: var(--el-fill-color);
|
||||
--el-select-dropdown-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-select-dropdown-empty-color: #94a3b8;
|
||||
--el-select-dropdown-max-height: 274px;
|
||||
--el-select-dropdown-padding: 6px 0;
|
||||
--el-select-dropdown-empty-padding: 10px 0;
|
||||
--el-select-dropdown-header-padding: 10px;
|
||||
--el-select-dropdown-footer-padding: 10px;
|
||||
--el-select-dropdown-border: 1px solid var(--el-border-color);
|
||||
|
||||
--el-tag-font-size: 12px;
|
||||
--el-tag-border-radius: 4px;
|
||||
--el-tag-border-radius-rounded: 9999px;
|
||||
--el-tag-bg-color: var(--el-fill-color-light);
|
||||
--el-tag-border-color: var(--el-border-color);
|
||||
--el-tag-text-color: #e2e8f0;
|
||||
--el-tag-close-color: #94a3b8;
|
||||
--el-tag-close-hover-color: #64748b;
|
||||
|
||||
--el-button-font-weight: 500;
|
||||
--el-button-border-color: var(--el-border-color);
|
||||
--el-button-bg-color: var(--el-fill-color);
|
||||
--el-button-text-color: #e2e8f0;
|
||||
--el-button-disabled-text-color: #64748b;
|
||||
--el-button-disabled-bg-color: var(--el-fill-color);
|
||||
--el-button-disabled-border-color: var(--el-border-color);
|
||||
--el-button-divide-border-color: rgba(255, 255, 255, 0.1);
|
||||
|
||||
--el-tooltip-font-size: 12px;
|
||||
--el-tooltip-border-color: var(--el-border-color);
|
||||
--el-tooltip-fill: var(--el-fill-color-light);
|
||||
--el-tooltip-light-border-color: var(--el-border-color-light);
|
||||
--el-tooltip-light-fill: var(--el-fill-color);
|
||||
|
||||
--el-cascader-menu-text-color: #e2e8f0;
|
||||
--el-cascader-menu-selected-text-color: var(--el-color-primary);
|
||||
--el-cascader-menu-fill: var(--el-fill-color);
|
||||
--el-cascader-menu-font-size: 14px;
|
||||
--el-cascader-menu-radius: 4px;
|
||||
--el-cascader-menu-border: solid 1px var(--el-border-color);
|
||||
--el-cascader-menu-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
--el-cascader-node-background-hover: var(--el-fill-color-light);
|
||||
--el-cascader-node-color-disabled: #64748b;
|
||||
--el-cascader-color-empty: #64748b;
|
||||
--el-cascader-tag-background: var(--el-fill-color-light);
|
||||
|
||||
--el-statistic-title-font-weight: 400;
|
||||
--el-statistic-title-font-size: 12px;
|
||||
--el-statistic-title-color: #e2e8f0;
|
||||
--el-statistic-content-font-weight: 400;
|
||||
--el-statistic-content-font-size: 24px;
|
||||
--el-statistic-content-color: #f8fafc;
|
||||
|
||||
--el-switch-on-color: var(--el-color-primary);
|
||||
--el-switch-off-color: #1e293b;
|
||||
|
||||
--el-loading-spinner-size: 42px;
|
||||
--el-loading-fullscreen-spinner-size: 50px;
|
||||
--el-loading-text-color: var(--el-color-primary);
|
||||
|
||||
--el-progress-default-color: var(--el-color-primary);
|
||||
--el-progress-inside-text-color: #f8fafc;
|
||||
|
||||
--el-pagination-font-size: 14px;
|
||||
--el-pagination-bg-color: var(--el-fill-color);
|
||||
--el-pagination-text-color: #e2e8f0;
|
||||
--el-pagination-border-radius: 4px;
|
||||
--el-pagination-button-color: #e2e8f0;
|
||||
--el-pagination-button-width: 32px;
|
||||
--el-pagination-button-height: 32px;
|
||||
--el-pagination-button-disabled-color: #64748b;
|
||||
--el-pagination-button-disabled-bg-color: var(--el-fill-color);
|
||||
--el-pagination-hover-color: var(--el-color-primary);
|
||||
|
||||
--el-steps-color: var(--el-border-color);
|
||||
--el-steps-text-color: #e2e8f0;
|
||||
--el-steps-border-color: var(--el-border-color);
|
||||
|
||||
--el-datepicker-text-color: #e2e8f0;
|
||||
--el-datepicker-off-text-color: #64748b;
|
||||
--el-datepicker-header-text-color: #e2e8f0;
|
||||
--el-datepicker-icon-color: #94a3b8;
|
||||
--el-datepicker-border-color: var(--el-border-color);
|
||||
--el-datepicker-inner-border-color: var(--el-border-color-light);
|
||||
--el-datepicker-inrange-bg-color: var(--el-fill-color-light);
|
||||
--el-datepicker-inrange-hover-bg-color: var(--el-fill-color-dark);
|
||||
--el-datepicker-active-color: var(--el-color-primary);
|
||||
--el-datepicker-hover-text-color: var(--el-color-primary);
|
||||
--el-datepicker-cell-hover-color: var(--el-fill-color-light);
|
||||
|
||||
// 布局相关变量 - 由 theme.ts 动态覆盖
|
||||
--menu-background: var(--el-fill-color);
|
||||
--menu-text: #e2e8f0;
|
||||
--menu-active-text: var(--el-color-primary);
|
||||
--menu-active-bg: rgba(64, 128, 255, 0.15);
|
||||
--menu-hover: var(--el-fill-color-light);
|
||||
|
||||
--sidebar-background: var(--el-fill-color);
|
||||
--sidebar-text-color: #e2e8f0;
|
||||
--sidebar-active-text-color: var(--el-color-primary);
|
||||
--sidebar-active-bg: rgba(64, 128, 255, 0.15);
|
||||
--sidebar-active-hover-bg: rgba(64, 128, 255, 0.2);
|
||||
--sidebar-hover: var(--el-fill-color-light);
|
||||
--sidebar-logo-text-color: var(--el-color-primary);
|
||||
--sidebar-logo-background: var(--el-fill-color);
|
||||
}
|
||||
@@ -1,338 +0,0 @@
|
||||
/**
|
||||
* Element Plus 亮色模式主题变量
|
||||
*
|
||||
* 注意:主题色变体(light-1 到 light-9, dark-2)由 theme.ts 动态生成
|
||||
* 此文件仅提供默认基础值和组件特定样式
|
||||
*/
|
||||
|
||||
:root {
|
||||
--el-color-primary: #3b82f6;
|
||||
--el-color-success: #10b981;
|
||||
--el-color-warning: #f59e0b;
|
||||
--el-color-danger: #ef4444;
|
||||
--el-color-info: #64748b;
|
||||
|
||||
--el-bg-color: #f8fafc;
|
||||
--el-bg-color-page: #f8fafc;
|
||||
--el-bg-color-overlay: #ffffff;
|
||||
--el-fill-color-blank: #ffffff;
|
||||
|
||||
--el-fill-color: #f1f5f9;
|
||||
--el-fill-color-light: #f8fafc;
|
||||
--el-fill-color-lighter: #ffffff;
|
||||
--el-fill-color-extra-light: #ffffff;
|
||||
--el-fill-color-dark: #e2e8f0;
|
||||
--el-fill-color-darker: #cbd5e1;
|
||||
|
||||
--el-text-color-primary: #0f172a;
|
||||
--el-text-color-regular: #334155;
|
||||
--el-text-color-secondary: #64748b;
|
||||
--el-text-color-placeholder: #94a3b8;
|
||||
|
||||
--el-border-color: #e2e8f0;
|
||||
--el-border-color-light: #f1f5f9;
|
||||
--el-border-color-lighter: #f8fafc;
|
||||
--el-border-color-extra-light: #ffffff;
|
||||
--el-border-color-dark: #cbd5e1;
|
||||
--el-border-color-darker: #94a3b8;
|
||||
|
||||
--el-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
--el-box-shadow-light: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-box-shadow-lighter: 0 1px 1px 0 rgba(0, 0, 0, 0.03);
|
||||
--el-box-shadow-dark: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
--el-disabled-bg-color: #f1f5f9;
|
||||
--el-disabled-text-color: #94a3b8;
|
||||
--el-disabled-border-color: #e2e8f0;
|
||||
|
||||
--el-overlay-color: rgba(15, 23, 42, 0.5);
|
||||
--el-overlay-color-light: rgba(15, 23, 42, 0.3);
|
||||
--el-overlay-color-lighter: rgba(15, 23, 42, 0.15);
|
||||
|
||||
--el-scrollbar-bg-color: #f1f5f9;
|
||||
--el-scrollbar-thumb-color: #cbd5e1;
|
||||
--el-scrollbar-thumb-hover-color: #94a3b8;
|
||||
|
||||
--el-table-bg-color: #ffffff;
|
||||
--el-table-tr-bg-color: #ffffff;
|
||||
--el-table-header-bg-color: #f8fafc;
|
||||
--el-table-row-hover-bg-color: #f1f5f9;
|
||||
--el-table-border-color: #e2e8f0;
|
||||
|
||||
--el-dialog-width: 50%;
|
||||
--el-dialog-margin-top: 15vh;
|
||||
--el-dialog-bg-color: #ffffff;
|
||||
--el-dialog-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
--el-dialog-title-font-size: 18px;
|
||||
--el-dialog-content-font-size: 14px;
|
||||
--el-dialog-font-line-height: 1.5;
|
||||
--el-dialog-padding-primary: 16px;
|
||||
--el-dialog-border-radius: 4px;
|
||||
|
||||
--el-drawer-bg-color: #ffffff;
|
||||
--el-drawer-padding-primary: 20px;
|
||||
|
||||
--el-dropdown-menu-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-dropdown-menuItem-hover-fill: #f1f5f9;
|
||||
--el-dropdown-menuItem-hover-color: var(--el-color-primary);
|
||||
--el-dropdown-menu-index: 10;
|
||||
|
||||
--el-popover-bg-color: #ffffff;
|
||||
--el-popover-font-size: 14px;
|
||||
--el-popover-border-color: #f1f5f9;
|
||||
--el-popover-padding: 12px;
|
||||
--el-popover-padding-large: 18px 20px;
|
||||
--el-popover-title-font-size: 16px;
|
||||
--el-popover-title-text-color: #0f172a;
|
||||
--el-popover-border-radius: 4px;
|
||||
|
||||
--el-popper-border-radius: 4px;
|
||||
|
||||
--el-card-border-color: #f1f5f9;
|
||||
--el-card-border-radius: 4px;
|
||||
--el-card-padding: 20px;
|
||||
--el-card-bg-color: #ffffff;
|
||||
|
||||
--el-badge-bg-color: #ef4444;
|
||||
--el-badge-radius: 10px;
|
||||
--el-badge-font-size: 12px;
|
||||
--el-badge-padding: 6px;
|
||||
--el-badge-size: 18px;
|
||||
|
||||
--el-segmented-color: #334155;
|
||||
--el-segmented-bg-color: #f8fafc;
|
||||
--el-segmented-padding: 2px;
|
||||
--el-segmented-item-selected-color: #ffffff;
|
||||
--el-segmented-item-selected-bg-color: var(--el-color-primary);
|
||||
--el-segmented-item-selected-disabled-bg-color: #b1d4fb;
|
||||
--el-segmented-item-hover-color: #0f172a;
|
||||
--el-segmented-item-hover-bg-color: #e2e8f0;
|
||||
--el-segmented-item-active-bg-color: #cbd5e1;
|
||||
--el-segmented-item-disabled-color: #94a3b8;
|
||||
|
||||
--el-tour-width: 520px;
|
||||
--el-tour-padding-primary: 12px;
|
||||
--el-tour-font-line-height: 1.5;
|
||||
--el-tour-title-font-size: 16px;
|
||||
--el-tour-title-text-color: #0f172a;
|
||||
--el-tour-title-font-weight: 400;
|
||||
--el-tour-close-color: #64748b;
|
||||
--el-tour-font-size: 14px;
|
||||
--el-tour-color: #0f172a;
|
||||
--el-tour-bg-color: #ffffff;
|
||||
--el-tour-border-radius: 4px;
|
||||
|
||||
--el-anchor-bg-color: #ffffff;
|
||||
--el-anchor-padding-indent: 14px;
|
||||
--el-anchor-line-height: 22px;
|
||||
--el-anchor-font-size: 12px;
|
||||
--el-anchor-color: #64748b;
|
||||
--el-anchor-active-color: var(--el-color-primary);
|
||||
--el-anchor-marker-bg-color: var(--el-color-primary);
|
||||
|
||||
--el-mention-font-size: 14px;
|
||||
--el-mention-bg-color: #ffffff;
|
||||
--el-mention-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-mention-border: 1px solid #f1f5f9;
|
||||
--el-mention-option-color: #334155;
|
||||
--el-mention-option-height: 34px;
|
||||
--el-mention-option-min-width: 100px;
|
||||
--el-mention-option-hover-background: #f8fafc;
|
||||
--el-mention-option-selected-color: var(--el-color-primary);
|
||||
--el-mention-option-disabled-color: #94a3b8;
|
||||
--el-mention-option-loading-color: #64748b;
|
||||
--el-mention-option-loading-padding: 10px 0;
|
||||
--el-mention-max-height: 174px;
|
||||
--el-mention-padding: 6px 0;
|
||||
--el-mention-header-padding: 10px;
|
||||
--el-mention-footer-padding: 10px;
|
||||
|
||||
--el-skeleton-color: #f1f5f9;
|
||||
--el-skeleton-to-color: #cbd5e1;
|
||||
|
||||
--el-alert-padding: 8px 16px;
|
||||
--el-alert-border-radius-base: 4px;
|
||||
--el-alert-title-font-size: 14px;
|
||||
--el-alert-title-with-description-font-size: 16px;
|
||||
--el-alert-description-font-size: 14px;
|
||||
--el-alert-close-font-size: 16px;
|
||||
--el-alert-close-customed-font-size: 14px;
|
||||
--el-alert-icon-size: 16px;
|
||||
--el-alert-icon-large-size: 28px;
|
||||
|
||||
--el-messagebox-title-color: #0f172a;
|
||||
--el-messagebox-width: 420px;
|
||||
--el-messagebox-border-radius: 4px;
|
||||
--el-messagebox-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
--el-messagebox-font-size: 18px;
|
||||
--el-messagebox-content-font-size: 14px;
|
||||
--el-messagebox-content-color: #334155;
|
||||
--el-messagebox-error-font-size: 12px;
|
||||
--el-messagebox-padding-primary: 12px;
|
||||
--el-messagebox-font-line-height: 1.5;
|
||||
|
||||
--el-message-bg-color: #ebf5fb;
|
||||
--el-message-border-color: #f8fafc;
|
||||
--el-message-padding: 11px 15px;
|
||||
--el-message-close-size: 16px;
|
||||
--el-message-close-icon-color: #94a3b8;
|
||||
--el-message-close-hover-color: #64748b;
|
||||
|
||||
--el-notification-width: 330px;
|
||||
--el-notification-padding: 14px 26px 14px 13px;
|
||||
--el-notification-radius: 8px;
|
||||
--el-notification-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-notification-border-color: #f8fafc;
|
||||
--el-notification-icon-size: 24px;
|
||||
--el-notification-close-font-size: 16px;
|
||||
--el-notification-group-margin-left: 13px;
|
||||
--el-notification-group-margin-right: 8px;
|
||||
--el-notification-content-font-size: 14px;
|
||||
--el-notification-content-color: #334155;
|
||||
--el-notification-title-font-size: 16px;
|
||||
--el-notification-title-color: #0f172a;
|
||||
--el-notification-close-color: #64748b;
|
||||
--el-notification-close-hover-color: #334155;
|
||||
|
||||
--el-input-text-color: #334155;
|
||||
--el-input-border: 1px solid #e2e8f0;
|
||||
--el-input-hover-border: 1px solid #94a3b8;
|
||||
--el-input-focus-border: 1px solid var(--el-color-primary);
|
||||
--el-input-transparent-border: 0 0 0 1px transparent inset;
|
||||
--el-input-border-color: #e2e8f0;
|
||||
--el-input-border-radius: 4px;
|
||||
--el-input-bg-color: #ffffff;
|
||||
--el-input-icon-color: #94a3b8;
|
||||
--el-input-placeholder-color: #94a3b8;
|
||||
--el-input-hover-border-color: #94a3b8;
|
||||
--el-input-clear-hover-color: #64748b;
|
||||
--el-input-focus-border-color: var(--el-color-primary);
|
||||
--el-input-width: 100%;
|
||||
|
||||
--el-input-disabled-fill: #f1f5f9;
|
||||
--el-input-disabled-border: #e2e8f0;
|
||||
--el-input-disabled-text-color: #94a3b8;
|
||||
--el-input-disabled-placeholder-color: #94a3b8;
|
||||
|
||||
--el-select-border-color-hover: #94a3b8;
|
||||
--el-select-disabled-color: #94a3b8;
|
||||
--el-select-disabled-border: #e2e8f0;
|
||||
--el-select-font-size: 14px;
|
||||
--el-select-close-hover-color: #64748b;
|
||||
--el-select-input-color: #94a3b8;
|
||||
--el-select-multiple-input-color: #334155;
|
||||
--el-select-input-focus-border-color: var(--el-color-primary);
|
||||
--el-select-input-font-size: 14px;
|
||||
--el-select-width: 100%;
|
||||
|
||||
--el-select-option-text-color: #334155;
|
||||
--el-select-option-disabled-color: #94a3b8;
|
||||
--el-select-option-height: 34px;
|
||||
--el-select-option-hover-background: #f8fafc;
|
||||
--el-select-option-selected-text-color: var(--el-color-primary);
|
||||
|
||||
--el-select-group-text-color: #64748b;
|
||||
--el-select-group-height: 34px;
|
||||
--el-select-group-font-size: 12px;
|
||||
|
||||
--el-select-dropdown-bg-color: #ffffff;
|
||||
--el-select-dropdown-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-select-dropdown-empty-color: #64748b;
|
||||
--el-select-dropdown-max-height: 274px;
|
||||
--el-select-dropdown-padding: 6px 0;
|
||||
--el-select-dropdown-empty-padding: 10px 0;
|
||||
--el-select-dropdown-header-padding: 10px;
|
||||
--el-select-dropdown-footer-padding: 10px;
|
||||
--el-select-dropdown-border: 1px solid #f1f5f9;
|
||||
|
||||
--el-tag-font-size: 12px;
|
||||
--el-tag-border-radius: 4px;
|
||||
--el-tag-border-radius-rounded: 9999px;
|
||||
|
||||
--el-button-font-weight: 500;
|
||||
--el-button-border-color: #e2e8f0;
|
||||
--el-button-bg-color: #ffffff;
|
||||
--el-button-text-color: #334155;
|
||||
--el-button-disabled-text-color: #94a3b8;
|
||||
--el-button-disabled-bg-color: #f1f5f9;
|
||||
--el-button-disabled-border-color: #e2e8f0;
|
||||
--el-button-divide-border-color: rgba(255, 255, 255, 0.5);
|
||||
|
||||
--el-tooltip-font-size: 12px;
|
||||
--el-tooltip-border-color: #0f172a;
|
||||
--el-tooltip-fill: #0f172a;
|
||||
--el-tooltip-light-border-color: #e2e8f0;
|
||||
--el-tooltip-light-fill: #ffffff;
|
||||
|
||||
--el-cascader-menu-text-color: #334155;
|
||||
--el-cascader-menu-selected-text-color: var(--el-color-primary);
|
||||
--el-cascader-menu-fill: #ffffff;
|
||||
--el-cascader-menu-font-size: 14px;
|
||||
--el-cascader-menu-radius: 4px;
|
||||
--el-cascader-menu-border: solid 1px #f1f5f9;
|
||||
--el-cascader-menu-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--el-cascader-node-background-hover: #f8fafc;
|
||||
--el-cascader-node-color-disabled: #94a3b8;
|
||||
--el-cascader-color-empty: #94a3b8;
|
||||
--el-cascader-tag-background: #f1f5f9;
|
||||
|
||||
--el-statistic-title-font-weight: 400;
|
||||
--el-statistic-title-font-size: 12px;
|
||||
--el-statistic-title-color: #334155;
|
||||
--el-statistic-content-font-weight: 400;
|
||||
--el-statistic-content-font-size: 24px;
|
||||
--el-statistic-content-color: #0f172a;
|
||||
|
||||
--el-switch-on-color: var(--el-color-primary);
|
||||
--el-switch-off-color: #e2e8f0;
|
||||
|
||||
--el-loading-spinner-size: 42px;
|
||||
--el-loading-fullscreen-spinner-size: 50px;
|
||||
--el-loading-text-color: var(--el-color-primary);
|
||||
|
||||
--el-progress-default-color: var(--el-color-primary);
|
||||
--el-progress-inside-text-color: #ffffff;
|
||||
|
||||
--el-pagination-font-size: 14px;
|
||||
--el-pagination-bg-color: #ffffff;
|
||||
--el-pagination-text-color: #334155;
|
||||
--el-pagination-border-radius: 4px;
|
||||
--el-pagination-button-color: #334155;
|
||||
--el-pagination-button-width: 32px;
|
||||
--el-pagination-button-height: 32px;
|
||||
--el-pagination-button-disabled-color: #94a3b8;
|
||||
--el-pagination-button-disabled-bg-color: #f1f5f9;
|
||||
--el-pagination-hover-color: var(--el-color-primary);
|
||||
|
||||
--el-steps-color: #e2e8f0;
|
||||
--el-steps-text-color: #334155;
|
||||
--el-steps-border-color: #e2e8f0;
|
||||
|
||||
--el-datepicker-text-color: #334155;
|
||||
--el-datepicker-off-text-color: #94a3b8;
|
||||
--el-datepicker-header-text-color: #334155;
|
||||
--el-datepicker-icon-color: #64748b;
|
||||
--el-datepicker-border-color: #e2e8f0;
|
||||
--el-datepicker-inner-border-color: #f1f5f9;
|
||||
--el-datepicker-inrange-bg-color: #f8fafc;
|
||||
--el-datepicker-inrange-hover-bg-color: #f1f5f9;
|
||||
--el-datepicker-active-color: var(--el-color-primary);
|
||||
--el-datepicker-hover-text-color: var(--el-color-primary);
|
||||
--el-datepicker-cell-hover-color: #f8fafc;
|
||||
|
||||
// 布局相关变量 - 由 theme.ts 动态覆盖
|
||||
--menu-background: #ffffff;
|
||||
--menu-text: #1e293b;
|
||||
--menu-active-text: var(--el-color-primary);
|
||||
--menu-active-bg: #f8fafc;
|
||||
--menu-hover: #fafafa;
|
||||
|
||||
--sidebar-background: #ffffff;
|
||||
--sidebar-text-color: #1e293b;
|
||||
--sidebar-active-text-color: var(--el-color-primary);
|
||||
--sidebar-active-bg: #f8fafc;
|
||||
--sidebar-active-hover-bg: #f1f5f9;
|
||||
--sidebar-hover: #fafafa;
|
||||
--sidebar-logo-text-color: var(--el-color-primary);
|
||||
--sidebar-logo-background: #ffffff;
|
||||
}
|
||||
@@ -1,32 +1,3 @@
|
||||
// 主题颜色 - 跟随主题模式自动变化
|
||||
// 注意:SCSS 配置需要使用固定颜色值,动态主题色由 theme.ts 在运行时设置
|
||||
@forward "element-plus/theme-chalk/src/common/var.scss" with (
|
||||
$colors: (
|
||||
"primary": (
|
||||
"base": #3b82f6,
|
||||
),
|
||||
"success": (
|
||||
"base": #10b981,
|
||||
),
|
||||
"warning": (
|
||||
"base": #f59e0b,
|
||||
),
|
||||
"danger": (
|
||||
"base": #ef4444,
|
||||
),
|
||||
"info": (
|
||||
"base": #64748b,
|
||||
),
|
||||
"default": (
|
||||
"base": #f8fafc,
|
||||
),
|
||||
),
|
||||
|
||||
$bg-color: (
|
||||
"page": #f8fafc,
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* 简化颜色系统设计原则
|
||||
*
|
||||
@@ -39,33 +10,51 @@
|
||||
:root {
|
||||
// ==================== 品牌主题色 ====================
|
||||
// 由 theme.ts 动态设置,这里提供默认值
|
||||
--brand-primary: var(--el-color-primary, #3b82f6);
|
||||
--brand-primary: var(--el-color-primary, #1677ff);
|
||||
--brand-success: #10b981;
|
||||
--brand-warning: #f59e0b;
|
||||
--brand-danger: #ef4444;
|
||||
--brand-info: #64748b;
|
||||
|
||||
// ==================== 固定的自定义颜色 ====================
|
||||
--custom-bg-light: #ffffff;
|
||||
--custom-bg-dark: #0f172a;
|
||||
--custom-text-light: #334155;
|
||||
--custom-text-dark: #f1f5f9;
|
||||
|
||||
// ==================== 亮色模式背景层次 ====================
|
||||
--custom-bg-primary: #f8fafc;
|
||||
--custom-bg-secondary: #ffffff;
|
||||
--custom-bg-tertiary: #ffffff;
|
||||
|
||||
// ==================== 暗黑模式背景层次 ====================
|
||||
--custom-bg-primary-dark: var(--el-bg-color, #020617);
|
||||
--custom-bg-secondary-dark: var(--el-bg-color-overlay, #0f172a);
|
||||
--custom-bg-tertiary-dark: #1e293b;
|
||||
--brand-info: #2f86ff;
|
||||
|
||||
// ==================== 亮色模式(默认)====================
|
||||
// 语义化布局变量(推荐优先使用)
|
||||
--layout-bg-primary: var(--el-bg-color, #f8fafc);
|
||||
--layout-bg-secondary: var(--el-bg-color-overlay, #ffffff);
|
||||
--layout-bg-tertiary: #ffffff;
|
||||
--layout-text-primary: #0f172a;
|
||||
--layout-text-secondary: #475569;
|
||||
--layout-text-tertiary: #64748b;
|
||||
--layout-text-disabled: #94a3b8;
|
||||
--layout-sidebar-bg: #ffffff;
|
||||
--layout-sidebar-text: #334155;
|
||||
--layout-sidebar-active-text: var(--brand-primary);
|
||||
--layout-sidebar-active-bg: #f8fafc;
|
||||
--layout-sidebar-active-hover-bg: #f1f5f9;
|
||||
--layout-sidebar-hover: #f1f5f9;
|
||||
--layout-menu-bg: var(--layout-sidebar-bg);
|
||||
--layout-menu-text: var(--layout-sidebar-text);
|
||||
--layout-menu-active-text: var(--layout-sidebar-active-text);
|
||||
--layout-menu-active-bg: var(--layout-sidebar-active-bg);
|
||||
--layout-menu-hover: var(--layout-sidebar-hover);
|
||||
--layout-logo-bg: var(--layout-sidebar-bg);
|
||||
--layout-logo-text: var(--layout-sidebar-active-text);
|
||||
--layout-header-bg: var(--layout-menu-bg);
|
||||
--layout-header-text: var(--layout-text-primary);
|
||||
--layout-header-border: var(--el-border-color-light, #e2e8f0);
|
||||
--layout-tags-bg: var(--layout-bg-primary);
|
||||
--layout-tags-border: var(--el-border-color-light, #e2e8f0);
|
||||
--layout-tags-item-bg: var(--el-bg-color, #ffffff);
|
||||
--layout-tags-item-text: var(--layout-text-primary);
|
||||
--layout-tags-item-active-bg: var(--el-color-primary-light-9, #dbeafe);
|
||||
--layout-tags-item-active-text: var(--el-color-primary, #1677ff);
|
||||
--layout-content-bg: var(--layout-bg-primary);
|
||||
// 列表页 gutter/留白透出:--layout-content-canvas(dark/css-vars.css,主色轻混 --el-bg-color-page)
|
||||
--layout-content-surface-bg: var(--el-bg-color-overlay, #ffffff);
|
||||
|
||||
// 背景色系
|
||||
--bg-primary: var(--custom-bg-primary);
|
||||
--bg-secondary: var(--custom-bg-secondary);
|
||||
--bg-tertiary: var(--custom-bg-tertiary);
|
||||
--bg-primary: var(--layout-bg-primary, #f8fafc);
|
||||
--bg-secondary: var(--layout-bg-secondary, #ffffff);
|
||||
--bg-tertiary: var(--layout-bg-tertiary, #ffffff);
|
||||
|
||||
// 文字色系
|
||||
--text-primary: #0f172a;
|
||||
@@ -78,35 +67,57 @@
|
||||
--border-secondary: #cbd5e1;
|
||||
--border-tertiary: #f1f5f9;
|
||||
|
||||
// 菜单色系
|
||||
--menu-background: var(--sidebar-background, var(--custom-bg-light));
|
||||
--menu-text: var(--sidebar-text-color, var(--custom-text-light));
|
||||
--menu-active-text: var(--sidebar-active-text-color, var(--brand-primary));
|
||||
--menu-hover: var(--sidebar-hover, #f1f5f9);
|
||||
--sidebar-logo-background: var(--sidebar-background, var(--custom-bg-light));
|
||||
--sidebar-logo-text-color: var(--brand-primary);
|
||||
|
||||
// 状态色系
|
||||
--status-success: var(--brand-success);
|
||||
--status-warning: var(--brand-warning);
|
||||
--status-danger: var(--brand-danger);
|
||||
--status-info: var(--brand-info);
|
||||
// 菜单兼容(仅保留 Element Plus 所需 hover 变量)
|
||||
--el-menu-hover-bg-color: var(--layout-menu-hover, #f3f6fb);
|
||||
|
||||
// 科技感增强
|
||||
--tech-glow: rgba(var(--brand-primary-rgb, 59, 130, 246), 0.12);
|
||||
--tech-glow: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.12);
|
||||
--tech-gradient: linear-gradient(
|
||||
135deg,
|
||||
rgba(var(--brand-primary-rgb, 59, 130, 246), 0.02) 0%,
|
||||
rgba(var(--brand-primary-rgb, 22, 119, 255), 0.02) 0%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
/** 暗黑主题 */
|
||||
html.dark {
|
||||
// 语义化布局变量(暗色)
|
||||
--layout-bg-primary: var(--el-bg-color, #020617);
|
||||
--layout-bg-secondary: var(--el-bg-color-overlay, #0f172a);
|
||||
--layout-bg-tertiary: #1e293b;
|
||||
--layout-text-primary: #f8fafc;
|
||||
--layout-text-secondary: #cbd5e1;
|
||||
--layout-text-tertiary: #94a3b8;
|
||||
--layout-text-disabled: #64748b;
|
||||
--layout-sidebar-bg: #0f172a;
|
||||
--layout-sidebar-text: #f1f5f9;
|
||||
--layout-sidebar-active-text: var(--brand-primary);
|
||||
--layout-sidebar-active-bg: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.2);
|
||||
--layout-sidebar-active-hover-bg: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.26);
|
||||
--layout-sidebar-hover: #1e293b;
|
||||
--layout-menu-bg: var(--layout-sidebar-bg);
|
||||
--layout-menu-text: var(--layout-sidebar-text);
|
||||
--layout-menu-active-text: var(--layout-sidebar-active-text);
|
||||
--layout-menu-active-bg: var(--layout-sidebar-active-bg);
|
||||
--layout-menu-hover: var(--layout-sidebar-hover);
|
||||
--layout-logo-bg: var(--layout-sidebar-bg);
|
||||
--layout-logo-text: var(--layout-sidebar-active-text);
|
||||
--layout-header-bg: var(--layout-menu-bg);
|
||||
--layout-header-text: var(--layout-text-primary);
|
||||
--layout-header-border: var(--el-border-color, #334155);
|
||||
--layout-tags-bg: var(--layout-bg-primary);
|
||||
--layout-tags-border: var(--el-border-color, #334155);
|
||||
--layout-tags-item-bg: var(--el-fill-color, #0f172a);
|
||||
--layout-tags-item-text: var(--layout-text-primary);
|
||||
--layout-tags-item-active-bg: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.2);
|
||||
--layout-tags-item-active-text: var(--el-color-primary, #1677ff);
|
||||
--layout-content-bg: var(--layout-bg-primary);
|
||||
--layout-content-surface-bg: var(--el-fill-color, #0f172a);
|
||||
|
||||
// 背景色系
|
||||
--bg-primary: var(--custom-bg-primary-dark);
|
||||
--bg-secondary: var(--custom-bg-secondary-dark);
|
||||
--bg-tertiary: var(--custom-bg-tertiary-dark);
|
||||
--bg-primary: var(--layout-bg-primary, #020617);
|
||||
--bg-secondary: var(--layout-bg-secondary, #0f172a);
|
||||
--bg-tertiary: var(--layout-bg-tertiary, #1e293b);
|
||||
|
||||
// 文字色系
|
||||
--text-primary: #f8fafc;
|
||||
@@ -119,25 +130,14 @@ html.dark {
|
||||
--border-secondary: var(--el-border-color-light, #334155);
|
||||
--border-tertiary: var(--el-border-color-lighter, #475569);
|
||||
|
||||
// 菜单色系
|
||||
--menu-background: var(--sidebar-background, var(--custom-bg-dark));
|
||||
--menu-text: var(--sidebar-text-color, var(--custom-text-dark));
|
||||
--menu-active-text: var(--sidebar-active-text-color, var(--brand-primary));
|
||||
--menu-hover: var(--sidebar-hover, #1e293b);
|
||||
--sidebar-logo-background: var(--sidebar-background, var(--custom-bg-dark));
|
||||
--sidebar-logo-text-color: var(--brand-primary);
|
||||
|
||||
// 状态色系
|
||||
--status-success: var(--brand-success);
|
||||
--status-warning: var(--brand-warning);
|
||||
--status-danger: var(--brand-danger);
|
||||
--status-info: var(--brand-info);
|
||||
// 菜单兼容(仅保留 Element Plus 所需 hover 变量)
|
||||
--el-menu-hover-bg-color: var(--layout-menu-hover, #1b2a45);
|
||||
|
||||
// 科技感增强
|
||||
--tech-glow: rgba(var(--brand-primary-rgb, 59, 130, 246), 0.25);
|
||||
--tech-glow: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.25);
|
||||
--tech-gradient: linear-gradient(
|
||||
135deg,
|
||||
rgba(var(--brand-primary-rgb, 59, 130, 246), 0.08) 0%,
|
||||
rgba(var(--brand-primary-rgb, 22, 119, 255), 0.08) 0%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
|
||||
@@ -148,13 +148,13 @@ html.dark {
|
||||
--w-e-textarea-slight-border-color: var(--border-secondary);
|
||||
--w-e-textarea-slight-color: var(--text-tertiary);
|
||||
--w-e-textarea-slight-bg-color: var(--bg-tertiary);
|
||||
--w-e-textarea-selected-border-color: rgba(var(--brand-primary-rgb, 59, 130, 246), 0.4);
|
||||
--w-e-textarea-selected-border-color: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.4);
|
||||
--w-e-textarea-handler-bg-color: var(--brand-primary);
|
||||
|
||||
--w-e-toolbar-color: var(--text-primary);
|
||||
--w-e-toolbar-bg-color: var(--bg-secondary);
|
||||
--w-e-toolbar-active-color: var(--brand-primary);
|
||||
--w-e-toolbar-active-bg-color: rgba(var(--brand-primary-rgb, 59, 130, 246), 0.08);
|
||||
--w-e-toolbar-active-bg-color: rgba(var(--brand-primary-rgb, 22, 119, 255), 0.08);
|
||||
--w-e-toolbar-disabled-color: var(--text-disabled);
|
||||
--w-e-toolbar-border-color: var(--border-primary);
|
||||
|
||||
@@ -162,12 +162,10 @@ html.dark {
|
||||
--w-e-modal-button-border-color: var(--border-secondary);
|
||||
}
|
||||
|
||||
$menu-background: var(--menu-background);
|
||||
$menu-text: var(--menu-text);
|
||||
$menu-active-text: var(--menu-active-text);
|
||||
$menu-hover: var(--menu-hover);
|
||||
$sidebar-logo-background: var(--sidebar-logo-background);
|
||||
$sidebar-logo-text-color: var(--sidebar-logo-text-color);
|
||||
$menu-background: var(--layout-menu-bg);
|
||||
$menu-text: var(--layout-menu-text);
|
||||
$menu-active-text: var(--layout-menu-active-text);
|
||||
$menu-hover: var(--layout-menu-hover);
|
||||
|
||||
$sidebar-width: 210px;
|
||||
$sidebar-width-collapsed: 54px;
|
||||
|
||||
+324
-310
@@ -1,8 +1,13 @@
|
||||
import { ThemeMode } from "@/enums";
|
||||
|
||||
const COLOR_VARIANT_LEVELS = [0.08, 0.16, 0.24, 0.32, 0.4, 0.52, 0.64, 0.76, 0.88];
|
||||
|
||||
function normalizeHexColor(hex: string): string {
|
||||
return hex.length === 9 ? hex.slice(0, 7) : hex;
|
||||
}
|
||||
|
||||
function hexToRgb(hex: string): [number, number, number] {
|
||||
// 处理带alpha通道的颜色值,去除alpha部分
|
||||
const cleanHex = hex.length === 9 ? hex.slice(0, 7) : hex;
|
||||
const cleanHex = normalizeHexColor(hex);
|
||||
const bigint = parseInt(cleanHex.slice(1), 16);
|
||||
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
|
||||
}
|
||||
@@ -20,10 +25,6 @@ function getLuminance(hex: string): number {
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
}
|
||||
|
||||
function isLightColor(hex: string): boolean {
|
||||
return getLuminance(hex) > 0.5;
|
||||
}
|
||||
|
||||
function getDarkColor(color: string, level: number): string {
|
||||
const rgb = hexToRgb(color);
|
||||
for (let i = 0; i < 3; i++) rgb[i] = Math.round(20.5 * level + rgb[i] * (1 - level));
|
||||
@@ -54,15 +55,13 @@ interface ColorVariants {
|
||||
}
|
||||
|
||||
function generateColorVariants(baseColor: string): ColorVariants {
|
||||
const lightLevels = [0.08, 0.16, 0.24, 0.32, 0.4, 0.52, 0.64, 0.76, 0.88];
|
||||
const light = lightLevels.map((level) => getLightColor(baseColor, level));
|
||||
const light = COLOR_VARIANT_LEVELS.map((level) => getLightColor(baseColor, level));
|
||||
const dark = getDarkColor(baseColor, 0.15);
|
||||
return { light, dark };
|
||||
}
|
||||
|
||||
function generateDarkModeVariants(baseColor: string): ColorVariants {
|
||||
const darkLevels = [0.08, 0.16, 0.24, 0.32, 0.4, 0.52, 0.64, 0.76, 0.88];
|
||||
const light = darkLevels.map((level) => getDarkColor(baseColor, level));
|
||||
const light = COLOR_VARIANT_LEVELS.map((level) => getDarkColor(baseColor, level));
|
||||
const dark = getLightColor(baseColor, 0.15);
|
||||
return { light, dark };
|
||||
}
|
||||
@@ -96,13 +95,6 @@ interface ColorScheme {
|
||||
dark: string;
|
||||
darker: string;
|
||||
};
|
||||
table: {
|
||||
bg: string;
|
||||
trBg: string;
|
||||
headerBg: string;
|
||||
hoverBg: string;
|
||||
border: string;
|
||||
};
|
||||
sidebar: {
|
||||
background: string;
|
||||
text: string;
|
||||
@@ -118,221 +110,225 @@ interface ColorScheme {
|
||||
activeBg: string;
|
||||
hover: string;
|
||||
};
|
||||
}
|
||||
|
||||
function generateLightThemeScheme(primary: string, isLightPrimary: boolean): ColorScheme {
|
||||
if (isLightPrimary) {
|
||||
return {
|
||||
bg: {
|
||||
primary: getLightColor(primary, 0.92),
|
||||
secondary: "#ffffff",
|
||||
tertiary: "#ffffff",
|
||||
},
|
||||
fill: {
|
||||
base: getLightColor(primary, 0.88),
|
||||
light: getLightColor(primary, 0.92),
|
||||
lighter: getLightColor(primary, 0.96),
|
||||
extraLight: "#ffffff",
|
||||
dark: getLightColor(primary, 0.8),
|
||||
darker: getLightColor(primary, 0.7),
|
||||
},
|
||||
shadow: {
|
||||
base: `0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)`,
|
||||
light: `0 1px 2px 0 rgba(0, 0, 0, 0.05)`,
|
||||
lighter: `0 1px 1px 0 rgba(0, 0, 0, 0.03)`,
|
||||
dark: `0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)`,
|
||||
},
|
||||
border: {
|
||||
base: getLightColor(primary, 0.85),
|
||||
light: getLightColor(primary, 0.9),
|
||||
lighter: getLightColor(primary, 0.94),
|
||||
extraLight: "#ffffff",
|
||||
dark: getLightColor(primary, 0.75),
|
||||
darker: getLightColor(primary, 0.65),
|
||||
},
|
||||
table: {
|
||||
bg: "#ffffff",
|
||||
trBg: "#ffffff",
|
||||
headerBg: getLightColor(primary, 0.92),
|
||||
hoverBg: getLightColor(primary, 0.88),
|
||||
border: getLightColor(primary, 0.85),
|
||||
},
|
||||
sidebar: {
|
||||
background: getLightColor(primary, 0.92),
|
||||
text: "#1e293b",
|
||||
activeText: getDarkColor(primary, 0.15),
|
||||
activeBg: getLightColor(primary, 0.88),
|
||||
activeHoverBg: getLightColor(primary, 0.65),
|
||||
hover: "#fafafa",
|
||||
},
|
||||
menu: {
|
||||
background: getLightColor(primary, 0.92),
|
||||
text: "#1e293b",
|
||||
activeText: getDarkColor(primary, 0.15),
|
||||
activeBg: getLightColor(primary, 0.88),
|
||||
hover: "#fafafa",
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
bg: {
|
||||
primary: getLightColor(primary, 0.75),
|
||||
secondary: "#ffffff",
|
||||
tertiary: "#ffffff",
|
||||
},
|
||||
fill: {
|
||||
base: "#f1f5f9",
|
||||
light: "#f8fafc",
|
||||
lighter: "#ffffff",
|
||||
extraLight: "#ffffff",
|
||||
dark: "#e2e8f0",
|
||||
darker: "#cbd5e1",
|
||||
},
|
||||
shadow: {
|
||||
base: `0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)`,
|
||||
light: `0 1px 2px 0 rgba(0, 0, 0, 0.05)`,
|
||||
lighter: `0 1px 1px 0 rgba(0, 0, 0, 0.03)`,
|
||||
dark: `0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)`,
|
||||
},
|
||||
border: {
|
||||
base: blendTwoColors("#cbd5e1", primary, 0.2),
|
||||
light: blendTwoColors("#e2e8f0", primary, 0.15),
|
||||
lighter: blendTwoColors("#f1f5f9", primary, 0.1),
|
||||
extraLight: "#ffffff",
|
||||
dark: blendTwoColors("#94a3b8", primary, 0.25),
|
||||
darker: blendTwoColors("#64748b", primary, 0.3),
|
||||
},
|
||||
table: {
|
||||
bg: blendTwoColors("#ffffff", primary, 0.02),
|
||||
trBg: blendTwoColors("#ffffff", primary, 0.02),
|
||||
headerBg: blendTwoColors("#f8fafc", primary, 0.15),
|
||||
hoverBg: blendTwoColors("#f1f5f9", primary, 0.1),
|
||||
border: blendTwoColors("#cbd5e1", primary, 0.2),
|
||||
},
|
||||
sidebar: {
|
||||
background: blendTwoColors("#ffffff", primary, 0.05),
|
||||
text: "#1e293b",
|
||||
activeText: getDarkColor(primary, 0.1),
|
||||
activeBg: getLightColor(primary, 0.88),
|
||||
activeHoverBg: getLightColor(primary, 0.65),
|
||||
hover: blendTwoColors("#fafafa", primary, 0.1),
|
||||
},
|
||||
menu: {
|
||||
background: blendTwoColors("#ffffff", primary, 0.05),
|
||||
text: "#1e293b",
|
||||
activeText: getDarkColor(primary, 0.1),
|
||||
activeBg: getLightColor(primary, 0.88),
|
||||
hover: blendTwoColors("#fafafa", primary, 0.1),
|
||||
},
|
||||
text: {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
tertiary: string;
|
||||
disabled: string;
|
||||
};
|
||||
}
|
||||
|
||||
function generateDarkThemeScheme(primary: string, isLightPrimary: boolean): ColorScheme {
|
||||
if (isLightPrimary) {
|
||||
return {
|
||||
bg: {
|
||||
primary: getLightColor(primary, 0.85),
|
||||
secondary: getLightColor(primary, 0.95),
|
||||
tertiary: getLightColor(primary, 0.97),
|
||||
overlay: getLightColor(primary, 0.95),
|
||||
},
|
||||
fill: {
|
||||
base: blendTwoColors("#0f172a", primary, 0.1),
|
||||
light: blendTwoColors("#1e293b", primary, 0.15),
|
||||
lighter: blendTwoColors("#0f172a", primary, 0.05),
|
||||
extraLight: blendTwoColors("#020617", primary, 0.02),
|
||||
dark: blendTwoColors("#334155", primary, 0.2),
|
||||
darker: blendTwoColors("#475569", primary, 0.25),
|
||||
},
|
||||
shadow: {
|
||||
base: `0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24)`,
|
||||
light: `0 1px 2px 0 rgba(0, 0, 0, 0.2)`,
|
||||
lighter: `0 1px 1px 0 rgba(0, 0, 0, 0.12)`,
|
||||
dark: `0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.24)`,
|
||||
},
|
||||
border: {
|
||||
base: getLightColor(primary, 0.85),
|
||||
light: getLightColor(primary, 0.9),
|
||||
lighter: getLightColor(primary, 0.94),
|
||||
extraLight: getLightColor(primary, 0.97),
|
||||
dark: getLightColor(primary, 0.78),
|
||||
darker: getLightColor(primary, 0.68),
|
||||
},
|
||||
table: {
|
||||
bg: blendTwoColors("#020617", primary, 0.02),
|
||||
trBg: blendTwoColors("#020617", primary, 0.02),
|
||||
headerBg: blendTwoColors("#1e293b", primary, 0.15),
|
||||
hoverBg: blendTwoColors("#0f172a", primary, 0.1),
|
||||
border: blendTwoColors("#1e293b", primary, 0.12),
|
||||
},
|
||||
sidebar: {
|
||||
background: getLightColor(primary, 0.92),
|
||||
text: "#e2e8f0",
|
||||
activeText: primary,
|
||||
activeBg: getLightColor(primary, 0.9),
|
||||
activeHoverBg: getLightColor(primary, 0.65),
|
||||
hover: getLightColor(primary, 0.88),
|
||||
},
|
||||
menu: {
|
||||
background: getLightColor(primary, 0.92),
|
||||
text: "#e2e8f0",
|
||||
activeText: primary,
|
||||
activeBg: getLightColor(primary, 0.9),
|
||||
hover: getLightColor(primary, 0.88),
|
||||
},
|
||||
};
|
||||
}
|
||||
interface CoreThemeTokens {
|
||||
brandPrimary: string;
|
||||
layoutBgPrimary: string;
|
||||
layoutBgSecondary: string;
|
||||
layoutBgTertiary: string;
|
||||
layoutSidebarBg: string;
|
||||
layoutSidebarText: string;
|
||||
layoutSidebarActiveText: string;
|
||||
layoutSidebarActiveBg: string;
|
||||
layoutSidebarActiveHoverBg: string;
|
||||
layoutSidebarHover: string;
|
||||
layoutMenuActiveBg: string;
|
||||
layoutHeaderBg: string;
|
||||
layoutHeaderText: string;
|
||||
layoutHeaderBorder: string;
|
||||
layoutTagsBg: string;
|
||||
layoutTagsBorder: string;
|
||||
layoutTagsItemBg: string;
|
||||
layoutTagsItemText: string;
|
||||
layoutTagsItemActiveBg: string;
|
||||
layoutTagsItemActiveText: string;
|
||||
layoutContentBg: string;
|
||||
layoutContentSurfaceBg: string;
|
||||
}
|
||||
|
||||
const LIGHT_TEXT_SCHEME: ColorScheme["text"] = {
|
||||
primary: "#0f172a",
|
||||
secondary: "#475569",
|
||||
tertiary: "#64748b",
|
||||
disabled: "#94a3b8",
|
||||
};
|
||||
|
||||
const DARK_TEXT_SCHEME: ColorScheme["text"] = {
|
||||
primary: "#f8fafc",
|
||||
secondary: "#cbd5e1",
|
||||
tertiary: "#94a3b8",
|
||||
disabled: "#64748b",
|
||||
};
|
||||
|
||||
const LIGHT_SHADOW_SCHEME: ColorScheme["shadow"] = {
|
||||
base: `0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)`,
|
||||
light: `0 1px 2px 0 rgba(0, 0, 0, 0.05)`,
|
||||
lighter: `0 1px 1px 0 rgba(0, 0, 0, 0.03)`,
|
||||
dark: `0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)`,
|
||||
};
|
||||
|
||||
const DARK_SHADOW_SCHEME: ColorScheme["shadow"] = {
|
||||
base: `0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24)`,
|
||||
light: `0 1px 2px 0 rgba(0, 0, 0, 0.2)`,
|
||||
lighter: `0 1px 1px 0 rgba(0, 0, 0, 0.12)`,
|
||||
dark: `0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.24)`,
|
||||
};
|
||||
|
||||
const ENTERPRISE_LIGHT_NEUTRAL = {
|
||||
bgPrimary: "#f5f7fb",
|
||||
bgSecondary: "#ffffff",
|
||||
bgTertiary: "#f8fafc",
|
||||
fillBase: "#eef3fb",
|
||||
fillLight: "#f7f9fd",
|
||||
fillLighter: "#ffffff",
|
||||
borderBase: "#d8e2f0",
|
||||
borderLight: "#e7edf5",
|
||||
borderLighter: "#f0f4fa",
|
||||
};
|
||||
|
||||
const ENTERPRISE_DARK_NEUTRAL = {
|
||||
bgPrimary: "#0b1220",
|
||||
bgSecondary: "#111a2c",
|
||||
bgTertiary: "#17233a",
|
||||
fillBase: "#141f33",
|
||||
fillLight: "#1b2a45",
|
||||
fillLighter: "#111a2c",
|
||||
borderBase: "#253858",
|
||||
borderLight: "#31486b",
|
||||
borderLighter: "#3f5c86",
|
||||
};
|
||||
|
||||
function createCoreThemeTokens(scheme: ColorScheme, primary: string): CoreThemeTokens {
|
||||
const isDarkScheme = scheme.text.primary === DARK_TEXT_SCHEME.primary;
|
||||
const headerBg = blendTwoColors(scheme.menu.background, scheme.bg.secondary, 0.18);
|
||||
const tagsBg = blendTwoColors(scheme.bg.secondary, scheme.fill.light, 0.28);
|
||||
const tagsItemBg = blendTwoColors(scheme.bg.secondary, scheme.fill.light, 0.18);
|
||||
const tagsItemActiveBg = isDarkScheme
|
||||
? blendTwoColors(scheme.fill.light, primary, 0.28)
|
||||
: blendTwoColors(scheme.fill.light, primary, 0.2);
|
||||
const tagsItemActiveText = isDarkScheme
|
||||
? getLightColor(primary, 0.1)
|
||||
: getDarkColor(primary, 0.08);
|
||||
// 内容区分为两层:页面底色 + 容器(padding空白区)底色,提升层次感
|
||||
const contentBg = blendTwoColors(scheme.bg.primary, scheme.fill.light, 0.08);
|
||||
const contentSurfaceBg = blendTwoColors(scheme.bg.secondary, scheme.fill.base, 0.22);
|
||||
|
||||
return {
|
||||
brandPrimary: primary,
|
||||
layoutBgPrimary: scheme.bg.primary,
|
||||
layoutBgSecondary: scheme.bg.overlay ?? scheme.bg.secondary,
|
||||
layoutBgTertiary: scheme.bg.tertiary,
|
||||
layoutSidebarBg: scheme.sidebar.background,
|
||||
layoutSidebarText: scheme.sidebar.text,
|
||||
layoutSidebarActiveText: scheme.sidebar.activeText,
|
||||
layoutSidebarActiveBg: scheme.sidebar.activeBg,
|
||||
layoutSidebarActiveHoverBg: scheme.sidebar.activeHoverBg,
|
||||
layoutSidebarHover: scheme.sidebar.hover,
|
||||
layoutMenuActiveBg: scheme.menu.activeBg,
|
||||
layoutHeaderBg: headerBg,
|
||||
layoutHeaderText: scheme.text.primary,
|
||||
layoutHeaderBorder: scheme.border.light,
|
||||
layoutTagsBg: tagsBg,
|
||||
layoutTagsBorder: scheme.border.light,
|
||||
layoutTagsItemBg: tagsItemBg,
|
||||
layoutTagsItemText: scheme.text.primary,
|
||||
layoutTagsItemActiveBg: tagsItemActiveBg,
|
||||
layoutTagsItemActiveText: tagsItemActiveText,
|
||||
layoutContentBg: contentBg,
|
||||
layoutContentSurfaceBg: contentSurfaceBg,
|
||||
};
|
||||
}
|
||||
|
||||
function generateLightThemeScheme(primary: string): ColorScheme {
|
||||
const activeBg = blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.fillLight, primary, 0.18);
|
||||
const activeHoverBg = blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.fillBase, primary, 0.24);
|
||||
|
||||
return {
|
||||
bg: {
|
||||
primary: blendTwoColors("#020617", primary, 0.05),
|
||||
secondary: blendTwoColors("#0f172a", primary, 0.08),
|
||||
tertiary: blendTwoColors("#1e293b", primary, 0.1),
|
||||
overlay: blendTwoColors("#0f172a", primary, 0.08),
|
||||
primary: ENTERPRISE_LIGHT_NEUTRAL.bgPrimary,
|
||||
secondary: ENTERPRISE_LIGHT_NEUTRAL.bgSecondary,
|
||||
tertiary: ENTERPRISE_LIGHT_NEUTRAL.bgTertiary,
|
||||
},
|
||||
fill: {
|
||||
base: blendTwoColors("#0f172a", primary, 0.1),
|
||||
light: blendTwoColors("#1e293b", primary, 0.15),
|
||||
lighter: blendTwoColors("#0f172a", primary, 0.05),
|
||||
extraLight: blendTwoColors("#020617", primary, 0.02),
|
||||
dark: blendTwoColors("#334155", primary, 0.2),
|
||||
darker: blendTwoColors("#475569", primary, 0.25),
|
||||
},
|
||||
shadow: {
|
||||
base: `0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.24)`,
|
||||
light: `0 1px 2px 0 rgba(0, 0, 0, 0.2)`,
|
||||
lighter: `0 1px 1px 0 rgba(0, 0, 0, 0.12)`,
|
||||
dark: `0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.24)`,
|
||||
base: ENTERPRISE_LIGHT_NEUTRAL.fillBase,
|
||||
light: ENTERPRISE_LIGHT_NEUTRAL.fillLight,
|
||||
lighter: ENTERPRISE_LIGHT_NEUTRAL.fillLighter,
|
||||
extraLight: "#ffffff",
|
||||
dark: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.fillBase, primary, 0.12),
|
||||
darker: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.borderBase, primary, 0.16),
|
||||
},
|
||||
shadow: LIGHT_SHADOW_SCHEME,
|
||||
border: {
|
||||
base: blendTwoColors("#1e293b", primary, 0.12),
|
||||
light: blendTwoColors("#334155", primary, 0.15),
|
||||
lighter: blendTwoColors("#475569", primary, 0.2),
|
||||
extraLight: blendTwoColors("#64748b", primary, 0.25),
|
||||
dark: blendTwoColors("#0f172a", primary, 0.08),
|
||||
darker: blendTwoColors("#020617", primary, 0.05),
|
||||
},
|
||||
table: {
|
||||
bg: blendTwoColors("#020617", primary, 0.02),
|
||||
trBg: blendTwoColors("#020617", primary, 0.02),
|
||||
headerBg: blendTwoColors("#1e293b", primary, 0.15),
|
||||
hoverBg: blendTwoColors("#0f172a", primary, 0.1),
|
||||
border: blendTwoColors("#1e293b", primary, 0.12),
|
||||
base: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.borderBase, primary, 0.1),
|
||||
light: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.borderLight, primary, 0.08),
|
||||
lighter: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.borderLighter, primary, 0.05),
|
||||
extraLight: "#ffffff",
|
||||
dark: blendTwoColors("#94a3b8", primary, 0.15),
|
||||
darker: blendTwoColors("#64748b", primary, 0.2),
|
||||
},
|
||||
sidebar: {
|
||||
background: blendTwoColors("#0f172a", primary, 0.08),
|
||||
text: "#e2e8f0",
|
||||
activeText: getLightColor(primary, 0.15),
|
||||
activeBg: getLightColor(primary, 0.9),
|
||||
activeHoverBg: getLightColor(primary, 0.65),
|
||||
hover: blendTwoColors("#1e293b", primary, 0.15),
|
||||
background: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.bgSecondary, primary, 0.06),
|
||||
text: "#1e293b",
|
||||
activeText: getDarkColor(primary, 0.1),
|
||||
activeBg,
|
||||
activeHoverBg,
|
||||
hover: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.fillLight, primary, 0.15),
|
||||
},
|
||||
menu: {
|
||||
background: blendTwoColors("#0f172a", primary, 0.08),
|
||||
background: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.bgSecondary, primary, 0.04),
|
||||
text: "#1e293b",
|
||||
activeText: getDarkColor(primary, 0.1),
|
||||
activeBg,
|
||||
hover: blendTwoColors(ENTERPRISE_LIGHT_NEUTRAL.fillLight, primary, 0.08),
|
||||
},
|
||||
text: LIGHT_TEXT_SCHEME,
|
||||
};
|
||||
}
|
||||
|
||||
function generateDarkThemeScheme(primary: string): ColorScheme {
|
||||
const baseDarkBg = blendTwoColors(ENTERPRISE_DARK_NEUTRAL.bgPrimary, primary, 0.04);
|
||||
const secondaryDarkBg = blendTwoColors(ENTERPRISE_DARK_NEUTRAL.bgSecondary, primary, 0.06);
|
||||
const tertiaryDarkBg = blendTwoColors(ENTERPRISE_DARK_NEUTRAL.bgTertiary, primary, 0.08);
|
||||
const activeBg = blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillLight, primary, 0.22);
|
||||
const activeHoverBg = blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillLight, primary, 0.28);
|
||||
|
||||
return {
|
||||
bg: {
|
||||
primary: baseDarkBg,
|
||||
secondary: secondaryDarkBg,
|
||||
tertiary: tertiaryDarkBg,
|
||||
overlay: secondaryDarkBg,
|
||||
},
|
||||
fill: {
|
||||
base: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillBase, primary, 0.08),
|
||||
light: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillLight, primary, 0.12),
|
||||
lighter: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillLighter, primary, 0.06),
|
||||
extraLight: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.bgPrimary, primary, 0.04),
|
||||
dark: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.borderLight, primary, 0.16),
|
||||
darker: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.borderLighter, primary, 0.18),
|
||||
},
|
||||
shadow: DARK_SHADOW_SCHEME,
|
||||
border: {
|
||||
base: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.borderBase, primary, 0.1),
|
||||
light: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.borderLight, primary, 0.14),
|
||||
lighter: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.borderLighter, primary, 0.16),
|
||||
extraLight: blendTwoColors("#64748b", primary, 0.2),
|
||||
dark: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.bgSecondary, primary, 0.08),
|
||||
darker: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.bgPrimary, primary, 0.06),
|
||||
},
|
||||
sidebar: {
|
||||
background: secondaryDarkBg,
|
||||
text: "#e2e8f0",
|
||||
activeText: getLightColor(primary, 0.15),
|
||||
activeBg: getLightColor(primary, 0.9),
|
||||
hover: blendTwoColors("#1e293b", primary, 0.15),
|
||||
activeBg,
|
||||
activeHoverBg,
|
||||
hover: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillLight, primary, 0.14),
|
||||
},
|
||||
menu: {
|
||||
background: secondaryDarkBg,
|
||||
text: "#e2e8f0",
|
||||
activeText: getLightColor(primary, 0.15),
|
||||
activeBg,
|
||||
hover: blendTwoColors(ENTERPRISE_DARK_NEUTRAL.fillLight, primary, 0.14),
|
||||
},
|
||||
text: DARK_TEXT_SCHEME,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -340,18 +336,85 @@ const SEMANTIC_COLORS = {
|
||||
success: "#10b981",
|
||||
warning: "#f59e0b",
|
||||
danger: "#ef4444",
|
||||
info: "#64748b",
|
||||
info: "#2f86ff",
|
||||
} as const;
|
||||
|
||||
function assignThemeRoleColors(colors: Record<string, string>, scheme: ColorScheme): void {
|
||||
// Element Plus 核心变量
|
||||
colors["el-bg-color"] = scheme.bg.primary;
|
||||
colors["el-bg-color-page"] = scheme.bg.primary;
|
||||
colors["el-bg-color-overlay"] = scheme.bg.overlay ?? scheme.bg.secondary;
|
||||
|
||||
// 边框颜色
|
||||
colors["el-border-color"] = scheme.border.base;
|
||||
colors["el-border-color-light"] = scheme.border.light;
|
||||
colors["el-border-color-lighter"] = scheme.border.lighter;
|
||||
colors["el-border-color-extra-light"] = scheme.border.extraLight;
|
||||
colors["el-border-color-dark"] = scheme.border.dark;
|
||||
colors["el-border-color-darker"] = scheme.border.darker;
|
||||
|
||||
// 填充颜色
|
||||
colors["el-fill-color"] = scheme.fill.base;
|
||||
colors["el-fill-color-light"] = scheme.fill.light;
|
||||
colors["el-fill-color-lighter"] = scheme.fill.lighter;
|
||||
colors["el-fill-color-extra-light"] = scheme.fill.extraLight;
|
||||
colors["el-fill-color-dark"] = scheme.fill.dark;
|
||||
colors["el-fill-color-darker"] = scheme.fill.darker;
|
||||
|
||||
// 阴影效果
|
||||
colors["el-box-shadow"] = scheme.shadow.base;
|
||||
colors["el-box-shadow-light"] = scheme.shadow.light;
|
||||
colors["el-box-shadow-lighter"] = scheme.shadow.lighter;
|
||||
colors["el-box-shadow-dark"] = scheme.shadow.dark;
|
||||
|
||||
// 抽屉背景色
|
||||
colors["el-drawer-bg-color"] = scheme.fill.base;
|
||||
|
||||
// 菜单 / 侧边栏由 layout-* 语义变量统一驱动(见 assignCoreLayoutTokens)
|
||||
}
|
||||
|
||||
function assignCoreLayoutTokens(colors: Record<string, string>, coreTokens: CoreThemeTokens): void {
|
||||
colors["el-color-primary"] = coreTokens.brandPrimary;
|
||||
colors["layout-bg-primary"] = coreTokens.layoutBgPrimary;
|
||||
colors["layout-bg-secondary"] = coreTokens.layoutBgSecondary;
|
||||
colors["layout-bg-tertiary"] = coreTokens.layoutBgTertiary;
|
||||
colors["layout-sidebar-bg"] = coreTokens.layoutSidebarBg;
|
||||
colors["layout-sidebar-text"] = coreTokens.layoutSidebarText;
|
||||
colors["layout-sidebar-active-text"] = coreTokens.layoutSidebarActiveText;
|
||||
colors["layout-sidebar-active-bg"] = coreTokens.layoutSidebarActiveBg;
|
||||
colors["layout-sidebar-active-hover-bg"] = coreTokens.layoutSidebarActiveHoverBg;
|
||||
colors["layout-sidebar-hover"] = coreTokens.layoutSidebarHover;
|
||||
colors["layout-header-bg"] = coreTokens.layoutHeaderBg;
|
||||
colors["layout-header-text"] = coreTokens.layoutHeaderText;
|
||||
colors["layout-header-border"] = coreTokens.layoutHeaderBorder;
|
||||
colors["layout-tags-bg"] = coreTokens.layoutTagsBg;
|
||||
colors["layout-tags-border"] = coreTokens.layoutTagsBorder;
|
||||
colors["layout-tags-item-bg"] = coreTokens.layoutTagsItemBg;
|
||||
colors["layout-tags-item-text"] = coreTokens.layoutTagsItemText;
|
||||
colors["layout-tags-item-active-bg"] = coreTokens.layoutTagsItemActiveBg;
|
||||
colors["layout-tags-item-active-text"] = coreTokens.layoutTagsItemActiveText;
|
||||
colors["layout-content-bg"] = coreTokens.layoutContentBg;
|
||||
colors["layout-content-surface-bg"] = coreTokens.layoutContentSurfaceBg;
|
||||
colors["layout-menu-bg"] = coreTokens.layoutSidebarBg;
|
||||
colors["layout-menu-text"] = coreTokens.layoutSidebarText;
|
||||
colors["layout-menu-active-text"] = coreTokens.layoutSidebarActiveText;
|
||||
colors["layout-menu-active-bg"] = coreTokens.layoutMenuActiveBg;
|
||||
colors["layout-menu-hover"] = coreTokens.layoutSidebarHover;
|
||||
colors["layout-logo-bg"] = coreTokens.layoutSidebarBg;
|
||||
colors["layout-logo-text"] = coreTokens.layoutSidebarActiveText;
|
||||
colors["layout-text-primary"] = colors["layout-text-primary"] ?? "#0f172a";
|
||||
colors["layout-text-secondary"] = colors["layout-text-secondary"] ?? "#475569";
|
||||
colors["layout-text-tertiary"] = colors["layout-text-tertiary"] ?? "#64748b";
|
||||
colors["layout-text-disabled"] = colors["layout-text-disabled"] ?? "#94a3b8";
|
||||
}
|
||||
|
||||
export function generateThemeColors(primary: string, theme: ThemeMode) {
|
||||
// 处理带alpha通道的颜色值,去除alpha部分
|
||||
const cleanPrimary = primary.length === 9 ? primary.slice(0, 7) : primary;
|
||||
const cleanPrimary = normalizeHexColor(primary);
|
||||
const colors: Record<string, string> = {
|
||||
primary: cleanPrimary,
|
||||
...SEMANTIC_COLORS,
|
||||
};
|
||||
|
||||
const isLight = isLightColor(cleanPrimary);
|
||||
const rgb = hexToRgb(cleanPrimary);
|
||||
|
||||
const isDarkMode = theme === ThemeMode.DARK;
|
||||
@@ -359,6 +422,7 @@ export function generateThemeColors(primary: string, theme: ThemeMode) {
|
||||
? generateDarkModeVariants(cleanPrimary)
|
||||
: generateColorVariants(cleanPrimary);
|
||||
|
||||
// 生成颜色变体,使用 Element Plus 标准命名
|
||||
primaryVariants.light.forEach((color, i) => {
|
||||
colors[`primary-light-${i + 1}`] = color;
|
||||
});
|
||||
@@ -372,100 +436,29 @@ export function generateThemeColors(primary: string, theme: ThemeMode) {
|
||||
colors[`${name}-dark-2`] = variants.dark;
|
||||
});
|
||||
|
||||
// 品牌颜色 RGB 值,用于科技感效果
|
||||
colors["brand-primary-rgb"] = `${rgb[0]}, ${rgb[1]}, ${rgb[2]}`;
|
||||
Object.entries(SEMANTIC_COLORS).forEach(([name, color]) => {
|
||||
const c = hexToRgb(color);
|
||||
colors[`brand-${name}-rgb`] = `${c[0]}, ${c[1]}, ${c[2]}`;
|
||||
});
|
||||
|
||||
// 生成主题方案
|
||||
const scheme = isDarkMode
|
||||
? generateDarkThemeScheme(cleanPrimary, isLight)
|
||||
: generateLightThemeScheme(cleanPrimary, isLight);
|
||||
? generateDarkThemeScheme(cleanPrimary)
|
||||
: generateLightThemeScheme(cleanPrimary);
|
||||
|
||||
colors["custom-bg-primary"] = scheme.bg.primary;
|
||||
colors["custom-bg-secondary"] = scheme.bg.secondary;
|
||||
colors["custom-bg-tertiary"] = scheme.bg.tertiary;
|
||||
// 文本语义变量
|
||||
colors["layout-text-primary"] = scheme.text.primary;
|
||||
colors["layout-text-secondary"] = scheme.text.secondary;
|
||||
colors["layout-text-tertiary"] = scheme.text.tertiary;
|
||||
colors["layout-text-disabled"] = scheme.text.disabled;
|
||||
|
||||
colors["el-bg-color"] = scheme.bg.primary;
|
||||
colors["el-bg-color-page"] = scheme.bg.primary;
|
||||
colors["el-bg-color-overlay"] = scheme.bg.overlay ?? scheme.bg.secondary;
|
||||
// 角色色和核心 token(主题控制主入口)
|
||||
assignThemeRoleColors(colors, scheme);
|
||||
const coreTokens = createCoreThemeTokens(scheme, cleanPrimary);
|
||||
|
||||
if (isDarkMode) {
|
||||
colors["el-text-color-primary"] = "#f8fafc";
|
||||
colors["el-text-color-regular"] = "#e2e8f0";
|
||||
colors["el-text-color-secondary"] = "#94a3b8";
|
||||
colors["el-text-color-placeholder"] = "#64748b";
|
||||
colors["el-disabled-bg-color"] = "#0f172a";
|
||||
colors["el-disabled-text-color"] = "#475569";
|
||||
colors["el-disabled-border-color"] = "#1e293b";
|
||||
colors["el-overlay-color"] = "rgba(0, 0, 0, 0.7)";
|
||||
colors["el-overlay-color-light"] = "rgba(0, 0, 0, 0.5)";
|
||||
colors["el-overlay-color-lighter"] = "rgba(0, 0, 0, 0.3)";
|
||||
colors["el-scrollbar-bg-color"] = "#0f172a";
|
||||
colors["el-scrollbar-thumb-color"] = "#334155";
|
||||
colors["el-scrollbar-thumb-hover-color"] = "#475569";
|
||||
} else {
|
||||
colors["el-text-color-primary"] = "#0f172a";
|
||||
colors["el-text-color-regular"] = "#334155";
|
||||
colors["el-text-color-secondary"] = "#64748b";
|
||||
colors["el-text-color-placeholder"] = "#94a3b8";
|
||||
colors["el-disabled-bg-color"] = "#f1f5f9";
|
||||
colors["el-disabled-text-color"] = "#94a3b8";
|
||||
colors["el-disabled-border-color"] = "#e2e8f0";
|
||||
colors["el-overlay-color"] = "rgba(15, 23, 42, 0.5)";
|
||||
colors["el-overlay-color-light"] = "rgba(15, 23, 42, 0.3)";
|
||||
colors["el-overlay-color-lighter"] = "rgba(15, 23, 42, 0.15)";
|
||||
colors["el-scrollbar-bg-color"] = "#f1f5f9";
|
||||
colors["el-scrollbar-thumb-color"] = "#cbd5e1";
|
||||
colors["el-scrollbar-thumb-hover-color"] = "#94a3b8";
|
||||
}
|
||||
|
||||
colors["el-border-color"] = scheme.border.base;
|
||||
colors["el-border-color-light"] = scheme.border.light;
|
||||
colors["el-border-color-lighter"] = scheme.border.lighter;
|
||||
colors["el-border-color-extra-light"] = scheme.border.extraLight;
|
||||
colors["el-border-color-dark"] = scheme.border.dark;
|
||||
colors["el-border-color-darker"] = scheme.border.darker;
|
||||
|
||||
colors["el-fill-color"] = scheme.fill.base;
|
||||
colors["el-fill-color-light"] = scheme.fill.light;
|
||||
colors["el-fill-color-lighter"] = scheme.fill.lighter;
|
||||
colors["el-fill-color-extra-light"] = scheme.fill.extraLight;
|
||||
colors["el-fill-color-dark"] = scheme.fill.dark;
|
||||
colors["el-fill-color-darker"] = scheme.fill.darker;
|
||||
|
||||
colors["el-box-shadow"] = scheme.shadow.base;
|
||||
colors["el-box-shadow-light"] = scheme.shadow.light;
|
||||
colors["el-box-shadow-lighter"] = scheme.shadow.lighter;
|
||||
colors["el-box-shadow-dark"] = scheme.shadow.dark;
|
||||
|
||||
colors["el-table-bg-color"] = scheme.table.bg;
|
||||
colors["el-table-tr-bg-color"] = scheme.table.trBg;
|
||||
colors["el-table-header-bg-color"] = scheme.table.headerBg;
|
||||
colors["el-table-row-hover-bg-color"] = scheme.table.hoverBg;
|
||||
colors["el-table-border-color"] = scheme.table.border;
|
||||
|
||||
// 抽屉背景色 - 使用主题填充色
|
||||
colors["el-drawer-bg-color"] = scheme.fill.base;
|
||||
|
||||
// 侧边栏和菜单相关变量
|
||||
colors["sidebar-background"] = scheme.sidebar.background;
|
||||
colors["sidebar-text-color"] = scheme.sidebar.text;
|
||||
colors["sidebar-active-text-color"] = scheme.sidebar.activeText;
|
||||
colors["sidebar-active-bg"] = scheme.sidebar.activeBg;
|
||||
colors["sidebar-active-hover-bg"] = scheme.sidebar.activeHoverBg;
|
||||
colors["sidebar-hover"] = scheme.sidebar.hover;
|
||||
|
||||
// Logo 相关变量
|
||||
colors["sidebar-logo-background"] = scheme.sidebar.background;
|
||||
colors["sidebar-logo-text-color"] = scheme.sidebar.activeText;
|
||||
|
||||
// 布局菜单变量 - 确保与布局文件兼容
|
||||
colors["menu-background"] = scheme.menu.background;
|
||||
colors["menu-text"] = scheme.menu.text;
|
||||
colors["menu-active-text"] = scheme.menu.activeText;
|
||||
colors["menu-active-bg"] = scheme.menu.activeBg;
|
||||
colors["menu-hover"] = scheme.menu.hover;
|
||||
assignCoreLayoutTokens(colors, coreTokens);
|
||||
|
||||
return colors;
|
||||
}
|
||||
@@ -473,16 +466,37 @@ export function generateThemeColors(primary: string, theme: ThemeMode) {
|
||||
export function applyTheme(colors: Record<string, string>) {
|
||||
const el = document.documentElement;
|
||||
|
||||
const setVar = (key: string, value: string) => {
|
||||
el.style.setProperty(`--${key}`, value);
|
||||
};
|
||||
|
||||
const pickColor = (keys: string[]) => keys.map((k) => colors[k]).find(Boolean);
|
||||
const isDirectCssVar = (key: string) =>
|
||||
key.startsWith("el-") || key.startsWith("brand-") || key.startsWith("layout-");
|
||||
|
||||
// 仅允许核心调色板变量走 --el-color-*,避免无关变量污染 :root
|
||||
const isAllowedElColorToken = (key: string) =>
|
||||
/^(primary|success|warning|danger|info)$/.test(key) ||
|
||||
/^(primary|success|warning|danger|info)-light-[1-9]$/.test(key) ||
|
||||
/^(primary|success|warning|danger|info)-dark-2$/.test(key);
|
||||
|
||||
Object.entries(colors).forEach(([key, value]) => {
|
||||
if (key.startsWith("el-")) {
|
||||
el.style.setProperty(`--${key}`, value);
|
||||
} else if (key.startsWith("sidebar-") || key.startsWith("menu-")) {
|
||||
el.style.setProperty(`--${key}`, value);
|
||||
} else {
|
||||
el.style.setProperty(`--el-color-${key}`, value);
|
||||
if (isDirectCssVar(key)) {
|
||||
setVar(key, value);
|
||||
return;
|
||||
}
|
||||
if (isAllowedElColorToken(key)) {
|
||||
// Element Plus 色板变量(--el-color-primary-light-1 等)
|
||||
setVar(`el-color-${key}`, value);
|
||||
}
|
||||
});
|
||||
|
||||
// 确保布局相关的背景变量也被设置
|
||||
setVar("bg-primary", pickColor(["layout-bg-primary", "el-bg-color"]) ?? "");
|
||||
setVar("bg-secondary", pickColor(["layout-bg-secondary", "el-bg-color-overlay"]) ?? "");
|
||||
setVar("bg-tertiary", pickColor(["layout-bg-tertiary", "el-bg-color-overlay"]) ?? "");
|
||||
|
||||
// 触发主题更新动画
|
||||
requestAnimationFrame(() => {
|
||||
el.style.setProperty("--theme-update-trigger", Date.now().toString());
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="chat-input">
|
||||
<div class="chat-input" :class="{ 'chat-input--disabled': disabled }">
|
||||
<div class="input-wrapper">
|
||||
<div v-if="uploadedFiles.length > 0" class="uploaded-files">
|
||||
<div v-for="file in uploadedFiles" :key="file.id" class="file-item">
|
||||
@@ -201,19 +201,26 @@ defineExpose({
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: 20px;
|
||||
background: var(--el-bg-color-page);
|
||||
background: var(--el-bg-color-overlay);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
box-shadow: var(--el-box-shadow);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--el-color-primary);
|
||||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--el-color-primary) 35%, transparent);
|
||||
}
|
||||
|
||||
.message-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -258,11 +265,11 @@ defineExpose({
|
||||
.send-button {
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 6px rgba(24, 144, 255, 0.3);
|
||||
box-shadow: 0 2px 8px color-mix(in srgb, var(--el-color-primary) 35%, transparent);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
|
||||
box-shadow: 0 4px 14px color-mix(in srgb, var(--el-color-primary) 45%, transparent);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@@ -278,10 +285,26 @@ defineExpose({
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--el-text-color-tertiary);
|
||||
color: var(--el-text-color-secondary);
|
||||
text-align: center;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
}
|
||||
|
||||
&.chat-input--disabled .input-wrapper .input-container {
|
||||
opacity: 0.72;
|
||||
filter: grayscale(0.06);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-border-color-light);
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
transform: none;
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--el-border-color-light);
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -73,7 +73,8 @@ defineExpose({
|
||||
.chat-messages {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
background: var(--el-bg-color);
|
||||
/* 与 index chat-main 同底,避免 disabled 灰 + page 色打架 */
|
||||
background: transparent;
|
||||
|
||||
.messages-list {
|
||||
max-width: 800px;
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="navbar-right">
|
||||
<el-button v-if="hasMessages" text :icon="Delete" @click="handleClearChat">
|
||||
清空对话
|
||||
</el-button>
|
||||
<el-button text :icon="Setting" @click="handleToggleConnection">
|
||||
{{ isConnected ? "断开连接" : "重新连接" }}
|
||||
</el-button>
|
||||
@@ -25,6 +22,9 @@
|
||||
</el-icon>
|
||||
<span class="status-text">{{ connectionStatusText }}</span>
|
||||
</el-tag>
|
||||
<el-button v-if="hasMessages" text :icon="Delete" @click="handleClearChat">
|
||||
清空对话
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -108,6 +108,11 @@ const toggleSidebar = () => {
|
||||
background: var(--el-fill-color-light);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid color-mix(in srgb, var(--el-color-primary) 45%, transparent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.collapse-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@@ -118,14 +123,30 @@ const toggleSidebar = () => {
|
||||
|
||||
.navbar-right {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
/* EP 相邻按钮自带 margin-left,叠在 flex gap 上会导致间距忽大忽小 */
|
||||
:deep(.el-button) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 32px;
|
||||
padding: 0 12px;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
|
||||
:deep(.el-tag__content) {
|
||||
display: inline-flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
&.connected {
|
||||
|
||||
@@ -75,6 +75,7 @@ import MarkdownIt from "markdown-it";
|
||||
import markdownItHighlightjs from "markdown-it-highlightjs";
|
||||
import hljs from "highlight.js";
|
||||
import DOMPurify from "dompurify";
|
||||
/* 亮色用 atom-one;暗色由文末全局块覆盖 .hljs 底与字色,避免整段代码发亮底 */
|
||||
import "highlight.js/styles/atom-one-light.css";
|
||||
import { useUserStoreHook } from "@/store";
|
||||
import type { ChatMessage } from "@/views/module_ai/chat/types";
|
||||
@@ -347,7 +348,9 @@ const formatFileSize = (bytes: number): string => {
|
||||
line-height: 1.6;
|
||||
color: var(--el-text-color-primary);
|
||||
word-wrap: break-word;
|
||||
transition: all 0.3s ease;
|
||||
transition:
|
||||
max-height 0.25s ease,
|
||||
opacity 0.2s ease;
|
||||
|
||||
&.collapsed {
|
||||
position: relative;
|
||||
@@ -361,7 +364,10 @@ const formatFileSize = (bytes: number): string => {
|
||||
left: 0;
|
||||
height: 60px;
|
||||
content: "";
|
||||
background: linear-gradient(transparent, var(--el-bg-color));
|
||||
background: linear-gradient(
|
||||
transparent,
|
||||
var(--chat-area-bg, var(--layout-content-canvas, var(--el-bg-color-page)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,6 +490,29 @@ const formatFileSize = (bytes: number): string => {
|
||||
.message-actions {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.message-body .message-text {
|
||||
padding: 10px 14px;
|
||||
background: color-mix(in srgb, var(--el-color-primary) 10%, var(--el-bg-color-overlay));
|
||||
border: 1px solid
|
||||
color-mix(in srgb, var(--el-color-primary) 18%, var(--el-border-color-light));
|
||||
border-radius: 12px;
|
||||
|
||||
&.collapsed::after {
|
||||
background: linear-gradient(
|
||||
transparent,
|
||||
color-mix(in srgb, var(--el-color-primary) 10%, var(--el-bg-color-overlay))
|
||||
);
|
||||
}
|
||||
|
||||
:deep(pre) {
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
:deep(code:not(pre code)) {
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,3 +536,36 @@ const formatFileSize = (bytes: number): string => {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 暗色下覆盖 highlight.js 亮色主题,避免代码块发白底 -->
|
||||
<style lang="scss">
|
||||
html.dark .chat-messages .message-text {
|
||||
pre.hljs,
|
||||
code.hljs {
|
||||
color: var(--el-text-color-regular) !important;
|
||||
background: var(--el-fill-color) !important;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: var(--el-text-color-secondary) !important;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-built_in {
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-title,
|
||||
.hljs-attr {
|
||||
color: var(--el-color-success) !important;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-literal {
|
||||
color: var(--el-color-warning) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -388,7 +388,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
|
||||
box-shadow: 0 4px 12px color-mix(in srgb, var(--el-color-primary) 30%, transparent);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@@ -486,9 +486,17 @@ defineExpose({
|
||||
|
||||
&.active {
|
||||
color: var(--el-color-primary);
|
||||
background: var(--el-color-primary-light-9);
|
||||
border-color: var(--el-color-primary-light-7);
|
||||
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.1);
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 9%,
|
||||
var(--chat-area-bg, var(--el-bg-color-overlay))
|
||||
);
|
||||
border-color: color-mix(
|
||||
in srgb,
|
||||
var(--el-color-primary) 18%,
|
||||
var(--el-border-color-light)
|
||||
);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.session-icon {
|
||||
|
||||
@@ -8,21 +8,18 @@
|
||||
<p class="welcome-subtitle">我是您的专属AI助手,可以帮您回答问题、处理任务和进行智能对话</p>
|
||||
|
||||
<div class="example-prompts">
|
||||
<div class="prompt-card" @click="handlePromptClick('请介绍一下FastApiAdmin系统')">
|
||||
<h4>系统介绍</h4>
|
||||
<p>请介绍一下FastApiAdmin系统</p>
|
||||
</div>
|
||||
<div class="prompt-card" @click="handlePromptClick('如何在系统中创建新的模块?')">
|
||||
<h4>开发指导</h4>
|
||||
<p>如何在系统中创建新的模块?</p>
|
||||
</div>
|
||||
<div class="prompt-card" @click="handlePromptClick('系统的权限管理是如何工作的?')">
|
||||
<h4>权限管理</h4>
|
||||
<p>FA系统的权限管理是如何工作的?</p>
|
||||
</div>
|
||||
<div class="prompt-card" @click="handlePromptClick('如何优化FA系统的性能?')">
|
||||
<h4>性能优化</h4>
|
||||
<p>如何优化系统的性能?</p>
|
||||
<div
|
||||
v-for="card in promptCards"
|
||||
:key="card.prompt"
|
||||
class="prompt-card"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="handlePromptClick(card.prompt)"
|
||||
@keydown.enter.prevent="handlePromptClick(card.prompt)"
|
||||
@keydown.space.prevent="handlePromptClick(card.prompt)"
|
||||
>
|
||||
<h4>{{ card.title }}</h4>
|
||||
<p>{{ card.body }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -38,6 +35,17 @@ interface Emits {
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const promptCards = [
|
||||
{ title: "系统介绍", body: "请介绍一下FastApiAdmin系统", prompt: "请介绍一下FastApiAdmin系统" },
|
||||
{ title: "开发指导", body: "如何在系统中创建新的模块?", prompt: "如何在系统中创建新的模块?" },
|
||||
{
|
||||
title: "权限管理",
|
||||
body: "FA系统的权限管理是如何工作的?",
|
||||
prompt: "系统的权限管理是如何工作的?",
|
||||
},
|
||||
{ title: "性能优化", body: "如何优化系统的性能?", prompt: "如何优化FA系统的性能?" },
|
||||
];
|
||||
|
||||
const handlePromptClick = (prompt: string) => {
|
||||
emit("prompt-click", prompt);
|
||||
};
|
||||
@@ -85,10 +93,13 @@ const handlePromptClick = (prompt: string) => {
|
||||
padding: 20px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
background: var(--el-bg-color-page);
|
||||
background: var(--el-bg-color-overlay);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
@@ -96,6 +107,12 @@ const handlePromptClick = (prompt: string) => {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid color-mix(in srgb, var(--el-color-primary) 40%, transparent);
|
||||
outline-offset: 2px;
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 14px;
|
||||
|
||||
@@ -301,12 +301,20 @@ onUnmounted(disconnectWebSocket);
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main-chat {
|
||||
/* L2 内容面:与 AppMain 的 L0 画布(留白/间隙)区分开,避免与 gap 同色 */
|
||||
--chat-area-bg: var(--layout-content-surface-bg, var(--el-bg-color-overlay));
|
||||
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: var(--chat-area-bg);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
|
||||
/* 与右侧同一表面色;与内容区的分界交给 Sidebar 的竖线即可 */
|
||||
.sidebar-container {
|
||||
width: 200px;
|
||||
background: var(--el-bg-color);
|
||||
background: transparent;
|
||||
transition: width 0.3s ease;
|
||||
|
||||
&.collapsed {
|
||||
@@ -319,26 +327,28 @@ onUnmounted(disconnectWebSocket);
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: var(--chat-area-bg);
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
height: auto;
|
||||
padding: 0;
|
||||
background: var(--el-bg-color);
|
||||
background: var(--chat-area-bg);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
.chat-main {
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background: var(--chat-area-bg);
|
||||
}
|
||||
|
||||
.chat-footer {
|
||||
height: auto;
|
||||
min-height: 80px;
|
||||
padding: 0;
|
||||
background: var(--el-bg-color);
|
||||
border-top: 1px solid var(--el-border-color-light);
|
||||
background: var(--chat-area-bg);
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -138,7 +138,6 @@
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
<el-button
|
||||
v-hasPerm="['module_generator:gencode:create']"
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="createTableVisible = true"
|
||||
>
|
||||
@@ -78,7 +77,6 @@
|
||||
<el-button
|
||||
v-hasPerm="['module_generator:gencode:import']"
|
||||
type="success"
|
||||
plain
|
||||
icon="Upload"
|
||||
@click="handleImportClick"
|
||||
>
|
||||
@@ -89,7 +87,6 @@
|
||||
<el-button
|
||||
v-hasPerm="['module_generator:gencode:delete']"
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="ids.length === 0"
|
||||
@click="handleDelete()"
|
||||
@@ -101,7 +98,6 @@
|
||||
<el-button
|
||||
v-hasPerm="['module_generator:gencode:code']"
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
:disabled="!canGenerate"
|
||||
@click="handleGenTable('0')"
|
||||
@@ -145,7 +141,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="tableList"
|
||||
highlight-current-row
|
||||
class="data-table__content"
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
|
||||
@@ -145,6 +145,7 @@
|
||||
height="calc(100vh - 290px)"
|
||||
max-height="calc(100vh - 290px)"
|
||||
border
|
||||
stripe
|
||||
>
|
||||
<template #empty>
|
||||
<el-empty :image-size="80" description="暂无数据" />
|
||||
|
||||
@@ -107,7 +107,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="server.disks" border>
|
||||
<el-table :data="server.disks" border stripe>
|
||||
<template #empty>
|
||||
<el-empty :image-size="80" description="暂无数据" />
|
||||
</template>
|
||||
|
||||
@@ -143,7 +143,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 430px)"
|
||||
max-height="calc(100vh - 430px)"
|
||||
border
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -142,7 +142,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -192,7 +192,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -163,7 +163,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -177,7 +177,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -188,7 +188,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 445px)"
|
||||
max-height="calc(100vh - 445px)"
|
||||
border
|
||||
|
||||
@@ -327,7 +327,6 @@
|
||||
v-loading="logLoading"
|
||||
:data="executionLogData"
|
||||
class="data-table__content"
|
||||
highlight-current-row
|
||||
border
|
||||
stripe
|
||||
height="calc(100vh - 240px)"
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
height="calc(100vh - 440px)"
|
||||
max-height="calc(100vh - 440px)"
|
||||
border
|
||||
|
||||
@@ -107,7 +107,6 @@
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="dataSource"
|
||||
highlight-current-row
|
||||
class="data-table__content"
|
||||
height="450"
|
||||
max-height="450"
|
||||
|
||||
Reference in New Issue
Block a user