refactor: 胶囊条改为纯进度展示,去掉"当前阶段"和"阶段耗时"
胶囊条 CapsuleStages 重构: - 去掉 currentStage/progress 旧 props - 每段只显示进度百分比 + 状态颜色(idle/active/done) - 支持并行阶段(多个可同时 active) - 数据由实际 PlanTask/DevTask/TestCase 状态驱动 进度数据来源: - 调研:任务完成数 / 总数 - 产品/UI:需求完成数 / 关联数 - 开发:DevTask 进度(STATUS_PROGRESS 加权) - 测试:已执行用例 / 总用例 版本列表页: - 去掉"当前阶段"和"阶段进度"两列 - 替换为"状态"列(显示版本状态标签) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -314,38 +314,38 @@ export default function VersionDetailPage() {
|
||||
return totals.total > 0 ? Math.round((totals.done / totals.total) * 100) : 0;
|
||||
};
|
||||
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const calcDays = (group: typeof vPlans) => {
|
||||
if (group.length === 0) return 0;
|
||||
const starts = group.map((p) => p.startTime).sort();
|
||||
const startDate = starts[0];
|
||||
if (startDate > today) return 0;
|
||||
const diff = Math.ceil((new Date(today).getTime() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24));
|
||||
return Math.max(1, diff); // 当天开始至少算1天
|
||||
const getPlanStatus = (group: typeof vPlans): 'idle' | 'active' | 'done' => {
|
||||
if (group.length === 0) return 'idle';
|
||||
if (group.every((p) => p.status === 'completed')) return 'done';
|
||||
if (group.some((p) => p.status === 'in_progress')) return 'active';
|
||||
return 'idle';
|
||||
};
|
||||
|
||||
const stageProgress: Record<string, { percent: number; daysSpent: number }> = {};
|
||||
if (researchPlans.length > 0) stageProgress['requirement'] = { percent: calcGroupProgress(researchPlans, 'research'), daysSpent: calcDays(researchPlans) };
|
||||
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) };
|
||||
type StageProgressItem = { percent: number; status: 'idle' | 'active' | 'done' };
|
||||
const stageProgress: Partial<Record<string, StageProgressItem>> = {};
|
||||
|
||||
// 开发阶段进度由 DevTask 驱动
|
||||
if (researchPlans.length > 0) stageProgress['requirement'] = { percent: calcGroupProgress(researchPlans, 'research'), status: getPlanStatus(researchPlans) };
|
||||
if (productPlans.length > 0) stageProgress['product_design'] = { percent: calcGroupProgress(productPlans, 'product'), status: getPlanStatus(productPlans) };
|
||||
if (uiPlans.length > 0) stageProgress['ui_design'] = { percent: calcGroupProgress(uiPlans, 'ui'), status: getPlanStatus(uiPlans) };
|
||||
|
||||
// 开发阶段
|
||||
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 };
|
||||
const allSubmitted = versionDevTasks.every((t) => t.status === 'submitted');
|
||||
const hasActive = versionDevTasks.some((t) => t.status === 'in_progress' || t.status === 'testing');
|
||||
stageProgress['dev'] = { percent: devProgress, status: allSubmitted ? 'done' : hasActive ? 'active' : 'idle' };
|
||||
}
|
||||
|
||||
// 测试阶段进度由 TestCase 完成率驱动
|
||||
const versionTestCases = testCases.filter((c) => c.versionId === version.id);
|
||||
if (versionTestCases.length > 0) {
|
||||
const executed = versionTestCases.filter((c) => c.status === 'passed' || c.status === 'failed' || c.status === 'blocked').length;
|
||||
const testPercent = Math.round((executed / versionTestCases.length) * 100);
|
||||
stageProgress['testing'] = { percent: testPercent, daysSpent: 0 };
|
||||
// 测试阶段
|
||||
if (versionTCs.length > 0) {
|
||||
const executed = versionTCs.filter((c) => c.status === 'passed' || c.status === 'failed' || c.status === 'blocked').length;
|
||||
const testPercent = Math.round((executed / versionTCs.length) * 100);
|
||||
const allPassed = versionTCs.every((c) => c.status === 'passed');
|
||||
const hasRunning = versionTCs.some((c) => c.status === 'running');
|
||||
stageProgress['testing'] = { percent: testPercent, status: allPassed ? 'done' : (hasRunning || executed > 0) ? 'active' : 'idle' };
|
||||
}
|
||||
|
||||
return <CapsuleStages currentStage={version.currentStage} progress={version.progress} stageProgress={stageProgress} />;
|
||||
return <CapsuleStages stageProgress={stageProgress as any} />;
|
||||
})()}
|
||||
|
||||
{/* 双栏:加班排名 + 原因占比 */}
|
||||
|
||||
Reference in New Issue
Block a user