2026-05-23 11:21:17 +08:00

207 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { apiRequest } from "@/shared/api/request";
import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
import type { QueryParams } from "@/shared/api/request";
export interface GamePlatformDto {
appCode?: string;
platformCode: string;
platformName: string;
status: string;
apiBaseUrl: string;
// 服务端按 adapterType 选择厂商协议demo/yomi_v4/leadercc_v1/zeeone_v1/baishun_v1。
adapterType: string;
// callbackSecret 由后台列表返回,用于配置页直接核对和轮换厂商 key。
callbackSecret?: string;
callbackSecretSet: boolean;
callbackIpWhitelist: string[];
// 厂商扩展配置保留 JSON 字符串,后台前端不绑定具体字段结构。
adapterConfigJson: string;
sortOrder: number;
createdAtMs?: number;
updatedAtMs?: number;
}
export interface GameCatalogDto {
appCode?: string;
gameId: string;
platformCode: string;
providerGameId: string;
gameName: string;
category: string;
iconUrl: string;
coverUrl: string;
launchMode: string;
orientation: string;
minCoin: number;
status: string;
sortOrder: number;
tags: string[];
createdAtMs?: number;
updatedAtMs?: number;
}
export interface GameCatalogPage {
items: GameCatalogDto[];
nextCursor?: string;
pageSize?: number;
serverTimeMs?: number;
}
export interface GamePlatformPage {
items: GamePlatformDto[];
serverTimeMs?: number;
}
export interface GameSyncPayload {
dryRun?: boolean;
status?: string;
category?: string;
launchMode?: string;
minCoin?: number;
tags?: string[];
gameListType?: number;
providerGameIds?: string[];
}
export interface GameSyncResult {
platformCode: string;
synced: number;
dryRun: boolean;
items: GameCatalogDto[];
}
export type GamePlatformPayload = Omit<
GamePlatformDto,
"appCode" | "createdAtMs" | "updatedAtMs" | "callbackSecretSet"
>;
export type GameCatalogPayload = Omit<GameCatalogDto, "appCode" | "createdAtMs" | "updatedAtMs">;
export interface GameCatalogQuery {
platformCode?: string;
status?: string;
pageSize?: number;
cursor?: string;
}
export function listGamePlatforms(status = ""): Promise<GamePlatformPage> {
const endpoint = API_ENDPOINTS.listPlatforms;
return apiRequest<GamePlatformPage>(apiEndpointPath(API_OPERATIONS.listPlatforms), {
method: endpoint.method,
query: { status },
}).then((page) => ({
...page,
items: (page.items || []).map(normalizePlatform),
}));
}
export function upsertGamePlatform(payload: GamePlatformPayload, platformCode = ""): Promise<GamePlatformDto> {
const operation = platformCode ? API_OPERATIONS.updatePlatform : API_OPERATIONS.createPlatform;
const endpoint = API_ENDPOINTS[operation];
return apiRequest<GamePlatformDto, GamePlatformPayload>(
apiEndpointPath(operation, platformCode ? { platform_code: platformCode } : {}),
{
body: payload,
method: endpoint.method,
},
).then(normalizePlatform);
}
export function listGameCatalog(query: GameCatalogQuery = {}): Promise<GameCatalogPage> {
const endpoint = API_ENDPOINTS.listCatalog;
return apiRequest<GameCatalogPage>(apiEndpointPath(API_OPERATIONS.listCatalog), {
method: endpoint.method,
query: query as QueryParams,
}).then((page) => ({
...page,
items: (page.items || []).map(normalizeCatalog),
}));
}
export function upsertGameCatalog(payload: GameCatalogPayload, gameId = ""): Promise<GameCatalogDto> {
const operation = gameId ? API_OPERATIONS.updateCatalog : API_OPERATIONS.createCatalog;
const endpoint = API_ENDPOINTS[operation];
return apiRequest<GameCatalogDto, GameCatalogPayload>(
apiEndpointPath(operation, gameId ? { game_id: gameId } : {}),
{
body: payload,
method: endpoint.method,
},
).then(normalizeCatalog);
}
export function setGameStatus(gameId: string, status: string): Promise<GameCatalogDto> {
const endpoint = API_ENDPOINTS.setGameStatus;
return apiRequest<GameCatalogDto, { status: string }>(
apiEndpointPath(API_OPERATIONS.setGameStatus, { game_id: gameId }),
{
body: { status },
method: endpoint.method,
},
).then(normalizeCatalog);
}
export function syncGamePlatformCatalog(platformCode: string, payload: GameSyncPayload = {}): Promise<GameSyncResult> {
return apiRequest<GameSyncResult, GameSyncPayload>(
`/v1/admin/game/platforms/${encodeURIComponent(platformCode)}/sync-games`,
{
body: payload,
method: "POST",
},
).then((result) => ({
...result,
items: (result.items || []).map(normalizeCatalog),
synced: numberValue(result.synced),
dryRun: Boolean(result.dryRun),
}));
}
function normalizePlatform(platform: Partial<GamePlatformDto>): GamePlatformDto {
return {
appCode: stringValue(platform.appCode),
platformCode: stringValue(platform.platformCode),
platformName: stringValue(platform.platformName),
status: stringValue(platform.status || "active"),
apiBaseUrl: stringValue(platform.apiBaseUrl),
adapterType: stringValue(platform.adapterType || "demo"),
callbackSecret: stringValue(platform.callbackSecret),
callbackSecretSet: Boolean(platform.callbackSecretSet),
callbackIpWhitelist: Array.isArray(platform.callbackIpWhitelist)
? platform.callbackIpWhitelist.map(String).filter(Boolean)
: [],
adapterConfigJson: stringValue(platform.adapterConfigJson || "{}"),
sortOrder: numberValue(platform.sortOrder),
createdAtMs: numberValue(platform.createdAtMs),
updatedAtMs: numberValue(platform.updatedAtMs),
};
}
function normalizeCatalog(game: Partial<GameCatalogDto>): GameCatalogDto {
return {
appCode: stringValue(game.appCode),
gameId: stringValue(game.gameId),
platformCode: stringValue(game.platformCode),
providerGameId: stringValue(game.providerGameId),
gameName: stringValue(game.gameName),
category: stringValue(game.category),
iconUrl: stringValue(game.iconUrl),
coverUrl: stringValue(game.coverUrl),
launchMode: stringValue(game.launchMode || "h5_popup"),
orientation: stringValue(game.orientation || "portrait"),
minCoin: numberValue(game.minCoin),
status: stringValue(game.status || "active"),
sortOrder: numberValue(game.sortOrder),
tags: Array.isArray(game.tags) ? game.tags.map(String).filter(Boolean) : [],
createdAtMs: numberValue(game.createdAtMs),
updatedAtMs: numberValue(game.updatedAtMs),
};
}
function stringValue(value: unknown) {
return typeof value === "string" ? value : value === undefined || value === null ? "" : String(value);
}
function numberValue(value: unknown) {
const number = Number(value || 0);
return Number.isFinite(number) ? number : 0;
}