import { useCallback, useEffect, useMemo, useState } from "react"; import { drawStatusOptions } from "@/features/lucky-gift/constants.js"; import { AdminFilterResetButton, AdminFilterSelect, AdminListToolbar, AdminSearchBox } from "@/shared/ui/AdminListLayout.jsx"; import { DataTable } from "@/shared/ui/DataTable.jsx"; import { TimeText } from "@/shared/ui/TimeText.jsx"; import { fetchLuckyGiftDraws } from "../api.js"; import { formatMultiplierFromPPM, formatNumber } from "../format.js"; import { OpsStatusBadge } from "./OpsStatusBadge.jsx"; const PAGE_SIZE = 20; const initialFilters = { poolId: "", status: "", userId: "" }; export function DrawsView({ apps, defaultAppCode, poolIDsByApp }) { // 抽奖流水量大且服务端分页,必须选定应用后按需拉取,不能像配置那样一次拉全。 const [appCode, setAppCode] = useState(defaultAppCode); const [filters, setFilters] = useState(initialFilters); const [page, setPage] = useState(1); const [state, setState] = useState({ error: "", items: [], loading: false, total: 0 }); useEffect(() => { // 首屏 dashboard 加载完成前 defaultAppCode 为空,就绪后自动选中第一个应用。 setAppCode((current) => current || defaultAppCode); }, [defaultAppCode]); useEffect(() => { if (!appCode) { return undefined; } let cancelled = false; setState((current) => ({ ...current, error: "", loading: true })); fetchLuckyGiftDraws({ appCode, page, pageSize: PAGE_SIZE, poolId: filters.poolId, status: filters.status, userId: filters.userId }) .then((result) => { if (cancelled) { return; } setState((current) => ({ error: "", // 滚动加载:翻页时向已加载列表追加;筛选变化会把 page 重置为 1,从头替换。 items: page > 1 ? [...current.items, ...result.items] : result.items, loading: false, total: result.total })); }) .catch((error) => { if (cancelled) { return; } setState((current) => ({ ...current, error: error.message || "获取抽奖记录失败", loading: false })); }); return () => { cancelled = true; }; }, [appCode, filters, page]); const changeAppCode = useCallback((nextAppCode) => { setAppCode(nextAppCode); // 奖池归属于应用,切换应用后旧奖池筛选一定失效,一并重置。 setFilters(initialFilters); setPage(1); }, []); const changeFilter = useCallback((key, value) => { setFilters((current) => ({ ...current, [key]: value })); setPage(1); }, []); const resetFilters = useCallback(() => { setFilters(initialFilters); setPage(1); }, []); const appOptions = useMemo(() => apps.map((item) => [item.app_code ?? item.appCode, item.app_code ?? item.appCode]), [apps]); const poolOptions = useMemo(() => (poolIDsByApp.get(appCode) || []).map((poolID) => [poolID, poolID]), [appCode, poolIDsByApp]); const hasActiveFilters = Boolean(filters.poolId || filters.status || filters.userId); return (