1
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-29 23:10:43 +08:00
parent 0395bd7ec6
commit 89ab1bf1c0
20 changed files with 204 additions and 244 deletions

View File

@@ -99,11 +99,9 @@ import {
} from '../../services/puzzle-gallery';
import {
advanceLocalPuzzleNextLevel,
dragPuzzlePieceOrGroup,
getPuzzleRun,
startPuzzleRun,
submitPuzzleLeaderboard,
swapPuzzlePieces,
updatePuzzleRunPause,
usePuzzleRuntimeProp as consumePuzzleRuntimeProp,
} from '../../services/puzzle-runtime';
@@ -557,6 +555,37 @@ function LazyPanelFallback({ label }: { label: string }) {
);
}
function mergePuzzleServiceRuntimeState(
currentRun: PuzzleRunSnapshot,
serviceRun: PuzzleRunSnapshot,
): PuzzleRunSnapshot {
if (!currentRun.currentLevel || !serviceRun.currentLevel) {
return currentRun;
}
const serviceLevel = serviceRun.currentLevel;
const leaderboardEntries =
serviceLevel.leaderboardEntries.length > 0
? serviceLevel.leaderboardEntries
: serviceRun.leaderboardEntries;
return {
...currentRun,
leaderboardEntries,
currentLevel: {
...currentRun.currentLevel,
timeLimitMs: serviceLevel.timeLimitMs,
remainingMs: serviceLevel.remainingMs,
pausedAccumulatedMs: serviceLevel.pausedAccumulatedMs,
pauseStartedAtMs: serviceLevel.pauseStartedAtMs,
freezeAccumulatedMs: serviceLevel.freezeAccumulatedMs,
freezeStartedAtMs: serviceLevel.freezeStartedAtMs,
freezeUntilMs: serviceLevel.freezeUntilMs,
leaderboardEntries,
},
};
}
export function PlatformEntryFlowShellImpl({
selectionStage,
setSelectionStage,
@@ -1565,20 +1594,10 @@ export function PlatformEntryFlowShellImpl({
}
setPuzzleError(null);
if (isLocalPuzzleRun(puzzleRun)) {
setPuzzleRun(swapLocalPuzzlePieces(puzzleRun, payload));
return;
}
void swapPuzzlePieces(puzzleRun.runId, payload)
.then(({ run }) => {
setPuzzleRun(run);
})
.catch((error) => {
setPuzzleError(resolvePuzzleErrorMessage(error, '交换拼图块失败。'));
});
// 交换、合并与通关判定都由前端即时裁决,正式 run 不再等待后端 /swap。
setPuzzleRun(swapLocalPuzzlePieces(puzzleRun, payload));
},
[isPuzzleBusy, puzzleRun, resolvePuzzleErrorMessage, setPuzzleError],
[isPuzzleBusy, puzzleRun, setPuzzleError],
);
const dragPuzzlePiece = useCallback(
@@ -1588,20 +1607,11 @@ export function PlatformEntryFlowShellImpl({
}
setPuzzleError(null);
if (isLocalPuzzleRun(puzzleRun)) {
setPuzzleRun(dragLocalPuzzlePiece(puzzleRun, payload));
return;
}
void dragPuzzlePieceOrGroup(puzzleRun.runId, payload)
.then(({ run }) => {
setPuzzleRun(run);
})
.catch((error) => {
setPuzzleError(resolvePuzzleErrorMessage(error, '拖动拼图块失败。'));
});
// 拖动落点、合并、拆分与通关判定都属于前端即时交互裁决。
// 后端只保留开局、道具、下一关与真实排行榜等服务侧能力。
setPuzzleRun(dragLocalPuzzlePiece(puzzleRun, payload));
},
[isPuzzleBusy, puzzleRun, resolvePuzzleErrorMessage, setPuzzleError],
[isPuzzleBusy, puzzleRun, setPuzzleError],
);
useEffect(() => {
@@ -1641,7 +1651,9 @@ export function PlatformEntryFlowShellImpl({
const { run } = await updatePuzzleRunPause(puzzleRun.runId, {
paused,
});
setPuzzleRun(run);
setPuzzleRun((currentRun) =>
currentRun ? mergePuzzleServiceRuntimeState(currentRun, run) : currentRun,
);
void platformBootstrap.refreshProfileDashboard();
} catch (error) {
setPuzzleError(
@@ -1669,7 +1681,9 @@ export function PlatformEntryFlowShellImpl({
try {
const { run } = await getPuzzleRun(puzzleRun.runId);
setPuzzleRun(run);
setPuzzleRun((currentRun) =>
currentRun ? mergePuzzleServiceRuntimeState(currentRun, run) : currentRun,
);
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '同步拼图失败状态失败。'),
@@ -1703,9 +1717,14 @@ export function PlatformEntryFlowShellImpl({
const { run } = await consumePuzzleRuntimeProp(puzzleRun.runId, {
propKind,
});
setPuzzleRun(run);
const nextRun = mergePuzzleServiceRuntimeState(
puzzleRunRef.current ?? puzzleRun,
run,
);
puzzleRunRef.current = nextRun;
setPuzzleRun(nextRun);
void platformBootstrap.refreshProfileDashboard();
return run;
return nextRun;
},
[platformBootstrap, puzzleRun],
);
@@ -1744,7 +1763,12 @@ export function PlatformEntryFlowShellImpl({
void submitPuzzleLeaderboard(puzzleRun.runId, payload)
.then(({ run }) => {
setPuzzleRun(run);
setPuzzleRun((currentRun) => {
if (!currentRun) {
return currentRun;
}
return mergePuzzleServiceRuntimeState(currentRun, run);
});
})
.catch((error) => {
submittedPuzzleLeaderboardKeysRef.current.delete(submitKey);