feat(tasks): 漏洞列改为按严重度分档显示 严/高/中/低

- TaskListMetricsAll 用 COUNT(*) FILTER 按 severity 分四档统计(同一条查询)
- TaskListMetrics.Findings 及 TaskDTO.findings 由数字改为 {critical,high,medium,low}
- 列表页「漏洞」列渲染 x/x/x/x,配色沿用 severity 语义、为 0 的档位弱化
- severity 为空/白名单外的记录不计入任一档;mock 同步为对象结构
This commit is contained in:
Autumn-27 committed 2026-09-24 13:32:45 -04:00
1 parent e65d3e5202
commit 87b3c3c770
7 files changed
+90 -48

No files matched your search

+39 -31
View File
@@ -30,37 +30,45 @@ func rawString(raw json.RawMessage) string {
// ---- Task (frontend "Task") ---- created_at as RFC3339, plus a derived status.
type TaskDTO struct {
ID string `json:"id"`
ExplorationID int64 `json:"exploration_id"`
Name string `json:"name"` // 可选任务名称;空=未命名
CategoryID *int64 `json:"category_id,omitempty"`
CategoryName string `json:"category_name,omitempty"`
Pinned bool `json:"pinned"`
PinnedAt string `json:"pinned_at,omitempty"`
Description string `json:"description"`
Goal string `json:"goal"`
Status string `json:"status"` // created | running | paused | done | failed
CreatedAt string `json:"created_at"`
CreatedUnix int64 `json:"created_unix"` // created_at as unix seconds (for run-duration calc)
CompletedAt string `json:"completed_at"` // RFC3339 finish time (done/failed); "" if unfinished
CompletedUnix int64 `json:"completed_unix"` // completed_at as unix seconds (0 if unfinished)
LastActivity int64 `json:"last_activity_unix"` // unix seconds of the last activity (0 if none)
Paused bool `json:"paused"`
Queued bool `json:"queued"`
Tokens TokenTotalDTO `json:"tokens"` // whole-task token consumption
GoalsTotal int `json:"goals_total"`
GoalsMet int `json:"goals_met"`
InFlight int `json:"in_flight"` // 运行中 Worker 数(state=running 的意图)
Findings int `json:"findings"` // 该任务已登记的漏洞数(findings 表)
LLMProfileID *int64 `json:"llm_profile_id,omitempty"` // LLM profile used for this task; nil = default
LLMProfileIDs []int64 `json:"llm_profile_ids"`
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
LLMFailoverState string `json:"llm_failover_state"`
LLMFailoverReason string `json:"llm_failover_reason,omitempty"`
SourceTaskIDs []string `json:"source_task_ids"`
ArchiveBlockedBy string `json:"archive_blocked_by_task_id,omitempty"`
CompanyIDs []int64 `json:"company_ids"`
CoverageEnabled bool `json:"coverage_enabled"` // 资产覆盖度功能开关(创建时定)
ID string `json:"id"`
ExplorationID int64 `json:"exploration_id"`
Name string `json:"name"` // 可选任务名称;空=未命名
CategoryID *int64 `json:"category_id,omitempty"`
CategoryName string `json:"category_name,omitempty"`
Pinned bool `json:"pinned"`
PinnedAt string `json:"pinned_at,omitempty"`
Description string `json:"description"`
Goal string `json:"goal"`
Status string `json:"status"` // created | running | paused | done | failed
CreatedAt string `json:"created_at"`
CreatedUnix int64 `json:"created_unix"` // created_at as unix seconds (for run-duration calc)
CompletedAt string `json:"completed_at"` // RFC3339 finish time (done/failed); "" if unfinished
CompletedUnix int64 `json:"completed_unix"` // completed_at as unix seconds (0 if unfinished)
LastActivity int64 `json:"last_activity_unix"` // unix seconds of the last activity (0 if none)
Paused bool `json:"paused"`
Queued bool `json:"queued"`
Tokens TokenTotalDTO `json:"tokens"` // whole-task token consumption
GoalsTotal int `json:"goals_total"`
GoalsMet int `json:"goals_met"`
InFlight int `json:"in_flight"` // 运行中 Worker 数(state=running 的意图)
Findings FindingSeverityDTO `json:"findings"` // 该任务已登记的漏洞数(findings 表,按严重度分档)
LLMProfileID *int64 `json:"llm_profile_id,omitempty"` // LLM profile used for this task; nil = default
LLMProfileIDs []int64 `json:"llm_profile_ids"`
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
LLMFailoverState string `json:"llm_failover_state"`
LLMFailoverReason string `json:"llm_failover_reason,omitempty"`
SourceTaskIDs []string `json:"source_task_ids"`
ArchiveBlockedBy string `json:"archive_blocked_by_task_id,omitempty"`
CompanyIDs []int64 `json:"company_ids"`
CoverageEnabled bool `json:"coverage_enabled"` // 资产覆盖度功能开关(创建时定)
}
// FindingSeverityDTO 是任务列表里按严重度分档的漏洞计数(严重/高/中/低)。
type FindingSeverityDTO struct {
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
}
func applyTaskArchiveBlocker(dto *TaskDTO, blockers map[int64]int64) {
+7 -2
View File
@@ -148,7 +148,7 @@ func New(ctx context.Context, m *Manager, skillDir string, dataDir string, keyDi
chatCancel: map[string]context.CancelCauseFunc{}, triggerQ: map[string][]triggeredRun{},
triggerActive: map[string]int{}, triggerCfg: map[string]triggerBehavior{},
profChatAgents: map[int64]*agent.ChatAgent{},
provByProfile: map[int64]*provEntry{}, llmHealth: newLLMHealthRegistry(m.pg),
provByProfile: map[int64]*provEntry{}, llmHealth: newLLMHealthRegistry(m.pg),
taskAgents: map[string]*taskAgentBundle{}, archiveWake: make(chan struct{}, 1)}
s.initSideQuestions()
// 熔断阈值/冷却是失败路径上的热参数,启动时把全局重试策略推给 Registry 一次;
@@ -1040,7 +1040,12 @@ func (s *Server) listTasks(w http.ResponseWriter, r *http.Request) {
dto.GoalsTotal = metric.Goals.Total
dto.GoalsMet = metric.Goals.Met
dto.InFlight = metric.RunningIntents
dto.Findings = metric.Findings
dto.Findings = FindingSeverityDTO{
Critical: metric.Findings.Critical,
High: metric.Findings.High,
Medium: metric.Findings.Medium,
Low: metric.Findings.Low,
}
dtos = append(dtos, dto)
}
writeJSON(w, 200, map[string]any{"tasks": dtos, "active": active})