Organize project by 5 core modules based on requirement docs. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
951 lines
42 KiB
TypeScript
951 lines
42 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
import { Checkbox } from "@/components/ui/checkbox"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Separator } from "@/components/ui/separator"
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
|
import { Search, Filter, Download, RefreshCw, Play, ArrowRight, Settings } from 'lucide-react'
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog"
|
|
|
|
// 模拟图表组件
|
|
const NetworkGraph = ({ data, title }: { data: any; title: string }) => (
|
|
<div className="w-full h-96 bg-muted/30 rounded-md flex items-center justify-center">
|
|
<div className="text-center">
|
|
<p className="text-muted-foreground">{title}</p>
|
|
<p className="text-sm text-muted-foreground">关联网络图将在这里显示</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
const ScatterPlot = ({ data, title }: { data: any; title: string }) => (
|
|
<div className="w-full h-64 bg-muted/30 rounded-md flex items-center justify-center">
|
|
<div className="text-center">
|
|
<p className="text-muted-foreground">{title}</p>
|
|
<p className="text-sm text-muted-foreground">散点图将在这里显示</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
const HeatMap = ({ data, title }: { data: any; title: string }) => (
|
|
<div className="w-full h-64 bg-muted/30 rounded-md flex items-center justify-center">
|
|
<div className="text-center">
|
|
<p className="text-muted-foreground">{title}</p>
|
|
<p className="text-sm text-muted-foreground">热力图将在这里显示</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
interface CorrelationResult {
|
|
id: string
|
|
field1: string
|
|
field2: string
|
|
correlationCoefficient: number
|
|
significance: number
|
|
sampleSize: number
|
|
createdAt: string
|
|
dataSource: string
|
|
}
|
|
|
|
interface UserSegmentCorrelation {
|
|
id: string
|
|
segment1: string
|
|
segment2: string
|
|
overlapPercentage: number
|
|
uniqueUsers1: number
|
|
uniqueUsers2: number
|
|
commonUsers: number
|
|
}
|
|
|
|
export function DataCorrelationAnalysis() {
|
|
const [activeTab, setActiveTab] = useState("field-correlation")
|
|
const [isCreatingAnalysis, setIsCreatingAnalysis] = useState(false)
|
|
const [selectedFields, setSelectedFields] = useState<string[]>([])
|
|
const [selectedDataSources, setSelectedDataSources] = useState<string[]>([])
|
|
|
|
// 模拟字段列表
|
|
const fields = [
|
|
{ id: "userId", name: "用户ID", type: "string", dataSource: "所有数据源" },
|
|
{ id: "phoneNumber", name: "手机号", type: "string", dataSource: "所有数据源" },
|
|
{ id: "identityNumber", name: "身份证号", type: "string", dataSource: "所有数据源" },
|
|
{ id: "deviceImei", name: "IMEI设备号", type: "string", dataSource: "所有数据源" },
|
|
{ id: "registrationDate", name: "注册时间", type: "datetime", dataSource: "用户数据库" },
|
|
{ id: "lastActiveTime", name: "最后活跃时间", type: "datetime", dataSource: "行为分析平台" },
|
|
{ id: "age", name: "年龄", type: "number", dataSource: "用户数据库" },
|
|
{ id: "gender", name: "性别", type: "string", dataSource: "用户数据库" },
|
|
{ id: "location", name: "地区", type: "string", dataSource: "用户数据库" },
|
|
{ id: "totalSpent", name: "消费总额", type: "number", dataSource: "交易系统" },
|
|
{ id: "purchaseFrequency", name: "购买频率", type: "number", dataSource: "交易系统" },
|
|
{ id: "averageOrderValue", name: "平均订单金额", type: "number", dataSource: "交易系统" },
|
|
{ id: "preferredCategory", name: "偏好类别", type: "string", dataSource: "交易系统" },
|
|
{ id: "loginFrequency", name: "登录频率", type: "number", dataSource: "行为分析平台" },
|
|
{ id: "timeSpentPerSession", name: "单次会话时长", type: "number", dataSource: "行为分析平台" },
|
|
{ id: "clickThroughRate", name: "点击率", type: "number", dataSource: "行为分析平台" },
|
|
{ id: "conversionRate", name: "转化率", type: "number", dataSource: "行为分析平台" },
|
|
{ id: "rfmScore", name: "RFM评分", type: "number", dataSource: "用户价值模型" },
|
|
{ id: "lifetimeValue", name: "生命周期价值", type: "number", dataSource: "用户价值模型" },
|
|
{ id: "churnRisk", name: "流失风险", type: "number", dataSource: "用户价值模型" },
|
|
]
|
|
|
|
// 模拟数据源
|
|
const dataSources = [
|
|
{ id: "all", name: "所有数据源" },
|
|
{ id: "user-db", name: "用户数据库" },
|
|
{ id: "transaction", name: "交易系统" },
|
|
{ id: "behavior", name: "行为分析平台" },
|
|
{ id: "user-value", name: "用户价值模型" },
|
|
]
|
|
|
|
// 模拟用户分群
|
|
const userSegments = [
|
|
{ id: "high-value", name: "高价值用户", count: 12500 },
|
|
{ id: "new-users", name: "新注册用户", count: 45600 },
|
|
{ id: "inactive", name: "非活跃用户", count: 28900 },
|
|
{ id: "potential", name: "潜在高转化用户", count: 18700 },
|
|
{ id: "loyal", name: "忠诚用户", count: 9800 },
|
|
{ id: "risk", name: "流失风险用户", count: 15400 },
|
|
]
|
|
|
|
// 模拟相关性分析结果
|
|
const correlationResults: CorrelationResult[] = [
|
|
{
|
|
id: "corr-1",
|
|
field1: "年龄",
|
|
field2: "消费总额",
|
|
correlationCoefficient: 0.72,
|
|
significance: 0.001,
|
|
sampleSize: 45678,
|
|
createdAt: "2023-07-20 15:30",
|
|
dataSource: "用户数据库 & 交易系统",
|
|
},
|
|
{
|
|
id: "corr-2",
|
|
field1: "登录频率",
|
|
field2: "购买频率",
|
|
correlationCoefficient: 0.85,
|
|
significance: 0.001,
|
|
sampleSize: 38945,
|
|
createdAt: "2023-07-20 15:30",
|
|
dataSource: "行为分析平台 & 交易系统",
|
|
},
|
|
{
|
|
id: "corr-3",
|
|
field1: "单次会话时长",
|
|
field2: "转化率",
|
|
correlationCoefficient: 0.65,
|
|
significance: 0.01,
|
|
sampleSize: 42156,
|
|
createdAt: "2023-07-20 15:30",
|
|
dataSource: "行为分析平台",
|
|
},
|
|
{
|
|
id: "corr-4",
|
|
field1: "地区",
|
|
field2: "偏好类别",
|
|
correlationCoefficient: 0.58,
|
|
significance: 0.05,
|
|
sampleSize: 45678,
|
|
createdAt: "2023-07-20 15:30",
|
|
dataSource: "用户数据库 & 交易系统",
|
|
},
|
|
{
|
|
id: "corr-5",
|
|
field1: "RFM评分",
|
|
field2: "生命周期价值",
|
|
correlationCoefficient: 0.92,
|
|
significance: 0.001,
|
|
sampleSize: 45678,
|
|
createdAt: "2023-07-20 15:30",
|
|
dataSource: "用户价值模型",
|
|
},
|
|
]
|
|
|
|
// 模拟用户分群相关性
|
|
const segmentCorrelations: UserSegmentCorrelation[] = [
|
|
{
|
|
id: "seg-corr-1",
|
|
segment1: "高价值用户",
|
|
segment2: "忠诚用户",
|
|
overlapPercentage: 68.5,
|
|
uniqueUsers1: 12500,
|
|
uniqueUsers2: 9800,
|
|
commonUsers: 6713,
|
|
},
|
|
{
|
|
id: "seg-corr-2",
|
|
segment1: "新注册用户",
|
|
segment2: "潜在高转化用户",
|
|
overlapPercentage: 12.3,
|
|
uniqueUsers1: 45600,
|
|
uniqueUsers2: 18700,
|
|
commonUsers: 5609,
|
|
},
|
|
{
|
|
id: "seg-corr-3",
|
|
segment1: "非活跃用户",
|
|
segment2: "流失风险用户",
|
|
overlapPercentage: 75.2,
|
|
uniqueUsers1: 28900,
|
|
uniqueUsers2: 15400,
|
|
commonUsers: 11581,
|
|
},
|
|
{
|
|
id: "seg-corr-4",
|
|
segment1: "高价值用户",
|
|
segment2: "潜在高转化用户",
|
|
overlapPercentage: 8.7,
|
|
uniqueUsers1: 12500,
|
|
uniqueUsers2: 18700,
|
|
commonUsers: 1088,
|
|
},
|
|
{
|
|
id: "seg-corr-5",
|
|
segment1: "忠诚用户",
|
|
segment2: "流失风险用户",
|
|
overlapPercentage: 2.1,
|
|
uniqueUsers1: 9800,
|
|
uniqueUsers2: 15400,
|
|
commonUsers: 206,
|
|
},
|
|
]
|
|
|
|
const getCorrelationStrength = (coefficient: number) => {
|
|
const absCoefficient = Math.abs(coefficient)
|
|
if (absCoefficient >= 0.8) return "强"
|
|
if (absCoefficient >= 0.5) return "中"
|
|
return "弱"
|
|
}
|
|
|
|
const getCorrelationBadge = (coefficient: number) => {
|
|
const absCoefficient = Math.abs(coefficient)
|
|
if (absCoefficient >= 0.8) {
|
|
return <Badge className="bg-green-100 text-green-800">强相关</Badge>
|
|
}
|
|
if (absCoefficient >= 0.5) {
|
|
return <Badge className="bg-yellow-100 text-yellow-800">中等相关</Badge>
|
|
}
|
|
return <Badge className="bg-gray-100 text-gray-800">弱相关</Badge>
|
|
}
|
|
|
|
const getSignificanceBadge = (significance: number) => {
|
|
if (significance <= 0.001) {
|
|
return <Badge className="bg-green-100 text-green-800">高度显著 (p≤0.001)</Badge>
|
|
}
|
|
if (significance <= 0.01) {
|
|
return <Badge className="bg-green-100 text-green-800">显著 (p≤0.01)</Badge>
|
|
}
|
|
if (significance <= 0.05) {
|
|
return <Badge className="bg-yellow-100 text-yellow-800">边际显著 (p≤0.05)</Badge>
|
|
}
|
|
return <Badge className="bg-red-100 text-red-800">{'不显著 (p>0.05)'}</Badge>
|
|
}
|
|
|
|
const toggleFieldSelection = (fieldId: string) => {
|
|
if (selectedFields.includes(fieldId)) {
|
|
setSelectedFields(selectedFields.filter((id) => id !== fieldId))
|
|
} else {
|
|
setSelectedFields([...selectedFields, fieldId])
|
|
}
|
|
}
|
|
|
|
const toggleDataSourceSelection = (sourceId: string) => {
|
|
if (selectedDataSources.includes(sourceId)) {
|
|
setSelectedDataSources(selectedDataSources.filter((id) => id !== sourceId))
|
|
} else {
|
|
setSelectedDataSources([...selectedDataSources, sourceId])
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<h2 className="text-2xl font-bold">数据关联分析</h2>
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="outline">
|
|
<Download className="mr-2 h-4 w-4" />
|
|
导出分析结果
|
|
</Button>
|
|
<Button onClick={() => setIsCreatingAnalysis(true)}>
|
|
<Play className="mr-2 h-4 w-4" />
|
|
创建新分析
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
|
|
<TabsList>
|
|
<TabsTrigger value="field-correlation">字段相关性</TabsTrigger>
|
|
<TabsTrigger value="segment-correlation">分群相关性</TabsTrigger>
|
|
<TabsTrigger value="user-network">用户关联网络</TabsTrigger>
|
|
<TabsTrigger value="path-analysis">用户路径分析</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="field-correlation" className="space-y-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="flex justify-between items-center">
|
|
<CardTitle>字段相关性分析</CardTitle>
|
|
<div className="flex items-center gap-2">
|
|
<div className="relative">
|
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
<Input type="text" placeholder="搜索字段..." className="pl-8 w-[200px]" />
|
|
</div>
|
|
<Select defaultValue="all">
|
|
<SelectTrigger className="w-[150px]">
|
|
<Filter className="mr-2 h-4 w-4" />
|
|
<SelectValue placeholder="相关性强度" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">所有强度</SelectItem>
|
|
<SelectItem value="strong">强相关</SelectItem>
|
|
<SelectItem value="medium">中等相关</SelectItem>
|
|
<SelectItem value="weak">弱相关</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>字段1</TableHead>
|
|
<TableHead>字段2</TableHead>
|
|
<TableHead>相关系数</TableHead>
|
|
<TableHead>相关强度</TableHead>
|
|
<TableHead>显著性</TableHead>
|
|
<TableHead>样本量</TableHead>
|
|
<TableHead>数据源</TableHead>
|
|
<TableHead className="text-right">操作</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{correlationResults.map((result) => (
|
|
<TableRow key={result.id}>
|
|
<TableCell className="font-medium">{result.field1}</TableCell>
|
|
<TableCell className="font-medium">{result.field2}</TableCell>
|
|
<TableCell>{result.correlationCoefficient.toFixed(2)}</TableCell>
|
|
<TableCell>{getCorrelationBadge(result.correlationCoefficient)}</TableCell>
|
|
<TableCell>{getSignificanceBadge(result.significance)}</TableCell>
|
|
<TableCell>{result.sampleSize.toLocaleString()}</TableCell>
|
|
<TableCell>{result.dataSource}</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="sm">
|
|
查看详情
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>相关性热力图</CardTitle>
|
|
<CardDescription>字段间相关性强度可视化</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<HeatMap data={{}} title="字段相关性热力图" />
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>散点图分析</CardTitle>
|
|
<CardDescription>选择两个字段查看其相关性散点图</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex gap-4">
|
|
<div className="flex-1">
|
|
<Label>X轴字段</Label>
|
|
<Select defaultValue="age">
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="选择字段" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{fields
|
|
.filter((field) => field.type === "number")
|
|
.map((field) => (
|
|
<SelectItem key={field.id} value={field.id}>
|
|
{field.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex-1">
|
|
<Label>Y轴字段</Label>
|
|
<Select defaultValue="totalSpent">
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="选择字段" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{fields
|
|
.filter((field) => field.type === "number")
|
|
.map((field) => (
|
|
<SelectItem key={field.id} value={field.id}>
|
|
{field.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<ScatterPlot data={{}} title="年龄 vs 消费总额" />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="segment-correlation" className="space-y-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="flex justify-between items-center">
|
|
<CardTitle>用户分群相关性分析</CardTitle>
|
|
<Button>创建新分析</Button>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>分群1</TableHead>
|
|
<TableHead>分群2</TableHead>
|
|
<TableHead>重叠率</TableHead>
|
|
<TableHead>分群1用户数</TableHead>
|
|
<TableHead>分群2用户数</TableHead>
|
|
<TableHead>共同用户数</TableHead>
|
|
<TableHead className="text-right">操作</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{segmentCorrelations.map((correlation) => (
|
|
<TableRow key={correlation.id}>
|
|
<TableCell className="font-medium">{correlation.segment1}</TableCell>
|
|
<TableCell className="font-medium">{correlation.segment2}</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center gap-2">
|
|
<span>{correlation.overlapPercentage.toFixed(1)}%</span>
|
|
{correlation.overlapPercentage > 50 ? (
|
|
<Badge className="bg-green-100 text-green-800">高重叠</Badge>
|
|
) : correlation.overlapPercentage > 20 ? (
|
|
<Badge className="bg-yellow-100 text-yellow-800">中等重叠</Badge>
|
|
) : (
|
|
<Badge className="bg-gray-100 text-gray-800">低重叠</Badge>
|
|
)}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>{correlation.uniqueUsers1.toLocaleString()}</TableCell>
|
|
<TableCell>{correlation.uniqueUsers2.toLocaleString()}</TableCell>
|
|
<TableCell>{correlation.commonUsers.toLocaleString()}</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="sm">
|
|
查看详情
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>分群重叠分析</CardTitle>
|
|
<CardDescription>选择两个用户分群查看其重叠情况</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex gap-4">
|
|
<div className="flex-1">
|
|
<Label>分群1</Label>
|
|
<Select defaultValue="high-value">
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="选择分群" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{userSegments.map((segment) => (
|
|
<SelectItem key={segment.id} value={segment.id}>
|
|
{segment.name} ({segment.count.toLocaleString()})
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex-1">
|
|
<Label>分群2</Label>
|
|
<Select defaultValue="loyal">
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="选择分群" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{userSegments.map((segment) => (
|
|
<SelectItem key={segment.id} value={segment.id}>
|
|
{segment.name} ({segment.count.toLocaleString()})
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-6 border rounded-md">
|
|
<div className="flex justify-center items-center">
|
|
<div className="w-32 h-32 rounded-full bg-blue-100 flex items-center justify-center text-blue-800 font-bold text-lg">
|
|
高价值用户
|
|
</div>
|
|
<div className="w-24 h-24 bg-blue-200 mx-4 flex items-center justify-center text-blue-800 font-bold">
|
|
重叠
|
|
<br />
|
|
68.5%
|
|
</div>
|
|
<div className="w-32 h-32 rounded-full bg-green-100 flex items-center justify-center text-green-800 font-bold text-lg">
|
|
忠诚用户
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 text-center">
|
|
<p className="text-sm text-muted-foreground">
|
|
共同用户: 6,713人 | 高价值用户: 12,500人 | 忠诚用户: 9,800人
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="user-network" className="space-y-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>用户关联网络分析</CardTitle>
|
|
<CardDescription>基于多维度标识符的用户关联网络</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<div className="flex gap-2">
|
|
<Select defaultValue="all">
|
|
<SelectTrigger className="w-[150px]">
|
|
<SelectValue placeholder="关联维度" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">所有维度</SelectItem>
|
|
<SelectItem value="id">用户ID</SelectItem>
|
|
<SelectItem value="phone">手机号</SelectItem>
|
|
<SelectItem value="identity">身份证号</SelectItem>
|
|
<SelectItem value="imei">IMEI设备号</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Select defaultValue="high-value">
|
|
<SelectTrigger className="w-[150px]">
|
|
<SelectValue placeholder="用户分群" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">所有用户</SelectItem>
|
|
{userSegments.map((segment) => (
|
|
<SelectItem key={segment.id} value={segment.id}>
|
|
{segment.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Button variant="outline" size="sm">
|
|
<Settings className="mr-2 h-4 w-4" />
|
|
网络设置
|
|
</Button>
|
|
<Button variant="outline" size="sm">
|
|
<RefreshCw className="mr-2 h-4 w-4" />
|
|
刷新
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<NetworkGraph data={{}} title="用户关联网络图" />
|
|
|
|
<div className="flex justify-between items-center">
|
|
<div>
|
|
<h3 className="text-sm font-medium">网络统计</h3>
|
|
<p className="text-xs text-muted-foreground">节点: 1,245 | 连接: 3,567 | 平均连接度: 2.87</p>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Badge className="bg-blue-100 text-blue-800">用户ID</Badge>
|
|
<Badge className="bg-green-100 text-green-800">手机号</Badge>
|
|
<Badge className="bg-purple-100 text-purple-800">身份证号</Badge>
|
|
<Badge className="bg-orange-100 text-orange-800">IMEI设备号</Badge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>关联群组分析</CardTitle>
|
|
<CardDescription>自动检测的用户关联群组</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>群组ID</TableHead>
|
|
<TableHead>用户数</TableHead>
|
|
<TableHead>关联强度</TableHead>
|
|
<TableHead>主要关联维度</TableHead>
|
|
<TableHead>检测时间</TableHead>
|
|
<TableHead className="text-right">操作</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableCell className="font-medium">群组-001</TableCell>
|
|
<TableCell>125</TableCell>
|
|
<TableCell>
|
|
<Badge className="bg-green-100 text-green-800">强</Badge>
|
|
</TableCell>
|
|
<TableCell>手机号, IMEI设备号</TableCell>
|
|
<TableCell>2023-07-20 15:30</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="sm">
|
|
查看详情
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium">群组-002</TableCell>
|
|
<TableCell>87</TableCell>
|
|
<TableCell>
|
|
<Badge className="bg-green-100 text-green-800">强</Badge>
|
|
</TableCell>
|
|
<TableCell>身份证号, 用户ID</TableCell>
|
|
<TableCell>2023-07-20 15:30</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="sm">
|
|
查看详情
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium">群组-003</TableCell>
|
|
<TableCell>215</TableCell>
|
|
<TableCell>
|
|
<Badge className="bg-yellow-100 text-yellow-800">中</Badge>
|
|
</TableCell>
|
|
<TableCell>手机号, 用户ID</TableCell>
|
|
<TableCell>2023-07-20 15:30</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="sm">
|
|
查看详情
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium">群组-004</TableCell>
|
|
<TableCell>56</TableCell>
|
|
<TableCell>
|
|
<Badge className="bg-gray-100 text-gray-800">弱</Badge>
|
|
</TableCell>
|
|
<TableCell>IMEI设备号</TableCell>
|
|
<TableCell>2023-07-20 15:30</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="sm">
|
|
查看详情
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="path-analysis" className="space-y-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>用户路径分析</CardTitle>
|
|
<CardDescription>分析用户在不同系统和渠道间的行为路径</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<div className="flex gap-2">
|
|
<Select defaultValue="registration-to-purchase">
|
|
<SelectTrigger className="w-[200px]">
|
|
<SelectValue placeholder="选择路径类型" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="registration-to-purchase">注册到首次购买</SelectItem>
|
|
<SelectItem value="browse-to-purchase">浏览到购买</SelectItem>
|
|
<SelectItem value="multi-purchase">多次购买路径</SelectItem>
|
|
<SelectItem value="churn-path">用户流失路径</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Select defaultValue="all">
|
|
<SelectTrigger className="w-[150px]">
|
|
<SelectValue placeholder="用户分群" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">所有用户</SelectItem>
|
|
{userSegments.map((segment) => (
|
|
<SelectItem key={segment.id} value={segment.id}>
|
|
{segment.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<Button variant="outline">
|
|
<RefreshCw className="mr-2 h-4 w-4" />
|
|
刷新分析
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="p-4 border rounded-md">
|
|
<div className="flex justify-center items-center">
|
|
<div className="flex flex-col items-center">
|
|
<div className="w-32 h-12 bg-blue-100 rounded-md flex items-center justify-center text-blue-800 font-medium">
|
|
注册
|
|
</div>
|
|
<div className="text-xs text-muted-foreground mt-1">100%</div>
|
|
</div>
|
|
<div className="flex flex-col items-center mx-2">
|
|
<ArrowRight className="h-6 w-6 text-muted-foreground" />
|
|
<div className="text-xs text-muted-foreground">85%</div>
|
|
</div>
|
|
<div className="flex flex-col items-center">
|
|
<div className="w-32 h-12 bg-blue-100 rounded-md flex items-center justify-center text-blue-800 font-medium">
|
|
浏览产品
|
|
</div>
|
|
<div className="text-xs text-muted-foreground mt-1">85%</div>
|
|
</div>
|
|
<div className="flex flex-col items-center mx-2">
|
|
<ArrowRight className="h-6 w-6 text-muted-foreground" />
|
|
<div className="text-xs text-muted-foreground">65%</div>
|
|
</div>
|
|
<div className="flex flex-col items-center">
|
|
<div className="w-32 h-12 bg-blue-100 rounded-md flex items-center justify-center text-blue-800 font-medium">
|
|
加入购物车
|
|
</div>
|
|
<div className="text-xs text-muted-foreground mt-1">55%</div>
|
|
</div>
|
|
<div className="flex flex-col items-center mx-2">
|
|
<ArrowRight className="h-6 w-6 text-muted-foreground" />
|
|
<div className="text-xs text-muted-foreground">40%</div>
|
|
</div>
|
|
<div className="flex flex-col items-center">
|
|
<div className="w-32 h-12 bg-green-100 rounded-md flex items-center justify-center text-green-800 font-medium">
|
|
完成购买
|
|
</div>
|
|
<div className="text-xs text-muted-foreground mt-1">22%</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<h3 className="text-sm font-medium mb-2">路径转化率</h3>
|
|
<div className="space-y-2">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">注册到浏览</span>
|
|
<span className="text-sm">85%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-green-600 h-1.5 rounded-full" style={{ width: "85%" }}></div>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">浏览到加购</span>
|
|
<span className="text-sm">65%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-green-600 h-1.5 rounded-full" style={{ width: "65%" }}></div>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">加购到购买</span>
|
|
<span className="text-sm">40%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-yellow-600 h-1.5 rounded-full" style={{ width: "40%" }}></div>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">总体转化率</span>
|
|
<span className="text-sm">22%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-yellow-600 h-1.5 rounded-full" style={{ width: "22%" }}></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h3 className="text-sm font-medium mb-2">路径流失点</h3>
|
|
<div className="space-y-2">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">注册后未浏览</span>
|
|
<span className="text-sm">15%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-red-600 h-1.5 rounded-full" style={{ width: "15%" }}></div>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">浏览后未加购</span>
|
|
<span className="text-sm">35%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-red-600 h-1.5 rounded-full" style={{ width: "35%" }}></div>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">加购后未购买</span>
|
|
<span className="text-sm">60%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-red-600 h-1.5 rounded-full" style={{ width: "60%" }}></div>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-sm">总体流失率</span>
|
|
<span className="text-sm">78%</span>
|
|
</div>
|
|
<div className="w-full bg-gray-200 rounded-full h-1.5">
|
|
<div className="bg-red-600 h-1.5 rounded-full" style={{ width: "78%" }}></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
</Tabs>
|
|
|
|
{/* 创建分析对话框 */}
|
|
<Dialog open={isCreatingAnalysis} onOpenChange={setIsCreatingAnalysis}>
|
|
<DialogContent className="sm:max-w-[600px]">
|
|
<DialogHeader>
|
|
<DialogTitle>创建新的相关性分析</DialogTitle>
|
|
<DialogDescription>选择要分析的数据字段和数据源</DialogDescription>
|
|
</DialogHeader>
|
|
<div className="space-y-4 py-4">
|
|
<div className="space-y-2">
|
|
<Label>选择数据源</Label>
|
|
<div className="grid grid-cols-2 gap-2">
|
|
{dataSources.map((source) => (
|
|
<div key={source.id} className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id={`source-${source.id}`}
|
|
checked={selectedDataSources.includes(source.id)}
|
|
onCheckedChange={() => toggleDataSourceSelection(source.id)}
|
|
/>
|
|
<Label htmlFor={`source-${source.id}`}>{source.name}</Label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-2">
|
|
<Label>选择要分析的字段</Label>
|
|
<div className="relative">
|
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
<Input type="text" placeholder="搜索字段..." className="pl-8" />
|
|
</div>
|
|
|
|
<div className="h-60 overflow-y-auto border rounded-md p-2">
|
|
{fields.map((field) => (
|
|
<div key={field.id} className="flex items-center space-x-2 py-1">
|
|
<Checkbox
|
|
id={`field-${field.id}`}
|
|
checked={selectedFields.includes(field.id)}
|
|
onCheckedChange={() => toggleFieldSelection(field.id)}
|
|
/>
|
|
<Label htmlFor={`field-${field.id}`} className="flex-1">
|
|
{field.name}
|
|
</Label>
|
|
<span className="text-xs text-muted-foreground">{field.type}</span>
|
|
<Badge variant="outline">{field.dataSource}</Badge>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label>分析设置</Label>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="correlation-method">相关性方法</Label>
|
|
<Select defaultValue="pearson">
|
|
<SelectTrigger id="correlation-method">
|
|
<SelectValue placeholder="选择方法" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="pearson">Pearson相关系数</SelectItem>
|
|
<SelectItem value="spearman">Spearman等级相关</SelectItem>
|
|
<SelectItem value="kendall">Kendall's Tau</SelectItem>
|
|
<SelectItem value="chi-square">卡方检验</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="sample-size">样本大小</Label>
|
|
<Select defaultValue="all">
|
|
<SelectTrigger id="sample-size">
|
|
<SelectValue placeholder="选择样本大小" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">全部数据</SelectItem>
|
|
<SelectItem value="10000">10,000</SelectItem>
|
|
<SelectItem value="50000">50,000</SelectItem>
|
|
<SelectItem value="100000">100,000</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox id="save-result" defaultChecked />
|
|
<Label htmlFor="save-result">保存分析结果</Label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={() => setIsCreatingAnalysis(false)}>
|
|
取消
|
|
</Button>
|
|
<Button onClick={() => setIsCreatingAnalysis(false)}>
|
|
<Play className="mr-2 h-4 w-4" />
|
|
开始分析
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</div>
|
|
)
|
|
}
|