按后台配置扣除创作泥点

前端创作表单泥点预校验改为读取入口契约配置

拼图和抓大鹅初始生成后端扣费改为解析后台配置

汪汪声浪初始三图生成按入口总成本拆分扣费

创作工作台按钮和确认弹窗展示后台配置泥点成本

补充泥点扣费回归测试并同步文档与共享记忆
This commit is contained in:
2026-06-08 15:47:48 +08:00
parent 3ca5a460f1
commit 5ea9f0a120
21 changed files with 425 additions and 45 deletions

View File

@@ -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();