# 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
