修复拼图生成队列与草稿恢复

补齐拼图队列状态回传,生成页展示排队/运行状态

修复草稿进入时生成中与结果页路由恢复逻辑

避免新增空白关卡立即自动保存并保留编辑弹窗

恢复稳定拼图 profile 缺失时的同源 session 草稿投影

让外部生成 worker/controller 跳过 HTTP 认证快照恢复

补充外部生成 worker 与拼图草稿排障记录
This commit is contained in:
2026-06-19 10:47:56 +08:00
parent e3258f6f1d
commit d9c32261fc
12 changed files with 628 additions and 93 deletions
@@ -165,6 +165,7 @@ import {
fetchCreationEntryConfig,
} from '../../services/creationEntryConfigService';
import {
type CreationUrlState,
clearCreationUrlState,
readCreationUrlState,
writeCreationUrlState,
@@ -499,6 +500,7 @@ import {
type PendingDraftShelfKind,
type PendingDraftShelfMap,
type PendingDraftShelfMetadata,
buildPuzzleDraftOpenNoticeKeys,
resolveBigFishDraftOpenIntent,
resolveJumpHopDraftOpenIntent,
resolveMatch3DDraftOpenIntent,
@@ -909,6 +911,29 @@ function pushPuzzleResultHistoryEntry(
writeCreationUrlState(buildPuzzleCreationUrlState(session));
}
function pushPuzzleGeneratingHistoryEntry(
session: PuzzleAgentSessionSnapshot | null,
fallbackState?: CreationUrlState,
) {
pushAppHistoryPath('/creation/puzzle/generating');
writeCreationUrlState(
session ? buildPuzzleCreationUrlState(session) : (fallbackState ?? {}),
);
}
function buildPuzzleCreationUrlStateFromWork(
item: PuzzleWorkSummary,
): CreationUrlState {
const sourceSessionId = item.sourceSessionId?.trim() || null;
return {
sessionId: sourceSessionId,
profileId:
item.profileId?.trim() || buildPuzzleResultProfileId(sourceSessionId),
workId: item.workId?.trim() || buildPuzzleResultWorkId(sourceSessionId),
};
}
const PUZZLE_DRAFT_GENERATION_POINT_COST = 2;
const PUZZLE_BACKGROUND_ACTION_POLL_INTERVAL_MS = 3000;
const PUZZLE_BACKGROUND_ACTION_MAX_POLL_ATTEMPTS = 160;
@@ -4247,6 +4272,7 @@ export function PlatformEntryFlowShellImpl({
);
activePuzzleGenerationSessionIdRef.current =
response.session.sessionId;
pushPuzzleGeneratingHistoryEntry(response.session);
setSelectionStage('puzzle-generating');
markDraftGenerating('puzzle', [
response.session.sessionId,
@@ -4391,6 +4417,7 @@ export function PlatformEntryFlowShellImpl({
);
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = session.sessionId;
pushPuzzleGeneratingHistoryEntry(session);
setSelectionStage('puzzle-generating');
const nextGenerationState = createPuzzleDraftGenerationStateFromPayload(
formPayload ?? buildPuzzleFormPayloadFromSession(session),
@@ -5657,6 +5684,7 @@ export function PlatformEntryFlowShellImpl({
}
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = nextSession.sessionId;
pushPuzzleGeneratingHistoryEntry(nextSession);
setSelectionStage('puzzle-generating');
try {
@@ -12060,6 +12088,66 @@ export function PlatformEntryFlowShellImpl({
setPuzzleRun(null);
setPuzzleRuntimeAuthMode('default');
setSelectedPuzzleDetail(null);
const restorePuzzleGeneratingSession = (
latestSession: PuzzleAgentSessionSnapshot,
) => {
const payload = buildPuzzleFormPayloadFromSession(latestSession);
const startedAtMs = resolveMiniGameDraftGenerationStartedAtMs(
latestSession.updatedAt,
);
const baseGenerationState =
createMiniGameDraftGenerationStateForRestoredDraft(
'puzzle',
{
puzzleAiRedraw: payload.aiRedraw ?? true,
puzzleProgressPercent:
latestSession.draft && !latestSession.draft.formDraft
? latestSession.progressPercent
: undefined,
},
startedAtMs,
);
const generationState = mergePuzzleSessionProgressIntoGenerationState(
baseGenerationState,
latestSession,
);
puzzleFlow.setSession(latestSession);
setPuzzleFormDraftPayload(payload);
setPuzzleGenerationState(generationState);
setPuzzleBackgroundCompileTasks((current) => ({
...current,
[latestSession.sessionId]: {
session: latestSession,
payload,
generationState,
error: null,
},
}));
enterCreateTab();
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = latestSession.sessionId;
pushPuzzleGeneratingHistoryEntry(latestSession);
setSelectionStage('puzzle-generating');
};
const openPuzzleReadyResultSession = (
latestSession: PuzzleAgentSessionSnapshot,
) => {
const payload = buildPuzzleFormPayloadFromSession(latestSession);
puzzleFlow.setSession(latestSession);
setPuzzleFormDraftPayload(payload);
setPuzzleGenerationState(null);
setPuzzleBackgroundCompileTasks((current) => {
const next = { ...current };
delete next[latestSession.sessionId];
return next;
});
enterCreateTab();
selectionStageRef.current = 'puzzle-result';
activePuzzleGenerationSessionIdRef.current = null;
markDraftNoticeSeen(buildPuzzleDraftOpenNoticeKeys(item));
pushPuzzleResultHistoryEntry(latestSession);
setSelectionStage('puzzle-result');
};
if (openIntent.type === 'open-published-detail') {
await openPuzzleDetail(item.profileId, { tab: 'create' });
@@ -12125,6 +12213,10 @@ export function PlatformEntryFlowShellImpl({
enterCreateTab();
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
pushPuzzleGeneratingHistoryEntry(
failedSession,
buildPuzzleCreationUrlStateFromWork(item),
);
setPuzzleGenerationState(failedGenerationState);
setSelectionStage('puzzle-generating');
return;
@@ -12139,6 +12231,10 @@ export function PlatformEntryFlowShellImpl({
enterCreateTab();
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
pushPuzzleGeneratingHistoryEntry(
puzzleSession ?? backgroundTask?.session ?? null,
buildPuzzleCreationUrlStateFromWork(item),
);
setPuzzleGenerationState(rebasedGenerationState);
if (backgroundTask) {
setPuzzleBackgroundCompileTasks((current) => ({
@@ -12169,6 +12265,7 @@ export function PlatformEntryFlowShellImpl({
enterCreateTab();
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
pushPuzzleGeneratingHistoryEntry(rebasedTask.session);
setSelectionStage('puzzle-generating');
return;
}
@@ -12177,42 +12274,14 @@ export function PlatformEntryFlowShellImpl({
try {
const { session: latestSession } =
await getPuzzleAgentSession(sourceSessionId);
const payload = buildPuzzleFormPayloadFromSession(latestSession);
const startedAtMs = resolveMiniGameDraftGenerationStartedAtMs(
latestSession.updatedAt,
);
const baseGenerationState =
createMiniGameDraftGenerationStateForRestoredDraft(
'puzzle',
{
puzzleAiRedraw: payload.aiRedraw ?? true,
puzzleProgressPercent:
latestSession.draft && !latestSession.draft.formDraft
? latestSession.progressPercent
: undefined,
},
startedAtMs,
);
const generationState = mergePuzzleSessionProgressIntoGenerationState(
baseGenerationState,
latestSession,
);
puzzleFlow.setSession(latestSession);
setPuzzleFormDraftPayload(payload);
setPuzzleGenerationState(generationState);
setPuzzleBackgroundCompileTasks((current) => ({
...current,
[latestSession.sessionId]: {
session: latestSession,
payload,
generationState,
error: null,
},
}));
enterCreateTab();
selectionStageRef.current = 'puzzle-generating';
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
setSelectionStage('puzzle-generating');
if (
!isPuzzleFormOnlyDraft(latestSession) &&
isPuzzleCompileActionReady(latestSession)
) {
openPuzzleReadyResultSession(latestSession);
return;
}
restorePuzzleGeneratingSession(latestSession);
return;
} catch (error) {
setPuzzleError(
@@ -12238,6 +12307,10 @@ export function PlatformEntryFlowShellImpl({
setSelectionStage('puzzle-agent-workspace');
} else {
setPuzzleFormDraftPayload(null);
pushPuzzleResultHistoryEntry(restoredSession);
selectionStageRef.current = 'puzzle-result';
activePuzzleGenerationSessionIdRef.current = null;
setSelectionStage('puzzle-result');
}
},
[