Files
Genarrative/src/components/platform-entry/barkBattleWorkCache.ts
T

243 lines
8.1 KiB
TypeScript

import type {
BarkBattleConfigEditorPayload,
BarkBattleDraftConfig,
BarkBattleGenerationStatus as SharedBarkBattleGenerationStatus,
BarkBattlePublishedConfig,
BarkBattleWorkSummary,
} from '../../../packages/shared/src/contracts/barkBattle';
export type BarkBattleGenerationStatus = SharedBarkBattleGenerationStatus;
export function mergeBarkBattleWorkSummary(
current: BarkBattleWorkSummary,
updated: BarkBattleWorkSummary,
): BarkBattleWorkSummary {
if (current.workId !== updated.workId) {
return current;
}
if (current.status === 'published' && updated.status !== 'published') {
return {
...updated,
...current,
playCount: current.playCount ?? updated.playCount,
recentPlayCount7d: current.recentPlayCount7d ?? updated.recentPlayCount7d,
updatedAt: current.updatedAt || updated.updatedAt,
publishedAt: current.publishedAt ?? updated.publishedAt,
};
}
return { ...current, ...updated };
}
export function hasBarkBattleSummaryRequiredImages(item: BarkBattleWorkSummary) {
return Boolean(
item.playerCharacterImageSrc?.trim() &&
item.opponentCharacterImageSrc?.trim() &&
item.uiBackgroundImageSrc?.trim(),
);
}
export function hasBarkBattleDraftRequiredImages(draft: BarkBattleDraftConfig) {
return Boolean(
draft.playerCharacterImageSrc?.trim() &&
draft.opponentCharacterImageSrc?.trim() &&
draft.uiBackgroundImageSrc?.trim(),
);
}
export function resolveBarkBattleDraftGenerationStatus(
draft: BarkBattleDraftConfig,
partialFailed: boolean,
): BarkBattleGenerationStatus {
if (hasBarkBattleDraftRequiredImages(draft)) {
return 'ready';
}
return partialFailed ? 'partial_failed' : 'pending_assets';
}
export function buildBarkBattlePublishedConfigFromDraft(
draft: BarkBattleDraftConfig,
): BarkBattlePublishedConfig {
return {
workId: draft.workId ?? draft.draftId,
draftId: draft.draftId,
configVersion: draft.configVersion ?? 1,
rulesetVersion: draft.rulesetVersion ?? 'bark-battle-ruleset-v1',
playTypeId: 'bark-battle',
title: draft.title,
description: draft.description,
themeDescription: draft.themeDescription,
playerImageDescription: draft.playerImageDescription,
opponentImageDescription: draft.opponentImageDescription,
onomatopoeia: draft.onomatopoeia,
playerCharacterImageSrc: draft.playerCharacterImageSrc,
opponentCharacterImageSrc: draft.opponentCharacterImageSrc,
uiBackgroundImageSrc: draft.uiBackgroundImageSrc,
difficultyPreset: draft.difficultyPreset,
updatedAt: draft.updatedAt,
publishedAt: draft.updatedAt,
};
}
export function buildBarkBattlePublishSnapshot(
draft: BarkBattleDraftConfig,
): BarkBattleConfigEditorPayload {
return {
title: draft.title,
description: draft.description,
themeDescription: draft.themeDescription,
playerImageDescription: draft.playerImageDescription,
opponentImageDescription: draft.opponentImageDescription,
onomatopoeia: draft.onomatopoeia,
...(draft.playerCharacterImageSrc
? { playerCharacterImageSrc: draft.playerCharacterImageSrc }
: {}),
...(draft.opponentCharacterImageSrc
? { opponentCharacterImageSrc: draft.opponentCharacterImageSrc }
: {}),
...(draft.uiBackgroundImageSrc
? { uiBackgroundImageSrc: draft.uiBackgroundImageSrc }
: {}),
difficultyPreset: draft.difficultyPreset,
};
}
export function mergeBarkBattlePublishedConfigAssets(
published: BarkBattlePublishedConfig,
draft: BarkBattleDraftConfig,
): BarkBattlePublishedConfig {
return {
...published,
playerCharacterImageSrc:
published.playerCharacterImageSrc ?? draft.playerCharacterImageSrc,
opponentCharacterImageSrc:
published.opponentCharacterImageSrc ?? draft.opponentCharacterImageSrc,
uiBackgroundImageSrc:
published.uiBackgroundImageSrc ?? draft.uiBackgroundImageSrc,
};
}
export function buildBarkBattlePublishedConfigFromWork(
work: BarkBattleWorkSummary,
): BarkBattlePublishedConfig {
return {
workId: work.workId,
draftId: work.draftId ?? null,
configVersion: 1,
rulesetVersion: 'bark-battle-ruleset-v1',
playTypeId: 'bark-battle',
title: work.title,
description: work.summary,
themeDescription: work.themeDescription,
playerImageDescription: work.playerImageDescription,
opponentImageDescription: work.opponentImageDescription,
onomatopoeia: work.onomatopoeia,
playerCharacterImageSrc: work.playerCharacterImageSrc ?? undefined,
opponentCharacterImageSrc: work.opponentCharacterImageSrc ?? undefined,
uiBackgroundImageSrc: work.uiBackgroundImageSrc ?? undefined,
difficultyPreset: work.difficultyPreset,
updatedAt: work.updatedAt,
publishedAt: work.publishedAt ?? work.updatedAt,
};
}
export function buildBarkBattleDraftConfigFromWorkSummary(
work: BarkBattleWorkSummary,
): BarkBattleDraftConfig {
return {
draftId: work.draftId ?? work.workId,
workId: work.workId,
title: work.title,
description: work.summary,
themeDescription: work.themeDescription,
playerImageDescription: work.playerImageDescription,
opponentImageDescription: work.opponentImageDescription,
onomatopoeia: work.onomatopoeia,
playerCharacterImageSrc: work.playerCharacterImageSrc ?? undefined,
opponentCharacterImageSrc: work.opponentCharacterImageSrc ?? undefined,
uiBackgroundImageSrc: work.uiBackgroundImageSrc ?? undefined,
difficultyPreset: work.difficultyPreset,
configVersion: 1,
rulesetVersion: 'bark-battle-ruleset-v1',
updatedAt: work.updatedAt,
};
}
export function shouldPreserveLocalBarkBattleWorkOnRefresh(
item: BarkBattleWorkSummary,
refreshed: readonly BarkBattleWorkSummary[],
) {
if (item.status === 'published') {
return !refreshed.some(
(entry) => entry.workId === item.workId && entry.status === 'published',
);
}
if (refreshed.some((entry) => entry.workId === item.workId)) {
return false;
}
// 中文注释:Bark Battle 创建/生成完成/保存后会先把本地摘要塞进作品架,
// 后端 /works 读模型可能短暂落后;只要刷新结果还没有同 workId,就保留本地草稿,
// 避免 ready 且三图齐全的草稿在刷新窗口期从“我的草稿”里消失。
return true;
}
export function buildBarkBattleWorkSummaryFromDraft(
draft: BarkBattleDraftConfig,
user:
| {
id: string;
displayName: string;
publicUserCode: string;
}
| null
| undefined,
generationStatus: BarkBattleGenerationStatus = 'pending_assets',
): BarkBattleWorkSummary {
const workId = draft.workId?.trim() || draft.draftId;
return {
workId,
draftId: draft.draftId,
ownerUserId: user?.id ?? '',
authorDisplayName: user?.displayName ?? '创作者',
title: draft.title,
summary: draft.description ?? '',
themeDescription: draft.themeDescription,
playerImageDescription: draft.playerImageDescription,
opponentImageDescription: draft.opponentImageDescription,
onomatopoeia: draft.onomatopoeia,
playerCharacterImageSrc: draft.playerCharacterImageSrc ?? null,
opponentCharacterImageSrc: draft.opponentCharacterImageSrc ?? null,
uiBackgroundImageSrc: draft.uiBackgroundImageSrc ?? null,
difficultyPreset: draft.difficultyPreset,
status: 'draft',
generationStatus,
publishReady: hasBarkBattleDraftRequiredImages(draft),
playCount: 0,
updatedAt: draft.updatedAt,
publishedAt: null,
};
}
export function mergeBarkBattleWorksByWorkId(
items: readonly BarkBattleWorkSummary[],
): BarkBattleWorkSummary[] {
const byWorkId = new Map<string, BarkBattleWorkSummary>();
for (const item of items) {
const current = byWorkId.get(item.workId);
if (!current) {
byWorkId.set(item.workId, item);
continue;
}
if (current.status !== 'published' && item.status === 'published') {
byWorkId.set(item.workId, { ...current, ...item });
continue;
}
if (current.status === item.status || current.status === 'published') {
byWorkId.set(item.workId, mergeBarkBattleWorkSummary(current, item));
}
}
return Array.from(byWorkId.values());
}