"use client"; import type { ComponentType } from "react"; import { ChevronRight, Network, Pencil, Plus, Trash2, Users } from "lucide-react"; import { useTranslation } from "react-i18next"; import { AdminSubnav, AdminSubnavButton } from "@/components/admin/admin-subnav"; import { AdminNoResourceState, AdminTableNoResourceRow } from "@/components/admin/admin-no-resource-state"; import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { AdminRowActionsMenu } from "@/components/admin/admin-row-actions-menu"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { AgentsPlayersPanel } from "@/modules/agents/agents-players-panel"; import { AgentProfileFields, type AgentProfileFieldsProps } from "@/modules/agents/agent-profile-fields"; import { formatCredit } from "@/modules/agents/agent-line-sidebar"; import { Button } from "@/components/ui/button"; import { percentValueToUi } from "@/lib/admin-rate-percent"; import { resolveRoleStatusTone } from "@/lib/admin-status-tone"; import { cn } from "@/lib/utils"; import type { AgentNodeProfileSummary, AgentNodeRow, AgentProfileRow } from "@/types/api/admin-agent"; function relativeShareRate(totalShareRate: number | undefined, parentShareRate: number | undefined): string | null { if ( totalShareRate == null || parentShareRate == null || parentShareRate <= 0 ) { return null; } return percentValueToUi((totalShareRate / parentShareRate) * 100); } export type AgentDetailTab = "overview" | "profile" | "downline" | "players"; export type AgentLineDetailPanelProps = { node: AgentNodeRow | null; profile: AgentProfileRow | null; profileLoading: boolean; childAgents: AgentNodeRow[]; childCountById: Map; siteCode: string; siteLabel: string | null; parentName: string | null; detailTab: AgentDetailTab; onDetailTabChange: (tab: AgentDetailTab) => void; canViewProfileTab: boolean; canEditProfileTab: boolean; profileReadOnly: boolean; canViewDownlineTab: boolean; canViewPlayersTab: boolean; playersTabHint?: string | null; canManageNode: boolean; canCreateChild: boolean; canCreateChildAgent: boolean; canCreatePlayerAction: boolean; canDeleteChild: (node: AgentNodeRow) => boolean; onEditChild: (node: AgentNodeRow) => void; onDeleteChild: (node: AgentNodeRow) => void; onAddChild: () => void; onAddPlayer: () => void; onEditCurrent: () => void; onSelectChild: (node: AgentNodeRow) => void; profileFields: AgentProfileFieldsProps | null; profileSaving: boolean; onSaveProfile: () => void; playerCreateRequestKey?: number; }; export function AgentLineDetailPanel({ node, profile, profileLoading, childAgents, childCountById, siteCode, siteLabel, parentName, detailTab, onDetailTabChange, canViewProfileTab, canEditProfileTab, profileReadOnly, canViewDownlineTab, canViewPlayersTab, playersTabHint, canManageNode, canCreateChild, canCreateChildAgent, canCreatePlayerAction, canDeleteChild, onEditChild, onDeleteChild, onAddChild, onAddPlayer, onEditCurrent, onSelectChild, profileFields, profileSaving, onSaveProfile, playerCreateRequestKey = 0, }: AgentLineDetailPanelProps): React.ReactElement { const { t } = useTranslation(["agents", "common"]); if (node === null) { return (

{t("lineUi.selectAgent", { defaultValue: "选择左侧代理查看占成与授信" })}

{t("lineUi.selectAgentHint", { defaultValue: "信用占成盘以代理树为结算边界,占成、授信与回水均在代理节点配置。", })}

); } const tabs: { key: AgentDetailTab; label: string; count?: number; visible: boolean }[] = [ { key: "overview", label: t("lineUi.tabOverview", { defaultValue: "概览" }), visible: true, }, { key: "profile", label: profileReadOnly ? t("lineUi.tabProfileReadOnly", { defaultValue: "占成与授信(只读)" }) : t("lineUi.tabProfile", { defaultValue: "占成与授信" }), visible: canViewProfileTab, }, { key: "downline", label: t("lineUi.tabDownline", { defaultValue: "直属下级" }), count: childAgents.length, visible: canViewDownlineTab, }, { key: "players", label: t("lineUi.tabPlayers", { defaultValue: "直属玩家" }), visible: canViewPlayersTab, }, ]; const siteDisplay = siteLabel && siteCode.trim() !== "" ? `${siteLabel} (${siteCode})` : siteLabel ?? siteCode; const childActionHint = canCreateChild ? null : canCreateChildAgent ? t("lineUi.addChildUnavailableHint", { defaultValue: "当前代理未开启“允许创建下级代理”,如需新增请先调整该代理配置。", }) : t("lineUi.addChildNoPermissionHint", { defaultValue: "当前账号没有为该节点创建下级代理的权限。", }); const playerActionHint = canViewPlayersTab && !canCreatePlayerAction ? playersTabHint ?? null : null; const showPrimaryAction = detailTab === "downline" || detailTab === "players"; const primaryActionEnabled = detailTab === "players" ? canCreatePlayerAction : canCreateChild; const primaryActionLabel = detailTab === "players" ? t("lineUi.createDirectPlayer", { defaultValue: "创建直属玩家" }) : t("createChild", { defaultValue: "添加下级代理" }); const primaryActionHint = detailTab === "players" ? playerActionHint : childActionHint; return (

{node.name}

{node.status === 1 ? t("common:status.enabled", { defaultValue: "启用" }) : t("common:status.disabled", { defaultValue: "停用" })}
{siteDisplay ? (

{siteDisplay}

) : null}
{canManageNode ? ( <>
{showPrimaryAction && primaryActionEnabled ? ( ) : null}
{primaryActionHint ? (

{primaryActionHint}

) : null} ) : null}
{tabs .filter((tab) => tab.visible) .map((tab) => ( onDetailTabChange(tab.key)} count={tab.count} > {tab.label} ))}
{detailTab === "overview" ? ( onDetailTabChange("downline")} onGoToPlayers={() => onDetailTabChange("players")} /> ) : null} {detailTab === "profile" && canViewProfileTab && profileFields ? ( {profileReadOnly ? t("lineUi.tabProfileReadOnly", { defaultValue: "占成与授信(只读)" }) : t("lineUi.tabProfile", { defaultValue: "占成与授信" })}

{profileReadOnly ? t("lineUi.profileReadOnlyHint", { defaultValue: "占成、授信与回水由上级配置,如需调整请联系上级代理或平台。", }) : t("lineUi.profileTabHint", { defaultValue: "占成、授信、回水与风控标签在此维护;登录名、密码与启停状态请用「编辑代理」。", })}

{canManageNode && canEditProfileTab ? (
) : null}
) : null} {detailTab === "downline" && canViewDownlineTab ? ( ) : null} {detailTab === "players" && canViewPlayersTab ? ( ) : null}
); } function OverviewTab({ profile, profileLoading, profileReadOnly, canViewDownlineTab, canViewPlayersTab, playersTabHint, childCount, onGoToDownline, onGoToPlayers, }: { profile: AgentProfileRow | null; profileLoading: boolean; profileReadOnly: boolean; canViewDownlineTab: boolean; canViewPlayersTab: boolean; playersTabHint?: string | null; childCount: number; onGoToDownline: () => void; onGoToPlayers: () => void; }): React.ReactElement { const { t } = useTranslation(["agents", "common"]); const rebateCap = profile && !profileLoading ? percentValueToUi(profile.rebate_limit ?? 0) : null; const parentRelativeShare = relativeShareRate( profile?.total_share_rate, profile?.parent_caps?.total_share_rate, ); return (
{profileReadOnly ? (
) : (
)} {!profileReadOnly && !profileLoading && profile ? (
0 ? profile.risk_tags!.join(", ") : t("common:states.none", { defaultValue: "无" }) } />
) : null} {profileReadOnly ? (

{t("lineUi.selfAgentOverviewHint", { defaultValue: "以下为上级为您分配的授信额度,占成与回水由上级在后台维护,本账号不可查看或修改。", })}

) : null} {canViewDownlineTab || canViewPlayersTab || playersTabHint ? (
{canViewDownlineTab ? ( ) : null} {canViewPlayersTab ? ( ) : null} {!canViewPlayersTab && playersTabHint ? (

{t("lineUi.tabPlayers", { defaultValue: "直属玩家" })}

{playersTabHint}

) : null}
) : null}
); } function OverviewLinkCard({ icon: Icon, title, summary, description, actionLabel, onAction, }: { icon: ComponentType<{ className?: string }>; title: string; summary: string; description: string; actionLabel: string; onAction: () => void; }): React.ReactElement { return (

{title}

5 ? "text-xl" : "text-2xl tabular-nums" )}> {summary}

{description}

); } function DownlineTable({ childAgents, childCountById, parentTotalShareRate, canManageNode, canCreateChild, canDeleteChild, onEditChild, onDeleteChild, onSelectChild, onAddChild, }: { childAgents: AgentNodeRow[]; childCountById: Map; parentTotalShareRate?: number; canManageNode: boolean; canCreateChild: boolean; canDeleteChild: (node: AgentNodeRow) => boolean; onEditChild: (node: AgentNodeRow) => void; onDeleteChild: (node: AgentNodeRow) => void; onSelectChild: (node: AgentNodeRow) => void; onAddChild: () => void; }): React.ReactElement { const { t } = useTranslation(["agents", "common"]); const createChildLabel = t("lineUi.createDownline", { defaultValue: "创建下级代理" }); const editChildLabel = t("lineUi.editDownline", { defaultValue: "编辑代理" }); const deleteChildLabel = t("lineUi.deleteDownline", { defaultValue: "删除代理" }); return (
{t("agentCode", { defaultValue: "代理编码" })} {t("agentName", { defaultValue: "代理名称" })} {t("loginUsername", { defaultValue: "登录名" })} {t("lineUi.downlineColumns.email", { defaultValue: "邮箱" })} {t("profile.totalShareRate", { defaultValue: "占成 (%)" })} {t("profile.creditLimit", { defaultValue: "授信额度" })} {t("lineUi.allocatedCredit", { defaultValue: "已下发" })} {t("lineUi.downlineColumns.downlineCount", { defaultValue: "下级数" })} {t("common:status.label", { defaultValue: "状态" })} {canManageNode ? ( {t("common:table.actions", { defaultValue: "操作" })} ) : null} {childAgents.length === 0 ? ( ) : ( childAgents.map((child) => { const summary = child.profile_summary; return ( onSelectChild(child)} > {child.code} {child.name} {child.username ?? "—"} {child.email ?? "—"} {summary ? (
{`${summary.total_share_rate ?? 0}%`}
{parentTotalShareRate && parentTotalShareRate > 0 ? (
{t("profile.relativeShareRateValue", { defaultValue: "占上级 {{rate}}%", rate: relativeShareRate( summary.total_share_rate, parentTotalShareRate, ) ?? "0", })}
) : null}
) : "—"}
{summary ? formatCredit(summary.credit_limit) : "—"} {summary ? formatCredit(summary.allocated_credit) : "—"} {childCountById.get(child.id) ?? 0} {child.status === 1 ? t("common:status.enabled", { defaultValue: "启用" }) : t("common:status.disabled", { defaultValue: "停用" })} {canManageNode ? ( e.stopPropagation()} > onEditChild(child), }, { key: "delete", label: deleteChildLabel, icon: Trash2, destructive: true, disabled: !canDeleteChild(child), onClick: () => onDeleteChild(child), }, ]} /> ) : null}
); }) )}
); } function MetricCard({ label, value, subtitle, accent = false, highlight = false, }: { label: string; value: string; subtitle?: string; accent?: boolean; highlight?: boolean; }): React.ReactElement { return (

{label}

{value}

{subtitle ?

{subtitle}

: null}
); }