"use client"; import { useQuery } from "@tanstack/react-query"; import { Badge } from "@workspace/ui/components/badge"; import { Button } from "@workspace/ui/components/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@workspace/ui/components/card"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@workspace/ui/components/dialog"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@workspace/ui/components/table"; import { ProTable, type ProTableActions, } from "@workspace/ui/composed/pro-table/pro-table"; import { getGroupHistory, getGroupHistoryDetail, getNodeGroupList, } from "@workspace/ui/services/admin/group"; import { Loader2 } from "lucide-react"; import { useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { formatDate } from "@/utils/common"; export default function GroupHistory() { const { t } = useTranslation("group"); const ref = useRef(null); const [detailOpen, setDetailOpen] = useState(false); const [detailLoading, setDetailLoading] = useState(false); const [selectedHistory, setSelectedHistory] = useState(null); const [details, setDetails] = useState([]); const [nodeGroupMap, setNodeGroupMap] = useState>( new Map() ); // User list dialog state const [userListOpen, setUserListOpen] = useState(false); const [selectedNodeGroupName, setSelectedNodeGroupName] = useState(""); const [userList, setUserList] = useState([]); const [userListTotal, setUserListTotal] = useState(0); // Fetch all node groups const { data: nodeGroups } = useQuery({ queryKey: ["getNodeGroupListForDetail"], queryFn: async () => { const { data } = await getNodeGroupList({ page: 1, size: 100, }); return data.data?.list || []; }, }); // Build ID to name maps when groups are loaded if (nodeGroups) { const newNodeGroupMap = new Map(); nodeGroups.forEach((ng: API.NodeGroup) => { newNodeGroupMap.set(ng.id, ng.name); }); if (newNodeGroupMap.size !== nodeGroupMap.size) { setNodeGroupMap(newNodeGroupMap); } } const getModeLabel = (mode: string) => { switch (mode) { case "average": return t("averageMode", "Average"); case "subscribe": return t("subscribeMode", "Subscribe"); case "traffic": return t("trafficMode", "Traffic"); default: return mode; } }; const getTriggerTypeLabel = (type: string) => { switch (type) { case "manual": return t("manualTrigger", "Manual"); case "auto": return t("autoTrigger", "Auto"); case "schedule": return t("scheduleTrigger", "Schedule"); default: return type; } }; const handleViewDetail = async (record: API.GroupHistory) => { setSelectedHistory(record); setDetailOpen(true); setDetailLoading(true); try { const { data } = await getGroupHistoryDetail({ id: record.id, }); console.log("Group history detail response:", data); // 从返回的数据中获取详情列表 // data.data.config_snapshot.group_details 包含分组详情 if (data.data?.config_snapshot?.group_details) { setDetails(data.data.config_snapshot.group_details); } else { console.warn("No group_details found in response:", data); setDetails([]); } } catch (error) { console.error("Failed to fetch history details:", error); setDetails([]); } finally { setDetailLoading(false); } }; const handleShowUserList = async ( nodeGroupId: number, nodeGroupName: string ) => { setSelectedNodeGroupName(nodeGroupName); setUserListOpen(true); // 从历史详情记录中获取用户数据 const detail = details.find((d: any) => { const detailNodeGroupId = d.NodeGroupId || d.node_group_id; return detailNodeGroupId === nodeGroupId; }); if (detail) { const userDataJSON = detail.UserData || detail.user_data; if (userDataJSON) { try { const userData = JSON.parse(userDataJSON); setUserList(userData); setUserListTotal(userData.length); } catch (error) { console.error("Failed to parse user data:", error); setUserList([]); setUserListTotal(0); } } else { setUserList([]); setUserListTotal(0); } } else { setUserList([]); setUserListTotal(0); } }; return (
{t("groupHistory", "Group Calculation History")} {t( "groupHistoryDescription", "View group recalculation history and results" )} action={ref} actions={{ render: (row: any) => [ , ], }} columns={[ { id: "id", accessorKey: "id", header: t("id", "ID"), cell: ({ row }: { row: any }) => ( {t("idPrefix", "#")} {row.getValue("id")} ), }, { id: "group_mode", accessorKey: "group_mode", header: t("groupMode", "Group Mode"), cell: ({ row }: { row: any }) => ( {getModeLabel(row.getValue("group_mode"))} ), }, { id: "trigger_type", accessorKey: "trigger_type", header: t("triggerType", "Trigger Type"), cell: ({ row }: { row: any }) => ( {getTriggerTypeLabel(row.getValue("trigger_type"))} ), }, { id: "total_users", accessorKey: "total_users", header: t("totalUsers", "Total Users"), cell: ({ row }: { row: any }) => ( {row.getValue("total_users")} ), }, { id: "result", accessorKey: "error_log", header: t("result", "Result"), cell: ({ row }: { row: any }) => { const record = row.original; return (
{t("successCount", "Success")}: {record.success_count}{" "} {t("separator", "/")} {t("failedCount", "Failed")}:{" "} {record.failed_count}
{record.error_log && ( {t("failed", "Failed")} )} {!record.error_log && record.failed_count === 0 && ( {t("completed", "Completed")} )}
); }, }, { id: "created_at", accessorKey: "created_at", header: t("createdAt", "Created At"), cell: ({ row }: { row: any }) => formatDate(row.getValue("created_at")), }, ]} header={{ title: t("groupHistory", "Group Calculation History"), }} request={async (params) => { const { data } = await getGroupHistory({ page: params.page || 1, size: params.size || 10, }); return { list: data.data?.list || [], total: data.data?.total || 0, }; }} />
{/* Detail Dialog */} {t("groupHistoryDetail", "Group Calculation Detail")} {t("historyId", "History ID")}: {selectedHistory?.id}
{selectedHistory && ( <>
{t("groupMode", "Group Mode")}
{getModeLabel(selectedHistory.group_mode)}
{t("triggerType", "Trigger Type")}
{getTriggerTypeLabel(selectedHistory.trigger_type)}
{t("totalUsers", "Total Users")}
{selectedHistory.total_users}
{t("result", "Result")}
{t("successCount", "Success")}:{" "} {selectedHistory.success_count} {t("separator", "/")}{" "} {t("failedCount", "Failed")}:{" "} {selectedHistory.failed_count}
{selectedHistory.start_time && (
{t("startTime", "Start Time")}
{formatDate(selectedHistory.start_time)}
)} {selectedHistory.end_time && (
{t("endTime", "End Time")}
{formatDate(selectedHistory.end_time)}
)}
{selectedHistory.error_log && (
{t("errorMessage", "Error Message")}
{selectedHistory.error_log}
)} )}
{t("groupDetails", "Group Details")}
{detailLoading ? (
{t("loading", "Loading...")}
) : details.length > 0 ? ( <> {/* 统计信息 */}
{details.reduce( (sum: number, d: any) => sum + (d.UserCount || d.user_count || 0), 0 )}
{t("totalUsers", "Total Users")}
{details.reduce( (sum: number, d: any) => sum + (d.NodeCount || d.node_count || 0), 0 )}
{t("totalNodes", "Total Nodes")}
{details.length}
{t("totalNodeGroups", "Total Node Groups")}
{/* 详情表格 */}
{details.map((detail: any, index: number) => { const nodeGroupId = detail.NodeGroupId || detail.node_group_id; const nodeGroupName = nodeGroupMap.get(nodeGroupId) || `${t("idPrefix", "#")}${nodeGroupId}`; return ( ); })}
{t("nodeGroup", "Node Group")} {t("userCount", "User Count")} {t("nodeCount", "Node Count")}
{nodeGroupName}
{t("id", "ID")}: {nodeGroupId}
{detail.NodeCount || detail.node_count || 0}
) : (
{t("noDetails", "No details available")}
)}
{/* User List Dialog */} {selectedNodeGroupName} - {t("userList", "User List")} {t("totalUsers", "Total Users")}: {userListTotal}
{userList.length > 0 ? ( {t("id", "ID")} {t("email", "Email")} {userList.map((user) => ( {user.id} {user.email || "-"} ))}
) : (
{t("noUsers", "No users found")}
)}
); }