refactor: 收口公开详情启动意图

This commit is contained in:
2026-06-04 00:46:58 +08:00
parent 37a35daddb
commit e1134cc9ec
6 changed files with 645 additions and 188 deletions

View File

@@ -534,6 +534,7 @@ import {
resolvePlatformPublicWorkDetailOpenStrategy,
resolvePlatformPublicWorkLikeIntent,
resolvePlatformPublicWorkRemixIntent,
resolvePlatformPublicWorkStartIntent,
resolveVisiblePuzzleDetailCoverCount,
} from './platformPublicWorkDetailFlow';
import {
@@ -12611,134 +12612,93 @@ export function PlatformEntryFlowShellImpl({
}
runProtectedAction(() => {
if (isBigFishGalleryEntry(selectedPublicWorkDetail)) {
const work = mapPublicWorkDetailToBigFishWork(selectedPublicWorkDetail);
if (!work) {
setPublicWorkDetailError('当前作品缺少会话信息,暂时无法进入玩法。');
return;
}
startBigFishRunFromWork(work);
return;
}
const intent = resolvePlatformPublicWorkStartIntent(
selectedPublicWorkDetail,
{
selectedPuzzleDetail,
selectedRpgDetailEntry: selectedDetailEntry,
barkBattleGalleryEntries,
barkBattleWorks,
mapMatch3DWork: mapPublicWorkDetailToMatch3DWork,
},
);
if (isPuzzleGalleryEntry(selectedPublicWorkDetail)) {
const work =
selectedPuzzleDetail?.profileId === selectedPublicWorkDetail.profileId
? selectedPuzzleDetail
: mapPublicWorkDetailToPuzzleWork(selectedPublicWorkDetail);
if (!work) {
setPublicWorkDetailError(
'当前拼图作品信息不完整,暂时无法进入玩法。',
switch (intent.type) {
case 'blocked':
setPublicWorkDetailError(intent.errorMessage);
return;
case 'start-big-fish':
startBigFishRunFromWork(intent.work, intent.returnStage);
return;
case 'start-puzzle':
setPublicWorkDetailError(null);
void startPuzzleRunFromProfile(
intent.work.profileId,
intent.returnStage,
intent.work,
true,
null,
{ authMode: intent.authMode },
);
return;
}
setPublicWorkDetailError(null);
void startPuzzleRunFromProfile(
work.profileId,
'work-detail',
work,
true,
null,
{ authMode: 'isolated' },
);
return;
}
if (isJumpHopGalleryEntry(selectedPublicWorkDetail)) {
setPublicWorkDetailError(null);
void startJumpHopRunFromProfile(selectedPublicWorkDetail.profileId, {
returnStage: 'work-detail',
});
return;
}
if (isWoodenFishGalleryEntry(selectedPublicWorkDetail)) {
setPublicWorkDetailError(null);
void startWoodenFishRunFromProfile(selectedPublicWorkDetail.profileId, {
returnStage: 'work-detail',
});
return;
}
if (isMatch3DGalleryEntry(selectedPublicWorkDetail)) {
const work = mapPublicWorkDetailToMatch3DWork(selectedPublicWorkDetail);
if (!work) {
setPublicWorkDetailError(
'当前抓大鹅作品信息不完整,暂时无法进入玩法。',
case 'start-jump-hop':
setPublicWorkDetailError(null);
void startJumpHopRunFromProfile(intent.profileId, {
returnStage: intent.returnStage,
});
return;
case 'start-wooden-fish':
setPublicWorkDetailError(null);
void startWoodenFishRunFromProfile(intent.profileId, {
returnStage: intent.returnStage,
});
return;
case 'start-match3d':
setPublicWorkDetailError(null);
void startMatch3DRunFromProfile(
intent.work,
intent.returnStage,
true,
);
return;
}
setPublicWorkDetailError(null);
void startMatch3DRunFromProfile(work, 'work-detail', true);
return;
}
if (isSquareHoleGalleryEntry(selectedPublicWorkDetail)) {
const work = mapPublicWorkDetailToSquareHoleWork(
selectedPublicWorkDetail,
);
if (!work) {
setPublicWorkDetailError(
'当前方洞挑战作品信息不完整,暂时无法进入玩法。',
case 'start-square-hole':
setPublicWorkDetailError(null);
void startSquareHoleRunFromProfile(
intent.work,
intent.returnStage,
true,
);
return;
}
setPublicWorkDetailError(null);
void startSquareHoleRunFromProfile(work, 'work-detail', true);
return;
}
if (isVisualNovelGalleryEntry(selectedPublicWorkDetail)) {
setPublicWorkDetailError(null);
void startVisualNovelRunFromProfile(
selectedPublicWorkDetail.profileId,
'work-detail',
);
return;
}
if (isBarkBattleGalleryEntry(selectedPublicWorkDetail)) {
const work =
barkBattleGalleryEntries.find(
(item) => item.workId === selectedPublicWorkDetail.workId,
) ??
barkBattleWorks.find(
(item) => item.workId === selectedPublicWorkDetail.workId,
) ??
mapBarkBattlePublicDetailToWorkSummary(selectedPublicWorkDetail);
if (!work) {
setPublicWorkDetailError(
'当前汪汪声浪作品信息不完整,暂时无法进入玩法。',
case 'start-visual-novel':
setPublicWorkDetailError(null);
void startVisualNovelRunFromProfile(
intent.profileId,
intent.returnStage,
);
return;
case 'start-bark-battle':
setPublicWorkDetailError(null);
startBarkBattleRunFromWork(intent.work, intent.returnStage);
return;
case 'start-edutainment':
setPublicWorkDetailError(null);
void startBabyObjectMatchRuntimeFromEntry(
intent.entry,
intent.returnStage,
);
return;
case 'record-rpg-gallery-play':
break;
default: {
const exhaustive: never = intent;
return exhaustive;
}
setPublicWorkDetailError(null);
startBarkBattleRunFromWork(work, 'work-detail');
return;
}
if (isEdutainmentGalleryEntry(selectedPublicWorkDetail)) {
setPublicWorkDetailError(null);
void startBabyObjectMatchRuntimeFromEntry(
selectedPublicWorkDetail,
'work-detail',
);
return;
}
const launchEntry =
selectedDetailEntry?.profileId === selectedPublicWorkDetail.profileId
? selectedDetailEntry
: null;
if (!launchEntry) {
setPublicWorkDetailError('作品详情尚未读取完成。');
return;
}
setIsPublicWorkDetailBusy(true);
void recordRpgEntryWorldGalleryPlay(
launchEntry.ownerUserId,
launchEntry.profileId,
intent.entry.ownerUserId,
intent.entry.profileId,
)
.then((updatedEntry) => {
setSelectedDetailEntry(updatedEntry);

View File

@@ -3,6 +3,7 @@ import { expect, test } from 'vitest';
import type { BarkBattleWorkSummary } from '../../../packages/shared/src/contracts/barkBattle';
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
import type { JumpHopGalleryCardResponse } from '../../../packages/shared/src/contracts/jumpHop';
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
import type { PuzzleRunSnapshot } from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
@@ -30,12 +31,14 @@ import {
mapWoodenFishWorkToPublicWorkDetail,
type PlatformPublicWorkDetailKind,
type PlatformPublicWorkDetailOpenStrategy,
type PlatformPublicWorkStartIntentDeps,
resolveActivePlatformPublicWorkAuthorEntry,
resolvePlatformPublicWorkActionMode,
resolvePlatformPublicWorkDetailOpenDecision,
resolvePlatformPublicWorkDetailOpenStrategy,
resolvePlatformPublicWorkLikeIntent,
resolvePlatformPublicWorkRemixIntent,
resolvePlatformPublicWorkStartIntent,
resolveVisiblePuzzleDetailCoverCount,
} from './platformPublicWorkDetailFlow';
@@ -56,7 +59,10 @@ type TypedPlatformPublicGalleryCardOverrides<
function narrowTypedEntry<TSourceType extends PlatformGallerySourceType>(
entry: TypedPlatformPublicGalleryCard,
): Extract<TypedPlatformPublicGalleryCard, { sourceType: TSourceType }> {
return entry as Extract<TypedPlatformPublicGalleryCard, { sourceType: TSourceType }>;
return entry as Extract<
TypedPlatformPublicGalleryCard,
{ sourceType: TSourceType }
>;
}
function buildRpgEntry(
@@ -104,19 +110,47 @@ function buildTypedEntry<TSourceType extends PlatformGallerySourceType>(
switch (sourceType) {
case 'puzzle':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'big-fish':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'match3d':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'square-hole':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'visual-novel':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'jump-hop':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'wooden-fish':
return narrowTypedEntry<TSourceType>({ ...common, ...overrides, sourceType });
return narrowTypedEntry<TSourceType>({
...common,
...overrides,
sourceType,
});
case 'edutainment':
return narrowTypedEntry<TSourceType>({
...common,
@@ -337,6 +371,45 @@ function buildBarkBattleWork(
};
}
function buildMatch3DWork(
overrides: Partial<Match3DWorkSummary> = {},
): Match3DWorkSummary {
return {
workId: 'match3d-work',
profileId: 'match3d-profile',
ownerUserId: 'user-1',
sourceSessionId: 'match3d-session',
gameName: '抓大鹅作品',
themeText: '经典消除',
summary: '抓大鹅摘要',
tags: ['抓大鹅'],
coverImageSrc: '/match3d-cover.png',
referenceImageSrc: null,
clearCount: 12,
difficulty: 4,
publicationStatus: 'published',
playCount: 10,
updatedAt: '2026-06-01T01:00:00.000Z',
publishedAt: '2026-06-01T00:00:00.000Z',
publishReady: true,
generatedItemAssets: [],
...overrides,
};
}
function buildStartIntentDeps(
overrides: Partial<PlatformPublicWorkStartIntentDeps> = {},
): PlatformPublicWorkStartIntentDeps {
return {
selectedPuzzleDetail: null,
selectedRpgDetailEntry: null,
barkBattleGalleryEntries: [],
barkBattleWorks: [],
mapMatch3DWork: () => buildMatch3DWork(),
...overrides,
};
}
test('platform public work detail flow resolves detail kind for every play kind', () => {
const cases: Array<
[sourceType: PlatformGallerySourceType, kind: PlatformPublicWorkDetailKind]
@@ -579,18 +652,16 @@ test('platform public work detail flow maps detail entries back to work summarie
});
expect(
mapBarkBattlePublicDetailToWorkSummary(
{
...buildTypedEntry('bark-battle', {
themeTags: ['森林', '小狗', '对手'],
coverImageSrc: '/bark-bg.png',
coverCharacterImageSrcs: ['/player.png', '/opponent.png'],
playCount: 11,
recentPlayCount7d: 5,
}),
sourceSessionId: 'bark-draft',
},
),
mapBarkBattlePublicDetailToWorkSummary({
...buildTypedEntry('bark-battle', {
themeTags: ['森林', '小狗', '对手'],
coverImageSrc: '/bark-bg.png',
coverCharacterImageSrcs: ['/player.png', '/opponent.png'],
playCount: 11,
recentPlayCount7d: 5,
}),
sourceSessionId: 'bark-draft',
}),
).toMatchObject({
workId: 'bark-battle-work',
draftId: 'bark-draft',
@@ -605,8 +676,12 @@ test('platform public work detail flow maps detail entries back to work summarie
recentPlayCount7d: 5,
});
expect(mapPublicWorkDetailToPuzzleWork(buildTypedEntry('big-fish'))).toBeNull();
expect(mapPublicWorkDetailToBigFishWork(buildTypedEntry('puzzle'))).toBeNull();
expect(
mapPublicWorkDetailToPuzzleWork(buildTypedEntry('big-fish')),
).toBeNull();
expect(
mapPublicWorkDetailToBigFishWork(buildTypedEntry('puzzle')),
).toBeNull();
expect(
mapPublicWorkDetailToSquareHoleWork(buildTypedEntry('puzzle')),
).toBeNull();
@@ -654,13 +729,15 @@ test('platform public work detail flow resolves edit mode only for owned works',
});
test('platform public work detail flow resolves like intent', () => {
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('big-fish'))).toEqual(
{
type: 'like-big-fish',
profileId: 'big-fish-profile',
},
);
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('puzzle'))).toEqual({
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('big-fish')),
).toEqual({
type: 'like-big-fish',
profileId: 'big-fish-profile',
});
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('puzzle')),
).toEqual({
type: 'like-puzzle',
profileId: 'puzzle-profile',
});
@@ -669,42 +746,50 @@ test('platform public work detail flow resolves like intent', () => {
ownerUserId: 'user-1',
profileId: 'rpg-profile',
});
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('match3d'))).toEqual(
{
type: 'like-rpg-gallery',
ownerUserId: 'user-1',
profileId: 'match3d-profile',
},
);
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('edutainment'))).toEqual({
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('match3d')),
).toEqual({
type: 'like-rpg-gallery',
ownerUserId: 'user-1',
profileId: 'match3d-profile',
});
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('edutainment')),
).toEqual({
type: 'unsupported',
errorMessage: '宝贝识物点赞将在后续版本开放。',
});
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('bark-battle'))).toEqual(
{
type: 'unsupported',
errorMessage: '汪汪声浪点赞将在后续版本开放。',
},
);
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('square-hole'))).toEqual({
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('bark-battle')),
).toEqual({
type: 'unsupported',
errorMessage: '汪汪声浪点赞将在后续版本开放。',
});
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('square-hole')),
).toEqual({
type: 'unsupported',
errorMessage: '方洞挑战点赞将在后续版本开放。',
});
expect(resolvePlatformPublicWorkLikeIntent(buildTypedEntry('visual-novel'))).toEqual({
expect(
resolvePlatformPublicWorkLikeIntent(buildTypedEntry('visual-novel')),
).toEqual({
type: 'unsupported',
errorMessage: '视觉小说点赞将在后续版本开放。',
});
});
test('platform public work detail flow resolves remix intent', () => {
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('big-fish'))).toEqual(
{
type: 'remix-big-fish',
profileId: 'big-fish-profile',
selectionStage: 'big-fish-result',
},
);
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('puzzle'))).toEqual({
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('big-fish')),
).toEqual({
type: 'remix-big-fish',
profileId: 'big-fish-profile',
selectionStage: 'big-fish-result',
});
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('puzzle')),
).toEqual({
type: 'remix-puzzle',
profileId: 'puzzle-profile',
selectionStage: 'puzzle-result',
@@ -714,38 +799,236 @@ test('platform public work detail flow resolves remix intent', () => {
ownerUserId: 'user-1',
profileId: 'rpg-profile',
});
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('match3d'))).toEqual(
{
type: 'unsupported',
errorMessage: '抓大鹅作品改造将在后续版本开放。',
},
);
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('square-hole'))).toEqual({
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('match3d')),
).toEqual({
type: 'unsupported',
errorMessage: '抓大鹅作品改造将在后续版本开放。',
});
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('square-hole')),
).toEqual({
type: 'unsupported',
errorMessage: '方洞挑战作品改造将在后续版本开放。',
});
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('jump-hop'))).toEqual({
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('jump-hop')),
).toEqual({
type: 'unsupported',
errorMessage: '跳一跳作品改造将在后续版本开放。',
});
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('wooden-fish'))).toEqual({
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('wooden-fish')),
).toEqual({
type: 'unsupported',
errorMessage: '敲木鱼作品改造将在后续版本开放。',
});
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('visual-novel'))).toEqual({
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('visual-novel')),
).toEqual({
type: 'unsupported',
errorMessage: '视觉小说作品改造将在后续版本开放。',
});
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('edutainment'))).toEqual({
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('edutainment')),
).toEqual({
type: 'unsupported',
errorMessage: '宝贝识物作品改造将在创作链路接入后开放。',
});
expect(resolvePlatformPublicWorkRemixIntent(buildTypedEntry('bark-battle'))).toEqual(
{
type: 'unsupported',
errorMessage: '汪汪声浪作品改造将在后续版本开放。',
},
);
expect(
resolvePlatformPublicWorkRemixIntent(buildTypedEntry('bark-battle')),
).toEqual({
type: 'unsupported',
errorMessage: '汪汪声浪作品改造将在后续版本开放。',
});
});
test('platform public work detail flow resolves start intent for direct launches', () => {
const bigFishEntry = buildTypedEntry('big-fish');
expect(
resolvePlatformPublicWorkStartIntent(bigFishEntry, buildStartIntentDeps()),
).toEqual({
type: 'start-big-fish',
work: mapPublicWorkDetailToBigFishWork(bigFishEntry),
returnStage: 'work-detail',
});
const selectedPuzzleDetail = buildPuzzleWork({
profileId: 'puzzle-profile',
});
expect(
resolvePlatformPublicWorkStartIntent(
buildTypedEntry('puzzle'),
buildStartIntentDeps({ selectedPuzzleDetail }),
),
).toEqual({
type: 'start-puzzle',
work: selectedPuzzleDetail,
returnStage: 'work-detail',
authMode: 'isolated',
});
const puzzleEntry = buildTypedEntry('puzzle', {
profileId: 'fallback-puzzle-profile',
});
expect(
resolvePlatformPublicWorkStartIntent(
puzzleEntry,
buildStartIntentDeps({
selectedPuzzleDetail: buildPuzzleWork({ profileId: 'stale-profile' }),
}),
),
).toEqual({
type: 'start-puzzle',
work: mapPublicWorkDetailToPuzzleWork(puzzleEntry),
returnStage: 'work-detail',
authMode: 'isolated',
});
expect(
resolvePlatformPublicWorkStartIntent(
buildTypedEntry('jump-hop'),
buildStartIntentDeps(),
),
).toEqual({
type: 'start-jump-hop',
profileId: 'jump-hop-profile',
returnStage: 'work-detail',
});
expect(
resolvePlatformPublicWorkStartIntent(
buildTypedEntry('wooden-fish'),
buildStartIntentDeps(),
),
).toEqual({
type: 'start-wooden-fish',
profileId: 'wooden-fish-profile',
returnStage: 'work-detail',
});
expect(
resolvePlatformPublicWorkStartIntent(
buildTypedEntry('visual-novel'),
buildStartIntentDeps(),
),
).toEqual({
type: 'start-visual-novel',
profileId: 'visual-novel-profile',
returnStage: 'work-detail',
});
expect(
resolvePlatformPublicWorkStartIntent(
buildTypedEntry('edutainment'),
buildStartIntentDeps(),
),
).toEqual({
type: 'start-edutainment',
entry: buildTypedEntry('edutainment'),
returnStage: 'work-detail',
});
});
test('platform public work detail flow resolves start intent for mapper-backed launches', () => {
const match3DEntry = buildTypedEntry('match3d');
const match3DWork = buildMatch3DWork({ workId: 'mapped-match3d-work' });
expect(
resolvePlatformPublicWorkStartIntent(
match3DEntry,
buildStartIntentDeps({
mapMatch3DWork: (entry) =>
entry === match3DEntry ? match3DWork : null,
}),
),
).toEqual({
type: 'start-match3d',
work: match3DWork,
returnStage: 'work-detail',
});
expect(
resolvePlatformPublicWorkStartIntent(
match3DEntry,
buildStartIntentDeps({ mapMatch3DWork: () => null }),
),
).toEqual({
type: 'blocked',
errorMessage: '当前抓大鹅作品信息不完整,暂时无法进入玩法。',
});
const squareHoleEntry = buildTypedEntry('square-hole');
expect(
resolvePlatformPublicWorkStartIntent(
squareHoleEntry,
buildStartIntentDeps(),
),
).toEqual({
type: 'start-square-hole',
work: mapPublicWorkDetailToSquareHoleWork(squareHoleEntry),
returnStage: 'work-detail',
});
});
test('platform public work detail flow resolves bark battle start work priority', () => {
const entry = buildTypedEntry('bark-battle');
const galleryWork = buildBarkBattleWork({
workId: 'bark-battle-work',
title: '作品架缓存',
});
const loadedWork = buildBarkBattleWork({
workId: 'bark-battle-work',
title: '完整作品列表',
});
expect(
resolvePlatformPublicWorkStartIntent(
entry,
buildStartIntentDeps({
barkBattleGalleryEntries: [galleryWork],
barkBattleWorks: [loadedWork],
}),
),
).toEqual({
type: 'start-bark-battle',
work: galleryWork,
returnStage: 'work-detail',
});
expect(
resolvePlatformPublicWorkStartIntent(
entry,
buildStartIntentDeps({
barkBattleWorks: [loadedWork],
}),
),
).toEqual({
type: 'start-bark-battle',
work: loadedWork,
returnStage: 'work-detail',
});
expect(
resolvePlatformPublicWorkStartIntent(entry, buildStartIntentDeps()),
).toEqual({
type: 'start-bark-battle',
work: mapBarkBattlePublicDetailToWorkSummary(entry),
returnStage: 'work-detail',
});
});
test('platform public work detail flow resolves rpg start intent from loaded detail', () => {
const rpgEntry = buildRpgEntry();
expect(
resolvePlatformPublicWorkStartIntent(
rpgEntry,
buildStartIntentDeps({ selectedRpgDetailEntry: rpgEntry }),
),
).toEqual({
type: 'record-rpg-gallery-play',
entry: rpgEntry,
});
expect(
resolvePlatformPublicWorkStartIntent(rpgEntry, buildStartIntentDeps()),
).toEqual({
type: 'blocked',
errorMessage: '作品详情尚未读取完成。',
});
});
test('platform public work detail flow resolves direct open decision', () => {

View File

@@ -4,6 +4,7 @@ import type {
JumpHopGalleryCardResponse,
JumpHopWorkProfileResponse,
} from '../../../packages/shared/src/contracts/jumpHop';
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
import type { PuzzleRunSnapshot } from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
@@ -121,6 +122,72 @@ export type PlatformPublicWorkRemixIntent =
errorMessage: string;
};
export type PlatformPublicWorkStartIntent =
| {
type: 'blocked';
errorMessage: string;
}
| {
type: 'start-big-fish';
work: BigFishWorkSummary;
returnStage: 'work-detail';
}
| {
type: 'start-puzzle';
work: PuzzleWorkSummary;
returnStage: 'work-detail';
authMode: 'isolated';
}
| {
type: 'start-jump-hop';
profileId: string;
returnStage: 'work-detail';
}
| {
type: 'start-wooden-fish';
profileId: string;
returnStage: 'work-detail';
}
| {
type: 'start-match3d';
work: Match3DWorkSummary;
returnStage: 'work-detail';
}
| {
type: 'start-square-hole';
work: SquareHoleWorkSummary;
returnStage: 'work-detail';
}
| {
type: 'start-visual-novel';
profileId: string;
returnStage: 'work-detail';
}
| {
type: 'start-bark-battle';
work: BarkBattleWorkSummary;
returnStage: 'work-detail';
}
| {
type: 'start-edutainment';
entry: PlatformPublicGalleryCard;
returnStage: 'work-detail';
}
| {
type: 'record-rpg-gallery-play';
entry: CustomWorldGalleryCard;
};
export type PlatformPublicWorkStartIntentDeps = {
selectedPuzzleDetail?: PuzzleWorkSummary | null;
selectedRpgDetailEntry?: CustomWorldGalleryCard | null;
barkBattleGalleryEntries?: readonly BarkBattleWorkSummary[];
barkBattleWorks?: readonly BarkBattleWorkSummary[];
mapMatch3DWork: (
entry: PlatformPublicGalleryCard,
) => Match3DWorkSummary | null;
};
export type PlatformPublicWorkDetailOpenDecision =
| {
type: 'blocked';
@@ -622,6 +689,149 @@ export function resolvePlatformPublicWorkRemixIntent(
};
}
export function resolvePlatformPublicWorkStartIntent(
entry: PlatformPublicGalleryCard,
deps: PlatformPublicWorkStartIntentDeps,
): PlatformPublicWorkStartIntent {
if (isBigFishGalleryEntry(entry)) {
const work = mapPublicWorkDetailToBigFishWork(entry);
if (!work) {
return {
type: 'blocked',
errorMessage: '当前作品缺少会话信息,暂时无法进入玩法。',
};
}
return {
type: 'start-big-fish',
work,
returnStage: 'work-detail',
};
}
if (isPuzzleGalleryEntry(entry)) {
const work =
deps.selectedPuzzleDetail?.profileId === entry.profileId
? deps.selectedPuzzleDetail
: mapPublicWorkDetailToPuzzleWork(entry);
if (!work) {
return {
type: 'blocked',
errorMessage: '当前拼图作品信息不完整,暂时无法进入玩法。',
};
}
return {
type: 'start-puzzle',
work,
returnStage: 'work-detail',
authMode: 'isolated',
};
}
if (isJumpHopGalleryEntry(entry)) {
return {
type: 'start-jump-hop',
profileId: entry.profileId,
returnStage: 'work-detail',
};
}
if (isWoodenFishGalleryEntry(entry)) {
return {
type: 'start-wooden-fish',
profileId: entry.profileId,
returnStage: 'work-detail',
};
}
if (isMatch3DGalleryEntry(entry)) {
// 中文注释:抓大鹅运行态素材归一仍归 Match3D Module公开详情 Flow 只接其 Adapter。
const work = deps.mapMatch3DWork(entry);
if (!work) {
return {
type: 'blocked',
errorMessage: '当前抓大鹅作品信息不完整,暂时无法进入玩法。',
};
}
return {
type: 'start-match3d',
work,
returnStage: 'work-detail',
};
}
if (isSquareHoleGalleryEntry(entry)) {
const work = mapPublicWorkDetailToSquareHoleWork(entry);
if (!work) {
return {
type: 'blocked',
errorMessage: '当前方洞挑战作品信息不完整,暂时无法进入玩法。',
};
}
return {
type: 'start-square-hole',
work,
returnStage: 'work-detail',
};
}
if (isVisualNovelGalleryEntry(entry)) {
return {
type: 'start-visual-novel',
profileId: entry.profileId,
returnStage: 'work-detail',
};
}
if (isBarkBattleGalleryEntry(entry)) {
const work =
deps.barkBattleGalleryEntries?.find(
(item) => item.workId === entry.workId,
) ??
deps.barkBattleWorks?.find((item) => item.workId === entry.workId) ??
mapBarkBattlePublicDetailToWorkSummary(entry);
if (!work) {
return {
type: 'blocked',
errorMessage: '当前汪汪声浪作品信息不完整,暂时无法进入玩法。',
};
}
return {
type: 'start-bark-battle',
work,
returnStage: 'work-detail',
};
}
if (isEdutainmentGalleryEntry(entry)) {
return {
type: 'start-edutainment',
entry,
returnStage: 'work-detail',
};
}
const launchEntry =
deps.selectedRpgDetailEntry?.profileId === entry.profileId
? deps.selectedRpgDetailEntry
: null;
if (!launchEntry) {
return {
type: 'blocked',
errorMessage: '作品详情尚未读取完成。',
};
}
return {
type: 'record-rpg-gallery-play',
entry: launchEntry,
};
}
export function resolvePlatformPublicWorkDetailOpenDecision(
entry: PlatformPublicGalleryCard,
deps: PlatformPublicWorkDetailOpenDecisionDeps = {},