refactor: 收口推荐运行态启动意图
This commit is contained in:
@@ -49,7 +49,7 @@
|
|||||||
## 2026-06-03 平台入口公开作品流身份规则收口
|
## 2026-06-03 平台入口公开作品流身份规则收口
|
||||||
|
|
||||||
- 背景:平台入口公开作品推荐流需要同时处理 RPG、拼图、抓大鹅、跳一跳、敲木鱼、视觉小说、Bark Battle、宝贝识物等卡片,公开作品身份、跨玩法去重、排序和推荐运行态 kind 判定曾放在 `PlatformEntryFlowShellImpl.tsx` 巨型实现里。
|
- 背景:平台入口公开作品推荐流需要同时处理 RPG、拼图、抓大鹅、跳一跳、敲木鱼、视觉小说、Bark Battle、宝贝识物等卡片,公开作品身份、跨玩法去重、排序和推荐运行态 kind 判定曾放在 `PlatformEntryFlowShellImpl.tsx` 巨型实现里。
|
||||||
- 决策:公开作品身份和排序规则统一收口到 `src/components/platform-entry/platformPublicGalleryFlow.ts`;入口壳层只调用该 Module 的 `getPlatformPublicGalleryEntryKey`、`getPlatformRecommendRuntimeKind`、`isSamePlatformPublicGalleryEntry` 和 `mergePlatformPublicGalleryEntries`。`edutainment` key 必须带 `templateId`,RPG 卡片回退为 `rpg`。
|
- 决策:公开作品身份、排序规则和推荐 runtime 启动意图统一收口到 `src/components/platform-entry/platformPublicGalleryFlow.ts`;入口壳层只调用该 Module 的 `getPlatformPublicGalleryEntryKey`、`getPlatformRecommendRuntimeKind`、`resolvePlatformRecommendRuntimeStartIntent`、`isSamePlatformPublicGalleryEntry` 和 `mergePlatformPublicGalleryEntries`。`edutainment` key 必须带 `templateId`,RPG 卡片回退为 `rpg`。推荐 runtime 启动 intent 只返回启动目标、`embedded` / `returnStage` 参数、阻断文案和错误落点;壳层仍执行 request key、运行态 API、错误 setter 与 UI 状态。
|
||||||
- 影响范围:平台入口推荐流、公开作品详情、推荐 runtime 启动、跨玩法公开作品合并,以及后续新增玩法的入口接入。
|
- 影响范围:平台入口推荐流、公开作品详情、推荐 runtime 启动、跨玩法公开作品合并,以及后续新增玩法的入口接入。
|
||||||
- 验证方式:`npm run test -- src/components/platform-entry/platformPublicGalleryFlow.test.ts`、`npm run typecheck`、`npm run check:encoding`、相关文件 ESLint 通过。
|
- 验证方式:`npm run test -- src/components/platform-entry/platformPublicGalleryFlow.test.ts`、`npm run typecheck`、`npm run check:encoding`、相关文件 ESLint 通过。
|
||||||
- 关联文档:`docs/technical/【前端架构】平台入口PublicGalleryFlowModule收口计划-2026-06-03.md`。
|
- 关联文档:`docs/technical/【前端架构】平台入口PublicGalleryFlowModule收口计划-2026-06-03.md`。
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ AI 文字游戏模板接入以 [AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_
|
|||||||
|
|
||||||
前端 Server-Sent Events 客户端传输层收口到 `src/services/sseStream.ts`,事件边界、UTF-8 flush、JSON 解析跳过和提前取消约定见 [【前端架构】SSE客户端传输层收口约定-2026-06-03.md](./technical/%E3%80%90%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84%E3%80%91SSE%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BC%A0%E8%BE%93%E5%B1%82%E6%94%B6%E5%8F%A3%E7%BA%A6%E5%AE%9A-2026-06-03.md)。
|
前端 Server-Sent Events 客户端传输层收口到 `src/services/sseStream.ts`,事件边界、UTF-8 flush、JSON 解析跳过和提前取消约定见 [【前端架构】SSE客户端传输层收口约定-2026-06-03.md](./technical/%E3%80%90%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84%E3%80%91SSE%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BC%A0%E8%BE%93%E5%B1%82%E6%94%B6%E5%8F%A3%E7%BA%A6%E5%AE%9A-2026-06-03.md)。
|
||||||
|
|
||||||
平台入口公开作品身份、跨玩法去重、推荐运行态 kind 判定和最新排序收口到 `src/components/platform-entry/platformPublicGalleryFlow.ts`,规则见 [【前端架构】平台入口PublicGalleryFlowModule收口计划-2026-06-03.md](./technical/%E3%80%90%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84%E3%80%91%E5%B9%B3%E5%8F%B0%E5%85%A5%E5%8F%A3PublicGalleryFlowModule%E6%94%B6%E5%8F%A3%E8%AE%A1%E5%88%92-2026-06-03.md)。
|
平台入口公开作品身份、跨玩法去重、推荐运行态 kind 判定、推荐 runtime 启动意图和最新排序收口到 `src/components/platform-entry/platformPublicGalleryFlow.ts`,规则见 [【前端架构】平台入口PublicGalleryFlowModule收口计划-2026-06-03.md](./technical/%E3%80%90%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84%E3%80%91%E5%B9%B3%E5%8F%B0%E5%85%A5%E5%8F%A3PublicGalleryFlowModule%E6%94%B6%E5%8F%A3%E8%AE%A1%E5%88%92-2026-06-03.md)。
|
||||||
|
|
||||||
统一作品详情页的玩法 kind、详情打开策略、自有作品动作模式、编辑 / 点赞 / 改造 / 启动意图和公开详情映射收口到 `src/components/platform-entry/platformPublicWorkDetailFlow.ts`;抓大鹅公开详情映射与启动 / 编辑 Adapter 的素材归一仍归 `platformMatch3DRuntimeProfile.ts`,规则见 [【前端架构】PlatformPublicWorkDetailFlow收口计划-2026-06-03.md](./technical/【前端架构】PlatformPublicWorkDetailFlow收口计划-2026-06-03.md)。
|
统一作品详情页的玩法 kind、详情打开策略、自有作品动作模式、编辑 / 点赞 / 改造 / 启动意图和公开详情映射收口到 `src/components/platform-entry/platformPublicWorkDetailFlow.ts`;抓大鹅公开详情映射与启动 / 编辑 Adapter 的素材归一仍归 `platformMatch3DRuntimeProfile.ts`,规则见 [【前端架构】PlatformPublicWorkDetailFlow收口计划-2026-06-03.md](./technical/【前端架构】PlatformPublicWorkDetailFlow收口计划-2026-06-03.md)。
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,11 @@
|
|||||||
|
|
||||||
- `getPlatformPublicGalleryEntryKey(entry)`:按玩法类型、作者和 `profileId` 生成公开作品身份。
|
- `getPlatformPublicGalleryEntryKey(entry)`:按玩法类型、作者和 `profileId` 生成公开作品身份。
|
||||||
- `getPlatformRecommendRuntimeKind(entry)`:把公开作品卡映射为推荐运行态 kind。
|
- `getPlatformRecommendRuntimeKind(entry)`:把公开作品卡映射为推荐运行态 kind。
|
||||||
|
- `resolvePlatformRecommendRuntimeStartIntent(entry, deps)`:把公开作品卡映射为推荐 runtime 启动意图、错误落点和 embedded / returnStage 参数。
|
||||||
- `isSamePlatformPublicGalleryEntry(left, right)`:按公开作品身份比较。
|
- `isSamePlatformPublicGalleryEntry(left, right)`:按公开作品身份比较。
|
||||||
- `mergePlatformPublicGalleryEntries(rpgEntries, puzzleEntries)`:统一完成 RPG 与各玩法公开作品去重、覆盖和倒序排序。
|
- `mergePlatformPublicGalleryEntries(rpgEntries, puzzleEntries)`:统一完成 RPG 与各玩法公开作品去重、覆盖和倒序排序。
|
||||||
|
|
||||||
入口壳层只调用这些函数,不再在 `PlatformEntryFlowShellImpl.tsx` 内手写公开作品身份和排序规则。`isRecommendRuntimeReadyForEntry` 暂留入口壳层,因为它依赖各运行态 run 状态,直接抽出会把更多 runtime 状态类型拖入这个 Module,降低本次改造的 locality。
|
入口壳层只调用这些函数,不再在 `PlatformEntryFlowShellImpl.tsx` 内手写公开作品身份、排序规则和推荐 runtime 启动能力矩阵。`isRecommendRuntimeReadyForEntry` 暂留入口壳层,因为它依赖各运行态 run 状态,直接抽出会把更多 runtime 状态类型拖入这个 Module,降低本次改造的 locality。
|
||||||
|
|
||||||
## 玩法身份规则
|
## 玩法身份规则
|
||||||
|
|
||||||
@@ -23,9 +24,18 @@
|
|||||||
- 最终 key 格式为 `${kind}:${ownerUserId}:${profileId}`。
|
- 最终 key 格式为 `${kind}:${ownerUserId}:${profileId}`。
|
||||||
- 合并时后进入的相同 key 会覆盖先进入的卡片,然后按 `publishedAt ?? updatedAt` 新到旧排序;非法时间按 `0` 处理。
|
- 合并时后进入的相同 key 会覆盖先进入的卡片,然后按 `publishedAt ?? updatedAt` 新到旧排序;非法时间按 `0` 处理。
|
||||||
|
|
||||||
|
## 推荐 runtime 启动意图
|
||||||
|
|
||||||
|
- `resolvePlatformRecommendRuntimeStartIntent` 只表达推荐 runtime 的启动目标,不执行鉴权、运行态 API、错误 setter、缓存、request key 或 UI 状态更新。
|
||||||
|
- 大鱼吃小鱼、拼图、跳一跳、敲木鱼、抓大鹅、方洞挑战、视觉小说、汪汪声浪和宝贝识物返回对应启动 intent;RPG 维持当前无嵌入 runtime 的 `mark-ready` 行为。
|
||||||
|
- 大鱼吃小鱼、拼图、抓大鹅、方洞挑战和汪汪声浪在公开卡无法拼出启动 work 时返回 `blocked`,同时给出 `errorTarget`,由壳层 Adapter 分发到对应玩法错误 setter。
|
||||||
|
- 拼图优先使用同 `profileId` 的 `selectedPuzzleDetail`,否则从公开卡映射兼容 work 摘要。
|
||||||
|
- 抓大鹅 public detail -> work mapper 必须作为 Adapter 注入,继续由 Match3D Runtime Profile Module 维护 `generatedItemAssets` 归一化与背景资产提升。推荐 runtime 固定沿用旧参数 `returnStage = 'work-detail'` 与 `embedded = true`。
|
||||||
|
- 汪汪声浪优先使用推荐流已持有的 `barkBattleGalleryEntries`,再回退公开卡映射;不额外读取作品架列表。
|
||||||
|
|
||||||
## 后续深化
|
## 后续深化
|
||||||
|
|
||||||
下一步可继续把平台入口的作品架刷新、删除确认和直达恢复逻辑收口成更深的 Work Shelf **Module**。当前 `platformPublicGalleryFlow` 先提供一个稳定 seam,使公开作品 identity 与 runtime kind 的修改集中在一处。
|
下一步可继续把平台入口的作品架刷新、删除确认和直达恢复逻辑收口成更深的 Work Shelf **Module**。当前 `platformPublicGalleryFlow` 先提供一个稳定 seam,使公开作品 identity、runtime kind 与推荐 runtime 启动意图的修改集中在一处。
|
||||||
|
|
||||||
## 验证
|
## 验证
|
||||||
|
|
||||||
|
|||||||
@@ -361,15 +361,7 @@ import {
|
|||||||
selectAdjacentPlatformRecommendEntry,
|
selectAdjacentPlatformRecommendEntry,
|
||||||
} from '../rpg-entry/rpgEntryPublicGalleryViewModel';
|
} from '../rpg-entry/rpgEntryPublicGalleryViewModel';
|
||||||
import {
|
import {
|
||||||
isBarkBattleGalleryEntry,
|
|
||||||
isBigFishGalleryEntry,
|
|
||||||
isEdutainmentGalleryEntry,
|
isEdutainmentGalleryEntry,
|
||||||
isJumpHopGalleryEntry,
|
|
||||||
isMatch3DGalleryEntry,
|
|
||||||
isPuzzleGalleryEntry,
|
|
||||||
isSquareHoleGalleryEntry,
|
|
||||||
isVisualNovelGalleryEntry,
|
|
||||||
isWoodenFishGalleryEntry,
|
|
||||||
mapBabyObjectMatchDraftToPlatformGalleryCard,
|
mapBabyObjectMatchDraftToPlatformGalleryCard,
|
||||||
mapBarkBattleWorkToPlatformGalleryCard,
|
mapBarkBattleWorkToPlatformGalleryCard,
|
||||||
mapBigFishWorkToPlatformGalleryCard,
|
mapBigFishWorkToPlatformGalleryCard,
|
||||||
@@ -514,15 +506,12 @@ import {
|
|||||||
isSamePlatformPublicGalleryEntry,
|
isSamePlatformPublicGalleryEntry,
|
||||||
mergePlatformPublicGalleryEntries,
|
mergePlatformPublicGalleryEntries,
|
||||||
type RecommendRuntimeKind,
|
type RecommendRuntimeKind,
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent,
|
||||||
} from './platformPublicGalleryFlow';
|
} from './platformPublicGalleryFlow';
|
||||||
import {
|
import {
|
||||||
mapBarkBattlePublicDetailToWorkSummary,
|
|
||||||
mapBarkBattleWorkToPublicWorkDetail,
|
mapBarkBattleWorkToPublicWorkDetail,
|
||||||
mapBigFishWorkToPublicWorkDetail,
|
mapBigFishWorkToPublicWorkDetail,
|
||||||
mapJumpHopWorkToPublicWorkDetail,
|
mapJumpHopWorkToPublicWorkDetail,
|
||||||
mapPublicWorkDetailToBigFishWork,
|
|
||||||
mapPublicWorkDetailToPuzzleWork,
|
|
||||||
mapPublicWorkDetailToSquareHoleWork,
|
|
||||||
mapPuzzleWorkToPublicWorkDetail,
|
mapPuzzleWorkToPublicWorkDetail,
|
||||||
mapRpgGalleryCardToPublicWorkDetail,
|
mapRpgGalleryCardToPublicWorkDetail,
|
||||||
mapSquareHoleWorkToPublicWorkDetail,
|
mapSquareHoleWorkToPublicWorkDetail,
|
||||||
@@ -12762,98 +12751,99 @@ export function PlatformEntryFlowShellImpl({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let started = false;
|
let started = false;
|
||||||
if (isBigFishGalleryEntry(entry)) {
|
const intent = resolvePlatformRecommendRuntimeStartIntent(entry, {
|
||||||
const work = mapPublicWorkDetailToBigFishWork(entry);
|
selectedPuzzleDetail,
|
||||||
if (!work) {
|
barkBattleGalleryEntries,
|
||||||
setBigFishError('当前作品缺少会话信息,暂时无法进入玩法。');
|
mapMatch3DWork: mapPublicWorkDetailToMatch3DWork,
|
||||||
} else {
|
|
||||||
started = await startBigFishRunFromWork(work, 'platform', {
|
|
||||||
embedded: true,
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else if (isPuzzleGalleryEntry(entry)) {
|
switch (intent.type) {
|
||||||
const work =
|
case 'blocked':
|
||||||
selectedPuzzleDetail?.profileId === entry.profileId
|
if (intent.errorTarget === 'big-fish') {
|
||||||
? selectedPuzzleDetail
|
setBigFishError(intent.errorMessage);
|
||||||
: mapPublicWorkDetailToPuzzleWork(entry);
|
} else if (intent.errorTarget === 'puzzle') {
|
||||||
if (!work) {
|
setPuzzleError(intent.errorMessage);
|
||||||
setPuzzleError('当前拼图作品信息不完整,暂时无法进入玩法。');
|
} else if (intent.errorTarget === 'match3d') {
|
||||||
|
setMatch3DError(intent.errorMessage);
|
||||||
|
} else if (intent.errorTarget === 'square-hole') {
|
||||||
|
setSquareHoleError(intent.errorMessage);
|
||||||
} else {
|
} else {
|
||||||
|
setBarkBattleError(intent.errorMessage);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'start-big-fish':
|
||||||
|
started = await startBigFishRunFromWork(intent.work, 'platform', {
|
||||||
|
embedded: intent.embedded,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'start-puzzle':
|
||||||
started = await startPuzzleRunFromProfile(
|
started = await startPuzzleRunFromProfile(
|
||||||
work.profileId,
|
intent.work.profileId,
|
||||||
'platform',
|
intent.returnStage,
|
||||||
work,
|
intent.work,
|
||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
{ embedded: true },
|
{ embedded: intent.embedded },
|
||||||
);
|
);
|
||||||
}
|
break;
|
||||||
} else if (isJumpHopGalleryEntry(entry)) {
|
case 'start-jump-hop':
|
||||||
started = await startJumpHopRunFromProfile(entry.profileId, {
|
started = await startJumpHopRunFromProfile(intent.profileId, {
|
||||||
embedded: true,
|
embedded: intent.embedded,
|
||||||
returnStage: 'platform',
|
returnStage: intent.returnStage,
|
||||||
});
|
});
|
||||||
} else if (isWoodenFishGalleryEntry(entry)) {
|
break;
|
||||||
started = await startWoodenFishRunFromProfile(entry.profileId, {
|
case 'start-wooden-fish':
|
||||||
embedded: true,
|
started = await startWoodenFishRunFromProfile(intent.profileId, {
|
||||||
returnStage: 'platform',
|
embedded: intent.embedded,
|
||||||
|
returnStage: intent.returnStage,
|
||||||
});
|
});
|
||||||
} else if (isMatch3DGalleryEntry(entry)) {
|
break;
|
||||||
const work = mapPublicWorkDetailToMatch3DWork(entry);
|
case 'start-match3d':
|
||||||
if (!work) {
|
|
||||||
setMatch3DError('当前抓大鹅作品信息不完整,暂时无法进入玩法。');
|
|
||||||
} else {
|
|
||||||
started = await startMatch3DRunFromProfile(
|
started = await startMatch3DRunFromProfile(
|
||||||
work,
|
intent.work,
|
||||||
'work-detail',
|
intent.returnStage,
|
||||||
false,
|
false,
|
||||||
{ embedded: true },
|
{ embedded: intent.embedded },
|
||||||
);
|
);
|
||||||
}
|
break;
|
||||||
} else if (isSquareHoleGalleryEntry(entry)) {
|
case 'start-square-hole':
|
||||||
const work = mapPublicWorkDetailToSquareHoleWork(entry);
|
|
||||||
if (!work) {
|
|
||||||
setSquareHoleError(
|
|
||||||
'当前方洞挑战作品信息不完整,暂时无法进入玩法。',
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
started = await startSquareHoleRunFromProfile(
|
started = await startSquareHoleRunFromProfile(
|
||||||
work,
|
intent.work,
|
||||||
'platform',
|
intent.returnStage,
|
||||||
false,
|
false,
|
||||||
{ embedded: true },
|
{ embedded: intent.embedded },
|
||||||
);
|
);
|
||||||
}
|
break;
|
||||||
} else if (isVisualNovelGalleryEntry(entry)) {
|
case 'start-visual-novel':
|
||||||
started = await startVisualNovelRunFromProfile(
|
started = await startVisualNovelRunFromProfile(
|
||||||
entry.profileId,
|
intent.profileId,
|
||||||
'platform',
|
intent.returnStage,
|
||||||
{ embedded: true },
|
{ embedded: intent.embedded },
|
||||||
);
|
);
|
||||||
} else if (isBarkBattleGalleryEntry(entry)) {
|
break;
|
||||||
const work =
|
case 'start-bark-battle':
|
||||||
barkBattleGalleryEntries.find(
|
started = await startBarkBattleRunFromWork(
|
||||||
(item) => item.workId === entry.workId,
|
intent.work,
|
||||||
) ?? mapBarkBattlePublicDetailToWorkSummary(entry);
|
intent.returnStage,
|
||||||
if (!work) {
|
{ embedded: intent.embedded },
|
||||||
setBarkBattleError(
|
|
||||||
'当前汪汪声浪作品信息不完整,暂时无法进入玩法。',
|
|
||||||
);
|
);
|
||||||
} else {
|
break;
|
||||||
started = await startBarkBattleRunFromWork(work, 'platform', {
|
case 'start-edutainment':
|
||||||
embedded: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (isEdutainmentGalleryEntry(entry)) {
|
|
||||||
started = await startBabyObjectMatchRuntimeFromEntry(
|
started = await startBabyObjectMatchRuntimeFromEntry(
|
||||||
entry,
|
intent.entry,
|
||||||
'platform',
|
intent.returnStage,
|
||||||
{
|
{
|
||||||
embedded: true,
|
embedded: intent.embedded,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
break;
|
||||||
|
case 'mark-ready':
|
||||||
started = true;
|
started = true;
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
const exhaustive: never = intent;
|
||||||
|
return exhaustive;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCurrentStartRequest()) {
|
if (!isCurrentStartRequest()) {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { expect, test } from 'vitest';
|
import { expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import type { BarkBattleWorkSummary } from '../../../packages/shared/src/contracts/barkBattle';
|
||||||
|
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
|
||||||
|
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||||
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
|
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
|
||||||
import {
|
import {
|
||||||
EDUTAINMENT_BABY_OBJECT_MATCH_TEMPLATE_ID,
|
EDUTAINMENT_BABY_OBJECT_MATCH_TEMPLATE_ID,
|
||||||
@@ -12,8 +15,16 @@ import {
|
|||||||
getPlatformRecommendRuntimeKind,
|
getPlatformRecommendRuntimeKind,
|
||||||
isSamePlatformPublicGalleryEntry,
|
isSamePlatformPublicGalleryEntry,
|
||||||
mergePlatformPublicGalleryEntries,
|
mergePlatformPublicGalleryEntries,
|
||||||
|
type PlatformRecommendRuntimeStartIntentDeps,
|
||||||
type RecommendRuntimeKind,
|
type RecommendRuntimeKind,
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent,
|
||||||
} from './platformPublicGalleryFlow';
|
} from './platformPublicGalleryFlow';
|
||||||
|
import {
|
||||||
|
mapBarkBattlePublicDetailToWorkSummary,
|
||||||
|
mapPublicWorkDetailToBigFishWork,
|
||||||
|
mapPublicWorkDetailToPuzzleWork,
|
||||||
|
mapPublicWorkDetailToSquareHoleWork,
|
||||||
|
} from './platformPublicWorkDetailFlow';
|
||||||
|
|
||||||
type TypedPlatformPublicGalleryCard = Extract<
|
type TypedPlatformPublicGalleryCard = Extract<
|
||||||
PlatformPublicGalleryCard,
|
PlatformPublicGalleryCard,
|
||||||
@@ -109,6 +120,99 @@ function buildTypedEntry(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildPuzzleWork(
|
||||||
|
overrides: Partial<PuzzleWorkSummary> = {},
|
||||||
|
): PuzzleWorkSummary {
|
||||||
|
return {
|
||||||
|
workId: 'puzzle-work',
|
||||||
|
profileId: 'puzzle-profile',
|
||||||
|
ownerUserId: 'user-1',
|
||||||
|
sourceSessionId: 'puzzle-session',
|
||||||
|
authorDisplayName: '玩家',
|
||||||
|
levelName: '拼图作品',
|
||||||
|
summary: '拼图摘要',
|
||||||
|
themeTags: ['拼图'],
|
||||||
|
coverImageSrc: '/puzzle-cover.png',
|
||||||
|
publicationStatus: 'published',
|
||||||
|
updatedAt: '2026-06-01T01:00:00.000Z',
|
||||||
|
publishedAt: '2026-06-01T00:00:00.000Z',
|
||||||
|
playCount: 3,
|
||||||
|
remixCount: 2,
|
||||||
|
likeCount: 1,
|
||||||
|
pointIncentiveTotalHalfPoints: 0,
|
||||||
|
pointIncentiveClaimedPoints: 0,
|
||||||
|
pointIncentiveTotalPoints: 0,
|
||||||
|
pointIncentiveClaimablePoints: 0,
|
||||||
|
publishReady: true,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 buildBarkBattleWork(
|
||||||
|
overrides: Partial<BarkBattleWorkSummary> = {},
|
||||||
|
): BarkBattleWorkSummary {
|
||||||
|
return {
|
||||||
|
workId: 'bark-battle-work',
|
||||||
|
draftId: 'bark-battle-draft',
|
||||||
|
ownerUserId: 'user-1',
|
||||||
|
authorDisplayName: '玩家',
|
||||||
|
title: '汪汪声浪作品',
|
||||||
|
summary: '汪汪摘要',
|
||||||
|
themeDescription: '森林擂台',
|
||||||
|
playerImageDescription: '小狗',
|
||||||
|
opponentImageDescription: '对手',
|
||||||
|
playerCharacterImageSrc: '/player.png',
|
||||||
|
opponentCharacterImageSrc: '/opponent.png',
|
||||||
|
uiBackgroundImageSrc: '/bark-bg.png',
|
||||||
|
difficultyPreset: 'normal',
|
||||||
|
status: 'published',
|
||||||
|
generationStatus: 'ready',
|
||||||
|
publishReady: true,
|
||||||
|
playCount: 9,
|
||||||
|
recentPlayCount7d: 2,
|
||||||
|
updatedAt: '2026-06-01T01:00:00.000Z',
|
||||||
|
publishedAt: '2026-06-01T00:00:00.000Z',
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRecommendRuntimeStartDeps(
|
||||||
|
overrides: Partial<PlatformRecommendRuntimeStartIntentDeps> = {},
|
||||||
|
): PlatformRecommendRuntimeStartIntentDeps {
|
||||||
|
return {
|
||||||
|
selectedPuzzleDetail: null,
|
||||||
|
barkBattleGalleryEntries: [],
|
||||||
|
mapMatch3DWork: () => buildMatch3DWork(),
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
test('platform public gallery flow resolves stable key and runtime kind for every play kind', () => {
|
test('platform public gallery flow resolves stable key and runtime kind for every play kind', () => {
|
||||||
const cases: Array<
|
const cases: Array<
|
||||||
[sourceType: PlatformGallerySourceType, keyKind: string, kind: RecommendRuntimeKind]
|
[sourceType: PlatformGallerySourceType, keyKind: string, kind: RecommendRuntimeKind]
|
||||||
@@ -160,6 +264,181 @@ test('platform public gallery flow compares entries by resolved identity', () =>
|
|||||||
expect(isSamePlatformPublicGalleryEntry(left, otherKind)).toBe(false);
|
expect(isSamePlatformPublicGalleryEntry(left, otherKind)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('platform public gallery flow resolves recommend runtime start intent', () => {
|
||||||
|
const bigFishEntry = buildTypedEntry('big-fish');
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
bigFishEntry,
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-big-fish',
|
||||||
|
work: mapPublicWorkDetailToBigFishWork(bigFishEntry),
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedPuzzleDetail = buildPuzzleWork({
|
||||||
|
profileId: 'puzzle-profile',
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
buildTypedEntry('puzzle'),
|
||||||
|
buildRecommendRuntimeStartDeps({ selectedPuzzleDetail }),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-puzzle',
|
||||||
|
work: selectedPuzzleDetail,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const puzzleEntry = buildTypedEntry('puzzle', {
|
||||||
|
profileId: 'fallback-puzzle-profile',
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
puzzleEntry,
|
||||||
|
buildRecommendRuntimeStartDeps({
|
||||||
|
selectedPuzzleDetail: buildPuzzleWork({ profileId: 'stale-profile' }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-puzzle',
|
||||||
|
work: mapPublicWorkDetailToPuzzleWork(puzzleEntry),
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
buildTypedEntry('jump-hop'),
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-jump-hop',
|
||||||
|
profileId: 'jump-hop-profile',
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
buildTypedEntry('wooden-fish'),
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-wooden-fish',
|
||||||
|
profileId: 'wooden-fish-profile',
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
buildTypedEntry('visual-novel'),
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-visual-novel',
|
||||||
|
profileId: 'visual-novel-profile',
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
buildTypedEntry('edutainment'),
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-edutainment',
|
||||||
|
entry: buildTypedEntry('edutainment'),
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
buildRpgEntry(),
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'mark-ready',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('platform public gallery flow resolves recommend runtime mapper-backed start intent', () => {
|
||||||
|
const match3DEntry = buildTypedEntry('match3d');
|
||||||
|
const match3DWork = buildMatch3DWork({ workId: 'mapped-match3d-work' });
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
match3DEntry,
|
||||||
|
buildRecommendRuntimeStartDeps({
|
||||||
|
mapMatch3DWork: (entry) =>
|
||||||
|
entry === match3DEntry ? match3DWork : null,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-match3d',
|
||||||
|
work: match3DWork,
|
||||||
|
returnStage: 'work-detail',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
match3DEntry,
|
||||||
|
buildRecommendRuntimeStartDeps({ mapMatch3DWork: () => null }),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'blocked',
|
||||||
|
errorTarget: 'match3d',
|
||||||
|
errorMessage: '当前抓大鹅作品信息不完整,暂时无法进入玩法。',
|
||||||
|
});
|
||||||
|
|
||||||
|
const squareHoleEntry = buildTypedEntry('square-hole');
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
squareHoleEntry,
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-square-hole',
|
||||||
|
work: mapPublicWorkDetailToSquareHoleWork(squareHoleEntry),
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('platform public gallery flow resolves recommend runtime bark battle priority', () => {
|
||||||
|
const entry = buildTypedEntry('bark-battle');
|
||||||
|
const galleryWork = buildBarkBattleWork({
|
||||||
|
workId: 'bark-battle-work',
|
||||||
|
title: '推荐缓存',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
entry,
|
||||||
|
buildRecommendRuntimeStartDeps({
|
||||||
|
barkBattleGalleryEntries: [galleryWork],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-bark-battle',
|
||||||
|
work: galleryWork,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
entry,
|
||||||
|
buildRecommendRuntimeStartDeps(),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
type: 'start-bark-battle',
|
||||||
|
work: mapBarkBattlePublicDetailToWorkSummary(entry),
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('platform public gallery flow merges duplicate identities and sorts newest first', () => {
|
test('platform public gallery flow merges duplicate identities and sorts newest first', () => {
|
||||||
const staleRpgEntry = buildRpgEntry({
|
const staleRpgEntry = buildRpgEntry({
|
||||||
profileId: 'shared-rpg',
|
profileId: 'shared-rpg',
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
|
import type { BarkBattleWorkSummary } from '../../../packages/shared/src/contracts/barkBattle';
|
||||||
|
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
|
||||||
|
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
|
||||||
|
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||||
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
|
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
|
||||||
|
import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks';
|
||||||
import {
|
import {
|
||||||
isBarkBattleGalleryEntry,
|
isBarkBattleGalleryEntry,
|
||||||
isBigFishGalleryEntry,
|
isBigFishGalleryEntry,
|
||||||
@@ -11,6 +16,12 @@ import {
|
|||||||
isWoodenFishGalleryEntry,
|
isWoodenFishGalleryEntry,
|
||||||
type PlatformPublicGalleryCard,
|
type PlatformPublicGalleryCard,
|
||||||
} from '../rpg-entry/rpgEntryWorldPresentation';
|
} from '../rpg-entry/rpgEntryWorldPresentation';
|
||||||
|
import {
|
||||||
|
mapBarkBattlePublicDetailToWorkSummary,
|
||||||
|
mapPublicWorkDetailToBigFishWork,
|
||||||
|
mapPublicWorkDetailToPuzzleWork,
|
||||||
|
mapPublicWorkDetailToSquareHoleWork,
|
||||||
|
} from './platformPublicWorkDetailFlow';
|
||||||
|
|
||||||
export type RecommendRuntimeKind =
|
export type RecommendRuntimeKind =
|
||||||
| 'bark-battle'
|
| 'bark-battle'
|
||||||
@@ -24,6 +35,85 @@ export type RecommendRuntimeKind =
|
|||||||
| 'visual-novel'
|
| 'visual-novel'
|
||||||
| 'rpg';
|
| 'rpg';
|
||||||
|
|
||||||
|
export type PlatformRecommendRuntimeStartErrorTarget =
|
||||||
|
| 'bark-battle'
|
||||||
|
| 'big-fish'
|
||||||
|
| 'match3d'
|
||||||
|
| 'puzzle'
|
||||||
|
| 'square-hole';
|
||||||
|
|
||||||
|
export type PlatformRecommendRuntimeStartIntent =
|
||||||
|
| {
|
||||||
|
type: 'blocked';
|
||||||
|
errorTarget: PlatformRecommendRuntimeStartErrorTarget;
|
||||||
|
errorMessage: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-big-fish';
|
||||||
|
work: BigFishWorkSummary;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-puzzle';
|
||||||
|
work: PuzzleWorkSummary;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-jump-hop';
|
||||||
|
profileId: string;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-wooden-fish';
|
||||||
|
profileId: string;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-match3d';
|
||||||
|
work: Match3DWorkSummary;
|
||||||
|
returnStage: 'work-detail';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-square-hole';
|
||||||
|
work: SquareHoleWorkSummary;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-visual-novel';
|
||||||
|
profileId: string;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-bark-battle';
|
||||||
|
work: BarkBattleWorkSummary;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'start-edutainment';
|
||||||
|
entry: PlatformPublicGalleryCard;
|
||||||
|
returnStage: 'platform';
|
||||||
|
embedded: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'mark-ready';
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PlatformRecommendRuntimeStartIntentDeps = {
|
||||||
|
selectedPuzzleDetail?: PuzzleWorkSummary | null;
|
||||||
|
barkBattleGalleryEntries?: readonly BarkBattleWorkSummary[];
|
||||||
|
mapMatch3DWork: (
|
||||||
|
entry: PlatformPublicGalleryCard,
|
||||||
|
) => Match3DWorkSummary | null;
|
||||||
|
};
|
||||||
|
|
||||||
export function getPlatformPublicGalleryEntryTime(
|
export function getPlatformPublicGalleryEntryTime(
|
||||||
entry: PlatformPublicGalleryCard,
|
entry: PlatformPublicGalleryCard,
|
||||||
) {
|
) {
|
||||||
@@ -100,6 +190,148 @@ export function getPlatformRecommendRuntimeKind(
|
|||||||
return 'rpg';
|
return 'rpg';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolvePlatformRecommendRuntimeStartIntent(
|
||||||
|
entry: PlatformPublicGalleryCard,
|
||||||
|
deps: PlatformRecommendRuntimeStartIntentDeps,
|
||||||
|
): PlatformRecommendRuntimeStartIntent {
|
||||||
|
if (isBigFishGalleryEntry(entry)) {
|
||||||
|
const work = mapPublicWorkDetailToBigFishWork(entry);
|
||||||
|
if (!work) {
|
||||||
|
return {
|
||||||
|
type: 'blocked',
|
||||||
|
errorTarget: 'big-fish',
|
||||||
|
errorMessage: '当前作品缺少会话信息,暂时无法进入玩法。',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'start-big-fish',
|
||||||
|
work,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPuzzleGalleryEntry(entry)) {
|
||||||
|
const work =
|
||||||
|
deps.selectedPuzzleDetail?.profileId === entry.profileId
|
||||||
|
? deps.selectedPuzzleDetail
|
||||||
|
: mapPublicWorkDetailToPuzzleWork(entry);
|
||||||
|
if (!work) {
|
||||||
|
return {
|
||||||
|
type: 'blocked',
|
||||||
|
errorTarget: 'puzzle',
|
||||||
|
errorMessage: '当前拼图作品信息不完整,暂时无法进入玩法。',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'start-puzzle',
|
||||||
|
work,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJumpHopGalleryEntry(entry)) {
|
||||||
|
return {
|
||||||
|
type: 'start-jump-hop',
|
||||||
|
profileId: entry.profileId,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWoodenFishGalleryEntry(entry)) {
|
||||||
|
return {
|
||||||
|
type: 'start-wooden-fish',
|
||||||
|
profileId: entry.profileId,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMatch3DGalleryEntry(entry)) {
|
||||||
|
// 中文注释:抓大鹅推荐 runtime 仍接 Match3D Module 的 Adapter,避免复制素材归一规则。
|
||||||
|
const work = deps.mapMatch3DWork(entry);
|
||||||
|
if (!work) {
|
||||||
|
return {
|
||||||
|
type: 'blocked',
|
||||||
|
errorTarget: 'match3d',
|
||||||
|
errorMessage: '当前抓大鹅作品信息不完整,暂时无法进入玩法。',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'start-match3d',
|
||||||
|
work,
|
||||||
|
returnStage: 'work-detail',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSquareHoleGalleryEntry(entry)) {
|
||||||
|
const work = mapPublicWorkDetailToSquareHoleWork(entry);
|
||||||
|
if (!work) {
|
||||||
|
return {
|
||||||
|
type: 'blocked',
|
||||||
|
errorTarget: 'square-hole',
|
||||||
|
errorMessage: '当前方洞挑战作品信息不完整,暂时无法进入玩法。',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'start-square-hole',
|
||||||
|
work,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVisualNovelGalleryEntry(entry)) {
|
||||||
|
return {
|
||||||
|
type: 'start-visual-novel',
|
||||||
|
profileId: entry.profileId,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBarkBattleGalleryEntry(entry)) {
|
||||||
|
const work =
|
||||||
|
deps.barkBattleGalleryEntries?.find(
|
||||||
|
(item) => item.workId === entry.workId,
|
||||||
|
) ?? mapBarkBattlePublicDetailToWorkSummary(entry);
|
||||||
|
if (!work) {
|
||||||
|
return {
|
||||||
|
type: 'blocked',
|
||||||
|
errorTarget: 'bark-battle',
|
||||||
|
errorMessage: '当前汪汪声浪作品信息不完整,暂时无法进入玩法。',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'start-bark-battle',
|
||||||
|
work,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEdutainmentGalleryEntry(entry)) {
|
||||||
|
return {
|
||||||
|
type: 'start-edutainment',
|
||||||
|
entry,
|
||||||
|
returnStage: 'platform',
|
||||||
|
embedded: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'mark-ready',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function isSamePlatformPublicGalleryEntry(
|
export function isSamePlatformPublicGalleryEntry(
|
||||||
left: PlatformPublicGalleryCard,
|
left: PlatformPublicGalleryCard,
|
||||||
right: PlatformPublicGalleryCard,
|
right: PlatformPublicGalleryCard,
|
||||||
|
|||||||
Reference in New Issue
Block a user