feat(subscription): 订阅过期状态自动更新与服务端排序
- 新增 SubscriptionExpiryService 定时任务,每分钟更新过期订阅状态 - 订阅列表支持服务端排序(按过期时间、状态、创建时间) - 实时显示正确的过期状态,无需等待定时任务 - 允许对已过期订阅进行续期操作 - DataTable 组件支持 serverSideSort 模式
This commit is contained in:
@@ -330,12 +330,10 @@ func (s *SubscriptionService) ExtendSubscription(ctx context.Context, subscripti
|
||||
newExpiresAt = MaxExpiresAt
|
||||
}
|
||||
|
||||
// 如果是缩短(负数),检查新的过期时间必须大于当前时间
|
||||
if days < 0 {
|
||||
now := time.Now()
|
||||
if !newExpiresAt.After(now) {
|
||||
return nil, ErrAdjustWouldExpire
|
||||
}
|
||||
// 检查新的过期时间必须大于当前时间
|
||||
now := time.Now()
|
||||
if !newExpiresAt.After(now) {
|
||||
return nil, ErrAdjustWouldExpire
|
||||
}
|
||||
|
||||
if err := s.userSubRepo.ExtendExpiry(ctx, subscriptionID, newExpiresAt); err != nil {
|
||||
@@ -383,6 +381,7 @@ func (s *SubscriptionService) ListUserSubscriptions(ctx context.Context, userID
|
||||
return nil, err
|
||||
}
|
||||
normalizeExpiredWindows(subs)
|
||||
normalizeSubscriptionStatus(subs)
|
||||
return subs, nil
|
||||
}
|
||||
|
||||
@@ -404,17 +403,19 @@ func (s *SubscriptionService) ListGroupSubscriptions(ctx context.Context, groupI
|
||||
return nil, nil, err
|
||||
}
|
||||
normalizeExpiredWindows(subs)
|
||||
normalizeSubscriptionStatus(subs)
|
||||
return subs, pag, nil
|
||||
}
|
||||
|
||||
// List 获取所有订阅(分页,支持筛选)
|
||||
func (s *SubscriptionService) List(ctx context.Context, page, pageSize int, userID, groupID *int64, status string) ([]UserSubscription, *pagination.PaginationResult, error) {
|
||||
// List 获取所有订阅(分页,支持筛选和排序)
|
||||
func (s *SubscriptionService) List(ctx context.Context, page, pageSize int, userID, groupID *int64, status, sortBy, sortOrder string) ([]UserSubscription, *pagination.PaginationResult, error) {
|
||||
params := pagination.PaginationParams{Page: page, PageSize: pageSize}
|
||||
subs, pag, err := s.userSubRepo.List(ctx, params, userID, groupID, status)
|
||||
subs, pag, err := s.userSubRepo.List(ctx, params, userID, groupID, status, sortBy, sortOrder)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
normalizeExpiredWindows(subs)
|
||||
normalizeSubscriptionStatus(subs)
|
||||
return subs, pag, nil
|
||||
}
|
||||
|
||||
@@ -441,6 +442,18 @@ func normalizeExpiredWindows(subs []UserSubscription) {
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeSubscriptionStatus 根据实际过期时间修正状态(仅影响返回数据,不影响数据库)
|
||||
// 这确保前端显示正确的状态,即使定时任务尚未更新数据库
|
||||
func normalizeSubscriptionStatus(subs []UserSubscription) {
|
||||
now := time.Now()
|
||||
for i := range subs {
|
||||
sub := &subs[i]
|
||||
if sub.Status == SubscriptionStatusActive && !sub.ExpiresAt.After(now) {
|
||||
sub.Status = SubscriptionStatusExpired
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// startOfDay 返回给定时间所在日期的零点(保持原时区)
|
||||
func startOfDay(t time.Time) time.Time {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
@@ -659,11 +672,6 @@ func (s *SubscriptionService) GetUserSubscriptionsWithProgress(ctx context.Conte
|
||||
return progresses, nil
|
||||
}
|
||||
|
||||
// UpdateExpiredSubscriptions 更新过期订阅状态(定时任务调用)
|
||||
func (s *SubscriptionService) UpdateExpiredSubscriptions(ctx context.Context) (int64, error) {
|
||||
return s.userSubRepo.BatchUpdateExpiredStatus(ctx)
|
||||
}
|
||||
|
||||
// ValidateSubscription 验证订阅是否有效
|
||||
func (s *SubscriptionService) ValidateSubscription(ctx context.Context, sub *UserSubscription) error {
|
||||
if sub.Status == SubscriptionStatusExpired {
|
||||
|
||||
Reference in New Issue
Block a user