Browse Source

feat(api): 添加API抽象层及mock实现

新增API抽象层,包含auth、user、routes等模块的mock实现
Store模块改为调用API层而非直接依赖mock
为后续HTTP接口切换提供零改动架构基础
lbq 1 day ago
parent
commit
f5466a2cb0
7 changed files with 523 additions and 5 deletions
  1. 460 0
      CODE_REVIEW.md
  2. 15 0
      src/api/auth.ts
  3. 15 0
      src/api/index.ts
  4. 14 0
      src/api/routes.ts
  5. 14 0
      src/api/user.ts
  6. 2 2
      src/store/modules/permission.ts
  7. 3 3
      src/store/modules/user.ts

+ 460 - 0
CODE_REVIEW.md

@@ -0,0 +1,460 @@
+# DDAC-Front 代码审查报告
+
+> 审查日期:2026-03-28  
+> 项目:DDAC 游戏盾 SDK 管理后台  
+> 技术栈:Vue 3.5 + TypeScript 5.9 + Vite 8 + Pinia 3 + Vue Router 5 + Element Plus 2
+
+---
+
+## 一、项目概览
+
+### 1.1 目录结构
+
+```
+ddac-front/
+├── deploy.sh                  # 部署脚本
+├── Dockerfile                 # 多阶段构建 (node:20 → nginx:alpine)
+├── nginx.conf                 # Nginx 配置 (SPA history fallback + gzip)
+├── index.html                 # HTML 入口
+├── vite.config.ts             # Vite 构建配置
+├── vite/plugins/              # Vite 插件 (auto-import, svg-icon, compression)
+├── eslint.config.js           # ESLint Flat Config
+├── tsconfig.json              # TypeScript 项目引用
+├── .husky/                    # Git hooks (lint-staged)
+├── .env.development           # 开发环境变量
+├── .env.production            # 生产环境变量
+└── src/
+    ├── main.ts                # 应用入口
+    ├── App.vue                # 根组件
+    ├── permission.ts          # 路由守卫 (权限控制核心)
+    ├── router/index.ts        # 静态路由定义
+    ├── store/
+    │   ├── index.ts           # Pinia 实例
+    │   └── modules/
+    │       ├── app.ts         # UI 状态 (sidebar 收起)
+    │       ├── user.ts        # 用户认证 (token/login/logout)
+    │       └── permission.ts  # 权限路由 (动态菜单生成)
+    ├── mock/index.ts          # Mock API (login/userInfo/routes)
+    ├── types/menu.ts          # 类型定义 (MenuItem/RouteMeta/API Response)
+    ├── utils/
+    │   ├── auth.ts            # Token 读写工具
+    │   ├── http.ts            # HTTP 客户端 (已注释,未启用)
+    │   ├── routeHelper.ts     # 菜单树 → 路由转换
+    │   ├── validate.ts        # 校验工具函数
+    │   └── errorCode.ts       # 错误码映射
+    ├── composables/
+    │   └── useTheme.ts        # 暗色模式切换 (基于 VueUse)
+    ├── styles/
+    │   ├── theme.scss         # 全局主题变量 (亮色/暗色)
+    │   └── element.scss       # Element Plus 样式覆盖
+    ├── layout/
+    │   ├── index.vue          # 主布局 (Grid: sidebar + header + main)
+    │   └── components/
+    │       ├── Header.vue     # 顶栏 (折叠/主题/用户下拉)
+    │       ├── AppMain.vue    # 内容区 (router-view + transition)
+    │       └── Sidebar/       # 侧边栏 (Logo + 菜单递归渲染)
+    ├── components/
+    │   ├── Breadcrumb/        # 面包屑 (基于 route.meta)
+    │   ├── Pagination/        # 分页 (v-model 双向绑定)
+    │   ├── TableCard/         # 表格卡片 (列筛选 + 分页 + 插槽)
+    │   ├── TabFilter/         # Tab 筛选器
+    │   ├── ThemeToggle/       # 亮暗切换开关
+    │   ├── StatusText/        # 状态指示器
+    │   └── SvgIcon/           # SVG 图标
+    └── views/
+        ├── auth/              # 登录/注册
+        ├── dashboard/         # 首页
+        ├── sdk/               # SDK 管理 (列表 + 详情 + 8 子模块)
+        ├── system/            # 系统管理 (用户/角色)
+        ├── content/           # 内容管理 (文章)
+        └── error/             # 404 页面
+```
+
+### 1.2 技术栈总览
+
+| 层面      | 技术选型                                   | 版本      |
+| --------- | ------------------------------------------ | --------- |
+| 框架      | Vue 3 (Composition API + `<script setup>`) | 3.5       |
+| 语言      | TypeScript                                 | 5.9       |
+| 构建      | Vite 8 (Rolldown)                          | 8.0       |
+| 路由      | Vue Router                                 | 5.0       |
+| 状态管理  | Pinia (Setup Store)                        | 3.0       |
+| UI 组件库 | Element Plus                               | 2.13      |
+| 图表      | ECharts + vue-echarts                      | 6.0 / 8.0 |
+| HTTP      | Axios (已引入但未启用,当前用 Mock)        | 1.13      |
+| CSS       | SCSS + CSS Variables (主题系统)            | —         |
+| 工具库    | VueUse                                     | 14.2      |
+| 代码规范  | ESLint (Flat Config) + Prettier + Husky    | —         |
+| 部署      | Docker (多阶段) + Nginx                    | —         |
+
+---
+
+## 二、架构评估
+
+### 2.1 整体架构评价:⭐⭐⭐⭐ (4/5)
+
+项目采用经典的中后台 SPA 架构,层次清晰,模块划分合理。核心亮点:
+
+- **权限路由系统设计优秀**:静态路由 + 动态注入的模式,通过 `permission.ts` 路由守卫 + Pinia Store + Mock API 三方配合,实现了完整的 RBAC 权限控制流程。
+- **主题系统完善**:基于 CSS Variables 的亮暗双主题,配合 VueUse 的 `useDark` 实现持久化,过渡动画流畅。
+- **组件封装到位**:`TableCard`、`Pagination`、`TabFilter` 等业务组件设计合理,Props 类型完整,插槽灵活。
+
+### 2.2 数据流
+
+```
+用户访问 → router.beforeEach (permission.ts)
+  ├─ 无 Token → 白名单放行 or 重定向 /auth
+  └─ 有 Token
+       ├─ 路由已加载 → 直接放行
+       └─ 路由未加载
+            ├─ userStore.getUserInfo() → 获取角色
+            ├─ permissionStore.generateRoutes() → 按角色过滤菜单
+            ├─ flattenMenuToRoutes() → 菜单树扁平化为路由
+            ├─ router.addRoute('Root', ...) → 注册动态路由
+            └─ router.addRoute(notFoundRoute) → 注册 404
+```
+
+### 2.3 架构亮点
+
+| 亮点         | 说明                                                     | 关键文件                          |
+| ------------ | -------------------------------------------------------- | --------------------------------- |
+| 动态权限路由 | 后端返回菜单 → 前端扁平化 → 动态注册,404 后置避免误匹配 | `permission.ts`, `routeHelper.ts` |
+| 组件懒加载   | `import.meta.glob` + `loadComponent` 按路径动态加载视图  | `routeHelper.ts:6-26`             |
+| 角色过滤     | Mock 层模拟后端角色过滤逻辑,前端可无缝切换真实接口      | `mock/index.ts:75-88`             |
+| Grid 布局    | Layout 使用 CSS Grid 实现侧边栏自适应收起                | `layout/index.vue`                |
+| 列筛选器     | TableCard 内置列显隐控制,全选/反选/重置                 | `TableCard/index.vue`             |
+
+---
+
+## 三、代码质量分析
+
+### 3.1 优点
+
+#### ✅ 统一使用 Composition API + `<script setup lang="ts">`
+
+所有 `.vue` 文件均使用 `<script setup lang="ts">`,配合 `defineProps<T>()`、`defineEmits<T>()` 实现完整的 TypeScript 类型推导。
+
+```typescript
+// TableCard — 完善的类型定义
+interface TypeColumn extends BaseColumn {
+  type: 'selection' | 'index' | 'expand'
+}
+interface PropColumn extends BaseColumn {
+  type?: never
+  prop?: string
+  label: string
+}
+type TableColumn = TypeColumn | PropColumn
+```
+
+#### ✅ Pinia Setup Store 风格统一
+
+所有 Store 使用 Setup Store 模式(函数式),类型推导自然,代码简洁。
+
+#### ✅ 工程化配置完善
+
+- ESLint Flat Config + Prettier + Husky + lint-staged 形成完整的代码规范链
+- 环境变量分离 (`.env.development` / `.env.production`)
+- Docker 多阶段构建优化镜像大小
+
+#### ✅ 组件设计良好
+
+- `TableCard`:列配置化 + 插槽 + 分页 + 列筛选,复用度高
+- `Pagination`:`useVModel` 实现优雅的 v-model 双向绑定
+- `Breadcrumb`:自动从 `route.matched` + `meta.parentTitle` 构建层级
+
+### 3.2 问题与风险
+
+#### 🔴 P0 — HTTP 层完全注释,无真实 API 对接能力
+
+**文件**:`src/utils/http.ts`(184 行全部注释)
+
+整个 HTTP 客户端处于注释状态,所有 API 调用走 Mock。一旦需要对接后端,需要:
+
+1. 重写 HTTP 客户端
+2. 替换所有 Store 中的 Mock 调用
+3. 处理错误码、Token 刷新、重复提交等逻辑
+
+**建议**:尽快启用 HTTP 层,设计 API 抽象层(Repository 模式),让 Store 通过接口调用而非直接依赖 Mock。
+
+---
+
+#### 🔴 P0 — 无测试覆盖
+
+**现状**:
+
+- `package.json` 中无任何测试框架依赖(无 vitest / jest / mocha)
+- `src/` 下无任何 `.test.ts` / `.spec.ts` 文件
+
+**风险**:权限路由、登录流程、角色过滤等核心逻辑无自动化验证,任何重构都可能引入回归 Bug。
+
+**建议**:
+
+1. 引入 Vitest(与 Vite 生态天然集成)
+2. 优先为以下模块编写单测:
+   - `utils/routeHelper.ts`(`flattenMenuToRoutes` 逻辑复杂)
+   - `store/modules/permission.ts`(角色过滤)
+   - `store/modules/user.ts`(登录/登出流程)
+   - `mock/index.ts`(`filterRoutesByRoles`)
+
+---
+
+#### 🟡 P1 — `any` 类型使用过多
+
+**位置统计**:
+
+| 文件                     | 位置                                                              | 说明                  |
+| ------------------------ | ----------------------------------------------------------------- | --------------------- |
+| `sdk/index.vue:57`       | `ref<any[]>([])`                                                  | selectedRows          |
+| `sdk/index.vue:117`      | `(type: string, row: any)`                                        | btnClickHandler 参数  |
+| `sdk/index.vue:137`      | `(selection: any[])`                                              | handleSelectionChange |
+| `TableCard/index.vue:11` | `formatter?: (row: any, column: any, cellValue: any, ...) => any` | 格式化函数            |
+| `TableCard/index.vue:32` | `data: any[]`                                                     | 表格数据              |
+| `validate.ts:32`         | `path: string \| Record<string, any>`                             | isExternal 参数       |
+
+**建议**:
+
+- `TableCard` 引入泛型:`TableCardProps<T>` + `data: T[]`
+- SDK 页面定义 `SdkInstance` 接口替代 `any`
+- 为 `formatter` 定义更精确的回调签名
+
+---
+
+#### 🟡 P1 — 大量页面为空壳占位符
+
+**影响范围**:
+
+| 文件                              | 实际内容               |
+| --------------------------------- | ---------------------- |
+| `views/dashboard/index.vue`       | 仅标题 + 段落          |
+| `views/system/user/index.vue`     | 仅标题 + "开发中..."   |
+| `views/system/role/index.vue`     | 仅标题 + "开发中..."   |
+| `views/content/article/index.vue` | 仅标题 + "开发中..."   |
+| `views/Home.vue`                  | 未被路由引用的孤立文件 |
+
+**问题**:
+
+- `Home.vue` 未被任何路由使用,属于死代码
+- 多个占位页面样式硬编码 `color: #fff`,暗色模式下可读但亮色模式下可能不可见
+- 重复的占位页面结构(h1 + p)无抽象
+
+**建议**:
+
+1. 删除 `Home.vue` 或将其纳入路由
+2. 创建 `PlaceholderPage.vue` 组件统一占位样式
+3. 确保占位内容在亮/暗模式下均可见
+
+---
+
+#### 🟡 P1 — 样式硬编码与重复
+
+**问题实例**:
+
+1. **登录页样式与暗色背景强耦合**:
+
+   ```scss
+   // auth/index.vue — 硬编码暗色背景
+   .auth-box {
+     background: rgba(6, 5, 25, 0.8); // 仅适配暗色主题
+   }
+   ```
+
+   登录页在亮色模式下视觉可能异常。
+
+2. **登录/注册表单样式大量重复**:
+   `login.vue` 和 `register.vue` 中 `:deep(.el-input__wrapper)`、`.input-prefix`、`.form-end`、`.form-links` 样式几乎完全相同(约 80 行重复)。
+
+3. **占位页面颜色硬编码**:
+   ```scss
+   // dashboard, user, role, article 均如此
+   h1 {
+     color: #fff;
+   } // 硬编码白色,亮色模式下不可见
+   p {
+     color: rgba(255, 255, 255, 0.65);
+   }
+   ```
+
+**建议**:
+
+1. 抽取 `auth-form.scss` 共享样式
+2. 占位页面使用 CSS 变量(`var(--admin-text-primary)`)
+3. 登录页适配双主题或固定为暗色并加注释说明
+
+---
+
+#### 🟡 P1 — Token 安全性
+
+**文件**:`store/modules/user.ts`, `utils/auth.ts`
+
+**现状**:Token 存储在 `localStorage`,存在 XSS 攻击窃取风险。
+
+**建议**:
+
+- 短期:确保所有输入经过消毒,减少 XSS 攻击面
+- 长期:考虑 HttpOnly Cookie + CSRF Token 方案
+- 添加 Token 过期检查(当前无客户端过期逻辑,仅依赖后端 401)
+
+---
+
+#### 🟢 P2 — 遗留的注释代码
+
+| 文件                                    | 行数                             | 说明                                       |
+| --------------------------------------- | -------------------------------- | ------------------------------------------ |
+| `utils/http.ts`                         | 184 行(全部注释)               | HTTP 客户端脚手架                          |
+| `layout/components/Header.vue:52-56`    | `.title` 样式未使用              | 无对应 DOM                                 |
+| `components/Breadcrumb/index.vue:80-89` | `.back-btn` 样式存在但按钮被注释 | `<!-- <el-button v-if="canGoBack" ... -->` |
+| `styles/element.scss:7,13,31-35`        | hover/active 样式被注释          | 按钮交互效果                               |
+
+**建议**:清理无用注释代码,通过 Git 历史保留而非注释保留。
+
+---
+
+#### 🟢 P2 — 缺少错误边界和全局错误处理
+
+**现状**:
+
+- 无 Vue 全局错误处理器(`app.config.errorHandler`)
+- 无全局加载状态管理
+- 路由守卫中 `catch` 仅 `console.error` + 重置 Token
+
+**建议**:
+
+1. 添加 `app.config.errorHandler` 捕获未处理异常
+2. 在 AppMain 中添加 Suspense + ErrorBoundary
+3. 路由守卫错误时给用户可见提示(当前仅控制台输出)
+
+---
+
+#### 🟢 P2 — 缺少国际化 (i18n)
+
+**现状**:所有 UI 文案硬编码中文,无 i18n 框架。
+
+**影响**:如有多语言需求,后续改造成本高。
+
+**建议**:评估是否需要多语言。如果需要,尽早引入 `vue-i18n`。
+
+---
+
+#### 🟢 P2 — `vite.config.ts` 硬编码后端地址
+
+```typescript
+const baseUrl = 'http://localhost:8080' // 硬编码
+```
+
+**建议**:移入 `.env.development`,通过 `import.meta.env.VITE_API_TARGET` 读取。
+
+---
+
+#### 🟢 P2 — `register.vue` 缺少表单验证
+
+**对比**:`login.vue` 有完整的 `FormRules` 验证,但 `register.vue` 的表单无任何校验规则,`el-form` 也未绑定 `:rules` 和 `ref`。
+
+---
+
+## 四、SDK 模块深度分析
+
+SDK 管理是当前最完整的业务模块,包含列表页和详情页。
+
+### 4.1 SDK 列表页 (`views/sdk/index.vue`)
+
+**优点**:
+
+- 完整使用了 `TableCard` + `TabFilter` + `Breadcrumb` 组件组合
+- 列配置化,操作列使用插槽自定义渲染
+- 支持多选、搜索、分页
+
+**问题**:
+
+- **数据硬编码**:`tableData` 直接在组件内定义模拟数据,未通过 API 获取
+- **操作按钮未实现**:升级、编辑、续费、删除按钮仅有 UI,无事件处理
+- **query 参数透传**:`router.push({ query: row })` 将整行数据序列化到 URL,可能导致 URL 过长或泄漏敏感数据
+- **console.log 残留**:`handleTabChange` 和 `handleChange` 仅打印日志
+
+### 4.2 SDK 详情页 (`views/sdk/detail.vue`)
+
+**优点**:
+
+- 动态组件映射(8 个 Tab 子模块),结构清晰
+- 泛型约束 Tab 类型:`type TabKey = keyof typeof componentMap`
+
+**问题**:
+
+- `handleTabChange` 为空函数 `{}`,无实际逻辑
+- 详情页未接收列表页传递的实例 ID,无法加载对应数据
+
+### 4.3 SDK 子模块 (`views/sdk/components/`)
+
+9 个子组件(ForwardRules、ConnectionList、SDKDetail 等)均需进一步检查实现完整度。
+
+---
+
+## 五、代码统计
+
+### 5.1 文件数量
+
+| 类别                       | 数量  |
+| -------------------------- | ----- |
+| 页面组件 (`views/**`)      | ~15   |
+| 布局组件 (`layout/**`)     | 5     |
+| 通用组件 (`components/**`) | 7     |
+| Store 模块                 | 3     |
+| 工具函数                   | 4     |
+| 类型定义                   | 1     |
+| Mock 数据                  | 1     |
+| 测试文件                   | **0** |
+
+### 5.2 代码成熟度分布
+
+| 成熟度   | 文件                                                | 占比 |
+| -------- | --------------------------------------------------- | ---- |
+| 功能完整 | auth, layout, components, permission, router, store | ~60% |
+| 骨架搭建 | sdk/index, sdk/detail                               | ~15% |
+| 空壳占位 | dashboard, system/_, content/_                      | ~20% |
+| 死代码   | Home.vue, http.ts (注释)                            | ~5%  |
+
+---
+
+## 六、优先改进建议
+
+### 6.1 短期(1-2 周)
+
+| 优先级 | 任务                                         | 工作量 |
+| ------ | -------------------------------------------- | ------ |
+| P0     | 启用 HTTP 层,创建 API 抽象,替换 Mock 调用  | 3-5 天 |
+| P0     | 引入 Vitest,为核心工具函数和 Store 编写单测 | 2-3 天 |
+| P1     | 清理 `any` 类型,为 TableCard 引入泛型       | 1 天   |
+| P1     | 抽取登录/注册共享样式,修复占位页亮色模式    | 0.5 天 |
+| P2     | 清理注释代码、删除 Home.vue                  | 0.5 天 |
+
+### 6.2 中期(1-2 个月)
+
+| 任务           | 说明                                        |
+| -------------- | ------------------------------------------- |
+| 完善业务页面   | 将占位页升级为功能页,复用 TableCard 等组件 |
+| 全局错误处理   | 添加 `errorHandler` + ErrorBoundary         |
+| Token 安全增强 | 客户端过期检查、刷新 Token 机制             |
+| API 层完善     | 统一错误码处理、请求取消、防重复提交        |
+
+### 6.3 长期
+
+| 任务          | 说明                                                   |
+| ------------- | ------------------------------------------------------ |
+| 国际化 (i18n) | 如有多语言需求,引入 vue-i18n                          |
+| 微前端拆分    | 如果业务模块持续增长,考虑 qiankun / Module Federation |
+| CI/CD 集成    | Lint + Test + Build 自动化流水线                       |
+| 性能监控      | 接入 Sentry / 自建错误上报                             |
+
+---
+
+## 七、总结
+
+DDAC-Front 是一个**架构清晰、组件设计合理、工程化基础扎实**的 Vue 3 后台项目。核心权限路由系统和主题系统实现质量较高。当前主要处于**原型/开发早期阶段**,大量业务页面为空壳。
+
+**最关键的三个行动项**:
+
+1. **启用 HTTP 层** — 这是连接后端的前提,越早做越好
+2. **添加测试** — 权限路由逻辑复杂度高,无测试保障风险大
+3. **消灭 `any`** — TypeScript 的价值在于类型安全,`any` 削弱了这一价值
+
+整体评价:**框架优秀,业务待填充,基础设施需补强**。

+ 15 - 0
src/api/auth.ts

@@ -0,0 +1,15 @@
+import type { LoginResponse } from '@/types/menu'
+import { mockLogin } from '@/mock'
+
+/**
+ * 用户登录
+ * @param username 用户名
+ * @param password 密码
+ * @returns LoginResponse 包含 token
+ *
+ * TODO: 后端就绪后替换为
+ * return http.post('/auth/login', { username, password })
+ */
+export function login(username: string, password: string): Promise<LoginResponse> {
+  return mockLogin(username, password)
+}

+ 15 - 0
src/api/index.ts

@@ -0,0 +1,15 @@
+/**
+ * API 抽象层
+ *
+ * 设计原则:
+ * - Store 只调用 api/ 层的函数,不直接依赖 mock 或 http
+ * - 所有函数返回类型明确,与 types/menu.ts 中的 Response 类型对齐
+ * - 后端就绪后,只需修改本目录下的实现(mock → http),Store 零改动
+ *
+ * 当前状态:所有接口走 mock(src/mock)
+ * 切换时机:后端接口就绪后,逐个函数替换为真实 HTTP 调用
+ */
+
+export { login } from './auth'
+export { getUserInfo } from './user'
+export { getRoutes } from './routes'

+ 14 - 0
src/api/routes.ts

@@ -0,0 +1,14 @@
+import type { RoutesResponse } from '@/types/menu'
+import { mockGetRoutes } from '@/mock'
+
+/**
+ * 获取当前用户的权限路由
+ * @param token 用户 token
+ * @returns RoutesResponse 包含菜单树
+ *
+ * TODO: 后端就绪后替换为
+ * return http.get('/routes')
+ */
+export function getRoutes(token: string): Promise<RoutesResponse> {
+  return mockGetRoutes(token)
+}

+ 14 - 0
src/api/user.ts

@@ -0,0 +1,14 @@
+import type { UserInfoResponse } from '@/types/menu'
+import { mockGetUserInfo } from '@/mock'
+
+/**
+ * 获取当前用户信息(角色、昵称、头像)
+ * @param token 用户 token
+ * @returns UserInfoResponse
+ *
+ * TODO: 后端就绪后替换为
+ * return http.get('/user/info')
+ */
+export function getUserInfo(token: string): Promise<UserInfoResponse> {
+  return mockGetUserInfo(token)
+}

+ 2 - 2
src/store/modules/permission.ts

@@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
 import { ref } from 'vue'
 import type { RouteRecordRaw } from 'vue-router'
 import type { MenuItem } from '@/types/menu'
-import { mockGetRoutes } from '@/mock'
+import { getRoutes as apiGetRoutes } from '@/api'
 import { flattenMenuToRoutes } from '@/utils/routeHelper'
 
 export const usePermissionStore = defineStore('permission', () => {
@@ -19,7 +19,7 @@ export const usePermissionStore = defineStore('permission', () => {
    * 3. 返回扁平化的路由配置(由路由守卫负责注册到 router)
    */
   async function generateRoutes(token: string): Promise<RouteRecordRaw[]> {
-    const res = await mockGetRoutes(token)
+    const res = await apiGetRoutes(token)
     const rawMenuData: MenuItem[] = res.data
 
     // 保留嵌套结构给 Sidebar 使用

+ 3 - 3
src/store/modules/user.ts

@@ -1,6 +1,6 @@
 import { defineStore } from 'pinia'
 import { ref, computed } from 'vue'
-import { mockLogin, mockGetUserInfo } from '@/mock'
+import { login as apiLogin, getUserInfo as apiGetUserInfo } from '@/api'
 
 const TOKEN_KEY = import.meta.env.VITE_APP_TOKEN_KEY
 
@@ -14,14 +14,14 @@ export const useUserStore = defineStore('user', () => {
 
   /** 登录:获取并存储 Token */
   async function login(username: string, password: string) {
-    const res = await mockLogin(username, password)
+    const res = await apiLogin(username, password)
     token.value = res.data.token
     localStorage.setItem(TOKEN_KEY, res.data.token)
   }
 
   /** 获取用户信息(在路由守卫中调用) */
   async function getUserInfo() {
-    const res = await mockGetUserInfo(token.value)
+    const res = await apiGetUserInfo(token.value)
     name.value = res.data.name
     roles.value = res.data.roles
     avatar.value = res.data.avatar