diff --git a/src/frontend/src/components/TaskModal.tsx b/src/frontend/src/components/TaskModal.tsx index 596b3e9..ac72ec0 100644 --- a/src/frontend/src/components/TaskModal.tsx +++ b/src/frontend/src/components/TaskModal.tsx @@ -606,3 +606,59 @@ export default function TaskModal() { ); } + +// 项目归属选择器 +function ProjectSelector({ taskId, currentProject, projects }: { + taskId: string; currentProject: string | null; projects: Record; +}) { + const [moving, setMoving] = useState(false); + const pid = currentProject || ''; + const projName = projects[pid]?.name || pid || '未知项目'; + + const handleMove = async (targetPid: string) => { + if (targetPid === pid || !pid) return; + setMoving(true); + try { + const res = await fetch(`/api/projects/${pid}/tasks/${taskId}/move`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ target_project_id: targetPid }), + }); + if (res.ok) { + const toast = useStore.getState().toast; + toast(`✅ 已移动到 ${projects[targetPid]?.name || targetPid}`); + useStore.getState().loadV2Tasks(); + } else { + const d = await res.json(); + useStore.getState().toast(d.detail || '移动失败', 'err'); + } + } catch { + useStore.getState().toast('网络错误', 'err'); + } + setMoving(false); + }; + + const otherProjects = Object.entries(projects).filter(([p]) => p !== pid && !p.startsWith('_')); + + return ( + + + 📁 {projName} + + + + ); +}