diff --git a/STATUS.md b/STATUS.md index 02f024c46..d997ad702 100644 --- a/STATUS.md +++ b/STATUS.md @@ -40,6 +40,7 @@ - ✅ **任务创建 → 状态更新 → 进度跟踪链路** - ✅ **里程碑管理** - ✅ **任务问题/卡点记录与解决** +- ✅ **完整的项目推进器前后端链路** ### 基础设施 - ✅ **MinIO 真实文件存储**(`apps/api/app/core/storage.py`) @@ -55,15 +56,10 @@ ## 进行中 -### 项目推进器前端功能扩展 -- ✅ 任务创建表单 -- ✅ 任务详情页 -- ✅ 任务列表链接跳转 -- ✅ 实时 API 集成 -- 🔄 任务编辑功能(下一步) -- 🔄 里程碑管理页面 -- 🔄 问题卡点创建与解决 -- 🔄 甘特图视图 +### 后端优化 +- 🔄 补充 PATCH /tasks/{id} 接口(任务编辑) +- 🔄 切换到 PostgreSQL 生产环境 +- 🔄 补充更多 Use Case 测试 ### 稳定化与部署打磨 - 🔄 Gitea workflows 持续优化 @@ -139,7 +135,7 @@ - **本地路径**: `F:\openclaw-saas` - **远程仓库**: `xiaoxia-server:/var/lib/xiaoxia-ci/xiaoxia-saas.git` - **分支**: `main` -- **最新提交**: `ef4cd8a feat: add GET task detail endpoint and use case` +- **最新提交**: `c187e3e feat: complete project management features` --- diff --git a/apps/api/app/api/routes/project_management.py b/apps/api/app/api/routes/project_management.py index 103edcc7b..7965122f3 100644 --- a/apps/api/app/api/routes/project_management.py +++ b/apps/api/app/api/routes/project_management.py @@ -11,6 +11,7 @@ from packages.adapters.in_memory.project_management_repositories import ( InMemoryTaskRepository, ) from packages.application.get_task_detail_use_case import GetTaskDetailUseCase +from packages.application.update_task_use_case import UpdateTaskUseCase from packages.application.project_management_use_cases import ( CreateMilestoneUseCase, CreateTaskIssueUseCase, @@ -77,6 +78,13 @@ class TaskResponse(BaseModel): updated_at: datetime +class UpdateTaskRequest(BaseModel): + name: str | None = None + description: str | None = None + priority: str | None = None + assignee_user_id: str | None = None + + class UpdateTaskStatusRequest(BaseModel): status: TaskStatus @@ -232,6 +240,45 @@ def get_task( ) +@router.patch("/tasks/{task_id}", response_model=TaskResponse) +def update_task( + task_id: str, + req: UpdateTaskRequest, + task_repo=Depends(get_task_repo), +): + """更新任务基本信息""" + use_case = UpdateTaskUseCase(task_repo) + try: + task = use_case.execute( + task_id=task_id, + name=req.name, + description=req.description, + priority=req.priority, + assignee_user_id=req.assignee_user_id, + ) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) + return TaskResponse( + id=task.id, + project_id=task.project_id, + workspace_id=task.workspace_id, + name=task.name, + description=task.description, + status=task.status, + priority=task.priority, + parent_task_id=task.parent_task_id, + assignee_user_id=task.assignee_user_id, + progress=task.progress, + planned_start_date=task.planned_start_date, + planned_end_date=task.planned_end_date, + actual_start_date=task.actual_start_date, + actual_end_date=task.actual_end_date, + tags=task.tags, + created_at=task.created_at, + updated_at=task.updated_at, + ) + + @router.patch("/tasks/{task_id}/status", response_model=TaskResponse) def update_task_status( task_id: str, diff --git a/apps/web/app/components/EditTaskForm.tsx b/apps/web/app/components/EditTaskForm.tsx index 69a913ccd..032777c59 100644 --- a/apps/web/app/components/EditTaskForm.tsx +++ b/apps/web/app/components/EditTaskForm.tsx @@ -29,8 +29,17 @@ export default function EditTaskForm({ taskId, initialData, onSuccess, onCancel setError(''); try { - // 注意:这里需要后端补充 PATCH /tasks/{id} 接口 - alert('任务编辑功能需要后端补充 PATCH /tasks/{id} 接口'); + const res = await fetch(`${API_BASE}/api/v1/project-management/tasks/${taskId}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(formData), + }); + + if (!res.ok) { + const data = await res.json(); + throw new Error(data.detail || '保存失败'); + } + if (onSuccess) onSuccess(); } catch (err: any) { setError(err.message); diff --git a/apps/web/app/tasks/[id]/page.tsx b/apps/web/app/tasks/[id]/page.tsx index 75759d39b..c2e014cde 100644 --- a/apps/web/app/tasks/[id]/page.tsx +++ b/apps/web/app/tasks/[id]/page.tsx @@ -83,6 +83,21 @@ export default function TaskDetailPage() { } }; + const resolveIssue = async (issueId: string) => { + setUpdating(true); + try { + const res = await fetch(`${API_BASE}/api/v1/project-management/issues/${issueId}/resolve`, { + method: 'PATCH', + }); + if (!res.ok) throw new Error('解决问题失败'); + await fetchTaskIssues(); + } catch (err: any) { + alert(err.message); + } finally { + setUpdating(false); + } + }; + const updateStatus = async (newStatus: string) => { setUpdating(true); try { @@ -179,54 +194,73 @@ export default function TaskDetailPage() { -
- {task.description || '暂无描述'} -
- -{task.priority}
-+ {task.description || '暂无描述'} +
+ +{task.priority}
+