mirror of
https://github.com/Fasthei/taiji-pda-v0.git
synced 2026-09-26 21:21:55 +00:00
feat: 服务网关页面添加折叠功能展示Agent接口
- 为MCP、A2A、API三种网关类型添加折叠/展开按钮 - 移除固定的网关端点,每个Agent使用独立URL - 展开后显示Agent接口列表(等待后端接口对接) - 移除原有的"查看接口"弹窗
This commit is contained in:
+142
-134
@@ -5,7 +5,7 @@ import { DashboardLayout } from "@/components/dashboard-layout"
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { GitBranch, Activity, Code2, Boxes, Workflow, Plus, Upload } from "lucide-react"
|
||||
import { GitBranch, Activity, Code2, Boxes, Workflow, Plus, Upload, ChevronDown, ChevronRight, Copy, ExternalLink } from "lucide-react"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
import { useLanguage } from "@/hooks/useLanguage"
|
||||
import { TaijiAPIClient } from "@/lib/api-client"
|
||||
@@ -24,6 +24,7 @@ import { Label } from "@/components/ui/label"
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
|
||||
|
||||
export default function ModelGatewayPage() {
|
||||
const { t } = useLanguage()
|
||||
@@ -38,8 +39,12 @@ export default function ModelGatewayPage() {
|
||||
const [gatewayAPIs, setGatewayAPIs] = useState<any[]>([])
|
||||
const [monitoring, setMonitoring] = useState<any>(null)
|
||||
const [stats, setStats] = useState({ availableGateways: 0, endpoints: 0, avgLatency: 0, requestsToday: 0 })
|
||||
const [showGatewayDialog, setShowGatewayDialog] = useState(false)
|
||||
const [selectedGateway, setSelectedGateway] = useState<any>(null)
|
||||
const [expandedGateways, setExpandedGateways] = useState<Record<string, boolean>>({})
|
||||
const [gatewayAgents, setGatewayAgents] = useState<Record<string, any[]>>({
|
||||
MCP: [],
|
||||
A2A: [],
|
||||
API: [],
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
loadGatewayData()
|
||||
@@ -125,26 +130,38 @@ export default function ModelGatewayPage() {
|
||||
fullName: "Model Context Protocol",
|
||||
icon: Code2,
|
||||
description: "适用于需要上下文理解的复杂对话场景",
|
||||
endpoint: "agentmcp.taijiaicloud.com",
|
||||
},
|
||||
{
|
||||
name: "A2A",
|
||||
fullName: "Agent-to-Agent Protocol",
|
||||
icon: Boxes,
|
||||
description: "适用于多Agent协同工作的场景",
|
||||
endpoint: "agenta2a.taijiaicloud.com",
|
||||
},
|
||||
{
|
||||
name: "API",
|
||||
fullName: "Standard API Gateway",
|
||||
icon: Workflow,
|
||||
description: "标准REST API,适用于简单的请求响应场景",
|
||||
endpoint: "agentapi.taijiaicloud.com",
|
||||
},
|
||||
]
|
||||
|
||||
const providersToUse = providers.length > 0 ? providers : []
|
||||
|
||||
const toggleGatewayExpand = (gatewayName: string) => {
|
||||
setExpandedGateways(prev => ({
|
||||
...prev,
|
||||
[gatewayName]: !prev[gatewayName]
|
||||
}))
|
||||
}
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
navigator.clipboard.writeText(text)
|
||||
toast({
|
||||
title: t("已复制", "Copied"),
|
||||
description: t("内容已复制到剪贴板", "Content copied to clipboard"),
|
||||
})
|
||||
}
|
||||
|
||||
const handleCreateAPI = async (apiData: { name: string; method: "json" | "url"; content: string }) => {
|
||||
try {
|
||||
const result = await TaijiAPIClient.createGatewayAPI(apiData.name, apiData.method, apiData.content)
|
||||
@@ -277,37 +294,130 @@ export default function ModelGatewayPage() {
|
||||
<CardContent className="space-y-4">
|
||||
{gatewayTypes.map((gateway) => {
|
||||
const Icon = gateway.icon
|
||||
const isExpanded = expandedGateways[gateway.name] || false
|
||||
const agents = gatewayAgents[gateway.name] || []
|
||||
|
||||
return (
|
||||
<div
|
||||
<Collapsible
|
||||
key={gateway.name}
|
||||
className="flex items-center justify-between rounded-lg border border-border bg-card p-4"
|
||||
open={isExpanded}
|
||||
onOpenChange={() => toggleGatewayExpand(gateway.name)}
|
||||
>
|
||||
<div className="flex items-center gap-4 flex-1">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||
<Icon className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<h3 className="font-semibold text-lg">{gateway.name}</h3>
|
||||
<Badge className="bg-green-500/10 text-green-500 text-xs">active</Badge>
|
||||
<div className="rounded-lg border border-border bg-card overflow-hidden">
|
||||
{/* 主卡片区域 */}
|
||||
<CollapsibleTrigger asChild>
|
||||
<div className="flex items-center justify-between p-4 cursor-pointer hover:bg-muted/50 transition-colors">
|
||||
<div className="flex items-center gap-4 flex-1">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||
<Icon className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<h3 className="font-semibold text-lg">{gateway.name}</h3>
|
||||
<Badge className="bg-green-500/10 text-green-500 text-xs">active</Badge>
|
||||
{agents.length > 0 && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{agents.length} {t("个Agent", "Agents")}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-1">{gateway.fullName}</p>
|
||||
<p className="text-xs text-muted-foreground">{gateway.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="ghost" size="sm" className="gap-1">
|
||||
{isExpanded ? (
|
||||
<>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
{t("收起", "Collapse")}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
{t("展开接口", "Expand APIs")}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-1">{gateway.fullName}</p>
|
||||
<p className="text-xs text-muted-foreground">{gateway.description}</p>
|
||||
</div>
|
||||
</CollapsibleTrigger>
|
||||
|
||||
{/* 折叠内容区域 - Agent 接口列表 */}
|
||||
<CollapsibleContent>
|
||||
<div className="border-t border-border bg-muted/30 p-4">
|
||||
{/* Agent 接口列表 */}
|
||||
<div className="space-y-3">
|
||||
{agents.length === 0 ? (
|
||||
<div className="text-center py-6 text-muted-foreground bg-background rounded-md border border-dashed">
|
||||
<p className="text-sm">
|
||||
{t("暂无已部署的 Agent", "No deployed agents yet")}
|
||||
</p>
|
||||
<p className="text-xs mt-1">
|
||||
{t("部署 Agent 后,接口信息将显示在这里", "API information will appear here after deploying agents")}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{agents.map((agent: any, index: number) => (
|
||||
<div
|
||||
key={agent.id || index}
|
||||
className="flex items-center justify-between p-3 rounded-md bg-background border border-border hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="font-medium text-sm">{agent.name}</span>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`text-xs ${
|
||||
agent.status === 'running'
|
||||
? 'bg-green-500/10 text-green-500 border-green-500/20'
|
||||
: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/20'
|
||||
}`}
|
||||
>
|
||||
{agent.status || 'unknown'}
|
||||
</Badge>
|
||||
</div>
|
||||
<code className="text-xs text-primary font-mono break-all">
|
||||
{agent.endpoint || agent.url || t("等待后端返回", "Waiting for backend")}
|
||||
</code>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 ml-2 flex-shrink-0">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
if (agent.endpoint || agent.url) {
|
||||
copyToClipboard(agent.endpoint || agent.url)
|
||||
}
|
||||
}}
|
||||
disabled={!agent.endpoint && !agent.url}
|
||||
>
|
||||
<Copy className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// TODO: 跳转到 Agent 详情页
|
||||
}}
|
||||
>
|
||||
<ExternalLink className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</div>
|
||||
<div className="flex items-center gap-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setSelectedGateway(gateway)
|
||||
setShowGatewayDialog(true)
|
||||
}}
|
||||
>
|
||||
{t("查看接口", "View API")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Collapsible>
|
||||
)
|
||||
})}
|
||||
</CardContent>
|
||||
@@ -504,108 +614,6 @@ export default function ModelGatewayPage() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Gateway API Details Dialog */}
|
||||
<Dialog open={showGatewayDialog} onOpenChange={setShowGatewayDialog}>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{selectedGateway?.name} {t("接口说明", "API Documentation")}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{selectedGateway?.fullName} - {selectedGateway?.description}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4 py-4">
|
||||
{/* 接口地址 */}
|
||||
<div className="space-y-2">
|
||||
<Label>{t("接口地址", "Endpoint URL")}</Label>
|
||||
<div className="rounded-md bg-muted p-3 font-mono text-sm">
|
||||
https://{selectedGateway?.endpoint}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 使用示例 */}
|
||||
<div className="space-y-2">
|
||||
<Label>{t("使用示例", "Usage Example")}</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<code className="text-xs whitespace-pre-wrap">
|
||||
{selectedGateway?.name === "MCP" && (
|
||||
<>
|
||||
{`curl -X POST https://${selectedGateway?.endpoint}/v1/context \\
|
||||
-H "Authorization: Bearer YOUR_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{
|
||||
"model": "gpt-4",
|
||||
"context": "Your context here",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Hello"}
|
||||
]
|
||||
}'`}
|
||||
</>
|
||||
)}
|
||||
{selectedGateway?.name === "A2A" && (
|
||||
<>
|
||||
{`curl -X POST https://${selectedGateway?.endpoint}/v1/agent/invoke \\
|
||||
-H "Authorization: Bearer YOUR_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{
|
||||
"source_agent": "agent-001",
|
||||
"target_agent": "agent-002",
|
||||
"task": "process_data",
|
||||
"payload": {"data": "example"}
|
||||
}'`}
|
||||
</>
|
||||
)}
|
||||
{selectedGateway?.name === "API" && (
|
||||
<>
|
||||
{`curl -X POST https://${selectedGateway?.endpoint}/v1/chat/completions \\
|
||||
-H "Authorization: Bearer YOUR_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{
|
||||
"model": "gpt-4",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Hello"}
|
||||
]
|
||||
}'`}
|
||||
</>
|
||||
)}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 功能说明 */}
|
||||
<div className="space-y-2">
|
||||
<Label>{t("功能说明", "Features")}</Label>
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
{selectedGateway?.name === "MCP" && (
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>{t("支持上下文管理和会话状态保持", "Supports context management and session state persistence")}</li>
|
||||
<li>{t("适用于复杂对话场景", "Suitable for complex dialogue scenarios")}</li>
|
||||
<li>{t("提供模型上下文协议标准接口", "Provides Model Context Protocol standard interface")}</li>
|
||||
</ul>
|
||||
)}
|
||||
{selectedGateway?.name === "A2A" && (
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>{t("支持Agent间通信和任务分发", "Supports inter-agent communication and task distribution")}</li>
|
||||
<li>{t("适用于多Agent协同工作场景", "Suitable for multi-agent collaboration scenarios")}</li>
|
||||
<li>{t("提供Agent到Agent协议标准接口", "Provides Agent-to-Agent Protocol standard interface")}</li>
|
||||
</ul>
|
||||
)}
|
||||
{selectedGateway?.name === "API" && (
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>{t("兼容OpenAI API格式", "Compatible with OpenAI API format")}</li>
|
||||
<li>{t("适用于简单的请求响应场景", "Suitable for simple request-response scenarios")}</li>
|
||||
<li>{t("提供标准REST API接口", "Provides standard REST API interface")}</li>
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button onClick={() => setShowGatewayDialog(false)}>{t("关闭", "Close")}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DashboardLayout>
|
||||
</AuthGuard>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user