# 赛事管理模块产品方案与实现计划 ## 📋 目录 1. [产品交互方案](#产品交互方案) 2. [数据库设计分析](#数据库设计分析) 3. [功能模块划分](#功能模块划分) 4. [实现计划](#实现计划) 5. [技术实现要点](#技术实现要点) --- ## 产品交互方案 ### 1. 赛事创建 #### 1.1 功能概述 管理员创建赛事,填写赛事基本信息、时间安排、参赛范围等。 #### 1.2 交互流程 ``` 管理员进入"赛事管理" → 点击"创建赛事" → 填写表单 → 保存草稿/提交审核 ``` #### 1.3 表单字段(基于 t_contest 表) - **基本信息** - 赛事名称(必填,唯一性校验) - 赛事类型(字典:individual/team) - 赛事状态(默认:unpublished) - 封面图(上传) - 海报图(上传) - 赛事详情(富文本编辑器) - **时间安排** - 赛事开始时间 - 赛事结束时间 - 报名开始时间 - 报名结束时间 - 作品提交开始时间 - 作品提交结束时间 - 评审开始时间 - 评审结束时间 - 结果发布时间(可选) - **参赛范围** - 授权租户(多选,支持租户列表选择) - 提交规则(once/resubmit) - **联系信息** - 联系人姓名 - 联系电话 - 联系人二维码(上传) - **组织信息** - 主办单位(数组) - 协办单位(数组) - 赞助单位(数组) - **线下信息** - 线下地址(可选) - **评审规则** - 评审规则ID(关联评审规则配置) #### 1.4 业务规则 - 时间顺序校验:报名开始 < 报名结束 < 提交开始 < 提交结束 < 评审开始 < 评审结束 < 结果发布 - 赛事名称在系统内唯一 - 创建后状态为 `unpublished`,需要发布后才能被租户看到 - 支持保存草稿(可多次编辑) --- ### 2. 赛事发布 #### 2.1 功能概述 管理员将已创建的赛事发布,使其对授权租户可见。 #### 2.2 交互流程 ``` 赛事列表 → 选择赛事 → 点击"发布" → 确认发布 → 更新状态为 published ``` #### 2.3 业务规则 - 只有状态为 `unpublished` 的赛事可以发布 - 发布前校验必填字段完整性 - 发布后,授权租户可以看到该赛事 - 已发布的赛事可以撤回(状态改回 `unpublished`),但需要检查是否有报名记录 --- ### 3. 赛事公告 #### 3.1 功能概述 管理员发布赛事相关公告,通知参赛者重要信息。 #### 3.2 交互流程 ``` 赛事详情页 → "公告管理" → 创建公告 → 编辑内容 → 发布公告 ``` #### 3.3 功能设计 **注意**:当前 SQL 中没有公告表,需要新增: - `t_contest_notice` 表 - id, contest_id, title, content, notice_type, priority, publish_time, creator, create_time, modify_time, valid_state #### 3.4 公告类型 - 系统公告(系统自动生成) - 人工公告(管理员发布) - 紧急通知(高优先级) --- ### 4. 赛事报名 #### 4.1 功能概述 授权租户的用户(学生/老师)报名参加赛事,支持个人赛和团队赛。 #### 4.2 交互流程 **个人赛报名:** ``` 租户用户登录 → 浏览已发布赛事 → 选择赛事 → 点击"立即报名" → 填写信息 → 提交报名 ``` **团队赛报名:** ``` 队长创建团队 → 邀请成员 → 成员确认加入 → 队长提交团队报名 → 等待审核 ``` #### 4.3 报名流程详细设计 **4.3.1 个人赛报名** 1. 用户选择赛事 2. 检查报名时间是否在有效期内 3. 检查用户是否已报名(防止重复报名) 4. 填写报名信息(账号信息自动填充) 5. 提交报名(状态:pending) 6. 管理员审核(可选,根据赛事配置) 7. 审核通过(状态:passed)或拒绝(状态:rejected) **4.3.2 团队赛报名** 1. 队长创建团队 - 填写团队名称(租户内唯一) - 设置最大成员数 - 邀请成员(通过账号搜索) 2. 成员确认加入 - 收到邀请通知 - 确认/拒绝加入 3. 队长提交团队报名 - 检查团队成员数量是否符合要求 - 提交报名(所有成员状态:pending) 4. 管理员审核团队报名 - 审核通过:所有成员状态改为 passed - 审核拒绝:所有成员状态改为 rejected #### 4.4 数据表关系 - `t_contest_registration`:报名记录表 - 个人赛:registration_type = 'individual',team_id = null - 团队赛:registration_type = 'team',team_id 关联 t_contest_team - `t_contest_team`:团队表 - `t_contest_team_member`:团队成员表 #### 4.5 业务规则 - 报名时间限制:必须在 `register_start_time` 和 `register_end_time` 之间 - 报名状态流转:pending → passed/rejected/withdrawn - 已通过的报名可以撤回(withdrawn),但需要检查是否已提交作品 - 团队名称在同一赛事、同一租户内唯一 - 团队成员角色:leader(队长)、member(队员)、mentor(指导教师) --- ### 5. 赛事作品提交 #### 5.1 功能概述 已报名的用户提交参赛作品,支持单次提交和多次提交(根据赛事配置)。 #### 5.2 交互流程 ``` 已报名用户 → 进入"我的赛事" → 选择赛事 → 点击"提交作品" → 上传作品文件 → 填写作品信息 → 提交 ``` #### 5.3 作品提交表单 - 作品标题(必填) - 作品说明(可选) - 作品文件(支持多文件上传) - 图片、视频、3D模型等 - 文件类型和大小限制 - 作品预览URL(可选,用于3D/视频预览) - AI建模元数据(可选,JSON格式) #### 5.4 提交规则 **单次提交(submit_rule = 'once'):** - 只能提交一次作品 - 提交后状态为 `submitted`,不可修改 **多次提交(submit_rule = 'resubmit'):** - 可以多次提交作品 - 每次提交创建新版本(version 递增) - 旧版本 `is_latest = 0`,新版本 `is_latest = 1` - 只有最新版本参与评审 #### 5.5 数据表关系 - `t_contest_work`:作品主表 - entry_id 关联 t_contest_registration.id - files 字段存储简易文件列表(JSON) - `t_contest_work_attachment`:作品附件表(详细文件信息) #### 5.6 业务规则 - 提交时间限制:必须在 `submit_start_time` 和 `submit_end_time` 之间 - 必须已通过报名审核(registration_state = 'passed') - 作品编号(work_no)自动生成,格式:CONTEST-{contest_id}-{序号} - 作品状态流转: - submitted(已提交) - locked(已锁定,不可修改) - reviewing(评审中) - rejected(已拒绝) - accepted(已接受) --- ### 6. 赛事作品评审 #### 6.1 功能概述 评委对提交的作品进行评分,支持多维度评分和评语。 #### 6.2 交互流程 ``` 评委登录 → 进入"评审管理" → 选择赛事 → 查看分配的作品列表 → 点击作品 → 查看作品详情 → 评分 → 提交评分 ``` #### 6.3 评审流程设计 **6.3.1 作品分配** - 需要新增表:`t_contest_work_judge_assignment`(作品分配表) - id, contest_id, work_id, judge_id, assignment_time, status - 管理员或系统自动分配作品给评委 - 支持手动分配和自动分配(轮询、随机等) **6.3.2 评分界面** - 显示作品信息(标题、说明、文件、预览等) - 显示评审规则(review_rule_id 关联的评审规则) - 多维度评分表单 - 根据评审规则动态生成评分维度 - 每个维度设置分数范围 - 总分自动计算(根据评审规则配置的权重) - 评语输入框 - 提交评分按钮 **6.3.3 评分数据** - `t_contest_work_score`:评分表 - dimension_scores:JSON格式,存储各维度分数 - total_score:总分(根据规则计算) - comments:评语 #### 6.4 评审规则设计 需要新增表:`t_contest_review_rule`(评审规则表) - id, contest_id, rule_name, dimensions(JSON,存储评分维度配置) - 示例维度配置: ```json { "dimension1": { "name": "创意性", "weight": 0.3, "maxScore": 100 }, "dimension2": { "name": "技术性", "weight": 0.4, "maxScore": 100 }, "dimension3": { "name": "完成度", "weight": 0.3, "maxScore": 100 } } ``` #### 6.5 业务规则 - 评审时间限制:必须在 `review_start_time` 和 `review_end_time` 之间 - 作品状态更新:评审开始时,作品状态改为 `reviewing` - 每个作品可以被多个评委评审 - 最终得分计算:取所有评委的平均分,或根据评审规则计算 - 评审完成后,作品状态改为 `accepted` 或 `rejected` --- ### 7. 赛事结果公布 #### 7.1 功能概述 管理员公布赛事评审结果,包括获奖名单、排名等。 #### 7.2 交互流程 ``` 管理员 → 进入"赛事管理" → 选择赛事 → 点击"公布结果" → 确认公布 → 结果发布 ``` #### 7.3 结果公布内容 - 获奖名单(按奖项分类) - 作品排名(按总分排序) - 各维度平均分统计 - 评审统计信息(参与评审人数、作品数量等) #### 7.4 业务规则 - 只有评审已完成的赛事可以公布结果 - 公布后,`result_publish_time` 设置为当前时间 - 结果公布后,所有用户可以看到排名和获奖信息 - 支持导出结果(Excel/PDF) --- ## 数据库设计分析 ### 现有表结构 #### 1. t_contest(赛事表) ✅ **优点:** - 字段设计完整,覆盖赛事全生命周期 - 支持多租户(contest_tenant 字段) - 时间字段齐全 ⚠️ **注意事项:** - `contest_tenant` 使用 text 类型存储租户列表,建议考虑 JSON 类型或关联表 - `organizers`、`co_organizers`、`sponsors` 使用 text 存储数组,建议使用 JSON #### 2. t_contest_attachment(赛事附件表) ✅ 设计合理,支持多种文件类型 #### 3. t_contest_work(作品表) ✅ **优点:** - 支持版本控制(version、is_latest) - 支持多种提交来源(teacher/student/team_leader) - 支持 AI 建模元数据 ⚠️ **问题:** - 索引 `idx_submit_filter` 引用了不存在的字段 `review_status`,应删除或修正 #### 4. t_contest_work_attachment(作品附件表) ⚠️ **问题:** - 第102行末尾有多余的逗号,需要删除 #### 5. t_contest_work_score(评分表) ⚠️ **问题:** - 表定义重复(104-123行和125-144行),需要删除重复定义 #### 6. t_contest_registration(报名表) ✅ 设计合理,支持个人和团队报名 #### 7. t_contest_team(团队表) ⚠️ **问题:** - 唯一索引 `uk_team_name` 引用了不存在的字段 `name`,应改为 `team_name` #### 8. t_contest_team_member(团队成员表) ✅ 设计合理 ### 缺失的表结构 #### 1. t_contest_notice(赛事公告表) ```sql CREATE TABLE `t_contest_notice` ( `id` varchar(63) NOT NULL COMMENT '主键id', `contest_id` varchar(63) NOT NULL COMMENT '赛事id', `title` varchar(255) NOT NULL COMMENT '公告标题', `content` text NOT NULL COMMENT '公告内容', `notice_type` varchar(31) NOT NULL DEFAULT 'manual' COMMENT '公告类型:system/manual/urgent', `priority` int DEFAULT 0 COMMENT '优先级(数字越大优先级越高)', `publish_time` datetime DEFAULT NULL COMMENT '发布时间', `creator` varchar(63) NOT NULL DEFAULT '' COMMENT '创建人', `modifier` varchar(63) NOT NULL DEFAULT '' COMMENT '修改人', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `modify_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `valid_state` varchar(1) NOT NULL DEFAULT '1' COMMENT '有效状态(1-有效,2-失效)', PRIMARY KEY (`id`), KEY `idx_contest` (`contest_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='赛事公告表'; ``` #### 2. t_contest_review_rule(评审规则表) ```sql CREATE TABLE `t_contest_review_rule` ( `id` varchar(63) NOT NULL COMMENT '主键id', `contest_id` varchar(63) NOT NULL COMMENT '赛事id', `rule_name` varchar(127) NOT NULL COMMENT '规则名称', `dimensions` json NOT NULL COMMENT '评分维度配置JSON', `calculation_rule` varchar(31) DEFAULT 'average' COMMENT '计算规则:average/max/min/weighted', `creator` varchar(63) NOT NULL DEFAULT '' COMMENT '创建人', `modifier` varchar(63) NOT NULL DEFAULT '' COMMENT '修改人', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `modify_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `valid_state` varchar(1) NOT NULL DEFAULT '1' COMMENT '有效状态(1-有效,2-失效)', PRIMARY KEY (`id`), KEY `idx_contest` (`contest_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评审规则表'; ``` #### 3. t_contest_work_judge_assignment(作品分配表) ```sql CREATE TABLE `t_contest_work_judge_assignment` ( `id` varchar(63) NOT NULL COMMENT '主键id', `contest_id` varchar(63) NOT NULL COMMENT '赛事id', `work_id` varchar(63) NOT NULL COMMENT '作品id', `judge_id` varchar(63) NOT NULL COMMENT '评委用户id', `assignment_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '分配时间', `status` varchar(31) NOT NULL DEFAULT 'assigned' COMMENT '分配状态:assigned/reviewing/completed', `creator` varchar(63) NOT NULL DEFAULT '' COMMENT '创建人', `modifier` varchar(63) NOT NULL DEFAULT '' COMMENT '修改人', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `modify_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_work_judge` (`work_id`, `judge_id`), KEY `idx_contest_judge` (`contest_id`, `judge_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='作品分配表'; ``` --- ## 功能模块划分 ### 后端模块结构 ``` backend/src/contests/ ├── contests.module.ts # 赛事主模块 ├── contests.controller.ts # 赛事控制器 ├── contests.service.ts # 赛事服务 ├── dto/ │ ├── create-contest.dto.ts │ ├── update-contest.dto.ts │ ├── query-contest.dto.ts │ └── publish-contest.dto.ts ├── works/ │ ├── works.module.ts │ ├── works.controller.ts │ ├── works.service.ts │ └── dto/ │ ├── create-work.dto.ts │ ├── update-work.dto.ts │ └── submit-work.dto.ts ├── registrations/ │ ├── registrations.module.ts │ ├── registrations.controller.ts │ ├── registrations.service.ts │ └── dto/ │ ├── create-registration.dto.ts │ ├── review-registration.dto.ts │ └── create-team.dto.ts ├── teams/ │ ├── teams.module.ts │ ├── teams.controller.ts │ ├── teams.service.ts │ └── dto/ │ ├── create-team.dto.ts │ └── invite-member.dto.ts ├── reviews/ │ ├── reviews.module.ts │ ├── reviews.controller.ts │ ├── reviews.service.ts │ └── dto/ │ ├── create-score.dto.ts │ ├── assign-work.dto.ts │ └── create-review-rule.dto.ts └── notices/ ├── notices.module.ts ├── notices.controller.ts ├── notices.service.ts └── dto/ ├── create-notice.dto.ts └── update-notice.dto.ts ``` ### 前端模块结构 ``` frontend/src/views/contests/ ├── Index.vue # 赛事列表页 ├── Create.vue # 创建赛事页 ├── Detail.vue # 赛事详情页 ├── Edit.vue # 编辑赛事页 ├── works/ │ ├── Index.vue # 作品列表页 │ ├── Submit.vue # 提交作品页 │ └── Detail.vue # 作品详情页 ├── registrations/ │ ├── Index.vue # 报名列表页 │ ├── Register.vue # 报名页 │ └── Review.vue # 审核报名页 ├── teams/ │ ├── Index.vue # 团队列表页 │ ├── Create.vue # 创建团队页 │ └── Detail.vue # 团队详情页 ├── reviews/ │ ├── Index.vue # 评审列表页 │ ├── Score.vue # 评分页 │ └── Results.vue # 结果公布页 └── notices/ ├── Index.vue # 公告列表页 └── Create.vue # 创建公告页 ``` --- ## 实现计划 ### 阶段一:基础功能(2-3周) #### 1.1 数据库迁移 - [ ] 修复 SQL 文件中的错误 - 删除 `t_contest_work_score` 重复定义 - 修复 `t_contest_work_attachment` 的逗号错误 - 修复 `t_contest_team` 索引字段名错误 - 修复 `t_contest_work` 索引字段错误 - [ ] 创建缺失的表(公告表、评审规则表、作品分配表) - [ ] 更新 Prisma schema - [ ] 执行数据库迁移 #### 1.2 后端基础模块 - [ ] 创建 contests 模块(Controller、Service、DTO) - [ ] 实现赛事 CRUD 接口 - [ ] 实现赛事发布/撤回接口 - [ ] 实现租户权限控制 - [ ] 编写单元测试 #### 1.3 前端基础页面 - [ ] 创建赛事列表页 - [ ] 创建赛事创建/编辑页 - [ ] 创建赛事详情页 - [ ] 集成权限控制 - [ ] 实现路由配置 ### 阶段二:报名功能(2周) #### 2.1 后端实现 - [ ] 创建 registrations 模块 - [ ] 实现个人报名接口 - [ ] 实现团队报名接口 - [ ] 实现报名审核接口 - [ ] 实现报名状态流转逻辑 #### 2.2 前端实现 - [ ] 创建报名页面 - [ ] 创建团队管理页面 - [ ] 创建报名审核页面 - [ ] 实现报名状态展示 ### 阶段三:作品提交功能(2周) #### 3.1 后端实现 - [ ] 创建 works 模块 - [ ] 实现作品提交接口 - [ ] 实现文件上传功能 - [ ] 实现作品版本控制逻辑 - [ ] 实现作品状态管理 #### 3.2 前端实现 - [ ] 创建作品提交页面 - [ ] 实现文件上传组件 - [ ] 创建作品列表页 - [ ] 创建作品详情页 ### 阶段四:评审功能(2-3周) #### 4.1 后端实现 - [ ] 创建 reviews 模块 - [ ] 实现评审规则管理接口 - [ ] 实现作品分配接口 - [ ] 实现评分接口 - [ ] 实现评分计算逻辑 #### 4.2 前端实现 - [ ] 创建评审规则配置页 - [ ] 创建作品分配页 - [ ] 创建评分页面 - [ ] 实现多维度评分表单 ### 阶段五:结果公布与公告(1周) #### 5.1 后端实现 - [ ] 创建 notices 模块 - [ ] 实现公告 CRUD 接口 - [ ] 实现结果公布接口 - [ ] 实现结果统计接口 #### 5.2 前端实现 - [ ] 创建公告管理页面 - [ ] 创建结果公布页面 - [ ] 实现结果展示页面 ### 阶段六:优化与测试(1-2周) #### 6.1 功能优化 - [ ] 性能优化(数据库查询优化、缓存) - [ ] 用户体验优化 - [ ] 错误处理完善 #### 6.2 测试 - [ ] 单元测试 - [ ] 集成测试 - [ ] 端到端测试 - [ ] 压力测试 --- ## 技术实现要点 ### 1. 权限设计 #### 1.1 权限编码规划 ``` contest:create # 创建赛事 contest:read # 查看赛事 contest:update # 更新赛事 contest:delete # 删除赛事 contest:publish # 发布赛事 contest:register # 报名赛事 work:submit # 提交作品 work:read # 查看作品 work:update # 更新作品 review:assign # 分配作品 review:score # 评分 review:read # 查看评审 result:publish # 公布结果 notice:create # 创建公告 notice:read # 查看公告 ``` #### 1.2 角色规划 - **超级管理员**:所有权限 - **赛事管理员**:contest:*、notice:*、result:publish - **评委**:review:assign、review:score、review:read、work:read - **参赛者**:contest:read、contest:register、work:submit、work:read ### 2. 租户隔离 #### 2.1 数据隔离策略 - 赛事创建:超级租户创建,通过 `contest_tenant` 字段控制可见范围 - 报名数据:通过 `tenant_key` 字段隔离 - 作品数据:通过 `tenant_key` 字段隔离 - 评审数据:通过 `tenant_key` 字段隔离 #### 2.2 接口权限控制 - 使用 `@TenantId()` 装饰器获取租户信息 - Service 层自动过滤租户数据 - Controller 层验证租户权限 ### 3. 时间状态管理 #### 3.1 赛事状态机 ``` unpublished → published → (可撤回) → unpublished ``` #### 3.2 报名状态机 ``` pending → passed/rejected/withdrawn ``` #### 3.3 作品状态机 ``` submitted → locked → reviewing → accepted/rejected ``` #### 3.4 定时任务 - 自动更新报名状态(根据时间) - 自动更新作品提交状态 - 自动更新评审状态 - 自动发送通知(可选) ### 4. 文件上传 #### 4.1 文件存储 - 使用对象存储(OSS/S3)或本地存储 - 文件类型限制:图片、视频、3D模型、文档等 - 文件大小限制:根据文件类型设置 #### 4.2 文件管理 - 文件上传接口 - 文件删除接口 - 文件预览接口 - 文件下载接口 ### 5. 通知系统 #### 5.1 通知类型 - 报名成功通知 - 报名审核结果通知 - 作品提交成功通知 - 评审结果通知 - 结果公布通知 #### 5.2 通知方式(可选) - 站内消息 - 邮件通知 - 短信通知(可选) ### 6. 数据统计 #### 6.1 赛事统计 - 报名人数统计 - 作品提交数量统计 - 评审进度统计 - 结果统计 #### 6.2 报表导出 - 报名名单导出(Excel) - 作品列表导出(Excel) - 评审结果导出(Excel) - 结果报告导出(PDF) --- ## 注意事项 ### 1. SQL 文件问题修复 在开始开发前,必须先修复 SQL 文件中的错误: - 删除重复的 `t_contest_work_score` 表定义 - 修复 `t_contest_work_attachment` 表的语法错误 - 修复 `t_contest_team` 表的索引错误 - 修复 `t_contest_work` 表的索引错误 ### 2. 数据一致性 - 报名和作品的关系:一个报名可以对应多个作品版本 - 团队和报名的关系:一个团队对应多个报名记录(每个成员一条) - 作品和评分的关系:一个作品可以有多条评分记录(多个评委) ### 3. 性能考虑 - 赛事列表查询需要分页 - 作品列表查询需要分页和筛选 - 评分计算需要缓存 - 文件上传需要异步处理 ### 4. 安全性 - 文件上传需要验证文件类型和大小 - 接口需要权限验证 - 敏感操作需要日志记录 - 防止 SQL 注入和 XSS 攻击 --- ## 总结 本方案基于现有的多租户 RBAC 系统架构,设计了完整的赛事管理功能模块。主要特点: 1. **完整的生命周期管理**:从赛事创建到结果公布的全流程 2. **灵活的参赛方式**:支持个人赛和团队赛 3. **强大的评审系统**:支持多维度评分和自定义评审规则 4. **良好的扩展性**:模块化设计,易于扩展新功能 建议按照阶段逐步实现,每个阶段完成后进行测试和优化,确保系统稳定可靠。