Files
martial-admin-mini/doc/API接口设计.md
宅房 7bd197f4ac Mock版本完成 - UI冻结版本
完成内容:
- 5个完整的UI页面(登录、评分列表、评分详情、多场地列表、修改评分)
- 完整的Mock数据展示
- 完整的业务逻辑实现
- 文档体系建立(2000+行文档)

文档包含:
- 项目概述.md
- 页面功能说明.md
- API接口设计.md (17个接口)
- 数据结构设计.md (17个接口定义)
- 功能模块划分.md
- 后端实现对比报告.md
- 数据可行性分析报告.md (95分评估)
- 保护Mock版本的实施方案.md (4层保护机制)
- API对接完成度检查报告.md

此版本为Mock原型版本,所有UI功能完整,数据为硬编码Mock数据。
2025-12-11 13:22:19 +08:00

23 KiB
Raw Permalink Blame History

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']