refactor: 收口平台弹窗状态模型

This commit is contained in:
2026-06-03 22:00:36 +08:00
parent 3efbb6882c
commit caac418e0e
6 changed files with 501 additions and 311 deletions

View File

@@ -421,6 +421,19 @@ import {
hasPuzzleRuntimeUrlStateValue,
normalizeCreationUrlValue,
} from './platformCreationUrlStateModel';
import {
buildPlatformErrorDialogDismissKey,
buildPlatformTaskCompletionDialogDismissKey,
formatPlatformDialogSource,
isBackgroundGenerationStillRunningMessage,
PLATFORM_TASK_COMPLETION_MESSAGE,
type PlatformDialogCandidate,
type PlatformErrorDialogState,
type PlatformTaskCompletionDialogState,
type PlatformTaskFailureDialogState,
resolveActivePlatformDialog,
resolvePlatformErrorDialog,
} from './platformDialogStateModel';
import {
buildCreationWorkShelfRuntimeState,
buildDraftCompletionDialogSource,
@@ -480,10 +493,7 @@ import type {
SelectionStage,
} from './platformEntryTypes';
import { PlatformEntryWorldDetailView } from './PlatformEntryWorldDetailView';
import {
PlatformErrorDialog,
type PlatformErrorDialogPayload,
} from './PlatformErrorDialog';
import { PlatformErrorDialog } from './PlatformErrorDialog';
import { PlatformFeedbackView } from './PlatformFeedbackView';
import {
buildMatch3DProfileFromSession,
@@ -509,10 +519,7 @@ import {
buildPuzzleResultProfileId,
buildPuzzleResultWorkId,
} from './platformPuzzleIdentityModel';
import {
PlatformTaskCompletionDialog,
type PlatformTaskCompletionDialogPayload,
} from './PlatformTaskCompletionDialog';
import { PlatformTaskCompletionDialog } from './PlatformTaskCompletionDialog';
import { PlatformWorkDetailView } from './PlatformWorkDetailView';
import { usePlatformCreationAgentFlowController } from './usePlatformCreationAgentFlowController';
import { usePlatformEntryBootstrap } from './usePlatformEntryBootstrap';
@@ -1507,39 +1514,6 @@ function buildWoodenFishPendingSession(
};
}
function normalizePlatformErrorMessage(message: string | null | undefined) {
const normalized = message?.trim();
return normalized ? normalized : null;
}
function formatPlatformErrorSource(label: string, id?: string | null) {
const normalizedId = id?.trim();
return normalizedId ? `${label} ${normalizedId}` : label;
}
function isBackgroundGenerationStillRunningMessage(message: string) {
return /|||/u.test(message);
}
function buildPlatformErrorDialogDismissKey(
error: (PlatformErrorDialogPayload & { key: string }) | null,
) {
return error ? `${error.key}:${error.source}:${error.message}` : null;
}
function buildPlatformTaskCompletionDialogDismissKey(
completion:
| (PlatformTaskCompletionDialogPayload & {
key: string;
completedAtMs: number | null;
})
| null,
) {
return completion
? `${completion.key}:${completion.source}:${completion.message}:${completion.completedAtMs ?? 0}`
: null;
}
/** 为恢复的小游戏草稿重建生成态,保留后端开始时间作为进度事实源。 */
function createMiniGameDraftGenerationStateForRestoredDraft(
kind: MiniGameDraftGenerationKind,
@@ -2733,23 +2707,11 @@ export function PlatformEntryFlowShellImpl({
const [
pendingPlatformTaskCompletionDialog,
setPendingPlatformTaskCompletionDialog,
] = useState<
| (PlatformTaskCompletionDialogPayload & {
key: string;
completedAtMs: number | null;
})
| null
>(null);
] = useState<PlatformTaskCompletionDialogState | null>(null);
const [
pendingPlatformTaskFailureDialog,
setPendingPlatformTaskFailureDialog,
] = useState<
| (PlatformErrorDialogPayload & {
key: string;
failedAtMs: number;
})
| null
>(null);
] = useState<PlatformTaskFailureDialogState | null>(null);
const [profileTaskRefreshKey, setProfileTaskRefreshKey] = useState(0);
const [initialCreationUrlState] = useState(() => readCreationUrlState());
const handledInitialCreationUrlStateRef = useRef(false);
@@ -2916,7 +2878,7 @@ export function PlatformEntryFlowShellImpl({
setPendingPlatformTaskCompletionDialog({
key: `${kind}:${collectDraftNoticeKeys(kind, ids).join('|')}:${completedAtMs}`,
source: buildDraftCompletionDialogSource(kind, ids),
message: '生成任务已完成,可以继续查看草稿。',
message: PLATFORM_TASK_COMPLETION_MESSAGE,
completedAtMs,
});
},
@@ -5462,263 +5424,237 @@ export function PlatformEntryFlowShellImpl({
dismissedPlatformTaskCompletionDialogKey,
setDismissedPlatformTaskCompletionDialogKey,
] = useState<string | null>(null);
const currentPlatformErrorDialog = useMemo<
(PlatformErrorDialogPayload & { key: string }) | null
>(() => {
const candidates: Array<{
key: string;
source: string;
message: string | null | undefined;
}> = [
{
key: pendingPlatformTaskFailureDialog?.key ?? 'draft-failure',
source: pendingPlatformTaskFailureDialog?.source ?? '创作草稿',
message: pendingPlatformTaskFailureDialog?.message,
},
{
key: 'creation-entry-config',
source: '创作入口配置',
message: creationEntryConfigError,
},
{
key: 'platform-bootstrap',
source: '平台首页',
message: platformBootstrap.platformError,
},
{
key: 'rpg-creation-type',
source: '创作入口',
message: sessionController.creationTypeError,
},
{
key: 'rpg-restore',
source: '创作作品架',
message: sessionController.agentWorkspaceRestoreError,
},
{
key: 'rpg-result',
source: formatPlatformErrorSource(
'RPG 草稿',
sessionController.agentSession?.sessionId ??
sessionController.generatedCustomWorldProfile?.id,
),
message: resultViewError,
},
{
key: 'public-work-detail',
source: formatPlatformErrorSource(
'作品详情',
selectedPublicWorkDetail
? resolvePlatformPublicWorkCode(selectedPublicWorkDetail)
: selectedDetailEntry?.profileId,
),
message: publicWorkDetailError ?? detailNavigation.detailError,
},
{
key: 'big-fish',
source: formatPlatformErrorSource(
selectionStage === 'big-fish-runtime' ? '大鱼吃小鱼游玩' : '大鱼草稿',
bigFishRun?.runId ?? bigFishSession?.sessionId,
),
message: bigFishError,
},
{
key: 'match3d',
source: formatPlatformErrorSource(
selectionStage === 'match3d-runtime' ? '抓大鹅游玩' : '抓大鹅草稿',
match3dRun?.runId ??
match3dGenerationViewSession?.sessionId ??
match3dSession?.sessionId,
),
message: match3dGenerationViewError ?? match3dError,
},
{
key: 'square-hole',
source: formatPlatformErrorSource(
selectionStage === 'square-hole-runtime'
? '方洞挑战游玩'
: '方洞挑战草稿',
squareHoleRun?.runId ?? squareHoleSession?.sessionId,
),
message: squareHoleError,
},
{
key: 'jump-hop',
source: formatPlatformErrorSource(
selectionStage === 'jump-hop-runtime' ? '跳一跳游玩' : '跳一跳草稿',
jumpHopRun?.runId ?? jumpHopSession?.sessionId,
),
message: jumpHopError,
},
{
key: 'wooden-fish',
source: formatPlatformErrorSource(
selectionStage === 'wooden-fish-runtime'
? '敲木鱼游玩'
: '敲木鱼草稿',
woodenFishRun?.runId ?? woodenFishSession?.sessionId,
),
message: woodenFishError,
},
{
key: 'puzzle',
source: formatPlatformErrorSource(
selectionStage === 'puzzle-runtime' ? '拼图游玩' : '拼图草稿',
puzzleRun?.runId ??
puzzleGenerationViewSession?.sessionId ??
puzzleSession?.sessionId,
),
message:
puzzleGenerationViewError ?? puzzleCreationError ?? puzzleError,
},
{
key: 'puzzle-onboarding',
source: '拼图首次创作',
message: puzzleOnboardingError,
},
{
key: 'puzzle-shelf',
source: '拼图作品架',
message: puzzleShelfError,
},
{
key: 'visual-novel',
source: formatPlatformErrorSource(
selectionStage === 'visual-novel-runtime'
? '视觉小说游玩'
: '视觉小说草稿',
visualNovelRun?.runId ?? visualNovelSession?.sessionId,
),
message: visualNovelError,
},
{
key: 'baby-object-match',
source: formatPlatformErrorSource(
selectionStage === 'baby-object-match-runtime'
? '宝贝识物游玩'
: '宝贝识物草稿',
babyObjectMatchDraft?.profileId,
),
message: babyObjectMatchError,
},
{
key: 'bark-battle',
source: formatPlatformErrorSource(
selectionStage === 'bark-battle-runtime'
? '汪汪声浪游玩'
: '汪汪声浪草稿',
barkBattlePublishedConfig?.workId ?? barkBattleDraftConfig?.workId,
),
message: barkBattleError,
},
{
key: 'creative-agent',
source: formatPlatformErrorSource(
'智能创作 Agent',
creativeAgentSession?.sessionId,
),
message: creativeAgentError,
},
{
key: 'rpg-generation',
source: formatPlatformErrorSource(
'RPG 草稿生成',
sessionController.agentSession?.sessionId,
),
message: sessionController.activeGenerationError,
},
];
const currentPlatformErrorDialog =
useMemo<PlatformErrorDialogState | null>(() => {
const candidates: PlatformDialogCandidate[] = [
{
key: pendingPlatformTaskFailureDialog?.key ?? 'draft-failure',
source: pendingPlatformTaskFailureDialog?.source ?? '创作草稿',
message: pendingPlatformTaskFailureDialog?.message,
},
{
key: 'creation-entry-config',
source: '创作入口配置',
message: creationEntryConfigError,
},
{
key: 'platform-bootstrap',
source: '平台首页',
message: platformBootstrap.platformError,
},
{
key: 'rpg-creation-type',
source: '创作入口',
message: sessionController.creationTypeError,
},
{
key: 'rpg-restore',
source: '创作作品架',
message: sessionController.agentWorkspaceRestoreError,
},
{
key: 'rpg-result',
source: formatPlatformDialogSource(
'RPG 草稿',
sessionController.agentSession?.sessionId ??
sessionController.generatedCustomWorldProfile?.id,
),
message: resultViewError,
},
{
key: 'public-work-detail',
source: formatPlatformDialogSource(
'作品详情',
selectedPublicWorkDetail
? resolvePlatformPublicWorkCode(selectedPublicWorkDetail)
: selectedDetailEntry?.profileId,
),
message: publicWorkDetailError ?? detailNavigation.detailError,
},
{
key: 'big-fish',
source: formatPlatformDialogSource(
selectionStage === 'big-fish-runtime'
? '大鱼吃小鱼游玩'
: '大鱼草稿',
bigFishRun?.runId ?? bigFishSession?.sessionId,
),
message: bigFishError,
},
{
key: 'match3d',
source: formatPlatformDialogSource(
selectionStage === 'match3d-runtime' ? '抓大鹅游玩' : '抓大鹅草稿',
match3dRun?.runId ??
match3dGenerationViewSession?.sessionId ??
match3dSession?.sessionId,
),
message: match3dGenerationViewError ?? match3dError,
},
{
key: 'square-hole',
source: formatPlatformDialogSource(
selectionStage === 'square-hole-runtime'
? '方洞挑战游玩'
: '方洞挑战草稿',
squareHoleRun?.runId ?? squareHoleSession?.sessionId,
),
message: squareHoleError,
},
{
key: 'jump-hop',
source: formatPlatformDialogSource(
selectionStage === 'jump-hop-runtime' ? '跳一跳游玩' : '跳一跳草稿',
jumpHopRun?.runId ?? jumpHopSession?.sessionId,
),
message: jumpHopError,
},
{
key: 'wooden-fish',
source: formatPlatformDialogSource(
selectionStage === 'wooden-fish-runtime'
? '敲木鱼游玩'
: '敲木鱼草稿',
woodenFishRun?.runId ?? woodenFishSession?.sessionId,
),
message: woodenFishError,
},
{
key: 'puzzle',
source: formatPlatformDialogSource(
selectionStage === 'puzzle-runtime' ? '拼图游玩' : '拼图草稿',
puzzleRun?.runId ??
puzzleGenerationViewSession?.sessionId ??
puzzleSession?.sessionId,
),
message:
puzzleGenerationViewError ?? puzzleCreationError ?? puzzleError,
},
{
key: 'puzzle-onboarding',
source: '拼图首次创作',
message: puzzleOnboardingError,
},
{
key: 'puzzle-shelf',
source: '拼图作品架',
message: puzzleShelfError,
},
{
key: 'visual-novel',
source: formatPlatformDialogSource(
selectionStage === 'visual-novel-runtime'
? '视觉小说游玩'
: '视觉小说草稿',
visualNovelRun?.runId ?? visualNovelSession?.sessionId,
),
message: visualNovelError,
},
{
key: 'baby-object-match',
source: formatPlatformDialogSource(
selectionStage === 'baby-object-match-runtime'
? '宝贝识物游玩'
: '宝贝识物草稿',
babyObjectMatchDraft?.profileId,
),
message: babyObjectMatchError,
},
{
key: 'bark-battle',
source: formatPlatformDialogSource(
selectionStage === 'bark-battle-runtime'
? '汪汪声浪游玩'
: '汪汪声浪草稿',
barkBattlePublishedConfig?.workId ?? barkBattleDraftConfig?.workId,
),
message: barkBattleError,
},
{
key: 'creative-agent',
source: formatPlatformDialogSource(
'智能创作 Agent',
creativeAgentSession?.sessionId,
),
message: creativeAgentError,
},
{
key: 'rpg-generation',
source: formatPlatformDialogSource(
'RPG 草稿生成',
sessionController.agentSession?.sessionId,
),
message: sessionController.activeGenerationError,
},
];
for (const candidate of candidates) {
const message = normalizePlatformErrorMessage(candidate.message);
if (message) {
return {
key: candidate.key,
source: candidate.source,
message,
};
}
}
return null;
}, [
babyObjectMatchDraft?.profileId,
babyObjectMatchError,
barkBattleDraftConfig?.workId,
barkBattleError,
barkBattlePublishedConfig?.workId,
bigFishError,
bigFishRun?.runId,
bigFishSession?.sessionId,
creationEntryConfigError,
creativeAgentError,
creativeAgentSession?.sessionId,
detailNavigation.detailError,
jumpHopError,
jumpHopRun?.runId,
jumpHopSession?.sessionId,
match3dError,
match3dGenerationViewError,
match3dGenerationViewSession?.sessionId,
match3dRun?.runId,
match3dSession?.sessionId,
pendingPlatformTaskFailureDialog,
platformBootstrap.platformError,
publicWorkDetailError,
puzzleCreationError,
puzzleError,
puzzleGenerationViewError,
puzzleGenerationViewSession?.sessionId,
puzzleOnboardingError,
puzzleRun?.runId,
puzzleSession?.sessionId,
puzzleShelfError,
resultViewError,
selectedDetailEntry?.profileId,
selectedPublicWorkDetail,
selectionStage,
sessionController.activeGenerationError,
sessionController.agentSession?.sessionId,
sessionController.agentWorkspaceRestoreError,
sessionController.creationTypeError,
sessionController.generatedCustomWorldProfile?.id,
squareHoleError,
squareHoleRun?.runId,
squareHoleSession?.sessionId,
visualNovelError,
visualNovelRun?.runId,
visualNovelSession?.sessionId,
woodenFishError,
woodenFishRun?.runId,
woodenFishSession?.sessionId,
]);
const currentPlatformTaskCompletionDialog = useMemo<
| (PlatformTaskCompletionDialogPayload & {
key: string;
completedAtMs: number | null;
})
| null
>(
() => pendingPlatformTaskCompletionDialog,
[pendingPlatformTaskCompletionDialog],
);
const activePlatformTaskCompletionDialogDismissKey =
buildPlatformTaskCompletionDialogDismissKey(
currentPlatformTaskCompletionDialog,
return resolvePlatformErrorDialog(candidates);
}, [
babyObjectMatchDraft?.profileId,
babyObjectMatchError,
barkBattleDraftConfig?.workId,
barkBattleError,
barkBattlePublishedConfig?.workId,
bigFishError,
bigFishRun?.runId,
bigFishSession?.sessionId,
creationEntryConfigError,
creativeAgentError,
creativeAgentSession?.sessionId,
detailNavigation.detailError,
jumpHopError,
jumpHopRun?.runId,
jumpHopSession?.sessionId,
match3dError,
match3dGenerationViewError,
match3dGenerationViewSession?.sessionId,
match3dRun?.runId,
match3dSession?.sessionId,
pendingPlatformTaskFailureDialog,
platformBootstrap.platformError,
publicWorkDetailError,
puzzleCreationError,
puzzleError,
puzzleGenerationViewError,
puzzleGenerationViewSession?.sessionId,
puzzleOnboardingError,
puzzleRun?.runId,
puzzleSession?.sessionId,
puzzleShelfError,
resultViewError,
selectedDetailEntry?.profileId,
selectedPublicWorkDetail,
selectionStage,
sessionController.activeGenerationError,
sessionController.agentSession?.sessionId,
sessionController.agentWorkspaceRestoreError,
sessionController.creationTypeError,
sessionController.generatedCustomWorldProfile?.id,
squareHoleError,
squareHoleRun?.runId,
squareHoleSession?.sessionId,
visualNovelError,
visualNovelRun?.runId,
visualNovelSession?.sessionId,
woodenFishError,
woodenFishRun?.runId,
woodenFishSession?.sessionId,
]);
const currentPlatformTaskCompletionDialog =
useMemo<PlatformTaskCompletionDialogState | null>(
() => pendingPlatformTaskCompletionDialog,
[pendingPlatformTaskCompletionDialog],
);
const activePlatformTaskCompletionDialog =
activePlatformTaskCompletionDialogDismissKey &&
activePlatformTaskCompletionDialogDismissKey ===
dismissedPlatformTaskCompletionDialogKey
? null
: currentPlatformTaskCompletionDialog;
const activePlatformErrorDialogDismissKey =
buildPlatformErrorDialogDismissKey(currentPlatformErrorDialog);
const activePlatformErrorDialog =
activePlatformErrorDialogDismissKey &&
activePlatformErrorDialogDismissKey === dismissedPlatformErrorDialogKey
? null
: currentPlatformErrorDialog;
const activePlatformTaskCompletionDialog = resolveActivePlatformDialog(
currentPlatformTaskCompletionDialog,
dismissedPlatformTaskCompletionDialogKey,
buildPlatformTaskCompletionDialogDismissKey,
);
const activePlatformErrorDialog = resolveActivePlatformDialog(
currentPlatformErrorDialog,
dismissedPlatformErrorDialogKey,
buildPlatformErrorDialogDismissKey,
);
const closePlatformErrorDialog = useCallback(() => {
if (!currentPlatformErrorDialog) {
return;