20 KiB
20 KiB
学校管理与比赛管理模块 - 产品功能说明、实现思路与开发计划
📋 目录
概述
系统定位
本系统是一个多租户的学校管理与比赛管理平台,支持:
- 多租户架构:每个学校作为一个租户,数据完全隔离
- 统一用户体系:教师和学生基于统一的 User 表,通过扩展表存储特定信息
- 完整的比赛流程:从比赛创建、报名、作品提交到评审、结果公布的完整生命周期
- 灵活的权限控制:基于 RBAC 的权限管理,支持细粒度的功能权限控制
核心价值
- 学校管理数字化:实现学校组织架构、人员管理的数字化
- 比赛管理规范化:规范比赛流程,提高管理效率
- 数据安全隔离:多租户架构确保各学校数据安全隔离
- 灵活扩展:模块化设计,易于扩展新功能
比赛管理模块
1. 功能概述
比赛管理模块提供完整的比赛生命周期管理,从比赛创建、发布、报名、作品提交、评审到结果公布的完整流程。
2. 核心功能
2.1 比赛管理
功能描述:
- 创建比赛(基本信息、时间安排、参赛范围等)
- 编辑比赛信息
- 发布/撤回比赛
- 查看比赛列表和详情
用户角色:
- 超级管理员:创建和管理所有比赛
- 比赛管理员:管理指定比赛
业务规则:
- 比赛名称在系统内唯一
- 时间顺序校验:报名开始 < 报名结束 < 提交开始 < 提交结束 < 评审开始 < 评审结束 < 结果发布
- 只有发布的比赛才能被租户看到
- 已发布的比赛可以撤回,但需检查是否有报名记录
2.2 比赛报名
功能描述:
- 个人赛报名:学生或教师个人报名
- 团队赛报名:创建团队、邀请成员、提交团队报名
- 报名审核(可选)
- 查看报名状态
用户角色:
- 学生:个人报名、创建/加入团队
- 教师:个人报名、代学生报名、创建/管理团队
- 比赛管理员:审核报名
业务规则:
- 报名时间限制:必须在报名时间窗口内
- 个人赛:一个用户在一个比赛中只能报名一次
- 团队赛:
- 团队名称在同一比赛、同一租户内唯一
- 团队成员角色:leader(队长)、member(队员)、mentor(指导教师)
- 团队报名时,所有成员状态同步更新
2.3 作品提交
功能描述:
- 提交参赛作品(标题、说明、文件等)
- 支持单次提交和多次提交(根据比赛配置)
- 作品版本管理
- 查看作品列表和详情
用户角色:
- 学生:提交作品
- 教师:代学生提交作品
- 团队队长:提交团队作品
业务规则:
- 提交时间限制:必须在提交时间窗口内
- 必须已通过报名审核
- 单次提交(submit_rule = 'once'):只能提交一次
- 多次提交(submit_rule = 'resubmit'):
- 可以多次提交,每次创建新版本
- 只有最新版本参与评审
- 旧版本保留历史记录
2.4 作品评审
功能描述:
- 配置评审规则(评分维度、权重等)
- 分配作品给评委
- 评委评分(多维度评分、评语)
- 查看评审进度和结果
用户角色:
- 比赛管理员:配置评审规则、分配作品
- 评委:查看分配的作品、进行评分
业务规则:
- 评审时间限制:必须在评审时间窗口内
- 每个作品可以被多个评委评审
- 最终得分计算:根据评审规则计算(平均分、加权平均等)
- 评审完成后,作品状态更新为 accepted 或 rejected
2.5 结果公布
功能描述:
- 公布比赛结果(获奖名单、排名等)
- 查看比赛结果统计
- 导出结果(Excel/PDF)
用户角色:
- 比赛管理员:公布结果
- 所有用户:查看结果
业务规则:
- 只有评审已完成的比赛可以公布结果
- 结果公布后,所有用户可以看到排名和获奖信息
2.6 比赛公告
功能描述:
- 发布比赛公告
- 管理公告(编辑、删除、置顶)
- 查看公告列表
用户角色:
- 比赛管理员:发布和管理公告
- 所有用户:查看公告
业务规则:
- 支持公告类型:系统公告、人工公告、紧急通知
- 支持优先级设置
3. 数据模型
Contest (比赛)
├── ContestAttachment (比赛附件) [1:N]
├── ContestReviewRule (评审规则) [1:1]
├── ContestTeam (团队) [1:N]
│ └── ContestTeamMember (团队成员) [1:N]
├── ContestRegistration (报名记录) [1:N]
│ └── ContestWork (作品) [1:N]
│ ├── ContestWorkAttachment (作品附件) [1:N]
│ ├── ContestWorkJudgeAssignment (作品分配) [1:N]
│ └── ContestWorkScore (作品评分) [1:N]
└── ContestNotice (比赛公告) [1:N]
4. 关键业务规则
- 租户隔离:比赛通过
contest_tenants字段控制可见范围 - 时间管理:严格的时间顺序校验和状态流转
- 版本控制:作品支持版本管理,保留历史记录
- 评审灵活:支持多维度评分和自定义评审规则
技术架构
1. 后端架构
backend/
├── src/
│ ├── school/ # 学校管理模块
│ │ ├── schools/
│ │ ├── grades/
│ │ ├── classes/
│ │ ├── departments/
│ │ ├── teachers/
│ │ └── students/
│ ├── contests/ # 比赛管理模块
│ │ ├── contests/
│ │ ├── registrations/
│ │ ├── teams/
│ │ ├── works/
│ │ ├── reviews/
│ │ └── notices/
│ ├── auth/ # 认证授权
│ ├── tenants/ # 租户管理
│ └── common/ # 公共模块
技术栈:
- 框架:NestJS
- ORM:Prisma
- 数据库:MySQL
- 认证:JWT
- 权限:RBAC
2. 前端架构
frontend/
├── src/
│ ├── views/
│ │ ├── school/ # 学校管理页面
│ │ │ ├── schools/
│ │ │ ├── grades/
│ │ │ ├── classes/
│ │ │ ├── departments/
│ │ │ ├── teachers/
│ │ │ └── students/
│ │ └── contests/ # 比赛管理页面
│ │ ├── Index.vue
│ │ ├── Create.vue
│ │ ├── works/
│ │ ├── registrations/
│ │ └── reviews/
│ ├── api/ # API 接口
│ ├── stores/ # 状态管理
│ └── utils/ # 工具函数
技术栈:
- 框架:Vue 3 + TypeScript
- 路由:Vue Router
- 状态管理:Pinia
- UI 框架:Element Plus / Ant Design Vue
- 构建工具:Vite
3. 数据库设计
设计原则:
- 多租户隔离:所有业务表都包含
tenantId字段 - 统一用户体系:教师和学生基于 User 表
- 数据完整性:使用外键约束和级联删除
- 审计追踪:所有表包含创建人、修改人、时间字段
核心表:
- 学校管理:
schools,grades,classes,departments,teachers,students - 比赛管理:
t_contest,t_contest_registration,t_contest_work,t_contest_work_score
实现思路
1. 多租户数据隔离
1.1 租户识别
实现方式:
- 请求头方式(推荐):
X-Tenant-Code: 租户编码X-Tenant-Id: 租户ID
- JWT Token 方式:
- Token 中包含
tenantId字段 - 登录时自动关联租户
- Token 中包含
- 子域名方式:
- 从
Host请求头提取子域名 - 匹配租户的
code或domain字段
- 从
1.2 数据过滤
实现方式:
// Service 层自动过滤租户数据
async findAll(tenantId: number) {
return this.prisma.model.findMany({
where: { tenantId }
});
}
// Controller 层获取租户信息
@Get()
findAll(@Request() req) {
const tenantId = req.tenantId || req.user?.tenantId;
return this.service.findAll(tenantId);
}
2. 统一用户体系
2.1 用户创建流程
教师创建:
1. 创建 User 记录(username, password, tenantId)
2. 创建 Teacher 记录(关联 User.id)
3. 分配角色和权限
学生创建:
1. 创建 User 记录(username, password, tenantId)
2. 创建 Student 记录(关联 User.id)
3. 分配角色和权限
2.2 用户扩展信息
实现方式:
- 使用 Prisma 的一对一关系
- 通过
include查询关联数据 - 通过事务保证数据一致性
3. 比赛流程管理
3.1 状态机设计
比赛状态:
unpublished → published → (可撤回) → unpublished
报名状态:
pending → passed/rejected/withdrawn
作品状态:
submitted → locked → reviewing → accepted/rejected
3.2 时间校验
实现方式:
// DTO 验证
@IsDate()
@Validate(TimeOrderValidator)
registerStartTime: Date;
// 自定义验证器
class TimeOrderValidator implements ValidatorConstraintInterface {
validate(value: any, args: ValidationArguments) {
const dto = args.object as CreateContestDto;
return dto.registerStartTime < dto.registerEndTime <
dto.submitStartTime < dto.submitEndTime <
dto.reviewStartTime < dto.reviewEndTime;
}
}
4. 文件上传
4.1 文件存储
实现方式:
- 使用对象存储(OSS/S3)或本地存储
- 文件上传接口返回文件 URL
- 文件信息存储到数据库
4.2 文件管理
实现方式:
// 文件上传
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
async uploadFile(@UploadedFile() file: Express.Multer.File) {
// 验证文件类型和大小
// 上传到存储
// 返回文件 URL
}
// 文件删除
@Delete('files/:id')
async deleteFile(@Param('id') id: string) {
// 删除文件
// 更新数据库记录
}
5. 权限控制
5.1 权限编码
命名规则:资源:操作
示例:
school:create # 创建学校
school:read # 查看学校
teacher:create # 创建教师
student:read # 查看学生
contest:create # 创建比赛
contest:publish # 发布比赛
work:submit # 提交作品
review:score # 评分
5.2 权限验证
实现方式:
// 使用装饰器
@RequirePermission('contest:create')
@Post()
create(@Body() dto: CreateContestDto) {
// ...
}
// Guard 自动验证权限
@Injectable()
export class PermissionsGuard implements CanActivate {
async canActivate(context: ExecutionContext) {
const requiredPermission = this.reflector.get(PERMISSION_KEY);
const userPermissions = await this.getUserPermissions();
return userPermissions.includes(requiredPermission);
}
}
开发计划
阶段一:基础架构与学校管理(3-4周)
1.1 数据库迁移(1周)
任务:
- 执行学校管理模块数据库迁移
- 执行比赛管理模块数据库迁移
- 验证数据表结构
- 创建初始化数据脚本
交付物:
- 数据库迁移文件
- 初始化数据脚本
- 数据库设计文档
1.2 学校管理后端(2周)
任务:
- 创建 school 模块(Controller、Service、DTO)
- 实现学校信息 CRUD
- 实现年级管理 CRUD
- 实现班级管理 CRUD(支持行政班级和兴趣班)
- 实现部门管理 CRUD(支持树形结构)
- 实现教师管理 CRUD(自动创建 User)
- 实现学生管理 CRUD(自动创建 User)
- 实现学生兴趣班关联管理
- 实现租户权限控制
- 编写单元测试
交付物:
- 学校管理后端 API
- API 文档
- 单元测试
1.3 学校管理前端(1-2周)
任务:
- 创建学校管理页面结构
- 实现学校信息管理页面
- 实现年级管理页面
- 实现班级管理页面(支持类型切换)
- 实现部门管理页面(树形结构)
- 实现教师管理页面(列表、创建、编辑)
- 实现学生管理页面(列表、创建、编辑)
- 实现学生兴趣班管理页面
- 集成权限控制
- 实现路由配置
交付物:
- 学校管理前端页面
- 路由配置
- 权限控制
阶段二:比赛管理基础功能(3-4周)
2.1 比赛管理后端(2周)
任务:
- 创建 contests 模块(Controller、Service、DTO)
- 实现比赛 CRUD 接口
- 实现比赛发布/撤回接口
- 实现比赛附件管理接口
- 实现评审规则管理接口
- 实现租户权限控制
- 实现时间校验逻辑
- 编写单元测试
交付物:
- 比赛管理后端 API
- API 文档
- 单元测试
2.2 比赛管理前端(1-2周)
任务:
- 创建比赛管理页面结构
- 实现比赛列表页面
- 实现比赛创建/编辑页面
- 实现比赛详情页面
- 实现比赛发布功能
- 集成权限控制
- 实现路由配置
交付物:
- 比赛管理前端页面
- 路由配置
阶段三:报名功能(2-3周)
3.1 报名后端(1.5周)
任务:
- 创建 registrations 模块
- 实现个人报名接口
- 创建 teams 模块
- 实现团队创建/管理接口
- 实现团队报名接口
- 实现报名审核接口
- 实现报名状态流转逻辑
- 编写单元测试
交付物:
- 报名管理后端 API
- API 文档
3.2 报名前端(1-1.5周)
任务:
- 实现比赛报名页面
- 实现团队管理页面
- 实现报名审核页面
- 实现报名状态展示
- 实现团队邀请功能
交付物:
- 报名管理前端页面
阶段四:作品提交功能(2-3周)
4.1 作品提交后端(1.5周)
任务:
- 创建 works 模块
- 实现作品提交接口
- 实现文件上传功能
- 实现作品版本控制逻辑
- 实现作品状态管理
- 实现作品列表查询(支持筛选)
- 编写单元测试
交付物:
- 作品管理后端 API
- 文件上传功能
4.2 作品提交前端(1-1.5周)
任务:
- 实现作品提交页面
- 实现文件上传组件
- 实现作品列表页面
- 实现作品详情页面
- 实现作品版本管理
交付物:
- 作品管理前端页面
阶段五:评审功能(3-4周)
5.1 评审后端(2周)
任务:
- 创建 reviews 模块
- 实现评审规则管理接口
- 实现作品分配接口(手动/自动)
- 实现评分接口
- 实现评分计算逻辑
- 实现评审进度统计
- 编写单元测试
交付物:
- 评审管理后端 API
- 评分计算逻辑
5.2 评审前端(1-2周)
任务:
- 实现评审规则配置页面
- 实现作品分配页面
- 实现评分页面(多维度评分表单)
- 实现评审进度页面
- 实现评审结果统计
交付物:
- 评审管理前端页面
阶段六:结果公布与公告(1-2周)
6.1 结果公布后端(1周)
任务:
- 创建 notices 模块
- 实现公告 CRUD 接口
- 实现结果公布接口
- 实现结果统计接口
- 实现结果导出接口(Excel/PDF)
交付物:
- 公告和结果管理后端 API
6.2 结果公布前端(1周)
任务:
- 实现公告管理页面
- 实现结果公布页面
- 实现结果展示页面(排名、获奖名单)
- 实现结果导出功能
交付物:
- 公告和结果管理前端页面
阶段七:优化与测试(2-3周)
7.1 功能优化(1-2周)
任务:
- 性能优化(数据库查询优化、缓存)
- 用户体验优化
- 错误处理完善
- 日志记录完善
7.2 测试(1周)
任务:
- 单元测试补充
- 集成测试
- 端到端测试
- 压力测试
- 安全测试
交付物:
- 测试报告
- 性能报告
权限设计
1. 角色规划
1.1 系统角色
超级管理员(super_admin):
- 所有权限
- 创建和管理租户
- 创建和管理比赛
学校管理员(school_admin):
- 学校管理:school:*
- 年级管理:grade:*
- 班级管理:class:*
- 部门管理:department:*
- 教师管理:teacher:*
- 学生管理:student:*
比赛管理员(contest_admin):
- 比赛管理:contest:*
- 公告管理:notice:*
- 结果公布:result:publish
评委(judge):
- 作品查看:work:read
- 评审分配:review:assign
- 评分:review:score
- 评审查看:review:read
教师(teacher):
- 比赛查看:contest:read
- 比赛报名:contest:register
- 作品提交:work:submit
- 作品查看:work:read
- 学生管理:student:read(本班级)
学生(student):
- 比赛查看:contest:read
- 比赛报名:contest:register
- 作品提交:work:submit
- 作品查看:work:read(自己的作品)
- 结果查看:result:read
2. 权限编码
2.2 比赛管理权限
contest:create # 创建比赛
contest:read # 查看比赛
contest:update # 更新比赛
contest:delete # 删除比赛
contest:publish # 发布比赛
contest:register # 报名比赛
team:create # 创建团队
team:read # 查看团队
team:update # 更新团队
team:delete # 删除团队
work:submit # 提交作品
work:read # 查看作品
work:update # 更新作品
review:assign # 分配作品
review:score # 评分
review:read # 查看评审
result:publish # 公布结果
result:read # 查看结果
notice:create # 创建公告
notice:read # 查看公告
notice:update # 更新公告
notice:delete # 删除公告
数据流转
1. 学校管理数据流
创建租户
↓
创建学校信息
↓
创建年级
↓
创建班级(行政班级/兴趣班)
↓
创建部门
↓
创建教师账号(User + Teacher)
↓
创建学生账号(User + Student)
↓
学生加入兴趣班(StudentInterestClass)
2. 比赛管理数据流
创建比赛(超级管理员)
↓
配置评审规则
↓
发布比赛
↓
学生/教师报名(个人/团队)
↓
报名审核(可选)
↓
提交作品
↓
分配作品给评委
↓
评委评分
↓
计算最终得分
↓
公布结果
3. 关键数据关联
用户与学校:
- User.tenantId → Tenant.id
- Teacher.userId → User.id
- Student.userId → User.id
用户与比赛:
- ContestRegistration.userId → User.id
- ContestWork.submitterUserId → User.id
- ContestWorkScore.judgeId → User.id
比赛与租户:
- Contest.contestTenants (JSON) → Tenant.id[]
- ContestRegistration.tenantId → Tenant.id
- ContestWork.tenantId → Tenant.id
总结
本文档详细描述了学校管理和比赛管理两个核心模块的产品功能、实现思路和开发计划。主要特点:
- 完整的业务流程:覆盖从学校管理到比赛全生命周期的所有环节
- 清晰的架构设计:多租户、统一用户体系、模块化设计
- 详细的开发计划:分阶段实施,每个阶段都有明确的交付物
- 完善的权限体系:基于 RBAC 的细粒度权限控制
建议按照开发计划逐步实施,每个阶段完成后进行充分测试,确保系统稳定可靠。