refactor: overhaul system navigation based on 5 HTML docs
Reorganize modules, add AI Agent smart interaction, include prompt settings, enhance data output with subscriptions, and separate system monitoring. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
464
app/data-output/api-market/page.tsx
Normal file
464
app/data-output/api-market/page.tsx
Normal file
@@ -0,0 +1,464 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
import {
|
||||
Server, Plus, Key, FileText, BarChart3, Settings,
|
||||
Eye, Copy, Trash2, CheckCircle2, XCircle, Clock,
|
||||
Activity, ExternalLink, Code, Shield
|
||||
} from "lucide-react"
|
||||
|
||||
const apis = [
|
||||
{
|
||||
id: "1",
|
||||
name: "用户画像查询API",
|
||||
endpoint: "/api/v1/user/portrait",
|
||||
method: "GET",
|
||||
description: "根据用户ID查询完整画像信息",
|
||||
status: "active",
|
||||
callCount: 125680,
|
||||
avgLatency: 45,
|
||||
errorRate: 0.02,
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "标签批量查询API",
|
||||
endpoint: "/api/v1/tags/batch",
|
||||
method: "POST",
|
||||
description: "批量查询用户标签",
|
||||
status: "active",
|
||||
callCount: 89420,
|
||||
avgLatency: 120,
|
||||
errorRate: 0.05,
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "CLV评分API",
|
||||
endpoint: "/api/v1/clv/score",
|
||||
method: "GET",
|
||||
description: "获取用户CLV评分和预测值",
|
||||
status: "maintenance",
|
||||
callCount: 45230,
|
||||
avgLatency: 85,
|
||||
errorRate: 0.01,
|
||||
},
|
||||
]
|
||||
|
||||
const apiKeys = [
|
||||
{ id: "1", name: "生产环境密钥", key: "sk_prod_****8a9b", created: "2024-01-01", lastUsed: "2024-01-15", status: "active" },
|
||||
{ id: "2", name: "测试环境密钥", key: "sk_test_****3c2d", created: "2024-01-05", lastUsed: "2024-01-14", status: "active" },
|
||||
]
|
||||
|
||||
export default function APIMarketPage() {
|
||||
const [activeTab, setActiveTab] = useState("apis")
|
||||
const [showDocDialog, setShowDocDialog] = useState(false)
|
||||
const [showKeyDialog, setShowKeyDialog] = useState(false)
|
||||
const [showMonitorDialog, setShowMonitorDialog] = useState(false)
|
||||
const [selectedApi, setSelectedApi] = useState<typeof apis[0] | null>(null)
|
||||
|
||||
const getStatusBadge = (status: string) => {
|
||||
switch (status) {
|
||||
case "active":
|
||||
return <Badge className="bg-green-100 text-green-700">运行中</Badge>
|
||||
case "maintenance":
|
||||
return <Badge className="bg-yellow-100 text-yellow-700">维护中</Badge>
|
||||
case "disabled":
|
||||
return <Badge className="bg-gray-100 text-gray-700">已停用</Badge>
|
||||
default:
|
||||
return <Badge variant="secondary">未知</Badge>
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* 页面标题 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-foreground">API市场</h1>
|
||||
<p className="text-muted-foreground">管理和监控数据API服务</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={() => setShowKeyDialog(true)}>
|
||||
<Key className="mr-2 h-4 w-4" />
|
||||
管理密钥
|
||||
</Button>
|
||||
<Button>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
发布API
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 统计卡片 */}
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">API总数</p>
|
||||
<p className="text-2xl font-bold">12</p>
|
||||
</div>
|
||||
<Server className="h-8 w-8 text-blue-500" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">今日调用</p>
|
||||
<p className="text-2xl font-bold">45.2K</p>
|
||||
</div>
|
||||
<Activity className="h-8 w-8 text-green-500" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">平均延迟</p>
|
||||
<p className="text-2xl font-bold">68ms</p>
|
||||
</div>
|
||||
<Clock className="h-8 w-8 text-purple-500" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">成功率</p>
|
||||
<p className="text-2xl font-bold">99.8%</p>
|
||||
</div>
|
||||
<CheckCircle2 className="h-8 w-8 text-cyan-500" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 主内容区 */}
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
||||
<TabsList>
|
||||
<TabsTrigger value="apis">API列表</TabsTrigger>
|
||||
<TabsTrigger value="keys">API密钥</TabsTrigger>
|
||||
<TabsTrigger value="logs">调用日志</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="apis" className="space-y-4">
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>API名称</TableHead>
|
||||
<TableHead>端点</TableHead>
|
||||
<TableHead>方法</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead>调用量</TableHead>
|
||||
<TableHead>延迟</TableHead>
|
||||
<TableHead className="text-right">操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{apis.map((api) => (
|
||||
<TableRow key={api.id}>
|
||||
<TableCell>
|
||||
<div>
|
||||
<p className="font-medium">{api.name}</p>
|
||||
<p className="text-sm text-muted-foreground">{api.description}</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<code className="text-sm bg-muted px-2 py-1 rounded">{api.endpoint}</code>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline">{api.method}</Badge>
|
||||
</TableCell>
|
||||
<TableCell>{getStatusBadge(api.status)}</TableCell>
|
||||
<TableCell>{api.callCount.toLocaleString()}</TableCell>
|
||||
<TableCell>{api.avgLatency}ms</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setSelectedApi(api)
|
||||
setShowDocDialog(true)
|
||||
}}
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setSelectedApi(api)
|
||||
setShowMonitorDialog(true)
|
||||
}}
|
||||
>
|
||||
<BarChart3 className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Settings className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="keys" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle>API密钥</CardTitle>
|
||||
<CardDescription>管理API访问密钥</CardDescription>
|
||||
</div>
|
||||
<Button size="sm">
|
||||
<Plus className="h-4 w-4 mr-1" />
|
||||
创建密钥
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>名称</TableHead>
|
||||
<TableHead>密钥</TableHead>
|
||||
<TableHead>创建时间</TableHead>
|
||||
<TableHead>最后使用</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead className="text-right">操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{apiKeys.map((key) => (
|
||||
<TableRow key={key.id}>
|
||||
<TableCell className="font-medium">{key.name}</TableCell>
|
||||
<TableCell>
|
||||
<code className="text-sm bg-muted px-2 py-1 rounded">{key.key}</code>
|
||||
</TableCell>
|
||||
<TableCell>{key.created}</TableCell>
|
||||
<TableCell>{key.lastUsed}</TableCell>
|
||||
<TableCell>
|
||||
<Badge className="bg-green-100 text-green-700">活跃</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<Button variant="ghost" size="sm">
|
||||
<Eye className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" className="text-red-600">
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="logs" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>调用日志</CardTitle>
|
||||
<CardDescription>查看API调用历史记录</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>时间</TableHead>
|
||||
<TableHead>API</TableHead>
|
||||
<TableHead>方法</TableHead>
|
||||
<TableHead>状态码</TableHead>
|
||||
<TableHead>延迟</TableHead>
|
||||
<TableHead>IP</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>2024-01-15 14:30:25</TableCell>
|
||||
<TableCell>/api/v1/user/portrait</TableCell>
|
||||
<TableCell><Badge variant="outline">GET</Badge></TableCell>
|
||||
<TableCell><Badge className="bg-green-100 text-green-700">200</Badge></TableCell>
|
||||
<TableCell>42ms</TableCell>
|
||||
<TableCell>192.168.1.***</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>2024-01-15 14:30:18</TableCell>
|
||||
<TableCell>/api/v1/tags/batch</TableCell>
|
||||
<TableCell><Badge variant="outline">POST</Badge></TableCell>
|
||||
<TableCell><Badge className="bg-green-100 text-green-700">200</Badge></TableCell>
|
||||
<TableCell>118ms</TableCell>
|
||||
<TableCell>192.168.1.***</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>2024-01-15 14:30:05</TableCell>
|
||||
<TableCell>/api/v1/clv/score</TableCell>
|
||||
<TableCell><Badge variant="outline">GET</Badge></TableCell>
|
||||
<TableCell><Badge className="bg-red-100 text-red-700">500</Badge></TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
<TableCell>192.168.2.***</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{/* API文档弹窗 */}
|
||||
<Dialog open={showDocDialog} onOpenChange={setShowDocDialog}>
|
||||
<DialogContent className="max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{selectedApi?.name} - 接口文档</DialogTitle>
|
||||
<DialogDescription>{selectedApi?.description}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant="outline">{selectedApi?.method}</Badge>
|
||||
<code className="flex-1 bg-muted px-3 py-2 rounded text-sm">{selectedApi?.endpoint}</code>
|
||||
<Button variant="outline" size="sm">
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-medium">请求参数</Label>
|
||||
<div className="mt-2 bg-muted rounded-lg p-4">
|
||||
<pre className="text-sm">{`{
|
||||
"user_id": "string (必填) - 用户唯一标识",
|
||||
"fields": "array (可选) - 需要返回的字段列表"
|
||||
}`}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-medium">响应示例</Label>
|
||||
<div className="mt-2 bg-muted rounded-lg p-4">
|
||||
<pre className="text-sm">{`{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"user_id": "U12345",
|
||||
"portrait": {
|
||||
"basic": { "age": 28, "gender": "M" },
|
||||
"tags": ["高价值", "活跃用户"],
|
||||
"clv_score": 92
|
||||
}
|
||||
}
|
||||
}`}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setShowDocDialog(false)}>关闭</Button>
|
||||
<Button>
|
||||
<ExternalLink className="mr-2 h-4 w-4" />
|
||||
在线调试
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 监控弹窗 */}
|
||||
<Dialog open={showMonitorDialog} onOpenChange={setShowMonitorDialog}>
|
||||
<DialogContent className="max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{selectedApi?.name} - 性能监控</DialogTitle>
|
||||
<DialogDescription>查看API实时性能指标</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<Card className="p-4">
|
||||
<p className="text-sm text-muted-foreground">今日调用</p>
|
||||
<p className="text-2xl font-bold">{selectedApi?.callCount.toLocaleString()}</p>
|
||||
</Card>
|
||||
<Card className="p-4">
|
||||
<p className="text-sm text-muted-foreground">平均延迟</p>
|
||||
<p className="text-2xl font-bold">{selectedApi?.avgLatency}ms</p>
|
||||
</Card>
|
||||
<Card className="p-4">
|
||||
<p className="text-sm text-muted-foreground">错误率</p>
|
||||
<p className="text-2xl font-bold">{((selectedApi?.errorRate || 0) * 100).toFixed(2)}%</p>
|
||||
</Card>
|
||||
</div>
|
||||
<Card className="p-4">
|
||||
<p className="text-sm font-medium mb-4">调用趋势 (最近24小时)</p>
|
||||
<div className="h-48 flex items-end justify-between gap-1">
|
||||
{Array.from({ length: 24 }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex-1 bg-primary/20 rounded-t"
|
||||
style={{ height: `${Math.random() * 100}%` }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setShowMonitorDialog(false)}>关闭</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 密钥管理弹窗 */}
|
||||
<Dialog open={showKeyDialog} onOpenChange={setShowKeyDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>创建API密钥</DialogTitle>
|
||||
<DialogDescription>创建新的API访问密钥</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label>密钥名称</Label>
|
||||
<Input placeholder="输入密钥名称,如:生产环境密钥" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>权限范围</Label>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
|
||||
<input type="checkbox" defaultChecked />
|
||||
<span>用户画像API</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
|
||||
<input type="checkbox" defaultChecked />
|
||||
<span>标签查询API</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
|
||||
<input type="checkbox" />
|
||||
<span>CLV评分API</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
|
||||
<input type="checkbox" />
|
||||
<span>流量包API</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setShowKeyDialog(false)}>取消</Button>
|
||||
<Button>创建密钥</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user