feat: Add license management repository, models, and configuration for license and authorization code operations.

This commit is contained in:
wood911010 committed 2026-02-27 00:55:04 +08:00
1 parent a95322b6c5
commit 7dd00dc074
2 files changed
+54 -32

No files matched your search

+13 -13
View File
@@ -63,14 +63,14 @@ func (l *License) BeforeUpdate(tx *gorm.DB) error {
// LicenseListRequest 许可证列表查询请求结构
type LicenseListRequest struct {
Page int `form:"page" binding:"omitempty,min=1"` // 页码,默认1
PageSize int `form:"page_size" binding:"omitempty,min=1,max=100"` // 每页条数,默认20,最大100
AuthorizationCodeID string `form:"authorization_code_id" binding:"omitempty"` // 授权码ID筛选
CustomerID string `form:"customer_id" binding:"omitempty"` // 客户ID筛选
Status string `form:"status" binding:"omitempty,oneof=active inactive revoked"` // 状态筛选
IsOnline *bool `form:"is_online" binding:"omitempty"` // 在线状态筛选
Sort string `form:"sort" binding:"omitempty,oneof=created_at updated_at activated_at last_heartbeat"` // 排序字段,默认created_at
Order string `form:"order" binding:"omitempty,oneof=asc desc"` // 排序方向,默认desc
Page int `form:"page" binding:"omitempty,min=1"` // 页码,默认1
PageSize int `form:"page_size" binding:"omitempty,min=1,max=100"` // 每页条数,默认20,最大100
AuthorizationCodeID string `form:"authorization_code_id" binding:"omitempty"` // 授权码ID筛选
CustomerID string `form:"customer_id" binding:"omitempty"` // 客户ID筛选
Status string `form:"status" binding:"omitempty,oneof=active inactive revoked"` // 状态筛选
IsOnline *string `form:"is_online" binding:"omitempty"` // 在线状态筛选
Sort string `form:"sort" binding:"omitempty,oneof=created_at updated_at activated_at last_heartbeat"` // 排序字段,默认created_at
Order string `form:"order" binding:"omitempty,oneof=asc desc"` // 排序方向,默认desc
}
// LicenseListItem 许可证列表项结构
@@ -186,11 +186,11 @@ type GrowthRate struct {
// DeviceListRequest 设备列表查询请求结构(客户用户接口)
type DeviceListRequest struct {
Page int `form:"page" binding:"omitempty,min=1"` // 页码,默认1
PageSize int `form:"page_size" binding:"omitempty,min=1,max=100"` // 每页数量,默认20,最大100
DeviceName string `form:"device_name" binding:"omitempty,max=100"` // 设备名称模糊搜索(匹配device_info.name)
AuthorizationCodeID string `form:"authorization_code_id" binding:"omitempty,len=36"` // 按授权码ID筛选设备
IsOnline *bool `form:"is_online" binding:"omitempty"` // 是否在线筛选(true在线,false离线;不传不过滤)
Page int `form:"page" binding:"omitempty,min=1"` // 页码,默认1
PageSize int `form:"page_size" binding:"omitempty,min=1,max=100"` // 每页数量,默认20,最大100
DeviceName string `form:"device_name" binding:"omitempty,max=100"` // 设备名称模糊搜索(匹配device_info.name)
AuthorizationCodeID string `form:"authorization_code_id" binding:"omitempty,len=36"` // 按授权码ID筛选设备
IsOnline *string `form:"is_online" binding:"omitempty"` // 是否在线筛选(true在线,false离线;不传不过滤)
}
// DeviceListItem 设备列表项结构(客户用户接口)
@@ -66,13 +66,18 @@ func (r *licenseRepository) GetLicenseList(ctx context.Context, req *models.Lice
}
// 在线状态筛选
if req.IsOnline != nil {
// 在线状态:最后心跳时间在5分钟内
fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
if *req.IsOnline {
query = query.Where("licenses.last_heartbeat >= ?", fiveMinutesAgo)
} else {
query = query.Where("licenses.last_heartbeat < ? OR licenses.last_heartbeat IS NULL", fiveMinutesAgo)
if req.IsOnline != nil && *req.IsOnline != "" {
cfg := config.GetConfig()
heartbeatTimeoutSeconds := cfg.License.HeartbeatTimeout
if heartbeatTimeoutSeconds <= 0 {
heartbeatTimeoutSeconds = 300 // 默认5分钟
}
onlineThreshold := time.Now().Add(-time.Duration(heartbeatTimeoutSeconds) * time.Second)
if *req.IsOnline == "true" {
query = query.Where("licenses.last_heartbeat >= ?", onlineThreshold)
} else if *req.IsOnline == "false" {
query = query.Where("licenses.last_heartbeat < ? OR licenses.last_heartbeat IS NULL", onlineThreshold)
}
}
@@ -106,12 +111,19 @@ func (r *licenseRepository) GetLicenseList(ctx context.Context, req *models.Lice
// 转换为响应格式
list := make([]models.LicenseListItem, len(licenses))
cfg := config.GetConfig()
heartbeatTimeoutSeconds := cfg.License.HeartbeatTimeout
if heartbeatTimeoutSeconds <= 0 {
heartbeatTimeoutSeconds = 300 // 默认5分钟
}
onlineThreshold := time.Now().Add(-time.Duration(heartbeatTimeoutSeconds) * time.Second)
for i, license := range licenses {
// 计算在线状态
isOnline := false
if license.LastHeartbeat != nil {
fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
isOnline = license.LastHeartbeat.After(fiveMinutesAgo)
isOnline = license.LastHeartbeat.After(onlineThreshold)
}
// 格式化时间
@@ -169,8 +181,13 @@ func (r *licenseRepository) GetLicenseByID(ctx context.Context, id string) (*mod
// 计算在线状态
if license.LastHeartbeat != nil {
fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
license.IsOnline = license.LastHeartbeat.After(fiveMinutesAgo)
cfg := config.GetConfig()
heartbeatTimeoutSeconds := cfg.License.HeartbeatTimeout
if heartbeatTimeoutSeconds <= 0 {
heartbeatTimeoutSeconds = 300 // 默认5分钟
}
onlineThreshold := time.Now().Add(-time.Duration(heartbeatTimeoutSeconds) * time.Second)
license.IsOnline = license.LastHeartbeat.After(onlineThreshold)
}
return &license, nil
@@ -238,8 +255,13 @@ func (r *licenseRepository) GetLicenseByKey(ctx context.Context, licenseKey stri
// 计算在线状态
if license.LastHeartbeat != nil {
fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
license.IsOnline = license.LastHeartbeat.After(fiveMinutesAgo)
cfg := config.GetConfig()
heartbeatTimeoutSeconds := cfg.License.HeartbeatTimeout
if heartbeatTimeoutSeconds <= 0 {
heartbeatTimeoutSeconds = 300 // 默认5分钟
}
onlineThreshold := time.Now().Add(-time.Duration(heartbeatTimeoutSeconds) * time.Second)
license.IsOnline = license.LastHeartbeat.After(onlineThreshold)
}
return &license, nil
@@ -299,10 +321,10 @@ func (r *licenseRepository) GetCustomerDeviceList(ctx context.Context, customerI
}
// 在线状态筛选
if req.IsOnline != nil {
if *req.IsOnline {
if req.IsOnline != nil && *req.IsOnline != "" {
if *req.IsOnline == "true" {
query = query.Where("licenses.last_heartbeat > ?", onlineThreshold)
} else {
} else if *req.IsOnline == "false" {
query = query.Where("(licenses.last_heartbeat <= ? OR licenses.last_heartbeat IS NULL)", onlineThreshold)
}
}
@@ -355,11 +377,11 @@ func (r *licenseRepository) GetCustomerDeviceList(ctx context.Context, customerI
// 格式化时间字段
var activatedAtStr, lastHeartbeatStr *string
if result.ActivatedAt != nil {
str := result.ActivatedAt.Format("2006-01-02T15:04:05Z")
str := result.ActivatedAt.Format(time.RFC3339)
activatedAtStr = &str
}
if result.LastHeartbeat != nil {
str := result.LastHeartbeat.Format("2006-01-02T15:04:05Z")
str := result.LastHeartbeat.Format(time.RFC3339)
lastHeartbeatStr = &str
}
@@ -379,7 +401,7 @@ func (r *licenseRepository) GetCustomerDeviceList(ctx context.Context, customerI
AuthorizationInfo: models.AuthorizationInfo{
AuthorizationCode: result.AuthorizationCode,
AuthorizationCodeID: result.AuthorizationCodeID,
EndDate: result.EndDate.Format("2006-01-02T15:04:05Z"),
EndDate: result.EndDate.Format(time.RFC3339),
Description: description,
},
}