# 后台布局与仪表盘
## 1. 修改 MainLayout.vue
### 1.1 文件路径
`resources\js\admin\layouts\MainLayout.vue`
### 1.2 操作说明
该文件在阶段3已创建为占位文件,现在将占位内容替换为完整的后台布局代码。
### 1.3 完整代码
```vue
<template>
<el-container>
<!-- 侧边栏 -->
<el-aside :width="isCollapse ? '64px' : '220px'">
<div>
<span v-if="!isCollapse">好站站</span>
<span v-else>好</span>
</div>
<el-menu
:collapse="isCollapse"
router
:default-active="$route.path"
background-color="#001529"
text-color="#bfbfbf"
active-text-color="#fff"
>
<el-menu-item index="/admin">
<el-icon><Odometer /></el-icon>
<span>仪表盘</span>
</el-menu-item>
<el-menu-item index="/admin/pages">
<el-icon><Document /></el-icon>
<span>页面管理</span>
</el-menu-item>
<el-menu-item index="/admin/site">
<el-icon><Setting /></el-icon>
<span>站点配置</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<!-- 顶部栏 -->
<el-header>
<div>
<el-icon @click="toggleCollapse">
<Fold v-if="!isCollapse" />
<Expand v-else />
</el-icon>
</div>
<div>
<el-dropdown @command="handleCommand">
<span>
{{ authStore.user?.name }}
<el-icon><CaretBottom /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
<!-- 主内容区 -->
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { useAuthStore } from '../stores/auth';
import {
Odometer,
Document,
Setting,
Fold,
Expand,
CaretBottom,
} from '@element-plus/icons-vue';
const router = useRouter();
const authStore = useAuthStore();
const isCollapse = ref(false);
const toggleCollapse = () => {
isCollapse.value = !isCollapse.value;
};
const handleCommand = async (command: string) => {
if (command === 'logout') {
await authStore.logout();
ElMessage.success('已退出登录');
router.push('/admin/login');
}
};
</script>
<style scoped>
.layout-container {
height: 100vh;
}
.aside {
background-color: #001529;
transition: width 0.3s;
}
.logo {
height: 64px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 20px;
font-weight: bold;
background-color: #002140;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
border-bottom: 1px solid #e8e8e8;
padding: 0 20px;
}
.collapse-btn {
font-size: 20px;
cursor: pointer;
}
.user-info {
display: flex;
align-items: center;
gap: 5px;
cursor: pointer;
}
.main {
background-color: #f0f2f5;
padding: 20px;
}
</style>
```
### 1.4 代码说明
| 代码 | 作用 |
|------|------|
| `el-container`、`el-aside`、`el-header`、`el-main` | Element Plus 布局组件,构建经典后台布局 |
| `:collapse="isCollapse"` | 控制侧边栏折叠状态 |
| `router` 属性 | 启用路由模式,点击菜单自动跳转 |
| `:default-active="$route.path"` | 根据当前路由高亮对应菜单 |
| `el-dropdown` | 用户下拉菜单,放置退出登录操作 |
| `authStore.user?.name` | 显示当前登录用户名(可选链防止空值报错) |
| `toggleCollapse` | 切换侧边栏折叠/展开 |
| `handleCommand` | 处理下拉菜单命令,执行退出登录 |
### 1.5 布局结构说明
```
┌─────────────────────────────────────────────────────────┐
│ ┌──────┐ ┌─────────────────────────────────────────┐ │
│ │ 好站 │ │ 折叠按钮 用户名 ▼ │ │
│ │ 站 │ ├─────────────────────────────────────────┤ │
│ ├──────┤ │ │ │
│ │ 仪表 │ │ │ │
│ │ 盘 │ │ 主内容区 │ │
│ ├──────┤ │ (router-view) │ │
│ │ 页面 │ │ │ │
│ │ 管理 │ │ │ │
│ ├──────┤ │ │ │
│ │ 站点 │ │ │ │
│ │ 配置 │ │ │ │
│ └──────┘ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
---
## 2. 修改 Dashboard.vue
### 2.1 文件路径
`resources\js\admin\views\Dashboard.vue`
### 2.2 操作说明
该文件在阶段3已创建为占位文件,现在将占位内容替换为仪表盘代码。
### 2.3 完整代码
```vue
<template>
<div>
<el-row :gutter="20">
<el-col :span="6">
<el-card>
<div>{{ pageCount }}</div>
<div>页面总数</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card>
<div>0</div>
<div>组件总数</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card>
<div>0</div>
<div>今日访问</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card>
<div>v1.0</div>
<div>系统版本</div>
</el-card>
</el-col>
</el-row>
<el-card style="margin-top: 20px">
<h3>欢迎使用好站站</h3>
<p>点击左侧菜单开始建站,或查看使用文档了解更多功能。</p>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
const pageCount = ref(0);
onMounted(async () => {
try {
const response = await axios.get('/api/admin/pages');
pageCount.value = response.data.length || 0;
} catch (error) {
console.error('获取页面统计失败', error);
}
});
</script>
<style scoped>
.stat-card {
text-align: center;
}
.stat-value {
font-size: 32px;
font-weight: bold;
color: #1890ff;
}
.stat-label {
color: #666;
margin-top: 10px;
}
.welcome-card h3 {
margin-bottom: 10px;
}
.welcome-card p {
color: #666;
}
</style>
```
### 2.4 代码说明
| 代码 | 作用 |
|------|------|
| `el-row` + `el-col` | Element Plus 栅格布局,实现响应式列布局 |
| `:gutter="20"` | 列间距 20px |
| `:span="6"` | 每列占 6/24,一行显示 4 列 |
| `el-card` | 卡片容器,展示统计数据和欢迎信息 |
| `pageCount` | 响应式数据,存储页面总数 |
| `onMounted` | 组件挂载后调用 API 获取数据 |
| `stat-value` | 蓝色大字体,突出统计数据 |
---
## 3. 编译验证
### 3.1 执行命令
```bash
npm run build
```
### 3.2 预期结果
编译成功,无报错。
---
## 4. 访问测试
### 4.1 登录后台
浏览器打开:`http://engine-api.test/admin/login`
输入账号密码登录。
### 4.2 验证后台布局
| 验证项 | 预期结果 |
|--------|---------|
| 侧边栏 | 显示「好站站」Logo 和三个菜单 |
| 侧边栏折叠 | 点击折叠按钮,侧边栏收缩 |
| 顶部栏 | 显示当前登录用户名 |
| 退出登录 | 点击退出,跳转到登录页 |
| 仪表盘 | 显示四个统计卡片和欢迎卡片 |
---
## 5. 验证结果
| 验证项 | 预期结果 | 实际结果 |
|--------|---------|---------|
| 编译 | 无报错 | ✅ 通过 |
| 侧边栏显示 | 显示菜单 | ✅ 通过 |
| 侧边栏折叠 | 正常折叠/展开 | ✅ 通过 |
| 顶部栏用户名 | 显示当前用户 | ✅ 通过 |
| 退出登录 | 跳转登录页 | ✅ 通过 |
| 仪表盘统计卡片 | 显示页面总数 | ✅ 通过 |
| 仪表盘欢迎卡片 | 显示欢迎信息 | ✅ 通过 |
---