refactor: 收口缺失创作状态回退

This commit is contained in:
2026-06-04 02:12:52 +08:00
parent e6e0f93102
commit 5ba5ca6bf8
6 changed files with 350 additions and 80 deletions

View File

@@ -540,7 +540,10 @@ import {
buildPuzzleResultProfileId,
buildPuzzleResultWorkId,
} from './platformPuzzleIdentityModel';
import { resolveSelectionStageAfterProtectedDataLoss } from './platformSelectionStageModel';
import {
resolveSelectionStageAfterMissingCreationState,
resolveSelectionStageAfterProtectedDataLoss,
} from './platformSelectionStageModel';
import { PlatformTaskCompletionDialog } from './PlatformTaskCompletionDialog';
import { PlatformWorkDetailView } from './PlatformWorkDetailView';
import { usePlatformCreationAgentFlowController } from './usePlatformCreationAgentFlowController';
@@ -8861,88 +8864,53 @@ export function PlatformEntryFlowShellImpl({
);
useEffect(() => {
if (selectionStage === 'big-fish-result' && !bigFishSession?.draft) {
setSelectionStage(
bigFishSession ? 'big-fish-agent-workspace' : 'platform',
);
}
if (selectionStage === 'big-fish-runtime' && !bigFishRun) {
setSelectionStage(bigFishSession?.draft ? 'big-fish-result' : 'platform');
}
}, [bigFishRun, bigFishSession, selectionStage, setSelectionStage]);
const nextSelectionStage = resolveSelectionStageAfterMissingCreationState({
stage: selectionStage,
bigFish: {
hasSession: Boolean(bigFishSession),
hasSessionDraft: Boolean(bigFishSession?.draft),
hasRun: Boolean(bigFishRun),
},
match3d: {
hasSession: Boolean(match3dSession),
hasSessionDraft: Boolean(match3dSession?.draft),
hasRun: Boolean(match3dRun),
},
squareHole: {
hasSession: Boolean(squareHoleSession),
hasSessionDraft: Boolean(squareHoleSession?.draft),
hasRun: Boolean(squareHoleRun),
},
visualNovel: {
hasSession: Boolean(visualNovelSession),
hasSessionDraft: Boolean(visualNovelSession?.draft),
hasWork: Boolean(visualNovelWork),
hasWorkDraft: Boolean(visualNovelWork?.draft),
hasRun: Boolean(visualNovelRun),
},
babyObjectMatch: {
hasDraft: Boolean(babyObjectMatchDraft),
hasFormPayload: Boolean(babyObjectMatchFormPayload),
},
});
useEffect(() => {
if (selectionStage === 'match3d-result' && !match3dSession?.draft) {
setSelectionStage(
match3dSession ? 'match3d-agent-workspace' : 'platform',
);
}
if (selectionStage === 'match3d-runtime' && !match3dRun) {
setSelectionStage(match3dSession?.draft ? 'match3d-result' : 'platform');
}
}, [match3dRun, match3dSession, selectionStage, setSelectionStage]);
useEffect(() => {
if (selectionStage === 'square-hole-result' && !squareHoleSession?.draft) {
setSelectionStage(
squareHoleSession ? 'square-hole-agent-workspace' : 'platform',
);
}
if (selectionStage === 'square-hole-runtime' && !squareHoleRun) {
setSelectionStage(
squareHoleSession?.draft ? 'square-hole-result' : 'platform',
);
}
}, [selectionStage, setSelectionStage, squareHoleRun, squareHoleSession]);
useEffect(() => {
if (
selectionStage === 'visual-novel-result' &&
!visualNovelSession?.draft &&
!visualNovelWork?.draft
) {
setSelectionStage(
visualNovelSession ? 'visual-novel-agent-workspace' : 'platform',
);
}
if (selectionStage === 'visual-novel-runtime' && !visualNovelRun) {
setSelectionStage(
visualNovelSession?.draft || visualNovelWork?.draft
? 'visual-novel-result'
: 'platform',
);
}
if (selectionStage === 'visual-novel-gallery-detail' && !visualNovelWork) {
setSelectionStage('platform');
}
}, [
selectionStage,
setSelectionStage,
visualNovelRun,
visualNovelSession,
visualNovelWork,
]);
useEffect(() => {
if (
selectionStage === 'baby-object-match-result' &&
!babyObjectMatchDraft
) {
setSelectionStage(
babyObjectMatchFormPayload ? 'baby-object-match-workspace' : 'platform',
);
}
if (
selectionStage === 'baby-object-match-runtime' &&
!babyObjectMatchDraft
) {
setSelectionStage('platform');
if (nextSelectionStage !== selectionStage) {
setSelectionStage(nextSelectionStage);
}
}, [
babyObjectMatchDraft,
babyObjectMatchFormPayload,
bigFishRun,
bigFishSession,
match3dRun,
match3dSession,
selectionStage,
setSelectionStage,
squareHoleRun,
squareHoleSession,
visualNovelRun,
visualNovelSession,
visualNovelWork,
]);
const startBigFishRun = useCallback(async () => {

View File

@@ -1,7 +1,11 @@
import { describe, expect, test } from 'vitest';
import type { SelectionStage } from './platformEntryTypes';
import { resolveSelectionStageAfterProtectedDataLoss } from './platformSelectionStageModel';
import {
type MissingCreationStateParams,
resolveSelectionStageAfterMissingCreationState,
resolveSelectionStageAfterProtectedDataLoss,
} from './platformSelectionStageModel';
describe('platformSelectionStageModel', () => {
test('keeps public and workspace stages after protected data loss', () => {
@@ -72,4 +76,203 @@ describe('platformSelectionStageModel', () => {
);
});
});
test('resolves missing session draft result stages', () => {
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'big-fish-result',
bigFish: { hasSession: true, hasSessionDraft: false, hasRun: false },
}),
),
).toBe('big-fish-agent-workspace');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'big-fish-result',
bigFish: { hasSession: false, hasSessionDraft: false, hasRun: false },
}),
),
).toBe('platform');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'match3d-result',
match3d: { hasSession: true, hasSessionDraft: false, hasRun: false },
}),
),
).toBe('match3d-agent-workspace');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'square-hole-result',
squareHole: {
hasSession: true,
hasSessionDraft: false,
hasRun: false,
},
}),
),
).toBe('square-hole-agent-workspace');
});
test('resolves missing session run stages', () => {
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'big-fish-runtime',
bigFish: { hasSession: true, hasSessionDraft: true, hasRun: false },
}),
),
).toBe('big-fish-result');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'big-fish-runtime',
bigFish: { hasSession: true, hasSessionDraft: false, hasRun: false },
}),
),
).toBe('platform');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'match3d-runtime',
match3d: { hasSession: true, hasSessionDraft: true, hasRun: false },
}),
),
).toBe('match3d-result');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'square-hole-runtime',
squareHole: {
hasSession: true,
hasSessionDraft: true,
hasRun: false,
},
}),
),
).toBe('square-hole-result');
});
test('resolves visual novel and baby object missing state stages', () => {
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'visual-novel-result',
visualNovel: {
hasSession: true,
hasSessionDraft: false,
hasWork: false,
hasWorkDraft: false,
hasRun: false,
},
}),
),
).toBe('visual-novel-agent-workspace');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'visual-novel-runtime',
visualNovel: {
hasSession: true,
hasSessionDraft: false,
hasWork: true,
hasWorkDraft: true,
hasRun: false,
},
}),
),
).toBe('visual-novel-result');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'visual-novel-gallery-detail',
visualNovel: {
hasSession: false,
hasSessionDraft: false,
hasWork: false,
hasWorkDraft: false,
hasRun: false,
},
}),
),
).toBe('platform');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'baby-object-match-result',
babyObjectMatch: { hasDraft: false, hasFormPayload: true },
}),
),
).toBe('baby-object-match-workspace');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'baby-object-match-runtime',
babyObjectMatch: { hasDraft: false, hasFormPayload: true },
}),
),
).toBe('platform');
});
test('keeps stages when required creation state exists', () => {
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'big-fish-result',
bigFish: { hasSession: true, hasSessionDraft: true, hasRun: false },
}),
),
).toBe('big-fish-result');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'big-fish-runtime',
bigFish: { hasSession: true, hasSessionDraft: true, hasRun: true },
}),
),
).toBe('big-fish-runtime');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'visual-novel-gallery-detail',
visualNovel: {
hasSession: false,
hasSessionDraft: false,
hasWork: true,
hasWorkDraft: false,
hasRun: false,
},
}),
),
).toBe('visual-novel-gallery-detail');
expect(
resolveSelectionStageAfterMissingCreationState(
buildMissingCreationStateParams({
stage: 'platform',
}),
),
).toBe('platform');
});
});
function buildMissingCreationStateParams(
overrides: Partial<MissingCreationStateParams> = {},
): MissingCreationStateParams {
return {
stage: 'platform',
bigFish: { hasSession: false, hasSessionDraft: false, hasRun: false },
match3d: { hasSession: false, hasSessionDraft: false, hasRun: false },
squareHole: { hasSession: false, hasSessionDraft: false, hasRun: false },
visualNovel: {
hasSession: false,
hasSessionDraft: false,
hasWork: false,
hasWorkDraft: false,
hasRun: false,
},
babyObjectMatch: { hasDraft: false, hasFormPayload: false },
...overrides,
};
}

View File

@@ -57,3 +57,97 @@ export function resolveSelectionStageAfterProtectedDataLoss(
): SelectionStage {
return PROTECTED_DATA_LOSS_STABLE_STAGE_BY_STAGE[stage] ? stage : 'platform';
}
type SessionDraftRunState = {
hasSession: boolean;
hasSessionDraft: boolean;
hasRun: boolean;
};
type VisualNovelCreationState = {
hasSession: boolean;
hasSessionDraft: boolean;
hasWork: boolean;
hasWorkDraft: boolean;
hasRun: boolean;
};
type BabyObjectMatchCreationState = {
hasDraft: boolean;
hasFormPayload: boolean;
};
export type MissingCreationStateParams = {
stage: SelectionStage;
bigFish: SessionDraftRunState;
match3d: SessionDraftRunState;
squareHole: SessionDraftRunState;
visualNovel: VisualNovelCreationState;
babyObjectMatch: BabyObjectMatchCreationState;
};
export function resolveSelectionStageAfterMissingCreationState(
params: MissingCreationStateParams,
): SelectionStage {
const { stage } = params;
if (stage === 'big-fish-result' && !params.bigFish.hasSessionDraft) {
return params.bigFish.hasSession ? 'big-fish-agent-workspace' : 'platform';
}
if (stage === 'big-fish-runtime' && !params.bigFish.hasRun) {
return params.bigFish.hasSessionDraft ? 'big-fish-result' : 'platform';
}
if (stage === 'match3d-result' && !params.match3d.hasSessionDraft) {
return params.match3d.hasSession ? 'match3d-agent-workspace' : 'platform';
}
if (stage === 'match3d-runtime' && !params.match3d.hasRun) {
return params.match3d.hasSessionDraft ? 'match3d-result' : 'platform';
}
if (stage === 'square-hole-result' && !params.squareHole.hasSessionDraft) {
return params.squareHole.hasSession
? 'square-hole-agent-workspace'
: 'platform';
}
if (stage === 'square-hole-runtime' && !params.squareHole.hasRun) {
return params.squareHole.hasSessionDraft
? 'square-hole-result'
: 'platform';
}
if (
stage === 'visual-novel-result' &&
!params.visualNovel.hasSessionDraft &&
!params.visualNovel.hasWorkDraft
) {
return params.visualNovel.hasSession
? 'visual-novel-agent-workspace'
: 'platform';
}
if (stage === 'visual-novel-runtime' && !params.visualNovel.hasRun) {
return params.visualNovel.hasSessionDraft || params.visualNovel.hasWorkDraft
? 'visual-novel-result'
: 'platform';
}
if (stage === 'visual-novel-gallery-detail' && !params.visualNovel.hasWork) {
return 'platform';
}
if (
stage === 'baby-object-match-result' &&
!params.babyObjectMatch.hasDraft
) {
return params.babyObjectMatch.hasFormPayload
? 'baby-object-match-workspace'
: 'platform';
}
if (
stage === 'baby-object-match-runtime' &&
!params.babyObjectMatch.hasDraft
) {
return 'platform';
}
return stage;
}