diff --git a/src/layouts/LeftLayout.vue b/src/layouts/LeftLayout.vue
index 2489c54f..6f5f5998 100644
--- a/src/layouts/LeftLayout.vue
+++ b/src/layouts/LeftLayout.vue
@@ -45,6 +45,8 @@ const appStore = useAppStore();
diff --git a/src/layouts/MixLayout.vue b/src/layouts/MixLayout.vue
index e73c7dec..581d3313 100644
--- a/src/layouts/MixLayout.vue
+++ b/src/layouts/MixLayout.vue
@@ -229,6 +229,8 @@ watch(
diff --git a/src/layouts/TopLayout.vue b/src/layouts/TopLayout.vue
index a07e425f..71cf79fc 100644
--- a/src/layouts/TopLayout.vue
+++ b/src/layouts/TopLayout.vue
@@ -49,6 +49,8 @@ const isLogoCollapsed = computed(() => width.value < 768);
diff --git a/src/styles/base/_mixins.scss b/src/styles/base/_mixins.scss
new file mode 100644
index 00000000..652c9f6d
--- /dev/null
+++ b/src/styles/base/_mixins.scss
@@ -0,0 +1,68 @@
+/**
+ * 布局 Mixins
+ *
+ * 所有布局组件共享的样式抽象,确保单一来源。
+ *
+ * ═══════════════════════════════════════════════════════════
+ * 主题变量契约(添加新主题时必须定义以下 CSS 变量)
+ * ═══════════════════════════════════════════════════════════
+ *
+ * --menu-background 菜单背景色
+ * --menu-text 菜单文字色
+ * --menu-active-text 菜单激活文字色(通常复用 --el-menu-active-color)
+ * --menu-hover 菜单悬浮背景色【自动派生——见 _theme.scss 颜色令牌】
+ * --sidebar-logo-background Logo 区域背景色
+ * --sidebar-logo-text-color Logo 区域文字色
+ *
+ * 自动派生规则:--menu-hover 通过 color-mix() 从 --menu-background 派生,
+ * 因此新主题只需定义 --menu-background,hover 颜色自动生成。
+ * 如需覆盖自动派生值,显式设置 --menu-hover 即可。
+ */
+
+@use "variables" as *;
+
+// ============================================
+// 布局计算 Mixins
+// ============================================
+
+/**
+ * 计算主内容区高度(考虑 TagsView 是否存在)
+ *
+ * 使用场景:各布局文件中的 .hasTagsView 样式块
+ *
+ * @example
+ * .hasTagsView {
+ * :deep(.app-main) {
+ * @include app-main-height-with-tags;
+ * }
+ * }
+ */
+@mixin app-main-height-with-tags {
+ height: calc(100vh - $navbar-height - $tags-view-height) !important;
+}
+
+/**
+ * 主内容区基础高度(无 TagsView)
+ *
+ * @example
+ * .layout__main {
+ * @include app-main-height;
+ * }
+ */
+@mixin app-main-height {
+ height: calc(100vh - $navbar-height);
+}
+
+/**
+ * 侧边栏滚动区高度(带 Logo 时)
+ */
+@mixin sidebar-scroll-height-with-logo {
+ height: calc(100vh - $navbar-height);
+}
+
+/**
+ * 侧边栏滚动区高度(带底部折叠按钮时,如 MixLayout 左侧)
+ */
+@mixin sidebar-scroll-height-with-toggle {
+ height: calc(100vh - $navbar-height - $sidebar-toggle-height);
+}
diff --git a/src/styles/base/_theme.scss b/src/styles/base/_theme.scss
index 74cd2432..3f2738dc 100644
--- a/src/styles/base/_theme.scss
+++ b/src/styles/base/_theme.scss
@@ -1,17 +1,45 @@
/**
* 主题变量定义
+ *
+ * ═══════════════════════════════════════════════════════════
+ * 主题变量契约
+ * ═══════════════════════════════════════════════════════════
+ *
+ * 新增主题只需定义以下变量,其余自动派生:
+ *
+ * 必须定义:
+ * --menu-background 菜单背景色
+ * --menu-text 菜单文字色
+ * --menu-active-text 菜单激活文字色
+ * --sidebar-logo-background Logo 区域背景色
+ * --sidebar-logo-text-color Logo 区域文字色
+ *
+ * 可选覆盖(有自动派生默认值):
+ * --menu-hover 菜单悬浮背景色
+ * → 浅色主题:从 --el-color-primary 与背景混合派生
+ * → 深色主题:半透明黑色叠加层,自适应动态背景
+ * → 可显式覆盖以微调
*/
+// ============================================
+// SCSS 颜色令牌(构建时源)
+// ============================================
+
+$menu-bg-light: #fff;
+$menu-hover-light: #e6f4ff; // 设计指定色,非纯推导
+
+$menu-bg-classic-blue: #304156;
+
// ============================================
// 默认主题(浅色 + 白色侧边栏)
// ============================================
:root {
// 菜单
- --menu-background: #fff;
+ --menu-background: #{$menu-bg-light};
--menu-text: #606266;
--menu-active-text: var(--el-menu-active-color);
- --menu-hover: #e6f4ff;
+ --menu-hover: #{$menu-hover-light};
// 侧边栏 Logo
--sidebar-logo-background: #fafafa;
@@ -57,10 +85,11 @@
// ============================================
html.sidebar-color-blue {
- --menu-background: #304156;
+ --menu-background: #{$menu-bg-classic-blue};
--menu-text: #bfcbd9;
--menu-active-text: var(--el-menu-active-color);
- --menu-hover: #263445;
+ // 自动派生:背景色加深 20% → #263445
+ --menu-hover: color-mix(in srgb, var(--menu-background) 80%, #000 20%);
--sidebar-logo-background: #2d3748;
--sidebar-logo-text-color: #fff;
}
@@ -73,6 +102,7 @@ html.dark {
--menu-background: var(--el-bg-color-overlay);
--menu-text: #fff;
--menu-active-text: var(--el-menu-active-color);
+ // 半透明叠加层:自适应 Element Plus 动态 overlay 背景色
--menu-hover: rgb(0 0 0 / 20%);
--sidebar-logo-background: rgb(0 0 0 / 20%);
--sidebar-logo-text-color: #fff;
diff --git a/src/styles/base/_variables.scss b/src/styles/base/_variables.scss
index 8ec4ccbd..4e565522 100644
--- a/src/styles/base/_variables.scss
+++ b/src/styles/base/_variables.scss
@@ -11,6 +11,7 @@ $sidebar-width: 210px;
$sidebar-width-collapsed: 54px;
$navbar-height: 50px;
$tags-view-height: 40px;
+$sidebar-toggle-height: 50px;
// ============================================
// CSS 变量映射(供组件和 SCSS 使用)
diff --git a/src/views/demo/api/apifox.vue b/src/views/demo/api/apifox.vue
index ea4593c1..a6eaea04 100644
--- a/src/views/demo/api/apifox.vue
+++ b/src/views/demo/api/apifox.vue
@@ -11,17 +11,15 @@
diff --git a/src/views/demo/internal-doc.vue b/src/views/demo/internal-doc.vue
index 16ac5824..baa54d7c 100644
--- a/src/views/demo/internal-doc.vue
+++ b/src/views/demo/internal-doc.vue
@@ -4,17 +4,15 @@