import { useMemo, useState, type FormEvent, type ReactNode } from 'react'; import { Copy, CreditCard, KeyRound, ListChecks, Plus, ShieldCheck, Trash2, UserRound } from 'lucide-react'; import type { GatewayAccessRuleBatchRequest, GatewayApiKey, IntegrationPlatform, PlatformModel } from '@easyai-ai-gateway/contracts'; import type { ConsoleData } from '../app-state'; import { EntityTable } from '../components/EntityTable'; import { Badge, Button, Card, CardContent, CardHeader, CardTitle, ConfirmDialog, DateTimePicker, FormDialog, Input, Label, Table, TableCell, TableHead, TableRow, Tabs } from '../components/ui'; import { AccessPermissionEditor, countAccessPermissionRules } from './admin/AccessPermissionEditor'; import type { ApiKeyForm, LoadState, WorkspaceSection } from '../types'; const tabs = [ { value: 'overview', label: '个人总览', icon: }, { value: 'billing', label: '余额充值', icon: }, { value: 'apiKeys', label: 'API Key', icon: }, { value: 'tasks', label: '任务记录', icon: }, ] satisfies Array<{ value: WorkspaceSection; label: string; icon: ReactNode }>; export function WorkspacePage(props: { apiKeyForm: ApiKeyForm; apiKeySecret: string; apiKeySecretsById: Record; apiKeyPolicyModels: PlatformModel[]; data: ConsoleData; message: string; section: WorkspaceSection; state: LoadState; onBatchAccessRules: (input: GatewayAccessRuleBatchRequest) => Promise; onDeleteApiKey: (apiKeyId: string) => Promise; onApiKeyFormChange: (value: ApiKeyForm) => void; onSectionChange: (value: WorkspaceSection) => void; onSubmitApiKey: (event: FormEvent) => void | Promise; onUseApiKeyForPlayground: (apiKeyId?: string) => void; }) { return ( {props.section === 'overview' && } {props.section === 'billing' && } {props.section === 'apiKeys' && } {props.section === 'tasks' && } ); } function WorkspaceOverview(props: { data: ConsoleData }) { const owner = props.data.users[0]; return ( 个人中心总览 用户组策略 [item.groupKey, item.priority, item.status, item.source])} /> ); } function BillingPanel() { return ( 余额 resource 0.00 local 充值 金额 创建充值订单 ); } function ApiKeyPanel(props: { apiKeyForm: ApiKeyForm; apiKeySecret: string; apiKeySecretsById: Record; apiKeyPolicyModels: PlatformModel[]; data: ConsoleData; message: string; state: LoadState; onBatchAccessRules: (input: GatewayAccessRuleBatchRequest) => Promise; onDeleteApiKey: (apiKeyId: string) => Promise; onApiKeyFormChange: (value: ApiKeyForm) => void; onSubmitApiKey: (event: FormEvent) => void | Promise; onUseApiKeyForPlayground: (apiKeyId?: string) => void; }) { const [createOpen, setCreateOpen] = useState(false); const [policyApiKeyId, setPolicyApiKeyId] = useState(''); const [pendingDelete, setPendingDelete] = useState(null); const [localMessage, setLocalMessage] = useState(''); const selectedPolicyKey = useMemo( () => props.data.apiKeys.find((item) => item.id === policyApiKeyId), [policyApiKeyId, props.data.apiKeys], ); const permissionPlatforms = useMemo(() => platformsForPermissionTree(props.apiKeyPolicyModels), [props.apiKeyPolicyModels]); async function copyApiKey(item: GatewayApiKey) { const secret = apiKeySecretFor(item, props.apiKeySecretsById); if (!secret) return; await navigator.clipboard.writeText(secret); setLocalMessage(`已复制 ${item.name || item.keyPrefix}`); } async function submitCreate(event: FormEvent) { try { await props.onSubmitApiKey(event); setCreateOpen(false); } catch { return; } } async function confirmDeleteApiKey() { if (!pendingDelete) return; await props.onDeleteApiKey(pendingDelete.id); setPendingDelete(null); } return ( <> API Key 按 Key 维护调用凭证、最近使用时间和平台/模型权限策略。 setCreateOpen(true)}> 创建 API Key {(localMessage || props.message) && {localMessage || props.message}} 名称 API Key 权限策略 最近使用 有效期 状态 创建时间 操作 {props.data.apiKeys.length ? props.data.apiKeys.map((item) => { const secret = apiKeySecretFor(item, props.apiKeySecretsById); const summary = countAccessPermissionRules(props.data.accessRules, 'api_key', item.id); return ( {item.name} {item.keyPrefix} {secret ? maskApiKey(secret) : item.keyPrefix} void copyApiKey(item)} > setPolicyApiKeyId(item.id)}> {permissionSummaryText(summary)} {formatDateTime(item.lastUsedAt)} {formatDateTime(item.expiresAt)} {item.status} {formatDateTime(item.createdAt)} setPendingDelete(item)}> ); }) : ( 暂无 API Key 点击右上角创建调用凭证。 )} setCreateOpen(false)}>取消 确认创建 > )} open={createOpen} title="创建 API Key" onClose={() => setCreateOpen(false)} onSubmit={(event) => void submitCreate(event)} > 名称 props.onApiKeyFormChange({ ...props.apiKeyForm, name: event.target.value })} /> 有效期 props.onApiKeyFormChange({ ...props.apiKeyForm, expiresAt })} /> setPolicyApiKeyId('')}>关闭} open={Boolean(selectedPolicyKey)} title={selectedPolicyKey ? `权限策略:${selectedPolicyKey.name}` : '权限策略'} onClose={() => setPolicyApiKeyId('')} onSubmit={(event) => event.preventDefault()} > setPendingDelete(null)} onConfirm={confirmDeleteApiKey} /> > ); } function TaskPanel(props: { data: ConsoleData }) { const task = props.data.taskResult; const usage = task?.usage ?? {}; const tokenText = usage.totalTokens ? `${usage.totalTokens}` : '-'; const chargeText = task?.finalChargeAmount ? `${task.finalChargeAmount}` : '-'; return ( 任务记录 {task ? ( {task.status} {task.kind} {task.model} {JSON.stringify({ result: task.result, usage: task.usage, billings: task.billings, billingSummary: task.billingSummary, metrics: task.metrics }, null, 2)} ) : ( 暂无任务 )} ); } function InfoItem(props: { label: string; value: string }) { return ( {props.label} {props.value} ); } function apiKeySecretFor(item: GatewayApiKey, secretsById: Record) { return secretsById[item.id] || item.secret || ''; } function maskApiKey(secret: string) { if (secret.length <= 18) return secret; return `${secret.slice(0, 12)}...${secret.slice(-4)}`; } function permissionSummaryText(summary: ReturnType) { const allow = summary.allow.platforms + summary.allow.models; const deny = summary.deny.platforms + summary.deny.models; if (allow === 0 && deny === 0) return '未配置'; return `允许 ${allow} / 拒绝 ${deny}`; } function formatDateTime(value?: string) { if (!value) return '-'; const date = new Date(value); if (Number.isNaN(date.getTime())) return '-'; return date.toLocaleString(); } function platformsForPermissionTree(models: PlatformModel[]): IntegrationPlatform[] { const byPlatform = new Map(); for (const model of models) { if (byPlatform.has(model.platformId)) continue; const name = model.platformName || model.provider || model.platformId; byPlatform.set(model.platformId, { id: model.platformId, provider: model.provider || '', platformKey: model.platformId, name, authType: '', status: 'enabled', priority: 100, defaultPricingMode: 'inherit', defaultDiscountFactor: 1, createdAt: '', updatedAt: '', }); } return Array.from(byPlatform.values()).sort((a, b) => a.name.localeCompare(b.name)); }
按 Key 维护调用凭证、最近使用时间和平台/模型权限策略。
{localMessage || props.message}
{secret ? maskApiKey(secret) : item.keyPrefix}
{JSON.stringify({ result: task.result, usage: task.usage, billings: task.billings, billingSummary: task.billingSummary, metrics: task.metrics }, null, 2)}