import type { BarkBattleDraftConfig, BarkBattleGenerationStatus as SharedBarkBattleGenerationStatus, 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 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: Boolean( draft.playerCharacterImageSrc?.trim() && draft.opponentCharacterImageSrc?.trim() && draft.uiBackgroundImageSrc?.trim(), ), playCount: 0, updatedAt: draft.updatedAt, publishedAt: null, }; } export function mergeBarkBattleWorksByWorkId( items: readonly BarkBattleWorkSummary[], ): BarkBattleWorkSummary[] { const byWorkId = new Map(); 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()); }