## 变更内容
### CI/CD
- 添加 GitHub Actions 工作流(test + golangci-lint)
- 添加 golangci-lint 配置,启用 errcheck/govet/staticcheck/unused/depguard
- 通过 depguard 强制 service 层不能直接导入 repository
### 错误处理修复
- 修复 CSV 写入、SSE 流式输出、随机数生成等未处理的错误
- GenerateRedeemCode() 现在返回 error
### 资源泄露修复
- 统一使用 defer func() { _ = xxx.Close() }() 模式
### 代码清理
- 移除未使用的常量
- 简化 nil map 检查
- 统一代码格式
50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
package model
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"time"
|
|
)
|
|
|
|
type RedeemCode struct {
|
|
ID int64 `gorm:"primaryKey" json:"id"`
|
|
Code string `gorm:"uniqueIndex;size:32;not null" json:"code"`
|
|
Type string `gorm:"size:20;default:balance;not null" json:"type"` // balance/concurrency/subscription
|
|
Value float64 `gorm:"type:decimal(20,8);not null" json:"value"` // 面值(USD)或并发数或有效天数
|
|
Status string `gorm:"size:20;default:unused;not null" json:"status"` // unused/used
|
|
UsedBy *int64 `gorm:"index" json:"used_by"`
|
|
UsedAt *time.Time `json:"used_at"`
|
|
CreatedAt time.Time `gorm:"not null" json:"created_at"`
|
|
|
|
// 订阅类型专用字段
|
|
GroupID *int64 `gorm:"index" json:"group_id"` // 订阅分组ID (仅subscription类型使用)
|
|
ValidityDays int `gorm:"default:30" json:"validity_days"` // 订阅有效天数 (仅subscription类型使用)
|
|
|
|
// 关联
|
|
User *User `gorm:"foreignKey:UsedBy" json:"user,omitempty"`
|
|
Group *Group `gorm:"foreignKey:GroupID" json:"group,omitempty"`
|
|
}
|
|
|
|
func (RedeemCode) TableName() string {
|
|
return "redeem_codes"
|
|
}
|
|
|
|
// IsUsed 检查是否已使用
|
|
func (r *RedeemCode) IsUsed() bool {
|
|
return r.Status == "used"
|
|
}
|
|
|
|
// CanUse 检查是否可以使用
|
|
func (r *RedeemCode) CanUse() bool {
|
|
return r.Status == "unused"
|
|
}
|
|
|
|
// GenerateRedeemCode 生成唯一的兑换码
|
|
func GenerateRedeemCode() (string, error) {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(b), nil
|
|
}
|