fix: 概览耗时显示精确到时分 + 总耗时含加班
1. 开始日期/实际截止显示精确到分钟: - 开始:取所有阶段最早时间 slice(0,16) - 实际截止:取所有阶段最晚完成时间 slice(0,16) - 格式如"2025-06-15 14:30" 2. 总耗时包含加班时长: - 显示"已耗时 X 天(含加班 Yh)" - 加班时长从 overtime records 实时汇总 - 无加班时不显示加班部分 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -396,7 +396,7 @@ export default function VersionDetailPage() {
|
|||||||
});
|
});
|
||||||
vDTs.forEach((t) => { if (t.startDate) startDates.push(t.startDate); });
|
vDTs.forEach((t) => { if (t.startDate) startDates.push(t.startDate); });
|
||||||
vTCsAll.forEach((c) => { if (c.startedAt) startDates.push(c.startedAt); });
|
vTCsAll.forEach((c) => { if (c.startedAt) startDates.push(c.startedAt); });
|
||||||
const actualStart = startDates.length > 0 ? startDates.sort()[0].slice(0, 10) : (version.startDate ?? null);
|
const actualStart = startDates.length > 0 ? startDates.sort()[0].slice(0, 16).replace('T', ' ') : (version.startDate ?? null);
|
||||||
|
|
||||||
// 实际截止日期
|
// 实际截止日期
|
||||||
const endDates: string[] = [];
|
const endDates: string[] = [];
|
||||||
@@ -404,15 +404,19 @@ export default function VersionDetailPage() {
|
|||||||
vDTs.forEach((t) => { if (t.completedAt) endDates.push(t.completedAt); });
|
vDTs.forEach((t) => { if (t.completedAt) endDates.push(t.completedAt); });
|
||||||
vTCsAll.forEach((c) => { if (c.completedAt) endDates.push(c.completedAt); });
|
vTCsAll.forEach((c) => { if (c.completedAt) endDates.push(c.completedAt); });
|
||||||
vBugsAll.forEach((b) => { if (b.closedAt) endDates.push(b.closedAt); });
|
vBugsAll.forEach((b) => { if (b.closedAt) endDates.push(b.closedAt); });
|
||||||
const actualEnd = endDates.length > 0 ? endDates.sort().reverse()[0].slice(0, 10) : null;
|
const actualEnd = endDates.length > 0 ? endDates.sort().reverse()[0].slice(0, 16).replace('T', ' ') : null;
|
||||||
|
|
||||||
// 逾期天数
|
// 逾期天数
|
||||||
const deadline = version.expectedReleaseDate;
|
const deadline = version.expectedReleaseDate;
|
||||||
let overdueDays = 0;
|
let overdueDays = 0;
|
||||||
if (deadline && actualEnd) {
|
if (deadline && actualEnd) {
|
||||||
overdueDays = Math.floor((new Date(actualEnd).getTime() - new Date(deadline).getTime()) / (1000 * 60 * 60 * 24));
|
overdueDays = Math.floor((new Date(actualEnd.replace(' ', 'T')).getTime() - new Date(deadline).getTime()) / (1000 * 60 * 60 * 24));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 总耗时 = 日历天数 + 加班时长
|
||||||
|
const versionOTForTime = records.filter((r) => r.versionId === version.id);
|
||||||
|
const otHoursTotal = Math.round(versionOTForTime.reduce((sum, r) => sum + r.duration, 0) * 10) / 10;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-2 text-[13px]">
|
<div className="flex flex-wrap items-center gap-x-4 gap-y-2 text-[13px]">
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
@@ -436,6 +440,9 @@ export default function VersionDetailPage() {
|
|||||||
<div className="flex items-center gap-1.5 text-[var(--ink-soft)]">
|
<div className="flex items-center gap-1.5 text-[var(--ink-soft)]">
|
||||||
<Clock className="h-3.5 w-3.5 text-[var(--ink-muted)]" />
|
<Clock className="h-3.5 w-3.5 text-[var(--ink-muted)]" />
|
||||||
已耗时 <span className="font-medium text-[var(--ink)]">{elapsedDays}</span> 天
|
已耗时 <span className="font-medium text-[var(--ink)]">{elapsedDays}</span> 天
|
||||||
|
{otHoursTotal > 0 && (
|
||||||
|
<span className="text-[var(--ink-muted)]">(含加班 <span className="font-medium text-orange-600">{otHoursTotal}h</span>)</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user