# Vue 3 前端项目分析报告 > 项目路径:`frontend/` > 分析日期:2026-03-28 > 项目类型:多租户竞赛/活动管理系统前端 --- ## 一、技术栈概览 | 组件 | 技术选型 | 版本 | |------|----------|------| | **框架** | Vue 3 | 3.4.21 | | **构建工具** | Vite | 5.1.6 | | **语言** | TypeScript | 5.4.3 | | **状态管理** | Pinia | 2.1.7 | | **路由** | Vue Router | 4.3.0 | | **UI 组件库** | Ant Design Vue | 4.1.1 | | **图标** | @ant-design/icons-vue | 7.0.1 | | **HTTP 客户端** | Axios | 1.6.7 | | **表单验证** | Vee Validate + Zod | 4.12.4 / 3.22.4 | | **富文本编辑器** | WangEditor | 5.1.12 | | **3D 渲染** | Three.js | 0.182.0 | | **样式** | Tailwind CSS + SCSS | 3.4.1 | | **日期处理** | Day.js | 1.11.10 | ### 完整依赖列表 ```json { "dependencies": { "@ant-design/icons-vue": "^7.0.1", "@vee-validate/zod": "^4.12.4", "@wangeditor/editor": "^5.1.23", "@wangeditor-editor-for-vue": "^5.1.12", "ant-design-vue": "^4.1.1", "axios": "^1.6.7", "dayjs": "^1.11.10", "pinia": "^2.1.7", "three": "^0.182.0", "vee-validate": "^4.12.4", "vue": "^3.4.21", "vue-router": "^4.3.0", "zod": "^3.22.4" }, "devDependencies": { "@vitejs/plugin-vue": "^5.0.4", "autoprefixer": "^10.4.18", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.22.0", "postcss": "^8.4.35", "sass": "^1.71.1", "tailwindcss": "^3.4.1", "typescript": "^5.4.3", "vite": "^5.1.6", "vue-tsc": "^3.2.2" } } ``` --- ## 二、项目架构 ### 目录结构 ``` frontend/ ├── src/ │ ├── api/ # API 接口层 │ │ ├── ai-3d.ts # AI 3D 任务接口 │ │ ├── auth.ts # 认证接口 │ │ ├── classes.ts # 班级管理接口 │ │ ├── config.ts # 系统配置接口 │ │ ├── contests.ts # 竞赛管理接口(核心) │ │ ├── departments.ts # 部门管理接口 │ │ ├── dict.ts # 数据字典接口 │ │ ├── grades.ts # 年级管理接口 │ │ ├── homework.ts # 作业管理接口 │ │ ├── judges-management.ts # 评委管理接口 │ │ ├── logs.ts # 日志管理接口 │ │ ├── menus.ts # 菜单管理接口 │ │ ├── permissions.ts # 权限管理接口 │ │ ├── preset-comments.ts # 预设评语接口 │ │ ├── public.ts # 公共接口 │ │ ├── roles.ts # 角色管理接口 │ │ ├── schools.ts # 学校管理接口 │ │ ├── students.ts # 学生管理接口 │ │ ├── teachers.ts # 教师管理接口 │ │ ├── tenants.ts # 租户管理接口 │ │ ├── upload.ts # 文件上传接口 │ │ └── users.ts # 用户管理接口 │ │ │ ├── components/ # 公共组件 │ │ ├── ModelViewer.vue # 3D 模型预览组件 │ │ └── RichTextEditor.vue # 富文本编辑器组件 │ │ │ ├── composables/ # 组合式函数 │ │ ├── useListRequest.ts # 列表请求 Hook │ │ └── useSimpleListRequest.ts # 简单列表请求 Hook │ │ │ ├── directives/ # 自定义指令 │ │ └── permission.ts # 权限指令 │ │ │ ├── layouts/ # 布局组件 │ │ ├── BasicLayout.vue # 管理端基础布局 │ │ ├── EmptyLayout.vue # 空白布局 │ │ └── PublicLayout.vue # 公众端布局 │ │ │ ├── router/ # 路由配置 │ │ └── index.ts # 路由主文件(含动态路由) │ │ │ ├── stores/ # Pinia 状态管理 │ │ └── auth.ts # 认证状态 │ │ │ ├── types/ # TypeScript 类型定义 │ │ ├── api.ts # API 通用类型 │ │ ├── auth.ts # 认证相关类型 │ │ └── router.ts # 路由扩展类型 │ │ │ ├── utils/ # 工具函数 │ │ ├── auth.ts # 认证工具 │ │ ├── avatar.ts # 头像工具 │ │ ├── menu.ts # 菜单工具 │ │ └── request.ts # Axios 封装 │ │ │ └── views/ # 页面组件 │ ├── activities/ # 活动评审页面 │ ├── auth/ # 认证页面 │ ├── content/ # 内容管理页面 │ ├── contests/ # 竞赛管理页面(核心) │ ├── error/ # 错误页面 │ ├── homework/ # 作业管理页面 │ ├── model/ # 3D 模型页面 │ ├── public/ # 公众端页面 │ ├── school/ # 学校管理页面 │ ├── system/ # 系统管理页面 │ └── workbench/ # 工作台页面 │ ├── scripts/ # 构建脚本 └── package.json ``` --- ## 三、核心功能模块详解 ### 1. 认证授权模块 (`auth/`) **文件结构:** ``` src/stores/auth.ts # Pinia Store src/api/auth.ts # API 接口 src/views/auth/Login.vue # 登录页面 src/utils/auth.ts # 认证工具 ``` **核心功能:** - JWT Token 认证 - 用户信息获取 - 动态菜单加载 - 权限/角色判断 - 租户编码管理 **核心代码示例:** ```typescript // src/stores/auth.ts export const useAuthStore = defineStore("auth", () => { const user = ref(null) const token = ref(getToken() || "") const menus = ref([]) const isAuthenticated = computed(() => !!token.value) // 检查是否为超级管理员 const isSuperAdmin = (): boolean => { return user.value?.roles?.includes('super_admin') ?? false } // 检查是否有指定权限(超管自动拥有所有权限) const hasPermission = (permission: string): boolean => { if (isSuperAdmin()) return true return user.value?.permissions?.includes(permission) ?? false } const login = async (form: LoginForm) => { const response = await authApi.login(form) token.value = response.token user.value = response.user await fetchUserMenus() // 获取用户菜单 return response } // ... }) ``` --- ### 2. 路由系统 **核心特性:** - 基于动态菜单的路由加载 - 租户编码路径前缀(`/:tenantCode/`) - 权限守卫 - 公众端与管理端分离 **路由结构:** ```typescript // 基础路由 const baseRoutes = [ // 管理端登录 { path: "/:tenantCode/login", component: Login }, // 公众端路由(/p 前缀) { path: "/p", children: [ { path: "gallery", name: "PublicGallery" }, // 作品广场 { path: "activities", name: "PublicActivities" }, // 活动大厅 { path: "mine", name: "PublicMine" }, // 个人中心 { path: "create", name: "PublicCreate" }, // 绘本创作 ] }, // 管理端路由(动态加载) { path: "/:tenantCode", name: "Main", component: BasicLayout, children: [ // 动态路由将通过菜单 API 添加 ] } ] ``` **路由守卫逻辑:** ```typescript router.beforeEach(async (to, _from, next) => { // 公众端路由直接放行 if (to.path.startsWith("/p/")) { next() return } const authStore = useAuthStore() // 未登录跳转登录页 if (!authStore.token && to.meta.requiresAuth !== false) { next({ name: "Login", query: { redirect: to.fullPath } }) return } // 已登录自动获取用户信息和菜单 if (authStore.token && !authStore.user) { await authStore.fetchUserInfo() await addDynamicRoutes() // 添加动态路由 } // 权限检查 const requiredPermissions = to.meta.permissions if (requiredPermissions && !authStore.hasAnyPermission(requiredPermissions)) { next({ name: "Forbidden" }) return } next() }) ``` --- ### 3. 竞赛管理模块 (`contests/`) ⭐核心业务 **页面结构:** ``` contests/ ├── Index.vue # 活动列表页 ├── Create.vue # 创建/编辑活动 ├── Detail.vue # 活动详情页 ├── SuperDetail.vue # 超管活动详情页 ├── RegisterIndividual.vue # 个人报名页 ├── RegisterTeam.vue # 团队报名页 │ ├── components/ │ ├── AddJudgeDrawer.vue # 添加评委抽屉 │ ├── AddParticipantDrawer.vue # 添加参与者抽屉 │ ├── AddTeacherDrawer.vue # 添加指导老师抽屉 │ ├── SubmitWorkDrawer.vue # 提交作品抽屉 │ ├── ViewWorkDrawer.vue # 查看作品抽屉 │ └── WorkDetailModal.vue # 作品详情弹窗 │ ├── judges/ │ └── Index.vue # 评委管理 │ ├── notices/ │ └── Index.vue # 公告管理 │ ├── registrations/ │ ├── Index.vue # 报名管理列表 │ └── Records.vue # 报名记录 │ ├── reviews/ │ ├── Index.vue # 评审管理 │ ├── Progress.vue # 评审进度 │ ├── ProgressDetail.vue # 评审进度详情 │ └── Tasks.vue # 评审任务 │ ├── results/ │ ├── Index.vue # 成果管理列表 │ └── Detail.vue # 成果发布详情 │ ├── works/ │ ├── Index.vue # 作品管理列表 │ └── WorksDetail.vue # 参赛作品详情 │ └── Guidance.vue # 我的指导(教师视角) ``` #### 3.1 活动列表页 (`Index.vue`) **功能:** - 活动列表展示(分页) - 活动阶段筛选(未发布/报名中/提交中/评审中/已完结) - 活动统计卡片 - 创建活动入口 - 活动状态管理(发布/完结/重新开启) #### 3.2 创建活动页 (`Create.vue`) **表单配置:** ```typescript interface CreateContestForm { contestName: string; // 活动名称 contestType: "individual" | "team"; // 活动类型 startTime: string; // 活动开始时间 endTime: string; // 活动结束时间 // 报名配置 registerStartTime: string; // 报名开始时间 registerEndTime: string; // 报名结束时间 requireAudit: boolean; // 是否需要审核 teamMinMembers?: number; // 团队最少人数 teamMaxMembers?: number; // 团队最多人数 // 作品配置 submitStartTime: string; // 作品提交开始时间 submitEndTime: string; // 作品提交结束时间 submitRule: "once" | "resubmit"; // 提交规则 workType: "image" | "video" | "document" | "code" | "other"; // 评审配置 reviewStartTime: string; // 评审开始时间 reviewEndTime: string; // 评审结束时间 reviewRuleId?: number; // 评审规则 ID // 成果配置 resultPublishTime?: string; // 结果发布时间 } ``` #### 3.3 报名管理模块 **功能:** - 报名列表(支持按状态筛选) - 报名审核(通过/拒绝) - 报名统计(待审核/已通过/已拒绝) - 添加指导老师 - 报名记录查看 #### 3.4 评审管理模块 **功能:** - 评委分配(手动/批量/自动) - 评审进度监控 - 作品评分界面 - 评审统计(评委进度/作品状态) **评审进度数据结构:** ```typescript interface ReviewProgress { contest: { /* 活动信息 */ }; summary: { totalWorks: number; // 总作品数 assignedWorksCount: number; // 已分配作品数 scoredWorksCount: number; // 已评分作品数 totalJudges: number; // 评委总数 }; progress: { assignmentProgress: number; // 分配进度百分比 scoringProgress: number; // 评分进度百分比 overallProgress: number; // 整体进度百分比 }; judgeProgress: JudgeProgressItem[]; // 评委进度列表 unassignedWorks: UnassignedWork[]; // 未分配作品列表 } ``` #### 3.5 成果管理模块 **功能:** - 计算最终得分(支持多种计算规则) - 自动排名 - 设置奖项(单个/批量/自动) - 成果发布/撤回 **API 示例:** ```typescript // 自动设置奖项 resultsApi.autoSetAwards(contestId, { first: 3, // 一等奖 3 名 second: 6, // 二等奖 6 名 third: 10, // 三等奖 10 名 excellent: 20 // 优秀奖 20 名 }) // 批量设置奖项 resultsApi.batchSetAwards(contestId, { awards: [ { workId: 1, awardLevel: 'first' }, { workId: 2, awardLevel: 'second' }, // ... ] }) ``` --- ### 4. 用户管理模块 (`system/users/`) **页面:** `src/views/system/users/Index.vue` **功能:** - 用户列表(分页 + 搜索) - 用户类型筛选(平台/机构/评委/公共) - 用户统计卡片 - 创建/编辑用户 - 用户状态切换(启用/禁用) - 角色分配 **查询参数:** ```typescript interface UserQueryParams { page?: number; pageSize?: number; keyword?: string; // 关键字搜索 userType?: "platform" | "org" | "judge" | "public"; filterTenantId?: number; // 按租户筛选 userSource?: "admin_created" | "self_registered"; status?: "enabled" | "disabled"; } ``` **用户统计接口:** ```typescript interface UserStats { total: number; // 总用户数 platform: number; // 平台用户 org: number; // 机构用户 judge: number; // 评委用户 public: number; // 公共用户 } ``` --- ### 5. AI 3D 创作模块 (`workbench/ai-3d/`) ⭐特色功能 **文件结构:** ``` workbench/ai-3d/ ├── Index.vue # 3D 建模实验室首页 ├── Generate.vue # 模型生成页面 └── History.vue # 创作历史 ``` **功能:** - AI 文生 3D 模型(腾讯混元 API) - 生成类型选择(Normal/LowPoly/Geometry/Sketch) - 任务状态轮询 - 多结果展示(4 个不同角度) - 模型下载 - 创作历史记录 **任务状态:** ```typescript type AI3DTaskStatus = "pending" | "processing" | "completed" | "failed" | "timeout"; interface AI3DTask { id: number; inputType: "text" | "image"; inputContent: string; status: AI3DTaskStatus; resultUrls?: string[]; // 多结果 URL previewUrls?: string[]; // 预览图 URL queuePosition?: number; // 队列位置 createTime: string; completeTime?: string; } ``` **生成参数:** ```typescript interface CreateAI3DTaskParams { inputType: "text" | "image"; inputContent: string; generateType?: "Normal" | "LowPoly" | "Geometry" | "Sketch"; faceCount?: number; // 模型面数 (10000-1500000) } ``` --- ### 6. 学校管理模块 (`school/`) **子模块:** ``` school/ ├── schools/ # 学校信息 ├── grades/ # 年级管理 ├── classes/ # 班级管理 ├── teachers/ # 教师管理 └── students/ # 学生管理 ``` **功能:** - 学校信息 CRUD - 年级管理(支持排序) - 班级管理(关联年级) - 教师列表(支持搜索) - 学生列表(支持按班级筛选) --- ### 7. 系统管理模块 (`system/`) **子模块:** | 页面 | 功能 | |------|------| | `users/` | 用户管理 | | `roles/` | 角色管理 | | `permissions/` | 权限管理 | | `menus/` | 菜单管理 | | `tenants/` | 租户管理 | | `dict/` | 数据字典 | | `config/` | 系统配置 | | `logs/` | 系统日志 | --- ### 8. 公众端模块 (`public/`) **页面结构:** ``` public/ ├── Login.vue # 公众端登录 ├── Gallery.vue # 作品广场 ├── Activities.vue # 活动大厅 ├── ActivityDetail.vue # 活动详情 │ ├── mine/ │ ├── Index.vue # 个人中心 │ ├── Registrations.vue # 我的报名 │ ├── Works.vue # 我的作品 │ └── Children.vue # 子女账号 │ ├── create/ │ ├── Index.vue # 绘本创作首页 │ └── Generating.vue # 生成中页面 │ ├── works/ │ ├── Index.vue # 我的作品库 │ ├── Detail.vue # 作品详情 │ └── Publish.vue # 发布作品 │ └── components/ └── WorkSelector.vue # 作品选择器 ``` **核心功能:** - 公众端独立登录 - 作品广场展示 - 活动大厅浏览 - 个人中心(报名/作品/子女管理) - AI 绘本创作 --- ### 9. 作业管理模块 (`homework/`) **页面:** - `Index.vue` - 作业列表 - `ReviewRules.vue` - 评审规则 - `Submissions.vue` - 提交记录 - `StudentDetail.vue` - 学生作业详情 - `StudentList.vue` - 学生列表 **功能:** - 作业发布与查看 - 作业提交记录 - 作业评审 - 成绩查看 --- ## 四、公共组件 ### 1. RichTextEditor.vue - 富文本编辑器 **功能:** - 基于 WangEditor - 支持图文混排 - 支持文件上传 - 表单验证集成 **使用示例:** ```vue ``` ### 2. ModelViewer.vue - 3D 模型预览 **功能:** - 基于 Three.js - 支持 GLB/GLTF 格式 - 轨道控制器(旋转/缩放/平移) - 自动加载/卸载 --- ## 五、API 封装 ### Axios 封装 (`utils/request.ts`) **核心特性:** - 请求拦截器(自动添加 Token) - 响应拦截器(统一错误处理) - 多租户支持 - TypeScript 泛型支持 **请求配置:** ```typescript const request = axios.create({ baseURL: '/api', timeout: 30000, }) // 请求拦截器 request.interceptors.request.use(config => { const token = getToken() if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) // 响应拦截器 request.interceptors.response.use( response => response.data, error => { if (error.response?.status === 401) { // Token 过期,跳转登录 } return Promise.reject(error) } ) ``` ### API 类型定义 ```typescript // types/api.ts export interface PaginationParams { page?: number pageSize?: number } export interface PaginationResponse { list: T[] total: number page: number pageSize: number } ``` --- ## 六、状态管理 ### Auth Store (`stores/auth.ts`) **State:** ```typescript { user: User | null, // 用户信息 token: string, // JWT Token menus: Menu[], // 用户菜单 loading: boolean // 加载状态 } ``` **Getters:** ```typescript { isAuthenticated: boolean, // 是否已登录 tenantCode: string, // 租户编码 isSuperAdmin: () => boolean, // 是否超管 hasPermission: (p: string) => boolean, // 权限检查 hasAnyRole: (roles: string[]) => boolean // 角色检查 } ``` **Actions:** ```typescript { login: (form: LoginForm) => Promise, logout: () => Promise, fetchUserInfo: () => Promise, fetchUserMenus: () => Promise, updateToken: (newToken: string) => void, initAuth: () => Promise, } ``` --- ## 七、组合式函数 (Composables) ### useListRequest **用途:** 列表数据请求通用逻辑 **使用示例:** ```typescript const { loading, list, total, page, pageSize, fetchList, handlePageChange, handleSizeChange, } = useListRequest(contestsApi.getList, initialParams) ``` ### useSimpleListRequest **用途:** 简化版列表请求(无分页) --- ## 八、自定义指令 ### v-permission 权限指令 **使用示例:** ```vue ``` **实现:** ```typescript // directives/permission.ts export const permission = { mounted(el, binding) { const { hasPermission } = useAuthStore() const value = binding.value const required = Array.isArray(value) ? value : [value] if (!hasPermission(required)) { el.parentNode?.removeChild(el) } } } ``` --- ## 九、核心业务流程 ### 1. 用户登录流程 ``` 1. 输入用户名密码 → 2. 调用 login API → 3. 存储 Token(按租户隔离) → 4. 获取用户信息 → 5. 获取用户菜单 → 6. 添加动态路由 → 7. 跳转到首页 ``` ### 2. 活动创建流程 ``` 1. 填写活动基本信息 → 2. 配置报名参数 → 3. 配置作品参数 → 4. 配置评审规则 → 5. 提交创建 → 6. 跳转到活动详情页 ``` ### 3. 作品提交流程 ``` 1. 选择活动 → 2. 点击提交作品 → 3. 填写作品信息(标题/描述) → 4. 上传作品文件 → 5. 上传预览图 → 6. 提交成功 → 7. 可查看/编辑(在截止时间前) ``` ### 4. 评审工作流程 ``` 1. 管理员分配作品给评委 → 2. 评委登录后查看待评审作品 → 3. 查看作品详情 → 4. 按维度评分 → 5. 填写评语 → 6. 提交评分 ``` ### 5. AI 3D 模型生成流程 ``` 1. 输入提示词 → 2. 选择生成类型 → 3. 提交任务 → 4. 轮询任务状态 → 5. 生成完成后展示 4 个角度模型 → 6. 下载模型文件 ``` --- ## 十、总结 ### 项目特点 1. **完整的前后端分离架构** - Vue 3 + TypeScript + Vite 2. **动态路由系统** - 基于菜单动态加载路由 3. **多租户支持** - 租户编码路径前缀 + Token 隔离 4. **细粒度权限控制** - 权限指令 + 路由守卫 5. **丰富的竞赛管理功能** - 从创建到评审全流程 6. **AI 能力集成** - 腾讯混元 3D 模型生成 7. **公众端独立入口** - /p 前缀区分 ### 适用场景 - 📚 图书馆绘本创作比赛 - 🏫 学校各类竞赛活动 - 🎨 艺术创作比赛 - 📖 作文/阅读比赛 - 🤖 科技创新大赛 ### 技术亮点 - Vue 3 Composition API - TypeScript 类型安全 - Pinia 状态管理 - Ant Design Vue 组件库 - Tailwind CSS 原子化 CSS - Three.js 3D 渲染 - WangEditor 富文本 --- > 文档生成时间:2026-03-28 > 分析人:AI Assistant