auto-sync: 2026-05-17 06:15:35
This commit is contained in:
@@ -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 <div className="loading">请选择一个项目</div>;
|
||||
}
|
||||
|
||||
if (loading) return <div className="loading">加载中...</div>;
|
||||
if (error) return <div className="error">加载失败: {error}</div>;
|
||||
|
||||
// 按状态分组
|
||||
const grouped: Record<string, Task[]> = {};
|
||||
for (const task of tasks) {
|
||||
const status = task.status || 'pending';
|
||||
if (!grouped[status]) grouped[status] = [];
|
||||
grouped[status].push(task);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
||||
<h2 className="page-title">任务看板</h2>
|
||||
<button className="btn" onClick={refresh}>刷新</button>
|
||||
</div>
|
||||
|
||||
{STATUS_ORDER.map(status => {
|
||||
const statusTasks = grouped[status] || [];
|
||||
if (statusTasks.length === 0) return null;
|
||||
return (
|
||||
<div key={status} style={{ marginBottom: 20 }}>
|
||||
<h3 style={{ fontSize: 14, color: 'var(--muted)', marginBottom: 8, textTransform: 'uppercase' }}>
|
||||
{status} ({statusTasks.length})
|
||||
</h3>
|
||||
<div className="task-board">
|
||||
{statusTasks.map(task => (
|
||||
<div
|
||||
key={task.id}
|
||||
className="task-card"
|
||||
onClick={() => onSelectTask(task)}
|
||||
>
|
||||
<div className="title">{task.title}</div>
|
||||
<div className="meta">
|
||||
<span className={`badge badge-${status}`}>{status}</span>
|
||||
{task.assignee && <span>👤 {task.assignee}</span>}
|
||||
{task.risk_level && <span>⚠️ {task.risk_level}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{tasks.length === 0 && (
|
||||
<div className="card">
|
||||
<p style={{ color: 'var(--muted)' }}>暂无任务。通过 API 或 CLI 创建任务。</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user