package service import ( "crypto/rand" "encoding/hex" "errors" "fmt" "strings" "time" "licserver/internal/model" "gorm.io/gorm" ) type LicenseService struct { db *gorm.DB } func NewLicenseService(db *gorm.DB) *LicenseService { return &LicenseService{db: db} } // 生成授权码 func generateLicenseCode() (string, error) { b := make([]byte, 16) if _, err := rand.Read(b); err != nil { return "", err } return hex.EncodeToString(b), nil } // 创建授权码 type LicenseCreateInput struct { LicenseType string `json:"license_type" binding:"required"` Duration int `json:"duration"` // 时间授权的有效期(分钟) MaxUses int `json:"max_uses"` // 次数授权的使用次数 Count int `json:"count" binding:"required,min=1"` // 生成数量 Remark string `json:"remark"` // 备注 BindCount int `json:"bind_count"` // 可绑定次数,默认为-1(无限制) } func (s *LicenseService) CreateLicenses(input *LicenseCreateInput, createdBy uint) ([]model.LicenseCode, error) { // 验证参数 input.LicenseType = strings.ToLower(input.LicenseType) // 转为小写 switch input.LicenseType { case "time": if input.Duration <= 0 { return nil, errors.New("时间授权必须指定有效期") } case "count": if input.MaxUses <= 0 { return nil, errors.New("次数授权必须指定使用次数") } case "permanent": // 永久授权不需要额外参数 default: return nil, errors.New("无效的授权类型") } // 如果未指定绑定次数,设置为默认值-1 if input.BindCount == 0 { input.BindCount = -1 } // 生成批次号 batchNo := time.Now().Format("20060102150405") licenses := make([]model.LicenseCode, 0, input.Count) for i := 0; i < input.Count; i++ { code, err := generateLicenseCode() if err != nil { return nil, err } license := model.LicenseCode{ Code: code, LicenseType: input.LicenseType, Duration: input.Duration, MaxUses: input.MaxUses, Status: "unused", CreatedBy: createdBy, BatchNo: batchNo, Remark: input.Remark, BindCount: input.BindCount, } licenses = append(licenses, license) } // 批量创建授权码 if err := s.db.Create(&licenses).Error; err != nil { return nil, err } return licenses, nil } // 验证并使用授权码 func (s *LicenseService) UseLicense(code, deviceUID, ip string) (*model.LicenseCode, error) { var license model.LicenseCode if err := s.db.Where("code = ?", code).First(&license).Error; err != nil { return nil, errors.New("授权码不存在") } // 检查授权码状态 if license.Status != "unused" { return nil, errors.New("授权码已被使用") } // 检查绑定次数 if license.BindCount == 0 { return nil, errors.New("授权码已达到最大绑定次数限制") } // 更新授权码状态 updates := map[string]interface{}{ "status": "used", "used_by": deviceUID, "used_at": time.Now(), } // 如果不是无限制,减少绑定次数 if license.BindCount > 0 { updates["bind_count"] = license.BindCount - 1 } if err := s.db.Model(&license).Updates(updates).Error; err != nil { return nil, err } // 记录使用日志 log := model.LicenseLog{ LicenseID: license.ID, DeviceUID: deviceUID, Action: "use", IP: ip, Status: "success", Message: fmt.Sprintf("设备 %s 使用授权码", deviceUID), } if err := s.db.Create(&log).Error; err != nil { return nil, err } return &license, nil } // 获取授权码列表 func (s *LicenseService) GetLicenses(status, licenseType, batchNo string, page, pageSize int) ([]model.LicenseCode, int64, error) { var licenses []model.LicenseCode var total int64 query := s.db.Model(&model.LicenseCode{}) if status != "" { query = query.Where("status = ?", strings.ToLower(status)) } if licenseType != "" { query = query.Where("license_type = ?", strings.ToLower(licenseType)) } if batchNo != "" { query = query.Where("batch_no = ?", batchNo) } // 获取所有符合条件的授权码 var allLicenses []model.LicenseCode if err := query.Find(&allLicenses).Error; err != nil { return nil, 0, err } // 检查每个授权码的有效性 for i := range allLicenses { if allLicenses[i].Status == "used" { if err := s.CheckLicenseValidity(allLicenses[i].Code); err != nil { // 如果检查失败,更新状态 s.db.Model(&allLicenses[i]).Update("status", "expired") allLicenses[i].Status = "expired" } } } total = int64(len(allLicenses)) // 分页 if page > 0 && pageSize > 0 { start := (page - 1) * pageSize end := start + pageSize if start < len(allLicenses) { if end > len(allLicenses) { end = len(allLicenses) } licenses = allLicenses[start:end] } } else { licenses = allLicenses } return licenses, total, nil } // 获取授权码使用日志 func (s *LicenseService) GetLicenseLogs(licenseID uint, page, pageSize int) ([]model.LicenseLog, int64, error) { var logs []model.LicenseLog var total int64 query := s.db.Model(&model.LicenseLog{}).Where("license_id = ?", licenseID) query.Count(&total) if page > 0 && pageSize > 0 { offset := (page - 1) * pageSize query = query.Offset(offset).Limit(pageSize) } err := query.Order("created_at DESC").Find(&logs).Error return logs, total, err } // ExportLogs 导出授权码日志 func (s *LicenseService) ExportLogs(licenseID uint) ([]byte, error) { logs, _, err := s.GetLicenseLogs(licenseID, 0, 0) // 获取所有日志 if err != nil { return nil, err } // 创建CSV内容 var content strings.Builder content.WriteString("操作类,设备UID,IP地址,状态,详细信息,时间\n") for _, log := range logs { // 转换操作类型 action := map[string]string{ "create": "创建", "use": "使用", "verify": "验证", }[log.Action] // 转换状态 status := map[string]string{ "success": "成功", "failed": "失败", }[log.Status] // 写入一行记录 content.WriteString(fmt.Sprintf("%s,%s,%s,%s,%s,%s\n", action, log.DeviceUID, log.IP, status, log.Message, log.CreatedAt.Format("2006-01-02 15:04:05"), )) } return []byte(content.String()), nil } // 撤销授权码 func (s *LicenseService) RevokeLicense(code string, userID uint) error { var license model.LicenseCode if err := s.db.Where("code = ?", code).First(&license).Error; err != nil { return errors.New("授权码不存在") } // 检查权限 if license.CreatedBy != userID { return errors.New("无权操作此授权码") } // 更新状态 if err := s.db.Model(&license).Update("status", "revoked").Error; err != nil { return err } // 记录日志 log := model.LicenseLog{ LicenseID: license.ID, Action: "revoke", Status: "success", Message: "授权码已撤销", } s.db.Create(&log) return nil } // 批量撤销授权码 func (s *LicenseService) RevokeLicenses(codes []string, userID uint) error { return s.db.Transaction(func(tx *gorm.DB) error { for _, code := range codes { var license model.LicenseCode if err := tx.Where("code = ?", code).First(&license).Error; err != nil { continue } // 检查权限 if license.CreatedBy != userID { continue } // 更新状态 if err := tx.Model(&license).Update("status", "revoked").Error; err != nil { return err } // 记录日志 log := model.LicenseLog{ LicenseID: license.ID, Action: "revoke", Status: "success", Message: "授权码已撤销", } tx.Create(&log) } return nil }) } // 验证授权码 func (s *LicenseService) ValidateLicense(code string) (*model.LicenseCode, error) { var license model.LicenseCode if err := s.db.Where("code = ?", code).First(&license).Error; err != nil { return nil, errors.New("无效的授权码") } // 检查状态 if license.Status != "unused" { return nil, errors.New("授权码已被使用或已撤销") } return &license, nil } // 导出授权码 func (s *LicenseService) ExportLicenses(codes []string) ([]byte, error) { var licenses []model.LicenseCode if err := s.db.Where("code IN ?", codes).Find(&licenses).Error; err != nil { return nil, err } // 创建CSV内容 var content strings.Builder content.WriteString("授权码,授权类型,有效期(天),使用次数,状态,使用设备,使用时间,批次号,备注\n") for _, license := range licenses { // 转换授权类型 licenseType := map[string]string{ "time": "时间授权", "count": "次数授权", "permanent": "永久授权", }[license.LicenseType] // 转换状态 status := map[string]string{ "unused": "未使用", "used": "已使用", "revoked": "已撤销", }[license.Status] // 写入一行记录 content.WriteString(fmt.Sprintf("%s,%s,%d,%d,%s,%s,%s,%s,%s\n", license.Code, licenseType, license.Duration, license.MaxUses, status, license.UsedBy, license.UsedAt.Format("2006-01-02 15:04:05"), license.BatchNo, license.Remark, )) } return []byte(content.String()), nil } // 获取授权码统计信息 func (s *LicenseService) GetLicenseStats() (map[string]interface{}, error) { var stats struct { Total int64 Unused int64 Used int64 Revoked int64 Today int64 ThisWeek int64 ThisMonth int64 } // 获取总数 s.db.Model(&model.LicenseCode{}).Count(&stats.Total) // 获取各状态数量 s.db.Model(&model.LicenseCode{}).Where("status = ?", "unused").Count(&stats.Unused) s.db.Model(&model.LicenseCode{}).Where("status = ?", "used").Count(&stats.Used) s.db.Model(&model.LicenseCode{}).Where("status = ?", "revoked").Count(&stats.Revoked) // 获取今日创建数量 today := time.Now().Format("2006-01-02") s.db.Model(&model.LicenseCode{}).Where("DATE(created_at) = ?", today).Count(&stats.Today) // 获取本周创建数量 weekStart := time.Now().AddDate(0, 0, -int(time.Now().Weekday())) s.db.Model(&model.LicenseCode{}).Where("created_at >= ?", weekStart).Count(&stats.ThisWeek) // 获取本月创建数量 monthStart := time.Now().Format("2006-01") + "-01" s.db.Model(&model.LicenseCode{}).Where("created_at >= ?", monthStart).Count(&stats.ThisMonth) return map[string]interface{}{ "total": stats.Total, "unused": stats.Unused, "used": stats.Used, "revoked": stats.Revoked, "today": stats.Today, "this_week": stats.ThisWeek, "this_month": stats.ThisMonth, }, nil } // 添加检查授权码有效性的方法 func (s *LicenseService) CheckLicenseValidity(code string) error { var license model.LicenseCode if err := s.db.Where("code = ?", code).First(&license).Error; err != nil { return errors.New("授权码不存在") } if license.Status != "unused" && license.Status != "used" { return errors.New("授权码已被撤销或过期") } // 检查授权类型特定的限制 switch license.LicenseType { case "time": // 计算过期时间 expireTime := license.UsedAt.Add(time.Duration(license.Duration) * time.Minute) if time.Now().After(expireTime) { // 更新状态为过期 s.db.Model(&license).Update("status", "expired") return errors.New("授权码已过期") } case "count": if license.UsedCount >= license.MaxUses { // 更新状态为过期 s.db.Model(&license).Update("status", "expired") return errors.New("授权码使用次数已达上限") } } return nil } // GetLicenseByCode 通过授权码获取授权信息 func (s *LicenseService) GetLicenseByCode(code string) (*model.LicenseCode, error) { var license model.LicenseCode if err := s.db.Where("code = ?", code).First(&license).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("授权码不存在") } return nil, err } return &license, nil }