898 lines
22 KiB
Markdown
898 lines
22 KiB
Markdown
|
|
# 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<User | null>(null)
|
|||
|
|
const token = ref<string>(getToken() || "")
|
|||
|
|
const menus = ref<Menu[]>([])
|
|||
|
|
|
|||
|
|
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
|
|||
|
|
<template>
|
|||
|
|
<RichTextEditor v-model="content" :height="400" />
|
|||
|
|
</template>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 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<T> {
|
|||
|
|
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<LoginResponse>,
|
|||
|
|
logout: () => Promise<void>,
|
|||
|
|
fetchUserInfo: () => Promise<User>,
|
|||
|
|
fetchUserMenus: () => Promise<Menu[]>,
|
|||
|
|
updateToken: (newToken: string) => void,
|
|||
|
|
initAuth: () => Promise<void>,
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、组合式函数 (Composables)
|
|||
|
|
|
|||
|
|
### useListRequest
|
|||
|
|
|
|||
|
|
**用途:** 列表数据请求通用逻辑
|
|||
|
|
|
|||
|
|
**使用示例:**
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const {
|
|||
|
|
loading,
|
|||
|
|
list,
|
|||
|
|
total,
|
|||
|
|
page,
|
|||
|
|
pageSize,
|
|||
|
|
fetchList,
|
|||
|
|
handlePageChange,
|
|||
|
|
handleSizeChange,
|
|||
|
|
} = useListRequest(contestsApi.getList, initialParams)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### useSimpleListRequest
|
|||
|
|
|
|||
|
|
**用途:** 简化版列表请求(无分页)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、自定义指令
|
|||
|
|
|
|||
|
|
### v-permission 权限指令
|
|||
|
|
|
|||
|
|
**使用示例:**
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<template>
|
|||
|
|
<button v-permission="['user:create']">创建用户</button>
|
|||
|
|
<button v-permission="'admin'">超管功能</button>
|
|||
|
|
</template>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现:**
|
|||
|
|
|
|||
|
|
```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
|