feat: 添加授权码状态计算逻辑并优化查询条件

This commit is contained in:
wood911010 committed 2025-10-21 10:16:11 +08:00
1 parent b3ca90017b
commit b8430c5b7d
3 files changed
+84 -24

No files matched your search

+30
View File
@@ -17,6 +17,36 @@ GET /api/v1/authorization-codes
- `sort` - 排序字段 (created_at/updated_at/code)
- `order` - 排序方向 (asc/desc)
**实现说明**
由于 `status` 是虚拟字段,需要在 SQL 查询中动态计算并筛选:
```sql
-- 状态计算逻辑
SELECT *,
CASE
WHEN is_locked = true THEN 'locked'
WHEN end_date < NOW() THEN 'expired'
WHEN start_date <= NOW() AND end_date >= NOW() THEN 'normal'
ELSE 'expired'
END AS status
FROM authorization_codes
WHERE 1=1
-- status 参数筛选
AND (
(:status = 'locked' AND is_locked = true) OR
(:status = 'expired' AND is_locked = false AND end_date < NOW()) OR
(:status = 'normal' AND is_locked = false AND start_date <= NOW() AND end_date >= NOW()) OR
:status IS NULL
)
-- 其他筛选条件
AND (:customer_id IS NULL OR customer_id = :customer_id)
AND (:start_date IS NULL OR created_at >= :start_date)
AND (:end_date IS NULL OR created_at <= :end_date)
ORDER BY created_at DESC
LIMIT :page_size OFFSET :offset;
```
**响应**
```json
{
@@ -44,6 +44,17 @@
### 状态管理属性
- (虚字段-不出现在表中)`status` - 授权状态 (normal正常/locked已锁定/expired已过期)
- **SQL 计算逻辑**:
```sql
CASE
WHEN is_locked = true THEN 'locked'
WHEN end_date < NOW() THEN 'expired'
WHEN start_date <= NOW() AND end_date >= NOW() THEN 'normal'
ELSE 'expired'
END AS status
```
- **优先级**: locked > expired > normal
- **筛选实现**: 在 WHERE 子句中使用相同逻辑进行条件判断
- `is_locked` - 是否被锁定 (布尔字段)
- `lock_reason` - 锁定原因 (自定义文本输入)
- `locked_at` - 锁定时间
@@ -2,9 +2,9 @@ package repository
import (
"context"
"license-manager/internal/models"
"math"
"time"
"license-manager/internal/models"
"gorm.io/gorm"
)
@@ -58,11 +58,17 @@ func (r *authorizationCodeRepository) GetAuthorizationCodeList(ctx context.Conte
order = "desc"
}
// 构建查询
// 构建查询,包含状态计算
query := r.db.WithContext(ctx).Table("authorization_codes ac").
Select(`ac.id, ac.code, ac.customer_id, c.customer_name,
ac.start_date, ac.end_date, ac.max_activations,
ac.deployment_type, ac.is_locked, ac.description, ac.created_at`).
ac.deployment_type, ac.is_locked, ac.description, ac.created_at,
CASE
WHEN ac.is_locked = true THEN 'locked'
WHEN ac.end_date < NOW() THEN 'expired'
WHEN ac.start_date <= NOW() AND ac.end_date >= NOW() THEN 'normal'
ELSE 'expired'
END AS status`).
Joins("LEFT JOIN customers c ON ac.customer_id = c.id AND c.deleted_at IS NULL")
// 添加筛选条件
@@ -70,7 +76,18 @@ func (r *authorizationCodeRepository) GetAuthorizationCodeList(ctx context.Conte
query = query.Where("ac.customer_id = ?", req.CustomerID)
}
// 状态筛选需要在应用层处理,因为status是计算字段
// 状态筛选 - 在 SQL 层面处理
if req.Status != "" {
switch req.Status {
case "locked":
query = query.Where("ac.is_locked = true")
case "expired":
query = query.Where("ac.is_locked = false AND ac.end_date < NOW()")
case "normal":
query = query.Where("ac.is_locked = false AND ac.start_date <= NOW() AND ac.end_date >= NOW()")
}
}
if req.StartDate != "" {
query = query.Where("ac.created_at >= ?", req.StartDate)
}
@@ -97,6 +114,7 @@ func (r *authorizationCodeRepository) GetAuthorizationCodeList(ctx context.Conte
IsLocked bool `json:"is_locked"`
Description *string `json:"description"`
CreatedAt string `json:"created_at"`
Status string `json:"status"` // 添加状态字段
}
offset := (page - 1) * pageSize
@@ -112,20 +130,21 @@ func (r *authorizationCodeRepository) GetAuthorizationCodeList(ctx context.Conte
if result.CustomerName != nil {
customerName = *result.CustomerName
}
list[i] = models.AuthorizationCodeListItem{
ID: result.ID,
Code: result.Code,
CustomerID: result.CustomerID,
CustomerName: customerName,
StartDate: result.StartDate,
EndDate: result.EndDate,
MaxActivations: result.MaxActivations,
CurrentActivations: 0, // TODO: 从licenses表统计
DeploymentType: result.DeploymentType,
IsLocked: result.IsLocked,
Description: result.Description,
CreatedAt: result.CreatedAt,
ID: result.ID,
Code: result.Code,
CustomerID: result.CustomerID,
CustomerName: customerName,
Status: result.Status, // 使用 SQL 计算的状态
StartDate: result.StartDate,
EndDate: result.EndDate,
MaxActivations: result.MaxActivations,
CurrentActivations: 0, // TODO: 从licenses表统计
DeploymentType: result.DeploymentType,
IsLocked: result.IsLocked,
Description: result.Description,
CreatedAt: result.CreatedAt,
}
}
@@ -224,12 +243,12 @@ func (r *authorizationCodeRepository) GetAuthorizationChangeList(ctx context.Con
offset := (req.Page - 1) * req.PageSize
var changes []struct {
ID string `json:"id"`
ChangeType string `json:"change_type"`
OperatorID string `json:"operator_id"`
OperatorName *string `json:"operator_name"`
Reason *string `json:"reason"`
CreatedAt time.Time `json:"created_at"`
ID string `json:"id"`
ChangeType string `json:"change_type"`
OperatorID string `json:"operator_id"`
OperatorName *string `json:"operator_name"`
Reason *string `json:"reason"`
CreatedAt time.Time `json:"created_at"`
}
if err := query.Order(orderBy).Limit(req.PageSize).Offset(offset).Scan(&changes).Error; err != nil {
@@ -264,4 +283,4 @@ func (r *authorizationCodeRepository) GetAuthorizationChangeList(ctx context.Con
PageSize: req.PageSize,
TotalPages: totalPages,
}, nil
}
}