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), }; }