This commit is contained in:
2026-04-22 23:44:57 +08:00
parent 76ac9d22a5
commit 84dc92646a
484 changed files with 9598 additions and 9135 deletions

View File

@@ -45,9 +45,7 @@ import {
getPuzzleAgentSession,
streamPuzzleAgentMessage,
} from '../../services/puzzle-agent';
import {
getPuzzleGalleryDetail,
} from '../../services/puzzle-gallery';
import { getPuzzleGalleryDetail } from '../../services/puzzle-gallery';
import {
advancePuzzleNextLevel,
dragPuzzlePieceOrGroup,
@@ -55,6 +53,7 @@ import {
swapPuzzlePieces,
} from '../../services/puzzle-runtime';
import { listPuzzleWorks } from '../../services/puzzle-works';
import { deleteRpgEntryWorldProfile } from '../../services/rpg-entry';
import { rpgCreationPreviewAdapter } from '../../services/rpg-creation/rpgCreationPreviewAdapter';
import type { CustomWorldProfile } from '../../types';
import { useAuthUi } from '../auth/AuthUiContext';
@@ -105,9 +104,7 @@ const CustomWorldAgentWorkspace = lazy(async () => {
});
const BigFishAgentWorkspace = lazy(async () => {
const module = await import(
'../big-fish-creation/BigFishAgentWorkspace'
);
const module = await import('../big-fish-creation/BigFishAgentWorkspace');
return {
default: module.BigFishAgentWorkspace,
};
@@ -148,9 +145,8 @@ export function PlatformEntryFlowShellImpl({
}: PlatformEntryFlowShellProps) {
const authUi = useAuthUi();
const [showCreationTypeModal, setShowCreationTypeModal] = useState(false);
const [selectedDetailEntry, setSelectedDetailEntry] = useState<
CustomWorldLibraryEntry<CustomWorldProfile> | null
>(null);
const [selectedDetailEntry, setSelectedDetailEntry] =
useState<CustomWorldLibraryEntry<CustomWorldProfile> | null>(null);
const [bigFishSession, setBigFishSession] =
useState<BigFishSessionSnapshotResponse | null>(null);
const [bigFishRun, setBigFishRun] =
@@ -172,6 +168,9 @@ export function PlatformEntryFlowShellImpl({
const [puzzleError, setPuzzleError] = useState<string | null>(null);
const [isPuzzleBusy, setIsPuzzleBusy] = useState(false);
const [isPuzzleLoadingLibrary, setIsPuzzleLoadingLibrary] = useState(false);
const [deletingCreationWorkId, setDeletingCreationWorkId] = useState<
string | null
>(null);
const [streamingPuzzleReplyText, setStreamingPuzzleReplyText] = useState('');
const [isStreamingPuzzleReply, setIsStreamingPuzzleReply] = useState(false);
const hasInitialAgentSession = Boolean(
@@ -180,6 +179,7 @@ export function PlatformEntryFlowShellImpl({
const platformBootstrap = usePlatformEntryBootstrap({
user: authUi?.user,
canAccessProtectedData: authUi?.canAccessProtectedData,
getProfileDashboard: getPlatformProfileDashboard,
handleContinueGame,
hasInitialAgentSession,
@@ -241,8 +241,10 @@ export function PlatformEntryFlowShellImpl({
setGeneratedCustomWorldProfile:
sessionController.setGeneratedCustomWorldProfile,
setCustomWorldError: sessionController.setCustomWorldError,
setCustomWorldAutoSaveError: autosaveCoordinator.setCustomWorldAutoSaveError,
setCustomWorldAutoSaveState: autosaveCoordinator.setCustomWorldAutoSaveState,
setCustomWorldAutoSaveError:
autosaveCoordinator.setCustomWorldAutoSaveError,
setCustomWorldAutoSaveState:
autosaveCoordinator.setCustomWorldAutoSaveState,
setCustomWorldGenerationViewSource:
sessionController.setCustomWorldGenerationViewSource,
setCustomWorldResultViewSource:
@@ -261,7 +263,8 @@ export function PlatformEntryFlowShellImpl({
sessionController.suppressAgentDraftResultAutoOpen,
releaseAgentDraftResultAutoOpenSuppression:
sessionController.releaseAgentDraftResultAutoOpenSuppression,
resetAutoSaveTrackingToIdle: autosaveCoordinator.resetAutoSaveTrackingToIdle,
resetAutoSaveTrackingToIdle:
autosaveCoordinator.resetAutoSaveTrackingToIdle,
markAutoSavedProfile: autosaveCoordinator.markAutoSavedProfile,
});
@@ -276,7 +279,8 @@ export function PlatformEntryFlowShellImpl({
autosaveCoordinator.executeAgentActionAndWait({
action: 'publish_world',
}),
syncAgentDraftResultProfile: autosaveCoordinator.syncAgentDraftResultProfile,
syncAgentDraftResultProfile:
autosaveCoordinator.syncAgentDraftResultProfile,
setGeneratedCustomWorldProfile:
sessionController.setGeneratedCustomWorldProfile,
});
@@ -290,7 +294,8 @@ export function PlatformEntryFlowShellImpl({
: [],
[sessionController.generatedCustomWorldProfile],
);
const agentResultPreview = sessionController.agentSession?.resultPreview ?? null;
const agentResultPreview =
sessionController.agentSession?.resultPreview ?? null;
const agentResultPreviewBlockers = useMemo(
() => agentResultPreview?.blockers?.map((entry) => entry.message) ?? [],
[agentResultPreview],
@@ -320,7 +325,9 @@ export function PlatformEntryFlowShellImpl({
const creationHubItems =
platformBootstrap.customWorldWorkEntries.length > 0
? platformBootstrap.customWorldWorkEntries
: buildCreationHubFallbackItems(platformBootstrap.savedCustomWorldEntries);
: buildCreationHubFallbackItems(
platformBootstrap.savedCustomWorldEntries,
);
const resultViewError =
autosaveCoordinator.customWorldAutoSaveError ??
sessionController.customWorldError;
@@ -346,9 +353,7 @@ export function PlatformEntryFlowShellImpl({
);
}
if (selectionStage === 'big-fish-runtime' && !bigFishRun) {
setSelectionStage(
bigFishSession?.draft ? 'big-fish-result' : 'platform',
);
setSelectionStage(bigFishSession?.draft ? 'big-fish-result' : 'platform');
}
}, [bigFishRun, bigFishSession, selectionStage, setSelectionStage]);
@@ -375,11 +380,7 @@ export function PlatformEntryFlowShellImpl({
sessionController.setCreationTypeError(null);
return true;
}, [
handleStartNewGame,
hasSavedGame,
sessionController,
]);
}, [handleStartNewGame, hasSavedGame, sessionController]);
const openCreationTypePicker = useCallback(() => {
if (!prepareCreationLaunch()) {
@@ -626,11 +627,7 @@ export function PlatformEntryFlowShellImpl({
setIsStreamingPuzzleReply(false);
}
},
[
isStreamingPuzzleReply,
puzzleSession,
resolvePuzzleErrorMessage,
],
[isStreamingPuzzleReply, puzzleSession, resolvePuzzleErrorMessage],
);
const executeBigFishAction = useCallback(
@@ -687,13 +684,18 @@ export function PlatformEntryFlowShellImpl({
await refreshPuzzleShelf();
}
const { session } = await getPuzzleAgentSession(puzzleSession.sessionId);
const { session } = await getPuzzleAgentSession(
puzzleSession.sessionId,
);
setPuzzleSession(session);
if (payload.action === 'compile_puzzle_draft') {
setSelectionStage('puzzle-result');
}
if (payload.action === 'publish_puzzle_work' && session.publishedProfileId) {
if (
payload.action === 'publish_puzzle_work' &&
session.publishedProfileId
) {
const galleryDetail = await getPuzzleGalleryDetail(
session.publishedProfileId,
);
@@ -701,9 +703,7 @@ export function PlatformEntryFlowShellImpl({
setSelectionStage('puzzle-gallery-detail');
}
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '执行拼图操作失败。'),
);
setPuzzleError(resolvePuzzleErrorMessage(error, '执行拼图操作失败。'));
} finally {
setIsPuzzleBusy(false);
}
@@ -757,9 +757,7 @@ export function PlatformEntryFlowShellImpl({
setPuzzleRun(run);
setSelectionStage('puzzle-runtime');
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '启动拼图玩法失败。'),
);
setPuzzleError(resolvePuzzleErrorMessage(error, '启动拼图玩法失败。'));
} finally {
setIsPuzzleBusy(false);
}
@@ -803,9 +801,7 @@ export function PlatformEntryFlowShellImpl({
const { run } = await swapPuzzlePieces(puzzleRun.runId, payload);
setPuzzleRun(run);
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '交换拼图块失败。'),
);
setPuzzleError(resolvePuzzleErrorMessage(error, '交换拼图块失败。'));
} finally {
setIsPuzzleBusy(false);
}
@@ -830,9 +826,7 @@ export function PlatformEntryFlowShellImpl({
const { run } = await dragPuzzlePieceOrGroup(puzzleRun.runId, payload);
setPuzzleRun(run);
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '拖动拼图块失败。'),
);
setPuzzleError(resolvePuzzleErrorMessage(error, '拖动拼图块失败。'));
} finally {
setIsPuzzleBusy(false);
}
@@ -852,9 +846,7 @@ export function PlatformEntryFlowShellImpl({
const { run } = await advancePuzzleNextLevel(puzzleRun.runId);
setPuzzleRun(run);
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '进入下一关失败。'),
);
setPuzzleError(resolvePuzzleErrorMessage(error, '进入下一关失败。'));
} finally {
setIsPuzzleBusy(false);
}
@@ -927,6 +919,68 @@ export function PlatformEntryFlowShellImpl({
});
}, [handleCustomWorldSelect, runProtectedAction, selectedDetailEntry]);
const handleExperienceRpgWork = useCallback(
(work: (typeof creationHubItems)[number]) => {
if (!work.profileId) {
return;
}
runProtectedAction(() => {
const matchedEntry = platformBootstrap.savedCustomWorldEntries.find(
(entry) => entry.profileId === work.profileId,
);
if (!matchedEntry) {
platformBootstrap.setPlatformError('未找到可体验的作品,请刷新后重试。');
return;
}
handleCustomWorldSelect(matchedEntry.profile);
});
},
[
handleCustomWorldSelect,
platformBootstrap,
platformBootstrap.savedCustomWorldEntries,
runProtectedAction,
],
);
const handleDeletePublishedWork = useCallback(
(work: (typeof creationHubItems)[number]) => {
if (!work.profileId || deletingCreationWorkId) {
return;
}
runProtectedAction(() => {
const confirmed = window.confirm(
`确认删除作品《${work.title}》吗?删除后会从你的作品列表和公开广场中移除。`,
);
if (!confirmed) {
return;
}
setDeletingCreationWorkId(work.workId);
platformBootstrap.setPlatformError(null);
void deleteRpgEntryWorldProfile(work.profileId)
.then(async (entries) => {
platformBootstrap.setSavedCustomWorldEntries(entries);
await platformBootstrap.refreshCustomWorldWorks().catch(() => []);
await platformBootstrap.refreshPublishedGallery().catch(() => []);
})
.catch((error) => {
platformBootstrap.setPlatformError(
resolveRpgCreationErrorMessage(error, '删除自定义世界失败。'),
);
})
.finally(() => {
setDeletingCreationWorkId(null);
});
});
},
[deletingCreationWorkId, platformBootstrap, runProtectedAction],
);
const openPuzzleDetail = useCallback(
async (profileId: string) => {
setIsPuzzleBusy(true);
@@ -938,9 +992,7 @@ export function PlatformEntryFlowShellImpl({
enterCreateTab();
setSelectionStage('puzzle-gallery-detail');
} catch (error) {
setPuzzleError(
resolvePuzzleErrorMessage(error, '读取拼图详情失败。'),
);
setPuzzleError(resolvePuzzleErrorMessage(error, '读取拼图详情失败。'));
} finally {
setIsPuzzleBusy(false);
}
@@ -950,13 +1002,14 @@ export function PlatformEntryFlowShellImpl({
useEffect(() => {
if (
(platformBootstrap.platformTab === 'create' || selectionStage === 'platform') &&
authUi?.user?.id
(platformBootstrap.platformTab === 'create' ||
selectionStage === 'platform') &&
platformBootstrap.canReadProtectedData
) {
void refreshPuzzleShelf();
}
}, [
authUi?.user?.id,
platformBootstrap.canReadProtectedData,
platformBootstrap.platformTab,
refreshPuzzleShelf,
selectionStage,
@@ -969,9 +1022,9 @@ export function PlatformEntryFlowShellImpl({
error={
platformBootstrap.isLoadingPlatform || isPuzzleLoadingLibrary
? null
: platformBootstrap.platformError ??
sessionController.creationTypeError ??
puzzleError
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError ??
puzzleError)
}
onRetry={() => {
platformBootstrap.setPlatformError(null);
@@ -981,9 +1034,13 @@ export function PlatformEntryFlowShellImpl({
);
});
}}
createError={sessionController.creationTypeError ?? bigFishError ?? puzzleError}
createError={
sessionController.creationTypeError ?? bigFishError ?? puzzleError
}
createBusy={
sessionController.isCreatingAgentSession || isBigFishBusy || isPuzzleBusy
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isPuzzleBusy
}
onCreateType={handleCreationHubCreateType}
onOpenDraft={(item) => {
@@ -1002,12 +1059,24 @@ export function PlatformEntryFlowShellImpl({
void detailNavigation.handleOpenCreationWork(matchedWork);
});
}}
onDeletePublished={(item) => {
handleDeletePublishedWork(item);
}}
deletingWorkId={deletingCreationWorkId}
onExperienceRpg={(item) => {
handleExperienceRpgWork(item);
}}
puzzleItems={puzzleWorks}
onOpenPuzzleDetail={(profileId) => {
runProtectedAction(() => {
void openPuzzleDetail(profileId);
});
}}
onExperiencePuzzle={(profileId) => {
runProtectedAction(() => {
void startPuzzleRunFromProfile(profileId);
});
}}
/>
);
@@ -1040,8 +1109,8 @@ export function PlatformEntryFlowShellImpl({
platformError={
platformBootstrap.isLoadingPlatform
? null
: platformBootstrap.platformError ??
sessionController.creationTypeError
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError)
}
dashboardError={
platformBootstrap.isLoadingDashboard
@@ -1175,7 +1244,8 @@ export function PlatformEntryFlowShellImpl({
<div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-[var(--platform-text-base)]">
{sessionController.isLoadingAgentSession
? '正在准备 Agent 共创工作区...'
: sessionController.creationTypeError || '正在恢复创作工作区...'}
: sessionController.agentWorkspaceRestoreError ||
'正在恢复创作工作区...'}
</div>
</div>
)}
@@ -1472,7 +1542,9 @@ export function PlatformEntryFlowShellImpl({
});
}}
readOnly={false}
compactAgentResultMode={sessionController.isAgentDraftResultView}
compactAgentResultMode={
sessionController.isAgentDraftResultView
}
backLabel={
sessionController.isAgentDraftResultView
? '返回创作'
@@ -1515,10 +1587,12 @@ export function PlatformEntryFlowShellImpl({
<PlatformEntryCreationTypeModal
isOpen={showCreationTypeModal}
isBusy={
sessionController.isCreatingAgentSession || isBigFishBusy || isPuzzleBusy
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isPuzzleBusy
}
error={
sessionController.creationTypeError ?? bigFishError ?? puzzleError
bigFishError ?? puzzleError ?? sessionController.creationTypeError
}
onClose={() => {
if (