diff --git a/src/api/project_routes.py b/src/api/project_routes.py index 1013192..89866a1 100644 --- a/src/api/project_routes.py +++ b/src/api/project_routes.py @@ -80,3 +80,38 @@ async def update_project(project_id: str, body: Dict[str, Any]): if not reg.update_project(project_id, **updates): raise HTTPException(404, f"Project not found: {project_id}") return {"ok": True} + + +@router.post("/{project_id}/tasks/{task_id}/move") +async def move_task(project_id: str, task_id: str, body: Dict[str, Any]): + """移动任务到另一个项目""" + target_project = body.get("target_project_id") + if not target_project: + raise HTTPException(422, "Missing target_project_id") + + reg = _registry() + # 验证目标项目存在 + target = reg.get_project(target_project) + if not target or target.get("status") not in ("active",): + raise HTTPException(404, f"Target project not found: {target_project}") + + # 从源项目读任务 + from src.blackboard.db import Blackboard + src_bb = Blackboard(Path(reg.root) / project_id / "blackboard.db") + task = src_bb.get_task(task_id) + if not task: + raise HTTPException(404, f"Task not found: {task_id}") + + # 写入目标项目 + tgt_bb = Blackboard(Path(reg.root) / target_project / "blackboard.db") + task_data = {k: getattr(task, k) for k in [ + "id", "title", "description", "status", "assignee", "assigned_by", + "priority", "task_type", "risk_level", "parent_task", "stage", + "depends_on", "stages_json", + ] if getattr(task, k, None) is not None} + tgt_bb.create_task_from_dict(task_data) + + # 从源项目删除(归档式删除) + src_bb.update_task_status(task_id, "cancelled") + + return {"ok": True, "moved_to": target_project}