Files
ssq-desk/internal/service/query_service.go
2026-01-14 14:17:38 +08:00

163 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"fmt"
"ssq-desk/internal/storage/models"
"ssq-desk/internal/storage/repository"
)
// QueryService 查询服务
type QueryService struct {
repo repository.SsqRepository
}
// NewQueryService 创建查询服务
func NewQueryService(repo repository.SsqRepository) *QueryService {
return &QueryService{repo: repo}
}
// QueryRequest 查询请求
type QueryRequest struct {
RedBalls []int `json:"red_balls"` // 红球列表最多6个
BlueBall int `json:"blue_ball"` // 蓝球0表示不限制
BlueBallRange []int `json:"blue_ball_range"` // 蓝球筛选范围
}
// QueryResult 查询结果
type QueryResult struct {
Total int64 `json:"total"` // 总记录数
Summary []MatchSummary `json:"summary"` // 分类统计
Details []models.SsqHistory `json:"details"` // 详细记录
}
// MatchSummary 匹配统计
type MatchSummary struct {
Type string `json:"type"` // 匹配类型:如 "6红1蓝"
Count int `json:"count"` // 匹配数量
Histories []models.SsqHistory `json:"histories"` // 匹配的记录
}
// Query 执行查询
func (s *QueryService) Query(req QueryRequest) (*QueryResult, error) {
// 验证输入
if err := s.validateRequest(req); err != nil {
return nil, err
}
// 查询数据
histories, err := s.repo.FindByRedAndBlue(req.RedBalls, req.BlueBall, req.BlueBallRange)
if err != nil {
return nil, fmt.Errorf("查询失败: %v", err)
}
// 处理结果:分类统计
summary := s.calculateSummary(histories, req.RedBalls, req.BlueBall)
return &QueryResult{
Total: int64(len(histories)),
Summary: summary,
Details: histories,
}, nil
}
// validateRequest 验证请求参数
func (s *QueryService) validateRequest(req QueryRequest) error {
// 验证红球
if len(req.RedBalls) > 6 {
return fmt.Errorf("红球数量不能超过6个")
}
for _, ball := range req.RedBalls {
if ball < 1 || ball > 33 {
return fmt.Errorf("红球号码必须在1-33之间: %d", ball)
}
}
// 验证蓝球
if req.BlueBall > 0 {
if req.BlueBall < 1 || req.BlueBall > 16 {
return fmt.Errorf("蓝球号码必须在1-16之间: %d", req.BlueBall)
}
}
// 验证蓝球范围
for _, ball := range req.BlueBallRange {
if ball < 1 || ball > 16 {
return fmt.Errorf("蓝球筛选范围必须在1-16之间: %d", ball)
}
}
return nil
}
// calculateSummary 计算分类统计
func (s *QueryService) calculateSummary(histories []models.SsqHistory, redBalls []int, blueBall int) []MatchSummary {
if len(redBalls) == 0 {
return []MatchSummary{}
}
// 创建红球集合,用于快速查找
redBallSet := make(map[int]bool)
for _, ball := range redBalls {
redBallSet[ball] = true
}
// 初始化统计
typeCounts := make(map[string][]models.SsqHistory)
// 遍历每条记录,计算匹配度
for _, history := range histories {
// 统计匹配的红球数量
matchedRedCount := 0
if redBallSet[history.RedBall1] {
matchedRedCount++
}
if redBallSet[history.RedBall2] {
matchedRedCount++
}
if redBallSet[history.RedBall3] {
matchedRedCount++
}
if redBallSet[history.RedBall4] {
matchedRedCount++
}
if redBallSet[history.RedBall5] {
matchedRedCount++
}
if redBallSet[history.RedBall6] {
matchedRedCount++
}
// 判断蓝球是否匹配
blueMatched := false
if blueBall > 0 {
blueMatched = history.BlueBall == blueBall
} else {
blueMatched = true // 未指定蓝球时,视为匹配
}
// 生成类型键
typeKey := fmt.Sprintf("%d红", matchedRedCount)
if blueMatched {
typeKey += "1蓝"
}
typeCounts[typeKey] = append(typeCounts[typeKey], history)
}
// 转换为结果格式,按匹配度排序
summary := make([]MatchSummary, 0)
types := []string{"6红1蓝", "6红", "5红1蓝", "5红", "4红1蓝", "4红", "3红1蓝", "3红", "2红1蓝", "2红", "1红1蓝", "1红", "0红1蓝", "0红"}
for _, t := range types {
if histories, ok := typeCounts[t]; ok {
summary = append(summary, MatchSummary{
Type: t,
Count: len(histories),
Histories: histories,
})
}
}
return summary
}