按后台配置扣除创作泥点
前端创作表单泥点预校验改为读取入口契约配置 拼图和抓大鹅初始生成后端扣费改为解析后台配置 汪汪声浪初始三图生成按入口总成本拆分扣费 创作工作台按钮和确认弹窗展示后台配置泥点成本 补充泥点扣费回归测试并同步文档与共享记忆
This commit is contained in:
@@ -159,6 +159,7 @@ import {
|
||||
} from '../../services/big-fish-works';
|
||||
import {
|
||||
type CreationEntryConfig,
|
||||
DEFAULT_UNIFIED_CREATION_MUD_POINT_COST,
|
||||
fetchCreationEntryConfig,
|
||||
} from '../../services/creationEntryConfigService';
|
||||
import {
|
||||
@@ -686,10 +687,6 @@ async function buildRecommendRuntimeAuthOptions(
|
||||
|
||||
return RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS;
|
||||
}
|
||||
const PUZZLE_DRAFT_GENERATION_POINT_COST = 2;
|
||||
const MATCH3D_DRAFT_GENERATION_POINT_COST = 10;
|
||||
const BARK_BATTLE_DRAFT_GENERATION_POINT_COST = 3;
|
||||
|
||||
function getPlatformPublicGalleryEntryTime(entry: PlatformPublicGalleryCard) {
|
||||
const rawTime = entry.publishedAt ?? entry.updatedAt;
|
||||
const timestamp = new Date(rawTime).getTime();
|
||||
@@ -4128,6 +4125,18 @@ export function PlatformEntryFlowShellImpl({
|
||||
creationEntryTypes,
|
||||
'visual-novel',
|
||||
);
|
||||
const resolveCreationEntryMudPointCost = useCallback(
|
||||
(id: PlatformCreationTypeId) =>
|
||||
creationEntryTypes.find((item) => item.id === id)?.mudPointCost ??
|
||||
DEFAULT_UNIFIED_CREATION_MUD_POINT_COST,
|
||||
[creationEntryTypes],
|
||||
);
|
||||
const puzzleDraftGenerationPointCost =
|
||||
resolveCreationEntryMudPointCost('puzzle');
|
||||
const match3DDraftGenerationPointCost =
|
||||
resolveCreationEntryMudPointCost('match3d');
|
||||
const barkBattleDraftGenerationPointCost =
|
||||
resolveCreationEntryMudPointCost('bark-battle');
|
||||
const [profilePlayStats, setProfilePlayStats] =
|
||||
useState<ProfilePlayStatsResponse | null>(null);
|
||||
const [profilePlayStatsError, setProfilePlayStatsError] = useState<
|
||||
@@ -6944,21 +6953,30 @@ export function PlatformEntryFlowShellImpl({
|
||||
setPuzzleCreationError(null);
|
||||
setPuzzleError(null);
|
||||
return ensureEnoughDraftGenerationPointsFromServer(
|
||||
PUZZLE_DRAFT_GENERATION_POINT_COST,
|
||||
puzzleDraftGenerationPointCost,
|
||||
);
|
||||
}, [ensureEnoughDraftGenerationPointsFromServer]);
|
||||
}, [
|
||||
ensureEnoughDraftGenerationPointsFromServer,
|
||||
puzzleDraftGenerationPointCost,
|
||||
]);
|
||||
const preflightMatch3DDraftGeneration = useCallback(async () => {
|
||||
setMatch3DError(null);
|
||||
return ensureEnoughDraftGenerationPointsFromServer(
|
||||
MATCH3D_DRAFT_GENERATION_POINT_COST,
|
||||
match3DDraftGenerationPointCost,
|
||||
);
|
||||
}, [ensureEnoughDraftGenerationPointsFromServer]);
|
||||
}, [
|
||||
ensureEnoughDraftGenerationPointsFromServer,
|
||||
match3DDraftGenerationPointCost,
|
||||
]);
|
||||
const preflightBarkBattleDraftGeneration = useCallback(async () => {
|
||||
setBarkBattleError(null);
|
||||
return ensureEnoughDraftGenerationPointsFromServer(
|
||||
BARK_BATTLE_DRAFT_GENERATION_POINT_COST,
|
||||
barkBattleDraftGenerationPointCost,
|
||||
);
|
||||
}, [ensureEnoughDraftGenerationPointsFromServer]);
|
||||
}, [
|
||||
barkBattleDraftGenerationPointCost,
|
||||
ensureEnoughDraftGenerationPointsFromServer,
|
||||
]);
|
||||
const draftGenerationPointNoticeDescription = draftGenerationPointNotice
|
||||
? draftGenerationPointNotice.title === '读取泥点余额失败'
|
||||
? '当前表单不会丢失,关闭后可继续编辑,稍后再试。'
|
||||
@@ -7973,7 +7991,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
buildPendingPuzzleDraftMetadata(payload),
|
||||
);
|
||||
if (shouldConsumePuzzleDraftPoints) {
|
||||
adjustProfileWalletBalanceLocally(-PUZZLE_DRAFT_GENERATION_POINT_COST);
|
||||
adjustProfileWalletBalanceLocally(-puzzleDraftGenerationPointCost);
|
||||
}
|
||||
selectionStageRef.current = 'puzzle-generating';
|
||||
activePuzzleGenerationSessionIdRef.current = nextSession.sessionId;
|
||||
@@ -8126,7 +8144,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
if (shouldConsumePuzzleDraftPoints) {
|
||||
adjustProfileWalletBalanceLocally(PUZZLE_DRAFT_GENERATION_POINT_COST);
|
||||
adjustProfileWalletBalanceLocally(puzzleDraftGenerationPointCost);
|
||||
}
|
||||
const failedGenerationState =
|
||||
resolveFinishedMiniGameDraftGenerationState(
|
||||
@@ -8176,6 +8194,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
isViewingPuzzleGeneration,
|
||||
preflightPuzzleDraftGeneration,
|
||||
puzzleFlow,
|
||||
puzzleDraftGenerationPointCost,
|
||||
refreshPuzzleShelf,
|
||||
recoverCompletedPuzzleDraftGeneration,
|
||||
refreshPlatformDashboardSilently,
|
||||
@@ -8235,7 +8254,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
nextSession.sessionId,
|
||||
buildPendingMatch3DDraftMetadata(payload),
|
||||
);
|
||||
adjustProfileWalletBalanceLocally(-MATCH3D_DRAFT_GENERATION_POINT_COST);
|
||||
adjustProfileWalletBalanceLocally(-match3DDraftGenerationPointCost);
|
||||
selectionStageRef.current = 'match3d-generating';
|
||||
activeMatch3DGenerationSessionIdRef.current = nextSession.sessionId;
|
||||
setSelectionStage('match3d-generating');
|
||||
@@ -8378,7 +8397,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
await refreshMatch3DShelf().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
adjustProfileWalletBalanceLocally(MATCH3D_DRAFT_GENERATION_POINT_COST);
|
||||
adjustProfileWalletBalanceLocally(match3DDraftGenerationPointCost);
|
||||
const failedGenerationState =
|
||||
resolveFinishedMiniGameDraftGenerationState(
|
||||
generationState,
|
||||
@@ -8453,6 +8472,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
[
|
||||
adjustProfileWalletBalanceLocally,
|
||||
match3dRuntimeAdapter,
|
||||
match3DDraftGenerationPointCost,
|
||||
isViewingMatch3DGeneration,
|
||||
markDraftGenerating,
|
||||
markDraftFailed,
|
||||
@@ -18384,7 +18404,10 @@ export function PlatformEntryFlowShellImpl({
|
||||
>
|
||||
<UnifiedCreationWorkspace
|
||||
playId="match3d"
|
||||
spec={getUnifiedSpec('match3d')}
|
||||
spec={{
|
||||
...getUnifiedSpec('match3d'),
|
||||
mudPointCost: match3DDraftGenerationPointCost,
|
||||
}}
|
||||
session={match3dSession}
|
||||
isBusy={isStreamingMatch3DReply}
|
||||
error={match3dError}
|
||||
@@ -19491,7 +19514,10 @@ export function PlatformEntryFlowShellImpl({
|
||||
>
|
||||
<UnifiedCreationWorkspace
|
||||
playId="puzzle"
|
||||
spec={getUnifiedSpec('puzzle')}
|
||||
spec={{
|
||||
...getUnifiedSpec('puzzle'),
|
||||
mudPointCost: puzzleDraftGenerationPointCost,
|
||||
}}
|
||||
session={puzzleSession}
|
||||
isBusy={isStreamingPuzzleReply}
|
||||
error={puzzleError}
|
||||
|
||||
@@ -16,6 +16,7 @@ export type PlatformCreationTypeCard = {
|
||||
subtitle: string;
|
||||
badge: string;
|
||||
imageSrc: string;
|
||||
mudPointCost: number;
|
||||
mudPointCostLabel: string;
|
||||
locked: boolean;
|
||||
categoryId: string;
|
||||
@@ -144,6 +145,9 @@ export function derivePlatformCreationTypes(
|
||||
subtitle: item.subtitle,
|
||||
badge: item.badge,
|
||||
imageSrc: item.imageSrc,
|
||||
mudPointCost: normalizeMudPointCost(
|
||||
item.unifiedCreationSpec?.mudPointCost,
|
||||
),
|
||||
mudPointCostLabel: formatMudPointCostText(
|
||||
item.unifiedCreationSpec?.mudPointCost,
|
||||
),
|
||||
|
||||
@@ -77,6 +77,7 @@ import { listBigFishWorks } from '../../services/big-fish-works';
|
||||
import {
|
||||
type CreationEntryConfig,
|
||||
fetchCreationEntryConfig,
|
||||
type UnifiedCreationSpec,
|
||||
} from '../../services/creationEntryConfigService';
|
||||
import {
|
||||
cancelCreativeAgentSession,
|
||||
@@ -184,6 +185,10 @@ import {
|
||||
AuthUiContext,
|
||||
type PlatformSettingsSection,
|
||||
} from '../auth/AuthUiContext';
|
||||
import {
|
||||
getUnifiedCreationSpec,
|
||||
type UnifiedCreationPlayId,
|
||||
} from '../unified-creation/unifiedCreationSpecs';
|
||||
import {
|
||||
RpgEntryFlowShell,
|
||||
type RpgEntryFlowShellProps,
|
||||
@@ -356,6 +361,16 @@ async function findPlatformTabPanel(tab: string) {
|
||||
return getPlatformTabPanel(tab);
|
||||
}
|
||||
|
||||
function buildTestUnifiedCreationSpec(
|
||||
playId: UnifiedCreationPlayId,
|
||||
mudPointCost: number,
|
||||
): UnifiedCreationSpec {
|
||||
return {
|
||||
...getUnifiedCreationSpec(playId),
|
||||
mudPointCost,
|
||||
};
|
||||
}
|
||||
|
||||
const testCreationEntryConfig = {
|
||||
startCard: {
|
||||
title: '新建作品',
|
||||
@@ -423,6 +438,7 @@ const testCreationEntryConfig = {
|
||||
categoryLabel: '热门推荐',
|
||||
categorySortOrder: 20,
|
||||
updatedAtMicros: 1,
|
||||
unifiedCreationSpec: buildTestUnifiedCreationSpec('puzzle', 8),
|
||||
},
|
||||
{
|
||||
id: 'match3d',
|
||||
@@ -437,6 +453,7 @@ const testCreationEntryConfig = {
|
||||
categoryLabel: '热门推荐',
|
||||
categorySortOrder: 20,
|
||||
updatedAtMicros: 1,
|
||||
unifiedCreationSpec: buildTestUnifiedCreationSpec('match3d', 12),
|
||||
},
|
||||
{
|
||||
id: 'bark-battle',
|
||||
@@ -451,6 +468,7 @@ const testCreationEntryConfig = {
|
||||
categoryLabel: '热门推荐',
|
||||
categorySortOrder: 20,
|
||||
updatedAtMicros: 1,
|
||||
unifiedCreationSpec: buildTestUnifiedCreationSpec('bark-battle', 6),
|
||||
},
|
||||
{
|
||||
id: 'square-hole',
|
||||
@@ -587,6 +605,7 @@ vi.mock('../../services/rpg-entry', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('../../services/creationEntryConfigService', () => ({
|
||||
DEFAULT_UNIFIED_CREATION_MUD_POINT_COST: 10,
|
||||
fetchCreationEntryConfig: vi.fn(),
|
||||
}));
|
||||
|
||||
@@ -3963,7 +3982,7 @@ test('direct bark battle runtime public code opens published runtime', async ()
|
||||
test('bark battle form checks mud points before creating image assets', async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(getProfileDashboard).mockResolvedValue({
|
||||
walletBalance: 2,
|
||||
walletBalance: 5,
|
||||
totalPlayTimeMs: 0,
|
||||
playedWorldCount: 0,
|
||||
updatedAt: '2026-05-14T10:00:00.000Z',
|
||||
@@ -3980,7 +3999,7 @@ test('bark battle form checks mud points before creating image assets', async ()
|
||||
|
||||
const noticeDialog = await screen.findByRole('dialog', { name: '泥点不足' });
|
||||
expect(
|
||||
within(noticeDialog).getByText('本次需要 3 泥点,当前 2 泥点。'),
|
||||
within(noticeDialog).getByText('本次需要 6 泥点,当前 5 泥点。'),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText('汪汪声浪配置表单')).toBeTruthy();
|
||||
expect(screen.queryByRole('tablist', { name: '创作入口页签' })).toBeNull();
|
||||
@@ -5309,7 +5328,7 @@ test('puzzle text-only form stays generating when compile starts background imag
|
||||
test('puzzle form checks mud points before creating a draft', async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(getProfileDashboard).mockResolvedValue({
|
||||
walletBalance: 1,
|
||||
walletBalance: 7,
|
||||
totalPlayTimeMs: 0,
|
||||
playedWorldCount: 0,
|
||||
updatedAt: '2026-05-14T10:00:00.000Z',
|
||||
@@ -5323,7 +5342,7 @@ test('puzzle form checks mud points before creating a draft', async () => {
|
||||
|
||||
const noticeDialog = await screen.findByRole('dialog', { name: '泥点不足' });
|
||||
expect(
|
||||
within(noticeDialog).getByText('本次需要 2 泥点,当前 1 泥点。'),
|
||||
within(noticeDialog).getByText('本次需要 8 泥点,当前 7 泥点。'),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText('拼图工作区:missing-session')).toBeTruthy();
|
||||
expect(screen.queryByRole('tablist', { name: '创作入口页签' })).toBeNull();
|
||||
@@ -5334,7 +5353,7 @@ test('puzzle form checks mud points before creating a draft', async () => {
|
||||
test('match3d form checks mud points before creating a draft', async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(getProfileDashboard).mockResolvedValue({
|
||||
walletBalance: 9,
|
||||
walletBalance: 11,
|
||||
totalPlayTimeMs: 0,
|
||||
playedWorldCount: 0,
|
||||
updatedAt: '2026-05-14T10:00:00.000Z',
|
||||
@@ -5350,7 +5369,7 @@ test('match3d form checks mud points before creating a draft', async () => {
|
||||
|
||||
const noticeDialog = await screen.findByRole('dialog', { name: '泥点不足' });
|
||||
expect(
|
||||
within(noticeDialog).getByText('本次需要 10 泥点,当前 9 泥点。'),
|
||||
within(noticeDialog).getByText('本次需要 12 泥点,当前 11 泥点。'),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText('抓大鹅工作区:missing-session')).toBeTruthy();
|
||||
expect(screen.queryByRole('tablist', { name: '创作入口页签' })).toBeNull();
|
||||
|
||||
@@ -68,6 +68,7 @@ export function UnifiedCreationWorkspace(props: UnifiedCreationWorkspaceProps) {
|
||||
showBackButton={false}
|
||||
title={null}
|
||||
unifiedChrome
|
||||
mudPointCost={props.spec.mudPointCost ?? undefined}
|
||||
/>
|
||||
</UnifiedCreationPage>
|
||||
);
|
||||
@@ -86,6 +87,7 @@ export function UnifiedCreationWorkspace(props: UnifiedCreationWorkspaceProps) {
|
||||
showBackButton={false}
|
||||
title={null}
|
||||
unifiedChrome
|
||||
mudPointCost={props.spec.mudPointCost ?? undefined}
|
||||
/>
|
||||
</UnifiedCreationPage>
|
||||
);
|
||||
|
||||
@@ -65,6 +65,13 @@ function confirmMatch3DPointCost() {
|
||||
fireEvent.click(within(confirmDialog).getByRole('button', { name: '确定' }));
|
||||
}
|
||||
|
||||
function confirmMatch3DPointCostText(text: string) {
|
||||
const confirmDialog = screen.getByRole('dialog', {
|
||||
name: '确认消耗泥点',
|
||||
});
|
||||
expect(within(confirmDialog).getByText(text)).toBeTruthy();
|
||||
}
|
||||
|
||||
test('match3d workspace submits derived entry form payload instead of agent chat', () => {
|
||||
const onCreateFromForm = vi.fn();
|
||||
const onExecuteAction = vi.fn();
|
||||
@@ -112,6 +119,26 @@ test('match3d workspace submits derived entry form payload instead of agent chat
|
||||
expect(onExecuteAction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('match3d workspace shows configured mud point cost', () => {
|
||||
render(
|
||||
<Match3DCreationWorkspace
|
||||
session={null}
|
||||
onBack={() => {}}
|
||||
onExecuteAction={() => {}}
|
||||
onCreateFromForm={() => {}}
|
||||
mudPointCost={12}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('消耗12泥点')).toBeTruthy();
|
||||
fireEvent.change(screen.getByLabelText('想做一个什么题材的抓大鹅?'), {
|
||||
target: { value: '陶泥甜品店' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: /生成抓大鹅草稿/u }));
|
||||
|
||||
confirmMatch3DPointCostText('消耗 12 泥点');
|
||||
});
|
||||
|
||||
test('match3d workspace can defer visible chrome to the unified creation page', () => {
|
||||
const { container } = render(
|
||||
<Match3DCreationWorkspace
|
||||
|
||||
@@ -20,6 +20,7 @@ type Match3DCreationWorkspaceProps = {
|
||||
showBackButton?: boolean;
|
||||
title?: string | null;
|
||||
unifiedChrome?: boolean;
|
||||
mudPointCost?: number;
|
||||
};
|
||||
|
||||
type Match3DFormState = {
|
||||
@@ -117,6 +118,7 @@ export function Match3DCreationWorkspace({
|
||||
showBackButton = true,
|
||||
title = '抓大鹅',
|
||||
unifiedChrome = false,
|
||||
mudPointCost = 10,
|
||||
}: Match3DCreationWorkspaceProps) {
|
||||
const [formState, setFormState] = useState<Match3DFormState>(() =>
|
||||
resolveInitialFormState(session, initialFormPayload),
|
||||
@@ -324,7 +326,7 @@ export function Match3DCreationWorkspace({
|
||||
)}
|
||||
<span>生成抓大鹅草稿</span>
|
||||
<span className="rounded-full bg-white/24 px-2 py-0.5 text-[11px] font-bold">
|
||||
消耗10泥点
|
||||
消耗{mudPointCost}泥点
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
@@ -345,7 +347,7 @@ export function Match3DCreationWorkspace({
|
||||
确认消耗泥点
|
||||
</div>
|
||||
<div className="mt-2 text-sm font-semibold leading-6 text-[var(--platform-text-base)]">
|
||||
消耗 10 泥点
|
||||
消耗 {mudPointCost} 泥点
|
||||
</div>
|
||||
<div className="mt-5 grid grid-cols-2 gap-3">
|
||||
<button
|
||||
|
||||
@@ -173,6 +173,13 @@ function confirmPuzzlePointCost() {
|
||||
fireEvent.click(within(confirmDialog).getByRole('button', { name: '确定' }));
|
||||
}
|
||||
|
||||
function confirmPuzzlePointCostText(text: string) {
|
||||
const confirmDialog = screen.getByRole('dialog', {
|
||||
name: '确认消耗泥点',
|
||||
});
|
||||
expect(within(confirmDialog).getByText(text)).toBeTruthy();
|
||||
}
|
||||
|
||||
test('puzzle workspace submits the work form instead of agent chat', () => {
|
||||
const onCreateFromForm = vi.fn();
|
||||
|
||||
@@ -216,6 +223,27 @@ test('puzzle workspace submits the work form instead of agent chat', () => {
|
||||
expect(screen.queryByText('旧会话消息不再渲染为聊天入口。')).toBeNull();
|
||||
});
|
||||
|
||||
test('puzzle workspace shows configured mud point cost', () => {
|
||||
render(
|
||||
<PuzzleCreationWorkspace
|
||||
session={null}
|
||||
onBack={() => {}}
|
||||
onSubmitMessage={() => {}}
|
||||
onExecuteAction={() => {}}
|
||||
onCreateFromForm={() => {}}
|
||||
mudPointCost={8}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('消耗8泥点')).toBeTruthy();
|
||||
fireEvent.change(screen.getByLabelText('画面描述'), {
|
||||
target: { value: '一座雨后的陶泥小镇。' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: /生成拼图游戏草稿/u }));
|
||||
|
||||
confirmPuzzlePointCostText('消耗 8 泥点');
|
||||
});
|
||||
|
||||
test('puzzle workspace can defer visible chrome to the unified creation page', () => {
|
||||
const { container } = render(
|
||||
<PuzzleCreationWorkspace
|
||||
|
||||
@@ -50,6 +50,7 @@ type PuzzleCreationWorkspaceProps = {
|
||||
showBackButton?: boolean;
|
||||
title?: string | null;
|
||||
unifiedChrome?: boolean;
|
||||
mudPointCost?: number;
|
||||
};
|
||||
|
||||
type PuzzleFormState = {
|
||||
@@ -248,6 +249,7 @@ export function PuzzleCreationWorkspace({
|
||||
showBackButton = true,
|
||||
title = '拼图',
|
||||
unifiedChrome = false,
|
||||
mudPointCost = 2,
|
||||
}: PuzzleCreationWorkspaceProps) {
|
||||
const [formState, setFormState] = useState<PuzzleFormState>(() =>
|
||||
resolveInitialFormState(session, initialFormPayload),
|
||||
@@ -667,7 +669,7 @@ export function PuzzleCreationWorkspace({
|
||||
inputError={referenceImageError}
|
||||
error={error}
|
||||
submitLabel="生成拼图游戏草稿"
|
||||
submitCostLabel={formState.aiRedraw ? '消耗2泥点' : null}
|
||||
submitCostLabel={formState.aiRedraw ? `消耗${mudPointCost}泥点` : null}
|
||||
submitDisabled={!canSubmit}
|
||||
labels={{
|
||||
imageField: '拼图画面',
|
||||
@@ -760,7 +762,7 @@ export function PuzzleCreationWorkspace({
|
||||
确认消耗泥点
|
||||
</div>
|
||||
<div className="mt-2 text-sm font-semibold leading-6 text-[var(--platform-text-base)]">
|
||||
消耗 2 泥点
|
||||
消耗 {mudPointCost} 泥点
|
||||
</div>
|
||||
<div className="mt-5 grid grid-cols-2 gap-3">
|
||||
<button
|
||||
|
||||
@@ -172,6 +172,7 @@ describe('barkBattleCreationClient', () => {
|
||||
body: JSON.stringify({
|
||||
slot: 'player-character',
|
||||
draftId: 'draft-1',
|
||||
billingPurpose: null,
|
||||
config: {
|
||||
title: '汪汪冠军杯',
|
||||
description: '',
|
||||
@@ -224,5 +225,16 @@ describe('barkBattleCreationClient', () => {
|
||||
'opponent-character': '泥点不足,本次需要 1 泥点,当前 0 泥点。',
|
||||
'ui-background': '场景图片生成失败:上游超时',
|
||||
});
|
||||
expect(requestJsonMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/api/creation/bark-battle/images/generate',
|
||||
expect.objectContaining({
|
||||
body: expect.stringContaining(
|
||||
'"billingPurpose":"initial_draft_generation"',
|
||||
),
|
||||
}),
|
||||
'生成汪汪声浪素材失败',
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -376,10 +376,12 @@ export function regenerateBarkBattleImageAsset(payload: {
|
||||
slot: BarkBattleAssetSlot;
|
||||
config: BarkBattleConfigEditorPayload;
|
||||
draftId?: string | null;
|
||||
billingPurpose?: BarkBattleImageAssetGenerateRequest['billingPurpose'];
|
||||
}): Promise<BarkBattleGeneratedImageAsset> {
|
||||
const request: BarkBattleImageAssetGenerateRequest = {
|
||||
slot: payload.slot,
|
||||
draftId: payload.draftId ?? null,
|
||||
billingPurpose: payload.billingPurpose ?? null,
|
||||
config: payload.config,
|
||||
};
|
||||
return requestJson<BarkBattleGeneratedImageAsset>(
|
||||
@@ -418,6 +420,7 @@ export async function generateAllBarkBattleImageAssets(payload: {
|
||||
slot,
|
||||
config: payload.config,
|
||||
draftId: payload.draftId,
|
||||
billingPurpose: 'initial_draft_generation',
|
||||
}),
|
||||
slot,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user