## 主要改动
### 1. 修复Mock数据格式问题
- 修复 mock/athlete.js 中 getProjects 函数
- 从字符串数组改为对象数组 { id, name }
- 确保Mock模式和API模式数据格式一致
### 2. 优化网络请求处理
- 优化 utils/request.js 的GET请求参数处理
- 参数自动URL编码
- 支持URL中已有查询参数的情况
- 代码逻辑更清晰
### 3. 新增完整的文档体系
- API对接说明.md - 项目根目录快速说明
- doc/API对接快速启动指南.md - 5分钟快速上手
- doc/后端接口开发清单.md - 后端开发规范(5个接口,6人天)
- doc/前端API对接指南.md - 前端联调指南
- doc/API对接准备完成报告.md - 项目状态总结
## 项目状态
✅ 前端准备完成度: 100%
- 架构设计优秀(dataAdapter适配器模式)
- 代码质量高(注释详细,结构清晰)
- Mock数据完整(可独立演示)
- API接口定义完整(9个接口)
- 页面全部接入(5个页面)
- 文档体系完善(20个文档)
⚠️ 后端待开发: 5个接口
- POST /api/mini/login
- GET /api/mini/athletes
- GET /api/mini/athletes/admin
- GET /api/mini/score/detail/{id}
- PUT /api/mini/score/modify
## 下一步
后端开发者可以参考 doc/后端接口开发清单.md 开始开发
预计工作量: 6人天(约1周)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
15 KiB
后端接口开发清单
项目: 武术评分系统小程序 前端项目: martial-admin-mini 后端框架: BladeX (Spring Boot + MyBatis Plus) 创建时间: 2025-12-12 状态: 待开发
📋 接口开发总览
接口统计
| 类型 | 数量 | 状态 |
|---|---|---|
| 需要新增的接口 | 5个 | ⚠️ 待开发 |
| 可以复用的接口 | 4个 | ✅ 已有 |
| 总计 | 9个 | 56% 待开发 |
开发优先级
| 优先级 | 接口数量 | 预计工作量 |
|---|---|---|
| 🔴 高优先级 | 2个 | 3天 |
| 🟡 中优先级 | 3个 | 3天 |
| 总计 | 5个 | 6人天 |
🔴 高优先级接口(必须先实现)
1. 登录验证接口
接口信息:
POST /api/mini/login
功能描述: 通过比赛编码和邀请码进行登录验证,返回Token和用户信息。
请求参数:
{
"matchCode": "123",
"inviteCode": "pub"
}
响应数据:
{
"code": 200,
"success": true,
"msg": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"userRole": "pub",
"matchId": "123",
"matchName": "2025年全国武术散打锦标赛暨第十七届世界武术锦标赛选拔赛",
"matchTime": "2025年6月25日 9:00",
"judgeId": "456",
"judgeName": "欧阳丽娜",
"venueId": "1",
"venueName": "第一场地",
"projects": ["女子组长拳", "男子组陈氏太极拳"]
}
}
实现逻辑:
- 验证
matchCode是否存在且有效 - 验证
inviteCode是否存在且未过期 - 查询
martial_judge_invite表获取评委信息 - 生成 JWT Token(使用 BladeX 的 Token 生成机制)
- 更新邀请码使用状态(
is_used=1,use_time=now()) - 返回用户信息和Token
SQL示例:
-- 验证邀请码
SELECT
ji.id,
ji.judge_id AS judgeId,
ji.role,
ji.venue_id AS venueId,
ji.projects,
j.judge_name AS judgeName,
c.id AS matchId,
c.competition_name AS matchName,
c.start_time AS matchTime,
v.venue_name AS venueName
FROM martial_judge_invite ji
LEFT JOIN martial_judge j ON ji.judge_id = j.id
LEFT JOIN martial_competition c ON ji.competition_id = c.id
LEFT JOIN martial_venue v ON ji.venue_id = v.id
WHERE ji.invite_code = #{inviteCode}
AND c.competition_code = #{matchCode}
AND ji.is_used = 0
AND ji.expire_time > NOW()
AND ji.is_deleted = 0
错误处理:
- 比赛编码不存在:
{ code: 400, msg: "比赛编码不存在" } - 邀请码错误:
{ code: 401, msg: "邀请码错误或已失效" } - 邀请码已使用:
{ code: 401, msg: "邀请码已被使用" } - 邀请码已过期:
{ code: 401, msg: "邀请码已过期" }
预计工作量: 2天
2. 获取评委的选手列表(普通评委)
接口信息:
GET /api/mini/athletes
功能描述: 获取当前评委分配的选手列表,包含评分状态。
请求参数:
judgeId=456&venueId=1&projectId=5
响应数据:
{
"code": 200,
"success": true,
"msg": "操作成功",
"data": [
{
"athleteId": "1",
"name": "张三",
"idCard": "123456789000000000",
"team": "少林寺武术大学院",
"number": "123-4567898275",
"myScore": 8.906,
"totalScore": 8.907,
"scored": true,
"scoreTime": "2025-06-25 09:15:00"
}
]
}
实现逻辑:
- 根据
venueId和projectId查询选手列表 - 左连接
martial_score表,获取当前评委的评分状态 - 按出场顺序排序
SQL示例:
SELECT
a.id AS athleteId,
a.player_name AS name,
a.id_card AS idCard,
a.team_name AS team,
a.player_no AS number,
a.total_score AS totalScore,
s.score AS myScore,
CASE WHEN s.id IS NOT NULL THEN 1 ELSE 0 END AS scored,
s.score_time AS scoreTime
FROM martial_athlete a
LEFT JOIN martial_score s
ON a.id = s.athlete_id
AND s.judge_id = #{judgeId}
WHERE a.venue_id = #{venueId}
AND a.project_id = #{projectId}
AND a.is_deleted = 0
ORDER BY a.order_num ASC
预计工作量: 1天
🟡 中优先级接口(核心功能)
3. 获取选手列表(裁判长)
接口信息:
GET /api/mini/athletes/admin
功能描述: 裁判长查看所有选手的评分统计情况。
请求参数:
competitionId=123&venueId=1&projectId=5
响应数据:
{
"code": 200,
"success": true,
"msg": "操作成功",
"data": [
{
"athleteId": "1",
"name": "张三",
"idCard": "123456789000000000",
"team": "少林寺武术大学院",
"number": "123-4567898275",
"totalScore": 8.907,
"judgeCount": 6,
"totalJudges": 6,
"canModify": true
}
]
}
实现逻辑:
- 查询选手列表
- 统计每个选手的评分人数
- 查询该项目的总评委数
- 判断是否可以修改(所有评委都已评分)
SQL示例:
SELECT
a.id AS athleteId,
a.player_name AS name,
a.id_card AS idCard,
a.team_name AS team,
a.player_no AS number,
a.total_score AS totalScore,
COUNT(s.id) AS judgeCount,
(SELECT COUNT(*) FROM martial_judge_project jp
WHERE jp.project_id = #{projectId} AND jp.is_deleted = 0) AS totalJudges,
CASE WHEN COUNT(s.id) = (SELECT COUNT(*) FROM martial_judge_project jp
WHERE jp.project_id = #{projectId} AND jp.is_deleted = 0) THEN 1 ELSE 0 END AS canModify
FROM martial_athlete a
LEFT JOIN martial_score s ON a.id = s.athlete_id
WHERE a.venue_id = #{venueId}
AND a.project_id = #{projectId}
AND a.is_deleted = 0
GROUP BY a.id
ORDER BY a.order_num ASC
预计工作量: 1天
4. 获取评分详情(裁判长查看)
接口信息:
GET /api/mini/score/detail/{athleteId}
功能描述: 裁判长查看某个选手的所有评委评分详情。
请求参数:
路径参数: athleteId=1
响应数据:
{
"code": 200,
"success": true,
"msg": "操作成功",
"data": {
"athleteInfo": {
"athleteId": "1",
"name": "张三",
"idCard": "123456789000000000",
"team": "少林寺武术大学院",
"number": "123-4567898275",
"totalScore": 8.907
},
"judgeScores": [
{
"judgeId": "1",
"judgeName": "欧阳丽娜",
"score": 8.907,
"scoreTime": "2025-06-25 09:15:00",
"note": ""
}
],
"modification": {
"originalScore": 8.907,
"modifiedScore": 8.910,
"modifyReason": "修改原因",
"modifyTime": "2025-06-25 10:00:00",
"modifierName": "裁判长"
}
}
}
实现逻辑:
- 查询选手基本信息
- 查询所有评委的评分记录
- 查询修改记录(如果有)
SQL示例:
-- 选手信息
SELECT
a.id AS athleteId,
a.player_name AS name,
a.id_card AS idCard,
a.team_name AS team,
a.player_no AS number,
a.total_score AS totalScore
FROM martial_athlete a
WHERE a.id = #{athleteId}
-- 评委评分
SELECT
s.judge_id AS judgeId,
s.judge_name AS judgeName,
s.score,
s.score_time AS scoreTime,
s.note
FROM martial_score s
WHERE s.athlete_id = #{athleteId}
ORDER BY s.score_time ASC
-- 修改记录(如果 original_score 不为空)
SELECT
s.original_score AS originalScore,
s.score AS modifiedScore,
s.modify_reason AS modifyReason,
s.modify_time AS modifyTime,
j.judge_name AS modifierName
FROM martial_score s
LEFT JOIN martial_judge j ON s.updated_by = j.id
WHERE s.athlete_id = #{athleteId}
AND s.original_score IS NOT NULL
LIMIT 1
预计工作量: 1天
5. 修改评分(裁判长)
接口信息:
PUT /api/mini/score/modify
功能描述: 裁判长修改选手的总分。
请求参数:
{
"athleteId": "1",
"modifierId": "789",
"modifiedScore": 8.910,
"note": "修改原因"
}
响应数据:
{
"code": 200,
"success": true,
"msg": "修改成功",
"data": {
"athleteId": "1",
"originalScore": 8.907,
"modifiedScore": 8.910,
"modifyTime": "2025-06-25 10:00:00"
}
}
实现逻辑:
- 验证权限(只有裁判长可以修改)
- 查询当前总分
- 如果是第一次修改,保存
original_score - 更新
total_score - 记录
modify_reason和modify_time - 更新
martial_athlete表的total_score
SQL示例:
-- 更新选手总分(第一次修改)
UPDATE martial_athlete
SET
total_score = #{modifiedScore},
updated_by = #{modifierId},
update_time = NOW()
WHERE id = #{athleteId}
-- 记录修改信息(可以在 martial_score 表中添加一条特殊记录)
-- 或者在 martial_athlete 表中添加字段记录修改历史
权限验证:
-- 验证是否为裁判长
SELECT role
FROM martial_judge_invite
WHERE judge_id = #{modifierId}
AND role = 'chief_judge'
AND is_deleted = 0
预计工作量: 1天
✅ 可以复用的现有接口
6. 获取场地列表
接口信息:
GET /martial/venue/list
状态: ✅ 后端已实现,可直接使用
请求参数:
competitionId=123¤t=1&size=100
响应格式:
{
"code": 200,
"success": true,
"msg": "操作成功",
"data": {
"records": [
{ "id": "1", "venueName": "第一场地" }
]
}
}
前端适配: 需要从 data.records 中提取数据
7. 获取项目列表
接口信息:
GET /martial/project/list
状态: ✅ 后端已实现,可直接使用
请求参数:
competitionId=123¤t=1&size=100
响应格式:
{
"code": 200,
"success": true,
"msg": "操作成功",
"data": {
"records": [
{ "id": "5", "projectName": "女子组长拳" }
]
}
}
前端适配: 需要从 data.records 中提取数据
8. 获取扣分项列表
接口信息:
GET /martial/deductionItem/list
状态: ✅ 后端已实现,可直接使用
请求参数:
projectId=5¤t=1&size=100
响应格式:
{
"code": 200,
"success": true,
"msg": "操作成功",
"data": {
"records": [
{
"id": "1",
"itemName": "动作不到位",
"deductionPoint": -0.1
}
]
}
}
前端适配: 需要从 data.records 中提取数据
9. 提交评分
接口信息:
POST /martial/score/submit
状态: ✅ 后端已实现,可直接使用
请求参数:
{
"athleteId": "1",
"judgeId": "456",
"score": 8.907,
"deductionItems": "[{\"id\":\"1\",\"text\":\"动作不到位\",\"score\":-0.1}]",
"note": "表现优秀"
}
响应格式:
{
"code": 200,
"success": true,
"msg": "提交成功",
"data": null
}
🔧 后端开发建议
1. 创建专用Controller
建议创建 MartialMiniController 来统一管理小程序接口:
package org.springblade.modules.martial.controller;
import org.springblade.core.tool.api.R;
import org.springframework.web.bind.annotation.*;
/**
* 武术评分系统 - 小程序专用接口
*/
@RestController
@RequestMapping("/api/mini")
public class MartialMiniController {
@PostMapping("/login")
public R<LoginVO> login(@RequestBody LoginDTO dto) {
// 实现登录逻辑
}
@GetMapping("/athletes")
public R<List<AthleteScoreVO>> getMyAthletes(
@RequestParam Long judgeId,
@RequestParam Long venueId,
@RequestParam Long projectId
) {
// 实现获取选手列表逻辑
}
@GetMapping("/athletes/admin")
public R<List<AthleteAdminVO>> getAthletesForAdmin(
@RequestParam Long competitionId,
@RequestParam Long venueId,
@RequestParam Long projectId
) {
// 实现裁判长选手列表逻辑
}
@GetMapping("/score/detail/{athleteId}")
public R<ScoreDetailVO> getScoreDetail(@PathVariable Long athleteId) {
// 实现评分详情逻辑
}
@PutMapping("/score/modify")
public R<ModifyResultVO> modifyScore(@RequestBody ModifyScoreDTO dto) {
// 实现修改评分逻辑
}
}
2. 创建专用VO类
// LoginVO.java
public class LoginVO {
private String token;
private String userRole;
private String matchId;
private String matchName;
private String matchTime;
private String judgeId;
private String judgeName;
private String venueId;
private String venueName;
private List<String> projects;
}
// AthleteScoreVO.java
public class AthleteScoreVO {
private String athleteId;
private String name;
private String idCard;
private String team;
private String number;
private BigDecimal myScore;
private BigDecimal totalScore;
private Boolean scored;
private String scoreTime;
}
// AthleteAdminVO.java
public class AthleteAdminVO {
private String athleteId;
private String name;
private String idCard;
private String team;
private String number;
private BigDecimal totalScore;
private Integer judgeCount;
private Integer totalJudges;
private Boolean canModify;
}
3. Token认证配置
确保使用 Blade-Auth 头部:
// 在拦截器中获取Token
String token = request.getHeader("Blade-Auth");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
// 验证Token
}
4. 响应格式统一
使用 BladeX 的标准响应格式:
// 成功
return R.success(data);
// 失败
return R.fail("错误信息");
// 自定义状态码
return R.status(401).msg("未授权").build();
📝 开发检查清单
后端开发
- 创建
MartialMiniController - 实现登录接口
POST /api/mini/login - 实现获取选手列表接口
GET /api/mini/athletes - 实现裁判长选手列表接口
GET /api/mini/athletes/admin - 实现评分详情接口
GET /api/mini/score/detail/{id} - 实现修改评分接口
PUT /api/mini/score/modify - 创建对应的VO类
- 编写单元测试
- 更新Swagger文档
数据准备
- 创建测试比赛数据
- 创建测试评委数据
- 生成邀请码(pub 和 admin)
- 创建测试选手数据
- 配置场地和项目数据
- 配置扣分项数据
联调测试
- 测试登录接口(pub角色)
- 测试登录接口(admin角色)
- 测试获取选手列表
- 测试提交评分
- 测试评分详情查看
- 测试修改评分
- 测试Token过期处理
- 测试权限验证
🎯 开发时间表
| 阶段 | 任务 | 工作量 | 负责人 | 状态 |
|---|---|---|---|---|
| 第1天 | 创建Controller和VO类 | 0.5天 | 后端 | ⚪ 待开始 |
| 第1-2天 | 实现登录接口 | 1.5天 | 后端 | ⚪ 待开始 |
| 第3天 | 实现选手列表接口(2个) | 1天 | 后端 | ⚪ 待开始 |
| 第4天 | 实现评分详情接口 | 1天 | 后端 | ⚪ 待开始 |
| 第5天 | 实现修改评分接口 | 1天 | 后端 | ⚪ 待开始 |
| 第6天 | 单元测试和文档 | 1天 | 后端 | ⚪ 待开始 |
| 第7天 | 前后端联调 | 1天 | 前后端 | ⚪ 待开始 |
总计: 7个工作日
📞 联系方式
如有问题,请联系:
- 前端负责人: [待填写]
- 后端负责人: [待填写]
- 项目经理: [待填写]
文档版本: v1.0 最后更新: 2025-12-12 下次更新: 开发完成后