Files
Genarrative/src/components/platform-entry/platformPublicWorkDetailFlow.ts
kdletters 48c7cce1ba 合并 master 并修复架构分支回归
合入 master 最新的认证、玩法契约与推荐页改动。

修复拼图草稿生成、推荐页下一关和公开详情访客试玩回归。

修复抓大鹅草稿试玩鉴权与首屏推荐详情测试入口。

补齐相关测试夹具、文档与团队记忆更新。
2026-06-07 21:35:47 +08:00

1202 lines
30 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { BarkBattleWorkSummary } from '../../../packages/shared/src/contracts/barkBattle';
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
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 {
PuzzleClearGalleryCardResponse,
PuzzleClearWorkProfileResponse,
} from '../../../packages/shared/src/contracts/puzzleClear';
import type {
CustomWorldGalleryCard,
CustomWorldLibraryEntry,
} from '../../../packages/shared/src/contracts/runtime';
import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks';
import type { VisualNovelWorkSummary } from '../../../packages/shared/src/contracts/visualNovel';
import type {
WoodenFishGalleryCardResponse,
WoodenFishWorkProfileResponse,
} from '../../../packages/shared/src/contracts/woodenFish';
import { buildPublicWorkStagePath } from '../../routing/appPageRoutes';
import type { CustomWorldProfile } from '../../types';
import {
isBarkBattleGalleryEntry,
isBigFishGalleryEntry,
isEdutainmentGalleryEntry,
isJumpHopGalleryEntry,
isMatch3DGalleryEntry,
isPuzzleClearGalleryEntry,
isPuzzleGalleryEntry,
isSquareHoleGalleryEntry,
isVisualNovelGalleryEntry,
isWoodenFishGalleryEntry,
mapBarkBattleWorkToPlatformGalleryCard,
mapBigFishWorkToPlatformGalleryCard,
mapJumpHopWorkToPlatformGalleryCard,
mapPuzzleClearWorkToPlatformGalleryCard,
mapPuzzleWorkToPlatformGalleryCard,
mapSquareHoleWorkToPlatformGalleryCard,
mapVisualNovelWorkToPlatformGalleryCard,
mapWoodenFishWorkToPlatformGalleryCard,
type PlatformPublicGalleryCard,
} from '../rpg-entry/rpgEntryWorldPresentation';
import {
canExposePublicWork,
EDUTAINMENT_HIDDEN_MESSAGE,
} from './platformEdutainmentVisibility';
export type PlatformPublicWorkDetailKind =
| 'bark-battle'
| 'big-fish'
| 'edutainment'
| 'jump-hop'
| 'match3d'
| 'puzzle'
| 'puzzle-clear'
| 'rpg'
| 'square-hole'
| 'visual-novel'
| 'wooden-fish';
export type PlatformRpgPublicWorkDetailEntry =
| CustomWorldGalleryCard
| CustomWorldLibraryEntry<CustomWorldProfile>;
export type PlatformPublicWorkDetailOpenStrategy =
| {
type: 'use-entry';
kind: Exclude<
PlatformPublicWorkDetailKind,
'jump-hop' | 'puzzle' | 'rpg' | 'visual-novel' | 'wooden-fish'
>;
}
| {
type: 'load-puzzle-detail';
profileId: string;
}
| {
type: 'load-jump-hop-detail';
profileId: string;
}
| {
type: 'load-wooden-fish-detail';
profileId: string;
}
| {
type: 'load-visual-novel-detail';
profileId: string;
}
| {
type: 'load-rpg-detail';
entry: PlatformRpgPublicWorkDetailEntry;
};
export type PlatformPublicWorkActionMode = 'edit' | 'remix';
export type PlatformPublicWorkLikeIntent =
| {
type: 'like-big-fish';
profileId: string;
}
| {
type: 'like-puzzle';
profileId: string;
}
| {
type: 'like-rpg-gallery';
ownerUserId: string;
profileId: string;
}
| {
type: 'unsupported';
errorMessage: string;
};
export type PlatformPublicWorkRemixIntent =
| {
type: 'remix-big-fish';
profileId: string;
selectionStage: 'big-fish-result';
}
| {
type: 'remix-puzzle';
profileId: string;
selectionStage: 'puzzle-result';
}
| {
type: 'remix-rpg-gallery';
ownerUserId: string;
profileId: string;
}
| {
type: 'unsupported';
errorMessage: string;
};
export type PlatformPublicWorkEditIntent =
| {
type: 'blocked';
errorMessage: string;
}
| {
type: 'edit-big-fish';
work: BigFishWorkSummary;
}
| {
type: 'edit-puzzle';
work: PuzzleWorkSummary;
}
| {
type: 'edit-match3d';
work: Match3DWorkSummary;
forceDraft: true;
}
| {
type: 'edit-square-hole';
work: SquareHoleWorkSummary;
forceDraft: true;
}
| {
type: 'edit-visual-novel';
work: VisualNovelWorkSummary;
forceDraft: true;
}
| {
type: 'resolve-edutainment-draft';
entry: PlatformPublicGalleryCard;
}
| {
type: 'edit-bark-battle';
work: BarkBattleWorkSummary;
forceDraft: true;
}
| {
type: 'edit-rpg-gallery';
entry: CustomWorldLibraryEntry<CustomWorldProfile>;
};
export type PlatformPublicWorkEditIntentDeps = {
selectedPuzzleDetail?: PuzzleWorkSummary | null;
selectedRpgDetailEntry?: PlatformRpgPublicWorkDetailEntry | null;
visualNovelWorks?: readonly VisualNovelWorkSummary[];
barkBattleGalleryEntries?: readonly BarkBattleWorkSummary[];
barkBattleWorks?: readonly BarkBattleWorkSummary[];
mapMatch3DWork: (
entry: PlatformPublicGalleryCard,
) => Match3DWorkSummary | null;
};
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-puzzle-clear';
profileId: string;
returnStage: 'work-detail';
}
| {
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: PlatformRpgPublicWorkDetailEntry;
};
export type PlatformPublicWorkStartIntentDeps = {
selectedPuzzleDetail?: PuzzleWorkSummary | null;
selectedRpgDetailEntry?: PlatformRpgPublicWorkDetailEntry | null;
barkBattleGalleryEntries?: readonly BarkBattleWorkSummary[];
barkBattleWorks?: readonly BarkBattleWorkSummary[];
mapMatch3DWork: (
entry: PlatformPublicGalleryCard,
) => Match3DWorkSummary | null;
};
export type PlatformPublicWorkDetailOpenDecision =
| {
type: 'blocked';
selectedDetail: null;
errorMessage: string;
selectionStage: 'platform';
historyPath: null;
}
| {
type: 'open';
selectedDetail: PlatformPublicGalleryCard;
errorMessage: null;
selectionStage: 'work-detail';
historyPath: string | null;
};
export type PlatformPublicWorkDetailOpenDecisionDeps = {
canExposeEntry?: (entry: PlatformPublicGalleryCard) => boolean;
hiddenMessage?: string;
buildWorkDetailPath?: (publicWorkCode: string) => string;
};
export type ActivePlatformPublicWorkAuthorEntryInput = {
selectionStage: string;
selectedPublicWorkDetail: PlatformPublicGalleryCard | null;
selectedRpgDetailEntry: PlatformRpgPublicWorkDetailEntry | null;
};
export function isRpgPublicWorkDetailEntry(
entry: PlatformPublicGalleryCard,
): entry is PlatformRpgPublicWorkDetailEntry {
return !('sourceType' in entry);
}
export function mapRpgGalleryCardToPublicWorkDetail(
entry: PlatformRpgPublicWorkDetailEntry,
): CustomWorldGalleryCard {
return {
ownerUserId: entry.ownerUserId,
profileId: entry.profileId,
publicWorkCode: entry.publicWorkCode,
authorPublicUserCode: entry.authorPublicUserCode,
visibility: entry.visibility,
publishedAt: entry.publishedAt,
updatedAt: entry.updatedAt,
authorDisplayName: entry.authorDisplayName,
worldName: entry.worldName,
subtitle: entry.subtitle,
summaryText: entry.summaryText,
coverImageSrc: entry.coverImageSrc,
themeMode: entry.themeMode,
playableNpcCount: entry.playableNpcCount,
landmarkCount: entry.landmarkCount,
playCount: entry.playCount ?? 0,
remixCount: entry.remixCount ?? 0,
likeCount: entry.likeCount ?? 0,
recentPlayCount7d: entry.recentPlayCount7d ?? 0,
};
}
function isRpgPublicWorkLibraryEntry(
entry: PlatformRpgPublicWorkDetailEntry | null | undefined,
): entry is CustomWorldLibraryEntry<CustomWorldProfile> {
return Boolean(entry && 'profile' in entry);
}
export function mapPuzzleWorkToPublicWorkDetail(
item: PuzzleWorkSummary,
): PlatformPublicGalleryCard {
return mapPuzzleWorkToPlatformGalleryCard(item);
}
export function mapSquareHoleWorkToPublicWorkDetail(
item: SquareHoleWorkSummary,
): PlatformPublicGalleryCard {
return mapSquareHoleWorkToPlatformGalleryCard(item);
}
export function mapBigFishWorkToPublicWorkDetail(
item: BigFishWorkSummary,
): PlatformPublicGalleryCard {
return mapBigFishWorkToPlatformGalleryCard(item);
}
export function mapVisualNovelWorkToPublicWorkDetail(
item: VisualNovelWorkSummary,
): PlatformPublicGalleryCard {
return mapVisualNovelWorkToPlatformGalleryCard(item);
}
export function mapJumpHopWorkToPublicWorkDetail(
item: JumpHopGalleryCardResponse | JumpHopWorkProfileResponse,
): PlatformPublicGalleryCard {
return mapJumpHopWorkToPlatformGalleryCard(item);
}
export function mapPuzzleClearWorkToPublicWorkDetail(
item: PuzzleClearGalleryCardResponse | PuzzleClearWorkProfileResponse,
): PlatformPublicGalleryCard {
return mapPuzzleClearWorkToPlatformGalleryCard(item);
}
export function mapBarkBattleWorkToPublicWorkDetail(
item: BarkBattleWorkSummary,
): PlatformPublicGalleryCard {
return mapBarkBattleWorkToPlatformGalleryCard(item);
}
export function mapWoodenFishWorkToPublicWorkDetail(
item: WoodenFishGalleryCardResponse | WoodenFishWorkProfileResponse,
): PlatformPublicGalleryCard {
return mapWoodenFishWorkToPlatformGalleryCard(item);
}
export function mapBarkBattlePublicDetailToWorkSummary(
entry: PlatformPublicGalleryCard,
): BarkBattleWorkSummary | null {
if (!isBarkBattleGalleryEntry(entry)) {
return null;
}
return {
workId: entry.workId,
draftId: entry.sourceSessionId ?? null,
ownerUserId: entry.ownerUserId,
authorDisplayName: entry.authorDisplayName,
title: entry.worldName,
summary: entry.summaryText,
themeDescription: entry.themeTags[0] ?? entry.summaryText,
playerImageDescription: entry.themeTags[1] ?? entry.summaryText,
opponentImageDescription: entry.themeTags[2] ?? entry.summaryText,
onomatopoeia: undefined,
playerCharacterImageSrc: entry.coverCharacterImageSrcs[0] ?? null,
opponentCharacterImageSrc: entry.coverCharacterImageSrcs[1] ?? null,
uiBackgroundImageSrc: entry.coverImageSrc,
difficultyPreset: 'normal',
status: 'published',
generationStatus: 'ready',
publishReady: true,
playCount: entry.playCount ?? 0,
recentPlayCount7d: entry.recentPlayCount7d ?? 0,
updatedAt: entry.updatedAt,
publishedAt: entry.publishedAt,
};
}
export function mapPublicWorkDetailToPuzzleWork(
entry: PlatformPublicGalleryCard,
): PuzzleWorkSummary | null {
if (!isPuzzleGalleryEntry(entry)) {
return null;
}
return {
workId: entry.workId,
profileId: entry.profileId,
ownerUserId: entry.ownerUserId,
sourceSessionId:
'sourceSessionId' in entry && typeof entry.sourceSessionId === 'string'
? entry.sourceSessionId
: null,
authorDisplayName: entry.authorDisplayName,
levelName: entry.worldName,
summary: entry.summaryText,
themeTags: entry.themeTags,
coverImageSrc: entry.coverImageSrc,
publicationStatus: 'published',
updatedAt: entry.updatedAt,
publishedAt: entry.publishedAt,
playCount: entry.playCount ?? 0,
remixCount: entry.remixCount ?? 0,
likeCount: entry.likeCount ?? 0,
pointIncentiveTotalHalfPoints: 0,
pointIncentiveClaimedPoints: 0,
pointIncentiveTotalPoints: 0,
pointIncentiveClaimablePoints: 0,
publishReady: true,
levels:
entry.coverSlides?.map((slide, index) => ({
levelId: slide.id || `puzzle-level-${index + 1}`,
levelName: slide.label,
pictureDescription: entry.summaryText,
candidates: [],
selectedCandidateId: null,
coverImageSrc: slide.imageSrc,
coverAssetId: null,
generationStatus: 'ready' as const,
})) ?? [],
};
}
export function resolveVisiblePuzzleDetailCoverCount(
entry: PlatformPublicGalleryCard | null,
run: PuzzleRunSnapshot | null,
) {
if (!entry || !isPuzzleGalleryEntry(entry)) {
return 1;
}
if (run?.entryProfileId !== entry.profileId) {
return 1;
}
// 中文注释:封面首图永远公开,后续封面跟随当前玩家本次 run 的通关进度即时解锁。
return Math.max(1, run.clearedLevelCount + 1);
}
export function mapPublicWorkDetailToBigFishWork(
entry: PlatformPublicGalleryCard,
): BigFishWorkSummary | null {
if (!isBigFishGalleryEntry(entry)) {
return null;
}
const levelCount = Number.parseInt(
entry.themeTags.find((tag) => /^\d+$/u.test(tag))?.replace('', '') ??
'0',
10,
);
return {
workId: entry.workId,
sourceSessionId: entry.profileId,
ownerUserId: entry.ownerUserId,
authorDisplayName: entry.authorDisplayName,
title: entry.worldName,
subtitle: entry.subtitle,
summary: entry.summaryText,
coverImageSrc: entry.coverImageSrc,
status: 'published',
updatedAt: entry.updatedAt,
publishedAt: entry.publishedAt,
publishReady: true,
levelCount: Number.isNaN(levelCount) ? 0 : levelCount,
levelMainImageReadyCount: 0,
levelMotionReadyCount: 0,
backgroundReady: Boolean(entry.coverImageSrc),
playCount: entry.playCount ?? 0,
remixCount: entry.remixCount ?? 0,
likeCount: entry.likeCount ?? 0,
};
}
export function mapPublicWorkDetailToSquareHoleWork(
entry: PlatformPublicGalleryCard,
): SquareHoleWorkSummary | null {
if (!isSquareHoleGalleryEntry(entry)) {
return null;
}
return {
workId: entry.workId,
profileId: entry.profileId,
ownerUserId: entry.ownerUserId,
sourceSessionId:
'sourceSessionId' in entry && typeof entry.sourceSessionId === 'string'
? entry.sourceSessionId
: null,
gameName: entry.worldName,
themeText: entry.themeTags[0] ?? '方洞挑战',
twistRule: entry.subtitle,
summary: entry.summaryText,
tags: entry.themeTags,
coverImageSrc: entry.coverImageSrc,
backgroundPrompt: entry.backgroundPrompt ?? '方洞挑战运行背景',
backgroundImageSrc: entry.backgroundImageSrc ?? null,
shapeOptions: entry.shapeOptions ?? [],
holeOptions: entry.holeOptions ?? [],
shapeCount: entry.shapeCount ?? 8,
difficulty: entry.difficulty ?? 4,
publicationStatus: 'published',
playCount: entry.playCount ?? 0,
updatedAt: entry.updatedAt,
publishedAt: entry.publishedAt,
publishReady: true,
};
}
export function getPlatformPublicWorkDetailKind(
entry: PlatformPublicGalleryCard,
): PlatformPublicWorkDetailKind {
if (isBigFishGalleryEntry(entry)) {
return 'big-fish';
}
if (isPuzzleGalleryEntry(entry)) {
return 'puzzle';
}
if (isPuzzleClearGalleryEntry(entry)) {
return 'puzzle-clear';
}
if (isJumpHopGalleryEntry(entry)) {
return 'jump-hop';
}
if (isWoodenFishGalleryEntry(entry)) {
return 'wooden-fish';
}
if (isMatch3DGalleryEntry(entry)) {
return 'match3d';
}
if (isSquareHoleGalleryEntry(entry)) {
return 'square-hole';
}
if (isVisualNovelGalleryEntry(entry)) {
return 'visual-novel';
}
if (isBarkBattleGalleryEntry(entry)) {
return 'bark-battle';
}
if (isEdutainmentGalleryEntry(entry)) {
return 'edutainment';
}
return 'rpg';
}
export function resolvePlatformPublicWorkDetailOpenStrategy(
entry: PlatformPublicGalleryCard,
): PlatformPublicWorkDetailOpenStrategy {
if (isBigFishGalleryEntry(entry)) {
return {
type: 'use-entry',
kind: 'big-fish',
};
}
if (isPuzzleGalleryEntry(entry)) {
return {
type: 'load-puzzle-detail',
profileId: entry.profileId,
};
}
if (isPuzzleClearGalleryEntry(entry)) {
return {
type: 'use-entry',
kind: 'puzzle-clear',
};
}
if (isJumpHopGalleryEntry(entry)) {
return {
type: 'load-jump-hop-detail',
profileId: entry.profileId,
};
}
if (isWoodenFishGalleryEntry(entry)) {
return {
type: 'load-wooden-fish-detail',
profileId: entry.profileId,
};
}
if (isMatch3DGalleryEntry(entry)) {
return {
type: 'use-entry',
kind: 'match3d',
};
}
if (isSquareHoleGalleryEntry(entry)) {
return {
type: 'use-entry',
kind: 'square-hole',
};
}
if (isVisualNovelGalleryEntry(entry)) {
return {
type: 'load-visual-novel-detail',
profileId: entry.profileId,
};
}
if (isBarkBattleGalleryEntry(entry)) {
return {
type: 'use-entry',
kind: 'bark-battle',
};
}
if (isEdutainmentGalleryEntry(entry)) {
return {
type: 'use-entry',
kind: 'edutainment',
};
}
if (isRpgPublicWorkDetailEntry(entry)) {
return {
type: 'load-rpg-detail',
entry,
};
}
const exhaustive: never = entry;
return exhaustive;
}
export function resolvePlatformPublicWorkActionMode(
entry: PlatformPublicGalleryCard,
viewerUserId: string | null | undefined,
): PlatformPublicWorkActionMode {
return viewerUserId?.trim() && entry.ownerUserId === viewerUserId.trim()
? 'edit'
: 'remix';
}
export function resolvePlatformPublicWorkLikeIntent(
entry: PlatformPublicGalleryCard,
): PlatformPublicWorkLikeIntent {
if (isBigFishGalleryEntry(entry)) {
return {
type: 'like-big-fish',
profileId: entry.profileId,
};
}
if (isPuzzleGalleryEntry(entry)) {
return {
type: 'like-puzzle',
profileId: entry.profileId,
};
}
if (isEdutainmentGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '宝贝识物点赞将在后续版本开放。',
};
}
if (isPuzzleClearGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '拼消消点赞将在后续版本开放。',
};
}
if (isWoodenFishGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '作品类型 wooden-fish 暂不支持点赞。',
};
}
if (isJumpHopGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '作品类型 jump-hop 暂不支持点赞。',
};
}
if (isMatch3DGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '作品类型 match3d 暂不支持点赞。',
};
}
if (isBarkBattleGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '汪汪声浪点赞将在后续版本开放。',
};
}
if (isSquareHoleGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '方洞挑战点赞将在后续版本开放。',
};
}
if (isVisualNovelGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '视觉小说点赞将在后续版本开放。',
};
}
return {
type: 'like-rpg-gallery',
ownerUserId: entry.ownerUserId,
profileId: entry.profileId,
};
}
export function resolvePlatformPublicWorkRemixIntent(
entry: PlatformPublicGalleryCard,
): PlatformPublicWorkRemixIntent {
if (isBigFishGalleryEntry(entry)) {
return {
type: 'remix-big-fish',
profileId: entry.profileId,
selectionStage: 'big-fish-result',
};
}
if (isPuzzleGalleryEntry(entry)) {
return {
type: 'remix-puzzle',
profileId: entry.profileId,
selectionStage: 'puzzle-result',
};
}
if (isPuzzleClearGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '拼消消作品改造将在后续版本开放。',
};
}
if (isMatch3DGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '抓大鹅作品改造将在后续版本开放。',
};
}
if (isSquareHoleGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '方洞挑战作品改造将在后续版本开放。',
};
}
if (isJumpHopGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '跳一跳作品改造将在后续版本开放。',
};
}
if (isWoodenFishGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '敲木鱼作品改造将在后续版本开放。',
};
}
if (isVisualNovelGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '视觉小说作品改造将在后续版本开放。',
};
}
if (isEdutainmentGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '宝贝识物作品改造将在创作链路接入后开放。',
};
}
if (isBarkBattleGalleryEntry(entry)) {
return {
type: 'unsupported',
errorMessage: '汪汪声浪作品改造将在后续版本开放。',
};
}
return {
type: 'remix-rpg-gallery',
ownerUserId: entry.ownerUserId,
profileId: entry.profileId,
};
}
export function resolvePlatformPublicWorkEditIntent(
entry: PlatformPublicGalleryCard,
deps: PlatformPublicWorkEditIntentDeps,
): PlatformPublicWorkEditIntent {
if (isBigFishGalleryEntry(entry)) {
const work = mapPublicWorkDetailToBigFishWork(entry);
if (!work?.sourceSessionId?.trim()) {
return {
type: 'blocked',
errorMessage: '这份大鱼吃小鱼作品缺少原草稿会话,暂时无法编辑。',
};
}
return {
type: 'edit-big-fish',
work,
};
}
if (isPuzzleGalleryEntry(entry)) {
const work =
deps.selectedPuzzleDetail?.profileId === entry.profileId
? deps.selectedPuzzleDetail
: mapPublicWorkDetailToPuzzleWork(entry);
if (!work?.sourceSessionId?.trim()) {
return {
type: 'blocked',
errorMessage: '这份拼图作品缺少原草稿会话,暂时无法编辑。',
};
}
return {
type: 'edit-puzzle',
work,
};
}
if (isMatch3DGalleryEntry(entry)) {
// 中文注释:抓大鹅草稿恢复仍复用 Match3D Module 的 public detail -> work Adapter。
const work = deps.mapMatch3DWork(entry);
if (!work?.sourceSessionId?.trim()) {
return {
type: 'blocked',
errorMessage: '这份抓大鹅作品缺少原草稿会话,暂时无法编辑。',
};
}
return {
type: 'edit-match3d',
work,
forceDraft: true,
};
}
if (isSquareHoleGalleryEntry(entry)) {
const work = mapPublicWorkDetailToSquareHoleWork(entry);
if (!work?.sourceSessionId?.trim()) {
return {
type: 'blocked',
errorMessage: '这份方洞挑战作品缺少原草稿会话,暂时无法编辑。',
};
}
return {
type: 'edit-square-hole',
work,
forceDraft: true,
};
}
if (isJumpHopGalleryEntry(entry)) {
return {
type: 'blocked',
errorMessage: '这份跳一跳作品暂时请从作品架编辑。',
};
}
if (isPuzzleClearGalleryEntry(entry)) {
return {
type: 'blocked',
errorMessage: '这份拼消消作品暂时请从作品架编辑。',
};
}
if (isWoodenFishGalleryEntry(entry)) {
return {
type: 'blocked',
errorMessage: '这份敲木鱼作品暂时请从作品架编辑。',
};
}
if (isVisualNovelGalleryEntry(entry)) {
const work =
deps.visualNovelWorks?.find((item) => item.profileId === entry.profileId) ??
null;
if (!work) {
return {
type: 'blocked',
errorMessage: '这份视觉小说缺少可编辑草稿。',
};
}
return {
type: 'edit-visual-novel',
work,
forceDraft: true,
};
}
if (isEdutainmentGalleryEntry(entry)) {
return {
type: 'resolve-edutainment-draft',
entry,
};
}
if (isBarkBattleGalleryEntry(entry)) {
const work =
deps.barkBattleWorks?.find((item) => item.workId === entry.workId) ??
deps.barkBattleGalleryEntries?.find(
(item) => item.workId === entry.workId,
) ??
mapBarkBattlePublicDetailToWorkSummary(entry);
if (!work?.draftId?.trim()) {
return {
type: 'blocked',
errorMessage: '这份汪汪声浪缺少可编辑草稿。',
};
}
return {
type: 'edit-bark-battle',
work,
forceDraft: true,
};
}
const editEntry =
deps.selectedRpgDetailEntry?.profileId === entry.profileId &&
isRpgPublicWorkLibraryEntry(deps.selectedRpgDetailEntry)
? deps.selectedRpgDetailEntry
: null;
if (!editEntry) {
return {
type: 'blocked',
errorMessage: '作品详情尚未读取完成。',
};
}
return {
type: 'edit-rpg-gallery',
entry: editEntry,
};
}
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 (isPuzzleClearGalleryEntry(entry)) {
return {
type: 'start-puzzle-clear',
profileId: entry.profileId,
returnStage: 'work-detail',
};
}
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 = {},
): PlatformPublicWorkDetailOpenDecision {
const canExposeEntry = deps.canExposeEntry ?? canExposePublicWork;
const hiddenMessage = deps.hiddenMessage ?? EDUTAINMENT_HIDDEN_MESSAGE;
const buildWorkDetailPath =
deps.buildWorkDetailPath ??
((publicWorkCode: string) =>
buildPublicWorkStagePath('work-detail', publicWorkCode));
if (!canExposeEntry(entry)) {
return {
type: 'blocked',
selectedDetail: null,
errorMessage: hiddenMessage,
selectionStage: 'platform',
historyPath: null,
};
}
const publicWorkCode = entry.publicWorkCode?.trim()
? entry.publicWorkCode
: null;
return {
type: 'open',
selectedDetail: entry,
errorMessage: null,
selectionStage: 'work-detail',
historyPath: publicWorkCode ? buildWorkDetailPath(publicWorkCode) : null,
};
}
export function resolveActivePlatformPublicWorkAuthorEntry({
selectionStage,
selectedPublicWorkDetail,
selectedRpgDetailEntry,
}: ActivePlatformPublicWorkAuthorEntryInput): PlatformPublicGalleryCard | null {
if (selectionStage === 'work-detail') {
return selectedPublicWorkDetail;
}
if (
selectionStage === 'detail' &&
selectedRpgDetailEntry &&
selectedRpgDetailEntry.visibility !== 'draft'
) {
return selectedRpgDetailEntry;
}
return null;
}