diff --git a/src/layouts/README.md b/src/layouts/README.md
index f31eb7b5..9d36e764 100644
--- a/src/layouts/README.md
+++ b/src/layouts/README.md
@@ -1,34 +1,71 @@
# 布局系统
-本项目的布局系统采用模块化、可组合式API的架构,支持三种不同的布局模式:
-
-1. **左侧菜单布局 (LeftSideLayout)**: 传统的管理系统布局,左侧为菜单栏,顶部为导航栏
-2. **顶部菜单布局 (TopMenuLayout)**: 顶部为主菜单栏,适合菜单项较少的应用
-3. **混合菜单布局 (MixMenuLayout)**: 顶部为一级菜单,左侧为对应的子菜单,适合菜单层级较多的复杂应用
-
## 目录结构
```
layouts/
-├── README.md # 文档说明
-├── index.vue # 布局入口,根据设置选择对应的布局组件
-├── composables/ # 可组合式API
-│ ├── useLayout.ts # 布局通用逻辑
-│ ├── useLayoutResponsive.ts # 响应式布局逻辑
-│ └── useLayoutMenu.ts # 菜单处理逻辑
-└── components/ # 布局组件
- ├── LayoutBase.vue # 基础布局组件
- ├── SidebarMenu.vue # 菜单组件
- ├── common/ # 公共组件
- │ └── LayoutSidebar.vue # 侧边栏公共组件
- ├── LeftSideLayout/ # 左侧菜单布局
- │ └── index.vue
- ├── TopMenuLayout/ # 顶部菜单布局
- │ └── index.vue
- └── MixMenuLayout/ # 混合菜单布局
- └── index.vue
+├── index.vue # 布局系统入口,根据设置动态加载布局
+├── BaseLayout.vue # 基础布局容器,提供通用功能
+├── LeftLayout.vue # 左侧菜单布局
+├── TopLayout.vue # 顶部菜单布局
+├── MixLayout.vue # 混合布局(顶部+左侧)
+├── components/ # 布局相关组件
+│ ├── AppMain.vue # 主内容区域
+│ ├── NavBar.vue # 导航栏
+│ ├── NavbarActions.vue # 导航栏右侧操作区
+│ ├── TagsView.vue # 标签页视图
+│ ├── LayoutMenu.vue # 菜单组件
+│ ├── Sidebar/ # 侧边栏相关组件
+│ │ ├── SidebarLogo.vue # Logo 组件
+│ │ ├── SidebarMenu.vue # 菜单主体(未使用)
+│ │ ├── SidebarMenuItem.vue # 菜单项
+│ │ ├── SidebarMenuItemTitle.vue # 菜单项标题
+│ │ └── SidebarMixTopMenu.vue # 混合布局顶部菜单
+│ ├── Settings/ # 设置面板
+│ │ └── index.vue # 设置面板主组件(包含布局选择)
+│ └── common/ # 通用组件
+│ └── LayoutSidebar.vue # 侧边栏容器
+└── composables/ # 组合式函数
+ ├── useLayout.ts # 布局相关逻辑
+ ├── useLayoutMenu.ts # 菜单相关逻辑
+ └── useLayoutResponsive.ts # 响应式处理
```
+## 布局说明
+
+### 1. LeftLayout(左侧布局)
+- 传统的左侧固定菜单布局
+- 支持菜单折叠/展开
+- 适合大多数管理系统
+
+### 2. TopLayout(顶部布局)
+- 菜单位于顶部横向排列
+- 适合一级菜单较少的系统
+- 节省横向空间
+
+### 3. MixLayout(混合布局)
+- 一级菜单在顶部,二级菜单在左侧
+- 适合菜单层级较多的大型系统
+- 提供更好的菜单组织方式
+
+## 使用方式
+
+布局系统会根据 `settings store` 中的 `layout` 配置自动切换:
+
+```typescript
+// 在设置面板中切换布局
+// 或通过代码:
+settingsStore.layout = LayoutMode.LEFT; // 'left' | 'top' | 'mix'
+```
+
+## 自定义布局
+
+如需添加新布局:
+
+1. 在 `layouts/` 目录下创建新的布局组件(如 `CustomLayout.vue`)
+2. 在 `index.vue` 中导入并添加到切换逻辑
+3. 在 `enums/settings/layout.enum.ts` 中添加新的布局类型
+
## 主要功能
1. **响应式适配**: 自动适配桌面端和移动端,移动端下自动收起侧边栏
diff --git a/src/layouts/components/AppMain/index.vue b/src/layouts/components/AppMain.vue
similarity index 100%
rename from src/layouts/components/AppMain/index.vue
rename to src/layouts/components/AppMain.vue
diff --git a/src/layouts/components/Settings/index.vue b/src/layouts/components/Settings.vue
similarity index 63%
rename from src/layouts/components/Settings/index.vue
rename to src/layouts/components/Settings.vue
index 06554be0..925e04ac 100644
--- a/src/layouts/components/Settings/index.vue
+++ b/src/layouts/components/Settings.vue
@@ -61,7 +61,31 @@
{{ t("settings.navigation") }}
-
+
+
+
@@ -72,6 +96,20 @@ import { LayoutMode } from "@/enums/settings/layout.enum";
import { ThemeMode } from "@/enums/settings/theme.enum";
import { SidebarColor } from "@/enums/settings/theme.enum";
import { useSettingsStore, usePermissionStore, useAppStore } from "@/store";
+
+// 布局选项配置
+interface LayoutOption {
+ value: LayoutMode;
+ label: string;
+ className: string;
+}
+
+const layoutOptions: LayoutOption[] = [
+ { value: LayoutMode.LEFT, label: "左侧模式", className: "left" },
+ { value: LayoutMode.TOP, label: "顶部模式", className: "top" },
+ { value: LayoutMode.MIX, label: "混合模式", className: "mix" },
+];
+
// 颜色预设
const colorPresets = [
"#4080FF",
@@ -190,4 +228,97 @@ const handleCloseDrawer = () => {
}
}
}
+
+/* 布局选择器样式 */
+.layout-select {
+ display: flex;
+ gap: 10px;
+ justify-content: space-evenly;
+ padding: 10px 0;
+ --layout-primary: #1b2a47;
+ --layout-background: #f0f2f5;
+ --layout-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
+ --layout-hover: #e3f1f9;
+}
+
+.layout-item {
+ position: relative;
+ width: 18%;
+ height: 50px;
+ cursor: pointer;
+ background: var(--layout-background);
+ border-radius: 8px;
+ box-shadow: var(--layout-shadow);
+
+ transition:
+ transform 0.2s ease,
+ border-color 0.2s ease,
+ box-shadow 0.2s ease;
+
+ &:hover {
+ background-color: var(--layout-hover);
+ transform: scale(1.02);
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--el-color-primary);
+ }
+
+ &-part {
+ position: absolute;
+ background: var(--layout-primary);
+ border-radius: 4px;
+ box-shadow: var(--layout-shadow);
+ transition: all 0.3s ease;
+ }
+
+ &.left {
+ .layout-item-part {
+ &:first-child {
+ width: 30%;
+ height: 100%;
+ border-radius: 4px 0 0 4px;
+ }
+ &:last-child {
+ top: 0;
+ right: 0;
+ width: 70%;
+ height: 30%;
+ background: #fff;
+ border-radius: 0 4px 4px 0;
+ }
+ }
+ }
+
+ &.top {
+ .layout-item-part:first-child {
+ width: 100%;
+ height: 30%;
+ border-radius: 4px 4px 0 0;
+ }
+ }
+
+ &.mix {
+ .layout-item-part {
+ &:first-child {
+ width: 100%;
+ height: 30%;
+ border-radius: 4px 4px 0 0;
+ }
+ &:last-child {
+ bottom: 0;
+ left: 0;
+ width: 30%;
+ height: 70%;
+ border-radius: 0 0 4px 4px;
+ }
+ }
+ }
+}
+
+.is-active {
+ background-color: var(--layout-hover);
+ border: 2px solid var(--el-color-primary);
+ transform: scale(1.05);
+}
diff --git a/src/layouts/components/Settings/components/LayoutSelect.vue b/src/layouts/components/Settings/components/LayoutSelect.vue
deleted file mode 100644
index 488341cc..00000000
--- a/src/layouts/components/Settings/components/LayoutSelect.vue
+++ /dev/null
@@ -1,140 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/layouts/components/Sidebar/components/SidebarMenu.vue b/src/layouts/components/Sidebar/components/SidebarMenu.vue
deleted file mode 100644
index 4c8b36f5..00000000
--- a/src/layouts/components/Sidebar/components/SidebarMenu.vue
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/layouts/components/common/LayoutSidebar.vue b/src/layouts/components/Sidebar/index.vue
similarity index 92%
rename from src/layouts/components/common/LayoutSidebar.vue
rename to src/layouts/components/Sidebar/index.vue
index 6933bd30..a022aeef 100644
--- a/src/layouts/components/common/LayoutSidebar.vue
+++ b/src/layouts/components/Sidebar/index.vue
@@ -8,6 +8,8 @@