import type { ReactNode } from 'react'; import { Boxes, Building2, Gauge, History, KeyRound, Route, ServerCog, ShieldCheck, UsersRound, Workflow } from 'lucide-react'; import type { BaseModelUpsertRequest, CatalogProviderUpsertRequest, GatewayAccessRuleBatchRequest, GatewayAccessRuleUpsertRequest, GatewayTenantUpsertRequest, GatewayUserUpsertRequest, PricingRuleSetUpsertRequest, RuntimePolicySetUpsertRequest, UserGroupUpsertRequest, WalletBalanceAdjustmentRequest, } from '@easyai-ai-gateway/contracts'; import type { ConsoleData, StatItem } from '../app-state'; import { EntityTable } from '../components/EntityTable'; import { StatGrid } from '../components/StatGrid'; import { Badge, Card, CardContent, CardHeader, CardTitle, Tabs } from '../components/ui'; import type { AdminSection, LoadState, PlatformWithModelsInput } from '../types'; import { AccessRulesPanel } from './admin/AccessRulesPanel'; import { AuditLogsPanel } from './admin/AuditLogsPanel'; import { BaseModelCatalogPanel } from './admin/BaseModelCatalogPanel'; import { TenantsPanel, UserGroupsPanel, UsersPanel } from './admin/IdentityManagementPanels'; import { PlatformManagementPanel } from './admin/PlatformManagementPanel'; import { PricingRulesPanel } from './admin/PricingRulesPanel'; import { ProviderManagementPanel } from './admin/ProviderManagementPanel'; import { RuntimePoliciesPanel } from './admin/RuntimePoliciesPanel'; const tabs = [ { value: 'overview', label: '总览', icon: }, { value: 'globalModels', label: 'Provider', icon: }, { value: 'pricing', label: '定价规则', icon: }, { value: 'runtime', label: '运行策略', icon: }, { value: 'baseModels', label: '基准模型库', icon: }, { value: 'platforms', label: '平台管理', icon: }, { value: 'tenants', label: '租户', icon: }, { value: 'users', label: '用户', icon: }, { value: 'userGroups', label: '用户组', icon: }, { value: 'accessRules', label: '模型权限', icon: }, { value: 'auditLogs', label: '审计日志', icon: }, ] satisfies Array<{ value: AdminSection; label: string; icon: ReactNode }>; export function AdminPage(props: { data: ConsoleData; operationMessage: string; section: AdminSection; stats: StatItem[]; state: LoadState; onDeleteBaseModel: (baseModelId: string) => Promise; onDeletePlatform: (platformId: string) => Promise; onDeleteProvider: (providerId: string) => Promise; onDeletePricingRuleSet: (ruleSetId: string) => Promise; onDeleteRuntimePolicySet: (policySetId: string) => Promise; onDeleteAccessRule: (ruleId: string) => Promise; onDeleteTenant: (tenantId: string) => Promise; onDeleteUser: (userId: string) => Promise; onDeleteUserGroup: (groupId: string) => Promise; onSaveBaseModel: (input: BaseModelUpsertRequest, baseModelId?: string) => Promise; onResetAllBaseModels: () => Promise; onResetBaseModel: (baseModelId: string) => Promise; onBatchAccessRules: (input: GatewayAccessRuleBatchRequest) => Promise; onSavePlatform: (input: PlatformWithModelsInput) => Promise; onSaveProvider: (input: CatalogProviderUpsertRequest, providerId?: string) => Promise; onSavePricingRuleSet: (input: PricingRuleSetUpsertRequest, ruleSetId?: string) => Promise; onSaveRuntimePolicySet: (input: RuntimePolicySetUpsertRequest, policySetId?: string) => Promise; onSaveAccessRule: (input: GatewayAccessRuleUpsertRequest, ruleId?: string) => Promise; onSaveTenant: (input: GatewayTenantUpsertRequest, tenantId?: string) => Promise; onSaveUser: (input: GatewayUserUpsertRequest, userId?: string) => Promise; onSetUserWalletBalance: (userId: string, input: WalletBalanceAdjustmentRequest) => Promise; onSaveUserGroup: (input: UserGroupUpsertRequest, groupId?: string) => Promise; onSectionChange: (value: AdminSection) => void; }) { return ( {props.section === 'overview' && } {props.section === 'globalModels' && ( )} {props.section === 'baseModels' && ( )} {props.section === 'runtime' && ( )} {props.section === 'accessRules' && ( )} {props.section === 'pricing' && ( )} {props.section === 'platforms' && ( )} {props.section === 'tenants' && } {props.section === 'users' && } {props.section === 'userGroups' && } {props.section === 'auditLogs' && } ); } function identityPanelProps(props: { data: ConsoleData; operationMessage: string; state: LoadState; onDeleteTenant: (tenantId: string) => Promise; onDeleteUser: (userId: string) => Promise; onDeleteUserGroup: (groupId: string) => Promise; onSaveTenant: (input: GatewayTenantUpsertRequest, tenantId?: string) => Promise; onSaveUser: (input: GatewayUserUpsertRequest, userId?: string) => Promise; onSetUserWalletBalance: (userId: string, input: WalletBalanceAdjustmentRequest) => Promise; onSaveUserGroup: (input: UserGroupUpsertRequest, groupId?: string) => Promise; }) { return { data: props.data, operationMessage: props.operationMessage, state: props.state, onDeleteTenant: props.onDeleteTenant, onDeleteUser: props.onDeleteUser, onDeleteUserGroup: props.onDeleteUserGroup, onSaveTenant: props.onSaveTenant, onSaveUser: props.onSaveUser, onSetUserWalletBalance: props.onSetUserWalletBalance, onSaveUserGroup: props.onSaveUserGroup, }; } function OverviewPanel(props: { data: ConsoleData; stats: StatItem[] }) { const enabledPlatforms = props.data.platforms.filter((item) => item.status === 'enabled'); const chatModels = props.data.models.filter((item) => item.modelType.includes('text_generate') && item.enabled); const imageModels = props.data.models.filter((item) => item.modelType.some((type) => type.includes('image')) && item.enabled); return ( } label="路由候选" value={enabledPlatforms.length} detail="平台优先级 / 失败切换" /> } label="策略对象" value={props.data.userGroups.length} detail="用户组 / 折扣 / 并发" /> } label="运行窗口" value={props.data.rateLimitWindows.length} detail="TPM / RPM / 并发" /> 可用平台 [item.provider, item.internalName || item.name, item.status, item.priority])} /> 近期任务 {props.data.taskResult ? ( {props.data.taskResult.status} {props.data.taskResult.model} {JSON.stringify(props.data.taskResult.result ?? {}, null, 2)} ) : ( 暂无任务记录 )} 模型能力 item.modelType.some((type) => type.includes('video'))).length, 'Next', '/v1/videos/*'], ]} /> 限流窗口 [item.scopeKey, item.metric, item.usedValue, item.limitValue])} /> ); } function ManagementCard(props: { detail: string; icon: ReactNode; label: string; value: number }) { return ( {props.icon} {props.label} {props.value} {props.detail} ); }
{JSON.stringify(props.data.taskResult.result ?? {}, null, 2)}