diff --git a/internal/handler/key_handler.go b/internal/handler/key_handler.go index 09949b5..9b6221c 100644 --- a/internal/handler/key_handler.go +++ b/internal/handler/key_handler.go @@ -62,6 +62,12 @@ type GroupIDRequest struct { GroupID uint `json:"group_id" binding:"required"` } +// ValidateGroupKeysRequest defines the payload for validating keys in a group. +type ValidateGroupKeysRequest struct { + GroupID uint `json:"group_id" binding:"required"` + Status string `json:"status,omitempty"` +} + // AddMultipleKeys handles creating new keys from a text block within a specific group. func (s *Server) AddMultipleKeys(c *gin.Context) { var req KeyTextRequest @@ -258,12 +264,18 @@ func (s *Server) TestMultipleKeys(c *gin.Context) { // ValidateGroupKeys initiates a manual validation task for all keys in a group. func (s *Server) ValidateGroupKeys(c *gin.Context) { - var req GroupIDRequest + var req ValidateGroupKeysRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, app_errors.NewAPIError(app_errors.ErrInvalidJSON, err.Error())) return } + // Validate status if provided + if req.Status != "" && req.Status != models.KeyStatusActive && req.Status != models.KeyStatusInvalid { + response.Error(c, app_errors.NewAPIError(app_errors.ErrValidation, "Invalid status value")) + return + } + groupDB, ok := s.findGroupByID(c, req.GroupID) if !ok { return @@ -275,7 +287,7 @@ func (s *Server) ValidateGroupKeys(c *gin.Context) { return } - taskStatus, err := s.KeyManualValidationService.StartValidationTask(group) + taskStatus, err := s.KeyManualValidationService.StartValidationTask(group, req.Status) if err != nil { response.Error(c, app_errors.NewAPIError(app_errors.ErrTaskInProgress, err.Error())) return diff --git a/internal/services/key_manual_validation_service.go b/internal/services/key_manual_validation_service.go index 80ef858..52979c3 100644 --- a/internal/services/key_manual_validation_service.go +++ b/internal/services/key_manual_validation_service.go @@ -41,10 +41,14 @@ func NewKeyManualValidationService(db *gorm.DB, validator *keypool.KeyValidator, } // StartValidationTask starts a new manual validation task for a given group. -func (s *KeyManualValidationService) StartValidationTask(group *models.Group) (*TaskStatus, error) { +func (s *KeyManualValidationService) StartValidationTask(group *models.Group, status string) (*TaskStatus, error) { var keys []models.APIKey - if err := s.DB.Where("group_id = ?", group.ID).Find(&keys).Error; err != nil { - return nil, fmt.Errorf("failed to get keys for group %s: %w", group.Name, err) + query := s.DB.Where("group_id = ?", group.ID) + if status != "" { + query = query.Where("status = ?", status) + } + if err := query.Find(&keys).Error; err != nil { + return nil, fmt.Errorf("failed to get keys for group %s with status '%s': %w", group.Name, status, err) } if len(keys) == 0 { @@ -59,13 +63,20 @@ func (s *KeyManualValidationService) StartValidationTask(group *models.Group) (* } // Run the validation in a separate goroutine - go s.runValidation(group, keys) + go s.runValidation(group, keys, status) return taskStatus, nil } -func (s *KeyManualValidationService) runValidation(group *models.Group, keys []models.APIKey) { - logrus.Infof("Starting manual validation for group %s", group.Name) +func (s *KeyManualValidationService) runValidation(group *models.Group, keys []models.APIKey, status string) { + logFields := logrus.Fields{ + "group": group.Name, + "status": status, + } + if status == "" { + logFields["status"] = "all" + } + logrus.WithFields(logFields).Info("Starting manual validation") jobs := make(chan models.APIKey, len(keys)) results := make(chan bool, len(keys)) diff --git a/web/src/api/keys.ts b/web/src/api/keys.ts index e1f59c5..b60b5e9 100644 --- a/web/src/api/keys.ts +++ b/web/src/api/keys.ts @@ -175,14 +175,21 @@ export const keysApi = { }, // 验证分组密钥 - async validateGroupKeys(groupId: number): Promise<{ + async validateGroupKeys( + groupId: number, + status?: "active" | "invalid" + ): Promise<{ is_running: boolean; group_name: string; processed: number; total: number; started_at: string; }> { - const res = await http.post("/keys/validate-group", { group_id: groupId }); + const payload: { group_id: number; status?: string } = { group_id: groupId }; + if (status) { + payload.status = status; + } + const res = await http.post("/keys/validate-group", payload); return res.data; }, diff --git a/web/src/components/GlobalTaskProgressBar.vue b/web/src/components/GlobalTaskProgressBar.vue index 56e4aed..e1b5f55 100644 --- a/web/src/components/GlobalTaskProgressBar.vue +++ b/web/src/components/GlobalTaskProgressBar.vue @@ -49,7 +49,7 @@ async function pollOnce() { let msg = "任务已完成。"; if (task.task_type === "KEY_VALIDATION") { const result = task.result as import("@/types/models").KeyValidationResult; - msg = `密钥验证完成,处理了 ${result.total_keys} 个密钥,其中 ${result.valid_keys} 个有效,${result.invalid_keys} 个无效。`; + msg = `密钥验证完成,处理了 ${result.total_keys} 个密钥,其中 ${result.valid_keys} 个成功,${result.invalid_keys} 个失败。请注意:验证失败并不一定拉黑该密钥,需要失败次数达到阈值才会拉黑。`; } else if (task.task_type === "KEY_IMPORT") { const result = task.result as import("@/types/models").KeyImportResult; msg = `密钥导入完成,成功添加 ${result.added_count} 个密钥,忽略了 ${result.ignored_count} 个。`; diff --git a/web/src/components/keys/KeyTable.vue b/web/src/components/keys/KeyTable.vue index d34072b..9c8e41c 100644 --- a/web/src/components/keys/KeyTable.vue +++ b/web/src/components/keys/KeyTable.vue @@ -67,6 +67,8 @@ const moreOptions = [ { label: "清空所有无效密钥", key: "clearInvalid", props: { style: { color: "#d03050" } } }, { type: "divider" }, { label: "验证所有密钥", key: "validateAll" }, + { label: "验证有效密钥", key: "validateActive" }, + { label: "验证无效密钥", key: "validateInvalid" }, ]; let testingMsg: MessageReactive | null = null; @@ -150,7 +152,13 @@ function handleMoreAction(key: string) { restoreAllInvalid(); break; case "validateAll": - validateAllKeys(); + validateKeys("all"); + break; + case "validateActive": + validateKeys("active"); + break; + case "validateInvalid": + validateKeys("invalid"); break; case "clearInvalid": clearAllInvalid(); @@ -395,17 +403,24 @@ async function restoreAllInvalid() { }); } -async function validateAllKeys() { +async function validateKeys(status: "all" | "active" | "invalid") { if (!props.selectedGroup?.id || testingMsg) { return; } - testingMsg = window.$message.info("正在验证密钥...", { + let statusText = "所有"; + if (status === "active") { + statusText = "有效"; + } else if (status === "invalid") { + statusText = "无效"; + } + + testingMsg = window.$message.info(`正在验证${statusText}密钥...`, { duration: 0, }); try { - await keysApi.validateGroupKeys(props.selectedGroup.id); + await keysApi.validateGroupKeys(props.selectedGroup.id, status === "all" ? undefined : status); localStorage.removeItem("last_closed_task"); appState.taskPollingTrigger++; } catch (_error) {