作品管理与Phaser4客户端发布闭环
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m21s
Project CI / Backend tests (pull_request) Failing after 16s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m18s
Project CI / Frontend tests (pull_request) Successful in 2m8s
Project CI / Repository checks (pull_request) Failing after 16s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m56s
Project CI / Native shell tests (pull_request) Successful in 5m47s
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

补齐 Phaser4 客户端发布前校验、阶段进度与原生幂等账本

增加 Web 作者私有作品管理、资料编辑、版本历史与软删除

增加后台作品筛选、游标分页与删除治理

同步 SpacetimeDB schema、bindings、DTO、文档与定向测试
This commit is contained in:
2026-10-01 16:30:40 +08:00
parent 1f055e9902
commit a2b70d92b8
80 changed files with 5836 additions and 676 deletions
+23 -3
View File
@@ -33,6 +33,7 @@ import type {
AdminExternalApiKeyListResponse,
AdminFeatureGateConfigResponse,
AdminGameDistributionGameListResponse,
AdminGameDistributionGameStatus,
AdminGameDistributionRestoreRequest,
AdminGameDistributionRestoreResponse,
AdminGameDistributionReviewListResponse,
@@ -1243,17 +1244,36 @@ export function listAdminGameDistributionReviews(token: string, limit = 48) {
);
}
/**
* 后台作品管理列表。
*
* 关键词、作者与状态过滤以及游标分页都由服务端执行:前端只透传查询参数,
* 不本地过滤,否则分页边界会与 `nextCursor` 的语义打架。
*/
export function listAdminGameDistributionGames(
token: string,
options: { limit?: number } = {},
options: {
limit?: number;
keyword?: string;
owner?: string;
status?: AdminGameDistributionGameStatus | '';
cursor?: string | null;
} = {},
signal?: AbortSignal,
) {
const requestedLimit = options.limit ?? 50;
const normalizedLimit = Number.isFinite(requestedLimit)
? Math.min(Math.max(Math.trunc(requestedLimit), 1), 50)
? Math.min(Math.max(Math.trunc(requestedLimit), 1), 200)
: 50;
const params = new URLSearchParams({ limit: String(normalizedLimit) });
const keyword = options.keyword?.trim();
if (keyword) params.set('keyword', keyword);
const owner = options.owner?.trim();
if (owner) params.set('owner', owner);
if (options.status) params.set('status', options.status);
if (options.cursor) params.set('cursor', options.cursor);
return request<AdminGameDistributionGameListResponse>(
`/admin/api/game-distribution/games?limit=${normalizedLimit}`,
`/admin/api/game-distribution/games?${params.toString()}`,
{ token, signal },
);
}