feat: 平台错误与完成弹窗收口
This commit is contained in:
@@ -429,6 +429,10 @@ import {
|
||||
PlatformErrorDialog,
|
||||
type PlatformErrorDialogPayload,
|
||||
} from './PlatformErrorDialog';
|
||||
import {
|
||||
PlatformTaskCompletionDialog,
|
||||
type PlatformTaskCompletionDialogPayload,
|
||||
} from './PlatformTaskCompletionDialog';
|
||||
import { PlatformFeedbackView } from './PlatformFeedbackView';
|
||||
import { PlatformWorkDetailView } from './PlatformWorkDetailView';
|
||||
import { usePlatformCreationAgentFlowController } from './usePlatformCreationAgentFlowController';
|
||||
@@ -444,6 +448,7 @@ type DraftGenerationNoticeStatus = 'generating' | 'ready';
|
||||
type DraftGenerationNotice = {
|
||||
status: DraftGenerationNoticeStatus;
|
||||
seen: boolean;
|
||||
completedAtMs?: number;
|
||||
};
|
||||
type DraftGenerationNoticeMap = Record<string, DraftGenerationNotice>;
|
||||
type CreationWorkShelfKind = CreationWorkShelfItem['kind'];
|
||||
@@ -2027,12 +2032,74 @@ function formatPlatformErrorSource(label: string, id?: string | null) {
|
||||
return normalizedId ? `${label} ${normalizedId}` : label;
|
||||
}
|
||||
|
||||
function formatPlatformTaskCompletionSource(label: string, id?: string | null) {
|
||||
const normalizedId = id?.trim();
|
||||
return normalizedId ? `${label} ${normalizedId}` : label;
|
||||
}
|
||||
|
||||
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 pickDraftCompletionDialogSourceId(
|
||||
ids: Array<string | null | undefined>,
|
||||
) {
|
||||
const normalizedIds = ids
|
||||
.map((id) => id?.trim() ?? '')
|
||||
.filter((id) => Boolean(id));
|
||||
return (
|
||||
normalizedIds.find((id) => /session/i.test(id)) ??
|
||||
normalizedIds.find((id) => /work/i.test(id)) ??
|
||||
normalizedIds.find((id) => /draft/i.test(id)) ??
|
||||
normalizedIds.find((id) => /run/i.test(id)) ??
|
||||
normalizedIds.find((id) => /profile/i.test(id)) ??
|
||||
normalizedIds[0] ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
function buildDraftCompletionDialogSource(
|
||||
kind: CreationWorkShelfKind,
|
||||
ids: Array<string | null | undefined>,
|
||||
) {
|
||||
const sourceId = pickDraftCompletionDialogSourceId(ids);
|
||||
switch (kind) {
|
||||
case 'rpg':
|
||||
return formatPlatformTaskCompletionSource('RPG 草稿', sourceId);
|
||||
case 'big-fish':
|
||||
return formatPlatformTaskCompletionSource('大鱼吃小鱼草稿', sourceId);
|
||||
case 'match3d':
|
||||
return formatPlatformTaskCompletionSource('抓大鹅草稿', sourceId);
|
||||
case 'square-hole':
|
||||
return formatPlatformTaskCompletionSource('方洞挑战草稿', sourceId);
|
||||
case 'jump-hop':
|
||||
return formatPlatformTaskCompletionSource('跳一跳草稿', sourceId);
|
||||
case 'puzzle':
|
||||
return formatPlatformTaskCompletionSource('拼图草稿', sourceId);
|
||||
case 'visual-novel':
|
||||
return formatPlatformTaskCompletionSource('视觉小说草稿', sourceId);
|
||||
case 'bark-battle':
|
||||
return formatPlatformTaskCompletionSource('汪汪声浪草稿', sourceId);
|
||||
case 'baby-object-match':
|
||||
return formatPlatformTaskCompletionSource('宝贝识物草稿', sourceId);
|
||||
}
|
||||
}
|
||||
|
||||
function createMiniGameDraftGenerationStateForRestoredDraft(
|
||||
kind: MiniGameDraftGenerationKind,
|
||||
metadata?: MiniGameDraftGenerationState['metadata'],
|
||||
@@ -3327,6 +3394,16 @@ export function PlatformEntryFlowShellImpl({
|
||||
useState<DraftGenerationNoticeMap>({});
|
||||
const [pendingDraftShelfItems, setPendingDraftShelfItems] =
|
||||
useState<PendingDraftShelfMap>({});
|
||||
const [
|
||||
pendingPlatformTaskCompletionDialog,
|
||||
setPendingPlatformTaskCompletionDialog,
|
||||
] = useState<
|
||||
| (PlatformTaskCompletionDialogPayload & {
|
||||
key: string;
|
||||
completedAtMs: number | null;
|
||||
})
|
||||
| null
|
||||
>(null);
|
||||
const [initialCreationUrlState] = useState(() => readCreationUrlState());
|
||||
const handledInitialCreationUrlStateRef = useRef(false);
|
||||
const [initialPuzzleRuntimeUrlState] = useState(() =>
|
||||
@@ -3404,10 +3481,14 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
const completedAtMs = status === 'ready' ? Date.now() : undefined;
|
||||
setDraftGenerationNotices((current) => {
|
||||
const next = { ...current };
|
||||
for (const key of uniqueKeys) {
|
||||
next[key] = { status, seen };
|
||||
next[key] =
|
||||
completedAtMs === undefined
|
||||
? { status, seen }
|
||||
: { status, seen, completedAtMs };
|
||||
}
|
||||
return next;
|
||||
});
|
||||
@@ -3449,12 +3530,13 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
const markDraftGenerating = useCallback(
|
||||
(kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) => {
|
||||
setPendingPlatformTaskCompletionDialog(null);
|
||||
updateDraftGenerationNotices(
|
||||
collectDraftNoticeKeys(kind, ids),
|
||||
'generating',
|
||||
);
|
||||
},
|
||||
[updateDraftGenerationNotices],
|
||||
[setPendingPlatformTaskCompletionDialog, updateDraftGenerationNotices],
|
||||
);
|
||||
const markDraftReady = useCallback(
|
||||
(
|
||||
@@ -3467,17 +3549,27 @@ export function PlatformEntryFlowShellImpl({
|
||||
'ready',
|
||||
viewedImmediately,
|
||||
);
|
||||
if (!viewedImmediately) {
|
||||
const completedAtMs = Date.now();
|
||||
setPendingPlatformTaskCompletionDialog({
|
||||
key: `${kind}:${collectDraftNoticeKeys(kind, ids).join('|')}:${completedAtMs}`,
|
||||
source: buildDraftCompletionDialogSource(kind, ids),
|
||||
message: '生成任务已完成,可以继续查看草稿。',
|
||||
completedAtMs,
|
||||
});
|
||||
}
|
||||
},
|
||||
[updateDraftGenerationNotices],
|
||||
[setPendingPlatformTaskCompletionDialog, updateDraftGenerationNotices],
|
||||
);
|
||||
const markPendingDraftGenerating = useCallback(
|
||||
(
|
||||
kind: Exclude<CreationWorkShelfKind, 'rpg'>,
|
||||
id: string | null | undefined,
|
||||
) => {
|
||||
setPendingPlatformTaskCompletionDialog(null);
|
||||
updatePendingDraftShelfItem(kind, id, 'generating');
|
||||
},
|
||||
[updatePendingDraftShelfItem],
|
||||
[setPendingPlatformTaskCompletionDialog, updatePendingDraftShelfItem],
|
||||
);
|
||||
const markPendingDraftReady = useCallback(
|
||||
(
|
||||
@@ -5790,6 +5882,10 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
const [dismissedPlatformErrorDialogKey, setDismissedPlatformErrorDialogKey] =
|
||||
useState<string | null>(null);
|
||||
const [
|
||||
dismissedPlatformTaskCompletionDialogKey,
|
||||
setDismissedPlatformTaskCompletionDialogKey,
|
||||
] = useState<string | null>(null);
|
||||
const currentPlatformErrorDialog = useMemo<
|
||||
(PlatformErrorDialogPayload & { key: string }) | null
|
||||
>(() => {
|
||||
@@ -6013,6 +6109,25 @@ export function PlatformEntryFlowShellImpl({
|
||||
woodenFishRun?.runId,
|
||||
woodenFishSession?.sessionId,
|
||||
]);
|
||||
const currentPlatformTaskCompletionDialog = useMemo<
|
||||
| (PlatformTaskCompletionDialogPayload & {
|
||||
key: string;
|
||||
completedAtMs: number | null;
|
||||
})
|
||||
| null
|
||||
>(() => pendingPlatformTaskCompletionDialog, [
|
||||
pendingPlatformTaskCompletionDialog,
|
||||
]);
|
||||
const activePlatformTaskCompletionDialogDismissKey =
|
||||
buildPlatformTaskCompletionDialogDismissKey(
|
||||
currentPlatformTaskCompletionDialog,
|
||||
);
|
||||
const activePlatformTaskCompletionDialog =
|
||||
activePlatformTaskCompletionDialogDismissKey &&
|
||||
activePlatformTaskCompletionDialogDismissKey ===
|
||||
dismissedPlatformTaskCompletionDialogKey
|
||||
? null
|
||||
: currentPlatformTaskCompletionDialog;
|
||||
const activePlatformErrorDialogDismissKey =
|
||||
buildPlatformErrorDialogDismissKey(currentPlatformErrorDialog);
|
||||
const activePlatformErrorDialog =
|
||||
@@ -6118,6 +6233,19 @@ export function PlatformEntryFlowShellImpl({
|
||||
setSquareHoleError,
|
||||
setVisualNovelError,
|
||||
]);
|
||||
const closePlatformTaskCompletionDialog = useCallback(() => {
|
||||
if (!currentPlatformTaskCompletionDialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dismissKey = buildPlatformTaskCompletionDialogDismissKey(
|
||||
currentPlatformTaskCompletionDialog,
|
||||
);
|
||||
if (dismissKey) {
|
||||
setDismissedPlatformTaskCompletionDialogKey(dismissKey);
|
||||
}
|
||||
setPendingPlatformTaskCompletionDialog(null);
|
||||
}, [currentPlatformTaskCompletionDialog]);
|
||||
const shouldPollPuzzleGenerationSession =
|
||||
selectionStage === 'puzzle-generating' &&
|
||||
activePuzzleGenerationSessionId != null &&
|
||||
@@ -7116,6 +7244,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
setIsProfilePlayStatsOpen(false);
|
||||
setDraftGenerationNotices({});
|
||||
setPendingDraftShelfItems({});
|
||||
setPendingPlatformTaskCompletionDialog(null);
|
||||
resetRpgSessionViewState();
|
||||
setRpgGeneratedCustomWorldProfile(null);
|
||||
setRpgCustomWorldError(null);
|
||||
@@ -16871,6 +17000,12 @@ export function PlatformEntryFlowShellImpl({
|
||||
overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
|
||||
panelClassName="platform-remap-surface rounded-[1.5rem]"
|
||||
/>
|
||||
<PlatformTaskCompletionDialog
|
||||
completion={activePlatformTaskCompletionDialog}
|
||||
onClose={closePlatformTaskCompletionDialog}
|
||||
overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
|
||||
panelClassName="platform-remap-surface rounded-[1.5rem]"
|
||||
/>
|
||||
<UnifiedModal
|
||||
open={Boolean(pendingDeleteCreationWork)}
|
||||
title="删除作品"
|
||||
|
||||
Reference in New Issue
Block a user