"use client" import { useEffect, useState } from "react" import { useRouter } from "next/navigation" import { Card } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Shield, Users, DollarSign, Activity, Database, TrendingUp, AlertTriangle, Search, MoreVertical, Globe, LogOut, Settings, BarChart3, Clock, Building2, Plus, Eye, Edit, Trash2, Zap, Cpu, Server, Bot, Check, Calendar, Filter, Download, } from "lucide-react" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Label } from "@/components/ui/label" import { useLanguage } from "@/hooks/useLanguage" // Declare useLanguage import import { Badge } from "@/components/ui/badge" import { TaijiAPIClient, API_BASE_URLS } from "@/lib/api-client" import { SettingsTab } from "./components/SettingsTab" export default function AdminDashboard() { const router = useRouter() const { language, setLanguage } = useLanguage() const [activeTab, setActiveTab] = useState("overview") const [isAddChannelOpen, setIsAddChannelOpen] = useState(false) // const [isConfigGoodsOpen, setIsConfigGoodsOpen] = useState(false) // REMOVED // const [isAgentAllocationOpen, setIsAgentAllocationOpen] = useState(false) // REMOVED const [isResourceManagementOpen, setIsResourceManagementOpen] = useState(false) // ADDED const [isCommissionDialogOpen, setIsCommissionDialogOpen] = useState(false) const [selectedChannel, setSelectedChannel] = useState<(typeof channels)[0] | null>(null) const [selectedModels, setSelectedModels] = useState([]) // const [monthlyQuota, setMonthlyQuota] = useState(""); // REMOVED const [creditLimit, setCreditLimit] = useState("") const [isSubscriptionDialogOpen, setIsSubscriptionDialogOpen] = useState(false) const [selectedSubscriptionLevel, setSelectedSubscriptionLevel] = useState(null) const [commissionRate, setCommissionRate] = useState("") const [selectedTenant, setSelectedTenant] = useState(null) // Declare selectedTenant variable const [computeConfigOpen, setComputeConfigOpen] = useState(false) // State for compute configuration dialog // 新增:渠道管理对话框状态 const [isChannelDetailsDialogOpen, setIsChannelDetailsDialogOpen] = useState(false) const [isChannelEditDialogOpen, setIsChannelEditDialogOpen] = useState(false) const [channelAllocatedResources, setChannelAllocatedResources] = useState(null) // 渠道资源分配详情(新接口) const [channelTenantsResources, setChannelTenantsResources] = useState(null) // 租户资源分配数据(旧接口) const [channelTenantsResourcesLoading, setChannelTenantsResourcesLoading] = useState(false) const [isViewTenantsDialogOpen, setIsViewTenantsDialogOpen] = useState(false) const [isAddTenantDialogOpen, setIsAddTenantDialogOpen] = useState(false) const [isTenantPermissionDialogOpen, setIsTenantPermissionDialogOpen] = useState(false) const [channelTenantsLoading, setChannelTenantsLoading] = useState(false) const [channelTenants, setChannelTenants] = useState([]) const [selectedTenantForEdit, setSelectedTenantForEdit] = useState(null) const [selectedTenantForPermission, setSelectedTenantForPermission] = useState(null) // 新增:修改密码对话框状态 const [isChangePasswordDialogOpen, setIsChangePasswordDialogOpen] = useState(false) const [newPassword, setNewPassword] = useState("") const [confirmPassword, setConfirmPassword] = useState("") const [changePasswordLoading, setChangePasswordLoading] = useState(false) const [newTenantForm, setNewTenantForm] = useState({ name: "", email: "", password: "", systemRole: "tenant" as "tenant" | "billing-admin" | "operations-admin", }) const [tenantPermissions, setTenantPermissions] = useState([]) const [channelEditForm, setChannelEditForm] = useState({ name: "", contactName: "", email: "", phone: "", }) const [channelAdmins, setChannelAdmins] = useState([]) const [newChannelForm, setNewChannelForm] = useState({ name: "", email: "", password: "", commissionRate: "", }) const [billingData, setBillingData] = useState(null) const [billingLoading, setBillingLoading] = useState(false) const [isAddProviderOpen, setIsAddProviderOpen] = useState(false) const [isConfigProviderOpen, setIsConfigProviderOpen] = useState(false) const [providerType, setProviderType] = useState<"model" | "data">("model") const [selectedProvider, setSelectedProvider] = useState(null) const [providerForm, setProviderForm] = useState({ name: "", url: "", apiKey: "", models: [] as string[], // 改为数组支持多选 rpm: "", tpm: "", }) const [litellmModels, setLitellmModels] = useState([]) // LiteLLM 模型列表 const [litellmModelsLoading, setLitellmModelsLoading] = useState(false) // 加载状态 const [selectedAgent, setSelectedAgent] = useState(null) // State for selected agent in resources tab // Agent资源配置表单状态 const [agentConfigForm, setAgentConfigForm] = useState({ cpuRequest: "100m", cpuLimit: "500m", memoryRequest: "128Mi", memoryLimit: "512Mi", maxInstances: 10, }) const [customAgentCpu, setCustomAgentCpu] = useState("2") const [customAgentMemory, setCustomAgentMemory] = useState("4") const [agentResources, setAgentResources] = useState([]) // Agent资源列表 const [modelProviders, setModelProviders] = useState([]) // 模型供应商列表 const [resourcesLoading, setResourcesLoading] = useState(false) // const [isAgentAllocationOpen, setIsAgentAllocationOpen] = useState(false) // REMOVED const [selectedAgents, setSelectedAgents] = useState([]) const [agentQuantities, setAgentQuantities] = useState>({}) // Billing state const [billingView, setBillingView] = useState<"channel" | "tenant" | "calls">("channel") const [showFilterDialog, setShowFilterDialog] = useState(false) const [showDateDialog, setShowDateDialog] = useState(false) const [showExportDialog, setShowExportDialog] = useState(false) const [selectedRole, setSelectedRole] = useState(null) const [rolePermissions, setRolePermissions] = useState<{ [key: string]: string[] }>({ "billing-admin": ["overview", "channels", "billing"], "operations-admin": ["overview", "channels", "resources", "monitoring"], "super-admin": [ "overview", "channels", "resources", "monitoring", "billing", "provider-backend", "channel-backend", "settings", ], }) const [showAddAdminDialog, setShowAddAdminDialog] = useState(false) const [admins, setAdmins] = useState([]) const [adminsLoading, setAdminsLoading] = useState(false) const [deleteAdminConfirm, setDeleteAdminConfirm] = useState<{ open: boolean; admin: any | null }>({ open: false, admin: null, }) const [newAdminForm, setNewAdminForm] = useState({ name: "", email: "", password: "", role: "billing_admin", }) const [providerApprovals, setProviderApprovals] = useState([]) const [selectedApproval, setSelectedApproval] = useState(null) const [isApprovalDialogOpen, setIsApprovalDialogOpen] = useState(false) // 平台Agent申请审批相关状态 const [platformAgentApplications, setPlatformAgentApplications] = useState([]) const [selectedPlatformAgentApplication, setSelectedPlatformAgentApplication] = useState(null) const [isPlatformAgentApprovalDialogOpen, setIsPlatformAgentApprovalDialogOpen] = useState(false) const [approvedPodQuota, setApprovedPodQuota] = useState("") const [approvalReason, setApprovalReason] = useState("") // Simplified t function for demonstration const t = (zh: string, en: string) => (language === "zh" ? zh : en) const translations = { en: { title: "Super Admin Console", subtitle: "Platform Control Center", overview: "Overview", channels: "Channels", resources: "Resources", monitoring: "Monitoring", billing: "Billing", settings: "Settings", goodsProviders: "Goods Providers", // renamed from separate model/data providers logout: "Logout", totalTenants: "Total Tenants", totalChannels: "Total Channels", activeTenants: "Active Tenants", totalRevenue: "Total Revenue", systemHealth: "System Health", cpuUsage: "CPU Usage", memoryUsage: "Memory Usage", storageUsage: "Storage Usage", activeAgents: "Active Agents", recentTenants: "Recent Tenants", tenantName: "Tenant Name", status: "Status", plan: "Plan", usage: "Usage", actions: "Actions", search: "Search tenants...", searchChannels: "Search channels...", active: "Active", enterprise: "Enterprise", professional: "Professional", starter: "Starter", viewDetails: "View Details", suspend: "Suspend", systemMetrics: "System Metrics", healthy: "Healthy", addChannel: "Add Channel", channelName: "Channel Name", channelManagement: "Channel Management", channelDescription: "Manage distribution channels and their tenant portfolios", tenantCount: "Tenants", commission: "Commission Rate", contactPerson: "Contact Person", edit: "Edit", delete: "Delete", createChannel: "Create New Channel", cancel: "Cancel", create: "Create", channelNamePlaceholder: "Enter channel name", contactEmail: "Contact Email", contactPhone: "Contact Phone", commissionRate: "Commission Rate (%)", assignSubscriptionLevel: "Assign System Role", selectedTenantPlaceholder: "Select a tenant", agentHealthMonitoring: "Agent Health Monitoring", agentHealthDesc: "Monitor performance and health status of all platform agents", agentStatus: "Status", cpuUsageLabel: "CPU Usage", memoryUsageLabel: "Memory Usage", responseTime: "Response Time", requestCount: "Request Count", errorRate: "Error Rate", uptime: "Uptime", lastActive: "Last Active", ms: "ms", requests: "requests", warning: "Warning", critical: "Critical", // Added translations for role management userRoleSettings: "User Role Settings", billingAdministrator: "Billing Administrator", responsibleForBilling: "Responsible for billing, invoices, and financial management", operationsAdministrator: "Operations Administrator", responsibleForChannels: "Responsible for channels, resources, and monitoring", superAdministrator: "Super Administrator", fullAccess: "Full access to all platform features", permissions: "permissions", tabAccessPermissions: "Tab Access Permissions", selectTabs: "Select which tabs this role can access", providerBackend: "Provider Backend", channelBackend: "Channel Backend", savePermissions: "Save Permissions", // Added translations for add admin dialog addAdministrator: "Add Administrator", administratorName: "Administrator Name", enterAdministratorName: "Enter administrator name", email: "Email", enterEmailAddress: "Enter email address", password: "Password", setLoginPassword: "Set login password", role: "Role", billingAdmin: "Billing Administrator", operationsAdmin: "Operations Administrator", superAdmin: "Super Administrator", createAdministrator: "Create Administrator", // ADDED translations for billing billingManagement: "Billing Management", dateQuery: "Date Query", filter: "Filter", export: "Export", channelBillingDetails: "Channel Billing Details", callCount: "Call Count", totalEU: "Total EU", channelTotal: "Channel Total", billingPeriod: "Billing Period", tenantBillingDetails: "Tenant Billing Details", channel: "Channel", userTotal: "User Total", averageSpending: "Average Spending", callRecordsDetail: "Call Records Detail", callID: "Call ID", tenant: "Tenant", callTime: "Call Time", durationSeconds: "Duration(s)", singleCallCost: "Single Call Cost", timestamp: "Timestamp", EUCalculationRule: "EU Calculation: 1 EU = 10 seconds call time", // ADDED translations for filter dialog filterOptions: "Filter Options", customerName: "Customer Name", minCalls: "Min Calls", maxCalls: "Max Calls", applyFilter: "Apply Filter", // ADDED translations for date dialog dateTimeRange: "Date & Time Range", startDate: "Start Date & Time (YYYY-MM-DD HH:MM)", endDate: "End Date & Time (YYYY-MM-DD HH:MM)", query: "Query", // ADDED translations for export dialog exportFormat: "Export Format", selectExportFormat: "Select export file format", }, zh: { title: "超级管理员控制台", subtitle: "平台控制中心", overview: "概览", channels: "渠道管理", resources: "资源管理", monitoring: "监控", billing: "计费", settings: "设置", goodsProviders: "货源供应商", // renamed from separate model/data providers logout: "退出", totalTenants: "总租户数", totalChannels: "总渠道数", activeTenants: "活跃租户", totalRevenue: "总收入", systemHealth: "系统健康", cpuUsage: "CPU 使用率", memoryUsage: "内存使用率", storageUsage: "存储使用率", activeAgents: "活跃Agent", recentTenants: "最近租户", tenantName: "租户名称", status: "状态", plan: "方案", usage: "使用量", actions: "操作", search: "搜索租户...", searchChannels: "搜索渠道...", active: "活跃", enterprise: "企业版", professional: "专业版", starter: "入门版", viewDetails: "查看详情", suspend: "暂停", systemMetrics: "系统指标", healthy: "健康", addChannel: "添加渠道", channelName: "渠道名称", channelManagement: "渠道管理", channelDescription: "管理分销渠道及其租户组合", tenantCount: "租户数", commission: "佣金比例", contactPerson: "联系人", edit: "编辑", delete: "删除", createChannel: "创建新渠道", cancel: "取消", create: "创建", channelNamePlaceholder: "输入渠道名称", contactEmail: "联系邮箱", contactPhone: "联系电话", commissionRate: "佣金比例 (%)", assignSubscriptionLevel: "分配系统权限", selectedTenantPlaceholder: "选择一个租户", agentHealthMonitoring: "Agent健康监控", agentHealthDesc: "监控所有平台Agent的性能和健康状态", agentStatus: "状态", cpuUsageLabel: "CPU使用率", memoryUsageLabel: "内存使用率", responseTime: "响应时间", requestCount: "请求数量", errorRate: "错误率", uptime: "运行时间", lastActive: "最后活跃", warning: "警告", critical: "严重", // Added translations for role management userRoleSettings: "用户身份设置", billingAdministrator: "计费管理员", responsibleForBilling: "负责平台计费、账单和财务管理", operationsAdministrator: "运营管理员", responsibleForChannels: "负责渠道、资源和系统监控管理", superAdministrator: "超级管理员", fullAccess: "拥有所有权限,管理整个平台", permissions: "个权限", tabAccessPermissions: "标签页访问权限", selectTabs: "选择该角色可以访问的标签页", providerBackend: "供应商管理中心后台", channelBackend: "渠道管理中心后台", savePermissions: "保存权限配置", // Added translations for add admin dialog addAdministrator: "添加管理员", administratorName: "管理员名称", enterAdministratorName: "输入管理员名称", email: "邮箱", enterEmailAddress: "输入邮箱地址", password: "密码", setLoginPassword: "设置登录密码", role: "角色", billingAdmin: "计费管理员", operationsAdmin: "运营管理员", superAdmin: "超级管理员", createAdministrator: "创建管理员", // ADDED translations for billing billingManagement: "计费管理", dateQuery: "时间查询", filter: "筛选", export: "导出", channelBillingDetails: "渠道计费详情", callCount: "调用次数", totalEU: "总EU", channelTotal: "渠道总价", billingPeriod: "计费周期", tenantBillingDetails: "租户计费详情", channel: "渠道", userTotal: "用户总价", averageSpending: "平均消费", callRecordsDetail: "调用记录明细", callID: "调用ID", tenant: "租户", callTime: "调用时间", durationSeconds: "时长(秒)", singleCallCost: "单次调用总价", timestamp: "时间戳", EUCalculationRule: "EU计算:1 EU = 10秒调用时间", // ADDED translations for filter dialog filterOptions: "筛选选项", customerName: "客户名称", minCalls: "最小调用次数", maxCalls: "最大调用次数", applyFilter: "应用筛选", // ADDED translations for date dialog dateTimeRange: "时间范围", startDate: "开始时间 (年-月-日 时:分)", endDate: "结束时间 (年-月-日 时:分)", query: "查询", // ADDED translations for export dialog exportFormat: "导出格式", selectExportFormat: "选择导出文件格式", }, } const text = translations[language] const [agents, setAgents] = useState([]) const [agentSummary, setAgentSummary] = useState(null) // Agent监控汇总统计 const [stats, setStats] = useState([]) const [systemMetrics, setSystemMetrics] = useState([]) // 平台资源分配统计(platformAgents + customAgents) const [resourceAllocationStats, setResourceAllocationStats] = useState({ totalCount: 0, totalCpu: 0, totalMemory: 0, platformCount: 0, // 平台分配的 Agent 数量 customCount: 0, // 自定义启动的 Agent 数量 }) const [channels, setChannels] = useState([]) const [tenants, setTenants] = useState([]) const [recentLogins, setRecentLogins] = useState([]) // 最近登录的租户列表 const [availableModels, setAvailableModels] = useState([]) const [availableDataSources, setAvailableDataSources] = useState([]) const [availableAgents, setAvailableAgents] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const token = localStorage.getItem("admin_token") if (!token) { router.push("/admin/login") return } loadDashboardData() }, [router]) const loadDashboardData = async () => { try { setLoading(true) // 加载统计数据 - 使用正确的后端字段名 const statsResponse = await TaijiAPIClient.getAdminDashboardStats() const statsData = statsResponse?.data || statsResponse console.log("[v0] Stats Data:", statsData) if (statsData) { setStats([ { title: text.totalChannels, value: statsData.totalChannels?.toString() || "0", change: "", icon: Building2, trend: "up", }, { title: text.totalTenants, value: statsData.totalTenants?.toString() || "0", change: "", icon: Users, trend: "up", }, { title: text.activeTenants, value: statsData.totalAgents?.toString() || "0", // 使用 totalAgents 作为活跃指标 change: "", icon: Activity, trend: "up", }, { title: text.totalRevenue, value: statsData.totalRevenue ? `$${statsData.totalRevenue}` : "$0", change: "", icon: DollarSign, trend: "up", }, ]) // 计算平台资源分配统计 (platformAgents + customAgents) - 数据来自 stats 接口 const platformAgents = statsData.platformAgents || { count: 0, cpu: 0, memory: 0 } const customAgents = statsData.customAgents || { count: 0, cpu: 0, memory: 0 } setResourceAllocationStats({ totalCount: (platformAgents.count || 0) + (customAgents.count || 0), totalCpu: (platformAgents.cpu || 0) + (customAgents.cpu || 0), totalMemory: (platformAgents.memory || 0) + (customAgents.memory || 0), platformCount: platformAgents.count || 0, customCount: customAgents.count || 0, }) } // 加载系统性能指标 - 使用正确的监控接口 GET /api/v1/monitoring/metrics try { const metricsResponse = await TaijiAPIClient.getMonitoringMetrics() const metricsData = metricsResponse?.data || metricsResponse if (metricsData) { // 增加调试日志 console.log("[v0] Metrics Data:", metricsData) setSystemMetrics([ { label: text.cpuUsage, value: metricsData.cpu_usage || metricsData.system?.cpu_usage_percent || 0, max: 100, color: "bg-blue-500" }, { label: text.memoryUsage, value: metricsData.memory_usage || metricsData.system?.memory_usage_percent || 0, max: 100, color: "bg-green-500" }, { label: text.storageUsage, value: metricsData.disk_usage || metricsData.system?.disk_usage_percent || 0, max: 100, color: "bg-yellow-500" }, { label: text.activeAgents, value: metricsData.active_agents || metricsData.services?.active_agents || 0, max: 100, color: "bg-purple-500" }, ]) } else { // 如果监控接口没有返回数据,设置默认值 setSystemMetrics([ { label: text.cpuUsage, value: 0, max: 100, color: "bg-blue-500" }, { label: text.memoryUsage, value: 0, max: 100, color: "bg-green-500" }, { label: text.storageUsage, value: 0, max: 100, color: "bg-yellow-500" }, { label: text.activeAgents, value: 0, max: 100, color: "bg-purple-500" }, ]) } } catch (metricsError) { console.error("Failed to load monitoring metrics:", metricsError) // 监控接口失败时设置默认值 setSystemMetrics([ { label: text.cpuUsage, value: 0, max: 100, color: "bg-blue-500" }, { label: text.memoryUsage, value: 0, max: 100, color: "bg-green-500" }, { label: text.storageUsage, value: 0, max: 100, color: "bg-yellow-500" }, { label: text.activeAgents, value: 0, max: 100, color: "bg-purple-500" }, ]) } // 加载渠道列表 const channelsData = await TaijiAPIClient.getAdminChannels() if (channelsData?.data?.channels && Array.isArray(channelsData.data.channels)) { setChannels(channelsData.data.channels) } else if (Array.isArray(channelsData)) { setChannels(channelsData) } // 加载供应商申请列表(使用专用接口) try { const providerAppsData = await TaijiAPIClient.getProviderApplications() if (providerAppsData?.success && providerAppsData.data?.applications) { setProviderApprovals(providerAppsData.data.applications) } else if (providerAppsData?.data?.data && Array.isArray(providerAppsData.data.data)) { // 兼容旧的响应格式 setProviderApprovals(providerAppsData.data.data) } else if (Array.isArray(providerAppsData?.data)) { setProviderApprovals(providerAppsData.data) } else { setProviderApprovals([]) } } catch (error) { console.log("Failed to load provider applications:", error) setProviderApprovals([]) } // 加载平台Agent申请列表(新的专用接口) try { const platformAgentAppsData = await TaijiAPIClient.getPlatformAgentApplications() if (platformAgentAppsData?.success && platformAgentAppsData.data?.applications) { setPlatformAgentApplications(platformAgentAppsData.data.applications) } else if (Array.isArray(platformAgentAppsData?.data)) { setPlatformAgentApplications(platformAgentAppsData.data) } else { setPlatformAgentApplications([]) } } catch (error) { console.log("Failed to load platform agent applications:", error) setPlatformAgentApplications([]) } // 加载Agent监控数据 try { const agentMonitoringData = await TaijiAPIClient.getPlatformAgentStatus() if (agentMonitoringData?.data?.agents && Array.isArray(agentMonitoringData.data.agents)) { setAgents(agentMonitoringData.data.agents) // 保存汇总统计信息 if (agentMonitoringData.data.summary) { setAgentSummary(agentMonitoringData.data.summary) } } else if (Array.isArray(agentMonitoringData)) { setAgents(agentMonitoringData) } } catch (error) { console.error("Failed to load agent monitoring data:", error) setAgents([]) } // 加载模型提供商(用于渠道资源分配) const modelProvidersData = await TaijiAPIClient.getAdminModelProviders() if (modelProvidersData?.data?.providers && Array.isArray(modelProvidersData.data.providers)) { setAvailableModels(modelProvidersData.data.providers) setModelProviders(modelProvidersData.data.providers) } else if (Array.isArray(modelProvidersData)) { setAvailableModels(modelProvidersData) setModelProviders(modelProvidersData) } // 加载供应商列表(用于供应商管理) try { const providersData = await TaijiAPIClient.getModelProviders() if (providersData?.data?.providers && Array.isArray(providersData.data.providers)) { // 如果providers不为空,则使用该列表 setModelProviders(providersData.data.providers) } } catch (error) { console.log("Failed to load providers list:", error) // 如果获取失败,继续使用admin API的数据 } // 加载Agent资源 - 使用平台Agent模板接口(管理员端) const agentResourcesData = await TaijiAPIClient.getPlatformAgentTemplates() if (agentResourcesData?.data?.templates && Array.isArray(agentResourcesData.data.templates)) { setAvailableAgents(agentResourcesData.data.templates) setAgentResources(agentResourcesData.data.templates) } else if (agentResourcesData?.data?.agents && Array.isArray(agentResourcesData.data.agents)) { // 兼容旧的响应格式 setAvailableAgents(agentResourcesData.data.agents) setAgentResources(agentResourcesData.data.agents) } else if (Array.isArray(agentResourcesData)) { setAvailableAgents(agentResourcesData) setAgentResources(agentResourcesData) } // 加载租户列表 try { const tenantsData = await TaijiAPIClient.getAdminTenants() if (tenantsData?.success && tenantsData.data?.tenants) { setTenants(tenantsData.data.tenants) } else if (Array.isArray(tenantsData?.data)) { setTenants(tenantsData.data) } else { setTenants([]) } } catch (error) { console.log("Failed to load tenants:", error) setTenants([]) } // 加载最近登录的租户列表 try { const recentLoginsData = await TaijiAPIClient.getRecentLogins(10) if (recentLoginsData?.success && recentLoginsData.data?.recentTenants && Array.isArray(recentLoginsData.data.recentTenants)) { setRecentLogins(recentLoginsData.data.recentTenants) } else if (recentLoginsData?.success && recentLoginsData.data?.tenants && Array.isArray(recentLoginsData.data.tenants)) { // 兼容:后端返回的字段是 tenants 而不是 recentTenants setRecentLogins(recentLoginsData.data.tenants) } else if (Array.isArray(recentLoginsData?.data)) { setRecentLogins(recentLoginsData.data) } else { setRecentLogins([]) } } catch (error) { console.log("Failed to load recent logins:", error) setRecentLogins([]) } // 数据源列表暂时设为空(后端API待实现) setAvailableDataSources([]) } catch (error) { console.error("Failed to load dashboard data:", error) } finally { setLoading(false) } } const handleLogout = async () => { try { // 调用后端logout API await TaijiAPIClient.logout() } catch (error) { console.error("Logout API call failed:", error) } finally { // 清除所有本地存储的token和用户信息 localStorage.removeItem("admin_token") localStorage.removeItem("auth_token") localStorage.removeItem("channel_token") localStorage.removeItem("refresh_token") localStorage.removeItem("user") localStorage.removeItem("api_key") router.push("/admin/login") } } // handlers for goods configuration const handleConfigGoods = (channel: (typeof channels)[0]) => { setSelectedChannel(channel) // setIsConfigGoodsOpen(true) // REMOVED setIsResourceManagementOpen(true) // ADDED } // const handleSaveGoodsConfig = () => { // REMOVED // // Handle save logic // console.log("Saving config for:", selectedChannel?.name) // console.log("Selected models:", selectedModels) // console.log("Selected data sources:", selectedDataSources) // console.log("Monthly quota:", monthlyQuota) // console.log("Monthly budget:", monthlyBudget) // setIsConfigGoodsOpen(false) // setSelectedModels([]) // setSelectedDataSources([]) // setMonthlyQuota("") // setMonthlyBudget("") // } const handleEditCommission = (channel: (typeof channels)[0]) => { setSelectedChannel(channel) setCommissionRate(channel.commission.toString()) setIsCommissionDialogOpen(true) } const handleSaveCommission = async () => { if (!selectedChannel) return try { // 使用专门的佣金更新API const rate = parseFloat(commissionRate) / 100 // 将百分比转换为小数 const result = await TaijiAPIClient.updateChannelCommission(selectedChannel.id, rate) if (result?.success) { alert(language === "zh" ? `佣金比例已更新为 ${commissionRate}%` : `Commission rate updated to ${commissionRate}%`) } // 重新加载数据 await loadDashboardData() setIsCommissionDialogOpen(false) setCommissionRate("") } catch (error) { console.error("Failed to save commission:", error) alert(language === "zh" ? "保存失败" : "Failed to save") } } const handleAddProvider = async (type: "model" | "data") => { setProviderType(type) setProviderForm({ name: "", url: "", apiKey: "", models: [], rpm: "", tpm: "", }) // 加载 LiteLLM 模型列表 setLitellmModelsLoading(true) try { const models = await TaijiAPIClient.getLiteLLMModelIds() setLitellmModels(models) } catch (error) { console.error("Failed to load LiteLLM models:", error) setLitellmModels([]) } finally { setLitellmModelsLoading(false) } setIsAddProviderOpen(true) } const handleConfigProvider = async (provider: any, type: "model" | "data") => { setProviderType(type) setSelectedProvider(provider) setProviderForm({ name: provider.name, url: provider.url || "", apiKey: "••••••••", models: provider.models || [], rpm: provider.rpm?.toString() || "", tpm: provider.tpm?.toString() || "", }) // 加载 LiteLLM 模型列表 setLitellmModelsLoading(true) try { const models = await TaijiAPIClient.getLiteLLMModelIds() setLitellmModels(models) } catch (error) { console.error("Failed to load LiteLLM models:", error) setLitellmModels([]) } finally { setLitellmModelsLoading(false) } setIsConfigProviderOpen(true) } const handleSaveProvider = async () => { try { // 验证必填字段 if (!providerForm.name || !providerForm.url || !providerForm.apiKey || providerForm.models.length === 0) { alert(language === "zh" ? "请填写所有必填字段" : "Please fill in all required fields") return } const supportedModels = providerForm.models.filter((m: string) => m.length > 0) if (supportedModels.length === 0) { alert(language === "zh" ? "请至少选择一个模型" : "Please select at least one model") return } // 判断是添加新的还是更新现有的供应商 if (selectedProvider) { // 更新现有供应商 await TaijiAPIClient.updateProvider(selectedProvider.id, { name: providerForm.name, provider: providerType === "model" ? "openai" : "anthropic", apiUrl: providerForm.url, apiKey: providerForm.apiKey, supportedModels, rpm: parseInt(providerForm.rpm) || 3500, tpm: parseInt(providerForm.tpm) || 90000, }) alert(language === "zh" ? "供应商更新成功" : "Provider updated successfully") } else { // 创建新供应商 await TaijiAPIClient.createModelProvider({ name: providerForm.name, provider: "openai", // 默认为 openai,实际应该根据供应商类型选择 apiUrl: providerForm.url, apiKey: providerForm.apiKey, supportedModels, rpm: parseInt(providerForm.rpm) || 3500, tpm: parseInt(providerForm.tpm) || 90000, }) alert(language === "zh" ? "供应商创建成功" : "Provider created successfully") } // 重新加载数据 await loadDashboardData() // 清空表单 setIsAddProviderOpen(false) setIsConfigProviderOpen(false) setProviderForm({ name: "", url: "", apiKey: "", models: [], rpm: "", tpm: "", }) setSelectedProvider(null) } catch (error) { console.error("Failed to save provider:", error) alert(language === "zh" ? "保存失败,请检查输入" : "Failed to save provider. Please check your input") } } // const handleAgentAllocation = (channel: (typeof channels)[0]) => { // REMOVED // setSelectedChannel(channel) // setSelectedAgents([]) // setAgentQuantities({}) // setIsAgentAllocationOpen(true) // } // const handleSaveAgentAllocation = () => { // REMOVED // console.log("Saving agent allocation for:", selectedChannel?.name) // console.log("Selected agents:", selectedAgents) // console.log("Agent quantities:", agentQuantities) // setIsAgentAllocationOpen(false) // setSelectedAgents([]) // setAgentQuantities({}) // } // ADDED: Unified resource management handler const handleResourceManagement = async (channel: (typeof channels)[0]) => { setSelectedChannel(channel) // 重置选择状态 setSelectedModels([]) setSelectedAgents([]) setAgentQuantities({}) setCreditLimit("") setCustomAgentCpu("2") setCustomAgentMemory("4") // 从API加载当前渠道的资源配置 try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/${channel.id}/resources`, { headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() console.log("[DEBUG] Channel resources API response:", data) if (data.success && data.data) { // 加载已选择的模型 if (data.data.models && Array.isArray(data.data.models)) { console.log("[DEBUG] Loading models:", data.data.models) setSelectedModels(data.data.models) } // 加载已分配的Agent - 只加载有 agentId 的项目 if (data.data.agents && Array.isArray(data.data.agents)) { console.log("[DEBUG] Loading agents from API:", data.data.agents) console.log("[DEBUG] Available agents:", availableAgents) // 过滤掉无效的 agentId const validAgents = data.data.agents.filter((a: any) => a.agentId && typeof a.agentId === 'string') // 将后端返回的 agentId 映射到前端 availableAgents 的 agentKey (id || name) // 后端可能返回 agent.name 或 agent.id,需要兼容两种情况 const agentKeys: string[] = [] const quantities: { [key: string]: number } = {} validAgents.forEach((a: any) => { // 尝试在 availableAgents 中找到匹配的 agent const matchedAgent = availableAgents.find( (avail: any) => avail.id === a.agentId || avail.name === a.agentId ) if (matchedAgent) { // 使用 availableAgents 中的 agentKey (id || name) 作为选中状态的 key const agentKey = matchedAgent.id || matchedAgent.name agentKeys.push(agentKey) quantities[agentKey] = a.quantity || 1 } else { // 如果找不到匹配的,直接使用后端返回的 agentId agentKeys.push(a.agentId) quantities[a.agentId] = a.quantity || 1 } }) console.log("[DEBUG] Mapped agent keys:", agentKeys) console.log("[DEBUG] Agent quantities:", quantities) setSelectedAgents(agentKeys) setAgentQuantities(quantities) } // 加载自定义Agent资源配置 if (data.data.customAgentResources) { setCustomAgentCpu(String(data.data.customAgentResources.cpu || 2)) setCustomAgentMemory(String(data.data.customAgentResources.memory || 4)) } // 加载授信额度 if (data.data.channelCredit) { setCreditLimit(String(data.data.channelCredit)) } } } else { console.log("[DEBUG] Channel resources API returned non-OK status:", response.status) } } catch (error) { console.error("Failed to load channel resources:", error) // 如果加载失败,保持默认值(空数组) } setIsResourceManagementOpen(true) } // ADDED: Unified resource management save handler const handleSaveResourceManagement = async () => { if (!selectedChannel) return try { // 过滤掉无效的 agentId(undefined、null、空字符串) const validAgents = selectedAgents .filter((agentId) => agentId && typeof agentId === 'string' && agentId.trim() !== '') .map((agentId) => ({ agentId, quantity: agentQuantities[agentId] || 1, })) // 调试日志 console.log("[DEBUG] handleSaveResourceManagement:") console.log(" - selectedAgents:", selectedAgents) console.log(" - validAgents:", validAgents) console.log(" - agentQuantities:", agentQuantities) console.log(" - selectedModels:", selectedModels) const requestData = { models: selectedModels, agents: validAgents, customAgentResources: { cpu: parseFloat(customAgentCpu) || 2, memory: parseFloat(customAgentMemory) || 4, }, channelCredit: parseFloat(creditLimit) || 0, } console.log("[DEBUG] Request data:", JSON.stringify(requestData, null, 2)) await TaijiAPIClient.manageChannelResources(selectedChannel.id, requestData) // 重新加载数据 await loadDashboardData() setIsResourceManagementOpen(false) setSelectedModels([]) setSelectedAgents([]) setAgentQuantities({}) setCreditLimit("") } catch (error) { console.error("Failed to save resource management:", error) alert(language === "zh" ? "保存失败" : "Failed to save") } } // 新增:查看渠道详情 const handleViewChannelDetails = async (channel: (typeof channels)[0]) => { setSelectedChannel(channel) setIsChannelDetailsDialogOpen(true) setChannelAllocatedResources(null) setChannelTenantsResources(null) setChannelTenantsResourcesLoading(true) // 可选:从API获取最新的渠道详情 try { const response = await fetch(`/api/admin/channels/${channel.id}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('admin_token') || localStorage.getItem('auth_token')}` } }) if (response.ok) { const data = await response.json() if (data.success) { setSelectedChannel(data.data) } } } catch (error) { console.error('Failed to fetch channel details:', error) } // 同时加载渠道资源分配详情(新接口)和租户资源分配(旧接口) try { const [allocatedResponse, tenantsResponse] = await Promise.all([ TaijiAPIClient.getChannelAllocatedResources(channel.id), TaijiAPIClient.getChannelTenantsResources(channel.id) ]) if (allocatedResponse.success && allocatedResponse.data) { setChannelAllocatedResources(allocatedResponse.data) } if (tenantsResponse.success && tenantsResponse.data) { setChannelTenantsResources(tenantsResponse.data) } } catch (error) { console.error('Failed to fetch channel resources:', error) } finally { setChannelTenantsResourcesLoading(false) } } // 新增:编辑渠道信息 const handleEditChannel = async (channel: (typeof channels)[0]) => { setSelectedChannel(channel) setChannelEditForm({ name: channel.name, contactName: channel.contact || "", email: channel.email, phone: channel.phone || "", }) // 获取渠道管理员列表 try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`/api/admin/channels/${channel.id}/admins`, { headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() if (data.success && data.data) { setChannelAdmins(data.data.admins || []) } } } catch (error) { console.error('Failed to fetch channel admins:', error) setChannelAdmins([]) } setIsChannelEditDialogOpen(true) } // 新增:保存渠道编辑 const handleSaveChannelEdit = async () => { if (!selectedChannel) return try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/${selectedChannel.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ name: channelEditForm.name, email: channelEditForm.email, contactName: channelEditForm.contactName, phone: channelEditForm.phone }) }) if (response.ok) { const data = await response.json() if (data.success) { setSelectedChannel({ ...selectedChannel, name: channelEditForm.name, email: channelEditForm.email, contact: channelEditForm.contactName, phone: channelEditForm.phone }) setIsChannelEditDialogOpen(false) console.log('Channel updated successfully') } } else { console.error('Failed to update channel:', response.statusText) } } catch (error) { console.error("Failed to save channel edit:", error) } } // 新增:查看租户列表 const handleViewTenants = async (channel: (typeof channels)[0]) => { setSelectedChannel(channel) setIsViewTenantsDialogOpen(true) setChannelTenantsLoading(true) try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') // 超级管理员查看渠道租户时,使用 /api/admin/tenants 接口并传递 channel_id 参数 const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/tenants?channel_id=${channel.id}`, { headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() if (data.success && data.data?.tenants) { setChannelTenants(data.data.tenants) } else if (Array.isArray(data.data)) { setChannelTenants(data.data) } else { setChannelTenants([]) } } else { console.error('Failed to fetch tenants:', response.statusText) setChannelTenants([]) } } catch (error) { console.error("Failed to load tenants:", error) setChannelTenants([]) } finally { setChannelTenantsLoading(false) } } // 新增:修改租户密码 const handleTenantChangePassword = async (tenantId: string) => { const tenant = channelTenants.find(t => t.id === tenantId) if (!tenant) return setSelectedTenantForEdit(tenant) setNewPassword("") setConfirmPassword("") setIsChangePasswordDialogOpen(true) } // 新增:执行密码修改 const handleConfirmChangePassword = async () => { if (!selectedTenantForEdit) return // 验证密码 if (!newPassword || newPassword.length < 6) { alert(language === "zh" ? "密码长度至少6位" : "Password must be at least 6 characters") return } if (newPassword !== confirmPassword) { alert(language === "zh" ? "两次输入的密码不一致" : "Passwords do not match") return } setChangePasswordLoading(true) try { // 超级管理员修改租户密码时,需要提供 channel_id 参数 const channelId = selectedChannel?.id const result = await TaijiAPIClient.changeTenantPassword(selectedTenantForEdit.id, newPassword, channelId) if (result?.success) { alert(language === "zh" ? "密码修改成功" : "Password changed successfully") setIsChangePasswordDialogOpen(false) setNewPassword("") setConfirmPassword("") setSelectedTenantForEdit(null) } else { alert(result?.message || (language === "zh" ? "密码修改失败" : "Failed to change password")) } } catch (error: any) { console.error("Failed to change password:", error) alert(error?.message || (language === "zh" ? "密码修改出错" : "Error changing password")) } finally { setChangePasswordLoading(false) } } // 新增:删除租户 const handleDeleteTenant = async (tenantId: string) => { const tenant = channelTenants.find(t => t.id === tenantId) if (!tenant) return if (!window.confirm(language === "zh" ? `确定删除租户 ${tenant.name}?` : `Delete tenant ${tenant.name}?`)) return try { // 超级管理员删除租户时需要提供 channel_id const result = await TaijiAPIClient.deleteTenant(tenantId, selectedChannel?.id) if (result.success) { setChannelTenants(channelTenants.filter(t => t.id !== tenantId)) console.log('Tenant deleted successfully') } else { console.error('Failed to delete tenant:', result.message || 'Unknown error') } } catch (error) { console.error("Failed to delete tenant:", error) } } // 新增:禁用租户 const handleDisableTenant = async (tenantId: string) => { try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/tenants/${tenantId}/status`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ status: 'suspended' }) }) if (response.ok) { const data = await response.json() if (data.success) { setChannelTenants(channelTenants.map(t => t.id === tenantId ? { ...t, status: "disabled" } : t )) console.log('Tenant disabled successfully') } } else { console.error('Failed to disable tenant:', response.statusText) } } catch (error) { console.error("Failed to disable tenant:", error) } } // 新增:删除管理员 const handleRemoveAdmin = async (adminId: string) => { if (!selectedChannel) return try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/${selectedChannel.id}/admins/${adminId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() if (data.success) { // 从列表中移除该管理员 setChannelAdmins(channelAdmins.filter((admin: any) => admin.id !== adminId)) alert(language === "zh" ? "管理员已删除" : "Admin removed successfully") } else { alert(data.message || (language === "zh" ? "删除失败" : "Failed to remove")) } } else { console.error('Failed to remove admin:', response.statusText) alert(language === "zh" ? "删除失败" : "Failed to remove") } } catch (error) { console.error("Failed to remove admin:", error) alert(language === "zh" ? "删除出错" : "Error removing admin") } } // 新增:创建租户或管理员 // 根据系统权限选择不同的后端接口: // - tenant: 调用 /api/channel/tenants/create 创建租户 // - billing-admin/operations-admin: 调用 /api/admin/admins/create 创建管理员 const handleCreateTenant = async () => { if (!selectedChannel || !newTenantForm.name || !newTenantForm.email || !newTenantForm.password) { alert(language === "zh" ? "请填写所有必需字段" : "Please fill all required fields") return } try { console.log("Creating user with data:", { name: newTenantForm.name, email: newTenantForm.email, systemRole: newTenantForm.systemRole, channelId: selectedChannel.id, }) let result: any // 根据系统权限选择不同的接口 if (newTenantForm.systemRole === "tenant") { // 创建普通租户 - 调用 /api/channel/tenants/create result = await TaijiAPIClient.createChannelTenant({ name: newTenantForm.name, email: newTenantForm.email, password: newTenantForm.password, subscriptionTier: "free", // 租户默认使用 free 订阅等级 channelId: selectedChannel.id, // 超级管理员创建租户时必须提供channelId }) console.log("Create tenant result:", result) } else if (newTenantForm.systemRole === "billing-admin" || newTenantForm.systemRole === "operations-admin") { // 创建计费管理员或运营管理员 - 调用 /api/admin/admins/create // 角色映射:billing-admin -> billing_admin, operations-admin -> operations_admin const roleMap: Record = { "billing-admin": "billing_admin", "operations-admin": "operations_admin" } // 构建请求数据,包含 channelId const adminData = { name: newTenantForm.name, email: newTenantForm.email, password: newTenantForm.password, role: roleMap[newTenantForm.systemRole], channelId: selectedChannel.id, // 超级管理员创建管理员时必须提供channelId } console.log("Creating admin with data:", adminData) // 直接调用后端接口,因为 TaijiAPIClient.createAdmin 不支持 channelId 参数 const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/admins/create`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}`, }, body: JSON.stringify(adminData), }) result = await response.json() console.log("Create admin result:", result) } if (result?.success) { const successMsg = newTenantForm.systemRole === "tenant" ? (language === "zh" ? "租户创建成功" : "Tenant created successfully") : (language === "zh" ? "管理员创建成功" : "Admin created successfully") alert(successMsg) setNewTenantForm({ name: "", email: "", password: "", systemRole: "tenant" }) setIsAddTenantDialogOpen(false) // 重新加载租户列表 if (selectedChannel) { handleViewTenants(selectedChannel) } } else { // 显示更详细的错误信息 const errorMsg = result?.message || result?.detail || result?.error?.message || (language === "zh" ? "创建失败" : "Failed to create") alert(errorMsg) } } catch (error: any) { console.error("Failed to create tenant/admin:", error) // 显示更详细的错误信息 const errorMsg = error?.message || (language === "zh" ? "创建出错" : "Error creating") alert(language === "zh" ? `创建出错: ${errorMsg}` : `Error creating: ${errorMsg}`) } } // 新增:更新租户权限 const handleUpdateTenantPermissions = async () => { if (!selectedTenantForPermission) { alert(language === "zh" ? "请选择租户" : "Please select a tenant") return } try { const token = localStorage.getItem("admin_token") || localStorage.getItem("auth_token") const response = await fetch( `${API_BASE_URLS.mcpServer || "http://localhost:8002"}/api/channel/tenants/${selectedTenantForPermission.id}/permissions`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ permissions: tenantPermissions }), } ) if (response.ok) { const data = await response.json() if (data.success) { alert(language === "zh" ? "权限更新成功" : "Permissions updated successfully") setIsTenantPermissionDialogOpen(false) setTenantPermissions([]) // 更新租户列表中的权限信息 setChannelTenants( channelTenants.map((t) => t.id === selectedTenantForPermission.id ? { ...t, permissions: tenantPermissions } : t ) ) } } else { alert(language === "zh" ? "权限更新失败" : "Failed to update permissions") } } catch (error) { console.error("Failed to update permissions:", error) alert(language === "zh" ? "权限更新出错" : "Error updating permissions") } } const systemRoles = [ { id: "tenant", name: language === "zh" ? "租户" : "Tenant", description: language === "zh" ? "普通租户,基础功能访问" : "Regular tenant, basic feature access", }, { id: "billing-admin", name: language === "zh" ? "计费管理员" : "Billing Admin", description: language === "zh" ? "计费管理权限,处理账单和支付" : "Billing management, handle invoices and payments", }, { id: "operations-admin", name: language === "zh" ? "运营管理员" : "Operations Admin", description: language === "zh" ? "运营管理权限,监控和资源运维" : "Operations management, monitoring and resource ops", }, ] return (
{/* Header */}

{text.title}

{text.subtitle}

{/* Navigation tabs */}
{[ { id: "overview", label: text.overview, icon: BarChart3 }, { id: "channels", label: text.channels, icon: Building2 }, { id: "resources", label: text.resources, icon: Database }, { id: "monitoring", label: text.monitoring, icon: Activity }, { id: "billing", label: text.billing, icon: DollarSign }, { id: "settings", label: text.settings, icon: Settings }, ].map((tab) => ( ))}
{/* Main content */}
{activeTab === "overview" && ( <> {/* Stats grid - 删除活跃租户,保留3个统计卡片 */}
{stats.filter((stat, index) => index !== 2).map((stat, index) => (

{stat.title}

{stat.value}

{stat.change}
))}
{/* System Metrics - 保留系统指标 */}

{text.systemMetrics}

{systemMetrics.map((metric, index) => (
{metric.label} {typeof metric.value === "number" && metric.value < 200 ? `${metric.value}%` : metric.value}
))}
{/* Recent Logins - 最近登录的租户列表 */}

{language === "zh" ? "最近登录的租户" : "Recent Tenant Logins"}

{loading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : recentLogins.length === 0 ? (
{language === "zh" ? "暂无登录记录" : "No recent logins"}
) : ( recentLogins.map((tenant) => (

{tenant.tenantName || tenant.name}

{tenant.email} · {tenant.channelName || (language === "zh" ? "直属" : "Direct")}

{tenant.status === "active" ? (language === "zh" ? "活跃" : "Active") : (language === "zh" ? "离线" : "Offline")}
)) )}
{/* Platform Resource Allocation - 替换系统警告,只显示CPU和内存 */}

{language === "zh" ? "平台资源分配统计" : "Platform Resource Allocation"}

{/* CPU Allocation */}

{language === "zh" ? "已分配 CPU" : "Allocated CPU"}

{resourceAllocationStats.totalCpu.toFixed(1)} {language === "zh" ? "核" : "Cores"}

{language === "zh" ? `共 ${resourceAllocationStats.totalCount} 个 Agent` : `${resourceAllocationStats.totalCount} Agents`}
{/* Memory Allocation */}

{language === "zh" ? "已分配内存" : "Allocated Memory"}

{resourceAllocationStats.totalMemory.toFixed(1)} GB

{language === "zh" ? `平均 ${resourceAllocationStats.totalCount > 0 ? (resourceAllocationStats.totalMemory / resourceAllocationStats.totalCount).toFixed(1) : 0} GB/Agent` : `Avg ${resourceAllocationStats.totalCount > 0 ? (resourceAllocationStats.totalMemory / resourceAllocationStats.totalCount).toFixed(1) : 0} GB/Agent`}
{/* Agent 数量分类统计 */}
{language === "zh" ? "平台 Agent" : "Platform Agents"}: {resourceAllocationStats.platformCount} {language === "zh" ? "个" : ""}
{language === "zh" ? "自定义 Agent" : "Custom Agents"}: {resourceAllocationStats.customCount} {language === "zh" ? "个" : ""}
)} {activeTab === "channels" && (

{text.channelManagement}

{text.channelDescription}

{text.createChannel} {language === "zh" ? "创建新的分销渠道账户,渠道可以管理自己的租户组合" : "Create a new distribution channel account that can manage their own tenant portfolio"}
setNewChannelForm({ ...newChannelForm, name: e.target.value })} />
setNewChannelForm({ ...newChannelForm, email: e.target.value })} />
setNewChannelForm({ ...newChannelForm, password: e.target.value })} />
setNewChannelForm({ ...newChannelForm, commissionRate: e.target.value })} />
{loading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : channels.length === 0 ? (
{language === "zh" ? "暂无渠道" : "No channels available"}
) : ( channels.map((channel) => (

{channel.name}

{language === "zh" ? (channel.status === "active" ? "活跃" : "停用") : channel.status}

{text.contactPerson}: {channel.contact}

{channel.email}

{channel.tenantCount}

{text.tenantCount}

{channel.revenue}

{language === "zh" ? "月收入" : "Monthly"}

{channel.commission}%

{text.commission}

handleViewChannelDetails(channel)}> {text.viewDetails} handleEditChannel(channel)}> {text.edit} handleViewTenants(channel)}> {language === "zh" ? "查看租户" : "View Tenants"} handleEditCommission(channel)}> {language === "zh" ? "修改佣金" : "Edit Commission"} { if (!window.confirm( language === "zh" ? `确定要删除渠道 "${channel.name}" 吗?此操作不可撤销。` : `Are you sure you want to delete channel "${channel.name}"? This action cannot be undone.` )) { return } try { const token = localStorage.getItem('admin_token') || localStorage.getItem('auth_token') const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/${channel.id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() if (data.success) { alert(language === "zh" ? "渠道删除成功" : "Channel deleted successfully") await loadDashboardData() } else { alert(data.message || (language === "zh" ? "删除失败" : "Failed to delete")) } } else { const errorData = await response.json().catch(() => ({})) alert(errorData.message || (language === "zh" ? "删除失败" : "Failed to delete")) } } catch (error) { console.error("Failed to delete channel:", error) alert(language === "zh" ? "删除渠道出错" : "Error deleting channel") } }} > {language === "zh" ? "删除渠道" : "Delete Channel"} {/* handleConfigGoods(channel)}> // REMOVED */} {/* */} {/* {language === "zh" ? "货源配置" : "Goods Configuration"} */} {/* */} {/* handleAgentAllocation(channel)}> // REMOVED */} {/* */} {/* {language === "zh" ? "Agent分配" : "Agent Allocation"} */} {/* */} {/* CHANGED: Combine goods configuration and agent allocation into resource management */} handleResourceManagement(channel)}> {language === "zh" ? "资源管理" : "Resource Management"}
)) )}
{/* Commission Edit Dialog */} {language === "zh" ? "修改佣金比例" : "Edit Commission Rate"} {language === "zh" ? `为渠道 "${selectedChannel?.name}" 设置新的佣金比例` : `Set a new commission rate for channel "${selectedChannel?.name}"`}
setCommissionRate(e.target.value)} className="bg-background border-border" />

{language === "zh" ? "当前佣金比例: " + selectedChannel?.commission + "%" : "Current rate: " + selectedChannel?.commission + "%"}

{/* CHANGED: Combined Goods Configuration and Agent Allocation into a single Resource Management Dialog */} {/* // REMOVED */} {language === "zh" ? "资源管理" : "Resource Management"} {language === "zh" ? `为渠道 "${selectedChannel?.name}" 配置可用的模型、Agent和配额` : `Configure available models, agents and quota for channel "${selectedChannel?.name}"`}
{/* Models Selection */}
{availableModels.map((model) => (
{ if (e.target.checked) { setSelectedModels([...selectedModels, model.id]) } else { setSelectedModels(selectedModels.filter((m) => m !== model.id)) } }} className="w-4 h-4 rounded border-border" />
))}
{/* Agent Selection with Quantities */}

{language === "zh" ? "选择该渠道可以分配给租户的Agent并设置可用数量" : "Select agents that this channel can assign to tenants and set available quantities"}

{availableAgents.map((agent) => { // 使用 agent.id 或 agent.name 作为唯一标识符 // 后端返回的 Agent 模板数据中 name 是唯一的,id 可能为 undefined const agentKey = agent.id || agent.name const isSelected = selectedAgents.includes(agentKey) return (
{ if (isSelected) { setSelectedAgents(selectedAgents.filter((a) => a !== agentKey)) const newQuantities = { ...agentQuantities } delete newQuantities[agentKey] setAgentQuantities(newQuantities) } else { setSelectedAgents([...selectedAgents, agentKey]) setAgentQuantities({ ...agentQuantities, [agentKey]: 1 }) } }} >

{agent.name}

{agent.type}

{isSelected && (
{ const value = Math.max(1, Math.min(100, Number.parseInt(e.target.value) || 1)) setAgentQuantities({ ...agentQuantities, [agentKey]: value }) }} className="w-20 h-9" onClick={(e) => e.stopPropagation()} />
)} { e.stopPropagation() if (isSelected) { setSelectedAgents(selectedAgents.filter((a) => a !== agentKey)) const newQuantities = { ...agentQuantities } delete newQuantities[agentKey] setAgentQuantities(newQuantities) } else { setSelectedAgents([...selectedAgents, agentKey]) setAgentQuantities({ ...agentQuantities, [agentKey]: 1 }) } }} className="w-5 h-5 rounded border-border cursor-pointer" />
) })}

{language === "zh" ? "为该渠道的租户创建的自定义Agent配置默认CPU和内存资源" : "Configure default CPU and memory resources for custom agents created by this channel's tenants"}

setCustomAgentCpu(e.target.value)} className="bg-background border-border" />

{language === "zh" ? "推荐范围: 0.5-16核" : "Recommended: 0.5-16 cores"}

setCustomAgentMemory(e.target.value)} className="bg-background border-border" />

{language === "zh" ? "推荐范围: 0.5-64GB" : "Recommended: 0.5-64GB"}

{language === "zh" ? "此配置将应用于该渠道的租户创建的所有自定义Agent,不影响平台原生Agent。" : "This configuration will apply to all custom agents created by this channel's tenants, not affecting platform native agents."}

{/* REMOVED monthly quota field */}
setCreditLimit(e.target.value)} className="bg-background border-border" />

{language === "zh" ? "渠道可用授信上限 (USD)" : "Channel credit limit (USD)"}

{language === "zh" ? "资源配置摘要" : "Resource Configuration Summary"}

{language === "zh" ? "已选择模型" : "Models selected"}: {selectedModels.length}

{language === "zh" ? "已选择Agent" : "Agents selected"}: {selectedAgents.length}

{selectedAgents.length > 0 && (

{language === "zh" ? "总Agent数量: " : "Total agents: "} {Object.values(agentQuantities).reduce((sum, qty) => sum + qty, 0)}

)}

{language === "zh" ? "自定义Agent CPU: " : "Custom Agent CPU: "} {customAgentCpu} {language === "zh" ? "核" : "cores"}

{language === "zh" ? "自定义Agent 内存: " : "Custom Agent Memory: "} {customAgentMemory} GB

{/* REMOVED monthly quota from summary */}

{language === "zh" ? "渠道授信额度" : "Channel Credit Limit"}: ${creditLimit || "0"}

{/* Channel Details Dialog */} {language === "zh" ? "渠道详情" : "Channel Details"} {language === "zh" ? `查看渠道 "${selectedChannel?.name}" 的详细信息` : `View details for channel "${selectedChannel?.name}"`}
{/* Basic Information */}

{selectedChannel?.name}

{language === "zh" ? "活跃" : "Active"}

{selectedChannel?.email}

{selectedChannel?.createdAt || "-"}

{/* Quota Information */}

{language === "zh" ? "配额信息" : "Quota Information"}

{language === "zh" ? "租户总数" : "Total Tenants"} {selectedChannel?.tenantCount ?? 0}
{language === "zh" ? "授信额度" : "Credit Limit"} ${selectedChannel?.creditLimit ?? 0}
{language === "zh" ? "已用授信" : "Used Credit"} ${selectedChannel?.usedCredit ?? 0}
{language === "zh" ? "剩余授信" : "Remaining Credit"} ${selectedChannel?.remainingCredit ?? 0}
{/* Channel Resource Allocation Details */}

{language === "zh" ? "渠道资源分配详情" : "Channel Resource Allocation Details"}

{channelTenantsResourcesLoading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : channelAllocatedResources ? (
{/* Summary Statistics */} {channelAllocatedResources.summary && (

{channelAllocatedResources.summary.totalCustomAgentCpuQuota || 0}

{language === "zh" ? "自定义Agent CPU配额" : "Custom Agent CPU Quota"}

{channelAllocatedResources.summary.totalCustomAgentMemoryQuota || 0}GB

{language === "zh" ? "自定义Agent内存配额" : "Custom Agent Memory Quota"}

{channelAllocatedResources.summary.totalPlatformAgentPodUsed || 0}/{channelAllocatedResources.summary.totalPlatformAgentPodQuota || 0}

{language === "zh" ? "平台Agent Pod使用" : "Platform Agent Pods Used"}

{channelAllocatedResources.summary.totalModels || 0}

{language === "zh" ? "模型总数" : "Total Models"}

)} {/* Custom Agent Quota */} {channelAllocatedResources.customAgentQuota && (
{language === "zh" ? "自定义 Agent 配额" : "Custom Agent Quota"}

CPU {language === "zh" ? "配额" : "Quota"}

{channelAllocatedResources.customAgentQuota.cpuAllocatedToTenants || 0} / {channelAllocatedResources.customAgentQuota.cpuQuota || 0} {language === "zh" ? "核" : "cores"}

{language === "zh" ? "可用" : "Available"}: {channelAllocatedResources.customAgentQuota.cpuAvailable || 0} {language === "zh" ? "核" : "cores"}

{language === "zh" ? "内存配额" : "Memory Quota"}

{channelAllocatedResources.customAgentQuota.memoryAllocatedToTenants || 0} / {channelAllocatedResources.customAgentQuota.memoryQuota || 0} GB

{language === "zh" ? "可用" : "Available"}: {channelAllocatedResources.customAgentQuota.memoryAvailable || 0} GB

{channelAllocatedResources.customAgentQuota.cpuQuota > 0 ? Math.round((channelAllocatedResources.customAgentQuota.cpuAllocatedToTenants / channelAllocatedResources.customAgentQuota.cpuQuota) * 100) : 0}%

{language === "zh" ? "使用率" : "Usage"}

)} {/* Platform Agents */} {channelAllocatedResources.platformAgents && channelAllocatedResources.platformAgents.length > 0 && (
{language === "zh" ? "平台 Agent 配额" : "Platform Agent Quota"} {channelAllocatedResources.platformAgents.length}
{channelAllocatedResources.platformAgents.map((agent: any, idx: number) => (

{agent.templateDisplayName || agent.templateName}

{agent.cpuPerPod} CPU | {agent.memoryPerPod} {language === "zh" ? "内存" : "Memory"}

{agent.podUsed || 0} / {agent.podQuota || 0} Pods

{language === "zh" ? "已分配租户" : "Allocated to tenants"}: {agent.podAllocatedToTenants || 0}

))}
)} {/* Model Providers */} {channelAllocatedResources.modelProviders && channelAllocatedResources.modelProviders.length > 0 && (
{language === "zh" ? "模型供应商" : "Model Providers"} {channelAllocatedResources.modelProviders.length}
{channelAllocatedResources.modelProviders.map((provider: any, idx: number) => (

{provider.providerName}

{provider.status === "active" ? (language === "zh" ? "活跃" : "Active") : provider.status}
{provider.providerType}
{provider.models && provider.models.length > 0 && (
{provider.models.map((model: any, midx: number) => ( {model.modelName} ({model.rpmLimit} RPM) ))}
)}
))}
)} {/* Models */} {channelAllocatedResources.models && channelAllocatedResources.models.length > 0 && (
{language === "zh" ? "模型配额" : "Model Quota"} {channelAllocatedResources.models.length}
{channelAllocatedResources.models.map((model: any, idx: number) => ( ))}
{language === "zh" ? "模型" : "Model"} {language === "zh" ? "供应商" : "Provider"} RPM TPM {language === "zh" ? "已分配租户" : "Allocated"}
{model.modelName} {model.providerName || '-'} {model.rpmLimit?.toLocaleString() || '-'} {model.tpmLimit?.toLocaleString() || '-'} {model.allocatedToTenants || 0}
)} {/* No resources allocated */} {!channelAllocatedResources.customAgentQuota && (!channelAllocatedResources.platformAgents || channelAllocatedResources.platformAgents.length === 0) && (!channelAllocatedResources.models || channelAllocatedResources.models.length === 0) && (
{language === "zh" ? "暂无资源分配" : "No resources allocated"}
)}
) : (
{language === "zh" ? "暂无数据" : "No data available"}
)}
{/* Tenant Resource Allocation */}

{language === "zh" ? "租户资源分配" : "Tenant Resource Allocation"}

{channelTenantsResourcesLoading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : channelTenantsResources ? (
{/* Tenant Summary */} {channelTenantsResources.summary && (

{channelTenantsResources.summary.totalTenants || 0}

{language === "zh" ? "租户总数" : "Total Tenants"}

{channelTenantsResources.summary.tenantsWithCustomAgents || 0}

{language === "zh" ? "有自定义Agent" : "With Custom Agents"}

{channelTenantsResources.summary.tenantsWithPlatformAgents || 0}

{language === "zh" ? "有平台Agent" : "With Platform Agents"}

{channelTenantsResources.summary.tenantsWithModels || 0}

{language === "zh" ? "有模型配额" : "With Models"}

)} {/* Tenants List */} {channelTenantsResources.tenants && channelTenantsResources.tenants.length > 0 ? (
{channelTenantsResources.tenants.map((tenant: any) => (
{tenant.tenantName} {tenant.status === "active" ? (language === "zh" ? "活跃" : "Active") : (language === "zh" ? "已暂停" : "Suspended")}
{tenant.tenantEmail}
{/* Custom Agent Quota */} {tenant.customAgentQuota && (
● {language === "zh" ? "自定义Agent" : "Custom Agent"}: CPU {tenant.customAgentQuota.cpuUsed}/{tenant.customAgentQuota.cpuQuota} {language === "zh" ? "内存" : "Mem"} {tenant.customAgentQuota.memoryUsed}/{tenant.customAgentQuota.memoryQuota}GB
)} {/* Platform Agents */} {tenant.platformAgents && tenant.platformAgents.length > 0 && (
● {language === "zh" ? "平台Agent" : "Platform Agent"}: {tenant.platformAgents.map((agent: any, idx: number) => ( {agent.templateName} ({agent.podUsed}/{agent.podQuota}) ))}
)} {/* Models */} {tenant.models && tenant.models.length > 0 && (
● {language === "zh" ? "模型" : "Models"}: {tenant.models.map((model: any, idx: number) => ( {model.modelName} ))}
)} {/* No resources */} {!tenant.customAgentQuota && (!tenant.platformAgents || tenant.platformAgents.length === 0) && (!tenant.models || tenant.models.length === 0) && (
{language === "zh" ? "暂无资源分配" : "No resources allocated"}
)}
))}
) : (
{language === "zh" ? "暂无租户" : "No tenants"}
)}
) : (
{language === "zh" ? "暂无租户数据" : "No tenant data available"}
)}
{/* Channel Edit Dialog */} {language === "zh" ? "编辑渠道信息" : "Edit Channel"} {language === "zh" ? `修改渠道 "${selectedChannel?.name}" 的基本信息` : `Update basic information for channel "${selectedChannel?.name}"`}
{/* Basic Information Form */}
setChannelEditForm({ ...channelEditForm, name: e.target.value })} placeholder={language === "zh" ? "例: 阿里云渠道" : "e.g., Alibaba Cloud Partner"} className="bg-background border-border text-foreground" />
setChannelEditForm({ ...channelEditForm, contactName: e.target.value })} placeholder={language === "zh" ? "例: 张三" : "e.g., John Doe"} className="bg-background border-border text-foreground" />
setChannelEditForm({ ...channelEditForm, email: e.target.value })} placeholder={language === "zh" ? "例: contact@example.com" : "e.g., contact@example.com"} className="bg-background border-border text-foreground" />
setChannelEditForm({ ...channelEditForm, phone: e.target.value })} placeholder={language === "zh" ? "例: +86-10-XXXXXX" : "e.g., +1-555-0000"} className="bg-background border-border text-foreground" />
{/* Channel Admins Management */}

{language === "zh" ? "管理员管理" : "Administrator Management"}

{channelAdmins && channelAdmins.length > 0 ? ( channelAdmins.map((admin: any, index: number) => (

{admin.name}

{admin.email}

{language === "zh" ? admin.role === "billing" ? "计费管理员" : admin.role === "operations" ? "运营管理员" : "管理员" : admin.role === "billing" ? "Billing Admin" : admin.role === "operations" ? "Operations Admin" : "Administrator"}
)) ) : (

{language === "zh" ? "暂无管理员" : "No administrators"}

)}
{/* View Tenants Dialog */}
{language === "zh" ? "渠道租户管理" : "Channel Tenants"} {language === "zh" ? `查看和管理渠道 "${selectedChannel?.name}" 下的租户信息` : `View and manage tenants under channel "${selectedChannel?.name}"`}
{channelTenants && channelTenants.length > 0 ? (
{channelTenants.map((tenant: any) => (

{tenant.name}

{tenant.email}

{tenant.phone}

{tenant.permissions && tenant.permissions.length > 0 && (
{tenant.permissions.map((perm: string) => ( {perm} ))}
)}
{language === "zh" ? tenant.status === "active" ? "活跃" : "禁用" : tenant.status === "active" ? "Active" : "Disabled"}
{language === "zh" ? "创建时间" : "Created"}: {tenant.createdAt || "2024-01-15"}
{tenant.status === "active" && ( )}
))}
) : (

{language === "zh" ? "该渠道暂无租户" : "No tenants under this channel"}

)}
{/* Add Tenant Dialog */} {language === "zh" ? "添加新租户" : "Add New Tenant"} {language === "zh" ? "为渠道添加新的租户账户" : "Add a new tenant account to the channel"}
setNewTenantForm({ ...newTenantForm, name: e.target.value })} className="bg-background" />
setNewTenantForm({ ...newTenantForm, email: e.target.value })} className="bg-background" />
setNewTenantForm({ ...newTenantForm, password: e.target.value })} className="bg-background" />
{/* Change Password Dialog */} {language === "zh" ? "修改租户密码" : "Change Tenant Password"} {language === "zh" ? `为租户 "${selectedTenantForEdit?.name}" 设置新密码` : `Set a new password for tenant "${selectedTenantForEdit?.name}"`}
setNewPassword(e.target.value)} className="bg-background" />
setConfirmPassword(e.target.value)} className="bg-background" />
{newPassword && confirmPassword && newPassword !== confirmPassword && (

{language === "zh" ? "两次输入的密码不一致" : "Passwords do not match"}

)}

{language === "zh" ? "渠道申请审批" : "Channel Application Approvals"}

{loading ? ( ) : providerApprovals.length === 0 ? ( ) : ( providerApprovals.map((approval) => ( )) )}
{language === "zh" ? "渠道" : "Channel"} {language === "zh" ? "供应商" : "Provider"} {language === "zh" ? "期望模型" : "Models"} {language === "zh" ? "提交时间" : "Submitted"} {language === "zh" ? "状态" : "Status"} {language === "zh" ? "操作" : "Actions"}
{language === "zh" ? "加载中..." : "Loading..."}
{language === "zh" ? "暂无待审批申请" : "No pending applications"}
{approval.channelName} {approval.providerName} {approval.expectedModels} {approval.submittedAt} {language === "zh" ? approval.status === "pending" ? "待审批" : approval.status === "approved" ? "已批准" : "已拒绝" : approval.status === "pending" ? "Pending" : approval.status === "approved" ? "Approved" : "Rejected"} {approval.status === "pending" ? ( ) : ( {language === "zh" ? "已处理" : "Processed"} )}
{/* 平台Agent申请审批(新增) */}

{language === "zh" ? "平台Agent申请审批" : "Platform Agent Application Approvals"}

{loading ? ( ) : platformAgentApplications.length === 0 ? ( ) : ( platformAgentApplications.map((app) => ( )) )}
{language === "zh" ? "渠道" : "Channel"} {language === "zh" ? "模板名称" : "Template Name"} {language === "zh" ? "申请Pod配额" : "Requested Pod Quota"} {language === "zh" ? "申请理由" : "Reason"} {language === "zh" ? "提交时间" : "Submitted"} {language === "zh" ? "状态" : "Status"} {language === "zh" ? "操作" : "Actions"}
{language === "zh" ? "加载中..." : "Loading..."}
{language === "zh" ? "暂无待审批申请" : "No pending applications"}
{app.channelName || app.channelId} {app.templateDisplayName || app.templateName} {app.requestedPodQuota || 0} {app.reason || "-"} {app.createdAt} {language === "zh" ? app.status === "pending" ? "待审批" : app.status === "approved" ? "已批准" : "已拒绝" : app.status === "pending" ? "Pending" : app.status === "approved" ? "Approved" : "Rejected"} {app.status === "pending" && ( )}
{/* 平台Agent申请审批对话框(新增) */} {language === "zh" ? "审批平台Agent申请" : "Review Platform Agent Application"} {language === "zh" ? `审批渠道 "${selectedPlatformAgentApplication?.channelName || selectedPlatformAgentApplication?.channelId}" 的平台Agent申请` : `Review platform agent application from channel "${selectedPlatformAgentApplication?.channelName || selectedPlatformAgentApplication?.channelId}"`}

{selectedPlatformAgentApplication?.channelName || selectedPlatformAgentApplication?.channelId}

{selectedPlatformAgentApplication?.createdAt}

{selectedPlatformAgentApplication?.templateDisplayName || selectedPlatformAgentApplication?.templateName}

{selectedPlatformAgentApplication?.requestedPodQuota || 0}

{selectedPlatformAgentApplication?.reason || "-"}

setApprovedPodQuota(e.target.value)} className="bg-background border-border" />
setApprovalReason(e.target.value)} className="bg-background border-border" />
{/* 供应商申请审批对话框 */} {language === "zh" ? "审批供应商申请" : "Review Provider Application"} {language === "zh" ? `审批渠道 "${selectedApproval?.channelName}" 的供应商申请` : `Review provider application from channel "${selectedApproval?.channelName}"`}

{selectedApproval?.channelName}

{selectedApproval?.submittedAt}

{selectedApproval?.providerName}

{selectedApproval?.expectedModels}

{selectedApproval?.reason}

)} {activeTab === "resources" && (

{language === "zh" ? "平台Agent模板管理" : "Platform Agent Template Management"}

{language === "zh" ? "管理ACR模板的K8s资源配置(CPU/内存请求和限制)" : "Manage K8s resource configuration for ACR templates (CPU/Memory requests and limits)"}

{/* Agent Resource Cards */}
{resourcesLoading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : agentResources.length === 0 ? (
{language === "zh" ? "暂无Agent模板" : "No agent templates available"}
) : ( agentResources.map((agent) => ( { setSelectedAgent(agent) // 初始化配置表单数据 setAgentConfigForm({ cpuRequest: agent.cpuRequest || "100m", cpuLimit: agent.cpuLimit || "500m", memoryRequest: agent.memoryRequest || "128Mi", memoryLimit: agent.memoryLimit || "512Mi", maxInstances: agent.maxInstances || 10, }) setComputeConfigOpen(true) }} >

{agent.displayName || agent.name}

{agent.name}

{agent.description && (

{agent.description}

)}
{agent.status && ( {agent.status} )}
{/* CPU Request/Limit */}
CPU:
{agent.cpuRequest || agent.cpu || "100m"} / {agent.cpuLimit || "500m"}
{/* Memory Request/Limit */}
{language === "zh" ? "内存" : "Memory"}:
{agent.memoryRequest || agent.memory || "128Mi"} / {agent.memoryLimit || "512Mi"}
)) )}
{/* Agent Resource Configuration Dialog - K8s资源配置 */} {language === "zh" ? "Agent模板资源配置" : "Agent Template Resource Configuration"} {language === "zh" ? "配置K8s Pod的CPU和内存资源请求与限制" : "Configure K8s Pod CPU and memory resource requests and limits"}
{selectedAgent && ( <>

{selectedAgent.displayName || selectedAgent.name}

{selectedAgent.name}

{selectedAgent.description && (

{selectedAgent.description}

)} {selectedAgent.imageUrl && (

{selectedAgent.imageUrl}

)}
{/* CPU Request */}
setAgentConfigForm({ ...agentConfigForm, cpuRequest: e.target.value })} className="bg-background border-border text-foreground" />

{language === "zh" ? "Pod启动时保证的CPU资源" : "Guaranteed CPU for pod startup"}

setAgentConfigForm({ ...agentConfigForm, cpuLimit: e.target.value })} className="bg-background border-border text-foreground" />

{language === "zh" ? "Pod可使用的最大CPU资源" : "Maximum CPU the pod can use"}

{/* Memory Request/Limit */}
setAgentConfigForm({ ...agentConfigForm, memoryRequest: e.target.value })} className="bg-background border-border text-foreground" />

{language === "zh" ? "Pod启动时保证的内存资源" : "Guaranteed memory for pod startup"}

setAgentConfigForm({ ...agentConfigForm, memoryLimit: e.target.value })} className="bg-background border-border text-foreground" />

{language === "zh" ? "Pod可使用的最大内存资源" : "Maximum memory the pod can use"}

{/* Max Instances */}
setAgentConfigForm({ ...agentConfigForm, maxInstances: parseInt(e.target.value) || 10 })} min={1} max={100} className="bg-background border-border text-foreground" />

{language === "zh" ? "该模板可部署的最大Pod数量" : "Maximum number of pods for this template"}

{/* Info Box */}

{language === "zh" ? "K8s资源配置说明" : "K8s Resource Configuration"}

  • • {language === "zh" ? "CPU: 1 = 1核, 500m = 0.5核, 100m = 0.1核" : "CPU: 1 = 1 core, 500m = 0.5 core, 100m = 0.1 core"}
  • • {language === "zh" ? "内存: 1Gi = 1GB, 512Mi = 512MB, 128Mi = 128MB" : "Memory: 1Gi = 1GB, 512Mi = 512MB, 128Mi = 128MB"}
  • • {language === "zh" ? "Request: 保证资源,Limit: 最大资源" : "Request: guaranteed, Limit: maximum"}
)}

{language === "zh" ? "货源供应商管理" : "Goods Source Management"}

{language === "zh" ? "管理平台的模型供应商配置" : "Manage platform model provider configurations"}

{/* Model Providers Grid */}
{resourcesLoading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : modelProviders.length === 0 ? (
{language === "zh" ? "暂无模型供应商" : "No model providers available"}
) : ( modelProviders.map((provider) => (

{provider.name}

{provider.type}

{provider.status === "active" ? language === "zh" ? "活跃" : "Active" : language === "zh" ? "离线" : "Offline"}
{language === "zh" ? "支持模型" : "Models"} {(provider.supportedModels || provider.models || []).length}
RPM: {(provider.rpm || 0).toLocaleString()}
TPM: {(provider.tpm || 0).toLocaleString()}
)) )}
)} {activeTab === "monitoring" && (
{/* Agent health monitoring */}

{text.agentHealthMonitoring}

{text.agentHealthDesc}

{/* Agent总数统计卡片 */}

{language === "zh" ? "Agent总数" : "Total Agents"}

{agentSummary?.total ?? agents.length}

{language === "zh" ? "健康Agent" : "Healthy Agents"}

{agentSummary?.byHealthStatus?.healthy ?? agents.filter(a => a.healthStatus === "healthy" || a.status === "healthy" || a.status === "Running" || a.status === "available").length}

{language === "zh" ? "警告/异常" : "Warning/Critical"}

{(agentSummary?.byHealthStatus?.warning ?? 0) + (agentSummary?.byHealthStatus?.critical ?? 0) || agents.filter(a => a.healthStatus === "warning" || a.healthStatus === "critical" || a.status === "warning" || a.status === "critical").length}

{/* Agent health cards grid */}
{loading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : agents.length === 0 ? (
{language === "zh" ? "暂无Agent" : "No agents available"}
) : ( agents.map((agent) => { // 使用新的healthStatus字段,兼容旧的status字段 // 后端可能返回: healthy, Running, available, warning, critical const healthStatus = agent.healthStatus || agent.status const isHealthy = healthStatus === "healthy" || healthStatus === "Running" || healthStatus === "available" const isWarning = healthStatus === "warning" const statusColor = isHealthy ? "text-green-500 bg-green-500/10" : isWarning ? "text-yellow-500 bg-yellow-500/10" : "text-red-500 bg-red-500/10" const statusText = isHealthy ? text.healthy : isWarning ? text.warning : text.critical return ( {/* Agent header */}

{agent.name}

{agent.type === "platform" ? (language === "zh" ? "平台Agent" : "Platform Agent") : (language === "zh" ? "自定义Agent" : "Custom Agent")} {agent.healthMessage && ` · ${agent.healthMessage}`}

{statusText}
{/* Agent metrics */}
{/* CPU Usage - 使用 cpuUtilization 百分比值控制进度条,显示 cpuUsage 实际使用量 */}
{text.cpuUsageLabel} {agent.cpuUsage || "0m"} / {agent.cpuLimit || "500m"}
80 ? "bg-red-500" : (agent.cpuUtilization ?? 0) > 60 ? "bg-yellow-500" : "bg-green-500" }`} style={{ width: `${Math.min(agent.cpuUtilization ?? 0, 100)}%` }} />
{(agent.cpuUtilization ?? 0).toFixed(1)}%
{/* Memory Usage - 使用 memoryUtilization 百分比值控制进度条,显示 memoryUsage 实际使用量 */}
{text.memoryUsageLabel} {agent.memoryUsage || "0Mi"} / {agent.memoryLimit || "512Mi"}
80 ? "bg-red-500" : (agent.memoryUtilization ?? 0) > 60 ? "bg-yellow-500" : "bg-green-500" }`} style={{ width: `${Math.min(agent.memoryUtilization ?? 0, 100)}%` }} />
{(agent.memoryUtilization ?? 0).toFixed(1)}%
{/* Stats grid */}

{language === "zh" ? "CPU上限" : "CPU Limit"}

{agent.cpuLimit || "500m"}

{language === "zh" ? "内存上限" : "Memory Limit"}

{agent.memoryLimit || "512Mi"}

{language === "zh" ? "运行状态" : "Status"}

{agent.status || agent.k8sStatus || "-"}

{language === "zh" ? "数据来源" : "Source"}

{agent.source === "k8s" ? "K8s" : (agent.source === "database" ? "DB" : "-")}

) }) )}
)} {activeTab === "billing" && (

{t("计费管理", "Billing Management")}

{/* 计费维度切换 */}
{/* 渠道维度计费 */} {billingView === "channel" && (
{billingLoading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : ( <>
{t("渠道总数", "Total Channels")}
{billingData?.channelStats?.length || 0}
{t("总计费额", "Total Billing")}
${billingData?.channelStats?.reduce((sum: number, stat: any) => sum + (stat.totalCost || 0), 0).toFixed(2) || "0.00"}
{t("总EU消耗", "Total EU Consumption")}
{billingData?.channelStats?.reduce((sum: number, stat: any) => sum + (stat.totalEU || 0), 0).toLocaleString() || 0} EU

{t("渠道计费详情", "Channel Billing Details")}

{billingData?.channelStats?.length === 0 ? ( ) : ( billingData?.channelStats?.map((stat: any, idx: number) => ( )) )}
{t("渠道名称", "Channel Name")} {t("调用次数", "Call Count")} {t("总EU", "Total EU")} {t("渠道总价", "Channel Total")}
{language === "zh" ? "暂无数据" : "No data available"}
{stat.channelName || stat.channelId} {stat.calls?.toLocaleString() || 0} {stat.totalEU?.toLocaleString() || 0} EU ${stat.totalCost?.toFixed(2) || "0.00"}
)}
)} {/* 租户维度计费 */} {billingView === "tenant" && (
{billingLoading ? (
{language === "zh" ? "加载中..." : "Loading..."}
) : ( <>
{t("租户总数", "Total Tenants")}
{billingData?.tenantStats?.length || 0}
{t("用户总价", "User Total")}
${billingData?.tenantStats?.reduce((sum: number, stat: any) => sum + (stat.totalCost || 0), 0).toFixed(2) || "0.00"}
{t("平均消费", "Average Spending")}
${billingData?.tenantStats?.length > 0 ? (billingData.tenantStats.reduce((sum: number, stat: any) => sum + (stat.totalCost || 0), 0) / billingData.tenantStats.length).toFixed(2) : "0.00"}

{t("租户计费详情", "Tenant Billing Details")}

{billingData?.tenantStats?.length === 0 ? ( ) : ( billingData?.tenantStats?.map((stat: any, idx: number) => ( )) )}
{t("租户名称", "Tenant Name")} {t("所属渠道", "Channel")} {t("调用次数", "Call Count")} {t("总EU", "Total EU")} {t("用户总价", "User Total")}
{language === "zh" ? "暂无数据" : "No data available"}
{stat.tenantName || stat.tenantId} {stat.channelName || stat.channelId} {stat.calls?.toLocaleString() || 0} {stat.totalEU?.toLocaleString() || 0} EU ${stat.totalCost?.toFixed(2) || "0.00"}
)}
)} {/* 调用记录 */} {billingView === "calls" && (

{t("调用记录明细", "Call Records Detail")}

{t("EU计算规则:1 EU = 10秒调用时间", "EU Calculation: 1 EU = 10 seconds call time")}
{[ { id: "CALL-2024-001", tenant: "Tech Corp", channel: "Partner A", time: "2024-01-15 14:23:45", duration: 45, eu: 4.5, cost: "$0.45", }, { id: "CALL-2024-002", tenant: "AI Solutions", channel: "Partner A", time: "2024-01-15 14:24:12", duration: 30, eu: 3.0, cost: "$0.30", }, { id: "CALL-2024-003", tenant: "Data Inc", channel: "Partner B", time: "2024-01-15 14:25:03", duration: 120, eu: 12.0, cost: "$1.20", }, { id: "CALL-2024-004", tenant: "Cloud Systems", channel: "Partner C", time: "2024-01-15 14:26:31", duration: 65, eu: 6.5, cost: "$0.65", }, { id: "CALL-2024-005", tenant: "Tech Corp", channel: "Partner A", time: "2024-01-15 14:27:15", duration: 90, eu: 9.0, cost: "$0.90", }, ].map((call, idx) => ( ))}
{t("调用ID", "Call ID")} {t("租户", "Tenant")} {t("渠道", "Channel")} {t("调用时间", "Call Time")} {t("时长(秒)", "Duration(s)")} {t("EU", "EU")} {t("单次调用总价", "Single Call Cost")} {t("时间戳", "Timestamp")}
{call.id} {call.tenant} {call.channel} {call.time} {call.duration}s {call.eu} EU {call.cost} {call.time}
)} {t("筛选选项", "Filter Options")}
{t("时间范围", "Date & Time Range")}
{t("导出格式", "Export Format")}

{t("选择导出文件格式", "Select export file format")}

)} {activeTab === "settings" && (
{/* 管理员列表管理 */} {/* 用户身份权限设置 */}

{t("角色权限配置", "Role Permission Configuration")}

{t("配置不同角色的标签页访问权限", "Configure tab access permissions for different roles")}

{/* Billing Admin Role Card */} setSelectedRole("billing-admin")} >

{t("计费管理员", "Billing Administrator")}

{t( "负责平台计费、账单和财务管理", "Responsible for billing, invoices, and financial management", )}

{rolePermissions["billing-admin"].length} {t("个权限", "permissions")}
{/* Operations Admin Role Card */} setSelectedRole("operations-admin")} >

{t("运营管理员", "Operations Administrator")}

{t("负责渠道、资源和系统监控管理", "Responsible for channels, resources, and monitoring")}

{rolePermissions["operations-admin"].length} {t("个权限", "permissions")}
{/* Super Admin Role Card */} setSelectedRole("super-admin")} >

{t("超级管理员", "Super Administrator")}

{t("拥有所有权限,管理整个平台", "Full access to all platform features")}

{rolePermissions["super-admin"].length} {t("个权限", "permissions")}
{selectedRole && (

{t("标签页访问权限", "Tab Access Permissions")}

{t("选择该角色可以访问的标签页", "Select which tabs this role can access")}

{[ { id: "overview", label: t("概览", "Overview"), icon: "📊" }, { id: "channels", label: t("渠道管理", "Channel Management"), icon: "🏢" }, { id: "resources", label: t("资源管理", "Resource Management"), icon: "⚙️" }, { id: "monitoring", label: t("监控", "Monitoring"), icon: "📈" }, { id: "billing", label: t("计费", "Billing"), icon: "💰" }, { id: "provider-backend", label: t("供应商管理中心后台", "Provider Backend"), icon: "🔧" }, { id: "channel-backend", label: t("渠道管理中心后台", "Channel Backend"), icon: "🏪" }, { id: "settings", label: t("设置", "Settings"), icon: "⚙️" }, ].map((tab) => { const hasPermission = rolePermissions[selectedRole]?.includes(tab.id) return (
{ setRolePermissions((prev) => ({ ...prev, [selectedRole]: hasPermission ? prev[selectedRole].filter((p) => p !== tab.id) : [...prev[selectedRole], tab.id], })) }} >
{tab.icon} {hasPermission && }

{tab.label}

) })}
)}
)}
{/* System role assignment dialog */} {text.assignSubscriptionLevel}

{language === "zh" ? "为租户选择系统权限:" : "Select a system role for the tenant:"}

{systemRoles.map((role) => (
setSelectedSubscriptionLevel(role.id)} className={`p-4 rounded-lg border-2 cursor-pointer transition-colors ${ selectedSubscriptionLevel === role.id ? "border-primary bg-primary/5" : "border-border hover:border-primary/50" }`} >

{role.name}

{role.description}

{selectedSubscriptionLevel === role.id &&
}
))}
{/* Dialogs for Add/Config Provider */} {language === "zh" ? providerType === "model" ? "添加模型供应商" : "添加数据供应商" : providerType === "model" ? "Add Model Provider" : "Add Data Provider"} {language === "zh" ? "填写供应商信息以添加新的货源" : "Fill in provider information to add a new source"}
setProviderForm({ ...providerForm, name: e.target.value })} className="bg-background border-border text-foreground" />
setProviderForm({ ...providerForm, url: e.target.value })} className="bg-background border-border text-foreground" />
{providerType === "model" && ( <>
{litellmModelsLoading ? (
{language === "zh" ? "加载模型列表中..." : "Loading models..."}
) : (
{litellmModels.length === 0 ? (
{language === "zh" ? "暂无可用模型" : "No models available"}
) : (
{litellmModels.map((model) => (
{ if (e.target.checked) { setProviderForm({ ...providerForm, models: [...providerForm.models, model] }) } else { setProviderForm({ ...providerForm, models: providerForm.models.filter((m: string) => m !== model) }) } }} className="w-4 h-4 rounded border-border" />
))}
)}
)}

{language === "zh" ? `已选择 ${providerForm.models.length} 个模型` : `${providerForm.models.length} model(s) selected`}

setProviderForm({ ...providerForm, rpm: e.target.value })} className="bg-background border-border text-foreground" />
setProviderForm({ ...providerForm, tpm: e.target.value })} className="bg-background border-border text-foreground" />
)}
{language === "zh" ? "配置供应商" : "Configure Provider"} {language === "zh" ? `修改 "${selectedProvider?.name}" 的配置信息` : `Modify configuration for "${selectedProvider?.name}"`}
setProviderForm({ ...providerForm, name: e.target.value })} className="bg-background border-border text-foreground" />
setProviderForm({ ...providerForm, url: e.target.value })} className="bg-background border-border text-foreground" />
{providerType === "model" && ( <>
{litellmModelsLoading ? (
{language === "zh" ? "加载模型列表中..." : "Loading models..."}
) : (
{litellmModels.length === 0 ? (
{language === "zh" ? "暂无可用模型" : "No models available"}
) : (
{litellmModels.map((model) => (
{ if (e.target.checked) { setProviderForm({ ...providerForm, models: [...providerForm.models, model] }) } else { setProviderForm({ ...providerForm, models: providerForm.models.filter((m: string) => m !== model) }) } }} className="w-4 h-4 rounded border-border" />
))}
)}
)}

{language === "zh" ? `已选择 ${providerForm.models.length} 个模型` : `${providerForm.models.length} model(s) selected`}

setProviderForm({ ...providerForm, rpm: e.target.value })} className="bg-background border-border text-foreground" />
setProviderForm({ ...providerForm, tpm: e.target.value })} className="bg-background border-border text-foreground" />
)}
{/* Dialog for Add New Admin */} {t("添加新管理员", "Add New Administrator")} {t("创建新的管理员账户并分配角色", "Create a new administrator account and assign a role")}
setNewAdminForm({ ...newAdminForm, name: e.target.value })} className="bg-background border-border text-foreground" />
setNewAdminForm({ ...newAdminForm, email: e.target.value })} className="bg-background border-border text-foreground" />
setNewAdminForm({ ...newAdminForm, password: e.target.value })} className="bg-background border-border text-foreground" />

{newAdminForm.role === "billing-admin" && t("负责平台计费、账单和财务管理", "Responsible for billing, invoices, and financial management")} {newAdminForm.role === "operations-admin" && t("负责渠道、资源和系统监控管理", "Responsible for channels, resources, and monitoring")} {newAdminForm.role === "super-admin" && t("拥有所有权限,管理整个平台", "Full access to all platform features")}

) }