## 主要改动
### 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>
749 lines
15 KiB
Markdown
749 lines
15 KiB
Markdown
# 后端接口开发清单
|
||
|
||
> **项目**: 武术评分系统小程序
|
||
> **前端项目**: 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和用户信息。
|
||
|
||
**请求参数**:
|
||
```json
|
||
{
|
||
"matchCode": "123",
|
||
"inviteCode": "pub"
|
||
}
|
||
```
|
||
|
||
**响应数据**:
|
||
```json
|
||
{
|
||
"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": ["女子组长拳", "男子组陈氏太极拳"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**实现逻辑**:
|
||
1. 验证 `matchCode` 是否存在且有效
|
||
2. 验证 `inviteCode` 是否存在且未过期
|
||
3. 查询 `martial_judge_invite` 表获取评委信息
|
||
4. 生成 JWT Token(使用 BladeX 的 Token 生成机制)
|
||
5. 更新邀请码使用状态(`is_used=1`, `use_time=now()`)
|
||
6. 返回用户信息和Token
|
||
|
||
**SQL示例**:
|
||
```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
|
||
```
|
||
|
||
**响应数据**:
|
||
```json
|
||
{
|
||
"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"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**实现逻辑**:
|
||
1. 根据 `venueId` 和 `projectId` 查询选手列表
|
||
2. 左连接 `martial_score` 表,获取当前评委的评分状态
|
||
3. 按出场顺序排序
|
||
|
||
**SQL示例**:
|
||
```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
|
||
```
|
||
|
||
**响应数据**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"success": true,
|
||
"msg": "操作成功",
|
||
"data": [
|
||
{
|
||
"athleteId": "1",
|
||
"name": "张三",
|
||
"idCard": "123456789000000000",
|
||
"team": "少林寺武术大学院",
|
||
"number": "123-4567898275",
|
||
"totalScore": 8.907,
|
||
"judgeCount": 6,
|
||
"totalJudges": 6,
|
||
"canModify": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**实现逻辑**:
|
||
1. 查询选手列表
|
||
2. 统计每个选手的评分人数
|
||
3. 查询该项目的总评委数
|
||
4. 判断是否可以修改(所有评委都已评分)
|
||
|
||
**SQL示例**:
|
||
```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
|
||
```
|
||
|
||
**响应数据**:
|
||
```json
|
||
{
|
||
"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": "裁判长"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**实现逻辑**:
|
||
1. 查询选手基本信息
|
||
2. 查询所有评委的评分记录
|
||
3. 查询修改记录(如果有)
|
||
|
||
**SQL示例**:
|
||
```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
|
||
```
|
||
|
||
**功能描述**:
|
||
裁判长修改选手的总分。
|
||
|
||
**请求参数**:
|
||
```json
|
||
{
|
||
"athleteId": "1",
|
||
"modifierId": "789",
|
||
"modifiedScore": 8.910,
|
||
"note": "修改原因"
|
||
}
|
||
```
|
||
|
||
**响应数据**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"success": true,
|
||
"msg": "修改成功",
|
||
"data": {
|
||
"athleteId": "1",
|
||
"originalScore": 8.907,
|
||
"modifiedScore": 8.910,
|
||
"modifyTime": "2025-06-25 10:00:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
**实现逻辑**:
|
||
1. 验证权限(只有裁判长可以修改)
|
||
2. 查询当前总分
|
||
3. 如果是第一次修改,保存 `original_score`
|
||
4. 更新 `total_score`
|
||
5. 记录 `modify_reason` 和 `modify_time`
|
||
6. 更新 `martial_athlete` 表的 `total_score`
|
||
|
||
**SQL示例**:
|
||
```sql
|
||
-- 更新选手总分(第一次修改)
|
||
UPDATE martial_athlete
|
||
SET
|
||
total_score = #{modifiedScore},
|
||
updated_by = #{modifierId},
|
||
update_time = NOW()
|
||
WHERE id = #{athleteId}
|
||
|
||
-- 记录修改信息(可以在 martial_score 表中添加一条特殊记录)
|
||
-- 或者在 martial_athlete 表中添加字段记录修改历史
|
||
```
|
||
|
||
**权限验证**:
|
||
```sql
|
||
-- 验证是否为裁判长
|
||
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
|
||
```
|
||
|
||
**响应格式**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"success": true,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"records": [
|
||
{ "id": "1", "venueName": "第一场地" }
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端适配**: 需要从 `data.records` 中提取数据
|
||
|
||
---
|
||
|
||
### 7. 获取项目列表
|
||
|
||
**接口信息**:
|
||
```
|
||
GET /martial/project/list
|
||
```
|
||
|
||
**状态**: ✅ 后端已实现,可直接使用
|
||
|
||
**请求参数**:
|
||
```
|
||
competitionId=123¤t=1&size=100
|
||
```
|
||
|
||
**响应格式**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"success": true,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"records": [
|
||
{ "id": "5", "projectName": "女子组长拳" }
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端适配**: 需要从 `data.records` 中提取数据
|
||
|
||
---
|
||
|
||
### 8. 获取扣分项列表
|
||
|
||
**接口信息**:
|
||
```
|
||
GET /martial/deductionItem/list
|
||
```
|
||
|
||
**状态**: ✅ 后端已实现,可直接使用
|
||
|
||
**请求参数**:
|
||
```
|
||
projectId=5¤t=1&size=100
|
||
```
|
||
|
||
**响应格式**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"success": true,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"records": [
|
||
{
|
||
"id": "1",
|
||
"itemName": "动作不到位",
|
||
"deductionPoint": -0.1
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端适配**: 需要从 `data.records` 中提取数据
|
||
|
||
---
|
||
|
||
### 9. 提交评分
|
||
|
||
**接口信息**:
|
||
```
|
||
POST /martial/score/submit
|
||
```
|
||
|
||
**状态**: ✅ 后端已实现,可直接使用
|
||
|
||
**请求参数**:
|
||
```json
|
||
{
|
||
"athleteId": "1",
|
||
"judgeId": "456",
|
||
"score": 8.907,
|
||
"deductionItems": "[{\"id\":\"1\",\"text\":\"动作不到位\",\"score\":-0.1}]",
|
||
"note": "表现优秀"
|
||
}
|
||
```
|
||
|
||
**响应格式**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"success": true,
|
||
"msg": "提交成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 后端开发建议
|
||
|
||
### 1. 创建专用Controller
|
||
|
||
建议创建 `MartialMiniController` 来统一管理小程序接口:
|
||
|
||
```java
|
||
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类
|
||
|
||
```java
|
||
// 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` 头部:
|
||
|
||
```java
|
||
// 在拦截器中获取Token
|
||
String token = request.getHeader("Blade-Auth");
|
||
if (token != null && token.startsWith("Bearer ")) {
|
||
token = token.substring(7);
|
||
// 验证Token
|
||
}
|
||
```
|
||
|
||
### 4. 响应格式统一
|
||
|
||
使用 BladeX 的标准响应格式:
|
||
|
||
```java
|
||
// 成功
|
||
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
|
||
**下次更新**: 开发完成后
|