fix: 调研/产品/UI 实际耗时改为精确时间戳显示和计算

- PlanTab 自动进入"进行中"时调用 onUpdate 记录 actualStartAt
- 显示实际开始时间和完成时间(精确到分钟)
- calcPlanDuration 改为用时间差计算小时数(精确到0.5h)
- formatDuration 显示小时而非天数

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-12 16:32:50 +08:00
parent da1f98968b
commit 7af9206bec
2 changed files with 22 additions and 12 deletions

View File

@@ -55,13 +55,20 @@ export function PlanTab({ plans, versionId, versionDeadline, currentUserName, pl
) : ( ) : (
<div className="space-y-3"> <div className="space-y-3">
{typePlans.map((plan) => { {typePlans.map((plan) => {
// 已耗时已完成用实际完成时间进行中用当前时间未开始为0 const now = new Date().toISOString();
const now = new Date().toISOString().slice(0, 10); const nowDate = now.slice(0, 10);
const effectiveStatus = plan.status === 'pending' && plan.startTime <= now ? 'in_progress' : plan.status; // 自动进入进行中(到了计划开始日期)
const dur = effectiveStatus === 'completed' && plan.completedAt const shouldAutoStart = plan.status === 'pending' && plan.startTime <= nowDate;
? calcPlanDuration(plan.startTime, plan.completedAt) if (shouldAutoStart && !plan.actualStartAt) {
: effectiveStatus === 'in_progress' onUpdate(plan.id, { status: 'in_progress' });
? calcPlanDuration(plan.startTime, now) }
const effectiveStatus = shouldAutoStart ? 'in_progress' : plan.status;
// 耗时用实际时间戳计算
const actualStart = plan.actualStartAt || (shouldAutoStart ? now : null);
const dur = effectiveStatus === 'completed' && plan.completedAt && actualStart
? calcPlanDuration(actualStart, plan.completedAt)
: effectiveStatus === 'in_progress' && actualStart
? calcPlanDuration(actualStart, now)
: { days: 0, hours: 0 }; : { days: 0, hours: 0 };
const durText = dur.days > 0 || dur.hours > 0 ? formatDuration(dur.days, dur.hours) : '-'; const durText = dur.days > 0 || dur.hours > 0 ? formatDuration(dur.days, dur.hours) : '-';
return ( return (
@@ -76,7 +83,8 @@ export function PlanTab({ plans, versionId, versionDeadline, currentUserName, pl
</div> </div>
<div className="flex items-center gap-4 text-[12px] text-[var(--ink-soft)]"> <div className="flex items-center gap-4 text-[12px] text-[var(--ink-soft)]">
<span>{plan.startTime.slice(0, 10)} {plan.endTime.slice(0, 10)}</span> <span>{plan.startTime.slice(0, 10)} {plan.endTime.slice(0, 10)}</span>
{plan.completedAt && <span className="text-green-600">{plan.completedAt.slice(0, 10)}</span>} {plan.actualStartAt && <span className="text-blue-600">{plan.actualStartAt.slice(0, 16).replace('T', ' ')}</span>}
{plan.completedAt && <span className="text-green-600">{plan.completedAt.slice(0, 16).replace('T', ' ')}</span>}
<span className="font-medium text-[var(--ink)]"> {durText}</span> <span className="font-medium text-[var(--ink)]"> {durText}</span>
</div> </div>
{plan.overdueReason && ( {plan.overdueReason && (

View File

@@ -48,12 +48,14 @@ export function calcPlanDuration(start: string, end: string): { days: number; ho
const s = new Date(start).getTime(); const s = new Date(start).getTime();
const e = new Date(end).getTime(); const e = new Date(end).getTime();
if (isNaN(s) || isNaN(e) || e < s) return { days: 0, hours: 0 }; if (isNaN(s) || isNaN(e) || e < s) return { days: 0, hours: 0 };
const diff = Math.ceil((e - s) / (1000 * 60 * 60 * 24)); const diffHours = (e - s) / (1000 * 60 * 60);
const totalDays = Math.max(1, diff); // 当天开始当天结束至少1天 const hours = Math.round(diffHours * 2) / 2; // 精确到0.5h
return { days: totalDays, hours: totalDays * 8 }; const days = Math.ceil(diffHours / 24);
return { days, hours };
} }
export function formatDuration(days: number, _hours: number): string { export function formatDuration(days: number, hours: number): string {
if (hours > 0) return `${hours}h`;
if (days === 0) return '0天'; if (days === 0) return '0天';
return `${days}`; return `${days}`;
} }