Adjust MongoDB mock connector and update database structure. Enhance sidebar, data platform, and AI analysis tools. Clean up unnecessary code and update development docs. #VERCEL_SKIP Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
548 lines
24 KiB
TypeScript
548 lines
24 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 { Badge } from "@/components/ui/badge"
|
||
import { Progress } from "@/components/ui/progress"
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||
import {
|
||
Database,
|
||
Upload,
|
||
Download,
|
||
RefreshCw,
|
||
CheckCircle,
|
||
AlertCircle,
|
||
Clock,
|
||
FileText,
|
||
Settings,
|
||
ChevronRight,
|
||
ChevronDown,
|
||
Brain,
|
||
} from "lucide-react"
|
||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||
import { AIAnalysisTools } from "@/components/data-integration/ai-analysis-tools"
|
||
import { useToast } from "@/components/ui/use-toast" // 导入 useToast
|
||
|
||
export default function DataPlatformPage() {
|
||
const { toast } = useToast() // 初始化 toast
|
||
const [timeRange, setTimeRange] = useState("today")
|
||
const [expandedSections, setExpandedSections] = useState({
|
||
overview: true,
|
||
sources: true,
|
||
integration: false,
|
||
quality: false,
|
||
})
|
||
const [activeTab, setActiveTab] = useState("overview")
|
||
|
||
// 数据中台数据
|
||
const platformData = {
|
||
overview: {
|
||
totalRecords: 1245678,
|
||
dataSources: 8,
|
||
syncStatus: "正常",
|
||
lastUpdate: "2分钟前",
|
||
dataQuality: 94.6,
|
||
storageUsed: 2.3,
|
||
storageTotal: 10.0,
|
||
},
|
||
dataSources: [
|
||
{
|
||
name: "用户行为数据库",
|
||
type: "MySQL",
|
||
status: "connected",
|
||
records: 456789,
|
||
lastSync: "1分钟前",
|
||
quality: 96.8,
|
||
description: "用户行为轨迹数据",
|
||
aiReady: true, // 新增 AI 就绪状态
|
||
},
|
||
{
|
||
name: "CRM系统",
|
||
type: "API",
|
||
status: "connected",
|
||
records: 125678,
|
||
lastSync: "3分钟前",
|
||
quality: 94.2,
|
||
description: "客户关系管理数据",
|
||
aiReady: true,
|
||
},
|
||
{
|
||
name: "内容平台数据",
|
||
type: "API",
|
||
status: "syncing",
|
||
records: 234567,
|
||
lastSync: "正在同步",
|
||
quality: 92.5,
|
||
description: "抖音、小红书等平台数据",
|
||
aiReady: false,
|
||
},
|
||
{
|
||
name: "触客宝后台",
|
||
type: "API",
|
||
status: "connected",
|
||
records: 89234,
|
||
lastSync: "5分钟前",
|
||
quality: 95.1,
|
||
description: "呼入电话信息数据",
|
||
aiReady: true,
|
||
},
|
||
{
|
||
name: "飞书妙记",
|
||
type: "API",
|
||
status: "connected",
|
||
records: 12345,
|
||
lastSync: "10分钟前",
|
||
quality: 91.3,
|
||
description: "会议记录和内容摘要",
|
||
aiReady: true,
|
||
},
|
||
{
|
||
name: "表单提交数据",
|
||
type: "Webhook",
|
||
status: "connected",
|
||
records: 67890,
|
||
lastSync: "2分钟前",
|
||
quality: 97.2,
|
||
description: "在线表单提交数据",
|
||
aiReady: true,
|
||
},
|
||
],
|
||
integrationStats: {
|
||
totalIntegrations: 8,
|
||
activeIntegrations: 7,
|
||
failedIntegrations: 0,
|
||
pendingIntegrations: 1,
|
||
avgSyncTime: "2.3分钟",
|
||
successRate: 98.7,
|
||
},
|
||
dataQuality: {
|
||
completeness: 94.6,
|
||
accuracy: 96.2,
|
||
consistency: 92.8,
|
||
timeliness: 95.4,
|
||
validity: 93.7,
|
||
uniqueness: 97.1,
|
||
},
|
||
}
|
||
|
||
const toggleSection = (section: string) => {
|
||
setExpandedSections((prev) => ({
|
||
...prev,
|
||
[section]: !prev[section],
|
||
}))
|
||
}
|
||
|
||
const getStatusColor = (status: string) => {
|
||
switch (status) {
|
||
case "connected":
|
||
return "bg-green-100 text-green-800"
|
||
case "syncing":
|
||
return "bg-yellow-100 text-yellow-800"
|
||
case "error":
|
||
return "bg-red-100 text-red-800"
|
||
case "disconnected":
|
||
return "bg-gray-100 text-gray-800"
|
||
default:
|
||
return "bg-gray-100 text-gray-800"
|
||
}
|
||
}
|
||
|
||
const getStatusIcon = (status: string) => {
|
||
switch (status) {
|
||
case "connected":
|
||
return <CheckCircle className="h-4 w-4 text-green-600" />
|
||
case "syncing":
|
||
return <Clock className="h-4 w-4 text-yellow-600 animate-spin" />
|
||
case "error":
|
||
return <AlertCircle className="h-4 w-4 text-red-600" />
|
||
default:
|
||
return <AlertCircle className="h-4 w-4 text-gray-600" />
|
||
}
|
||
}
|
||
|
||
const handleConnectToAI = (sourceName: string) => {
|
||
toast({
|
||
title: "连接到AI",
|
||
description: `数据源 "${sourceName}" 已准备好连接到AI模型。`,
|
||
})
|
||
// 实际应用中,这里会触发一个后端API调用或跳转到AI配置页面
|
||
}
|
||
|
||
return (
|
||
<div className="container mx-auto py-4 md:py-6 space-y-4 md:space-y-6">
|
||
{/* 页面标题和工具栏 */}
|
||
<div className="flex flex-col md:flex-row md:justify-between md:items-center gap-4">
|
||
<div>
|
||
<h1 className="text-2xl md:text-3xl font-bold">数据中台</h1>
|
||
<p className="text-sm md:text-base text-muted-foreground mt-1">多源数据整合与管理中心</p>
|
||
</div>
|
||
<div className="flex flex-wrap gap-2">
|
||
<Select value={timeRange} onValueChange={setTimeRange}>
|
||
<SelectTrigger className="w-[120px] text-sm">
|
||
<SelectValue placeholder="时间范围" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="today">今日</SelectItem>
|
||
<SelectItem value="week">本周</SelectItem>
|
||
<SelectItem value="month">本月</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
<Button variant="outline" size="icon" className="h-9 w-9 bg-transparent">
|
||
<Upload className="h-4 w-4" />
|
||
</Button>
|
||
<Button variant="outline" size="icon" className="h-9 w-9 bg-transparent">
|
||
<RefreshCw className="h-4 w-4" />
|
||
</Button>
|
||
<Button variant="outline" size="sm" className="hidden md:flex bg-transparent">
|
||
<Download className="mr-2 h-4 w-4" />
|
||
导出
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
|
||
<TabsList className="grid w-full grid-cols-4 md:grid-cols-5">
|
||
<TabsTrigger value="overview">概览</TabsTrigger>
|
||
<TabsTrigger value="sources">数据源</TabsTrigger>
|
||
<TabsTrigger value="integration">集成统计</TabsTrigger>
|
||
<TabsTrigger value="quality">数据质量</TabsTrigger>
|
||
<TabsTrigger value="ai-models">AI 模型</TabsTrigger>
|
||
</TabsList>
|
||
|
||
<TabsContent value="overview" className="space-y-6">
|
||
{/* 数据中台概览 */}
|
||
<Collapsible
|
||
open={expandedSections.overview}
|
||
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, overview: open }))}
|
||
>
|
||
<Card className="border-none shadow-md">
|
||
<CollapsibleTrigger className="w-full">
|
||
<CardHeader className="bg-gradient-to-r from-blue-50 to-indigo-50 border-b hover:from-blue-100 hover:to-indigo-100 transition-colors cursor-pointer py-3 md:py-4">
|
||
<div className="flex justify-between items-center">
|
||
<div className="flex items-center gap-3">
|
||
<Database className="h-4 w-4 md:h-5 md:w-5 text-blue-600" />
|
||
<div className="text-left">
|
||
<CardTitle className="text-base md:text-lg">平台概览</CardTitle>
|
||
<CardDescription className="text-xs md:text-sm">数据中台整体运行状况</CardDescription>
|
||
</div>
|
||
</div>
|
||
{expandedSections.overview ? (
|
||
<ChevronDown className="h-4 w-4 md:h-5 md:w-5" />
|
||
) : (
|
||
<ChevronRight className="h-4 w-4 md:h-5 md:w-5" />
|
||
)}
|
||
</div>
|
||
</CardHeader>
|
||
</CollapsibleTrigger>
|
||
<CollapsibleContent>
|
||
<CardContent className="p-4">
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 md:gap-4">
|
||
<div className="bg-blue-50 p-3 rounded-lg text-center">
|
||
<div className="text-lg md:text-2xl font-bold text-blue-600">
|
||
{platformData.overview.totalRecords.toLocaleString()}
|
||
</div>
|
||
<div className="text-xs text-blue-700">总数据量</div>
|
||
</div>
|
||
<div className="bg-green-50 p-3 rounded-lg text-center">
|
||
<div className="text-lg md:text-2xl font-bold text-green-600">
|
||
{platformData.overview.dataSources}
|
||
</div>
|
||
<div className="text-xs text-green-700">数据源</div>
|
||
</div>
|
||
<div className="bg-purple-50 p-3 rounded-lg text-center">
|
||
<div className="text-lg md:text-2xl font-bold text-purple-600">
|
||
{platformData.overview.dataQuality}%
|
||
</div>
|
||
<div className="text-xs text-purple-700">数据质量</div>
|
||
</div>
|
||
<div className="bg-orange-50 p-3 rounded-lg text-center">
|
||
<div className="text-lg md:text-2xl font-bold text-orange-600">
|
||
{platformData.overview.storageUsed}GB
|
||
</div>
|
||
<div className="text-xs text-orange-700">存储使用</div>
|
||
</div>
|
||
</div>
|
||
<div className="mt-4 space-y-3">
|
||
<div>
|
||
<div className="flex justify-between text-sm mb-1">
|
||
<span>存储使用率</span>
|
||
<span>
|
||
{platformData.overview.storageUsed}GB / {platformData.overview.storageTotal}GB
|
||
</span>
|
||
</div>
|
||
<Progress
|
||
value={(platformData.overview.storageUsed / platformData.overview.storageTotal) * 100}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<div className="flex justify-between text-sm mb-1">
|
||
<span>数据质量</span>
|
||
<span>{platformData.overview.dataQuality}%</span>
|
||
</div>
|
||
<Progress value={platformData.overview.dataQuality} />
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</CollapsibleContent>
|
||
</Card>
|
||
</Collapsible>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="sources" className="space-y-6">
|
||
{/* 数据源管理 */}
|
||
<Collapsible
|
||
open={expandedSections.sources}
|
||
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, sources: open }))}
|
||
>
|
||
<Card className="border-none shadow-md">
|
||
<CollapsibleTrigger className="w-full">
|
||
<CardHeader className="bg-gradient-to-r from-green-50 to-emerald-50 border-b hover:from-green-100 hover:to-emerald-100 transition-colors cursor-pointer py-3 md:py-4">
|
||
<div className="flex justify-between items-center">
|
||
<div className="flex items-center gap-3">
|
||
<FileText className="h-4 w-4 md:h-5 md:w-5 text-green-600" />
|
||
<div className="text-left">
|
||
<CardTitle className="text-base md:text-lg">数据源管理</CardTitle>
|
||
<CardDescription className="text-xs md:text-sm">
|
||
数据源连接状态 ({platformData.dataSources.length})
|
||
</CardDescription>
|
||
</div>
|
||
</div>
|
||
{expandedSections.sources ? (
|
||
<ChevronDown className="h-4 w-4 md:h-5 md:w-5" />
|
||
) : (
|
||
<ChevronRight className="h-4 w-4 md:h-5 md:w-5" />
|
||
)}
|
||
</div>
|
||
</CardHeader>
|
||
</CollapsibleTrigger>
|
||
<CollapsibleContent>
|
||
<CardContent className="p-4">
|
||
<div className="space-y-3">
|
||
{platformData.dataSources.map((source, index) => (
|
||
<div key={index} className="bg-white border rounded-lg p-3 md:p-4">
|
||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-3">
|
||
<div className="flex-1">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
{getStatusIcon(source.status)}
|
||
<h3 className="font-medium text-sm md:text-base">{source.name}</h3>
|
||
<Badge className={getStatusColor(source.status)}>{source.status}</Badge>
|
||
<Badge variant="outline" className="text-xs">
|
||
{source.type}
|
||
</Badge>
|
||
</div>
|
||
<p className="text-xs md:text-sm text-gray-600 mb-2">{source.description}</p>
|
||
<div className="flex flex-wrap gap-4 text-xs">
|
||
<span>数据量: {source.records.toLocaleString()}</span>
|
||
<span>最后同步: {source.lastSync}</span>
|
||
<span>质量评分: {source.quality}%</span>
|
||
</div>
|
||
</div>
|
||
<div className="flex flex-col md:items-end gap-2">
|
||
<div className="text-right">
|
||
<div className="text-sm font-bold text-green-600">{source.quality}%</div>
|
||
<div className="text-xs text-gray-500">数据质量</div>
|
||
</div>
|
||
<div className="flex gap-2">
|
||
<Button variant="outline" size="sm" className="bg-transparent">
|
||
<Settings className="h-3 w-3 mr-1" />
|
||
配置
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
className="bg-transparent"
|
||
disabled={!source.aiReady}
|
||
onClick={() => handleConnectToAI(source.name)} // 添加点击事件
|
||
>
|
||
<Brain className="h-3 w-3 mr-1" />
|
||
{source.aiReady ? "连接到AI" : "AI未就绪"}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="mt-3">
|
||
<Progress value={source.quality} className="h-1.5" />
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</CardContent>
|
||
</CollapsibleContent>
|
||
</Card>
|
||
</Collapsible>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="integration" className="space-y-6">
|
||
{/* 数据集成统计 */}
|
||
<Collapsible
|
||
open={expandedSections.integration}
|
||
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, integration: open }))}
|
||
>
|
||
<Card className="border-none shadow-md">
|
||
<CollapsibleTrigger className="w-full">
|
||
<CardHeader className="bg-gradient-to-r from-purple-50 to-pink-50 border-b hover:from-purple-100 hover:to-pink-100 transition-colors cursor-pointer py-3 md:py-4">
|
||
<div className="flex justify-between items-center">
|
||
<div className="flex items-center gap-3">
|
||
<RefreshCw className="h-4 w-4 md:h-5 md:w-5 text-purple-600" />
|
||
<div className="text-left">
|
||
<CardTitle className="text-base md:text-lg">集成统计</CardTitle>
|
||
<CardDescription className="text-xs md:text-sm">数据集成性能指标</CardDescription>
|
||
</div>
|
||
</div>
|
||
{expandedSections.integration ? (
|
||
<ChevronDown className="h-4 w-4 md:h-5 md:w-5" />
|
||
) : (
|
||
<ChevronRight className="h-4 w-4 md:h-5 md:w-5" />
|
||
)}
|
||
</div>
|
||
</CardHeader>
|
||
</CollapsibleTrigger>
|
||
<CollapsibleContent>
|
||
<CardContent className="p-4">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
<div className="bg-blue-50 p-4 rounded-lg">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<Database className="h-4 w-4 text-blue-600" />
|
||
<span className="text-sm font-medium">集成概况</span>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">总集成数</span>
|
||
<span className="text-sm font-bold">{platformData.integrationStats.totalIntegrations}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">活跃集成</span>
|
||
<span className="text-sm font-bold">{platformData.integrationStats.activeIntegrations}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">待处理</span>
|
||
<span className="text-sm font-bold">{platformData.integrationStats.pendingIntegrations}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-green-50 p-4 rounded-lg">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<CheckCircle className="h-4 w-4 text-green-600" />
|
||
<span className="text-sm font-medium">性能指标</span>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">成功率</span>
|
||
<span className="text-sm font-bold">{platformData.integrationStats.successRate}%</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">平均同步时间</span>
|
||
<span className="text-sm font-bold">{platformData.integrationStats.avgSyncTime}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">失败集成</span>
|
||
<span className="text-sm font-bold">{platformData.integrationStats.failedIntegrations}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-purple-50 p-4 rounded-lg">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<Clock className="h-4 w-4 text-purple-600" />
|
||
<span className="text-sm font-medium">实时状态</span>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">最后更新</span>
|
||
<span className="text-sm font-bold">{platformData.overview.lastUpdate}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">同步状态</span>
|
||
<span className="text-sm font-bold text-green-600">{platformData.overview.syncStatus}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-xs text-gray-600">系统负载</span>
|
||
<span className="text-sm font-bold">正常</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</CollapsibleContent>
|
||
</Card>
|
||
</Collapsible>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="quality" className="space-y-6">
|
||
{/* 数据质量监控 */}
|
||
<Collapsible
|
||
open={expandedSections.quality}
|
||
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, quality: open }))}
|
||
>
|
||
<Card className="border-none shadow-md">
|
||
<CollapsibleTrigger className="w-full">
|
||
<CardHeader className="bg-gradient-to-r from-orange-50 to-red-50 border-b hover:from-orange-100 hover:to-red-100 transition-colors cursor-pointer py-3 md:py-4">
|
||
<div className="flex justify-between items-center">
|
||
<div className="flex items-center gap-3">
|
||
<CheckCircle className="h-4 w-4 md:h-5 md:w-5 text-orange-600" />
|
||
<div className="text-left">
|
||
<CardTitle className="text-base md:text-lg">数据质量监控</CardTitle>
|
||
<CardDescription className="text-xs md:text-sm">数据质量多维度评估</CardDescription>
|
||
</div>
|
||
</div>
|
||
{expandedSections.quality ? (
|
||
<ChevronDown className="h-4 w-4 md:h-5 md:w-5" />
|
||
) : (
|
||
<ChevronRight className="h-4 w-4 md:h-5 md:w-5" />
|
||
)}
|
||
</div>
|
||
</CardHeader>
|
||
</CollapsibleTrigger>
|
||
<CollapsibleContent>
|
||
<CardContent className="p-4">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{Object.entries(platformData.dataQuality).map(([key, value], index) => {
|
||
const labels = {
|
||
completeness: "完整性",
|
||
accuracy: "准确性",
|
||
consistency: "一致性",
|
||
timeliness: "及时性",
|
||
validity: "有效性",
|
||
uniqueness: "唯一性",
|
||
}
|
||
|
||
const colors = [
|
||
"bg-blue-50 text-blue-600",
|
||
"bg-green-50 text-green-600",
|
||
"bg-purple-50 text-purple-600",
|
||
"bg-orange-50 text-orange-600",
|
||
"bg-pink-50 text-pink-600",
|
||
"bg-indigo-50 text-indigo-600",
|
||
]
|
||
|
||
return (
|
||
<div key={key} className={`p-4 rounded-lg ${colors[index]}`}>
|
||
<div className="text-center">
|
||
<div className="text-2xl font-bold mb-1">{value}%</div>
|
||
<div className="text-sm">{labels[key as keyof typeof labels]}</div>
|
||
<div className="mt-2">
|
||
<Progress value={value} className="h-1.5" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
</CardContent>
|
||
</CollapsibleContent>
|
||
</Card>
|
||
</Collapsible>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="ai-models" className="space-y-6">
|
||
{/* AI 模型管理 */}
|
||
<AIAnalysisTools />
|
||
</TabsContent>
|
||
</Tabs>
|
||
</div>
|
||
)
|
||
}
|