fix(dev-task): 体验优化 — 新建弹窗默认值+详情卡片分区+筛选分页+胶囊联动

- 新建弹窗:负责人默认当前用户,提示版本截止日期,超期需填写原因
- 详情抽屉:重写为卡片分区布局,展示关联需求,状态流转按钮醒目化
- 详情实时更新:改为从 store 实时读取而非 prop 快照
- 列表增加筛选:负责人/状态/阻塞/任务类型 + 分页(每页20条)
- 工时展示:列表行显示 实际Xh / 预计Yh 格式
- 概览胶囊联动:dev 阶段进度由 DevTask 完成度驱动
- 概览统计卡片:替换 mock 为真实 DevTask 数据(待开发/开发中/阻塞中)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-11 18:51:33 +08:00
parent a560634091
commit d619846b93
6 changed files with 274 additions and 97 deletions

View File

@@ -19,7 +19,9 @@ import { VersionRequirementsTab } from '@/components/version/VersionRequirements
import { PlanTab } from '@/components/version/PlanTab';
import { DevTaskTab } from '@/components/dev-task/DevTaskTab';
import { useVersionPlanStore } from '@/stores/useVersionPlanStore';
import { useDevTaskStore } from '@/stores/useDevTaskStore';
import { useAuthStore } from '@/stores/useAuthStore';
import { calcGroupProgress as calcDevTaskProgress } from '@/lib/dev-task';
const PRIORITY_STYLE: Record<string, string> = {
P0: 'bg-red-500/10 text-red-600',
@@ -48,6 +50,7 @@ export default function VersionDetailPage() {
const { requirements, fetchRequirements, updateRequirement } = useRequirementStore();
const { records, fetchRecords } = useOvertimeStore();
const { plans, fetchPlans, createPlan, updatePlan, completePlan, deletePlan } = useVersionPlanStore();
const { tasks: devTasks, fetchTasks: fetchDevTasks } = useDevTaskStore();
const user = useAuthStore((s) => s.user);
const [activeTab, setActiveTab] = useState('overview');
@@ -55,6 +58,7 @@ export default function VersionDetailPage() {
useEffect(() => { fetchRequirements(); }, [fetchRequirements]);
useEffect(() => { fetchRecords(); }, [fetchRecords]);
useEffect(() => { fetchPlans(); }, [fetchPlans]);
useEffect(() => { fetchDevTasks(); }, [fetchDevTasks]);
const version = useMemo(() => getVersionDetail(overview, versionId), [overview, versionId]);
@@ -177,11 +181,13 @@ export default function VersionDetailPage() {
const reasonRanking = Object.entries(reasonMap).sort((a, b) => b[1] - a[1]);
const reasonTotal = reasonRanking.reduce((s, [, v]) => s + v, 0) || 1;
// Mock 数据占位
const mockTaskCount = Math.max(versionReqs.length * 2, 3);
// DevTask 真实统计
const versionDevTasks = devTasks.filter((t) => versionReqs.some((r) => r.id === t.requirementId));
const devTaskTodo = versionDevTasks.filter((t) => t.status === 'todo').length;
const devTaskInProgress = versionDevTasks.filter((t) => t.status === 'in_progress').length;
const devTaskBlocked = versionDevTasks.filter((t) => t.isBlocked).length;
const mockBugTotal = Math.max(Math.floor(versionReqs.length * 1.5), 2);
const mockBugOpen = Math.max(Math.floor(mockBugTotal * 0.3), 1);
const mockTaskPending = Math.max(Math.floor(mockTaskCount * 0.4), 1);
return (
<div className="space-y-4">
@@ -213,9 +219,9 @@ export default function VersionDetailPage() {
<div className="grid grid-cols-6 gap-3">
<StatCard label="加班时长" value={`${totalOTHours}h`} accent />
<StatCard label="关联需求" value={versionReqs.length} />
<StatCard label="待开发任务" value={mockTaskPending} />
<StatCard label="BUG总数" value={mockBugTotal} />
<StatCard label="未解决BUG" value={mockBugOpen} warn />
<StatCard label="待开发" value={devTaskTodo} />
<StatCard label="开发中" value={devTaskInProgress} accent />
<StatCard label="阻塞中" value={devTaskBlocked} warn={devTaskBlocked > 0} />
<StatCard label="参与人员" value={version.members?.length ?? 0} />
</div>
@@ -285,6 +291,14 @@ export default function VersionDetailPage() {
if (productPlans.length > 0) stageProgress['product_design'] = { percent: calcGroupProgress(productPlans, 'product'), daysSpent: calcDays(productPlans) };
if (uiPlans.length > 0) stageProgress['ui_design'] = { percent: calcGroupProgress(uiPlans, 'ui'), daysSpent: calcDays(uiPlans) };
// 开发阶段进度由 DevTask 驱动
if (versionDevTasks.length > 0) {
const devProgress = calcDevTaskProgress(versionDevTasks);
const devStart = versionDevTasks.reduce((min, t) => t.startDate && t.startDate < min ? t.startDate : min, today);
const devDays = devStart <= today ? Math.max(1, Math.ceil((new Date(today).getTime() - new Date(devStart).getTime()) / (1000 * 60 * 60 * 24))) : 0;
stageProgress['dev'] = { percent: devProgress, daysSpent: devDays };
}
return <CapsuleStages currentStage={version.currentStage} progress={version.progress} stageProgress={stageProgress} />;
})()}
@@ -458,6 +472,7 @@ export default function VersionDetailPage() {
<DevTaskTab
versionId={version.id}
requirementIds={versionReqs.map((r) => r.id)}
versionDeadline={version.expectedReleaseDate ?? undefined}
/>
);
})()