Files
users/components/data-integration/data-source-list.tsx

186 lines
6.2 KiB
TypeScript
Raw Permalink Normal View History

"use client"
import { useState } from "react"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Input } from "@/components/ui/input"
import { Edit, ExternalLink, MoreHorizontal, Search, RefreshCw } from "lucide-react"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
interface DataSource {
id: string
name: string
type: "api" | "file" | "database" | "third-party"
status: "active" | "inactive" | "error" | "pending"
lastSync: Date | null
recordCount: number
createdAt: Date
}
export function DataSourceList() {
const [searchQuery, setSearchQuery] = useState("")
// 模拟数据
const dataSources: DataSource[] = [
{
id: "1",
name: "CRM系统用户数据",
type: "api",
status: "active",
lastSync: new Date(2023, 6, 15, 14, 30),
recordCount: 45892,
createdAt: new Date(2023, 3, 10),
},
{
id: "2",
name: "电商平台订单数据",
type: "api",
status: "active",
lastSync: new Date(2023, 6, 15, 10, 15),
recordCount: 128456,
createdAt: new Date(2023, 2, 5),
},
{
id: "3",
name: "营销活动参与用户",
type: "file",
status: "active",
lastSync: new Date(2023, 6, 14, 9, 45),
recordCount: 8754,
createdAt: new Date(2023, 5, 20),
},
{
id: "4",
name: "APP用户行为数据",
type: "api",
status: "error",
lastSync: new Date(2023, 6, 10, 16, 20),
recordCount: 65432,
createdAt: new Date(2023, 1, 15),
},
{
id: "5",
name: "社交媒体用户数据",
type: "third-party",
status: "active",
lastSync: new Date(2023, 6, 15, 8, 0),
recordCount: 32145,
createdAt: new Date(2023, 4, 25),
},
]
// 过滤数据源
const filteredDataSources = dataSources.filter(
(source) =>
source.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
source.type.toLowerCase().includes(searchQuery.toLowerCase()),
)
const formatDate = (date: Date | null) => {
if (!date) return "从未同步"
return date.toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
})
}
const getStatusBadge = (status: DataSource["status"]) => {
switch (status) {
case "active":
return <Badge className="bg-green-100 text-green-800"></Badge>
case "inactive":
return <Badge className="bg-gray-100 text-gray-800"></Badge>
case "error":
return <Badge className="bg-red-100 text-red-800"></Badge>
case "pending":
return <Badge className="bg-yellow-100 text-yellow-800"></Badge>
}
}
const getTypeIcon = (type: DataSource["type"]) => {
switch (type) {
case "api":
return <Badge className="bg-blue-100 text-blue-800">API接口</Badge>
case "file":
return <Badge className="bg-purple-100 text-purple-800"></Badge>
case "database":
return <Badge className="bg-green-100 text-green-800"></Badge>
case "third-party":
return <Badge className="bg-orange-100 text-orange-800"></Badge>
}
}
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<div className="relative w-64">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="搜索数据源..."
className="pl-8"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<Button variant="outline" size="sm">
<RefreshCw className="h-4 w-4 mr-2" />
</Button>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredDataSources.map((source) => (
<TableRow key={source.id}>
<TableCell className="font-medium">{source.name}</TableCell>
<TableCell>{getTypeIcon(source.type)}</TableCell>
<TableCell>{getStatusBadge(source.status)}</TableCell>
<TableCell>{formatDate(source.lastSync)}</TableCell>
<TableCell>{source.recordCount.toLocaleString()}</TableCell>
<TableCell className="text-right">
<div className="flex justify-end space-x-2">
<Button variant="ghost" size="icon">
<Edit className="h-4 w-4" />
</Button>
<Button variant="ghost" size="icon">
<ExternalLink className="h-4 w-4" />
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem></DropdownMenuItem>
<DropdownMenuItem></DropdownMenuItem>
<DropdownMenuItem></DropdownMenuItem>
<DropdownMenuItem className="text-red-600"></DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
)
}