2026-05-14 09:57:41 +08:00

304 lines
9.1 KiB
JavaScript

import { useCallback, useEffect, useMemo, useState } from "react";
import {
listGameCatalog,
listGamePlatforms,
setGameStatus,
upsertGameCatalog,
upsertGamePlatform,
} from "@/features/games/api";
import { useGameAbilities } from "@/features/games/permissions.js";
import { useAdminQuery } from "@/shared/hooks/useAdminQuery.js";
import { useToast } from "@/shared/ui/ToastProvider.jsx";
const defaultGameForm = {
gameId: "",
platformCode: "",
providerGameId: "",
gameName: "",
category: "casual",
iconUrl: "",
coverUrl: "",
launchMode: "h5_popup",
orientation: "portrait",
minCoin: 0,
status: "active",
sortOrder: 0,
tagsText: "",
};
const defaultPlatformForm = {
platformCode: "",
platformName: "",
status: "active",
apiBaseUrl: "",
sortOrder: 0,
};
const emptyCatalog = { items: [], pageSize: 50 };
const emptyPlatforms = { items: [] };
const defaultPageSize = 50;
export function useGamesPage() {
const abilities = useGameAbilities();
const { showToast } = useToast();
const [platformCode, setPlatformCode] = useState("");
const [status, setStatus] = useState("");
const [page, setPage] = useState(1);
const [pageCursors, setPageCursors] = useState({ 1: "" });
const [pageSize, setPageSize] = useState(defaultPageSize);
const [activeAction, setActiveAction] = useState("");
const [editingGameId, setEditingGameId] = useState("");
const [editingPlatformCode, setEditingPlatformCode] = useState("");
const [gameForm, setGameForm] = useState(defaultGameForm);
const [platformForm, setPlatformForm] = useState(defaultPlatformForm);
const [loadingAction, setLoadingAction] = useState("");
const platformsQueryFn = useCallback(() => listGamePlatforms(), []);
const {
data: platformData = emptyPlatforms,
error: platformError,
loading: platformsLoading,
reload: reloadPlatforms,
} = useAdminQuery(platformsQueryFn, {
errorMessage: "加载游戏平台失败",
initialData: emptyPlatforms,
queryKey: ["games", "platforms"],
});
const catalogQueryFn = useCallback(
() => listGameCatalog({ cursor: pageCursors[page] || "", platformCode, status, pageSize }),
[page, pageCursors, pageSize, platformCode, status],
);
const {
data = emptyCatalog,
error,
loading,
reload,
} = useAdminQuery(catalogQueryFn, {
errorMessage: "加载游戏列表失败",
initialData: emptyCatalog,
keepPreviousData: true,
queryKey: ["games", "catalog", platformCode, status, pageSize, page, pageCursors[page] || ""],
});
const platformOptions = useMemo(
() => (platformData.items || []).map((platform) => [platform.platformCode, platform.platformName]),
[platformData.items],
);
useEffect(() => {
if (!gameForm.platformCode && platformOptions.length > 0 && activeAction === "create-game") {
setGameForm((current) => ({ ...current, platformCode: platformOptions[0][0] }));
}
}, [activeAction, gameForm.platformCode, platformOptions]);
const resetCatalogPage = () => {
setPage(1);
setPageCursors({ 1: "" });
};
const changePlatformCode = (value) => {
setPlatformCode(value);
resetCatalogPage();
};
const changeStatus = (value) => {
setStatus(value);
resetCatalogPage();
};
const changePageSize = (value) => {
setPageSize(value);
resetCatalogPage();
};
const changePage = (nextPage) => {
if (nextPage < 1 || nextPage === page) {
return;
}
if (nextPage === page + 1) {
if (!data.nextCursor) {
return;
}
setPageCursors((current) => ({ ...current, [nextPage]: data.nextCursor }));
}
setPage(nextPage);
};
const resetFilters = () => {
setPlatformCode("");
setStatus("");
setPageSize(defaultPageSize);
resetCatalogPage();
};
const openCreateGame = () => {
setEditingGameId("");
setGameForm({ ...defaultGameForm, platformCode: platformOptions[0]?.[0] || "" });
setActiveAction("create-game");
};
const openEditGame = (game) => {
setEditingGameId(game.gameId);
setGameForm(gameToForm(game));
setActiveAction("edit-game");
};
const openCreatePlatform = () => {
setEditingPlatformCode("");
setPlatformForm(defaultPlatformForm);
setActiveAction("create-platform");
};
const openEditPlatform = (platform) => {
setEditingPlatformCode(platform.platformCode);
setPlatformForm(platformToForm(platform));
setActiveAction("edit-platform");
};
const closeAction = () => {
setActiveAction("");
setEditingGameId("");
setEditingPlatformCode("");
};
const submitGame = async (event) => {
event.preventDefault();
const payload = gamePayload(gameForm);
setLoadingAction(activeAction);
try {
await upsertGameCatalog(payload, editingGameId);
await reload();
showToast(editingGameId ? "游戏已更新" : "游戏已创建", "success");
closeAction();
} catch (err) {
showToast(err.message || "保存游戏失败", "error");
} finally {
setLoadingAction("");
}
};
const submitPlatform = async (event) => {
event.preventDefault();
const payload = platformPayload(platformForm);
setLoadingAction(activeAction);
try {
await upsertGamePlatform(payload, editingPlatformCode);
await reloadPlatforms();
await reload();
showToast(editingPlatformCode ? "平台已更新" : "平台已创建", "success");
closeAction();
} catch (err) {
showToast(err.message || "保存平台失败", "error");
} finally {
setLoadingAction("");
}
};
const changeGameStatus = async (game, checked) => {
const nextStatus = checked ? "active" : "maintenance";
setLoadingAction(`status-${game.gameId}`);
try {
await setGameStatus(game.gameId, nextStatus);
await reload();
showToast("游戏状态已更新", "success");
} catch (err) {
showToast(err.message || "状态更新失败", "error");
} finally {
setLoadingAction("");
}
};
return {
abilities,
activeAction,
changeGameStatus,
closeAction,
data,
error: error || platformError,
gameForm,
loading: loading || platformsLoading,
loadingAction,
page,
openCreateGame,
openCreatePlatform,
openEditGame,
openEditPlatform,
pageSize,
platformCode,
platformData,
platformForm,
platformOptions,
reload,
resetFilters,
changePage,
changePageSize,
setGameForm,
setPlatformCode: changePlatformCode,
setPlatformForm,
setStatus: changeStatus,
status,
submitGame,
submitPlatform,
};
}
function gameToForm(game) {
return {
gameId: game.gameId || "",
platformCode: game.platformCode || "",
providerGameId: game.providerGameId || "",
gameName: game.gameName || "",
category: game.category || "casual",
iconUrl: game.iconUrl || "",
coverUrl: game.coverUrl || "",
launchMode: game.launchMode || "h5_popup",
orientation: game.orientation || "portrait",
minCoin: Number(game.minCoin || 0),
status: game.status || "active",
sortOrder: Number(game.sortOrder || 0),
tagsText: (game.tags || []).join(", "),
};
}
function platformToForm(platform) {
return {
platformCode: platform.platformCode || "",
platformName: platform.platformName || "",
status: platform.status || "active",
apiBaseUrl: platform.apiBaseUrl || "",
sortOrder: Number(platform.sortOrder || 0),
};
}
function gamePayload(form) {
return {
gameId: form.gameId.trim(),
platformCode: form.platformCode.trim(),
providerGameId: form.providerGameId.trim(),
gameName: form.gameName.trim(),
category: form.category.trim(),
iconUrl: form.iconUrl.trim(),
coverUrl: form.coverUrl.trim(),
launchMode: form.launchMode.trim() || "h5_popup",
orientation: form.orientation.trim() || "portrait",
minCoin: Number(form.minCoin || 0),
status: form.status.trim() || "active",
sortOrder: Number(form.sortOrder || 0),
tags: form.tagsText
.split(",")
.map((tag) => tag.trim())
.filter(Boolean),
};
}
function platformPayload(form) {
return {
platformCode: form.platformCode.trim(),
platformName: form.platformName.trim(),
status: form.status.trim() || "active",
apiBaseUrl: form.apiBaseUrl.trim(),
sortOrder: Number(form.sortOrder || 0),
};
}