From c0096f9dcb05b0434b798e9338374ff633d71069 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sun, 17 May 2026 06:15:35 +0800 Subject: [PATCH] auto-sync: 2026-05-17 06:15:35 --- src/frontend/src/pages/TaskBoard.tsx | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/frontend/src/pages/TaskBoard.tsx diff --git a/src/frontend/src/pages/TaskBoard.tsx b/src/frontend/src/pages/TaskBoard.tsx new file mode 100644 index 0000000..138f554 --- /dev/null +++ b/src/frontend/src/pages/TaskBoard.tsx @@ -0,0 +1,74 @@ +// 任务看板页面 + +import React from 'react'; +import { useTasks } from '../hooks/useApi'; +import type { Task } from '../types'; + +interface Props { + projectId: string | null; + onSelectTask: (task: Task) => void; +} + +const STATUS_ORDER = ['pending', 'working', 'review', 'blocked', 'done', 'failed']; + +export function TaskBoard({ projectId, onSelectTask }: Props) { + const { tasks, loading, error, refresh } = useTasks(projectId); + + if (!projectId) { + return
请选择一个项目
; + } + + if (loading) return
加载中...
; + if (error) return
加载失败: {error}
; + + // 按状态分组 + const grouped: Record = {}; + for (const task of tasks) { + const status = task.status || 'pending'; + if (!grouped[status]) grouped[status] = []; + grouped[status].push(task); + } + + return ( +
+
+

任务看板

+ +
+ + {STATUS_ORDER.map(status => { + const statusTasks = grouped[status] || []; + if (statusTasks.length === 0) return null; + return ( +
+

+ {status} ({statusTasks.length}) +

+
+ {statusTasks.map(task => ( +
onSelectTask(task)} + > +
{task.title}
+
+ {status} + {task.assignee && 👤 {task.assignee}} + {task.risk_level && ⚠️ {task.risk_level}} +
+
+ ))} +
+
+ ); + })} + + {tasks.length === 0 && ( +
+

暂无任务。通过 API 或 CLI 创建任务。

+
+ )} +
+ ); +}