feat(tasks): 任务列表新增漏洞数量列,描述/目标列收窄
- 任务列表接口 TaskListMetricsAll 批量统计每任务的漏洞数(findings 表, 按 task_id),经 TaskDTO.findings 下发;列表页新增「漏洞」列,>0 高亮 - 描述/目标列宽 max-w-xs → max-w-40,目标列补 title 悬浮全文 - mock data/handler 同步补 findings 字段
This commit is contained in:
1 parent
9bc8d16a0b
commit
e65d3e5202
7 files changed
+27
-3
No files matched your search
+9
-1
@@ -1299,6 +1299,7 @@ type TaskListMetrics struct {
|
|||||||
LastActivity int64
|
LastActivity int64
|
||||||
Goals GoalCounts
|
Goals GoalCounts
|
||||||
RunningIntents int // kind='intent' 且 state='running' 的条数,即运行中 Worker 数
|
RunningIntents int // kind='intent' 且 state='running' 的条数,即运行中 Worker 数
|
||||||
|
Findings int // findings 表里该任务的漏洞条数
|
||||||
}
|
}
|
||||||
|
|
||||||
// TaskListMetricsAll returns list aggregates for every live task in one query.
|
// TaskListMetricsAll returns list aggregates for every live task in one query.
|
||||||
@@ -1314,7 +1315,8 @@ func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error) {
|
|||||||
COALESCE(latest_activity.created_at,0),
|
COALESCE(latest_activity.created_at,0),
|
||||||
COALESCE(goal_metrics.total,0),
|
COALESCE(goal_metrics.total,0),
|
||||||
COALESCE(goal_metrics.met,0),
|
COALESCE(goal_metrics.met,0),
|
||||||
COALESCE(intent_metrics.running,0)
|
COALESCE(intent_metrics.running,0),
|
||||||
|
COALESCE(finding_metrics.findings,0)
|
||||||
FROM tasks task
|
FROM tasks task
|
||||||
LEFT JOIN LATERAL (
|
LEFT JOIN LATERAL (
|
||||||
SELECT SUM(input_tokens) AS input_tokens,
|
SELECT SUM(input_tokens) AS input_tokens,
|
||||||
@@ -1342,6 +1344,11 @@ func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error) {
|
|||||||
FROM exploration_nodes
|
FROM exploration_nodes
|
||||||
WHERE exploration_id=task.exploration_id AND kind='intent' AND state='running'
|
WHERE exploration_id=task.exploration_id AND kind='intent' AND state='running'
|
||||||
) intent_metrics ON true
|
) intent_metrics ON true
|
||||||
|
LEFT JOIN LATERAL (
|
||||||
|
SELECT COUNT(*) AS findings
|
||||||
|
FROM findings
|
||||||
|
WHERE task_id=task.id
|
||||||
|
) finding_metrics ON true
|
||||||
WHERE task.deleted_at IS NULL`)
|
WHERE task.deleted_at IS NULL`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1361,6 +1368,7 @@ func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error) {
|
|||||||
&metrics.Goals.Total,
|
&metrics.Goals.Total,
|
||||||
&metrics.Goals.Met,
|
&metrics.Goals.Met,
|
||||||
&metrics.RunningIntents,
|
&metrics.RunningIntents,
|
||||||
|
&metrics.Findings,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ type TaskDTO struct {
|
|||||||
GoalsTotal int `json:"goals_total"`
|
GoalsTotal int `json:"goals_total"`
|
||||||
GoalsMet int `json:"goals_met"`
|
GoalsMet int `json:"goals_met"`
|
||||||
InFlight int `json:"in_flight"` // 运行中 Worker 数(state=running 的意图)
|
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
|
LLMProfileID *int64 `json:"llm_profile_id,omitempty"` // LLM profile used for this task; nil = default
|
||||||
LLMProfileIDs []int64 `json:"llm_profile_ids"`
|
LLMProfileIDs []int64 `json:"llm_profile_ids"`
|
||||||
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
|
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
|
||||||
|
|||||||
@@ -1040,6 +1040,7 @@ func (s *Server) listTasks(w http.ResponseWriter, r *http.Request) {
|
|||||||
dto.GoalsTotal = metric.Goals.Total
|
dto.GoalsTotal = metric.Goals.Total
|
||||||
dto.GoalsMet = metric.Goals.Met
|
dto.GoalsMet = metric.Goals.Met
|
||||||
dto.InFlight = metric.RunningIntents
|
dto.InFlight = metric.RunningIntents
|
||||||
|
dto.Findings = metric.Findings
|
||||||
dtos = append(dtos, dto)
|
dtos = append(dtos, dto)
|
||||||
}
|
}
|
||||||
writeJSON(w, 200, map[string]any{"tasks": dtos, "active": active})
|
writeJSON(w, 200, map[string]any{"tasks": dtos, "active": active})
|
||||||
|
|||||||
@@ -950,6 +950,7 @@ export default function TasksPage() {
|
|||||||
onSort={sortTasksBy}
|
onSort={sortTasksBy}
|
||||||
/>
|
/>
|
||||||
<TableHead className="text-center">目标进度</TableHead>
|
<TableHead className="text-center">目标进度</TableHead>
|
||||||
|
<TableHead className="text-center">漏洞</TableHead>
|
||||||
<TableHead className="text-center">运行中 Worker</TableHead>
|
<TableHead className="text-center">运行中 Worker</TableHead>
|
||||||
<SortableTaskHead
|
<SortableTaskHead
|
||||||
field="created"
|
field="created"
|
||||||
@@ -1193,7 +1194,7 @@ const TaskRow = React.memo(function TaskRow({
|
|||||||
{taskIsPinned(task) && <PinIcon className="text-primary size-4 shrink-0" aria-label="已置顶" />}
|
{taskIsPinned(task) && <PinIcon className="text-primary size-4 shrink-0" aria-label="已置顶" />}
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-muted-foreground max-w-xs">
|
<TableCell className="text-muted-foreground max-w-40">
|
||||||
<Link
|
<Link
|
||||||
href={`/function/tasks/detail?id=${encodeURIComponent(task.id)}`}
|
href={`/function/tasks/detail?id=${encodeURIComponent(task.id)}`}
|
||||||
className="block truncate rounded-sm hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
className="block truncate rounded-sm hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
@@ -1202,7 +1203,9 @@ const TaskRow = React.memo(function TaskRow({
|
|||||||
{task.description}
|
{task.description}
|
||||||
</Link>
|
</Link>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-muted-foreground max-w-xs truncate">{task.goal}</TableCell>
|
<TableCell className="text-muted-foreground max-w-40 truncate" title={task.goal}>
|
||||||
|
{task.goal}
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<StatusBadge domain="task" value={task.status} dot />
|
<StatusBadge domain="task" value={task.status} dot />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -1213,6 +1216,13 @@ const TaskRow = React.memo(function TaskRow({
|
|||||||
<span className="text-muted-foreground">—</span>
|
<span className="text-muted-foreground">—</span>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="text-center text-xs tabular-nums">
|
||||||
|
{task.findings && task.findings > 0 ? (
|
||||||
|
<span className="text-destructive font-medium">{task.findings}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-muted-foreground">0</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="text-center text-xs tabular-nums">
|
<TableCell className="text-center text-xs tabular-nums">
|
||||||
{task.in_flight && task.in_flight > 0 ? (
|
{task.in_flight && task.in_flight > 0 ? (
|
||||||
<span className="text-foreground font-medium">{task.in_flight}</span>
|
<span className="text-foreground font-medium">{task.in_flight}</span>
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export const tasks: Task[] = [
|
|||||||
paused: false,
|
paused: false,
|
||||||
active: true,
|
active: true,
|
||||||
in_flight: 3,
|
in_flight: 3,
|
||||||
|
findings: 4,
|
||||||
stalled: false,
|
stalled: false,
|
||||||
goals_total: 5,
|
goals_total: 5,
|
||||||
goals_met: 2,
|
goals_met: 2,
|
||||||
@@ -90,6 +91,7 @@ export const tasks: Task[] = [
|
|||||||
paused: false,
|
paused: false,
|
||||||
active: false,
|
active: false,
|
||||||
in_flight: 2,
|
in_flight: 2,
|
||||||
|
findings: 2,
|
||||||
stalled: false,
|
stalled: false,
|
||||||
goals_total: 4,
|
goals_total: 4,
|
||||||
goals_met: 1,
|
goals_met: 1,
|
||||||
|
|||||||
@@ -1192,6 +1192,7 @@ function route(m: string, path: string, seg: string[], q: URLSearchParams, b: Re
|
|||||||
paused: false,
|
paused: false,
|
||||||
active: true,
|
active: true,
|
||||||
in_flight: 0,
|
in_flight: 0,
|
||||||
|
findings: 0,
|
||||||
stalled: false,
|
stalled: false,
|
||||||
goals_total: 0,
|
goals_total: 0,
|
||||||
goals_met: 0,
|
goals_met: 0,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface Task {
|
|||||||
queued?: boolean;
|
queued?: boolean;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
in_flight?: number;
|
in_flight?: number;
|
||||||
|
findings?: number; // 该任务已登记的漏洞数
|
||||||
last_activity?: string;
|
last_activity?: string;
|
||||||
stalled?: boolean;
|
stalled?: boolean;
|
||||||
goals_total?: number;
|
goals_total?: number;
|
||||||
|
|||||||
Reference in new issue
Block a user