Files
Genarrative/src/components/platform-entry/platformPublicWorkDetailFlow.ts
T
kdletters 387a1c26e3 完成全量检查整改
清理已跟踪原始日志与个人本地配置
修复前后端有效门禁、测试和构建问题
补齐生产 Jenkins、SpacetimeDB 本地命令与文档约束
收紧图片编辑器状态、附件与媒体引用测试
排除已下线旧创作入口测试并清理 warning
2026-07-17 16:56:46 +08:00

1267 lines
32 KiB
TypeScript

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 {
PuzzleClearGalleryCardResponse,
PuzzleClearWorkProfileResponse,
} from '../../../packages/shared/src/contracts/puzzleClear';
import type { PuzzleRunSnapshot } from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
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 PlatformPublicWorkInteractionConfig = {
sourceType: string;
likeEnabled: boolean;
remixEnabled: boolean;
likeDisabledMessage: string;
remixDisabledMessage: string;
};
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 getPlatformPublicWorkInteractionSourceType(
entry: PlatformPublicGalleryCard,
) {
return 'sourceType' in entry ? entry.sourceType : 'custom-world';
}
function resolveConfiguredPublicWorkInteractionBlock(
entry: PlatformPublicGalleryCard,
configs: readonly PlatformPublicWorkInteractionConfig[] | null | undefined,
action: 'like' | 'remix',
): PlatformPublicWorkLikeIntent | PlatformPublicWorkRemixIntent | null {
const sourceType = getPlatformPublicWorkInteractionSourceType(entry);
const config = configs?.find((item) => item.sourceType === sourceType);
if (!config) {
return null;
}
if (action === 'like' && !config.likeEnabled) {
return {
type: 'unsupported',
errorMessage:
config.likeDisabledMessage.trim() || '该作品类型暂不支持点赞。',
};
}
if (action === 'remix' && !config.remixEnabled) {
return {
type: 'unsupported',
errorMessage:
config.remixDisabledMessage.trim() || '该作品类型暂不支持改造。',
};
}
return null;
}
export function resolvePlatformPublicWorkLikeIntent(
entry: PlatformPublicGalleryCard,
configs?: readonly PlatformPublicWorkInteractionConfig[] | null,
): PlatformPublicWorkLikeIntent {
const configuredBlock = resolveConfiguredPublicWorkInteractionBlock(
entry,
configs,
'like',
);
if (configuredBlock) {
return configuredBlock as 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,
configs?: readonly PlatformPublicWorkInteractionConfig[] | null,
): PlatformPublicWorkRemixIntent {
const configuredBlock = resolveConfiguredPublicWorkInteractionBlock(
entry,
configs,
'remix',
);
if (configuredBlock) {
return configuredBlock as 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;
}