比赛管理系统概述
比赛管理系统是辣评平台的核心业务模块,用于管理多届次的比赛、参赛资格认证、评分规则等。
系统目标
- 支持多届次比赛管理
- 实现灵活的资格认证机制
- 提供完整的规则配置功能
- 支持比赛数据统计
比赛届次管理
数据模型
// Competition 比赛模型
type Competition struct {
ID uint `gorm:"primaryKey"`
Number int `gorm:"uniqueIndex"` // 届次
Name string
Description string `gorm:"type:text"`
IsActive bool // 是否为当前活跃比赛
IsLocked bool // 是否已锁定
StartDate time.Time
EndDate time.Time
SubmissionStart time.Time // 投稿开始时间
SubmissionEnd time.Time // 投稿结束时间
CommentStart time.Time // 评论开始时间
CommentEnd time.Time // 评论结束时间
CreatedAt time.Time
UpdatedAt time.Time
}
// CompetitionRule 比赛规则模型
type CompetitionRule struct {
ID uint
CompetitionID uint `gorm:"index"`
RuleNumber int // 规则编号
RuleContent string `gorm:"type:longtext"`
RuleJson string `gorm:"type:text"` // JSON 格式规则
IsActive bool
CreatedAt time.Time
UpdatedAt time.Time
}
参赛资格认证逻辑
资格认证模型
// QualificationStatistics 资格统计模型
type QualificationStatistics struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"uniqueIndex:idx_user_competition"`
CompetitionID uint `gorm:"uniqueIndex:idx_user_competition"`
IsAuthor bool // 是否为作者
IsReader bool // 是否为读者
CommentCount int // 评论数
SubmissionCount int // 投稿数
QualifiedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
// AuthorQualification 作者资格认证
type AuthorQualification struct {
ID uint
UserID uint
CompetitionID uint
SubmissionCount int // 投稿数
IsQualified bool
QualifiedAt *time.Time
}
资格认证逻辑
// CheckAuthorQualification 检查作者资格
func (s *QualificationService) CheckAuthorQualification(ctx context.Context, userID, competitionID uint) (bool, error) {
// 1. 获取用户在该比赛的投稿数
var submissionCount int64
if err := s.db.Model(&Submission{}).
Where("user_id = ? AND competition_id = ?", userID, competitionID).
Count(&submissionCount).Error; err != nil {
return false, err
}
// 2. 获取比赛规则
rule, err := s.getCompetitionRule(ctx, competitionID)
if err != nil {
return false, err
}
// 3. 检查是否满足作者资格
requiredSubmissions := rule.RequiredSubmissions // 假设规则中定义了所需投稿数
isQualified := submissionCount >= int64(requiredSubmissions)
// 4. 更新资格统计
s.updateQualificationStatistics(ctx, userID, competitionID, isQualified, true)
return isQualified, nil
}
// CheckReaderQualification 检查读者资格
func (s *QualificationService) CheckReaderQualification(ctx context.Context, userID, competitionID uint) (bool, error) {
// 1. 获取用户在该比赛的评论数
var commentCount int64
if err := s.db.Model(&Comment{}).
Where("user_id = ? AND competition_id = ?", userID, competitionID).
Count(&commentCount).Error; err != nil {
return false, err
}
// 2. 获取比赛规则
rule, err := s.getCompetitionRule(ctx, competitionID)
if err != nil {
return false, err
}
// 3. 检查是否满足读者资格
requiredComments := rule.RequiredComments
isQualified := commentCount >= int64(requiredComments)
// 4. 更新资格统计
s.updateQualificationStatistics(ctx, userID, competitionID, isQualified, false)
return isQualified, nil
}
资格统计与展示
统计计算
// CalculateQualificationStatistics 计算资格统计
func (s *QualificationService) CalculateQualificationStatistics(ctx context.Context, competitionID uint) error {
// 1. 获取所有参与该比赛的用户
var users []User
if err := s.db.Distinct("user_id").
Model(&Comment{}).
Where("competition_id = ?", competitionID).
Scan(&users).Error; err != nil {
return err
}
// 2. 为每个用户计算资格
for _, user := range users {
authorQualified, _ := s.CheckAuthorQualification(ctx, user.ID, competitionID)
readerQualified, _ := s.CheckReaderQualification(ctx, user.ID, competitionID)
stats := &QualificationStatistics{
UserID: user.ID,
CompetitionID: competitionID,
IsAuthor: authorQualified,
IsReader: readerQualified,
}
s.db.Save(stats)
}
return nil
}
// GetQualificationStatus 获取资格状态
func (s *QualificationService) GetQualificationStatus(ctx context.Context, userID, competitionID uint) (*QualificationStatistics, error) {
stats := &QualificationStatistics{}
err := s.db.Where("user_id = ? AND competition_id = ?", userID, competitionID).
First(stats).Error
return stats, err
}
补评欠债管理
欠债模型
// DebtRecord 欠债记录模型
type DebtRecord struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"index"`
CompetitionID uint `gorm:"index"`
DebtCount int // 欠债数量
Status string // 状态:pending, completed, overdue
DueDate time.Time // 截止日期
CompletedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
// MakeupComment 补评记录
type MakeupComment struct {
ID uint
UserID uint
CompetitionID uint
DebtRecordID uint
SubmissionID uint
Content string `gorm:"type:text"`
Score int
CreatedAt time.Time
}
欠债处理
// CreateDebtRecord 创建欠债记录
func (s *DebtService) CreateDebtRecord(ctx context.Context, userID, competitionID uint, debtCount int) error {
dueDate := time.Now().AddDate(0, 0, 7) // 7天截止
record := &DebtRecord{
UserID: userID,
CompetitionID: competitionID,
DebtCount: debtCount,
Status: "pending",
DueDate: dueDate,
}
return s.db.Create(record).Error
}
// CompleteDebt 完成欠债
func (s *DebtService) CompleteDebt(ctx context.Context, debtRecordID uint) error {
now := time.Now()
return s.db.Model(&DebtRecord{}).
Where("id = ?", debtRecordID).
Updates(map[string]interface{}{
"status": "completed",
"completed_at": now,
}).Error
}
// CheckOverdueDebt 检查逾期欠债
func (s *DebtService) CheckOverdueDebt(ctx context.Context) error {
return s.db.Model(&DebtRecord{}).
Where("status = ? AND due_date < ?", "pending", time.Now()).
Update("status", "overdue").Error
}
规则配置系统
规则管理
// RuleConfig 规则配置结构
type RuleConfig struct {
RequiredSubmissions int // 作者所需投稿数
RequiredComments int // 读者所需评论数
MinCommentScore int // 最低评分
MaxDebtDays int // 欠债最多天数
DebtPenalty string // 欠债惩罚
}
// UpdateCompetitionRule 更新比赛规则
func (s *RuleService) UpdateCompetitionRule(ctx context.Context, competitionID uint, config *RuleConfig) error {
// 1. 序列化规则配置
ruleJson, err := json.Marshal(config)
if err != nil {
return err
}
// 2. 更新规则
rule := &CompetitionRule{
CompetitionID: competitionID,
RuleJson: string(ruleJson),
}
return s.db.Save(rule).Error
}
// GetCompetitionRule 获取比赛规则
func (s *RuleService) GetCompetitionRule(ctx context.Context, competitionID uint) (*RuleConfig, error) {
rule := &CompetitionRule{}
if err := s.db.Where("competition_id = ? AND is_active = ?", competitionID, true).
First(rule).Error; err != nil {
return nil, err
}
// 反序列化规则
config := &RuleConfig{}
if err := json.Unmarshal([]byte(rule.RuleJson), config); err != nil {
return nil, err
}
return config, nil
}
比赛数据统计
统计功能
// CompetitionStatistics 比赛统计
type CompetitionStatistics struct {
CompetitionID uint
TotalUsers int64
TotalSubmissions int64
TotalComments int64
QualifiedAuthors int64
QualifiedReaders int64
AverageScore float64
}
// GetCompetitionStatistics 获取比赛统计
func (s *StatisticsService) GetCompetitionStatistics(ctx context.Context, competitionID uint) (*CompetitionStatistics, error) {
stats := &CompetitionStatistics{
CompetitionID: competitionID,
}
// 统计用户数
s.db.Model(&User{}).
Joins("JOIN comments ON users.id = comments.user_id").
Where("comments.competition_id = ?", competitionID).
Distinct("users.id").
Count(&stats.TotalUsers)
// 统计投稿数
s.db.Model(&Submission{}).
Where("competition_id = ?", competitionID).
Count(&stats.TotalSubmissions)
// 统计评论数
s.db.Model(&Comment{}).
Where("competition_id = ?", competitionID).
Count(&stats.TotalComments)
// 统计资格用户
s.db.Model(&QualificationStatistics{}).
Where("competition_id = ? AND is_author = ?", competitionID, true).
Count(&stats.QualifiedAuthors)
s.db.Model(&QualificationStatistics{}).
Where("competition_id = ? AND is_reader = ?", competitionID, true).
Count(&stats.QualifiedReaders)
// 计算平均评分
s.db.Model(&Comment{}).
Where("competition_id = ?", competitionID).
Select("AVG(score)").
Row().
Scan(&stats.AverageScore)
return stats, nil
}
API 接口设计
创建比赛
POST /api/admin/competitions
{
"number": 1,
"name": "第一届比赛",
"start_date": "2024-01-01",
"end_date": "2024-12-31"
}
获取比赛列表
GET /api/competitions
检查资格
GET /api/competitions/{id}/qualification/check
获取比赛统计
GET /api/competitions/{id}/statistics
总结
比赛管理与资格认证系统为辣评平台提供了完整的比赛管理能力,确保了比赛的公平性和规范性。