From bda4db5e5bf945a298ec8b3440c2cffad56f4cae Mon Sep 17 00:00:00 2001 From: Xiaoxia AI Date: Tue, 16 Jun 2026 12:40:12 +0800 Subject: [PATCH] feat: add task creation form and detail page - CreateTaskForm component with validation - Task detail page with issue list - Integrated create form into projects page - Task name links to detail page - Added workspace_id parameter - Improved state management --- apps/web/app/components/CreateTaskForm.tsx | 200 +++++++++++++++++++ apps/web/app/projects/page.tsx | 28 ++- apps/web/app/tasks/[id]/page.tsx | 213 +++++++++++++++++++++ 3 files changed, 436 insertions(+), 5 deletions(-) create mode 100644 apps/web/app/components/CreateTaskForm.tsx create mode 100644 apps/web/app/tasks/[id]/page.tsx diff --git a/apps/web/app/components/CreateTaskForm.tsx b/apps/web/app/components/CreateTaskForm.tsx new file mode 100644 index 000000000..d130f9800 --- /dev/null +++ b/apps/web/app/components/CreateTaskForm.tsx @@ -0,0 +1,200 @@ +'use client'; + +import { useState } from 'react'; +import { useRouter } from 'next/navigation'; + +const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'; + +interface CreateTaskFormProps { + projectId: string; + workspaceId: string; + onSuccess?: () => void; + onCancel?: () => void; +} + +export default function CreateTaskForm({ projectId, workspaceId, onSuccess, onCancel }: CreateTaskFormProps) { + const router = useRouter(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const [formData, setFormData] = useState({ + name: '', + description: '', + priority: 'medium', + assignee_user_id: '', + parent_task_id: '', + }); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + setError(''); + + try { + const res = await fetch(`${API_BASE}/api/v1/project-management/tasks`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + project_id: projectId, + workspace_id: workspaceId, + ...formData, + }), + }); + + if (!res.ok) { + const data = await res.json(); + throw new Error(data.detail || '创建失败'); + } + + if (onSuccess) { + onSuccess(); + } else { + router.push('/projects'); + } + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + return ( +
+

新增任务

+ + {error && ( +
+ {error} +
+ )} + +
+ + setFormData({ ...formData, name: e.target.value })} + style={{ + width: '100%', + padding: '8px 12px', + border: '1px solid var(--border)', + borderRadius: '4px', + fontSize: '14px', + }} + placeholder="输入任务名称" + /> +
+ +
+ +