收口创作入口契约后台表单
将统一创作契约泥点消耗改为数字字段并由前端格式化展示 将后台契约编辑从 JSON 文本改为结构化卡片与弹窗表单 隐藏玩法阶段等内部标识并按玩法默认映射自动带出 更新创作入口文档、团队记忆和回归测试
This commit is contained in:
@@ -205,6 +205,7 @@ export interface AdminUpsertCreationEntryEventBannersRequest {
|
||||
export interface UnifiedCreationSpecPayload {
|
||||
playId: string;
|
||||
title: string;
|
||||
mudPointCost: number;
|
||||
workspaceStage: string;
|
||||
generationStage: string;
|
||||
resultStage: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import {fireEvent, render, screen, waitFor} from '@testing-library/react';
|
||||
import {fireEvent, render, screen, waitFor, within} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import {beforeEach, expect, test, vi} from 'vitest';
|
||||
|
||||
@@ -28,6 +28,7 @@ vi.mock('../api/adminApiClient', () => ({
|
||||
const puzzleSpec: UnifiedCreationSpecPayload = {
|
||||
playId: 'puzzle',
|
||||
title: '拼图',
|
||||
mudPointCost: 10,
|
||||
workspaceStage: 'puzzle-agent-workspace',
|
||||
generationStage: 'puzzle-generating',
|
||||
resultStage: 'puzzle-result',
|
||||
@@ -93,6 +94,22 @@ test('创作入口后台展示并保存统一创作契约', async () => {
|
||||
).toContain('拼图');
|
||||
expect(container.querySelector('.admin-panel .admin-panel')).toBeNull();
|
||||
expect(container.querySelector('.admin-muted')).toBeNull();
|
||||
expect(screen.queryByLabelText('契约 JSON')).toBeNull();
|
||||
expect(screen.queryByText('puzzle-generating')).toBeNull();
|
||||
|
||||
await user.click(screen.getByRole('button', {name: '修改契约'}));
|
||||
const dialog = screen.getByRole('dialog', {name: '统一创作契约'});
|
||||
expect(within(dialog).queryByLabelText('玩法 ID')).toBeNull();
|
||||
expect(within(dialog).queryByLabelText('工作台阶段')).toBeNull();
|
||||
expect(within(dialog).queryByLabelText('生成阶段')).toBeNull();
|
||||
expect(within(dialog).queryByLabelText('结果阶段')).toBeNull();
|
||||
fireEvent.change(within(dialog).getByLabelText('泥点消耗'), {
|
||||
target: {value: '12'},
|
||||
});
|
||||
await user.click(within(dialog).getByRole('button', {name: '应用修改'}));
|
||||
|
||||
expect(screen.queryByRole('dialog', {name: '统一创作契约'})).toBeNull();
|
||||
expect(screen.getByText('12泥点数')).toBeTruthy();
|
||||
|
||||
await user.click(screen.getByRole('button', {name: '保存入库'}));
|
||||
await user.click(screen.getByRole('button', {name: '确认'}));
|
||||
@@ -102,7 +119,10 @@ test('创作入口后台展示并保存统一创作契约', async () => {
|
||||
'admin-token',
|
||||
expect.objectContaining({
|
||||
id: 'puzzle',
|
||||
unifiedCreationSpec: puzzleSpec,
|
||||
unifiedCreationSpec: {
|
||||
...puzzleSpec,
|
||||
mudPointCost: 12,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -110,6 +130,18 @@ test('创作入口后台展示并保存统一创作契约', async () => {
|
||||
|
||||
test('创作入口后台拒绝 playId 不一致的统一创作契约', async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(getAdminCreationEntryConfig).mockResolvedValueOnce({
|
||||
...configResponse,
|
||||
entries: [
|
||||
{
|
||||
...configResponse.entries[0]!,
|
||||
unifiedCreationSpec: {
|
||||
...puzzleSpec,
|
||||
playId: 'match3d',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
render(
|
||||
<AdminCreationEntrySwitchPage
|
||||
token="admin-token"
|
||||
@@ -117,15 +149,7 @@ test('创作入口后台拒绝 playId 不一致的统一创作契约', async ()
|
||||
/>,
|
||||
);
|
||||
|
||||
const textarea = await screen.findByLabelText('契约 JSON');
|
||||
fireEvent.change(textarea, {
|
||||
target: {
|
||||
value: JSON.stringify({
|
||||
...puzzleSpec,
|
||||
playId: 'match3d',
|
||||
}),
|
||||
},
|
||||
});
|
||||
await screen.findByText('pictureDescription');
|
||||
await user.click(screen.getByRole('button', {name: '保存入库'}));
|
||||
|
||||
expect(await screen.findByText('统一创作契约 playId 必须与入口 ID 一致')).toBeTruthy();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -791,6 +791,67 @@ button:disabled {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.admin-contract-card {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
border: 1px solid #eaded2;
|
||||
border-radius: 8px;
|
||||
background: #fffdf9;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.admin-contract-field-list,
|
||||
.admin-contract-field-editor-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.admin-contract-field-list {
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
}
|
||||
|
||||
.admin-contract-field-card,
|
||||
.admin-contract-field-editor {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
border: 1px solid #eaded2;
|
||||
border-radius: 8px;
|
||||
background: #fff8f1;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.admin-contract-field-card strong,
|
||||
.admin-contract-field-card span {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.admin-contract-field-card strong {
|
||||
color: #3d1f10;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.admin-contract-field-card span {
|
||||
color: #8f7868;
|
||||
font-size: 12px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.admin-contract-dialog {
|
||||
width: min(100%, 860px);
|
||||
}
|
||||
|
||||
.admin-contract-field-editor-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(120px, 0.6fr) minmax(0, 1fr) auto;
|
||||
gap: 10px;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.admin-contract-required-toggle {
|
||||
min-height: 42px;
|
||||
}
|
||||
|
||||
.admin-status {
|
||||
display: inline-flex;
|
||||
max-width: 460px;
|
||||
@@ -948,7 +1009,8 @@ button:disabled {
|
||||
.admin-two-column-wide,
|
||||
.admin-form-row,
|
||||
.admin-filter-grid,
|
||||
.admin-table-query-grid {
|
||||
.admin-table-query-grid,
|
||||
.admin-contract-field-editor-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user