1
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
upsertRpgWorldProfile,
|
||||
} from '../../services/rpg-creation';
|
||||
import type { AuthUser } from '../../services/authService';
|
||||
import { ApiClientError } from '../../services/apiClient';
|
||||
import {
|
||||
clearRpgProfileBrowseHistory as clearProfileBrowseHistory,
|
||||
deleteRpgEntryWorldProfile,
|
||||
@@ -517,6 +518,7 @@ beforeEach(() => {
|
||||
vi.mocked(createRpgCreationSession).mockResolvedValue({
|
||||
session: mockSession,
|
||||
});
|
||||
vi.mocked(getRpgCreationSession).mockResolvedValue(mockSession);
|
||||
vi.mocked(listRpgCreationWorks).mockResolvedValue([]);
|
||||
vi.mocked(executeRpgCreationAction).mockResolvedValue({
|
||||
operation: {
|
||||
@@ -669,6 +671,67 @@ test('create tab resumes agent workspace when draft has no compiled result yet',
|
||||
expect(screen.queryByText('世界档案')).toBeNull();
|
||||
});
|
||||
|
||||
test('opening a compiled draft with a missing agent session falls back to create hub', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
vi.mocked(listRpgCreationWorks)
|
||||
.mockResolvedValueOnce([
|
||||
{
|
||||
workId: 'draft:custom-world-agent-session-missing',
|
||||
sourceType: 'agent_session',
|
||||
status: 'draft',
|
||||
title: '潮雾列岛',
|
||||
subtitle: '世界底稿已生成',
|
||||
summary: '这是一份已经整理过首版结果页的草稿。',
|
||||
coverImageSrc: null,
|
||||
coverRenderMode: 'image',
|
||||
coverCharacterImageSrcs: [],
|
||||
updatedAt: '2026-04-20T11:00:00.000Z',
|
||||
publishedAt: null,
|
||||
stage: 'object_refining',
|
||||
stageLabel: '整理关键对象',
|
||||
playableNpcCount: 1,
|
||||
landmarkCount: 1,
|
||||
roleVisualReadyCount: 0,
|
||||
roleAnimationReadyCount: 0,
|
||||
roleAssetSummaryLabel: null,
|
||||
sessionId: 'custom-world-agent-session-missing',
|
||||
profileId: null,
|
||||
canResume: true,
|
||||
canEnterWorld: false,
|
||||
},
|
||||
])
|
||||
.mockResolvedValueOnce([]);
|
||||
|
||||
vi.mocked(getRpgCreationSession).mockRejectedValueOnce(
|
||||
new ApiClientError({
|
||||
message: 'custom world agent session not found',
|
||||
status: 404,
|
||||
code: 'NOT_FOUND',
|
||||
}),
|
||||
);
|
||||
|
||||
render(<TestWrapper withAuth />);
|
||||
|
||||
await openCreationHub(user);
|
||||
await user.click(screen.getByRole('button', { name: /继续完善/u }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(
|
||||
'这份共创草稿已失效,已为你返回创作中心,请重新开始创作。',
|
||||
),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(window.location.search).toBe('');
|
||||
expect(listRpgCreationWorks).toHaveBeenCalledTimes(2);
|
||||
expect(screen.getByText('还没有作品')).toBeTruthy();
|
||||
expect(
|
||||
screen.queryByText('Agent工作区:custom-world-agent-session-missing'),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('clicking a public work while logged out routes through requireAuth', async () => {
|
||||
const user = userEvent.setup();
|
||||
const requireAuth = vi.fn();
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
publishRpgEntryWorldProfile,
|
||||
unpublishRpgEntryWorldProfile,
|
||||
} from '../../services/rpg-entry';
|
||||
import { ApiClientError } from '../../services/apiClient';
|
||||
import type { CustomWorldProfile } from '../../types';
|
||||
import {
|
||||
normalizeRpgEntryAgentBackedProfile,
|
||||
@@ -79,6 +80,14 @@ type UseRpgEntryLibraryDetailParams = {
|
||||
markAutoSavedProfile: (profile: CustomWorldProfile) => void;
|
||||
};
|
||||
|
||||
function isMissingRpgEntryAgentSessionError(error: unknown) {
|
||||
return (
|
||||
error instanceof ApiClientError &&
|
||||
error.status === 404 &&
|
||||
error.code === 'NOT_FOUND'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 负责平台详情、创作作品入口和结果页打开路径。
|
||||
* 平台壳层只消费“打开哪个面板”的结果,不再自己拼接恢复流程细节。
|
||||
@@ -218,7 +227,6 @@ export function useRpgEntryLibraryDetail(
|
||||
const handleOpenCreationWork = useCallback(
|
||||
async (work: CustomWorldWorkSummary) => {
|
||||
if (work.status === 'draft' && work.sessionId) {
|
||||
persistAgentUiState(work.sessionId, null);
|
||||
setCustomWorldError(null);
|
||||
setCustomWorldAutoSaveError(null);
|
||||
setCustomWorldAutoSaveState('idle');
|
||||
@@ -228,33 +236,57 @@ export function useRpgEntryLibraryDetail(
|
||||
const shouldOpenAgentWorkspace =
|
||||
work.playableNpcCount <= 0 && work.landmarkCount <= 0;
|
||||
|
||||
if (shouldOpenAgentWorkspace) {
|
||||
// 仅八锚点未整理成底稿时才恢复 Agent 对话工作区。
|
||||
suppressAgentDraftResultAutoOpen();
|
||||
setGeneratedCustomWorldProfile(null);
|
||||
setCustomWorldResultViewSource(null);
|
||||
try {
|
||||
if (shouldOpenAgentWorkspace) {
|
||||
// 仅八锚点未整理成底稿时才恢复 Agent 对话工作区。
|
||||
suppressAgentDraftResultAutoOpen();
|
||||
persistAgentUiState(work.sessionId, null);
|
||||
setGeneratedCustomWorldProfile(null);
|
||||
setCustomWorldResultViewSource(null);
|
||||
setPlatformTabToCreate();
|
||||
setSelectionStage('agent-workspace');
|
||||
return;
|
||||
}
|
||||
|
||||
releaseAgentDraftResultAutoOpenSuppression();
|
||||
const latestSession = await syncAgentSessionSnapshot(work.sessionId);
|
||||
const nextProfile = buildDraftResultProfile(latestSession);
|
||||
if (!nextProfile) {
|
||||
persistAgentUiState(work.sessionId, null);
|
||||
setPlatformError('当前草稿还没有可编辑的结果页数据,请先继续补齐锚点。');
|
||||
setPlatformTabToCreate();
|
||||
setSelectionStage('agent-workspace');
|
||||
return;
|
||||
}
|
||||
|
||||
persistAgentUiState(work.sessionId, null);
|
||||
setGeneratedCustomWorldProfile(
|
||||
normalizeRpgEntryAgentBackedProfile(nextProfile),
|
||||
);
|
||||
setCustomWorldResultViewSource('agent-draft');
|
||||
setPlatformTabToCreate();
|
||||
setSelectionStage('agent-workspace');
|
||||
setSelectionStage('custom-world-result');
|
||||
return;
|
||||
} catch (error) {
|
||||
if (isMissingRpgEntryAgentSessionError(error)) {
|
||||
// 失效会话不能继续保留在恢复状态里,否则刷新后会重复命中同一个坏 session。
|
||||
persistAgentUiState(null, null);
|
||||
setGeneratedCustomWorldProfile(null);
|
||||
setCustomWorldResultViewSource(null);
|
||||
await refreshCustomWorldWorks().catch(() => []);
|
||||
setPlatformError(
|
||||
'这份共创草稿已失效,已为你返回创作中心,请重新开始创作。',
|
||||
);
|
||||
} else {
|
||||
setPlatformError(
|
||||
resolveRpgEntryErrorMessage(error, '读取创作草稿失败。'),
|
||||
);
|
||||
}
|
||||
|
||||
setPlatformTabToCreate();
|
||||
setSelectionStage('platform');
|
||||
return;
|
||||
}
|
||||
|
||||
releaseAgentDraftResultAutoOpenSuppression();
|
||||
const latestSession = await syncAgentSessionSnapshot(work.sessionId);
|
||||
const nextProfile = buildDraftResultProfile(latestSession);
|
||||
if (!nextProfile) {
|
||||
setPlatformError('当前草稿还没有可编辑的结果页数据,请先继续补齐锚点。');
|
||||
setPlatformTabToCreate();
|
||||
setSelectionStage('agent-workspace');
|
||||
return;
|
||||
}
|
||||
|
||||
setGeneratedCustomWorldProfile(
|
||||
normalizeRpgEntryAgentBackedProfile(nextProfile),
|
||||
);
|
||||
setCustomWorldResultViewSource('agent-draft');
|
||||
setPlatformTabToCreate();
|
||||
setSelectionStage('custom-world-result');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!work.profileId) {
|
||||
|
||||
Reference in New Issue
Block a user