# Tennis Training Hub - API接口文档 本文档详细描述了Tennis Training Hub的所有tRPC API接口,包括输入参数、输出格式和认证要求。 ## 认证说明 所有标记为 **需认证** 的接口需要用户已登录(通过Session Cookie)。未认证请求将返回 `UNAUTHORIZED` 错误。 ## 接口列表 ### 1. 认证模块 (`auth`) #### `auth.me` - 获取当前用户信息 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | 不需要 | | 输入 | 无 | | 输出 | `User | null` | 返回当前登录用户的完整信息,未登录返回 `null`。 #### `auth.loginWithUsername` - 用户名登录 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | 不需要 | | 输入 | `{ username: string }` | | 输出 | `{ user: User, isNew: boolean }` | **输入验证:** - `username`:1-64个字符 若用户名不存在则自动创建新账户。 #### `auth.logout` - 退出登录 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | 不需要 | | 输出 | `{ success: true }` | --- ### 2. 用户资料模块 (`profile`) #### `profile.stats` - 获取用户统计数据 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `UserStats` | #### `profile.update` - 更新用户资料 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ skillLevel?: "beginner" \| "intermediate" \| "advanced", trainingGoals?: string }` | | 输出 | `{ success: true }` | --- ### 3. 训练计划模块 (`plan`) #### `plan.generate` - AI生成训练计划 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ skillLevel: enum, durationDays: number, focusAreas?: string[] }` | | 输出 | `{ taskId: string, task: BackgroundTask }` | **输入验证:** - `skillLevel`:`"beginner"` / `"intermediate"` / `"advanced"` - `durationDays`:1-30 - `focusAreas`:可选,如 `["正手", "脚步"]` #### `plan.list` - 获取用户所有训练计划 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `TrainingPlan[]` | #### `plan.active` - 获取当前激活的训练计划 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `TrainingPlan | null` | #### `plan.adjust` - AI自动调整训练计划 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ planId: number }` | | 输出 | `{ taskId: string, task: BackgroundTask }` | --- ### 4. 视频管理模块 (`video`) #### `video.upload` - 上传训练视频 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ title: string, format: string, fileSize: number, fileBase64: string, exerciseType?: string }` | | 输出 | `{ videoId: number, url: string }` | #### `video.list` - 获取用户视频列表 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `TrainingVideo[]` | #### `video.get` - 获取视频详情 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ videoId: number }` | | 输出 | `TrainingVideo` | #### `video.updateStatus` - 更新视频分析状态 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ videoId: number, status: "pending" \| "analyzing" \| "completed" \| "failed" }` | | 输出 | `{ success: true }` | --- ### 5. 姿势分析模块 (`analysis`) #### `analysis.save` - 保存姿势分析结果 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | 见下表 | | 输出 | `{ analysisId: number }` | **输入参数:** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | videoId | number | 是 | 关联视频ID | | overallScore | number | 否 | 总体评分(0-100) | | poseMetrics | object | 否 | 关节角度等详细指标 | | detectedIssues | array | 否 | 检测到的问题列表 | | exerciseType | string | 否 | 动作类型 | | framesAnalyzed | number | 否 | 分析帧数 | | shotCount | number | 否 | 击球次数 | | avgSwingSpeed | number | 否 | 平均挥拍速度 | | maxSwingSpeed | number | 否 | 最大挥拍速度 | | totalMovementDistance | number | 否 | 总移动距离 | | strokeConsistency | number | 否 | 击球一致性(0-100) | | footworkScore | number | 否 | 脚步评分(0-100) | | fluidityScore | number | 否 | 流畅性评分(0-100) | | keyMoments | array | 否 | 关键时刻标记 | | movementTrajectory | array | 否 | 运动轨迹数据 | 保存分析结果后会自动触发NTRP评分重新计算。 #### `analysis.getCorrections` - AI生成矫正建议 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ poseMetrics: object, exerciseType: string, detectedIssues: array, imageUrls?: string[], imageDataUrls?: string[] }` | | 输出 | `{ taskId: string, task: BackgroundTask }` | 该接口始终走后台任务。若提供 `imageUrls` 或 `imageDataUrls`,服务端会优先走多模态纠正链路,并把相对地址规范化为可公网访问的绝对 URL。 #### `analysis.list` - 获取用户所有分析记录 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `PoseAnalysis[]` | #### `analysis.getByVideo` - 获取视频的分析结果 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ videoId: number }` | | 输出 | `PoseAnalysis | null` | --- ### 6. 训练记录模块 (`record`) ### 5.1 后台任务模块 (`task`) #### `task.list` - 获取当前用户后台任务 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ limit?: number }` | | 输出 | `BackgroundTask[]` | #### `task.get` - 获取单个后台任务 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ taskId: string }` | | 输出 | `BackgroundTask | null` | #### `task.retry` - 重试失败任务 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ taskId: string }` | | 输出 | `{ task: BackgroundTask }` | #### `task.createMediaFinalize` - 提交录制归档后台任务 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ sessionId: string, title: string, exerciseType?: string }` | | 输出 | `{ taskId: string, task: BackgroundTask }` | 该接口会校验媒体会话所属用户,并由后台 worker 轮询 Go 媒体服务状态,归档完成后自动登记到视频库。 ### 6. 训练记录模块 (`record`) #### `record.create` - 创建训练记录 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ exerciseName: string, planId?: number, durationMinutes?: number, notes?: string, poseScore?: number }` | | 输出 | `{ recordId: number }` | #### `record.complete` - 标记训练完成 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ recordId: number, poseScore?: number }` | | 输出 | `{ success: true }` | #### `record.list` - 获取训练记录列表 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ limit?: number }` (默认50) | | 输出 | `TrainingRecord[]` | --- ### 7. 评分模块 (`rating`) #### `rating.history` - 获取NTRP评分历史 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `RatingHistory[]` | #### `rating.current` - 获取当前NTRP评分 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `{ rating: number }` | --- ### 8. 打卡模块 (`checkin`) #### `checkin.today` - 获取今日打卡状态 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `DailyCheckin | null` | #### `checkin.do` - 执行打卡 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输入 | `{ notes?: string, minutesTrained?: number }` (可选) | | 输出 | `{ checkin: DailyCheckin, streak: number, newBadges: Badge[] }` | 打卡后会自动检查并授予新徽章。 #### `checkin.history` - 获取打卡历史 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ limit?: number }` (默认60) | | 输出 | `DailyCheckin[]` | --- ### 9. 徽章模块 (`badge`) #### `badge.list` - 获取用户徽章(含未获得) | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输出 | `BadgeWithStatus[]` | 返回所有24种徽章,标记已获得/未获得状态。 #### `badge.check` - 检查并授予新徽章 | 属性 | 值 | |------|-----| | 类型 | Mutation | | 认证 | **需认证** | | 输出 | `{ newBadges: Badge[] }` | #### `badge.definitions` - 获取所有徽章定义 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | 不需要 | | 输出 | `BadgeDefinition[]` | --- ### 10. 排行榜模块 (`leaderboard`) #### `leaderboard.get` - 获取排行榜 | 属性 | 值 | |------|-----| | 类型 | Query | | 认证 | **需认证** | | 输入 | `{ sortBy?: enum, limit?: number }` | | 输出 | `LeaderboardEntry[]` | **sortBy选项:** - `"ntrpRating"` - 按NTRP评分排名(默认) - `"totalMinutes"` - 按训练时长排名 - `"totalSessions"` - 按训练次数排名 - `"totalShots"` - 按击球数排名