diff --git a/apps/web/app/workspace/page.tsx b/apps/web/app/workspace/page.tsx index ed52ed8..d117e2f 100644 --- a/apps/web/app/workspace/page.tsx +++ b/apps/web/app/workspace/page.tsx @@ -39,11 +39,11 @@ const PLAN_STATUS_LABEL: Record = { pending: '未开始', in_pro export default function WorkspacePage() { const router = useRouter(); const { overview, fetchOverview } = useProductStore(); - const { plans, fetchPlans } = useVersionPlanStore(); + const { plans, fetchPlans, updatePlan } = useVersionPlanStore(); const { requirements, fetchRequirements } = useRequirementStore(); - const { tasks: devTasks, fetchTasks } = useDevTaskStore(); - const { testCases, fetchTestCases } = useTestCaseStore(); - const { bugs, fetchBugs } = useBugStore(); + const { tasks: devTasks, fetchTasks, updateTask } = useDevTaskStore(); + const { testCases, fetchTestCases, updateTestCase } = useTestCaseStore(); + const { bugs, fetchBugs, updateBug } = useBugStore(); const user = useAuthStore((s) => s.user); const [activeTab, setActiveTab] = useState('all'); const [showCompleted, setShowCompleted] = useState(true); @@ -121,10 +121,31 @@ export default function WorkspacePage() { const pendingCount = pendingByTab.all; const completedCount = (selectedVersionId ? workItems.filter((i) => i.versionId === selectedVersionId) : workItems).filter((i) => i.completed).length; + const handleItemAction = (item: WorkItem, action: string) => { + if (item.type === 'plan_research' || item.type === 'plan_product' || item.type === 'plan_ui') { + if (action === 'start') updatePlan(item.id, { status: 'in_progress' }); + if (action === 'complete') updatePlan(item.id, { status: 'completed', completedAt: new Date().toISOString() }); + } + if (item.type === 'devTask') { + if (action === 'start') updateTask(item.id, { status: 'in_progress' }); + if (action === 'testing') updateTask(item.id, { status: 'testing' }); + if (action === 'submit') updateTask(item.id, { status: 'submitted', completedAt: new Date().toISOString() }); + } + if (item.type === 'testCase') { + if (action === 'pass') updateTestCase(item.id, { status: 'passed', completedAt: new Date().toISOString() }); + if (action === 'fail') updateTestCase(item.id, { status: 'failed' }); + } + if (item.type === 'bug') { + if (action === 'fix') updateBug(item.id, { status: 'fixing' }); + if (action === 'fixed') updateBug(item.id, { status: 'fixed' }); + if (action === 'close') updateBug(item.id, { status: 'closed', closedAt: new Date().toISOString() }); + } + }; + return (
{/* 左侧第一列:产品/项目/版本树 */} -
+

与我相关

@@ -146,7 +167,7 @@ export default function WorkspacePage() {
{/* 左侧第二列:环节分类 */} -
+
待办 {pendingCount} @@ -201,7 +222,12 @@ export default function WorkspacePage() { ) : (
{filteredItems.map((item) => ( - item.versionId && router.push(`/versions/${item.versionId}`)} /> + item.versionId && router.push(`/versions/${item.versionId}`)} + onAction={(action) => handleItemAction(item, action)} + /> ))}
)} @@ -261,8 +287,9 @@ function ProjectNode({ name, versions, selectedVersionId, onSelect }: { ); } -function WorkItemCard({ item, onNavigate }: { item: WorkItem; onNavigate: () => void }) { +function WorkItemCard({ item, onNavigate, onAction }: { item: WorkItem; onNavigate: () => void; onAction: (action: string) => void }) { const statusBadge = getStatusBadge(item); + const actions = getActions(item); return (
@@ -282,6 +309,16 @@ function WorkItemCard({ item, onNavigate }: { item: WorkItem; onNavigate: () => {BUG_SEVERITY_LABEL[item.extra.severity as keyof typeof BUG_SEVERITY_LABEL] || ''} )} + {/* 操作按钮 */} + {actions.length > 0 && ( +
+ {actions.map((a) => ( + + ))} +
+ )} @@ -299,6 +336,34 @@ function WorkItemCard({ item, onNavigate }: { item: WorkItem; onNavigate: () => ); } +function getActions(item: WorkItem): { key: string; label: string; style: string }[] { + if (item.completed) return []; + + if (item.type === 'plan_research' || item.type === 'plan_product' || item.type === 'plan_ui') { + if (item.status === 'pending') return [{ key: 'start', label: '开始', style: 'text-blue-600 hover:bg-blue-50 border border-blue-200' }]; + if (item.status === 'in_progress') return [{ key: 'complete', label: '完成', style: 'text-emerald-600 hover:bg-emerald-50 border border-emerald-200' }]; + } + if (item.type === 'devTask') { + if (item.status === 'todo') return [{ key: 'start', label: '开始', style: 'text-blue-600 hover:bg-blue-50 border border-blue-200' }]; + if (item.status === 'in_progress') return [{ key: 'testing', label: '提测', style: 'text-purple-600 hover:bg-purple-50 border border-purple-200' }]; + if (item.status === 'testing') return [{ key: 'submit', label: '完成', style: 'text-emerald-600 hover:bg-emerald-50 border border-emerald-200' }]; + } + if (item.type === 'testCase') { + if (item.status === 'pending' || item.status === 'running' || item.status === 'failed') { + return [ + { key: 'pass', label: '通过', style: 'text-emerald-600 hover:bg-emerald-50 border border-emerald-200' }, + { key: 'fail', label: '失败', style: 'text-red-600 hover:bg-red-50 border border-red-200' }, + ]; + } + } + if (item.type === 'bug') { + if (item.status === 'open') return [{ key: 'fix', label: '修复中', style: 'text-blue-600 hover:bg-blue-50 border border-blue-200' }]; + if (item.status === 'fixing') return [{ key: 'fixed', label: '已修复', style: 'text-purple-600 hover:bg-purple-50 border border-purple-200' }]; + if (item.status === 'fixed' || item.status === 'verifying') return [{ key: 'close', label: '关闭', style: 'text-emerald-600 hover:bg-emerald-50 border border-emerald-200' }]; + } + return []; +} + function getStatusBadge(item: WorkItem) { if (item.type === 'devTask') { return (