feat: License 支持筛选多选批量删除
仅已吊销或已过期可删,有效授权自动跳过;单条删除同步限制。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
f26e787cfc
commit
d0e1ca3729
6 files changed
+152
-9
No files matched your search
@@ -135,7 +135,7 @@ func (ctrl *LicenseController) Update(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "更新成功", "data": lic})
|
||||
}
|
||||
|
||||
// Delete 删除 License // Logan.Li
|
||||
// Delete 删除 License(仅已吊销/已过期) // Logan.Li
|
||||
func (ctrl *LicenseController) Delete(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
lic, err := ctrl.svc.Delete(uint(id))
|
||||
@@ -147,6 +147,32 @@ func (ctrl *LicenseController) Delete(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "删除成功"})
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除:非吊销/未到期自动跳过 // Logan.Li
|
||||
func (ctrl *LicenseController) BatchDelete(c *gin.Context) {
|
||||
var req dto.LicenseBatchDeleteRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "参数错误: 请提供 ids"})
|
||||
return
|
||||
}
|
||||
result, err := ctrl.svc.BatchDelete(req.IDs)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": 1, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
utils.LogAction(ctrl.db, c, "batch_delete", "license", 0, "", "", "",
|
||||
"批量删除 License deleted="+strconv.Itoa(result.Deleted)+" skipped="+strconv.Itoa(result.Skipped))
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "批量删除完成",
|
||||
"data": dto.LicenseBatchDeleteResponse{
|
||||
Deleted: result.Deleted,
|
||||
Skipped: result.Skipped,
|
||||
Failed: result.Failed,
|
||||
SkippedIDs: result.SkippedIDs,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Renew 续期 // Logan.Li
|
||||
func (ctrl *LicenseController) Renew(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
|
||||
@@ -17,9 +17,17 @@ type LicenseRenew struct {
|
||||
Duration int `json:"duration" binding:"required"`
|
||||
}
|
||||
|
||||
// LicenseRevoke 吊销请求 // Logan.Li
|
||||
type LicenseRevoke struct {
|
||||
Reason string `json:"reason"`
|
||||
// LicenseBatchDeleteRequest 批量删除请求 // Logan.Li
|
||||
type LicenseBatchDeleteRequest struct {
|
||||
IDs []uint `json:"ids" binding:"required,min=1"`
|
||||
}
|
||||
|
||||
// LicenseBatchDeleteResponse 批量删除响应 // Logan.Li
|
||||
type LicenseBatchDeleteResponse struct {
|
||||
Deleted int `json:"deleted"`
|
||||
Skipped int `json:"skipped"`
|
||||
Failed int `json:"failed"`
|
||||
SkippedIDs []uint `json:"skipped_ids,omitempty"`
|
||||
}
|
||||
|
||||
// LicenseResponse License 响应 // Logan.Li
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user