feat: License 支持筛选多选批量删除

仅已吊销或已过期可删,有效授权自动跳过;单条删除同步限制。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Logan.LiandCursor committed 2026-08-12 21:53:34 +08:00
1 parent f26e787cfc
commit d0e1ca3729
6 files changed
+152 -9

No files matched your search

@@ -161,18 +161,72 @@ func (s *LicenseService) Update(id uint, updates map[string]interface{}) (*dto.L
return &resp, nil
}
// Delete 删除 License(软删除) // Logan.Li
// Delete 删除 License(仅允许已吊销或已过期;软删除) // Logan.Li
func (s *LicenseService) Delete(id uint) (*model.License, error) {
var lic model.License
if err := s.db.First(&lic, id).Error; err != nil {
return nil, errors.New("License 不存在")
}
if !isDeletableLicense(lic) {
return nil, errors.New("仅已吊销或已过期的 License 可删除")
}
if err := s.db.Delete(&model.License{}, id).Error; err != nil {
return nil, errors.New("删除 License 失败")
}
return &lic, nil
}
// BatchDeleteResult 批量删除结果 // Logan.Li
type BatchDeleteResult struct {
Deleted int `json:"deleted"`
Skipped int `json:"skipped"`
Failed int `json:"failed"`
SkippedIDs []uint `json:"skipped_ids,omitempty"`
}
// BatchDelete 批量删除:仅删已吊销/已过期,其余跳过 // Logan.Li
func (s *LicenseService) BatchDelete(ids []uint) (*BatchDeleteResult, error) {
result := &BatchDeleteResult{}
if len(ids) == 0 {
return result, nil
}
seen := map[uint]struct{}{}
for _, id := range ids {
if id == 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
var lic model.License
if err := s.db.First(&lic, id).Error; err != nil {
result.Failed++
continue
}
if !isDeletableLicense(lic) {
result.Skipped++
result.SkippedIDs = append(result.SkippedIDs, id)
continue
}
if err := s.db.Delete(&model.License{}, id).Error; err != nil {
result.Failed++
continue
}
result.Deleted++
}
return result, nil
}
// isDeletableLicense 仅吊销或到期可物理清理(软删) // Logan.Li
func isDeletableLicense(lic model.License) bool {
if lic.Status == model.LicenseStatusRevoked || lic.Status == model.LicenseStatusExpired {
return true
}
return utils.IsLicenseExpired(lic.EndDate)
}
// Renew 续期(仅在线证;离线证签名自包含,到期后应重新签发) // Logan.Li
func (s *LicenseService) Renew(id uint, duration int) (*dto.LicenseResponse, error) {
var lic model.License