审查日期:2026-03-28
项目:DDAC 游戏盾 SDK 管理后台
技术栈:Vue 3.5 + TypeScript 5.9 + Vite 8 + Pinia 3 + Vue Router 5 + Element Plus 2
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 页面
| 层面 | 技术选型 | 版本 |
|---|---|---|
| 框架 | 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 | — |
项目采用经典的中后台 SPA 架构,层次清晰,模块划分合理。核心亮点:
permission.ts 路由守卫 + Pinia Store + Mock API 三方配合,实现了完整的 RBAC 权限控制流程。useDark 实现持久化,过渡动画流畅。TableCard、Pagination、TabFilter 等业务组件设计合理,Props 类型完整,插槽灵活。用户访问 → router.beforeEach (permission.ts)
├─ 无 Token → 白名单放行 or 重定向 /auth
└─ 有 Token
├─ 路由已加载 → 直接放行
└─ 路由未加载
├─ userStore.getUserInfo() → 获取角色
├─ permissionStore.generateRoutes() → 按角色过滤菜单
├─ flattenMenuToRoutes() → 菜单树扁平化为路由
├─ router.addRoute('Root', ...) → 注册动态路由
└─ router.addRoute(notFoundRoute) → 注册 404
| 亮点 | 说明 | 关键文件 |
|---|---|---|
| 动态权限路由 | 后端返回菜单 → 前端扁平化 → 动态注册,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 |
<script setup lang="ts">所有 .vue 文件均使用 <script setup lang="ts">,配合 defineProps<T>()、defineEmits<T>() 实现完整的 TypeScript 类型推导。
// TableCard — 完善的类型定义
interface TypeColumn extends BaseColumn {
type: 'selection' | 'index' | 'expand'
}
interface PropColumn extends BaseColumn {
type?: never
prop?: string
label: string
}
type TableColumn = TypeColumn | PropColumn
所有 Store 使用 Setup Store 模式(函数式),类型推导自然,代码简洁。
.env.development / .env.production)TableCard:列配置化 + 插槽 + 分页 + 列筛选,复用度高Pagination:useVModel 实现优雅的 v-model 双向绑定Breadcrumb:自动从 route.matched + meta.parentTitle 构建层级文件:src/utils/http.ts(184 行全部注释)
整个 HTTP 客户端处于注释状态,所有 API 调用走 Mock。一旦需要对接后端,需要:
建议:尽快启用 HTTP 层,设计 API 抽象层(Repository 模式),让 Store 通过接口调用而非直接依赖 Mock。
现状:
package.json 中无任何测试框架依赖(无 vitest / jest / mocha)src/ 下无任何 .test.ts / .spec.ts 文件风险:权限路由、登录流程、角色过滤等核心逻辑无自动化验证,任何重构都可能引入回归 Bug。
建议:
utils/routeHelper.ts(flattenMenuToRoutes 逻辑复杂)store/modules/permission.ts(角色过滤)store/modules/user.ts(登录/登出流程)mock/index.ts(filterRoutesByRoles)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[]SdkInstance 接口替代 anyformatter 定义更精确的回调签名影响范围:
| 文件 | 实际内容 |
|---|---|
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,暗色模式下可读但亮色模式下可能不可见建议:
Home.vue 或将其纳入路由PlaceholderPage.vue 组件统一占位样式问题实例:
登录页样式与暗色背景强耦合:
// auth/index.vue — 硬编码暗色背景
.auth-box {
background: rgba(6, 5, 25, 0.8); // 仅适配暗色主题
}
登录页在亮色模式下视觉可能异常。
登录/注册表单样式大量重复:
login.vue 和 register.vue 中 :deep(.el-input__wrapper)、.input-prefix、.form-end、.form-links 样式几乎完全相同(约 80 行重复)。
占位页面颜色硬编码:
// dashboard, user, role, article 均如此
h1 {
color: #fff;
} // 硬编码白色,亮色模式下不可见
p {
color: rgba(255, 255, 255, 0.65);
}
建议:
auth-form.scss 共享样式var(--admin-text-primary))文件:store/modules/user.ts, utils/auth.ts
现状:Token 存储在 localStorage,存在 XSS 攻击窃取风险。
建议:
| 文件 | 行数 | 说明 |
|---|---|---|
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 历史保留而非注释保留。
现状:
app.config.errorHandler)catch 仅 console.error + 重置 Token建议:
app.config.errorHandler 捕获未处理异常现状:所有 UI 文案硬编码中文,无 i18n 框架。
影响:如有多语言需求,后续改造成本高。
建议:评估是否需要多语言。如果需要,尽早引入 vue-i18n。
vite.config.ts 硬编码后端地址const baseUrl = 'http://localhost:8080' // 硬编码
建议:移入 .env.development,通过 import.meta.env.VITE_API_TARGET 读取。
register.vue 缺少表单验证对比:login.vue 有完整的 FormRules 验证,但 register.vue 的表单无任何校验规则,el-form 也未绑定 :rules 和 ref。
SDK 管理是当前最完整的业务模块,包含列表页和详情页。
views/sdk/index.vue)优点:
TableCard + TabFilter + Breadcrumb 组件组合问题:
tableData 直接在组件内定义模拟数据,未通过 API 获取router.push({ query: row }) 将整行数据序列化到 URL,可能导致 URL 过长或泄漏敏感数据handleTabChange 和 handleChange 仅打印日志views/sdk/detail.vue)优点:
type TabKey = keyof typeof componentMap问题:
handleTabChange 为空函数 {},无实际逻辑views/sdk/components/)9 个子组件(ForwardRules、ConnectionList、SDKDetail 等)均需进一步检查实现完整度。
| 类别 | 数量 |
|---|---|
页面组件 (views/**) |
~15 |
布局组件 (layout/**) |
5 |
通用组件 (components/**) |
7 |
| Store 模块 | 3 |
| 工具函数 | 4 |
| 类型定义 | 1 |
| Mock 数据 | 1 |
| 测试文件 | 0 |
| 成熟度 | 文件 | 占比 |
|---|---|---|
| 功能完整 | auth, layout, components, permission, router, store | ~60% |
| 骨架搭建 | sdk/index, sdk/detail | ~15% |
| 空壳占位 | dashboard, system/, content/ | ~20% |
| 死代码 | Home.vue, http.ts (注释) | ~5% |
| 优先级 | 任务 | 工作量 |
|---|---|---|
| P0 | 启用 HTTP 层,创建 API 抽象,替换 Mock 调用 | 3-5 天 |
| P0 | 引入 Vitest,为核心工具函数和 Store 编写单测 | 2-3 天 |
| P1 | 清理 any 类型,为 TableCard 引入泛型 |
1 天 |
| P1 | 抽取登录/注册共享样式,修复占位页亮色模式 | 0.5 天 |
| P2 | 清理注释代码、删除 Home.vue | 0.5 天 |
| 任务 | 说明 |
|---|---|
| 完善业务页面 | 将占位页升级为功能页,复用 TableCard 等组件 |
| 全局错误处理 | 添加 errorHandler + ErrorBoundary |
| Token 安全增强 | 客户端过期检查、刷新 Token 机制 |
| API 层完善 | 统一错误码处理、请求取消、防重复提交 |
| 任务 | 说明 |
|---|---|
| 国际化 (i18n) | 如有多语言需求,引入 vue-i18n |
| 微前端拆分 | 如果业务模块持续增长,考虑 qiankun / Module Federation |
| CI/CD 集成 | Lint + Test + Build 自动化流水线 |
| 性能监控 | 接入 Sentry / 自建错误上报 |
DDAC-Front 是一个架构清晰、组件设计合理、工程化基础扎实的 Vue 3 后台项目。核心权限路由系统和主题系统实现质量较高。当前主要处于原型/开发早期阶段,大量业务页面为空壳。
最关键的三个行动项:
any — TypeScript 的价值在于类型安全,any 削弱了这一价值整体评价:框架优秀,业务待填充,基础设施需补强。