Files
users/app/data-integration/page.tsx
v0 2408d50cb0 refactor: overhaul UI for streamlined user experience
Redesign navigation, home overview, user portrait, and valuation pages
with improved functionality and responsive design.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2025-07-18 13:47:12 +00:00

555 lines
20 KiB
TypeScript

"use client"
import { useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Badge } from "@/components/ui/badge"
import { Database, Server, Link, Plus, FileText, RefreshCw } from "lucide-react"
export default function DataIntegrationPage() {
const [activeTab, setActiveTab] = useState("data-sources")
const [isDialogOpen, setIsDialogOpen] = useState(false)
return (
<div className="container mx-auto py-6 space-y-8">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h1 className="text-3xl font-bold tracking-tight"></h1>
<p className="text-muted-foreground">API接口</p>
</div>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="grid w-full max-w-md grid-cols-2">
<TabsTrigger value="data-sources"></TabsTrigger>
<TabsTrigger value="api-management">API管理</TabsTrigger>
</TabsList>
<TabsContent value="data-sources" className="space-y-6">
<DataSourcesTab setIsDialogOpen={setIsDialogOpen} />
<div className="mt-4">
<Button variant="outline" asChild>
<a href="/database-structure">
<Database className="mr-2 h-4 w-4" />
</a>
</Button>
</div>
</TabsContent>
<TabsContent value="api-management" className="space-y-6">
<ApiManagementTab />
</TabsContent>
</Tabs>
<AddDataSourceDialog isOpen={isDialogOpen} setIsOpen={setIsDialogOpen} />
</div>
)
}
// 数据源管理标签页
function DataSourcesTab({ setIsDialogOpen }: { setIsDialogOpen: (open: boolean) => void }) {
// 模拟数据源列表
const dataSources = [
{
id: "1",
name: "用户数据库",
type: "MySQL",
host: "db.example.com",
status: "connected",
lastSync: "2023-07-20 15:30",
tables: 24,
records: 156789,
},
{
id: "2",
name: "订单系统",
type: "PostgreSQL",
host: "orders.example.com",
status: "connected",
lastSync: "2023-07-19 12:45",
tables: 18,
records: 89456,
},
{
id: "3",
name: "内容库",
type: "MongoDB",
host: "content.example.com",
status: "error",
lastSync: "2023-07-15 09:20",
tables: 12,
records: 45678,
},
{
id: "4",
name: "用户行为分析",
type: "ClickHouse",
host: "analytics.example.com",
status: "connected",
lastSync: "2023-07-20 10:15",
tables: 8,
records: 2345678,
},
{
id: "5",
name: "CRM系统",
type: "Oracle",
host: "crm.example.com",
status: "pending",
lastSync: "等待连接",
tables: 0,
records: 0,
},
]
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<h2 className="text-2xl font-bold"></h2>
<Button onClick={() => setIsDialogOpen(true)}>
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{dataSources.map((source) => (
<TableRow key={source.id}>
<TableCell>
<div className="flex items-center">
<Database className="h-4 w-4 mr-2 text-muted-foreground" />
<span className="font-medium">{source.name}</span>
</div>
</TableCell>
<TableCell>{source.type}</TableCell>
<TableCell>{source.host}</TableCell>
<TableCell>
<Badge
className={
source.status === "connected"
? "bg-green-100 text-green-800"
: source.status === "error"
? "bg-red-100 text-red-800"
: "bg-yellow-100 text-yellow-800"
}
>
{source.status === "connected" ? "已连接" : source.status === "error" ? "错误" : "等待中"}
</Badge>
</TableCell>
<TableCell>{source.lastSync}</TableCell>
<TableCell>{source.tables}</TableCell>
<TableCell>{source.records.toLocaleString()}</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-2">
<Button variant="outline" size="sm">
<Link className="h-4 w-4 mr-1" />
</Button>
<Button size="sm">
<RefreshCw className="h-4 w-4 mr-1" />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="flex flex-col items-center p-4 border rounded-lg">
<Database className="h-8 w-8 mb-2 text-blue-500" />
<span className="font-medium">MySQL</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<Database className="h-8 w-8 mb-2 text-blue-500" />
<span className="font-medium">PostgreSQL</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<Database className="h-8 w-8 mb-2 text-green-500" />
<span className="font-medium">MongoDB</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<Database className="h-8 w-8 mb-2 text-yellow-500" />
<span className="font-medium">ClickHouse</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<Database className="h-8 w-8 mb-2 text-red-500" />
<span className="font-medium">Oracle</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<Database className="h-8 w-8 mb-2 text-purple-500" />
<span className="font-medium">SQL Server</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<Server className="h-8 w-8 mb-2 text-gray-500" />
<span className="font-medium">Redis</span>
<span className="text-xs text-muted-foreground"></span>
</div>
<div className="flex flex-col items-center p-4 border rounded-lg">
<FileText className="h-8 w-8 mb-2 text-gray-500" />
<span className="font-medium">CSV/Excel</span>
<span className="text-xs text-muted-foreground"></span>
</div>
</div>
</CardContent>
</Card>
</div>
)
}
// API管理标签页
function ApiManagementTab() {
// 模拟API接口数据
const apiEndpoints = [
{
id: "1",
name: "用户数据API",
endpoint: "/api/users",
method: "GET",
category: "用户画像",
status: "active",
calls: 12567,
lastCalled: "2023-07-20 16:45",
},
{
id: "2",
name: "用户标签API",
endpoint: "/api/users/tags",
method: "GET",
category: "用户画像",
status: "active",
calls: 8945,
lastCalled: "2023-07-20 15:30",
},
{
id: "3",
name: "流量池数据API",
endpoint: "/api/traffic-pools",
method: "GET",
category: "流量池",
status: "active",
calls: 5678,
lastCalled: "2023-07-20 14:20",
},
{
id: "4",
name: "AI分析API",
endpoint: "/api/ai/analyze",
method: "POST",
category: "AI分析",
status: "active",
calls: 3456,
lastCalled: "2023-07-20 13:15",
},
{
id: "5",
name: "数据同步API",
endpoint: "/api/sync",
method: "POST",
category: "数据集成",
status: "maintenance",
calls: 2345,
lastCalled: "2023-07-19 10:30",
},
]
// 模拟API密钥数据
const apiKeys = [
{
id: "1",
name: "Web应用",
key: "sk_web_*************",
created: "2023-05-15",
lastUsed: "2023-07-20",
status: "active",
},
{
id: "2",
name: "移动应用",
key: "sk_mobile_*************",
created: "2023-06-10",
lastUsed: "2023-07-19",
status: "active",
},
{
id: "3",
name: "第三方集成",
key: "sk_partner_*************",
created: "2023-04-20",
lastUsed: "2023-07-18",
status: "active",
},
]
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<h2 className="text-2xl font-bold">API接口管理</h2>
<Button>
<Plus className="mr-2 h-4 w-4" />
API
</Button>
</div>
<Card>
<CardHeader>
<CardTitle>API接口列表</CardTitle>
<CardDescription>API接口</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>API名称</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{apiEndpoints.map((api) => (
<TableRow key={api.id}>
<TableCell className="font-medium">{api.name}</TableCell>
<TableCell>
<code className="bg-muted px-1 py-0.5 rounded text-sm">{api.endpoint}</code>
</TableCell>
<TableCell>
<Badge
className={
api.method === "GET"
? "bg-blue-100 text-blue-800"
: api.method === "POST"
? "bg-green-100 text-green-800"
: api.method === "PUT"
? "bg-yellow-100 text-yellow-800"
: "bg-red-100 text-red-800"
}
>
{api.method}
</Badge>
</TableCell>
<TableCell>{api.category}</TableCell>
<TableCell>
<Badge
className={
api.status === "active" ? "bg-green-100 text-green-800" : "bg-yellow-100 text-yellow-800"
}
>
{api.status === "active" ? "正常" : "维护中"}
</Badge>
</TableCell>
<TableCell>{api.calls.toLocaleString()}</TableCell>
<TableCell>{api.lastCalled}</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-2">
<Button variant="outline" size="sm">
</Button>
<Button size="sm"></Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>API密钥管理</CardTitle>
<CardDescription>API访问密钥</CardDescription>
</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="bg-muted px-1 py-0.5 rounded text-sm">{key.key}</code>
</TableCell>
<TableCell>{key.created}</TableCell>
<TableCell>{key.lastUsed}</TableCell>
<TableCell>
<Badge className="bg-green-100 text-green-800">{key.status === "active" ? "有效" : "已禁用"}</Badge>
</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-2">
<Button variant="outline" size="sm">
</Button>
<Button variant="outline" size="sm" className="text-red-500">
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>API使用统计</CardTitle>
<CardDescription>API调用量和性能统计</CardDescription>
</CardHeader>
<CardContent className="h-80 flex items-center justify-center">
<div className="text-center text-muted-foreground">
<p>API调用统计图表</p>
</div>
</CardContent>
</Card>
</div>
)
}
// 添加数据源对话框
function AddDataSourceDialog({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: (open: boolean) => void }) {
const [dbType, setDbType] = useState("mysql")
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="db-type" className="text-right">
</Label>
<Select value={dbType} onValueChange={setDbType} className="col-span-3">
<SelectTrigger id="db-type">
<SelectValue placeholder="选择数据库类型" />
</SelectTrigger>
<SelectContent>
<SelectItem value="mysql">MySQL</SelectItem>
<SelectItem value="postgresql">PostgreSQL</SelectItem>
<SelectItem value="mongodb">MongoDB</SelectItem>
<SelectItem value="clickhouse">ClickHouse</SelectItem>
<SelectItem value="oracle">Oracle</SelectItem>
<SelectItem value="sqlserver">SQL Server</SelectItem>
<SelectItem value="redis">Redis</SelectItem>
<SelectItem value="file">CSV/Excel文件</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
</Label>
<Input id="name" placeholder="给数据源起个名字" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="host" className="text-right">
</Label>
<Input id="host" placeholder="例如: db.example.com" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="port" className="text-right">
</Label>
<Input
id="port"
placeholder={dbType === "mysql" ? "3306" : dbType === "postgresql" ? "5432" : "27017"}
className="col-span-3"
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="database" className="text-right">
</Label>
<Input id="database" placeholder="数据库名称" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
</Label>
<Input id="username" placeholder="数据库用户名" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="password" className="text-right">
</Label>
<Input id="password" type="password" placeholder="数据库密码" className="col-span-3" />
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setIsOpen(false)}>
</Button>
<Button type="submit"></Button>
<Button type="submit"></Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}