后台游戏审核页展示买断制泥点价格
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
- adminApiTypes:AdminGameDistributionReviewEntry 与 AdminGameDistributionGameDetail 新增 priceMudPoints: number 字段 - 审核页待审列表新增「价格」列:priceMudPoints 为 0、缺失或旧响应时显示「免费」,否则显示「N 泥点」 - 审核详情资料区新增「价格」项,与列表共用同一格式化口径,避免出现 NaN - 同步审核表 nth-child 列宽定义:新增价格列 96px,提交时间与审核列顺移,窄屏媒体查询一并覆盖第 6 列 - 补齐 AdminGameDistributionReviewPage 测试:付费 30 泥点、免费与缺字段回落各一条,并在详情用例断言价格展示
This commit is contained in:
@@ -1138,6 +1138,8 @@ export interface AdminGameDistributionReviewEntry {
|
||||
packageBytes: number;
|
||||
status: string;
|
||||
publicationRevision: number;
|
||||
/** 买断制泥点价格;0 表示免费。旧响应可能缺该字段。 */
|
||||
priceMudPoints: number;
|
||||
reviewReason: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
@@ -1166,6 +1168,8 @@ export interface AdminGameDistributionGameDetail {
|
||||
orientation: string;
|
||||
status: string;
|
||||
publicationRevision: number;
|
||||
/** 买断制泥点价格;0 表示免费。旧响应可能缺该字段。 */
|
||||
priceMudPoints: number;
|
||||
playCount: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ const entry: AdminGameDistributionReviewEntry = {
|
||||
packageBytes: 2048,
|
||||
status: 'pending_review',
|
||||
publicationRevision: 4,
|
||||
priceMudPoints: 30,
|
||||
reviewReason: null,
|
||||
// 真实后台下发的是 `seconds.microsZ`(非 ISO 8601),见 shared-kernel `format_timestamp_micros`。
|
||||
createdAt: '1791008678.817257Z',
|
||||
@@ -92,6 +93,7 @@ const detailResponse: AdminGameDistributionVersionDetailResponse = {
|
||||
orientation: 'landscape',
|
||||
status: 'unpublished',
|
||||
publicationRevision: 7,
|
||||
priceMudPoints: 30,
|
||||
playCount: 0,
|
||||
createdAt: '2026-09-20T08:00:00Z',
|
||||
},
|
||||
@@ -228,7 +230,8 @@ test('提交时间列把后端的 seconds.microsZ 渲染成可读本地时间',
|
||||
|
||||
const row = screen.getByText(gameTitle).closest('tr');
|
||||
expect(row).not.toBeNull();
|
||||
const submittedCell = within(row as HTMLElement).getAllByRole('cell')[3];
|
||||
// 列序:游戏 / 版本 / 发行包 / 价格 / 提交时间 / 审核。
|
||||
const submittedCell = within(row as HTMLElement).getAllByRole('cell')[4];
|
||||
// 解析不出来时会回落到 `-`,这正是本次修复前的线上表现。
|
||||
expect(submittedCell?.textContent).not.toBe('-');
|
||||
expect(submittedCell?.textContent).toMatch(
|
||||
@@ -236,6 +239,48 @@ test('提交时间列把后端的 seconds.microsZ 渲染成可读本地时间',
|
||||
);
|
||||
});
|
||||
|
||||
test('价格列按买断制口径展示,免费与缺失价格都不显示 NaN', async () => {
|
||||
const freeEntry: AdminGameDistributionReviewEntry = {
|
||||
...entry,
|
||||
versionId: 'version-2',
|
||||
gameId: 'game_2',
|
||||
versionNumber: 1,
|
||||
priceMudPoints: 0,
|
||||
};
|
||||
// 旧响应可能完全没有该字段;列表必须回落到“免费”而不是 NaN。
|
||||
const legacyEntry = {
|
||||
...entry,
|
||||
versionId: 'version-3',
|
||||
gameId: 'game_3',
|
||||
versionNumber: 3,
|
||||
priceMudPoints: undefined,
|
||||
} as unknown as AdminGameDistributionReviewEntry;
|
||||
vi.mocked(listAdminGameDistributionReviews).mockResolvedValue({
|
||||
entries: [entry, freeEntry, legacyEntry],
|
||||
nextCursor: null,
|
||||
});
|
||||
|
||||
render(
|
||||
<AdminGameDistributionReviewPage
|
||||
token="admin-token"
|
||||
onUnauthorized={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
await screen.findByText(gameTitle);
|
||||
|
||||
const cellAt = (text: string) => {
|
||||
const row = screen.getByText(text).closest('tr');
|
||||
expect(row).not.toBeNull();
|
||||
// 列序:游戏 / 版本 / 发行包 / 价格 / 提交时间 / 审核。
|
||||
return within(row as HTMLElement).getAllByRole('cell')[3]?.textContent;
|
||||
};
|
||||
|
||||
expect(cellAt(gameTitle)).toBe('30 泥点');
|
||||
expect(cellAt('game_2')).toBe('免费');
|
||||
expect(cellAt('game_3')).toBe('免费');
|
||||
expect(screen.queryByText(/NaN/u)).toBeNull();
|
||||
});
|
||||
|
||||
test('取消理由输入时不做审核操作', async () => {
|
||||
render(
|
||||
<AdminGameDistributionReviewPage
|
||||
@@ -298,6 +343,9 @@ test('详情展示发布者和冻结资料,并试玩当前待审版本', async
|
||||
fireEvent.click(screen.getByRole('button', { name: '详情' }));
|
||||
expect((await screen.findAllByText(/测试作者/u)).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText('测试详细介绍')).toBeTruthy();
|
||||
// 详情资料区展示买断制价格(0 或缺字段按“免费”)。
|
||||
expect(screen.getByText('价格')).toBeTruthy();
|
||||
expect(screen.getByText('30 泥点')).toBeTruthy();
|
||||
fireEvent.click(screen.getByRole('button', { name: '试玩当前待审版本' }));
|
||||
const frame = await screen.findByTitle('测试游戏 待审版本试玩');
|
||||
expect(frame.getAttribute('src')).toBe(
|
||||
|
||||
@@ -111,6 +111,11 @@ function formatBytes(value: number) {
|
||||
return `${value} B`;
|
||||
}
|
||||
|
||||
/** 买断制价格口径:0 或缺失(旧响应 / undefined)都按“免费”展示,避免出现 NaN。 */
|
||||
function formatPriceMudPoints(value: number | null | undefined) {
|
||||
return typeof value === 'number' && value > 0 ? `${value} 泥点` : '免费';
|
||||
}
|
||||
|
||||
function createReviewIdempotencyKey(versionId: string) {
|
||||
const random =
|
||||
typeof crypto !== 'undefined' && 'randomUUID' in crypto
|
||||
@@ -437,6 +442,7 @@ export function AdminGameDistributionReviewPage({
|
||||
{ key: 'gameId', label: '游戏' },
|
||||
{ key: 'versionNumber', label: '版本' },
|
||||
{ key: 'packageBytes', label: '发行包' },
|
||||
{ key: 'priceMudPoints', label: '价格' },
|
||||
{ key: 'createdAt', label: '提交时间' },
|
||||
{ key: 'actions', label: '审核' },
|
||||
]}
|
||||
@@ -482,6 +488,7 @@ export function AdminGameDistributionReviewPage({
|
||||
<code>{entry.packageSha256.slice(0, 12)}</code>
|
||||
</div>
|
||||
</td>
|
||||
<td>{formatPriceMudPoints(entry.priceMudPoints)}</td>
|
||||
<td>{formatAdminDateTime(entry.createdAt)}</td>
|
||||
<td className="admin-game-review-cell--actions">
|
||||
<AdminActionRow className="admin-review-actions">
|
||||
@@ -629,6 +636,10 @@ function AdminGameDistributionReviewDetailView({
|
||||
versionLabel={`v${detail.version.versionNumber}`}
|
||||
infoCards={[
|
||||
{ label: '状态', value: detail.version.status },
|
||||
{
|
||||
label: '价格',
|
||||
value: formatPriceMudPoints(detail.game.priceMudPoints),
|
||||
},
|
||||
{
|
||||
label: '提交时间',
|
||||
value: formatAdminDateTime(detail.version.createdAt),
|
||||
|
||||
@@ -27,14 +27,21 @@ table.admin-game-review-table td:nth-child(3) {
|
||||
width: 124px;
|
||||
}
|
||||
|
||||
/* 价格列:只展示「免费」或「N 泥点」,窄列即可。 */
|
||||
table.admin-game-review-table th:nth-child(4),
|
||||
table.admin-game-review-table td:nth-child(4) {
|
||||
width: 172px;
|
||||
width: 96px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.admin-game-review-table th:nth-child(5),
|
||||
table.admin-game-review-table td:nth-child(5) {
|
||||
width: 172px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.admin-game-review-table th:nth-child(6),
|
||||
table.admin-game-review-table td:nth-child(6) {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
@@ -100,7 +107,9 @@ table.admin-game-review-table td .admin-muted-text {
|
||||
table.admin-game-review-table th:nth-child(4),
|
||||
table.admin-game-review-table td:nth-child(4),
|
||||
table.admin-game-review-table th:nth-child(5),
|
||||
table.admin-game-review-table td:nth-child(5) {
|
||||
table.admin-game-review-table td:nth-child(5),
|
||||
table.admin-game-review-table th:nth-child(6),
|
||||
table.admin-game-review-table td:nth-child(6) {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user