# 数据结构设计文档 ## 文档说明 本文档定义了武术评分系统中所有核心数据结构和数据模型。这些数据结构用于前端状态管理、API请求响应、以及数据库设计参考。 --- ## 一、用户角色相关 ### 1.1 用户信息 (UserInfo) ```typescript interface UserInfo { userId: string // 用户ID username: string // 用户名 realName: string // 真实姓名 role: 'pub' | 'admin' // 角色: pub-普通评委, admin-裁判长 phone?: string // 手机号 email?: string // 邮箱 avatar?: string // 头像URL status: 'active' | 'inactive' // 状态 createdAt: string // 创建时间 (ISO 8601) updatedAt: string // 更新时间 (ISO 8601) } ``` **示例**: ```json { "userId": "user_001", "username": "judge001", "realName": "欧阳丽娜", "role": "pub", "phone": "13800138000", "email": "judge001@example.com", "avatar": "https://example.com/avatar.jpg", "status": "active", "createdAt": "2025-01-01T00:00:00Z", "updatedAt": "2025-06-25T08:00:00Z" } ``` ### 1.2 登录凭证 (LoginCredentials) ```typescript interface LoginCredentials { matchCode: string // 比赛编码 inviteCode: string // 邀请码 } ``` ### 1.3 认证响应 (AuthResponse) ```typescript interface AuthResponse { token: string // JWT Token userRole: 'pub' | 'admin' // 用户角色 matchId: string // 比赛ID matchName: string // 比赛名称 matchTime: string // 比赛时间 judgeId: string // 评委ID judgeName: string // 评委姓名 venueId?: string // 场地ID (普通评委) venueName?: string // 场地名称 (普通评委) } ``` --- ## 二、比赛相关 ### 2.1 比赛信息 (Match) ```typescript interface Match { matchId: string // 比赛ID matchName: string // 比赛名称 matchTime: string // 比赛开始时间 (ISO 8601) matchEndTime: string // 比赛结束时间 (ISO 8601) location: string // 比赛地点 status: MatchStatus // 比赛状态 description?: string // 比赛说明 venueCount: number // 场地数量 projectCount: number // 项目数量 athleteCount: number // 选手总数 judgeCount: number // 评委总数 createdAt: string // 创建时间 updatedAt: string // 更新时间 } type MatchStatus = 'upcoming' | 'ongoing' | 'finished' ``` **示例**: ```json { "matchId": "match_001", "matchName": "2025年全国武术散打锦标赛暨第十七届世界武术锦标赛选拔赛", "matchTime": "2025-06-25T09:00:00Z", "matchEndTime": "2025-06-25T18:00:00Z", "location": "北京体育馆", "status": "ongoing", "description": "全国性武术比赛", "venueCount": 5, "projectCount": 8, "athleteCount": 150, "judgeCount": 30, "createdAt": "2025-01-01T00:00:00Z", "updatedAt": "2025-06-25T08:00:00Z" } ``` --- ## 三、场地相关 ### 3.1 场地信息 (Venue) ```typescript interface Venue { venueId: string // 场地ID venueName: string // 场地名称 matchId: string // 所属比赛ID order: number // 排序顺序 athleteCount: number // 选手数量 scoredCount: number // 已评分数量 status: VenueStatus // 场地状态 description?: string // 场地描述 createdAt: string // 创建时间 } type VenueStatus = 'active' | 'completed' | 'paused' ``` **示例**: ```json { "venueId": "venue_001", "venueName": "第一场地", "matchId": "match_001", "order": 1, "athleteCount": 30, "scoredCount": 25, "status": "active", "description": "主场地", "createdAt": "2025-01-01T00:00:00Z" } ``` ### 3.2 场地列表 (VenueList) ```typescript type VenueList = Venue[] ``` --- ## 四、项目相关 ### 4.1 项目信息 (Project) ```typescript interface Project { projectId: string // 项目ID projectName: string // 项目名称 matchId: string // 所属比赛ID category: string // 项目类别 (如: 套路、太极拳) order: number // 排序顺序 athleteCount: number // 参赛选手数 minScore: number // 最低分 maxScore: number // 最高分 scoreStep: number // 评分步进值 status: ProjectStatus // 项目状态 description?: string // 项目说明 rules?: string // 评分规则 createdAt: string // 创建时间 } type ProjectStatus = 'upcoming' | 'ongoing' | 'completed' ``` **示例**: ```json { "projectId": "project_001", "projectName": "女子组长拳", "matchId": "match_001", "category": "套路", "order": 1, "athleteCount": 15, "minScore": 5.0, "maxScore": 10.0, "scoreStep": 0.001, "status": "ongoing", "description": "女子组长拳套路比赛", "rules": "按照国家标准执行", "createdAt": "2025-01-01T00:00:00Z" } ``` ### 4.2 项目列表 ```typescript type ProjectList = Project[] ``` **前端Mock数据**: ```javascript const projectList = [ '女子组长拳', '男子组陈氏太极拳', '女子组双剑(含长穗双剑)', '男子组杨氏太极拳', '女子组刀术', '男子组棍术', '女子组枪术', '男子组剑术' ] ``` --- ## 五、选手相关 ### 5.1 选手信息 (Athlete) ```typescript interface Athlete { athleteId: string // 选手ID name: string // 姓名 gender: 'male' | 'female' // 性别 age?: number // 年龄 idCard: string // 身份证号 team: string // 队伍/单位 number: string // 比赛编号 order: number // 出场顺序 projectId: string // 参赛项目ID projectName: string // 参赛项目名称 venueId: string // 比赛场地ID venueName: string // 比赛场地名称 matchId: string // 比赛ID photo?: string // 照片URL defaultScore?: number // 默认起评分 status: AthleteStatus // 选手状态 createdAt: string // 创建时间 } type AthleteStatus = 'waiting' | 'performing' | 'finished' ``` **示例**: ```json { "athleteId": "athlete_001", "name": "张三", "gender": "male", "age": 25, "idCard": "123456789000000000", "team": "少林寺武术大学院", "number": "123-4567898275", "order": 1, "projectId": "project_001", "projectName": "女子组长拳", "venueId": "venue_001", "venueName": "第一场地", "matchId": "match_001", "photo": "https://example.com/athlete.jpg", "defaultScore": 8.907, "status": "finished", "createdAt": "2025-01-01T00:00:00Z" } ``` ### 5.2 选手列表项(普通评委视图) ```typescript interface AthleteListItem { athleteId: string // 选手ID name: string // 姓名 gender: 'male' | 'female' // 性别 idCard: string // 身份证号 team: string // 队伍 number: string // 比赛编号 order: number // 出场顺序 myScore?: number // 我的评分 totalScore?: number // 总分 scored: boolean // 是否已评分 scoreTime?: string // 评分时间 status: AthleteStatus // 状态 } ``` **示例**: ```json { "athleteId": "athlete_001", "name": "张三", "gender": "male", "idCard": "123456789000000000", "team": "少林寺武术大学院", "number": "123-4567898275", "order": 1, "myScore": 8.906, "totalScore": 8.907, "scored": true, "scoreTime": "2025-06-25T09:15:00Z", "status": "finished" } ``` ### 5.3 选手列表项(裁判长视图) ```typescript interface AthleteListItemAdmin { athleteId: string // 选手ID name: string // 姓名 gender: 'male' | 'female' // 性别 idCard: string // 身份证号 team: string // 队伍 number: string // 比赛编号 order: number // 出场顺序 venueId: string // 场地ID venueName: string // 场地名称 projectId: string // 项目ID projectName: string // 项目名称 totalScore?: number // 总分 judgeCount: number // 已评分评委数 totalJudges: number // 总评委数 canModify: boolean // 是否可修改 status: AthleteStatus // 状态 } ``` **示例**: ```json { "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" } ``` --- ## 六、评分相关 ### 6.1 评分提交数据 (ScoreSubmit) ```typescript interface ScoreSubmit { matchId: string // 比赛ID athleteId: string // 选手ID judgeId: string // 评委ID projectId: string // 项目ID venueId: string // 场地ID score: number // 评分 (5.000 - 10.000) deductions: string[] // 扣分项ID列表 note?: string // 备注 } ``` **示例**: ```json { "matchId": "match_001", "athleteId": "athlete_001", "judgeId": "judge_001", "projectId": "project_001", "venueId": "venue_001", "score": 8.907, "deductions": ["deduction_001", "deduction_003"], "note": "整体表现良好" } ``` ### 6.2 评分记录 (Score) ```typescript interface Score { scoreId: string // 评分ID matchId: string // 比赛ID athleteId: string // 选手ID judgeId: string // 评委ID projectId: string // 项目ID venueId: string // 场地ID score: number // 评分 deductions: Deduction[] // 扣分项详情 note?: string // 备注 scoreTime: string // 评分时间 (ISO 8601) createdAt: string // 创建时间 updatedAt: string // 更新时间 } ``` **示例**: ```json { "scoreId": "score_001", "matchId": "match_001", "athleteId": "athlete_001", "judgeId": "judge_001", "projectId": "project_001", "venueId": "venue_001", "score": 8.907, "deductions": [ { "deductionId": "deduction_001", "text": "起势不稳", "score": -0.1 } ], "note": "整体表现良好", "scoreTime": "2025-06-25T09:15:00Z", "createdAt": "2025-06-25T09:15:00Z", "updatedAt": "2025-06-25T09:15:00Z" } ``` ### 6.3 评委评分项(显示用) ```typescript interface JudgeScore { scoreId: string // 评分ID judgeId: string // 评委ID judgeName: string // 评委姓名 score: number // 评分 deductions: Deduction[] // 扣分项 note?: string // 备注 scoreTime: string // 评分时间 } ``` **示例**: ```json { "scoreId": "score_001", "judgeId": "judge_001", "judgeName": "欧阳丽娜", "score": 8.907, "deductions": [ { "deductionId": "deduction_001", "text": "起势不稳", "score": -0.1 } ], "note": "整体表现良好", "scoreTime": "2025-06-25T09:15:00Z" } ``` ### 6.4 选手评分详情 (AthleteScoreDetail) ```typescript interface AthleteScoreDetail { athleteId: string // 选手ID athleteName: string // 选手姓名 team: string // 队伍 number: string // 比赛编号 projectName: string // 项目名称 totalScore: number // 总分 judgeCount: number // 已评分评委数 totalJudges: number // 总评委数 judgeScores: JudgeScore[] // 各评委评分 modifications: ScoreModification[] // 修改记录 } ``` **示例**: ```json { "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": [], "note": "表现良好", "scoreTime": "2025-06-25T09:15:00Z" } ], "modifications": [] } ``` --- ## 七、评分修改相关 ### 7.1 评分修改提交 (ScoreModifySubmit) ```typescript interface ScoreModifySubmit { athleteId: string // 选手ID modifierId: string // 修改人ID (裁判长) originalScore: number // 原始分数 modifiedScore: number // 修改后的分数 note: string // 修改原因 } ``` **示例**: ```json { "athleteId": "athlete_001", "modifierId": "admin_001", "originalScore": 8.907, "modifiedScore": 8.910, "note": "技术动作优秀,加分" } ``` ### 7.2 评分修改记录 (ScoreModification) ```typescript interface ScoreModification { modifyId: string // 修改记录ID athleteId: string // 选手ID modifierId: string // 修改人ID modifierName: string // 修改人姓名 originalScore: number // 原始分数 modifiedScore: number // 修改后的分数 note: string // 修改原因 modifyTime: string // 修改时间 (ISO 8601) createdAt: string // 创建时间 } ``` **示例**: ```json { "modifyId": "modify_001", "athleteId": "athlete_001", "modifierId": "admin_001", "modifierName": "总裁判长", "originalScore": 8.907, "modifiedScore": 8.910, "note": "技术动作优秀,加分", "modifyTime": "2025-06-25T10:00:00Z", "createdAt": "2025-06-25T10:00:00Z" } ``` --- ## 八、扣分项相关 ### 8.1 扣分项 (Deduction) ```typescript interface Deduction { deductionId: string // 扣分项ID projectId: string // 所属项目ID text: string // 扣分项描述 score: number // 扣分值 (负数) category?: string // 分类 order: number // 排序 createdAt: string // 创建时间 } ``` **示例**: ```json { "deductionId": "deduction_001", "projectId": "project_001", "text": "起势不稳", "score": -0.1, "category": "基础动作", "order": 1, "createdAt": "2025-01-01T00:00:00Z" } ``` ### 8.2 扣分项选择(前端用) ```typescript interface DeductionItem { deductionId?: string // 扣分项ID (对接后端后使用) text: string // 扣分项描述 checked: boolean // 是否选中 } ``` **前端Mock数据**: ```javascript const deductions = [ { text: '扣分项描述', checked: false }, { text: '扣分项描述', checked: false }, { text: '扣分项描述', checked: true }, { text: '扣分项描述', checked: false }, { text: '扣分项描述', checked: false }, { text: '扣分项描述', checked: true }, { text: '扣分项描述', checked: true }, { text: '扣分项描述', checked: false } ] ``` --- ## 九、统计分析相关 ### 9.1 比赛统计 (MatchStatistics) ```typescript interface MatchStatistics { matchId: string // 比赛ID totalAthletes: number // 总选手数 finishedAthletes: number // 已完成评分选手数 totalJudges: number // 总评委数 activeJudges: number // 活跃评委数 totalScores: number // 总评分数 averageScore: number // 平均分 highestScore: number // 最高分 lowestScore: number // 最低分 venueStats: VenueStatistics[] // 各场地统计 projectStats: ProjectStatistics[] // 各项目统计 } ``` ### 9.2 场地统计 (VenueStatistics) ```typescript interface VenueStatistics { venueId: string // 场地ID venueName: string // 场地名称 athleteCount: number // 选手数 finishedCount: number // 已完成数 progress: number // 进度百分比 } ``` **示例**: ```json { "venueId": "venue_001", "venueName": "第一场地", "athleteCount": 30, "finishedCount": 28, "progress": 93.3 } ``` ### 9.3 项目统计 (ProjectStatistics) ```typescript interface ProjectStatistics { projectId: string // 项目ID projectName: string // 项目名称 athleteCount: number // 选手数 finishedCount: number // 已完成数 averageScore: number // 平均分 progress: number // 进度百分比 } ``` **示例**: ```json { "projectId": "project_001", "projectName": "女子组长拳", "athleteCount": 15, "finishedCount": 15, "averageScore": 8.650, "progress": 100 } ``` ### 9.4 评委统计 (JudgeStatistics) ```typescript interface JudgeStatistics { judgeId: string // 评委ID judgeName: string // 评委姓名 role: 'pub' | 'admin' // 角色 venueId?: string // 场地ID venueName?: string // 场地名称 totalScores: number // 总评分数 averageScore: number // 平均给分 highestScore: number // 最高给分 lowestScore: number // 最低给分 lastScoreTime: string // 最后评分时间 } ``` **示例**: ```json { "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:00Z" } ``` --- ## 十、前端页面数据结构 ### 10.1 登录页数据 (LoginPageData) ```typescript interface LoginPageData { matchCode: string // 比赛编码 inviteCode: string // 邀请码 } ``` ### 10.2 评分列表页数据 (ScoreListPageData) ```typescript interface ScoreListPageData { matchInfo: { title: string // 比赛标题 time: string // 比赛时间 } venue: string // 场地名称 project: string // 项目名称 scoreStats: { scored: number // 已评分数 total: number // 总数 } players: AthleteListItem[] // 选手列表 } ``` ### 10.3 评分详情页数据 (ScoreDetailPageData) ```typescript interface ScoreDetailPageData { athleteId: string // 选手ID athleteInfo: { name: string // 姓名 idCard: string // 身份证号 team: string // 队伍 number: string // 编号 } currentScore: number // 当前评分 note: string // 备注 minScore: number // 最低分 maxScore: number // 最高分 deductions: DeductionItem[] // 扣分项 } ``` ### 10.4 多场地列表页数据 (ScoreListMultiPageData) ```typescript interface ScoreListMultiPageData { currentVenue: number // 当前场地ID currentProject: number // 当前项目索引 venues: Venue[] // 场地列表 projects: string[] // 项目列表 scoreStats: { scored: number // 已评分数 total: number // 总数 } players: AthleteListItemAdmin[] // 选手列表 } ``` ### 10.5 修改评分页数据 (ModifyScorePageData) ```typescript interface ModifyScorePageData { athleteId: string // 选手ID athleteInfo: { name: string // 姓名 idCard: string // 身份证号 team: string // 队伍 number: string // 编号 } originalScore: number // 原始总分 currentScore: number // 修改后的分数 note: string // 修改备注 minScore: number // 最低分 maxScore: number // 最高分 judgeScores: JudgeScore[] // 评委评分列表 } ``` --- ## 十一、全局数据结构 ### 11.1 全局数据 (GlobalData) ```typescript interface GlobalData { userRole: 'pub' | 'admin' // 用户角色 matchCode: string // 比赛编码 token?: string // JWT Token userInfo?: UserInfo // 用户信息 matchInfo?: Match // 比赛信息 } ``` **使用方式**: ```javascript // 设置全局数据 getApp().globalData = { userRole: 'pub', matchCode: 'MATCH2025001' } // 获取全局数据 const globalData = getApp().globalData const userRole = globalData.userRole ``` --- ## 十二、WebSocket推送数据结构 ### 12.1 新评分推送 ```typescript interface NewScoreMessage { type: 'new_score' data: { athleteId: string athleteName: string judgeId: string judgeName: string score: number totalScore: number judgeCount: number timestamp: string } } ``` ### 12.2 评分修改推送 ```typescript interface ScoreModifiedMessage { type: 'score_modified' data: { athleteId: string athleteName: string modifierId: string modifierName: string originalScore: number modifiedScore: number note: string timestamp: string } } ``` ### 12.3 选手状态更新推送 ```typescript interface AthleteStatusMessage { type: 'athlete_status' data: { athleteId: string athleteName: string status: AthleteStatus timestamp: string } } ``` --- ## 十三、分页数据结构 ### 13.1 分页请求参数 (PageRequest) ```typescript interface PageRequest { page: number // 页码(从1开始) pageSize: number // 每页数量 sortBy?: string // 排序字段 sortOrder?: 'asc' | 'desc' // 排序方向 } ``` ### 13.2 分页响应数据 (PageResponse) ```typescript interface PageResponse { total: number // 总记录数 page: number // 当前页码 pageSize: number // 每页数量 totalPages: number // 总页数 records: T[] // 数据列表 } ``` **示例**: ```json { "total": 150, "page": 1, "pageSize": 20, "totalPages": 8, "records": [ { "athleteId": "athlete_001", "name": "张三" } ] } ``` --- ## 十四、数据验证规则 ### 14.1 评分验证 ```typescript interface ScoreValidation { min: 5.000 // 最低分 max: 10.000 // 最高分 step: 0.001 // 步进值 precision: 3 // 小数位数 } ``` **验证函数**: ```javascript function validateScore(score) { return score >= 5.000 && score <= 10.000 && /^\d+\.\d{3}$/.test(score.toFixed(3)) } ``` ### 14.2 必填字段验证 ```typescript // 登录验证 const loginRequired = ['matchCode', 'inviteCode'] // 评分提交验证 const scoreSubmitRequired = [ 'matchId', 'athleteId', 'judgeId', 'projectId', 'venueId', 'score' ] // 评分修改验证 const scoreModifyRequired = [ 'athleteId', 'modifierId', 'originalScore', 'modifiedScore', 'note' ] ``` --- ## 十五、枚举类型汇总 ```typescript // 用户角色 enum UserRole { PUB = 'pub', // 普通评委 ADMIN = 'admin' // 裁判长 } // 比赛状态 enum MatchStatus { UPCOMING = 'upcoming', // 未开始 ONGOING = 'ongoing', // 进行中 FINISHED = 'finished' // 已结束 } // 场地状态 enum VenueStatus { ACTIVE = 'active', // 进行中 COMPLETED = 'completed', // 已完成 PAUSED = 'paused' // 暂停 } // 项目状态 enum ProjectStatus { UPCOMING = 'upcoming', // 未开始 ONGOING = 'ongoing', // 进行中 COMPLETED = 'completed' // 已完成 } // 选手状态 enum AthleteStatus { WAITING = 'waiting', // 等待中 PERFORMING = 'performing', // 表演中 FINISHED = 'finished' // 已完成 } // 用户状态 enum UserStatus { ACTIVE = 'active', // 激活 INACTIVE = 'inactive' // 停用 } // 性别 enum Gender { MALE = 'male', // 男 FEMALE = 'female' // 女 } ``` --- ## 十六、数据关系图 ``` Match (比赛) │ ├─→ Venue (场地) [1:N] │ │ │ └─→ Athlete (选手) [1:N] │ ├─→ Project (项目) [1:N] │ │ │ ├─→ Athlete (选手) [1:N] │ │ │ └─→ Deduction (扣分项) [1:N] │ ├─→ Judge (评委) [1:N] │ │ │ └─→ Score (评分) [1:N] │ └─→ Athlete (选手) [1:N] │ ├─→ Score (评分) [1:N] │ │ │ └─→ ScoreModification (修改记录) [1:N] │ └─→ ScoreModification (修改记录) [1:N] ``` --- ## 十七、数据存储建议 ### 17.1 前端本地存储 ```javascript // 使用 uni.setStorageSync 存储 const storageKeys = { TOKEN: 'auth_token', USER_INFO: 'user_info', MATCH_INFO: 'match_info', CACHE_VENUES: 'cache_venues', CACHE_PROJECTS: 'cache_projects' } // 存储Token uni.setStorageSync(storageKeys.TOKEN, token) // 获取Token const token = uni.getStorageSync(storageKeys.TOKEN) // 清除所有缓存 uni.clearStorageSync() ``` ### 17.2 数据缓存策略 ```typescript interface CacheStrategy { key: string // 缓存键 ttl: number // 过期时间(秒) refresh: boolean // 是否需要刷新 } const cacheConfig = { matchInfo: { key: 'match', ttl: 3600, refresh: false }, venues: { key: 'venues', ttl: 1800, refresh: false }, projects: { key: 'projects', ttl: 1800, refresh: false }, athletes: { key: 'athletes', ttl: 60, refresh: true } } ``` --- ## 附录:TypeScript类型定义文件 建议创建 `types/index.d.ts` 文件,集中管理所有类型定义: ```typescript // types/index.d.ts // 导出所有接口 export * from './user' export * from './match' export * from './venue' export * from './project' export * from './athlete' export * from './score' export * from './deduction' export * from './statistics' ``` 这样可以在项目中统一导入使用: ```typescript import { UserInfo, Match, Athlete, Score } from '@/types' ```