Files
users/app/user-value/page.tsx
v0 ea95107713 refactor: streamline mobile interface for data analysis focus
Remove settings, optimize mobile layout, highlight data analysis features
Use generic company names, simulate today's timeline, responsive design

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2025-07-19 02:17:17 +00:00

847 lines
37 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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 { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Input } from "@/components/ui/input"
import {
ArrowUpRight,
Download,
Filter,
RefreshCw,
Target,
TrendingUp,
Users,
Layers,
Tag,
BarChart3,
Search,
HelpCircle,
ChevronRight,
ChevronDown,
} from "lucide-react"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"
// 使用通用公司名称和当天时间线的用户数据
const mockUsers = [
{
id: "1",
name: "张明华",
company: "科技创新有限公司",
recency: 1,
frequency: 28,
monetary: 45600,
rfmScore: 95,
level: "高价值",
growth: "+8.5%",
upgradeFromDays: 45,
nextUpgrade: "VIP客户",
upgradeProbability: 85,
lastActive: "今天 14:30",
},
{
id: "2",
name: "李雨婷",
company: "数字营销公司",
recency: 3,
frequency: 22,
monetary: 32800,
rfmScore: 88,
level: "高价值",
growth: "+6.2%",
upgradeFromDays: 28,
nextUpgrade: "白金会员",
upgradeProbability: 78,
lastActive: "今天 13:45",
},
{
id: "3",
name: "王建国",
company: "软件开发工作室",
recency: 2,
frequency: 25,
monetary: 38900,
rfmScore: 91,
level: "高价值",
growth: "+7.8%",
upgradeFromDays: 38,
nextUpgrade: "企业VIP",
upgradeProbability: 82,
lastActive: "今天 12:20",
},
{
id: "4",
name: "刘思琪",
company: "数据分析咨询",
recency: 7,
frequency: 18,
monetary: 25400,
rfmScore: 76,
level: "中高价值",
growth: "+4.1%",
upgradeFromDays: 12,
nextUpgrade: "高价值用户",
upgradeProbability: 68,
lastActive: "今天 11:15",
},
{
id: "5",
name: "陈浩然",
company: "云计算服务商",
recency: 4,
frequency: 20,
monetary: 28700,
rfmScore: 82,
level: "中高价值",
growth: "+5.3%",
upgradeFromDays: 22,
nextUpgrade: "高价值用户",
upgradeProbability: 72,
lastActive: "今天 10:30",
},
{
id: "6",
name: "周欣妍",
company: "用户体验设计",
recency: 12,
frequency: 15,
monetary: 18600,
rfmScore: 65,
level: "中等价值",
growth: "+3.2%",
upgradeFromDays: 8,
nextUpgrade: "中高价值用户",
upgradeProbability: 55,
lastActive: "今天 09:45",
},
{
id: "7",
name: "马志强",
company: "企业解决方案",
recency: 6,
frequency: 16,
monetary: 22100,
rfmScore: 71,
level: "中等价值",
growth: "+4.8%",
upgradeFromDays: 15,
nextUpgrade: "中高价值用户",
upgradeProbability: 61,
lastActive: "今天 08:20",
},
{
id: "8",
name: "赵丽娟",
company: "品牌营销策划",
recency: 15,
frequency: 12,
monetary: 15800,
rfmScore: 58,
level: "中等价值",
growth: "+2.1%",
upgradeFromDays: 5,
nextUpgrade: "中高价值用户",
upgradeProbability: 45,
lastActive: "今天 07:30",
},
]
export default function UserValuePage() {
const [timeRange, setTimeRange] = useState("30days")
const [searchQuery, setSearchQuery] = useState("")
const [showModelDialog, setShowModelDialog] = useState(false)
const [showUpgradeDialog, setShowUpgradeDialog] = useState(false)
const [expandedSections, setExpandedSections] = useState({
overview: true,
model: false,
analysis: true,
upgradePaths: false,
})
const filteredUsers = mockUsers.filter(
(user) =>
user.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
user.company.toLowerCase().includes(searchQuery.toLowerCase()),
)
const getRFMLevelColor = (level: string) => {
switch (level) {
case "高价值":
return "bg-green-100 text-green-800"
case "中高价值":
return "bg-blue-100 text-blue-800"
case "中等价值":
return "bg-yellow-100 text-yellow-800"
case "低价值":
return "bg-gray-100 text-gray-800"
case "流失风险":
return "bg-red-100 text-red-800"
default:
return "bg-gray-100 text-gray-800"
}
}
const toggleSection = (section: string) => {
setExpandedSections((prev) => ({
...prev,
[section]: !prev[section],
}))
}
return (
<div className="container mx-auto p-4 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] md:w-[140px] text-sm">
<SelectValue placeholder="时间范围" />
</SelectTrigger>
<SelectContent>
<SelectItem value="7days">7</SelectItem>
<SelectItem value="30days">30</SelectItem>
<SelectItem value="90days">90</SelectItem>
</SelectContent>
</Select>
<Button variant="outline" size="icon" className="h-9 w-9 bg-transparent">
<Filter 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>
{/* 用户估值概览 */}
<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-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">
<Target 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"></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">
<Card className="bg-gradient-to-br from-green-50 to-emerald-50 border-none shadow-sm">
<CardContent className="p-3 md:p-4">
<div className="flex justify-between items-start">
<div>
<div className="text-xs md:text-sm font-medium text-green-600"></div>
<div className="text-lg md:text-2xl font-bold mt-1 md:mt-2">¥3,248</div>
<div className="text-xs text-green-600 mt-1 flex items-center">
<ArrowUpRight className="h-3 w-3 md:h-4 md:w-4 mr-1" />
+8.2%
</div>
</div>
<div className="bg-green-100 p-1.5 md:p-2 rounded-full">
<Target className="h-3 w-3 md:h-5 md:w-5 text-green-600" />
</div>
</div>
<div className="mt-2 md:mt-3">
<div className="flex justify-between text-xs mb-1">
<span></span>
<span>94%</span>
</div>
<Progress value={94} className="h-1 md:h-1.5 bg-green-100" />
</div>
</CardContent>
</Card>
<Card className="bg-gradient-to-br from-purple-50 to-pink-50 border-none shadow-sm">
<CardContent className="p-3 md:p-4">
<div className="flex justify-between items-start">
<div>
<div className="text-xs md:text-sm font-medium text-purple-600"></div>
<div className="text-lg md:text-2xl font-bold mt-1 md:mt-2">45,678</div>
<div className="text-xs text-green-600 mt-1 flex items-center">
<ArrowUpRight className="h-3 w-3 md:h-4 md:w-4 mr-1" />
+12.3%
</div>
</div>
<div className="bg-purple-100 p-1.5 md:p-2 rounded-full">
<TrendingUp className="h-3 w-3 md:h-5 md:w-5 text-purple-600" />
</div>
</div>
<div className="mt-2 md:mt-3">
<div className="flex justify-between text-xs mb-1">
<span></span>
<span>28.6%</span>
</div>
<Progress value={28.6} className="h-1 md:h-1.5 bg-purple-100" />
</div>
</CardContent>
</Card>
<Card className="bg-gradient-to-br from-blue-50 to-indigo-50 border-none shadow-sm">
<CardContent className="p-3 md:p-4">
<div className="flex justify-between items-start">
<div>
<div className="text-xs md:text-sm font-medium text-blue-600"></div>
<div className="text-lg md:text-2xl font-bold mt-1 md:mt-2">15.8%</div>
<div className="text-xs text-green-600 mt-1 flex items-center">
<ArrowUpRight className="h-3 w-3 md:h-4 md:w-4 mr-1" />
+2.1%
</div>
</div>
<div className="bg-blue-100 p-1.5 md:p-2 rounded-full">
<BarChart3 className="h-3 w-3 md:h-5 md:w-5 text-blue-600" />
</div>
</div>
<div className="mt-2 md:mt-3">
<div className="flex justify-between text-xs mb-1">
<span></span>
<span>11.2%</span>
</div>
<Progress value={141} className="h-1 md:h-1.5 bg-blue-100" />
</div>
</CardContent>
</Card>
<Card className="bg-gradient-to-br from-amber-50 to-yellow-50 border-none shadow-sm">
<CardContent className="p-3 md:p-4">
<div className="flex justify-between items-start">
<div>
<div className="text-xs md:text-sm font-medium text-amber-600"></div>
<div className="text-lg md:text-2xl font-bold mt-1 md:mt-2">12.5%</div>
<div className="text-xs text-green-600 mt-1 flex items-center">
<ArrowUpRight className="h-3 w-3 md:h-4 md:w-4 mr-1" />
+1.8%
</div>
</div>
<div className="bg-amber-100 p-1.5 md:p-2 rounded-full">
<Users className="h-3 w-3 md:h-5 md:w-5 text-amber-600" />
</div>
</div>
<div className="mt-2 md:mt-3">
<div className="flex justify-between text-xs mb-1">
<span></span>
<span>15%</span>
</div>
<Progress value={83} className="h-1 md:h-1.5 bg-amber-100" />
</div>
</CardContent>
</Card>
</div>
</CardContent>
</CollapsibleContent>
</Card>
</Collapsible>
{/* RFM估值模型 */}
<Collapsible
open={expandedSections.model}
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, model: 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">
<BarChart3 className="h-4 w-4 md:h-5 md:w-5 text-blue-600" />
<div className="text-left">
<CardTitle className="flex items-center gap-2 text-base md:text-lg">
RFM估值模型
<Button
variant="ghost"
size="sm"
onClick={(e) => {
e.stopPropagation()
setShowModelDialog(true)
}}
className="h-5 w-5 md:h-6 md:w-6 p-0"
>
<HelpCircle className="h-3 w-3 md:h-4 md:w-4" />
</Button>
</CardTitle>
<CardDescription className="text-xs md:text-sm"></CardDescription>
</div>
</div>
{expandedSections.model ? (
<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-3 gap-4 md:gap-6">
<div className="space-y-2">
<h3 className="font-semibold flex items-center text-sm md:text-base">
<span className="bg-red-100 text-red-800 w-5 h-5 md:w-6 md:h-6 rounded-full flex items-center justify-center mr-2 text-xs md:text-sm">
R
</span>
</h3>
<p className="text-xs md:text-sm text-muted-foreground"></p>
<div className="bg-gray-50 p-2 md:p-3 rounded-md">
<div className="text-xs md:text-sm space-y-1">
<div className="flex justify-between">
<span>1-3</span>
<span className="font-medium">5</span>
</div>
<div className="flex justify-between">
<span>4-7</span>
<span className="font-medium">4</span>
</div>
<div className="flex justify-between">
<span>8-14</span>
<span className="font-medium">3</span>
</div>
<div className="flex justify-between">
<span>15-30</span>
<span className="font-medium">2</span>
</div>
<div className="flex justify-between">
<span>30</span>
<span className="font-medium">1</span>
</div>
</div>
</div>
</div>
<div className="space-y-2">
<h3 className="font-semibold flex items-center text-sm md:text-base">
<span className="bg-green-100 text-green-800 w-5 h-5 md:w-6 md:h-6 rounded-full flex items-center justify-center mr-2 text-xs md:text-sm">
F
</span>
</h3>
<p className="text-xs md:text-sm text-muted-foreground"></p>
<div className="bg-gray-50 p-2 md:p-3 rounded-md">
<div className="text-xs md:text-sm space-y-1">
<div className="flex justify-between">
<span>25/</span>
<span className="font-medium">5</span>
</div>
<div className="flex justify-between">
<span>20-24/</span>
<span className="font-medium">4</span>
</div>
<div className="flex justify-between">
<span>15-19/</span>
<span className="font-medium">3</span>
</div>
<div className="flex justify-between">
<span>10-14/</span>
<span className="font-medium">2</span>
</div>
<div className="flex justify-between">
<span>1-9/</span>
<span className="font-medium">1</span>
</div>
</div>
</div>
</div>
<div className="space-y-2">
<h3 className="font-semibold flex items-center text-sm md:text-base">
<span className="bg-blue-100 text-blue-800 w-5 h-5 md:w-6 md:h-6 rounded-full flex items-center justify-center mr-2 text-xs md:text-sm">
M
</span>
</h3>
<p className="text-xs md:text-sm text-muted-foreground"></p>
<div className="bg-gray-50 p-2 md:p-3 rounded-md">
<div className="text-xs md:text-sm space-y-1">
<div className="flex justify-between">
<span>30000</span>
<span className="font-medium">5</span>
</div>
<div className="flex justify-between">
<span>20000-29999</span>
<span className="font-medium">4</span>
</div>
<div className="flex justify-between">
<span>10000-19999</span>
<span className="font-medium">3</span>
</div>
<div className="flex justify-between">
<span>5000-9999</span>
<span className="font-medium">2</span>
</div>
<div className="flex justify-between">
<span>5000</span>
<span className="font-medium">1</span>
</div>
</div>
</div>
</div>
</div>
<div className="mt-4 md:mt-6">
<h3 className="font-semibold mb-3 text-sm md:text-base">RFM评分等级</h3>
<div className="grid grid-cols-2 md:grid-cols-5 gap-2 md:gap-3">
<div className="bg-green-100 p-2 md:p-3 rounded-md text-center">
<p className="font-medium text-green-800 text-xs md:text-sm"></p>
<p className="text-xs text-green-700">85-100</p>
</div>
<div className="bg-blue-100 p-2 md:p-3 rounded-md text-center">
<p className="font-medium text-blue-800 text-xs md:text-sm"></p>
<p className="text-xs text-blue-700">70-84</p>
</div>
<div className="bg-yellow-100 p-2 md:p-3 rounded-md text-center">
<p className="font-medium text-yellow-800 text-xs md:text-sm"></p>
<p className="text-xs text-yellow-700">55-69</p>
</div>
<div className="bg-gray-100 p-2 md:p-3 rounded-md text-center">
<p className="font-medium text-gray-800 text-xs md:text-sm"></p>
<p className="text-xs text-gray-700">40-54</p>
</div>
<div className="bg-red-100 p-2 md:p-3 rounded-md text-center">
<p className="font-medium text-red-800 text-xs md:text-sm"></p>
<p className="text-xs text-red-700">0-39</p>
</div>
</div>
</div>
</CardContent>
</CollapsibleContent>
</Card>
</Collapsible>
{/* 用户价值分析 */}
<Collapsible
open={expandedSections.analysis}
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, analysis: 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">
<Users 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">
({filteredUsers.length})
</CardDescription>
</div>
</div>
{expandedSections.analysis ? (
<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="mb-4">
<div className="relative w-full md:w-64">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
type="search"
placeholder="搜索用户或公司..."
className="pl-8 text-sm"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
</div>
{/* 移动端卡片布局 */}
<div className="space-y-3 md:hidden">
{filteredUsers.map((user) => (
<div key={user.id} className="bg-white border rounded-lg p-3 space-y-2">
<div className="flex items-center justify-between">
<div>
<p className="font-medium text-sm">{user.name}</p>
<p className="text-xs text-gray-500">{user.company}</p>
</div>
<Badge className={`${getRFMLevelColor(user.level)} text-xs`}>{user.rfmScore}</Badge>
</div>
<div className="grid grid-cols-3 gap-2 text-xs">
<div className="text-center">
<p className="text-gray-500">R值</p>
<p className="font-medium">{user.recency}</p>
</div>
<div className="text-center">
<p className="text-gray-500">F值</p>
<p className="font-medium">{user.frequency}</p>
</div>
<div className="text-center">
<p className="text-gray-500">M值</p>
<p className="font-medium">¥{(user.monetary / 1000).toFixed(0)}K</p>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-xs text-gray-500">{user.lastActive}</span>
<span className="text-xs text-green-600">{user.growth}</span>
</div>
</div>
))}
</div>
{/* 桌面端表格布局 */}
<div className="hidden md:block rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-center">RFM评分</TableHead>
<TableHead className="text-center">R值</TableHead>
<TableHead className="text-center">F值</TableHead>
<TableHead className="text-center">M值</TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredUsers.map((user) => (
<TableRow key={user.id} className="hover:bg-gray-50">
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.company}</TableCell>
<TableCell className="text-center">
<Badge className={`${getRFMLevelColor(user.level)}`}>
{user.rfmScore} ({user.level})
</Badge>
</TableCell>
<TableCell className="text-center">{user.recency}</TableCell>
<TableCell className="text-center">{user.frequency}/</TableCell>
<TableCell className="text-center">¥{user.monetary.toLocaleString()}</TableCell>
<TableCell className="text-right text-green-600">{user.growth}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</CardContent>
</CollapsibleContent>
</Card>
</Collapsible>
{/* 用户升级路径分析 */}
<Collapsible
open={expandedSections.upgradePaths}
onOpenChange={(open) => setExpandedSections((prev) => ({ ...prev, upgradePaths: 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">
<TrendingUp className="h-4 w-4 md:h-5 md:w-5 text-orange-600" />
<div className="text-left">
<CardTitle className="flex items-center gap-2 text-base md:text-lg">
<Button
variant="ghost"
size="sm"
onClick={(e) => {
e.stopPropagation()
setShowUpgradeDialog(true)
}}
className="h-5 w-5 md:h-6 md:w-6 p-0"
>
<HelpCircle className="h-3 w-3 md:h-4 md:w-4" />
</Button>
</CardTitle>
<CardDescription className="text-xs md:text-sm"></CardDescription>
</div>
</div>
{expandedSections.upgradePaths ? (
<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-3 gap-3 md:gap-4 mb-4 md:mb-6">
<Card className="bg-white shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm md:text-lg flex items-center">
<Target className="h-4 w-4 md:h-5 md:w-5 mr-2 text-green-600" />
</CardTitle>
</CardHeader>
<CardContent className="text-xs md:text-sm">
<div className="space-y-1 md:space-y-2">
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">2,345</span>
</div>
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">5,678</span>
</div>
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">1,234</span>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-white shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm md:text-lg flex items-center">
<Layers className="h-4 w-4 md:h-5 md:w-5 mr-2 text-blue-600" />
</CardTitle>
</CardHeader>
<CardContent className="text-xs md:text-sm">
<div className="space-y-1 md:space-y-2">
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">12.5%</span>
</div>
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">28</span>
</div>
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">1,856</span>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-white shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm md:text-lg flex items-center">
<Tag className="h-4 w-4 md:h-5 md:w-5 mr-2 text-purple-600" />
</CardTitle>
</CardHeader>
<CardContent className="text-xs md:text-sm">
<div className="space-y-1 md:space-y-2">
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">¥2.3M</span>
</div>
<div className="flex justify-between items-center">
<span></span>
<span className="font-medium">¥1,245</span>
</div>
<div className="flex justify-between items-center">
<span>ROI提升</span>
<span className="font-medium">35.8%</span>
</div>
</div>
</CardContent>
</Card>
</div>
<div className="space-y-3 md:space-y-4">
<h3 className="text-sm md:text-lg font-medium"></h3>
<div className="space-y-2 md:space-y-3">
{filteredUsers.slice(0, 5).map((user) => (
<div
key={user.id}
className="flex flex-col md:flex-row md:items-center justify-between p-3 md:p-4 border rounded-lg hover:bg-gray-50 space-y-2 md:space-y-0"
>
<div className="flex items-center gap-3 md:gap-4">
<div>
<p className="font-medium text-sm md:text-base">{user.name}</p>
<p className="text-xs md:text-sm text-gray-500">{user.company}</p>
</div>
<Badge className={`${getRFMLevelColor(user.level)} text-xs`}>{user.level}</Badge>
</div>
<div className="flex flex-col md:flex-row items-start md:items-center gap-2 md:gap-4">
<div className="text-left md:text-right">
<p className="text-xs md:text-sm font-medium">: {user.nextUpgrade}</p>
<p className="text-xs text-gray-500">: {user.upgradeProbability}%</p>
</div>
<div className="w-full md:w-24">
<Progress value={user.upgradeProbability} className="h-1.5 md:h-2" />
</div>
<Button variant="outline" size="sm" className="text-xs bg-transparent">
</Button>
</div>
</div>
))}
</div>
</div>
</CardContent>
</CollapsibleContent>
</Card>
</Collapsible>
{/* RFM模型说明对话框 */}
<Dialog open={showModelDialog} onOpenChange={setShowModelDialog}>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle>RFM模型说明</DialogTitle>
<DialogDescription>RFM模型是一种用于客户价值评估的经典方法</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="p-4 bg-blue-50 rounded-lg">
<h4 className="font-medium mb-2">RFM模型</h4>
<p className="text-sm text-gray-600">
RFM模型是一种用于分析客户价值和客户创利能力的重要工具RecencyFrequencyMonetary
</p>
</div>
<div className="p-4 bg-green-50 rounded-lg">
<h4 className="font-medium mb-2">使RFM评分</h4>
<p className="text-sm text-gray-600">
1-5150-100便
</p>
</div>
</div>
</DialogContent>
</Dialog>
{/* 升级路径说明对话框 */}
<Dialog open={showUpgradeDialog} onOpenChange={setShowUpgradeDialog}>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="p-4 bg-purple-50 rounded-lg">
<h4 className="font-medium mb-2"></h4>
<p className="text-sm text-gray-600">
RFM评分
</p>
</div>
<div className="p-4 bg-orange-50 rounded-lg">
<h4 className="font-medium mb-2"></h4>
<p className="text-sm text-gray-600">
RFM中得分较低的
</p>
</div>
</div>
</DialogContent>
</Dialog>
</div>
)
}