1
This commit is contained in:
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user