4
This commit is contained in:
2025-11-14 11:07:35 +08:00
parent 129ecfd92c
commit 7e76eb1fa7

View File

@ -128,6 +128,10 @@ export default function App() {
setTimelineVisible(false); setTimelineVisible(false);
setTimelineResults([]); setTimelineResults([]);
setTimelineAdjustments({}); setTimelineAdjustments({});
// 新增:重置固定缓冲期、实际完成日期以及一次性建议缓冲期应用标志
setBaseBufferDays(14);
setActualCompletionDates({});
setHasAppliedSuggestedBuffer(false);
setIsRestoringSnapshot(false); setIsRestoringSnapshot(false);
setRestoredRecordIds([]); setRestoredRecordIds([]);
setRestoredRecordIdsText(''); setRestoredRecordIdsText('');
@ -2744,6 +2748,8 @@ export default function App() {
// 添加快照还原状态标志 // 添加快照还原状态标志
const [isRestoringSnapshot, setIsRestoringSnapshot] = useState(false); const [isRestoringSnapshot, setIsRestoringSnapshot] = useState(false);
const [hasAppliedSuggestedBuffer, setHasAppliedSuggestedBuffer] = useState(false);
// 当起始时间变更时,重新以最新起始时间为基准重算全流程 // 当起始时间变更时,重新以最新起始时间为基准重算全流程
useEffect(() => { useEffect(() => {
if (timelineResults.length > 0 && !isRestoringSnapshot) { if (timelineResults.length > 0 && !isRestoringSnapshot) {
@ -2751,12 +2757,21 @@ export default function App() {
} }
}, [startTime, isRestoringSnapshot]); }, [startTime, isRestoringSnapshot]);
// 当实际完成日期变化时,以最新状态进行重算,避免首次选择不触发或使用旧值
useEffect(() => {
if (timelineResults.length > 0 && !isRestoringSnapshot) {
recalculateTimeline(timelineAdjustments, false);
}
}, [actualCompletionDates, isRestoringSnapshot]);
// 重置调整的函数 // 重置调整的函数
const resetTimelineAdjustments = () => { const resetTimelineAdjustments = () => {
setTimelineAdjustments({}); setTimelineAdjustments({});
setDeliveryMarginDeductions(0); // 同时重置交期余量扣减 setDeliveryMarginDeductions(0); // 同时重置交期余量扣减
setCompletionDateAdjustment(0); // 重置最后流程完成日期调整 setCompletionDateAdjustment(0); // 重置最后流程完成日期调整
setActualCompletionDates({}); // 重置实际完成日期 setActualCompletionDates({}); // 重置实际完成日期
setBaseBufferDays(14); // 重置固定缓冲期为默认值
setHasAppliedSuggestedBuffer(false); // 重置建议缓冲期应用标志
recalculateTimeline({}, true); // 强制重算所有节点 recalculateTimeline({}, true); // 强制重算所有节点
}; };
@ -5434,6 +5449,7 @@ export default function App() {
setTimelineAdjustments({}); // 关闭时重置调整 setTimelineAdjustments({}); // 关闭时重置调整
setDeliveryMarginDeductions(0); // 关闭时重置交期余量扣减 setDeliveryMarginDeductions(0); // 关闭时重置交期余量扣减
setCompletionDateAdjustment(0); // 关闭时重置最后流程完成日期调整 setCompletionDateAdjustment(0); // 关闭时重置最后流程完成日期调整
setHasAppliedSuggestedBuffer(false); // 关闭时允许下次重新应用建议缓冲期
}} }}
footer={ footer={
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
@ -5445,10 +5461,107 @@ export default function App() {
value={baseBufferDays} value={baseBufferDays}
onChange={(val) => { onChange={(val) => {
const n = Number(val); const n = Number(val);
setBaseBufferDays(Number.isFinite(n) && n >= 0 ? n : 0); setBaseBufferDays(Number.isFinite(n) && n >= 0 ? Math.ceil(n) : 0);
}} }}
style={{ width: 90 }} style={{ width: 90 }}
/> />
{/* 建议缓冲期增量:根据实际完成偏差与交期余量自动反算 */}
{(() => {
try {
// 计算节点总调整量与动态缓冲期
const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
const baseBuferDays = baseBufferDays;
const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
// 获取有效的最后流程完成日期
let effectiveLastProcess: any = null;
let lastCompletionDate: Date | null = null;
for (let i = timelineResults.length - 1; i >= 0; i--) {
const process = timelineResults[i];
const processDate = new Date(process.estimatedEnd);
if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
effectiveLastProcess = process;
lastCompletionDate = processDate;
break;
}
}
if (!effectiveLastProcess && timelineResults.length > 0) {
effectiveLastProcess = timelineResults[timelineResults.length - 1];
lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
}
// 基线计划(不考虑实际完成、也不考虑调整):使用原始时效值重算
const baseline = getRecalculatedTimeline({});
let baselineLast: Date | null = null;
for (let i = baseline.length - 1; i >= 0; i--) {
const p = baseline[i];
const d = new Date(p.estimatedEnd);
if (!isNaN(d.getTime()) && p.estimatedEnd !== '时效值为0') { baselineLast = d; break; }
}
if (!baselineLast && baseline.length > 0) {
const d = new Date(baseline[baseline.length - 1].estimatedEnd);
if (!isNaN(d.getTime())) baselineLast = d;
}
// 当前计划考虑实际完成使用现有timelineResults
let currentLast: Date | null = null;
for (let i = timelineResults.length - 1; i >= 0; i--) {
const p = timelineResults[i];
const d = new Date(p.estimatedEnd);
if (!isNaN(d.getTime()) && p.estimatedEnd !== '时效值为0') { currentLast = d; break; }
}
if (!currentLast && timelineResults.length > 0) {
const d = new Date(timelineResults[timelineResults.length - 1].estimatedEnd);
if (!isNaN(d.getTime())) currentLast = d;
}
// 建议口径1自然日偏差当前计划 vs 原始计划)扣除默认缓冲期
let suggestedInt = 0;
let slipDays = 0;
if (baselineLast && currentLast) {
const dayMs = 1000 * 60 * 60 * 24;
slipDays = Math.ceil((currentLast.getTime() - baselineLast.getTime()) / dayMs);
const deficitCalendar = Math.max(0, slipDays - baseBuferDays);
suggestedInt = Math.ceil(deficitCalendar);
}
// 建议口径2工作日总调整量仅统计 external 节点的天数调整)扣除默认缓冲期
const totalWorkingAdjustments = Object.entries(timelineAdjustments).reduce((sum, [k, adj]) => {
const i = parseInt(k, 10);
const method = timelineResults[i]?.calculationMethod || 'external';
const val = Number(adj) || 0;
return method === 'internal' ? sum : sum + val;
}, 0);
const deficitWorking = Math.max(0, totalWorkingAdjustments - baseBuferDays);
const suggestedByWorking = Math.ceil(deficitWorking);
// 取两种口径的较大值,避免出现工作日调整很大但自然日差较小的误差
suggestedInt = Math.max(suggestedInt, suggestedByWorking);
const displayInt = Math.max(0, suggestedInt);
if (displayInt > 0) {
return (
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Text style={{ color: '#fa8c16' }}>+{displayInt}</Text>
<Button
size="small"
disabled={hasAppliedSuggestedBuffer}
onClick={() => {
if (!hasAppliedSuggestedBuffer) {
setBaseBufferDays(Math.ceil(baseBufferDays) + displayInt);
setHasAppliedSuggestedBuffer(true);
}
}}
>
{hasAppliedSuggestedBuffer ? '已应用' : '应用'}
</Button>
</div>
);
}
return null;
} catch {
return null;
}
})()}
<Button onClick={resetTimelineAdjustments}> <Button onClick={resetTimelineAdjustments}>
</Button> </Button>
@ -5770,11 +5883,8 @@ export default function App() {
const deltaToApply = desiredAdjustmentAbs - currentAdj; const deltaToApply = desiredAdjustmentAbs - currentAdj;
if (deltaToApply !== 0) { if (deltaToApply !== 0) {
const updated = handleTimelineAdjustment(index, deltaToApply); const updated = handleTimelineAdjustment(index, deltaToApply);
// 若该节点不允许调整交由实际完成日期的useEffect联动重算
if (!updated) { if (!updated) {
// 如果该节点不允许调整,仍然重算以联动后续节点
setTimeout(() => {
recalculateTimeline(timelineAdjustments, false);
}, 0);
return; return;
} }
} }
@ -5784,10 +5894,7 @@ export default function App() {
console.warn('自动调整量计算失败:', e); console.warn('自动调整量计算失败:', e);
} }
// 无论如何都重新计算时间线以联动交期余量 // 重算由依赖actualCompletionDates的useEffect触发避免使用旧状态
setTimeout(() => {
recalculateTimeline(timelineAdjustments, false);
}, 0);
}} }}
/> />
</div> </div>