import AddOutlined from "@mui/icons-material/AddOutlined"; import DeleteOutlineOutlined from "@mui/icons-material/DeleteOutlineOutlined"; import RefreshOutlined from "@mui/icons-material/RefreshOutlined"; import Avatar from "@mui/material/Avatar"; import MenuItem from "@mui/material/MenuItem"; import Switch from "@mui/material/Switch"; import TextField from "@mui/material/TextField"; import { useCallback, useEffect, useMemo, useState } from "react"; import { PERMISSIONS } from "@/app/permissions"; import { useAuth } from "@/app/auth/AuthProvider.jsx"; import { deleteDiceRobot, generateDiceRobots, listDiceRobots, setDiceRobotStatus } from "@/features/games/api"; import { useCountryOptions } from "@/features/host-org/hooks/useCountryOptions.js"; import styles from "@/features/games/games.module.css"; import { AdminActionIconButton, AdminFilterResetButton, AdminFilterSelect, AdminListBody, AdminListPage, AdminListToolbar, AdminRowActions, } from "@/shared/ui/AdminListLayout.jsx"; import { AdminFormDialog, AdminFormFieldGrid } from "@/shared/ui/AdminFormDialog.jsx"; import { useConfirm } from "@/shared/ui/ConfirmProvider.jsx"; import { DataTable } from "@/shared/ui/DataTable.jsx"; import { PageSkeleton } from "@/shared/ui/PageSkeleton.jsx"; import { useToast } from "@/shared/ui/ToastProvider.jsx"; import { formatMillis } from "@/shared/utils/time.js"; const defaultGenerateForm = { count: 20, country: "SA", nicknameLanguage: "arabic", }; const maxGenerateRobotCount = 1000; export function GameRobotPage() { const { can } = useAuth(); const confirm = useConfirm(); const { showToast } = useToast(); const canCreate = can(PERMISSIONS.gameCreate); const canUpdate = can(PERMISSIONS.gameUpdate); const canDelete = can(PERMISSIONS.gameDelete) || canUpdate; const { countryOptions, loadingCountries } = useCountryOptions(); const [items, setItems] = useState([]); const [status, setStatus] = useState(""); const [nextCursor, setNextCursor] = useState(""); const [loading, setLoading] = useState(true); const [loadingAction, setLoadingAction] = useState(""); const [dialogOpen, setDialogOpen] = useState(false); const [generateForm, setGenerateForm] = useState(defaultGenerateForm); const load = useCallback( async (cursor = "", append = false) => { setLoading(!append); try { const result = await listDiceRobots({ status, cursor, pageSize: 50 }); setItems((current) => (append ? [...current, ...(result.items || [])] : result.items || [])); setNextCursor(result.nextCursor || ""); } catch (err) { showToast(err.message || "加载全站机器人失败", "error"); } finally { setLoading(false); } }, [showToast, status], ); useEffect(() => { load("", false); }, [load]); useEffect(() => { setGenerateForm((current) => { if (countryOptions.length === 0) { return current; } const currentCountryEnabled = countryOptions.some((option) => option.value === current.country); if (current.country && currentCountryEnabled) { return current; } // 国家主数据由后端控制启用状态;默认优先沿用历史 SA,否则取当前启用列表第一项,避免提交空国家被 user-service 拒绝。 const defaultCountry = countryOptions.find((option) => option.value === "SA")?.value || countryOptions[0].value; return { ...current, country: defaultCountry }; }); }, [countryOptions]); const changeStatus = useCallback( async (robot, checked) => { setLoadingAction(`status-${robot.userId}`); try { await setDiceRobotStatus(robot.userId, checked ? "active" : "disabled"); await load("", false); showToast("机器人状态已更新", "success"); } catch (err) { showToast(err.message || "更新机器人状态失败", "error"); } finally { setLoadingAction(""); } }, [load, showToast], ); const removeRobot = useCallback( async (robot) => { const ok = await confirm({ confirmText: "删除", message: `${robot.nickname || robot.userId} 会从全站机器人列表移除,历史用户资料和对局记录保留。`, title: "删除全站机器人", tone: "danger", }); if (!ok) { return; } setLoadingAction(`delete-${robot.userId}`); try { await deleteDiceRobot(robot.userId); await load("", false); showToast("全站机器人已删除", "success"); } catch (err) { showToast(err.message || "删除全站机器人失败", "error"); } finally { setLoadingAction(""); } }, [confirm, load, showToast], ); const columns = useMemo( () => [ { key: "user", label: "机器人用户", width: "minmax(220px, 1fr)", render: (robot) => (