完成内容: - 5个完整的UI页面(登录、评分列表、评分详情、多场地列表、修改评分) - 完整的Mock数据展示 - 完整的业务逻辑实现 - 文档体系建立(2000+行文档) 文档包含: - 项目概述.md - 页面功能说明.md - API接口设计.md (17个接口) - 数据结构设计.md (17个接口定义) - 功能模块划分.md - 后端实现对比报告.md - 数据可行性分析报告.md (95分评估) - 保护Mock版本的实施方案.md (4层保护机制) - API对接完成度检查报告.md 此版本为Mock原型版本,所有UI功能完整,数据为硬编码Mock数据。
1137 lines
26 KiB
Markdown
1137 lines
26 KiB
Markdown
# 数据结构设计文档
|
||
|
||
## 文档说明
|
||
|
||
本文档定义了武术评分系统中所有核心数据结构和数据模型。这些数据结构用于前端状态管理、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<T> {
|
||
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'
|
||
```
|