# API接口设计文档 ## 接口概述 本文档定义了武术评分系统需要对接的所有后端API接口。当前项目为前端原型,所有数据均为Mock数据,需要按照本文档定义的接口规范进行后端开发和对接。 ## 接口规范 ### 基础信息 - **协议**: HTTPS - **请求格式**: JSON - **响应格式**: JSON - **字符编码**: UTF-8 - **认证方式**: JWT Token ### 通用请求头 ``` Content-Type: application/json Authorization: Bearer {token} ``` ### 通用响应格式 ```json { "code": 200, // 状态码 "message": "成功", // 提示信息 "data": {} // 业务数据 } ``` ### 状态码说明 | 状态码 | 说明 | |-------|------| | 200 | 请求成功 | | 400 | 请求参数错误 | | 401 | 未授权/Token失效 | | 403 | 权限不足 | | 404 | 资源不存在 | | 500 | 服务器错误 | --- ## 一、认证模块 ### 1.1 用户登录 **接口地址**: `POST /api/auth/login` **功能描述**: 通过比赛编码和邀请码进行登录认证 **请求参数**: ```json { "matchCode": "string", // 比赛编码,必填 "inviteCode": "string" // 邀请码 (pub/admin),必填 } ``` **响应数据**: ```json { "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": "第一场地" // 场地名称 (普通评委) } } ``` **错误响应**: ```json { "code": 401, "message": "邀请码错误或已失效", "data": null } ``` ### 1.2 退出登录 **接口地址**: `POST /api/auth/logout` **功能描述**: 用户退出登录,清除Token **请求参数**: 无 **响应数据**: ```json { "code": 200, "message": "退出成功", "data": null } ``` ### 1.3 Token验证 **接口地址**: `GET /api/auth/verify` **功能描述**: 验证Token是否有效 **请求参数**: 无(通过Header传递Token) **响应数据**: ```json { "code": 200, "message": "Token有效", "data": { "valid": true, "expiresIn": 3600 // 剩余有效时间(秒) } } ``` --- ## 二、比赛信息模块 ### 2.1 获取比赛详情 **接口地址**: `GET /api/matches/{matchId}` **功能描述**: 获取指定比赛的详细信息 **路径参数**: - `matchId`: 比赛ID **响应数据**: ```json { "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,必填 ``` **响应数据**: ```json { "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,选填(裁判长查询所有场地时不传) ``` **响应数据**: ```json { "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 **响应数据**: ```json { "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,必填 ``` **响应数据**: ```json { "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,选填 ``` **响应数据**: ```json { "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 **响应数据**: ```json { "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` **功能描述**: 普通评委提交对选手的评分 **请求参数**: ```json { "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": "整体表现良好" // 备注,选填 } ``` **响应数据**: ```json { "code": 200, "message": "评分提交成功", "data": { "scoreId": "score_001", "athleteId": "athlete_001", "score": 8.907, "createTime": "2025-06-25T09:15:00", "totalScore": 8.905, // 当前总分(如果有多个评委) "judgeCount": 3 // 已评分评委数 } } ``` **错误响应**: ```json { "code": 400, "message": "该选手已评分,不可重复提交", "data": null } ``` ### 6.2 获取评分详情 **接口地址**: `GET /api/scores/{athleteId}` **功能描述**: 获取选手的所有评分详情(裁判长使用) **路径参数**: - `athleteId`: 选手ID **请求参数**: ``` judgeId: string // 评委ID,选填(普通评委只能看自己的评分) ``` **响应数据**: ```json { "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 **请求参数**: ```json { "modifierId": "admin_001", // 裁判长ID,必填 "originalScore": 8.907, // 原始分数,必填 "modifiedScore": 8.910, // 修改后的分数,必填 "note": "技术动作优秀,加分" // 修改原因,必填 } ``` **响应数据**: ```json { "code": 200, "message": "修改成功", "data": { "modifyId": "modify_001", "athleteId": "athlete_001", "originalScore": 8.907, "modifiedScore": 8.910, "modifyTime": "2025-06-25T10:00:00" } } ``` **错误响应**: ```json { "code": 403, "message": "只有裁判长可以修改评分", "data": null } ``` ### 6.4 获取我的评分记录 **接口地址**: `GET /api/scores/my-records` **功能描述**: 获取当前评委的所有评分记录 **请求参数**: ``` judgeId: string // 评委ID,必填 matchId: string // 比赛ID,必填 page: number // 页码,选填,默认1 pageSize: number // 每页数量,选填,默认20 ``` **响应数据**: ```json { "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,必填 ``` **响应数据**: ```json { "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 **响应数据**: ```json { "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,必填 ``` **响应数据**: ```json { "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 推送消息格式 #### 新评分推送 ```json { "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" } } ``` #### 评分修改推送 ```json { "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" } } ``` #### 选手状态更新 ```json { "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,必填 ``` **响应数据**: ```json { "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调用示例 ```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 ``` 建议在项目中创建环境配置文件: ```javascript // 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'] ```