This commit is contained in:
2026-01-14 14:17:38 +08:00
commit f1e2ff6563
126 changed files with 13636 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
package models
import "time"
// Authorization 授权信息
type Authorization struct {
ID int `gorm:"primaryKey" json:"id"` // 主键ID
LicenseCode string `gorm:"type:varchar(100);not null;uniqueIndex" json:"license_code"` // 授权码(唯一)
DeviceID string `gorm:"type:varchar(100);not null;index" json:"device_id"` // 设备IDMD5哈希
ActivatedAt time.Time `gorm:"not null" json:"activated_at"` // 激活时间
ExpiresAt *time.Time `gorm:"type:datetime" json:"expires_at"` // 过期时间可选nil表示永不过期
Status int `gorm:"type:tinyint;not null;default:1" json:"status"` // 状态1:有效 0:无效)
CreatedAt time.Time `gorm:"autoCreateTime:false" json:"created_at"` // 创建时间(由程序设置)
UpdatedAt time.Time `gorm:"autoUpdateTime:false" json:"updated_at"` // 更新时间(由程序设置)
}
// TableName 指定表名
func (Authorization) TableName() string {
return "sys_authorization_code"
}

View File

@@ -0,0 +1,24 @@
package models
import "time"
// SsqHistory 双色球历史开奖数据
type SsqHistory struct {
ID int `gorm:"primaryKey;column:id" json:"id"`
IssueNumber string `gorm:"type:varchar(20);not null;index;column:issue_number" json:"issue_number"`
OpenDate *time.Time `gorm:"type:date;column:open_date" json:"open_date"`
RedBall1 int `gorm:"type:tinyint;not null;column:red_ball_1" json:"red_ball_1"`
RedBall2 int `gorm:"type:tinyint;not null;column:red_ball_2" json:"red_ball_2"`
RedBall3 int `gorm:"type:tinyint;not null;column:red_ball_3" json:"red_ball_3"`
RedBall4 int `gorm:"type:tinyint;not null;column:red_ball_4" json:"red_ball_4"`
RedBall5 int `gorm:"type:tinyint;not null;column:red_ball_5" json:"red_ball_5"`
RedBall6 int `gorm:"type:tinyint;not null;column:red_ball_6" json:"red_ball_6"`
BlueBall int `gorm:"type:tinyint;not null;column:blue_ball" json:"blue_ball"`
CreatedAt time.Time `gorm:"autoCreateTime:false;column:created_at" json:"created_at"` // 创建时间(由程序设置)
UpdatedAt time.Time `gorm:"autoUpdateTime:false;column:updated_at" json:"updated_at"` // 更新时间(由程序设置)
}
// TableName 指定表名
func (SsqHistory) TableName() string {
return "ssq_history"
}

View File

@@ -0,0 +1,20 @@
package models
import "time"
// Version 版本信息
type Version struct {
ID int `gorm:"primaryKey" json:"id"` // 主键ID
Version string `gorm:"type:varchar(20);not null;uniqueIndex" json:"version"` // 版本号语义化版本如1.0.0
DownloadURL string `gorm:"type:varchar(500)" json:"download_url"` // 下载地址更新包下载URL
Changelog string `gorm:"type:text" json:"changelog"` // 更新日志Markdown格式
ForceUpdate int `gorm:"type:tinyint;not null;default:0" json:"force_update"` // 是否强制更新1:是 0:否)
ReleaseDate *time.Time `gorm:"type:date" json:"release_date"` // 发布日期
CreatedAt time.Time `gorm:"autoCreateTime:false" json:"created_at"` // 创建时间(由程序设置)
UpdatedAt time.Time `gorm:"autoUpdateTime:false" json:"updated_at"` // 更新时间(由程序设置)
}
// TableName 指定表名
func (Version) TableName() string {
return "sys_version"
}

View File

@@ -0,0 +1,76 @@
package repository
import (
"ssq-desk/internal/database"
"ssq-desk/internal/storage/models"
"time"
"gorm.io/gorm"
)
// AuthRepository 授权数据访问接口
type AuthRepository interface {
Create(auth *models.Authorization) error
Update(auth *models.Authorization) error
GetByLicenseCode(licenseCode string) (*models.Authorization, error)
GetByDeviceID(deviceID string) (*models.Authorization, error)
}
// SQLiteAuthRepository SQLite 授权数据访问实现
type SQLiteAuthRepository struct {
db *gorm.DB
}
// NewSQLiteAuthRepository 创建 SQLite 授权数据访问实例
func NewSQLiteAuthRepository() (AuthRepository, error) {
db := database.GetSQLite()
if db == nil {
return nil, gorm.ErrInvalidDB
}
// 自动迁移
err := db.AutoMigrate(&models.Authorization{})
if err != nil {
return nil, err
}
return &SQLiteAuthRepository{db: db}, nil
}
// Create 创建授权记录
func (r *SQLiteAuthRepository) Create(auth *models.Authorization) error {
now := time.Now()
if auth.CreatedAt.IsZero() {
auth.CreatedAt = now
}
if auth.UpdatedAt.IsZero() {
auth.UpdatedAt = now
}
return r.db.Create(auth).Error
}
// Update 更新授权记录
func (r *SQLiteAuthRepository) Update(auth *models.Authorization) error {
auth.UpdatedAt = time.Now()
return r.db.Save(auth).Error
}
// GetByLicenseCode 根据授权码查询
func (r *SQLiteAuthRepository) GetByLicenseCode(licenseCode string) (*models.Authorization, error) {
var auth models.Authorization
err := r.db.Where("license_code = ?", licenseCode).First(&auth).Error
if err != nil {
return nil, err
}
return &auth, nil
}
// GetByDeviceID 根据设备ID查询
func (r *SQLiteAuthRepository) GetByDeviceID(deviceID string) (*models.Authorization, error) {
var auth models.Authorization
err := r.db.Where("device_id = ? AND status = ?", deviceID, 1).First(&auth).Error
if err != nil {
return nil, err
}
return &auth, nil
}

View File

@@ -0,0 +1,128 @@
package repository
import (
"gorm.io/gorm"
"ssq-desk/internal/database"
"ssq-desk/internal/storage/models"
"time"
)
// MySQLSsqRepository MySQL 实现
type MySQLSsqRepository struct {
db *gorm.DB
}
// NewMySQLSsqRepository 创建 MySQL 仓库
func NewMySQLSsqRepository() (SsqRepository, error) {
db := database.GetMySQL()
if db == nil {
return nil, gorm.ErrInvalidDB
}
return &MySQLSsqRepository{db: db}, nil
}
// FindAll 查询所有历史数据
func (r *MySQLSsqRepository) FindAll() ([]models.SsqHistory, error) {
var histories []models.SsqHistory
err := r.db.Order("issue_number DESC").Find(&histories).Error
return histories, err
}
// FindByIssue 根据期号查询
func (r *MySQLSsqRepository) FindByIssue(issueNumber string) (*models.SsqHistory, error) {
var history models.SsqHistory
err := r.db.Where("issue_number = ?", issueNumber).First(&history).Error
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return &history, err
}
// FindByRedBalls 根据红球查询(支持部分匹配)
func (r *MySQLSsqRepository) FindByRedBalls(redBalls []int) ([]models.SsqHistory, error) {
if len(redBalls) == 0 {
return r.FindAll()
}
var histories []models.SsqHistory
query := r.db
// 构建查询条件:红球在输入的红球列表中
for _, ball := range redBalls {
query = query.Where("red_ball_1 = ? OR red_ball_2 = ? OR red_ball_3 = ? OR red_ball_4 = ? OR red_ball_5 = ? OR red_ball_6 = ?",
ball, ball, ball, ball, ball, ball)
}
err := query.Order("issue_number DESC").Find(&histories).Error
return histories, err
}
// FindByRedAndBlue 根据红球和蓝球查询
func (r *MySQLSsqRepository) FindByRedAndBlue(redBalls []int, blueBall int, blueBallRange []int) ([]models.SsqHistory, error) {
var histories []models.SsqHistory
query := r.db
// 红球条件
if len(redBalls) > 0 {
for _, ball := range redBalls {
query = query.Where("red_ball_1 = ? OR red_ball_2 = ? OR red_ball_3 = ? OR red_ball_4 = ? OR red_ball_5 = ? OR red_ball_6 = ?",
ball, ball, ball, ball, ball, ball)
}
}
// 蓝球条件
if blueBall > 0 {
query = query.Where("blue_ball = ?", blueBall)
} else if len(blueBallRange) > 0 {
query = query.Where("blue_ball IN ?", blueBallRange)
}
err := query.Order("issue_number DESC").Find(&histories).Error
return histories, err
}
// Create 创建记录
func (r *MySQLSsqRepository) Create(history *models.SsqHistory) error {
now := time.Now()
if history.CreatedAt.IsZero() {
history.CreatedAt = now
}
if history.UpdatedAt.IsZero() {
history.UpdatedAt = now
}
return r.db.Create(history).Error
}
// BatchCreate 批量创建
func (r *MySQLSsqRepository) BatchCreate(histories []models.SsqHistory) error {
if len(histories) == 0 {
return nil
}
now := time.Now()
for i := range histories {
if histories[i].CreatedAt.IsZero() {
histories[i].CreatedAt = now
}
if histories[i].UpdatedAt.IsZero() {
histories[i].UpdatedAt = now
}
}
return r.db.CreateInBatches(histories, 100).Error
}
// GetLatestIssue 获取最新期号
func (r *MySQLSsqRepository) GetLatestIssue() (string, error) {
var history models.SsqHistory
err := r.db.Order("issue_number DESC").First(&history).Error
if err == gorm.ErrRecordNotFound {
return "", nil
}
return history.IssueNumber, err
}
// Count 统计总数
func (r *MySQLSsqRepository) Count() (int64, error) {
var count int64
err := r.db.Model(&models.SsqHistory{}).Count(&count).Error
return count, err
}

View File

@@ -0,0 +1,136 @@
package repository
import (
"fmt"
"gorm.io/gorm"
"ssq-desk/internal/database"
"ssq-desk/internal/storage/models"
"time"
)
// SQLiteSsqRepository SQLite 实现
type SQLiteSsqRepository struct {
db *gorm.DB
}
// NewSQLiteSsqRepository 创建 SQLite 仓库
func NewSQLiteSsqRepository() (SsqRepository, error) {
db := database.GetSQLite()
if db == nil {
return nil, fmt.Errorf("SQLite 数据库未初始化或初始化失败")
}
// 自动迁移表结构(数据库初始化时已迁移,这里再次确保)
err := db.AutoMigrate(&models.SsqHistory{})
if err != nil {
return nil, fmt.Errorf("SQLite 表迁移失败: %v", err)
}
return &SQLiteSsqRepository{db: db}, nil
}
// FindAll 查询所有历史数据
func (r *SQLiteSsqRepository) FindAll() ([]models.SsqHistory, error) {
var histories []models.SsqHistory
err := r.db.Order("issue_number DESC").Find(&histories).Error
return histories, err
}
// FindByIssue 根据期号查询
func (r *SQLiteSsqRepository) FindByIssue(issueNumber string) (*models.SsqHistory, error) {
var history models.SsqHistory
err := r.db.Where("issue_number = ?", issueNumber).First(&history).Error
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return &history, err
}
// FindByRedBalls 根据红球查询(支持部分匹配)
func (r *SQLiteSsqRepository) FindByRedBalls(redBalls []int) ([]models.SsqHistory, error) {
if len(redBalls) == 0 {
return r.FindAll()
}
var histories []models.SsqHistory
query := r.db
// 构建查询条件:红球在输入的红球列表中
for _, ball := range redBalls {
query = query.Where("red_ball_1 = ? OR red_ball_2 = ? OR red_ball_3 = ? OR red_ball_4 = ? OR red_ball_5 = ? OR red_ball_6 = ?",
ball, ball, ball, ball, ball, ball)
}
err := query.Order("issue_number DESC").Find(&histories).Error
return histories, err
}
// FindByRedAndBlue 根据红球和蓝球查询
func (r *SQLiteSsqRepository) FindByRedAndBlue(redBalls []int, blueBall int, blueBallRange []int) ([]models.SsqHistory, error) {
var histories []models.SsqHistory
query := r.db
// 红球条件
if len(redBalls) > 0 {
for _, ball := range redBalls {
query = query.Where("red_ball_1 = ? OR red_ball_2 = ? OR red_ball_3 = ? OR red_ball_4 = ? OR red_ball_5 = ? OR red_ball_6 = ?",
ball, ball, ball, ball, ball, ball)
}
}
// 蓝球条件
if blueBall > 0 {
query = query.Where("blue_ball = ?", blueBall)
} else if len(blueBallRange) > 0 {
query = query.Where("blue_ball IN ?", blueBallRange)
}
err := query.Order("issue_number DESC").Find(&histories).Error
return histories, err
}
// Create 创建记录
func (r *SQLiteSsqRepository) Create(history *models.SsqHistory) error {
now := time.Now()
if history.CreatedAt.IsZero() {
history.CreatedAt = now
}
if history.UpdatedAt.IsZero() {
history.UpdatedAt = now
}
return r.db.Create(history).Error
}
// BatchCreate 批量创建
func (r *SQLiteSsqRepository) BatchCreate(histories []models.SsqHistory) error {
if len(histories) == 0 {
return nil
}
now := time.Now()
for i := range histories {
if histories[i].CreatedAt.IsZero() {
histories[i].CreatedAt = now
}
if histories[i].UpdatedAt.IsZero() {
histories[i].UpdatedAt = now
}
}
return r.db.CreateInBatches(histories, 100).Error
}
// GetLatestIssue 获取最新期号
func (r *SQLiteSsqRepository) GetLatestIssue() (string, error) {
var history models.SsqHistory
err := r.db.Order("issue_number DESC").First(&history).Error
if err == gorm.ErrRecordNotFound {
return "", nil
}
return history.IssueNumber, err
}
// Count 统计总数
func (r *SQLiteSsqRepository) Count() (int64, error) {
var count int64
err := r.db.Model(&models.SsqHistory{}).Count(&count).Error
return count, err
}

View File

@@ -0,0 +1,25 @@
package repository
import (
"ssq-desk/internal/storage/models"
)
// SsqRepository 双色球数据仓库接口
type SsqRepository interface {
// FindAll 查询所有历史数据
FindAll() ([]models.SsqHistory, error)
// FindByIssue 根据期号查询
FindByIssue(issueNumber string) (*models.SsqHistory, error)
// FindByRedBalls 根据红球查询(支持部分匹配)
FindByRedBalls(redBalls []int) ([]models.SsqHistory, error)
// FindByRedAndBlue 根据红球和蓝球查询
FindByRedAndBlue(redBalls []int, blueBall int, blueBallRange []int) ([]models.SsqHistory, error)
// Create 创建记录
Create(history *models.SsqHistory) error
// BatchCreate 批量创建
BatchCreate(histories []models.SsqHistory) error
// GetLatestIssue 获取最新期号
GetLatestIssue() (string, error)
// Count 统计总数
Count() (int64, error)
}