# show_manager **Repository Path**: LIU_YIHUI/show_manager ## Basic Information - **Project Name**: show_manager - **Description**: 24人的路演,结束后二维码扫描投票。 ### 基本要求 1. 一共有100名投票人员,分成两组,专家组30人,大众组70人。 2. 专家组的分数占比为60%,大众组的分数占比为40%。 3. 投票人员的身份需要核验(比如手机号)。 4. 最后给出前12名排名。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-11-11 - **Last Updated**: 2025-11-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 路演投票系统 ## 开发方式 使用 Vscode 的 Cline 插件从 0 到 1 开发前后端代码,所有代码几乎都由 ai 编写。 本文档的内容不是 ai 写的,只是 ai 添加的格式。 ## 项目需求 24人的路演,结束后二维码扫描投票。 ### 基本要求 1. 一共有100名投票人员,分成两组,专家组30人,大众组70人。 2. 专家组的分数占比为60%,大众组的分数占比为40%。 3. 投票人员的身份需要核验(比如手机号)。 4. 最后给出前12名排名。 ### 注意事项 注意,这只是一个小练习,不是真正的项目需求,因此不需要设计的那么复杂,也不需要 rbac 权限控制。这只是一次性使用的小软件,不考虑后期扩展。 ## 我的部署环境: JDK8 、 Maven 3.5.3 、 Mysql 5.7 、 Redis 、 Lombok 插件。 项目中有 sql 脚本。 ## 实现思路 将用户分为组织者和评委。 ### 角色分工 - **组织者**:负责添加评委、发起投票、停止投票、查看统计结果。 - **评委**:分为专家和大众两种类型,可以给选手投票。 ### 设计简化 由于我没有开通 sms 服务,所以考虑使用邮件发送投票链接和验证码。不涉及演员管理。演员的编号写死从1 到 24,投票时让评委手动输入。 也不提供场次管理,因为在该模块中还要关联评委,前端页面比较麻烦,因此由开发者为组织者自行添加一条默认的记录,它的 id 为 1。 由于没有提供场次管理,因此场次的操作就都在主页面中完成。场次也没有关联任何评委,因此让所有评委投票。 ## 数据库表设计 ### 管理员表 (admin) | 字段名 | 类型 | 说明 | 备注 | |--------|------|------|------| | id | int | 主键 | 自增 | | name | varchar | 用户名 | 唯一且不可为空 | | password | varchar | 密码 | 不可为空 | | status | tinyint | 状态 | 0 正常,1 锁定,默认为 0 | | createTime | datetime | 创建时间 | 默认为当前时间,不可为空 | | updateTime | datetime | 更新时间 | 默认为当前时间,不可为空 | ### 场次表 (show_session) | 字段名 | 类型 | 说明 | 备注 | |--------|------|------|------| | id | int | 主键 | - | | name | varchar | 场次名称 | 不可为空 | | status | tinyint | 状态 | 0 未开始,1 进行中,2 已结束,默认为 0 | | createTime | datetime | 创建时间 | 默认为当前时间,不可为空 | | updateTime | datetime | 更新时间 | 默认为当前时间,不可为空 | ### 评委表 (judge) | 字段名 | 类型 | 说明 | 备注 | |--------|------|------|------| | id | int | 主键 | 自增 | | type | tinyint | 评委类型 | 0 大众,1 专家,不可为空 | | status | tinyint | 状态 | 0 未锁定,1 已锁定,默认为 0,不可为空 | | name | varchar | 姓名 | 唯一且不可为空 | | email | varchar | 邮箱 | 唯一且不可为空 | | createTime | datetime | 创建时间 | 默认为当前时间,不可为空 | | updateTime | datetime | 更新时间 | 默认为当前时间,不可为空 | ### 投票表 (vote) | 字段名 | 类型 | 说明 | 备注 | |--------|------|------|------| | id | int | 主键 | 自增 | | show_session_id | int | 场次 id | 不可为空 | | judge_id | int | 评委 id | 不可为空 | | player_code | int | 所支持选手的编号 | 不可为空 | | createTime | datetime | 创建时间 | 默认为当前时间,不可为空 | | updateTime | datetime | 更新时间 | 默认为当前时间,不可为空 | ## 界面设计 管理员的大多数页面和接口都需要登录。它们的路径都已 "/admin/" 开头。如果未登录,则跳转到管理员登录页面。为了一切从简,使用老旧的 session 技术实现登录功能。由于我不会前端,所以前端代码不要写的太复杂。很久之前接触过 JQuery,因此可以使用该框架发送 ajax 请求。 ### 登录页界面设计 用户输入管理员名称、密码即可直接登录。 ### 管理员主页设计 需要包含如下内容: - 提供评委管理的入口 - 显示场次名称、场次状态、大众评委数、专家评委数 - 显示实时统计按钮 - 如果场次状态为未开始,则需要提供发起投票按钮 - 如果场次状态为进行中,则需要提供停止投票按钮 - 如果场次状态为已结束,则需要提供完成投票按钮 ### 评委管理功能 评委管理中包含如下功能: - 评委的增删改查、清空 - 删除功能要支持批量操作。在删除时可以选中所有评委、部分评委,清除选中的所有评委 - 查询功能要支持按条件分页查询,使用表格展示 - 可以根据评委的类型、状态进行查询,也可以根据姓名、邮箱进行模糊查询 ## 发起投票功能实现思路 首先由管理员在主页面点击发起投票按钮。前端向后端发送 Ajax 请求,并告知用户服务端的操作结果。在请求体中需要携带参数 "showSessionId",固定值为 "1"。 ### 验证码业务设计 后端需要单独定义一个处理验证码业务的接口,包含发送、校验、删除验证码的方法。定义邮件验证码的业务实现类。在该实现类中调用已有的邮件业务层对象发送验证码。这样设计,可以方便日后扩展短信验证码的业务。 关于验证码的接收者,参数命名上,不要使用 email、phone 这样的名称,可以使用 account 等更通用的名称。 ### 后端实现逻辑 后端需要实现如下逻辑: 1. 查询 id 为 1 的场次。如果查询结果为空,则不允许发起投票。 2. 检查场次状态,只有状态为未开始时才允许发起投票。 3. 获取所有未锁定的评委。如果查询结果为空,则不允许发起投票。 4. 更新场次状态为进行中。 5. 调用验证码的业务层对象,向所有未锁定的评委发送一封邮件,包含投票链接和验证码。 准确的说,这不是验证码,是授权码。但是为了保证后期扩展方便,就命名为验证码。 ### 投票链接设计 投票链接: ``` http://localhost/judge/vote/doVote.html?showSessionId=1 ``` ### 验证码设计 验证码由64位数字组成。这64位数字,由多个0至99的随机数构成,不可以为65位,也不可以为尾随机数。总之就是要让这个验证码没有任何规律,你也可以采用其它更高效、安全的方式实现。 之所以设计成超长验证码,是因为该验证码的有效时长非常的长,防止强行测试。而且这也只是一个小案例,不打算制定严格的安全措施。将来可以在配置文件中配置,每秒只处理一个请求(未实现)。 ### 验证码存储 要将验证码存储在 Redis 中,永久有效。验证码的 key,由固定前缀 + 评委的 id 组成。验证码 key 的前缀,要存储在邮件验证码的业务实现类中,定义为静态私有常量。 ## 投票统计功能实现思路 接下来请你帮我实现投票统计功能。专家组的分数占比为60%,大众组的分数占比为40%。表关系是这样的,投票表有评委 id,评委表中有类型,包含大众和专家。 需要展示前12个名次选手的信息,同一个名次可以有多个选手。需要展示它们的名次、编号、大众票、大众的分、专家票、专家的分、总票数、总的分。同一个名次可以有多个选手。 统计页已创建,不过内容是无效的,请你清空重写。页面的 css、js 要放在单独的文件中。在页面所在目录创建 css、js 子目录,存放该页面的样式、脚本文件。要保证页面的美观性。新创建的控制器,跟路径要以 "/common" 开头。选手的得票率在业务层中计算。 ## SQL 示例 我编写了一个示例 sql,可以查询每个选手的大众票数或专家票数。不过一个选手会对应两条记录,你可以对其进行优化,使得一个选手只对应一条记录。 ```sql SELECT player_code, count(type) FROM vote INNER JOIN judge ON vote.judge_id = judge.id GROUP BY vote.player_code, judge.type; ``` 如果不能优化,可以在 sql 中追加分组过滤条件,例如 "HAVING judge.type = 0;"。评委类型通过参数传递,这样写就需要查询两次。 下面这个 sql 可以查询大众评委或专家评委的总票数。评委类型也在参数中传递。 ```sql SELECT count(vote.id) FROM vote INNER JOIN judge ON vote.judge_id = judge.id GROUP BY judge.type HAVING judge.type = 0; ```