完成内容: - 5个完整的UI页面(登录、评分列表、评分详情、多场地列表、修改评分) - 完整的Mock数据展示 - 完整的业务逻辑实现 - 文档体系建立(2000+行文档) 文档包含: - 项目概述.md - 页面功能说明.md - API接口设计.md (17个接口) - 数据结构设计.md (17个接口定义) - 功能模块划分.md - 后端实现对比报告.md - 数据可行性分析报告.md (95分评估) - 保护Mock版本的实施方案.md (4层保护机制) - API对接完成度检查报告.md 此版本为Mock原型版本,所有UI功能完整,数据为硬编码Mock数据。
23 KiB
API接口设计文档
接口概述
本文档定义了武术评分系统需要对接的所有后端API接口。当前项目为前端原型,所有数据均为Mock数据,需要按照本文档定义的接口规范进行后端开发和对接。
接口规范
基础信息
- 协议: HTTPS
- 请求格式: JSON
- 响应格式: JSON
- 字符编码: UTF-8
- 认证方式: JWT Token
通用请求头
Content-Type: application/json
Authorization: Bearer {token}
通用响应格式
{
"code": 200, // 状态码
"message": "成功", // 提示信息
"data": {} // 业务数据
}
状态码说明
| 状态码 | 说明 |
|---|---|
| 200 | 请求成功 |
| 400 | 请求参数错误 |
| 401 | 未授权/Token失效 |
| 403 | 权限不足 |
| 404 | 资源不存在 |
| 500 | 服务器错误 |
一、认证模块
1.1 用户登录
接口地址: POST /api/auth/login
功能描述: 通过比赛编码和邀请码进行登录认证
请求参数:
{
"matchCode": "string", // 比赛编码,必填
"inviteCode": "string" // 邀请码 (pub/admin),必填
}
响应数据:
{
"code": 200,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", // JWT Token
"userRole": "pub", // 用户角色: pub-普通评委, admin-裁判长
"matchId": "match_001", // 比赛ID
"matchName": "2025年全国武术散打锦标赛", // 比赛名称
"matchTime": "2025-06-25T09:00:00", // 比赛时间
"judgeId": "judge_001", // 评委ID
"judgeName": "张三", // 评委姓名
"venueId": "venue_001", // 场地ID (普通评委)
"venueName": "第一场地" // 场地名称 (普通评委)
}
}
错误响应:
{
"code": 401,
"message": "邀请码错误或已失效",
"data": null
}
1.2 退出登录
接口地址: POST /api/auth/logout
功能描述: 用户退出登录,清除Token
请求参数: 无
响应数据:
{
"code": 200,
"message": "退出成功",
"data": null
}
1.3 Token验证
接口地址: GET /api/auth/verify
功能描述: 验证Token是否有效
请求参数: 无(通过Header传递Token)
响应数据:
{
"code": 200,
"message": "Token有效",
"data": {
"valid": true,
"expiresIn": 3600 // 剩余有效时间(秒)
}
}
二、比赛信息模块
2.1 获取比赛详情
接口地址: GET /api/matches/{matchId}
功能描述: 获取指定比赛的详细信息
路径参数:
matchId: 比赛ID
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"matchId": "match_001",
"matchName": "2025年全国武术散打锦标赛暨第十七届世界武术锦标赛选拔赛",
"matchTime": "2025-06-25T09:00:00",
"matchEndTime": "2025-06-25T18:00:00",
"location": "北京体育馆",
"status": "ongoing", // ongoing-进行中, finished-已结束, upcoming-未开始
"description": "比赛说明",
"venueCount": 5, // 场地数量
"projectCount": 8, // 项目数量
"athleteCount": 150 // 参赛选手数量
}
}
三、场地管理模块
3.1 获取场地列表
接口地址: GET /api/venues
功能描述: 获取比赛的所有场地列表(裁判长专用)
请求参数:
matchId: string // 比赛ID,必填
响应数据:
{
"code": 200,
"message": "成功",
"data": [
{
"venueId": "venue_001",
"venueName": "第一场地",
"order": 1, // 排序顺序
"athleteCount": 30, // 选手数量
"scoredCount": 25, // 已评分数量
"status": "active" // active-进行中, completed-已完成
},
{
"venueId": "venue_002",
"venueName": "第二场地",
"order": 2,
"athleteCount": 30,
"scoredCount": 28,
"status": "active"
}
]
}
四、项目管理模块
4.1 获取项目列表
接口地址: GET /api/projects
功能描述: 获取比赛的所有项目列表
请求参数:
matchId: string // 比赛ID,必填
venueId: string // 场地ID,选填(裁判长查询所有场地时不传)
响应数据:
{
"code": 200,
"message": "成功",
"data": [
{
"projectId": "project_001",
"projectName": "女子组长拳",
"category": "套路", // 项目类别
"order": 1, // 排序顺序
"athleteCount": 15, // 参赛选手数
"minScore": 5.0, // 最低分
"maxScore": 10.0, // 最高分
"status": "ongoing" // ongoing-进行中, completed-已完成
},
{
"projectId": "project_002",
"projectName": "男子组陈氏太极拳",
"category": "太极拳",
"order": 2,
"athleteCount": 20,
"minScore": 5.0,
"maxScore": 10.0,
"status": "ongoing"
}
]
}
4.2 获取项目详情
接口地址: GET /api/projects/{projectId}
功能描述: 获取指定项目的详细信息
路径参数:
projectId: 项目ID
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"projectId": "project_001",
"projectName": "女子组长拳",
"category": "套路",
"description": "项目说明",
"rules": "评分规则",
"minScore": 5.0,
"maxScore": 10.0,
"scoreStep": 0.001, // 评分步进值
"athleteCount": 15,
"deductions": [ // 扣分项列表
{
"deductionId": "deduction_001",
"text": "起势不稳",
"score": -0.1
}
]
}
}
五、选手管理模块
5.1 获取选手列表(普通评委)
接口地址: GET /api/athletes
功能描述: 普通评委获取分配给自己的选手列表
请求参数:
matchId: string // 比赛ID,必填
venueId: string // 场地ID,必填
projectId: string // 项目ID,必填
judgeId: string // 评委ID,必填
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"total": 30, // 总选手数
"scored": 25, // 已评分数
"unscored": 5, // 未评分数
"athletes": [
{
"athleteId": "athlete_001",
"name": "张三",
"gender": "male", // male-男, female-女
"idCard": "123456789000000000",
"team": "少林寺武术大学院",
"number": "123-4567898275", // 比赛编号
"order": 1, // 出场顺序
"myScore": 8.906, // 我的评分(已评分时有值)
"totalScore": 8.907, // 总分(已评分时有值)
"scored": true, // 是否已评分
"scoreTime": "2025-06-25T09:15:00", // 评分时间
"status": "finished" // waiting-等待, performing-表演中, finished-完成
},
{
"athleteId": "athlete_002",
"name": "李四",
"gender": "male",
"idCard": "123456789000000001",
"team": "武当山武术学院",
"number": "123-4567898276",
"order": 2,
"myScore": null,
"totalScore": null,
"scored": false,
"scoreTime": null,
"status": "waiting"
}
]
}
}
5.2 获取选手列表(裁判长)
接口地址: GET /api/athletes/all
功能描述: 裁判长获取所有场地和项目的选手列表
请求参数:
matchId: string // 比赛ID,必填
venueId: string // 场地ID,选填
projectId: string // 项目ID,选填
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"total": 150,
"scored": 120,
"athletes": [
{
"athleteId": "athlete_001",
"name": "张三",
"gender": "male",
"idCard": "123456789000000000",
"team": "少林寺武术大学院",
"number": "123-4567898275",
"order": 1,
"venueId": "venue_001",
"venueName": "第一场地",
"projectId": "project_001",
"projectName": "女子组长拳",
"totalScore": 8.907, // 总分
"judgeCount": 6, // 评分评委数
"totalJudges": 6, // 总评委数
"canModify": true, // 是否可修改
"status": "finished"
}
]
}
}
5.3 获取选手详情
接口地址: GET /api/athletes/{athleteId}
功能描述: 获取选手详细信息
路径参数:
athleteId: 选手ID
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"athleteId": "athlete_001",
"name": "张三",
"gender": "male",
"age": 25,
"idCard": "123456789000000000",
"team": "少林寺武术大学院",
"number": "123-4567898275",
"order": 1,
"projectId": "project_001",
"projectName": "女子组长拳",
"venueId": "venue_001",
"venueName": "第一场地",
"photo": "https://example.com/photo.jpg", // 选手照片URL
"defaultScore": 8.907, // 默认起评分
"status": "finished"
}
}
六、评分管理模块
6.1 提交评分
接口地址: POST /api/scores
功能描述: 普通评委提交对选手的评分
请求参数:
{
"matchId": "match_001", // 比赛ID,必填
"athleteId": "athlete_001", // 选手ID,必填
"judgeId": "judge_001", // 评委ID,必填
"projectId": "project_001", // 项目ID,必填
"venueId": "venue_001", // 场地ID,必填
"score": 8.907, // 评分,必填
"deductions": [ // 扣分项ID列表,选填
"deduction_001",
"deduction_003"
],
"note": "整体表现良好" // 备注,选填
}
响应数据:
{
"code": 200,
"message": "评分提交成功",
"data": {
"scoreId": "score_001",
"athleteId": "athlete_001",
"score": 8.907,
"createTime": "2025-06-25T09:15:00",
"totalScore": 8.905, // 当前总分(如果有多个评委)
"judgeCount": 3 // 已评分评委数
}
}
错误响应:
{
"code": 400,
"message": "该选手已评分,不可重复提交",
"data": null
}
6.2 获取评分详情
接口地址: GET /api/scores/{athleteId}
功能描述: 获取选手的所有评分详情(裁判长使用)
路径参数:
athleteId: 选手ID
请求参数:
judgeId: string // 评委ID,选填(普通评委只能看自己的评分)
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"athleteId": "athlete_001",
"athleteName": "张三",
"team": "少林寺武术大学院",
"number": "123-4567898275",
"projectName": "女子组长拳",
"totalScore": 8.907,
"judgeCount": 6,
"totalJudges": 6,
"judgeScores": [
{
"scoreId": "score_001",
"judgeId": "judge_001",
"judgeName": "欧阳丽娜",
"score": 8.907,
"deductions": [
{
"deductionId": "deduction_001",
"text": "起势不稳",
"score": -0.1
}
],
"note": "整体表现良好",
"scoreTime": "2025-06-25T09:15:00"
},
{
"scoreId": "score_002",
"judgeId": "judge_002",
"judgeName": "张三",
"score": 8.901,
"deductions": [],
"note": "",
"scoreTime": "2025-06-25T09:16:00"
}
],
"modifications": [
{
"modifyId": "modify_001",
"modifierId": "admin_001",
"modifierName": "总裁判长",
"originalScore": 8.907,
"modifiedScore": 8.910,
"note": "技术动作优秀,加分",
"modifyTime": "2025-06-25T10:00:00"
}
]
}
}
6.3 修改评分(裁判长)
接口地址: PUT /api/scores/{athleteId}/modify
功能描述: 裁判长修改选手的总分
路径参数:
athleteId: 选手ID
请求参数:
{
"modifierId": "admin_001", // 裁判长ID,必填
"originalScore": 8.907, // 原始分数,必填
"modifiedScore": 8.910, // 修改后的分数,必填
"note": "技术动作优秀,加分" // 修改原因,必填
}
响应数据:
{
"code": 200,
"message": "修改成功",
"data": {
"modifyId": "modify_001",
"athleteId": "athlete_001",
"originalScore": 8.907,
"modifiedScore": 8.910,
"modifyTime": "2025-06-25T10:00:00"
}
}
错误响应:
{
"code": 403,
"message": "只有裁判长可以修改评分",
"data": null
}
6.4 获取我的评分记录
接口地址: GET /api/scores/my-records
功能描述: 获取当前评委的所有评分记录
请求参数:
judgeId: string // 评委ID,必填
matchId: string // 比赛ID,必填
page: number // 页码,选填,默认1
pageSize: number // 每页数量,选填,默认20
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"total": 25,
"page": 1,
"pageSize": 20,
"records": [
{
"scoreId": "score_001",
"athleteId": "athlete_001",
"athleteName": "张三",
"team": "少林寺武术大学院",
"projectName": "女子组长拳",
"score": 8.907,
"scoreTime": "2025-06-25T09:15:00"
}
]
}
}
七、扣分项管理模块
7.1 获取扣分项列表
接口地址: GET /api/deductions
功能描述: 获取指定项目的扣分项列表
请求参数:
projectId: string // 项目ID,必填
响应数据:
{
"code": 200,
"message": "成功",
"data": [
{
"deductionId": "deduction_001",
"text": "起势不稳",
"score": -0.1,
"category": "基础动作",
"order": 1
},
{
"deductionId": "deduction_002",
"text": "节奏不准",
"score": -0.05,
"category": "节奏控制",
"order": 2
},
{
"deductionId": "deduction_003",
"text": "力度不足",
"score": -0.1,
"category": "技术要求",
"order": 3
}
]
}
八、统计分析模块
8.1 获取比赛统计
接口地址: GET /api/statistics/match/{matchId}
功能描述: 获取比赛的整体统计数据(裁判长专用)
路径参数:
matchId: 比赛ID
响应数据:
{
"code": 200,
"message": "成功",
"data": {
"matchId": "match_001",
"totalAthletes": 150, // 总选手数
"finishedAthletes": 120, // 已完成评分选手数
"totalJudges": 30, // 总评委数
"activeJudges": 28, // 活跃评委数
"totalScores": 720, // 总评分数
"averageScore": 8.756, // 平均分
"highestScore": 9.850, // 最高分
"lowestScore": 7.200, // 最低分
"venueStats": [ // 各场地统计
{
"venueId": "venue_001",
"venueName": "第一场地",
"athleteCount": 30,
"finishedCount": 28,
"progress": 93.3
}
],
"projectStats": [ // 各项目统计
{
"projectId": "project_001",
"projectName": "女子组长拳",
"athleteCount": 15,
"finishedCount": 15,
"averageScore": 8.650,
"progress": 100
}
]
}
}
8.2 获取评委统计
接口地址: GET /api/statistics/judges
功能描述: 获取所有评委的评分统计(裁判长专用)
请求参数:
matchId: string // 比赛ID,必填
响应数据:
{
"code": 200,
"message": "成功",
"data": [
{
"judgeId": "judge_001",
"judgeName": "欧阳丽娜",
"role": "pub",
"venueId": "venue_001",
"venueName": "第一场地",
"totalScores": 25, // 总评分数
"averageScore": 8.765, // 平均给分
"highestScore": 9.500, // 最高给分
"lowestScore": 7.800, // 最低给分
"lastScoreTime": "2025-06-25T15:30:00" // 最后评分时间
}
]
}
九、实时推送模块(可选)
9.1 WebSocket连接
连接地址: wss://api.example.com/ws
认证方式: URL参数传递Token
wss://api.example.com/ws?token={jwt_token}
功能描述: 建立WebSocket连接,接收实时评分更新
9.2 推送消息格式
新评分推送
{
"type": "new_score",
"data": {
"athleteId": "athlete_001",
"athleteName": "张三",
"judgeId": "judge_001",
"judgeName": "欧阳丽娜",
"score": 8.907,
"totalScore": 8.905,
"judgeCount": 3,
"timestamp": "2025-06-25T09:15:00"
}
}
评分修改推送
{
"type": "score_modified",
"data": {
"athleteId": "athlete_001",
"athleteName": "张三",
"modifierId": "admin_001",
"modifierName": "总裁判长",
"originalScore": 8.907,
"modifiedScore": 8.910,
"note": "技术动作优秀,加分",
"timestamp": "2025-06-25T10:00:00"
}
}
选手状态更新
{
"type": "athlete_status",
"data": {
"athleteId": "athlete_001",
"athleteName": "张三",
"status": "performing", // waiting-等待, performing-表演中, finished-完成
"timestamp": "2025-06-25T09:10:00"
}
}
十、文件上传模块(扩展)
10.1 上传选手照片
接口地址: POST /api/upload/photo
功能描述: 上传选手照片
请求格式: multipart/form-data
请求参数:
file: File // 图片文件,必填
athleteId: string // 选手ID,必填
响应数据:
{
"code": 200,
"message": "上传成功",
"data": {
"fileId": "file_001",
"fileName": "athlete_photo.jpg",
"fileUrl": "https://example.com/photos/athlete_photo.jpg",
"fileSize": 102400,
"uploadTime": "2025-06-25T08:00:00"
}
}
接口调用示例
JavaScript调用示例
// 1. 登录
const login = async (matchCode, inviteCode) => {
try {
const response = await uni.request({
url: 'https://api.example.com/api/auth/login',
method: 'POST',
data: {
matchCode,
inviteCode
}
})
if (response.data.code === 200) {
// 保存Token
uni.setStorageSync('token', response.data.data.token)
uni.setStorageSync('userInfo', response.data.data)
return response.data.data
}
} catch (error) {
console.error('登录失败:', error)
throw error
}
}
// 2. 获取选手列表
const getAthletes = async (matchId, venueId, projectId, judgeId) => {
const token = uni.getStorageSync('token')
try {
const response = await uni.request({
url: 'https://api.example.com/api/athletes',
method: 'GET',
header: {
'Authorization': `Bearer ${token}`
},
data: {
matchId,
venueId,
projectId,
judgeId
}
})
return response.data.data
} catch (error) {
console.error('获取选手列表失败:', error)
throw error
}
}
// 3. 提交评分
const submitScore = async (scoreData) => {
const token = uni.getStorageSync('token')
try {
const response = await uni.request({
url: 'https://api.example.com/api/scores',
method: 'POST',
header: {
'Authorization': `Bearer ${token}`
},
data: scoreData
})
if (response.data.code === 200) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
return response.data.data
}
} catch (error) {
console.error('提交评分失败:', error)
uni.showToast({
title: '提交失败',
icon: 'none'
})
throw error
}
}
// 4. 修改评分(裁判长)
const modifyScore = async (athleteId, modifyData) => {
const token = uni.getStorageSync('token')
try {
const response = await uni.request({
url: `https://api.example.com/api/scores/${athleteId}/modify`,
method: 'PUT',
header: {
'Authorization': `Bearer ${token}`
},
data: modifyData
})
if (response.data.code === 200) {
uni.showToast({
title: '修改成功',
icon: 'success'
})
return response.data.data
}
} catch (error) {
console.error('修改评分失败:', error)
uni.showToast({
title: '修改失败',
icon: 'none'
})
throw error
}
}
接口安全建议
1. 认证安全
- 使用HTTPS协议
- JWT Token设置合理过期时间(建议8小时)
- Token应包含用户角色信息
- 实现Token刷新机制
2. 权限控制
- 普通评委只能访问自己的数据
- 裁判长可以访问所有数据
- 每个接口都需要验证用户权限
3. 数据验证
- 后端必须验证所有输入参数
- 评分范围必须在5.0-10.0之间
- 评分精度必须为0.001
- 防止重复提交评分
4. 日志记录
- 记录所有评分操作
- 记录所有修改操作
- 记录登录和登出
- 保留操作时间戳
5. 错误处理
- 统一错误响应格式
- 不暴露敏感信息
- 提供友好的错误提示
接口性能优化建议
1. 缓存策略
- 比赛信息、场地列表、项目列表可缓存
- 扣分项列表可缓存
- 选手列表需要实时更新
2. 分页查询
- 选手列表支持分页
- 评分记录支持分页
- 统计数据可按需加载
3. 数据压缩
- 使用Gzip压缩响应数据
- 图片使用CDN加速
4. 并发控制
- 限制单个评委的评分频率
- 防止恶意刷接口
- 实现请求限流
接口测试建议
1. 单元测试
- 测试所有接口的正常流程
- 测试各种异常情况
- 测试权限验证
2. 压力测试
- 模拟多评委同时评分
- 测试并发修改评分
- 测试WebSocket连接数
3. 集成测试
- 测试完整的评分流程
- 测试跨模块的数据一致性
附录:环境配置
开发环境
BASE_URL: https://dev-api.example.com
测试环境
BASE_URL: https://test-api.example.com
生产环境
BASE_URL: https://api.example.com
建议在项目中创建环境配置文件:
// config/env.js
const env = {
development: {
baseUrl: 'https://dev-api.example.com',
timeout: 10000
},
production: {
baseUrl: 'https://api.example.com',
timeout: 5000
}
}
export default env[process.env.NODE_ENV || 'development']