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>
This commit is contained in:
240
components/data-integration/integration-history.tsx
Normal file
240
components/data-integration/integration-history.tsx
Normal file
@@ -0,0 +1,240 @@
|
||||
"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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { Search, FileDown, Eye, RefreshCw } from "lucide-react"
|
||||
import {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationItem,
|
||||
PaginationLink,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "@/components/ui/pagination"
|
||||
|
||||
interface IntegrationRecord {
|
||||
id: string
|
||||
sourceId: string
|
||||
sourceName: string
|
||||
startTime: Date
|
||||
endTime: Date
|
||||
status: "success" | "failed" | "partial" | "running"
|
||||
totalRecords: number
|
||||
successRecords: number
|
||||
failedRecords: number
|
||||
notes: string
|
||||
}
|
||||
|
||||
export function IntegrationHistory() {
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
const [statusFilter, setStatusFilter] = useState("all")
|
||||
|
||||
// 模拟数据
|
||||
const integrationRecords: IntegrationRecord[] = [
|
||||
{
|
||||
id: "1",
|
||||
sourceId: "1",
|
||||
sourceName: "CRM系统用户数据",
|
||||
startTime: new Date(2023, 6, 15, 14, 30),
|
||||
endTime: new Date(2023, 6, 15, 14, 45),
|
||||
status: "success",
|
||||
totalRecords: 5280,
|
||||
successRecords: 5280,
|
||||
failedRecords: 0,
|
||||
notes: "完全同步成功",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
sourceId: "2",
|
||||
sourceName: "电商平台订单数据",
|
||||
startTime: new Date(2023, 6, 15, 10, 15),
|
||||
endTime: new Date(2023, 6, 15, 10, 40),
|
||||
status: "partial",
|
||||
totalRecords: 12500,
|
||||
successRecords: 12350,
|
||||
failedRecords: 150,
|
||||
notes: "部分记录格式错误",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
sourceId: "3",
|
||||
sourceName: "营销活动参与用户",
|
||||
startTime: new Date(2023, 6, 14, 9, 45),
|
||||
endTime: new Date(2023, 6, 14, 9, 50),
|
||||
status: "success",
|
||||
totalRecords: 875,
|
||||
successRecords: 875,
|
||||
failedRecords: 0,
|
||||
notes: "同步成功",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
sourceId: "4",
|
||||
sourceName: "APP用户行为数据",
|
||||
startTime: new Date(2023, 6, 10, 16, 20),
|
||||
endTime: new Date(2023, 6, 10, 16, 35),
|
||||
status: "failed",
|
||||
totalRecords: 8500,
|
||||
successRecords: 0,
|
||||
failedRecords: 8500,
|
||||
notes: "API连接超时",
|
||||
},
|
||||
{
|
||||
id: "5",
|
||||
sourceId: "5",
|
||||
sourceName: "社交媒体用户数据",
|
||||
startTime: new Date(2023, 6, 15, 8, 0),
|
||||
endTime: new Date(2023, 6, 15, 8, 15),
|
||||
status: "success",
|
||||
totalRecords: 3200,
|
||||
successRecords: 3200,
|
||||
failedRecords: 0,
|
||||
notes: "同步成功",
|
||||
},
|
||||
{
|
||||
id: "6",
|
||||
sourceId: "7",
|
||||
sourceName: "新用户注册数据",
|
||||
startTime: new Date(2023, 6, 15, 16, 0),
|
||||
endTime: null,
|
||||
status: "running",
|
||||
totalRecords: 0,
|
||||
successRecords: 0,
|
||||
failedRecords: 0,
|
||||
notes: "首次同步进行中",
|
||||
},
|
||||
]
|
||||
|
||||
// 过滤记录
|
||||
const filteredRecords = integrationRecords.filter((record) => {
|
||||
const matchesSearch = record.sourceName.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
const matchesStatus = statusFilter === "all" || record.status === statusFilter
|
||||
return matchesSearch && matchesStatus
|
||||
})
|
||||
|
||||
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: IntegrationRecord["status"]) => {
|
||||
switch (status) {
|
||||
case "success":
|
||||
return <Badge className="bg-green-100 text-green-800">成功</Badge>
|
||||
case "failed":
|
||||
return <Badge className="bg-red-100 text-red-800">失败</Badge>
|
||||
case "partial":
|
||||
return <Badge className="bg-yellow-100 text-yellow-800">部分成功</Badge>
|
||||
case "running":
|
||||
return <Badge className="bg-blue-100 text-blue-800">进行中</Badge>
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex space-x-2">
|
||||
<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>
|
||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||
<SelectTrigger className="w-[150px]">
|
||||
<SelectValue placeholder="状态筛选" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">全部状态</SelectItem>
|
||||
<SelectItem value="success">成功</SelectItem>
|
||||
<SelectItem value="failed">失败</SelectItem>
|
||||
<SelectItem value="partial">部分成功</SelectItem>
|
||||
<SelectItem value="running">进行中</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<Button variant="outline">
|
||||
<RefreshCw className="mr-2 h-4 w-4" />
|
||||
刷新
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>数据源</TableHead>
|
||||
<TableHead>开始时间</TableHead>
|
||||
<TableHead>结束时间</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead>总记录数</TableHead>
|
||||
<TableHead>成功数</TableHead>
|
||||
<TableHead>失败数</TableHead>
|
||||
<TableHead>备注</TableHead>
|
||||
<TableHead className="text-right">操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{filteredRecords.map((record) => (
|
||||
<TableRow key={record.id}>
|
||||
<TableCell className="font-medium">{record.sourceName}</TableCell>
|
||||
<TableCell>{formatDate(record.startTime)}</TableCell>
|
||||
<TableCell>{formatDate(record.endTime)}</TableCell>
|
||||
<TableCell>{getStatusBadge(record.status)}</TableCell>
|
||||
<TableCell>{record.totalRecords.toLocaleString()}</TableCell>
|
||||
<TableCell>{record.successRecords.toLocaleString()}</TableCell>
|
||||
<TableCell>{record.failedRecords.toLocaleString()}</TableCell>
|
||||
<TableCell>{record.notes}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex justify-end space-x-2">
|
||||
<Button variant="ghost" size="icon">
|
||||
<Eye className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon">
|
||||
<FileDown className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious href="#" />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">1</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#" isActive>
|
||||
2
|
||||
</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">3</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext href="#" />
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user