- {qualityChecks.map((check, index) => (
-
-
-
-
- {check.severity === "error" ? "严重" : "警告"}
+
+ {aiModels.map((model) => (
+
+
+
+ {model.name}
+
+ {getStatusIcon(model.status)}
+ {model.status}
-
+
{model.type} 模型
+
+
+
+
+ 准确率
+ {(model.accuracy * 100).toFixed(1)}%
+
+
+
+
+
-
{formatNumber(check.count)}
-
问题数量
+
算法:
+
{model.parameters.algorithm}
-
-
{check.percentage}%
-
占比
+
+ 特征数:
+ {model.parameters.features}
-
- ))}
-
-
-
-
-
+
+
+ 最后训练:
+ {new Date(model.lastTrained).toLocaleString()}
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+
)
}
diff --git a/app/globals.css b/app/globals.css
index 4004786..93849a9 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -4,14 +4,14 @@
@layer base {
:root {
- --background: 0 0% 100%;
+ --background: 240 10% 98%;
--foreground: 240 10% 3.9%;
- --card: 0 0% 100%;
+ --card: 240 10% 100%;
--card-foreground: 240 10% 3.9%;
- --popover: 0 0% 100%;
+ --popover: 240 10% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
- --primary-foreground: 0 0% 98%;
+ --primary-foreground: 240 5.9% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
@@ -23,26 +23,26 @@
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
- --radius: 0.5rem;
+ --radius: 0.75rem;
}
.dark {
--background: 240 10% 3.9%;
- --foreground: 0 0% 98%;
+ --foreground: 240 5.9% 98%;
--card: 240 10% 3.9%;
- --card-foreground: 0 0% 98%;
+ --card-foreground: 240 5.9% 98%;
--popover: 240 10% 3.9%;
- --popover-foreground: 0 0% 98%;
- --primary: 0 0% 98%;
+ --popover-foreground: 240 5.9% 98%;
+ --primary: 240 5.9% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
- --secondary-foreground: 0 0% 98%;
+ --secondary-foreground: 240 5.9% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
- --accent-foreground: 0 0% 98%;
+ --accent-foreground: 240 5.9% 98%;
--destructive: 0 62.8% 30.6%;
- --destructive-foreground: 0 0% 98%;
+ --destructive-foreground: 240 5.9% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
@@ -53,7 +53,140 @@
* {
@apply border-border;
}
+
+ html {
+ @apply scroll-smooth;
+ }
+
body {
- @apply bg-background text-foreground;
+ @apply bg-gradient-to-br from-blue-50 via-white to-purple-50 text-foreground min-h-screen;
+ background-attachment: fixed;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+
+ .dark body {
+ @apply bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900;
+ }
+
+ @media (max-width: 768px) {
+ body {
+ background-attachment: scroll;
+ }
+ }
+}
+
+@layer components {
+ .glass {
+ @apply backdrop-blur-md border border-white/20;
+ background-color: rgba(255, 255, 255, 0.1);
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
+ }
+
+ .glass-light {
+ @apply backdrop-blur-sm border border-white/30;
+ background-color: rgba(255, 255, 255, 0.2);
+ box-shadow: 0 4px 16px 0 rgba(31, 38, 135, 0.2);
+ }
+
+ .glass-heavy {
+ @apply backdrop-blur-xl border border-white/40;
+ background-color: rgba(255, 255, 255, 0.3);
+ box-shadow: 0 16px 64px 0 rgba(31, 38, 135, 0.5);
+ }
+
+ .glass-dark {
+ @apply backdrop-blur-md border border-white/10;
+ background-color: rgba(0, 0, 0, 0.1);
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
+ }
+
+ @media (max-width: 768px) {
+ .glass {
+ @apply backdrop-blur-sm;
+ background-color: rgba(255, 255, 255, 0.15);
+ }
+
+ .glass-light {
+ @apply backdrop-blur-sm;
+ background-color: rgba(255, 255, 255, 0.25);
+ }
+
+ .glass-heavy {
+ @apply backdrop-blur-md;
+ background-color: rgba(255, 255, 255, 0.35);
+ }
+ }
+
+ .glass-card {
+ @apply glass rounded-2xl p-6 transition-all duration-300;
+ }
+
+ .glass-card:hover {
+ background-color: rgba(255, 255, 255, 0.2);
+ }
+
+ @media (max-width: 768px) {
+ .glass-card {
+ @apply p-4 rounded-xl;
+ }
+ }
+
+ .glass-nav {
+ @apply glass-light rounded-2xl transition-all duration-300;
+ }
+
+ .glass-button {
+ @apply glass-light rounded-xl px-4 py-2 transition-all duration-300;
+ }
+
+ .glass-button:hover {
+ background-color: rgba(255, 255, 255, 0.3);
+ transform: scale(1.05);
+ }
+
+ @media (max-width: 768px) {
+ .glass-button {
+ @apply px-6 py-3 text-base;
+ min-height: 44px;
+ }
+ }
+
+ .glass-input {
+ @apply glass-light rounded-xl px-4 py-2 transition-all duration-300;
+ }
+
+ .glass-input:focus {
+ background-color: rgba(255, 255, 255, 0.3);
+ @apply ring-2 ring-white/50;
+ }
+
+ @media (max-width: 768px) {
+ .glass-input {
+ @apply px-4 py-3 text-base;
+ min-height: 44px;
+ }
+ }
+
+ .safe-area-top {
+ padding-top: env(safe-area-inset-top);
+ }
+
+ .safe-area-bottom {
+ padding-bottom: env(safe-area-inset-bottom);
+ }
+
+ .safe-area-left {
+ padding-left: env(safe-area-inset-left);
+ }
+
+ .safe-area-right {
+ padding-right: env(safe-area-inset-right);
+ }
+}
+
+@media (max-width: 768px) {
+ .overflow-scroll {
+ -webkit-overflow-scrolling: touch;
}
}
diff --git a/app/layout.tsx b/app/layout.tsx
index a8a6682..17f5e9d 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -2,7 +2,6 @@ import type React from "react"
import type { Metadata } from "next"
import { Inter } from "next/font/google"
import ClientLayout from "./ClientLayout"
-import "./globals.css"
const inter = Inter({ subsets: ["latin"] })
@@ -19,3 +18,6 @@ export default function RootLayout({
}) {
return
{children}
}
+
+
+import './globals.css'
\ No newline at end of file
diff --git a/app/monitoring/alerts/loading.tsx b/app/monitoring/alerts/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/monitoring/alerts/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/monitoring/alerts/page.tsx b/app/monitoring/alerts/page.tsx
new file mode 100644
index 0000000..8a55e38
--- /dev/null
+++ b/app/monitoring/alerts/page.tsx
@@ -0,0 +1,383 @@
+"use client"
+
+import { useState } from "react"
+import { Card, CardContent } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { Input } from "@/components/ui/input"
+import {
+ Bell,
+ ArrowLeft,
+ Plus,
+ Search,
+ Filter,
+ AlertTriangle,
+ CheckCircle2,
+ Clock,
+ Settings,
+ Trash2,
+ XCircle,
+} from "lucide-react"
+import Link from "next/link"
+import { CreateAlertRuleDialog } from "@/components/dialogs/create-alert-rule-dialog"
+import { AlertRuleSettingsDialog } from "@/components/dialogs/alert-rule-settings-dialog"
+
+const alertRules = [
+ {
+ id: 1,
+ name: "CPU使用率告警",
+ condition: "CPU > 80%",
+ duration: "5分钟",
+ severity: "warning",
+ status: "enabled",
+ triggers: 3,
+ },
+ {
+ id: 2,
+ name: "内存使用率告警",
+ condition: "Memory > 85%",
+ duration: "5分钟",
+ severity: "warning",
+ status: "enabled",
+ triggers: 1,
+ },
+ {
+ id: 3,
+ name: "API延迟告警",
+ condition: "P99 > 200ms",
+ duration: "3分钟",
+ severity: "critical",
+ status: "enabled",
+ triggers: 5,
+ },
+ {
+ id: 4,
+ name: "磁盘空间告警",
+ condition: "Disk > 90%",
+ duration: "10分钟",
+ severity: "critical",
+ status: "enabled",
+ triggers: 0,
+ },
+ {
+ id: 5,
+ name: "服务宕机告警",
+ condition: "Service Down",
+ duration: "1分钟",
+ severity: "critical",
+ status: "enabled",
+ triggers: 0,
+ },
+]
+
+const alertHistory = [
+ {
+ id: 1,
+ rule: "CPU使用率告警",
+ message: "node-04 CPU使用率达到 85%",
+ severity: "warning",
+ status: "active",
+ time: "10分钟前",
+ },
+ {
+ id: 2,
+ rule: "磁盘空间告警",
+ message: "磁盘使用率达到 80%,接近阈值",
+ severity: "warning",
+ status: "active",
+ time: "2小时前",
+ },
+ {
+ id: 3,
+ rule: "API延迟告警",
+ message: "API网关P99延迟达到 250ms",
+ severity: "critical",
+ status: "resolved",
+ time: "1小时前",
+ resolvedAt: "45分钟前",
+ },
+ {
+ id: 4,
+ rule: "内存使用率告警",
+ message: "node-02 内存使用率达到 88%",
+ severity: "warning",
+ status: "resolved",
+ time: "3小时前",
+ resolvedAt: "2小时前",
+ },
+ {
+ id: 5,
+ rule: "服务宕机告警",
+ message: "Redis服务短暂不可用",
+ severity: "critical",
+ status: "resolved",
+ time: "1天前",
+ resolvedAt: "1天前",
+ },
+]
+
+export default function AlertsPage() {
+ const [searchTerm, setSearchTerm] = useState("")
+ const [activeTab, setActiveTab] = useState<"rules" | "history">("history")
+ const [showCreateDialog, setShowCreateDialog] = useState(false)
+ const [showSettingsDialog, setShowSettingsDialog] = useState(false)
+ const [selectedRule, setSelectedRule] = useState<(typeof alertRules)[0] | null>(null)
+
+ const activeAlerts = alertHistory.filter((a) => a.status === "active")
+
+ const handleRuleSettings = (rule: (typeof alertRules)[0]) => {
+ setSelectedRule(rule)
+ setShowSettingsDialog(true)
+ }
+
+ return (
+
+
+ {/* 页面标题 */}
+
+
+
+
+
+ {/* 告警统计 */}
+
+
+
+
+
+
活跃告警
+
{activeAlerts.length}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
告警规则数
+
{alertRules.length}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* 标签页切换 */}
+
+
+
+
+
+ {activeTab === "history" ? (
+ <>
+ {/* 筛选工具栏 */}
+
+
+
+ setSearchTerm(e.target.value)}
+ className="pl-9 bg-white/70"
+ />
+
+
+
+
+ {/* 告警历史列表 */}
+
+ {alertHistory.map((alert) => (
+
+
+
+
+ {alert.status === "active" ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
{alert.rule}
+
+ {alert.severity === "critical" ? "严重" : "警告"}
+
+ {alert.status === "active" ? (
+ 活跃
+ ) : (
+ 已解决
+ )}
+
+
{alert.message}
+
+
+
+
+
{alert.time}
+ {alert.resolvedAt &&
解决于 {alert.resolvedAt}
}
+
+ {alert.status === "active" && (
+
+ )}
+
+
+
+
+ ))}
+
+ >
+ ) : (
+ /* 告警规则列表 */
+
+
+
+
+
+ | 规则名称 |
+ 触发条件 |
+ 持续时间 |
+ 严重程度 |
+ 触发次数 |
+ 状态 |
+ 操作 |
+
+
+
+ {alertRules.map((rule) => (
+
+ | {rule.name} |
+
+ {rule.condition}
+ |
+ {rule.duration} |
+
+
+ {rule.severity === "critical" ? "严重" : "警告"}
+
+ |
+ {rule.triggers} |
+
+ 启用
+ |
+
+
+
+
+
+ |
+
+ ))}
+
+
+
+
+ )}
+
+
+
+
+ )
+}
diff --git a/app/monitoring/business/loading.tsx b/app/monitoring/business/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/monitoring/business/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/monitoring/business/page.tsx b/app/monitoring/business/page.tsx
new file mode 100644
index 0000000..4f6992b
--- /dev/null
+++ b/app/monitoring/business/page.tsx
@@ -0,0 +1,299 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import {
+ TrendingUp,
+ ArrowLeft,
+ Users,
+ Target,
+ DollarSign,
+ Activity,
+ RefreshCw,
+ ArrowUpRight,
+ ArrowDownRight,
+} from "lucide-react"
+import Link from "next/link"
+import {
+ LineChart,
+ Line,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ ResponsiveContainer,
+ PieChart,
+ Pie,
+ Cell,
+} from "recharts"
+
+const kpiData = [
+ { name: "数据接入成功率", value: 99.2, target: 99, unit: "%", trend: "up", change: 0.3 },
+ { name: "标签覆盖率", value: 87.5, target: 85, unit: "%", trend: "up", change: 2.1 },
+ { name: "价值预测准确率", value: 91.8, target: 90, unit: "%", trend: "up", change: 1.2 },
+ { name: "API调用增长", value: 15.2, target: 10, unit: "%", trend: "up", change: 3.5 },
+]
+
+const userTrend = [
+ { date: "12-06", total: 4020000, active: 1250000, new: 12500 },
+ { date: "12-07", total: 4025000, active: 1280000, new: 13200 },
+ { date: "12-08", total: 4030000, active: 1260000, new: 11800 },
+ { date: "12-09", total: 4038000, active: 1320000, new: 14500 },
+ { date: "12-10", total: 4045000, active: 1350000, new: 15200 },
+ { date: "12-11", total: 4052000, active: 1380000, new: 16800 },
+ { date: "12-12", total: 4062000, active: 1420000, new: 18500 },
+]
+
+const valueDistribution = [
+ { name: "S级", value: 328000, percent: 8.1, color: "#f59e0b" },
+ { name: "A级", value: 650000, percent: 16.0, color: "#3b82f6" },
+ { name: "B级", value: 1220000, percent: 30.0, color: "#10b981" },
+ { name: "C级", value: 1180000, percent: 29.1, color: "#8b5cf6" },
+ { name: "D级", value: 684000, percent: 16.8, color: "#6b7280" },
+]
+
+const projectRanking = [
+ { rank: 1, name: "美妆护肤项目", users: 580000, value: 28.5, growth: 12.3 },
+ { rank: 2, name: "母婴亲子项目", users: 420000, value: 22.1, growth: 8.5 },
+ { rank: 3, name: "运动健康项目", users: 380000, value: 18.6, growth: 15.2 },
+ { rank: 4, name: "家居生活项目", users: 320000, value: 15.2, growth: 6.8 },
+ { rank: 5, name: "数码科技项目", users: 280000, value: 12.8, growth: 10.5 },
+]
+
+export default function BusinessPage() {
+ const [totalValue, setTotalValue] = useState(125.8)
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setTotalValue((prev) => prev + Math.random() * 0.01)
+ }, 5000)
+ return () => clearInterval(interval)
+ }, [])
+
+ return (
+
+
+ {/* 页面标题 */}
+
+
+
+
+
+
+
业务指标看板
+
核心业务KPI监控与分析
+
+
+
+
+
+ {/* 核心KPI */}
+
+ {kpiData.map((kpi, i) => (
+
+
+
+
{kpi.name}
+
= kpi.target ? "bg-emerald-100 text-emerald-700" : "bg-amber-100 text-amber-700"
+ }
+ >
+ 目标: {kpi.target}
+ {kpi.unit}
+
+
+
+
+ {kpi.value}
+ {kpi.unit}
+
+
+ {kpi.trend === "up" ?
:
}
+
{kpi.change}%
+
+
+
+
+ ))}
+
+
+ {/* 资产总价值 */}
+
+
+
+
+
数据资产总价值
+
{totalValue.toFixed(2)} 亿
+
+
+
+
+
+
+
+
+
+
+ {/* 用户增长趋势 */}
+
+
+
+
+ 用户增长趋势 (近7天)
+
+
+
+
+
+
+
+
+ `${(v / 10000).toFixed(0)}万`}
+ />
+ [`${(value / 10000).toFixed(1)}万`]}
+ />
+
+
+
+
+
+
+
+
+ {/* 价值等级分布 */}
+
+
+
+
+ 用户价值分布
+
+
+
+
+
+
+
+ `${name} ${percent}%`}
+ >
+ {valueDistribution.map((entry, index) => (
+ |
+ ))}
+
+ [`${(value / 10000).toFixed(1)}万`, "用户数"]} />
+
+
+
+
+ {valueDistribution.map((item, i) => (
+
+
+
+ {item.name}: {(item.value / 10000).toFixed(1)}万
+
+
+ ))}
+
+
+
+
+
+
+ {/* 项目价值排名 */}
+
+
+
+
+ 项目价值排名 Top 5
+
+
+
+
+
+
+
+ | 排名 |
+ 项目名称 |
+ 用户数 |
+ 资产价值 |
+ 环比增长 |
+
+
+
+ {projectRanking.map((project) => (
+
+ |
+
+ {project.rank}
+
+ |
+ {project.name} |
+ {(project.users / 10000).toFixed(1)}万 |
+ {project.value}亿 |
+
+
+
+ {project.growth}%
+
+ |
+
+ ))}
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/monitoring/health/loading.tsx b/app/monitoring/health/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/monitoring/health/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/monitoring/health/page.tsx b/app/monitoring/health/page.tsx
new file mode 100644
index 0000000..a4c0ce4
--- /dev/null
+++ b/app/monitoring/health/page.tsx
@@ -0,0 +1,220 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Card, CardContent, 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 { ArrowLeft, Server, CheckCircle2, AlertTriangle, RefreshCw, Clock } from "lucide-react"
+import Link from "next/link"
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts"
+
+const performanceData = [
+ { time: "5m", p50: 32, p95: 85, p99: 120 },
+ { time: "10m", p50: 35, p95: 88, p99: 125 },
+ { time: "15m", p50: 30, p95: 82, p99: 115 },
+ { time: "20m", p50: 38, p95: 92, p99: 135 },
+ { time: "25m", p50: 33, p95: 86, p99: 122 },
+ { time: "30m", p50: 31, p95: 84, p99: 118 },
+]
+
+const healthChecks = [
+ { name: "数据库连接池", status: "healthy", value: "48/50", description: "活跃连接数" },
+ { name: "Redis缓存", status: "healthy", value: "99.9%", description: "命中率" },
+ { name: "消息队列", status: "healthy", value: "0", description: "积压消息" },
+ { name: "定时任务", status: "healthy", value: "12/12", description: "运行中任务" },
+ { name: "外部API", status: "degraded", value: "95.2%", description: "成功率" },
+ { name: "文件存储", status: "healthy", value: "1.6TB", description: "已使用" },
+]
+
+const nodeStatus = [
+ { id: 1, name: "node-01", role: "Master", cpu: 62, memory: 68, status: "healthy" },
+ { id: 2, name: "node-02", role: "Worker", cpu: 55, memory: 72, status: "healthy" },
+ { id: 3, name: "node-03", role: "Worker", cpu: 48, memory: 65, status: "healthy" },
+ { id: 4, name: "node-04", role: "Worker", cpu: 71, memory: 78, status: "degraded" },
+]
+
+export default function HealthPage() {
+ const [overallHealth, setOverallHealth] = useState(98.5)
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setOverallHealth((prev) => Math.min(100, Math.max(95, prev + (Math.random() - 0.5) * 1)))
+ }, 5000)
+ return () => clearInterval(interval)
+ }, [])
+
+ return (
+
+
+ {/* 页面标题 */}
+
+
+
+
+
+
+
系统健康度
+
服务状态、性能指标与集群监控
+
+
+
+
+
+ {/* 整体健康度 */}
+
+
+
+
+
系统整体健康度
+
{overallHealth.toFixed(1)}%
+
所有核心服务运行正常
+
+
+
+
+
+
+
+
+ {/* 健康检查项 */}
+
+ {healthChecks.map((check, i) => (
+
+
+
+
+
{check.name}
+
{check.value}
+
{check.description}
+
+ {check.status === "healthy" ? (
+
+ ) : (
+
+ )}
+
+
+
+ ))}
+
+
+ {/* 响应时间分布 */}
+
+
+
+
+ API响应时间分布 (最近30分钟)
+
+
+
+
+
+
+
+
+ `${v}ms`} />
+ [`${value}ms`]}
+ />
+
+
+
+
+
+
+
+
+
+
+ {/* 集群节点状态 */}
+
+
+
+
+ 集群节点状态
+
+
+
+
+
+
+
+ | 节点 |
+ 角色 |
+ CPU |
+ 内存 |
+ 状态 |
+
+
+
+ {nodeStatus.map((node) => (
+
+ |
+
+
+ {node.name}
+
+ |
+
+ {node.role}
+ |
+
+
+ |
+
+
+ |
+
+ {node.status === "healthy" ? (
+
+
+ 正常
+
+ ) : (
+
+
+ 降级
+
+ )}
+ |
+
+ ))}
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/monitoring/loading.tsx b/app/monitoring/loading.tsx
new file mode 100644
index 0000000..04cd314
--- /dev/null
+++ b/app/monitoring/loading.tsx
@@ -0,0 +1,17 @@
+import { Skeleton } from "@/components/ui/skeleton"
+
+export default function Loading() {
+ return (
+
+
+
+
+ {[...Array(4)].map((_, i) => (
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/monitoring/page.tsx b/app/monitoring/page.tsx
new file mode 100644
index 0000000..2cf1a85
--- /dev/null
+++ b/app/monitoring/page.tsx
@@ -0,0 +1,381 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Card, CardContent, 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 {
+ Activity,
+ Server,
+ Cpu,
+ HardDrive,
+ Wifi,
+ AlertTriangle,
+ CheckCircle2,
+ Bell,
+ RefreshCw,
+ ArrowRight,
+ TrendingUp,
+} from "lucide-react"
+import Link from "next/link"
+import { XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from "recharts"
+
+// 模拟系统资源数据
+const systemMetrics = [
+ { time: "00:00", cpu: 45, memory: 62, disk: 78, network: 120 },
+ { time: "04:00", cpu: 32, memory: 58, disk: 78, network: 80 },
+ { time: "08:00", cpu: 58, memory: 65, disk: 79, network: 180 },
+ { time: "12:00", cpu: 72, memory: 71, disk: 79, network: 320 },
+ { time: "16:00", cpu: 68, memory: 69, disk: 80, network: 280 },
+ { time: "20:00", cpu: 55, memory: 64, disk: 80, network: 200 },
+]
+
+const recentAlerts = [
+ { id: 1, type: "warning", message: "数据同步任务延迟超过阈值", time: "10分钟前", status: "active" },
+ { id: 2, type: "info", message: "模型训练任务已完成", time: "30分钟前", status: "resolved" },
+ { id: 3, type: "error", message: "API网关响应超时", time: "1小时前", status: "resolved" },
+ { id: 4, type: "warning", message: "磁盘使用率超过80%", time: "2小时前", status: "active" },
+]
+
+const serviceStatus = [
+ { name: "数据接入服务", status: "healthy", uptime: "99.99%", latency: "12ms" },
+ { name: "标签计算引擎", status: "healthy", uptime: "99.95%", latency: "45ms" },
+ { name: "AI推理服务", status: "healthy", uptime: "99.90%", latency: "120ms" },
+ { name: "API网关", status: "degraded", uptime: "99.85%", latency: "85ms" },
+ { name: "数据库集群", status: "healthy", uptime: "99.99%", latency: "8ms" },
+ { name: "缓存服务", status: "healthy", uptime: "99.99%", latency: "2ms" },
+]
+
+export default function MonitoringPage() {
+ const [cpuUsage, setCpuUsage] = useState(65)
+ const [memoryUsage, setMemoryUsage] = useState(68)
+ const [diskUsage, setDiskUsage] = useState(80)
+ const [networkIO, setNetworkIO] = useState(256)
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setCpuUsage((prev) => Math.min(95, Math.max(30, prev + (Math.random() - 0.5) * 10)))
+ setMemoryUsage((prev) => Math.min(90, Math.max(50, prev + (Math.random() - 0.5) * 5)))
+ setNetworkIO((prev) => Math.min(500, Math.max(100, prev + (Math.random() - 0.5) * 50)))
+ }, 3000)
+ return () => clearInterval(interval)
+ }, [])
+
+ return (
+
+
+ {/* 页面标题 */}
+
+
+
系统监控与运营看板
+
实时监控系统健康状态、服务运行和告警信息
+
+
+
+
+
+
+
+
+
+
+ {/* 系统资源概览 */}
+
+
+
+
+
+
80 ? "text-red-600" : cpuUsage > 60 ? "text-amber-600" : "text-emerald-600"}`}
+ >
+ {cpuUsage.toFixed(1)}%
+
+
+
+ 8核 / 16线程
+
+
+
+
+
+
+
+
85 ? "text-red-600" : memoryUsage > 70 ? "text-amber-600" : "text-emerald-600"}`}
+ >
+ {memoryUsage.toFixed(1)}%
+
+
+
+ 54.4GB / 80GB
+
+
+
+
+
+
+
+
85 ? "text-red-600" : "text-amber-600"}`}>
+ {diskUsage}%
+
+
+
+ 1.6TB / 2TB
+
+
+
+
+
+
+
+ 入站: 180MB/s | 出站: 76MB/s
+
+
+
+
+ {/* 功能入口 */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* 系统资源趋势 */}
+
+
+ 系统资源趋势 (24小时)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* 最近告警 */}
+
+
+
+
+
+ 最近告警
+
+
+
+
+
+
+
+
+ {recentAlerts.map((alert) => (
+
+ {alert.type === "error" ? (
+
+ ) : alert.type === "warning" ? (
+
+ ) : (
+
+ )}
+
+
{alert.message}
+
+ {alert.time}
+ {alert.status === "active" ? (
+ 待处理
+ ) : (
+ 已解决
+ )}
+
+
+
+ ))}
+
+
+
+
+
+ {/* 服务状态 */}
+
+
+
+
+ 服务状态
+
+
+
+
+ {serviceStatus.map((service, i) => (
+
+
+
+
+
{service.name}
+
+ 可用性: {service.uptime} | 延迟: {service.latency}
+
+
+
+
+ {service.status === "healthy" ? "正常" : service.status === "degraded" ? "降级" : "故障"}
+
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/app/page.tsx b/app/page.tsx
index 8f4693f..acb0599 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,280 +1,396 @@
"use client"
+
import { useState, useEffect } from "react"
-import { Users, Database, Activity, DollarSign, TrendingUp, Search, ArrowUpRight, Zap } from "lucide-react"
-import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Badge } from "@/components/ui/badge"
-import Link from "next/link"
import {
+ Users,
+ Database,
+ RefreshCw,
+ Activity,
+ Globe,
+ Brain,
+ Tags,
LineChart,
- Line,
- XAxis,
- YAxis,
- CartesianGrid,
- Tooltip,
- ResponsiveContainer,
- PieChart,
- Pie,
- Cell,
-} from "recharts"
+ Package,
+ ArrowUpRight,
+ Zap,
+ Target,
+ CheckCircle,
+} from "lucide-react"
+import { Card, CardContent, 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 { useRouter } from "next/navigation"
+import Link from "next/link"
-// 模拟数据
-const growthData = [
- { month: "1月", users: 3200, value: 420 },
- { month: "2月", users: 3800, value: 480 },
- { month: "3月", users: 4100, value: 520 },
- { month: "4月", users: 4600, value: 580 },
- { month: "5月", users: 5200, value: 650 },
- { month: "6月", users: 5800, value: 720 },
-]
+interface SystemMetrics {
+ dataTaskSuccessRate: number
+ tagCoverageRate: number
+ valuePredictionAccuracy: number
+ apiDailyCallGrowth: number
+}
-const valueDistribution = [
- { name: "S级", value: 5, color: "#8B5CF6" },
- { name: "A级", value: 15, color: "#3B82F6" },
- { name: "B级", value: 35, color: "#10B981" },
- { name: "C级", value: 30, color: "#F59E0B" },
- { name: "D级", value: 15, color: "#EF4444" },
-]
+interface DataFlowStats {
+ totalUsers: number
+ totalProjects: number
+ totalDataSources: number
+ totalTags: number
+ totalModels: number
+ totalApiCalls: number
+}
-const recentActivities = [
- { id: 1, user: "张伟", action: "完成首次购买", time: "2分钟前", type: "purchase" },
- { id: 2, user: "李娜", action: "升级为A级用户", time: "5分钟前", type: "upgrade" },
- { id: 3, user: "王芳", action: "触发流失预警", time: "8分钟前", type: "warning" },
- { id: 4, user: "刘洋", action: "完成问卷调查", time: "12分钟前", type: "survey" },
- { id: 5, user: "陈明", action: "加入VIP计划", time: "15分钟前", type: "vip" },
-]
-
-export default function HomePage() {
+export default function OverviewPage() {
+ const router = useRouter()
const [searchQuery, setSearchQuery] = useState("")
- const [currentTime, setCurrentTime] = useState(new Date())
+ const [isRefreshing, setIsRefreshing] = useState(false)
+ const [lastUpdate, setLastUpdate] = useState(new Date())
+
+ // 核心OKR指标 (按PRD定义)
+ const [metrics, setMetrics] = useState
({
+ dataTaskSuccessRate: 99.7,
+ tagCoverageRate: 82.3,
+ valuePredictionAccuracy: 87.5,
+ apiDailyCallGrowth: 32.8,
+ })
+
+ // 数据流统计
+ const [stats, setStats] = useState({
+ totalUsers: 4028567890,
+ totalProjects: 1256,
+ totalDataSources: 28,
+ totalTags: 1892,
+ totalModels: 15,
+ totalApiCalls: 8956234,
+ })
+
+ // 实时数据流
+ const [dataFlows, setDataFlows] = useState([
+ { source: "存客宝", type: "用户行为", count: 125680, status: "running" },
+ { source: "触客宝", type: "互动数据", count: 89234, status: "running" },
+ { source: "数智员工", type: "账号数据", count: 45678, status: "running" },
+ { source: "外部API", type: "征信数据", count: 12890, status: "waiting" },
+ ])
useEffect(() => {
- const timer = setInterval(() => setCurrentTime(new Date()), 1000)
- return () => clearInterval(timer)
+ const interval = setInterval(() => {
+ // 模拟实时数据更新
+ setStats((prev) => ({
+ ...prev,
+ totalUsers: prev.totalUsers + Math.floor(Math.random() * 1000),
+ totalApiCalls: prev.totalApiCalls + Math.floor(Math.random() * 100),
+ }))
+ setDataFlows((prev) =>
+ prev.map((flow) => ({
+ ...flow,
+ count: flow.count + Math.floor(Math.random() * 100),
+ })),
+ )
+ }, 3000)
+ return () => clearInterval(interval)
}, [])
+ const refreshData = async () => {
+ setIsRefreshing(true)
+ await new Promise((r) => setTimeout(r, 1000))
+ setLastUpdate(new Date())
+ setIsRefreshing(false)
+ }
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ // 5大功能模块快捷入口(按HTML文档重构)
+ const modules = [
+ {
+ title: "数据接入",
+ icon: Database,
+ color: "text-blue-600",
+ bg: "bg-blue-100",
+ href: "/data-ingestion/sources",
+ desc: "数据源管理、清洗规则、任务调度、数据血缘",
+ stats: `${stats.totalDataSources}个数据源`,
+ },
+ {
+ title: "标签画像",
+ icon: Tags,
+ color: "text-green-600",
+ bg: "bg-green-100",
+ href: "/tag-portrait/tags",
+ desc: "标签体系、用户画像、人群圈选",
+ stats: `${stats.totalTags}个标签`,
+ },
+ {
+ title: "AI Agent",
+ icon: Brain,
+ color: "text-purple-600",
+ bg: "bg-purple-100",
+ href: "/ai-agent/chat",
+ desc: "智能对话、AI打标、AI清洗、自然语言查询",
+ stats: "5大AI能力",
+ },
+ {
+ title: "数据输出",
+ icon: Package,
+ color: "text-orange-600",
+ bg: "bg-orange-100",
+ href: "/data-output/packages",
+ desc: "流量包、API市场、数据订阅",
+ stats: `${formatNumber(stats.totalApiCalls)}次调用`,
+ },
+ {
+ title: "系统监控",
+ icon: LineChart,
+ color: "text-cyan-600",
+ bg: "bg-cyan-100",
+ href: "/system/health",
+ desc: "系统健康、告警中心、操作日志",
+ stats: "实时监控",
+ },
+ ]
+
return (
-
- {/* 顶部标题区 */}
-
+
+ {/* Header */}
+
-
数据资产中台
-
- {currentTime.toLocaleDateString("zh-CN", { weekday: "long", year: "numeric", month: "long", day: "numeric" })}
- {" · "}
- {currentTime.toLocaleTimeString("zh-CN")}
-
+
数据驾驶舱
+
私域银行生态数据中枢实时监控
-
-
- setSearchQuery(e.target.value)}
- />
-
-
- {/* 核心指标卡片 */}
-
-
-
- 用户资产总量
-
-
-
- 40.5亿
-
-
-
+20.1%
-
较上月
+ {/* 核心OKR指标 */}
+
+
+
+
+ 数据接入成功率
+ 目标≥99.5%
+ {metrics.dataTaskSuccessRate}%
+
-
-
- 活跃用户
-
-
-
- 2,350万
-
-
-
+18.2%
-
较上月
+
+
+
+ 标签覆盖率
+ 目标≥80%
+ {metrics.tagCoverageRate}%
+
-
-
- 数据处理量
-
-
-
- 125亿条
-
-
-
+32.5%
-
较上月
+
+
+
+ 价值预测准确率
+ 目标≥85%
+ {metrics.valuePredictionAccuracy}%
+
-
-
- 资产总价值
-
-
-
- ¥125.8亿
-
-
-
+45.2%
-
较上月
+
+
+
+ API调用增长
+ 目标≥30%QoQ
+ +{metrics.apiDailyCallGrowth}%
+
- {/* 图表区域 */}
-
-
-
- 用户增长趋势
- 近6个月用户与资产价值变化
+ {/* 用户资产总览 */}
+
+
+
+
+
+
+ 全平台用户资产
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 用户价值分布
- S/A/B/C/D级用户占比
-
-
-
-
- `${name}: ${value}%`}
- >
- {valueDistribution.map((entry, index) => (
- |
- ))}
-
-
-
-
-
- {valueDistribution.map((item) => (
-
- {item.name}: {item.value}%
-
- ))}
+
+
+ {formatNumber(stats.totalUsers)}
+ 总用户数
+
+
+
+
+
{stats.totalProjects.toLocaleString()}
+
项目数
+
+
-
- {/* 底部区域 */}
-
-
-
- 实时动态
- 用户行为实时监控
+ {/* 实时数据流 */}
+
+
+
+
+ 实时数据流入
+
-
-
- {recentActivities.map((activity) => (
-
-
-
- {activity.user.charAt(0)}
-
-
-
{activity.user}
-
{activity.action}
-
+
+ {dataFlows.map((flow, i) => (
+
+
+
+
+
{flow.source}
+
{flow.type}
-
{activity.time}
- ))}
-
-
-
-
-
- 快速入口
- 常用功能快速访问
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
{flow.count.toLocaleString()}
+
条/分钟
+
+
+ ))}
+
+ {/* 5大功能模块入口 */}
+
+
功能模块
+
+ {modules.map((module, index) => (
+
+
+
+
+
+
+ {module.title}
+ {module.desc}
+
+
+
+
+ ))}
+
+
+
+ {/* 系统关联图说明 */}
+
+
+
+
+ 系统关联与数据流向
+
+
+
+
+ {/* 数据流入 */}
+
+
+
+ 数据流入
+
+
+ {[
+ { name: "存客宝", desc: "用户基础信息、交易流水" },
+ { name: "触客宝", desc: "互动行为、活动参与" },
+ { name: "数智员工", desc: "账号信息、粉丝画像" },
+ { name: "外部系统", desc: "征信数据、行业数据" },
+ ].map((item, i) => (
+
+
+
+
{item.name}
+
{item.desc}
+
+
+ ))}
+
+
+
+ {/* 神射手处理 */}
+
+
+
+ 神射手处理
+
+
+ {[
+ { name: "数据治理", desc: "清洗、标准化、质量监控" },
+ { name: "标签计算", desc: "规则/模型/AI标签生成" },
+ { name: "价值评估", desc: "CLV、RFM、流失预测" },
+ { name: "AI洞察", desc: "智能分析、报告生成" },
+ ].map((item, i) => (
+
+
+
+
{item.name}
+
{item.desc}
+
+
+ ))}
+
+
+
+ {/* 服务输出 */}
+
+
+
+ 服务输出
+
+
+ {[
+ { name: "存客宝/触客宝", desc: "画像API、人群包推送" },
+ { name: "数智员工", desc: "账号价值评估API" },
+ { name: "聚宝盆", desc: "核心指标聚合接口" },
+ { name: "外部客户", desc: "行业报告、趋势分析包" },
+ ].map((item, i) => (
+
+
+
+
{item.name}
+
{item.desc}
+
+
+ ))}
+
+
+
+
+
)
}
diff --git a/app/platform/ai-assistant/data-analysis/page.tsx b/app/platform/ai-assistant/data-analysis/page.tsx
new file mode 100644
index 0000000..ea555c2
--- /dev/null
+++ b/app/platform/ai-assistant/data-analysis/page.tsx
@@ -0,0 +1,175 @@
+"use client"
+
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { BarChart3, TrendingUp, Users, Download, RefreshCw } from 'lucide-react'
+import { BarChart, Bar, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'
+
+export default function DataAnalysis() {
+ const userBehaviorData = [
+ { hour: '00:00', active: 1250, purchases: 85, interactions: 4200 },
+ { hour: '04:00', active: 850, purchases: 35, interactions: 1800 },
+ { hour: '08:00', active: 5600, purchases: 420, interactions: 18500 },
+ { hour: '12:00', active: 8900, purchases: 680, interactions: 28600 },
+ { hour: '16:00', active: 7200, purchases: 520, interactions: 22400 },
+ { hour: '20:00', active: 9500, purchases: 750, interactions: 32800 },
+ ]
+
+ const channelData = [
+ { name: '微信朋友圈', value: 35, color: '#8b5cf6' },
+ { name: '微信群', value: 28, color: '#3b82f6' },
+ { name: '一对一私聊', value: 22, color: '#10b981' },
+ { name: '小程序', value: 15, color: '#f59e0b' },
+ ]
+
+ const conversionData = [
+ { stage: '浏览', users: 100000, rate: 100 },
+ { stage: '兴趣', users: 45000, rate: 45 },
+ { stage: '咨询', users: 18000, rate: 18 },
+ { stage: '下单', users: 5400, rate: 5.4 },
+ { stage: '复购', users: 1620, rate: 1.6 },
+ ]
+
+ return (
+
+
+
+
数据分析
+
用户行为分析、渠道分析与转化漏斗
+
+
+
+
+ 刷新数据
+
+
+
+ 导出报告
+
+
+
+
+ {/* 关键指标 */}
+
+
+
+ 今日活跃用户
+
+
+ 285.6K
+ +12.5%
+
+
+
+
+ 转化率
+
+
+ 5.4%
+ +0.8%
+
+
+
+
+ 人均互动次数
+
+
+ 8.6
+ +1.2
+
+
+
+
+ 客单价
+
+
+ ¥328
+ +15.2%
+
+
+
+
+ {/* 用户行为趋势 */}
+
+
+
+
+
+ 用户活跃时段分布
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 渠道分布
+
+
+
+
+
+ `${name} ${value}%`}
+ outerRadius={100}
+ fill="#8884d8"
+ dataKey="value"
+ >
+ {channelData.map((entry, index) => (
+ |
+ ))}
+
+
+
+
+
+
+
+
+ {/* 转化漏斗 */}
+
+
+
+
+ 用户转化漏斗
+
+
+
+
+ {conversionData.map((stage, index) => (
+
+
+
{stage.stage}
+
+ {stage.users.toLocaleString()}人
+ {stage.rate}%
+
+
+
+ {stage.rate}%
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/ai-assistant/page.tsx b/app/platform/ai-assistant/page.tsx
new file mode 100644
index 0000000..d0a0bda
--- /dev/null
+++ b/app/platform/ai-assistant/page.tsx
@@ -0,0 +1,236 @@
+"use client"
+
+import Link from "next/link"
+import { useState } from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Textarea } from "@/components/ui/textarea"
+import { Cpu, BarChart3, TrendingUp, Users, Target, Brain, ArrowRight, Send, Sparkles } from 'lucide-react'
+
+export default function AIAssistant() {
+ const [message, setMessage] = useState("")
+ const [chatHistory, setChatHistory] = useState([
+ {
+ role: "assistant",
+ content: "你好!我是神射手AI助手,可以帮助你分析用户数据、生成报告、预测趋势。有什么我可以帮助你的吗?",
+ timestamp: "10:30",
+ },
+ ])
+
+ // AI功能卡片
+ const aiFeatures = [
+ {
+ icon: ,
+ title: "数据分析",
+ description: "自动分析用户行为,生成洞察报告",
+ color: "from-blue-500 to-cyan-500",
+ href: "/platform/ai-assistant/data-analysis",
+ stats: { reports: 1258, insights: 856 }
+ },
+ {
+ icon: ,
+ title: "趋势预测",
+ description: "预测用户行为和价值变化趋势",
+ color: "from-purple-500 to-pink-500",
+ href: "/platform/ai-assistant/trend-prediction",
+ stats: { accuracy: 94.2, predictions: 2450 }
+ },
+ {
+ icon: ,
+ title: "用户画像",
+ description: "智能生成用户群体画像",
+ color: "from-green-500 to-emerald-500",
+ href: "/platform/ai-assistant/user-profiling",
+ stats: { profiles: 4285, segments: 128 }
+ },
+ {
+ icon: ,
+ title: "精准推荐",
+ description: "推荐最佳营销策略和用户群",
+ color: "from-orange-500 to-red-500",
+ href: "/platform/ai-assistant/recommendation",
+ stats: { campaigns: 586, conversion: 18.5 }
+ },
+ ]
+
+ // 快捷问题
+ const quickQuestions = [
+ "分析今日新增用户特征",
+ "预测本月用户增长趋势",
+ "高价值用户流失预警",
+ "生成本周运营报告",
+ ]
+
+ const handleSend = () => {
+ if (!message.trim()) return
+
+ setChatHistory([
+ ...chatHistory,
+ {
+ role: "user",
+ content: message,
+ timestamp: new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }),
+ },
+ {
+ role: "assistant",
+ content: "正在分析您的问题,请稍候...",
+ timestamp: new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }),
+ },
+ ])
+ setMessage("")
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
+
+
AI智能助手
+
数据分析、报告生成与智能预测
+
+
+
+
+
+ {/* AI状态 */}
+
+
+
+
+ AI运行状态
+
+
+
+
+
+
+ 模型版本
+ v3.5
+
+
+ 响应速度
+ 0.8s
+
+
+ 准确率
+ 94.2%
+
+
+
+
+
+ {/* AI功能卡片 */}
+
+ {aiFeatures.map((feature, index) => (
+
+
+
+
+
+ {feature.icon}
+
+
+
+
{feature.description}
+
+
+
+ {Object.entries(feature.stats).map(([key, value], i) => (
+
+
{key === 'reports' ? '报告数' : key === 'insights' ? '洞察数' : key === 'accuracy' ? '准确率' : key === 'predictions' ? '预测数' : key === 'profiles' ? '画像数' : key === 'segments' ? '分组数' : key === 'campaigns' ? '活动数' : '转化率'}
+
+ {typeof value === 'number' && value % 1 !== 0 ? `${value}%` : value}
+
+
+ ))}
+
+
+
+
+ ))}
+
+
+ {/* 对话区域 */}
+
+
+
+
+
+ AI对话
+
+
+
+ {/* 聊天历史 */}
+
+ {chatHistory.map((chat, index) => (
+
+
+
{chat.content}
+
{chat.timestamp}
+
+
+ ))}
+
+
+ {/* 快捷问题 */}
+
+ {quickQuestions.map((question, index) => (
+ setMessage(question)}
+ className="bg-white/5 border-white/10 hover:bg-white/10 text-xs"
+ >
+
+ {question}
+
+ ))}
+
+
+ {/* 输入框 */}
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/platform/ai-assistant/recommendation/page.tsx b/app/platform/ai-assistant/recommendation/page.tsx
new file mode 100644
index 0000000..a690485
--- /dev/null
+++ b/app/platform/ai-assistant/recommendation/page.tsx
@@ -0,0 +1,313 @@
+"use client"
+
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Target, Users, TrendingUp, Zap, Download, RefreshCw, ArrowRight } from 'lucide-react'
+
+export default function Recommendation() {
+ const recommendedCampaigns = [
+ {
+ id: 1,
+ title: '美妆新品推广',
+ targetGroup: '高净值女性用户',
+ userCount: 856780,
+ expectedRevenue: 12850000,
+ probability: 82,
+ roi: 3.5,
+ timeframe: '未来7天',
+ actions: ['朋友圈广告', '私聊推送', '限时优惠'],
+ priority: 'high'
+ },
+ {
+ id: 2,
+ title: '会员升级计划',
+ targetGroup: '活跃普通会员',
+ userCount: 1285670,
+ expectedRevenue: 8560000,
+ probability: 75,
+ roi: 4.2,
+ timeframe: '未来15天',
+ actions: ['会员权益推广', '专属优惠', 'VIP体验券'],
+ priority: 'high'
+ },
+ {
+ id: 3,
+ title: '沉默用户唤醒',
+ targetGroup: '30天未活跃用户',
+ userCount: 2856780,
+ expectedRevenue: 5680000,
+ probability: 58,
+ roi: 2.8,
+ timeframe: '未来30天',
+ actions: ['优惠券发放', '新品预告', '个性化推荐'],
+ priority: 'medium'
+ },
+ {
+ id: 4,
+ title: '交叉销售',
+ targetGroup: '单品类购买用户',
+ userCount: 1714283,
+ expectedRevenue: 9280000,
+ probability: 68,
+ roi: 3.1,
+ timeframe: '未来14天',
+ actions: ['关联商品推荐', '搭配优惠', '场景营销'],
+ priority: 'medium'
+ },
+ ]
+
+ const recommendedSegments = [
+ {
+ name: '高转化潜力群体',
+ count: 428567,
+ conversion: 35.8,
+ value: 580,
+ characteristics: ['近期浏览频繁', '价格接受度高', '品牌认知强']
+ },
+ {
+ name: '复购价值用户',
+ count: 856780,
+ conversion: 28.5,
+ value: 420,
+ characteristics: ['首购满意度高', '客单价适中', '活跃度稳定']
+ },
+ {
+ name: '裂变传播节点',
+ count: 285670,
+ conversion: 22.3,
+ value: 320,
+ characteristics: ['社交影响力大', '分享意愿强', '粉丝基数高']
+ },
+ ]
+
+ const contentRecommendations = [
+ {
+ type: '朋友圈内容',
+ theme: '新品上市+限时优惠',
+ targetUsers: 2856780,
+ expectedEngagement: 18.5,
+ bestTime: '20:00-22:00'
+ },
+ {
+ type: '私聊话术',
+ theme: '专属VIP权益介绍',
+ targetUsers: 856780,
+ expectedEngagement: 42.8,
+ bestTime: '10:00-12:00'
+ },
+ {
+ type: '社群活动',
+ theme: '用户互动+抽奖',
+ targetUsers: 1285670,
+ expectedEngagement: 32.5,
+ bestTime: '周末 15:00-17:00'
+ },
+ ]
+
+ const getPriorityColor = (priority: string) => {
+ return priority === 'high' ? 'border-red-500 text-red-600 bg-red-50' : 'border-yellow-500 text-yellow-600 bg-yellow-50'
+ }
+
+ return (
+
+
+
+
精准推荐
+
AI智能推荐营销策略、目标用户群与内容方案
+
+
+
+
+ 刷新推荐
+
+
+
+ 导出方案
+
+
+
+
+ {/* 核心指标 */}
+
+
+
+ 推荐方案数
+
+
+ 586
+ 本月生成
+
+
+
+
+ 平均转化率
+
+
+ 18.5%
+ +3.2%
+
+
+
+
+ 预计收益
+
+
+ ¥36.4M
+ 近期方案
+
+
+
+
+ 平均ROI
+
+
+ 3.4x
+ 投入产出比
+
+
+
+
+ {/* 推荐营销方案 */}
+
+
+
+
+ 推荐营销方案
+
+
+
+
+ {recommendedCampaigns.map((campaign) => (
+
+
+
+
+
{campaign.title}
+
+ {campaign.priority === 'high' ? '高优先级' : '中优先级'}
+
+
+ {campaign.timeframe}
+
+
+
目标群体: {campaign.targetGroup}
+
+
+ 执行方案
+
+
+
+
+
+
+
目标用户数
+
{campaign.userCount.toLocaleString()}
+
+
+
预期收益
+
¥{(campaign.expectedRevenue / 10000).toFixed(1)}万
+
+
+
成功概率
+
{campaign.probability}%
+
+
+
预期ROI
+
{campaign.roi}x
+
+
+
+
+
推荐动作
+
+ {campaign.actions.map((action, index) => (
+
+
+ {action}
+
+ ))}
+
+
+
+ ))}
+
+
+
+
+ {/* 推荐目标群体 */}
+
+ {recommendedSegments.map((segment, index) => (
+
+
+ {segment.name}
+
+
+
+
+ 用户数
+ {segment.count.toLocaleString()}
+
+
+ 预期转化率
+ {segment.conversion}%
+
+
+ 人均价值
+ ¥{segment.value}
+
+
+
+
群体特征
+
+ {segment.characteristics.map((char, i) => (
+
+ {char}
+
+ ))}
+
+
+
+
+ ))}
+
+
+ {/* 内容推荐 */}
+
+
+
+
+ 内容推荐
+
+
+
+
+ {contentRecommendations.map((content, index) => (
+
+
+
+
{content.type}
+
{content.theme}
+
+
+ 最佳时间: {content.bestTime}
+
+
+
+
+ 目标触达:
+ {content.targetUsers.toLocaleString()} 人
+
+
+ 预期互动率:
+ {content.expectedEngagement}%
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/ai-assistant/trend-prediction/page.tsx b/app/platform/ai-assistant/trend-prediction/page.tsx
new file mode 100644
index 0000000..7258dfb
--- /dev/null
+++ b/app/platform/ai-assistant/trend-prediction/page.tsx
@@ -0,0 +1,222 @@
+"use client"
+
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { TrendingUp, TrendingDown, AlertCircle, Download, RefreshCw } from 'lucide-react'
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from 'recharts'
+
+export default function TrendPrediction() {
+ const userGrowthPrediction = [
+ { date: '2024-06', actual: 428, predicted: null },
+ { date: '2024-07', actual: null, predicted: 445 },
+ { date: '2024-08', actual: null, predicted: 468 },
+ { date: '2024-09', actual: null, predicted: 495 },
+ { date: '2024-10', actual: null, predicted: 528 },
+ { date: '2024-11', actual: null, predicted: 565 },
+ { date: '2024-12', actual: null, predicted: 608 },
+ ]
+
+ const valuePrediction = [
+ { date: '2024-06', actual: 125.8, predicted: null },
+ { date: '2024-07', actual: null, predicted: 132.5 },
+ { date: '2024-08', actual: null, predicted: 141.2 },
+ { date: '2024-09', actual: null, predicted: 151.8 },
+ { date: '2024-10', actual: null, predicted: 164.5 },
+ { date: '2024-11', actual: null, predicted: 179.2 },
+ { date: '2024-12', actual: null, predicted: 196.5 },
+ ]
+
+ const churnRiskData = [
+ { segment: '高价值用户', risk: 8.5, count: 1285, trend: 'down' },
+ { segment: 'VIP用户', risk: 12.3, count: 856, trend: 'stable' },
+ { segment: '活跃用户', risk: 18.6, count: 12856, trend: 'up' },
+ { segment: '沉默用户', risk: 45.8, count: 28560, trend: 'up' },
+ ]
+
+ const opportunityData = [
+ { name: '新品推广机会', potential: '¥85.6M', probability: 78, timeframe: '未来30天' },
+ { name: '复购唤醒', potential: '¥56.2M', probability: 65, timeframe: '未来15天' },
+ { name: '会员升级', potential: '¥38.5M', probability: 82, timeframe: '未来7天' },
+ { name: '交叉销售', potential: '¥92.8M', probability: 58, timeframe: '未来45天' },
+ ]
+
+ return (
+
+
+
+
趋势预测
+
用户增长预测、价值预测与流失预警
+
+
+
+
+ 重新预测
+
+
+
+ 导出报告
+
+
+
+
+ {/* 预测指标 */}
+
+
+
+ 下月预测用户数
+
+
+ 445M
+ +3.9% 增长
+
+
+
+
+ 下月预测价值
+
+
+ ¥132.5亿
+ +5.3% 增长
+
+
+
+
+ 流失风险用户
+
+
+ 42.5K
+ 需重点关注
+
+
+
+
+ 预测准确率
+
+
+ 94.2%
+ 基于历史数据
+
+
+
+
+ {/* 趋势图表 */}
+
+
+
+
+
+ 用户增长预测
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 资产价值预测
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* 流失风险预警 */}
+
+
+
+
+ 流失风险预警
+
+
+
+
+ {churnRiskData.map((item, index) => (
+
+
+
+
{item.segment}
+
{item.count.toLocaleString()} 用户
+
+
+
+
+ {item.trend === 'down' ? (
+
+ ) : item.trend === 'up' ? (
+
+ ) : (
+
+ )}
+
+
+ ))}
+
+
+
+
+ {/* 商机预测 */}
+
+
+
+
+ 商机预测
+
+
+
+
+ {opportunityData.map((item, index) => (
+
+
+
{item.name}
+
+ {item.timeframe}
+
+
+
+
+
预测收益
+
{item.potential}
+
+
+
成功概率
+
{item.probability}%
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/ai-assistant/user-profiling/page.tsx b/app/platform/ai-assistant/user-profiling/page.tsx
new file mode 100644
index 0000000..5e50949
--- /dev/null
+++ b/app/platform/ai-assistant/user-profiling/page.tsx
@@ -0,0 +1,239 @@
+"use client"
+
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Users, Tag, Download, RefreshCw, TrendingUp } from 'lucide-react'
+import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar } from 'recharts'
+
+export default function UserProfiling() {
+ const ageDistribution = [
+ { range: '18-25', count: 856780, percentage: 20 },
+ { range: '26-35', count: 1500000, percentage: 35 },
+ { range: '36-45', count: 1285670, percentage: 30 },
+ { range: '46-55', count: 428567, percentage: 10 },
+ { range: '55+', count: 214284, percentage: 5 },
+ ]
+
+ const behaviorProfile = [
+ { aspect: '消费能力', value: 85 },
+ { aspect: '活跃度', value: 72 },
+ { aspect: '互动频率', value: 68 },
+ { aspect: '忠诚度', value: 78 },
+ { aspect: '推荐意愿', value: 62 },
+ { aspect: '复购率', value: 75 },
+ ]
+
+ const segments = [
+ {
+ name: '高净值群体',
+ count: 1284567,
+ characteristics: ['消费能力强', '忠诚度高', '品牌认知强'],
+ value: 580,
+ color: 'purple'
+ },
+ {
+ name: '年轻潮流族',
+ count: 2856780,
+ characteristics: ['追求时尚', '社交活跃', '冲动消费'],
+ value: 280,
+ color: 'blue'
+ },
+ {
+ name: '理性消费者',
+ count: 4285670,
+ characteristics: ['价格敏感', '重视品质', '对比研究'],
+ value: 180,
+ color: 'green'
+ },
+ {
+ name: '价格敏感型',
+ count: 1714283,
+ characteristics: ['促销驱动', '低频复购', '优惠敏感'],
+ value: 85,
+ color: 'yellow'
+ },
+ ]
+
+ const interestTags = [
+ { tag: '美妆护肤', count: 2856780, heat: 95 },
+ { tag: '时尚穿搭', count: 2145680, heat: 88 },
+ { tag: '健康养生', count: 1856780, heat: 76 },
+ { tag: '数码科技', count: 1428567, heat: 72 },
+ { tag: '母婴育儿', count: 1285670, heat: 68 },
+ { tag: '美食烹饪', count: 985670, heat: 58 },
+ { tag: '运动健身', count: 856780, heat: 52 },
+ { tag: '旅游出行', count: 714283, heat: 45 },
+ ]
+
+ return (
+
+
+
+
用户画像
+
智能分析用户群体特征与行为偏好
+
+
+
+
+ 重新分析
+
+
+
+ 导出画像
+
+
+
+
+ {/* 核心指标 */}
+
+
+
+ 用户群体数
+
+
+ 128
+ 覆盖42.8亿用户
+
+
+
+
+ 标签覆盖率
+
+
+ 87.5%
+ 优秀
+
+
+
+
+ 画像完整度
+
+
+ 92.3%
+ 优秀
+
+
+
+
+ 更新频率
+
+
+ 实时
+ 每小时更新
+
+
+
+
+ {/* 年龄分布与行为画像 */}
+
+
+
+
+
+ 年龄分布
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 行为画像
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* 用户群体细分 */}
+
+
+
+
+ 用户群体细分
+
+
+
+
+ {segments.map((segment, index) => (
+
+
+
{segment.name}
+
+ {segment.count.toLocaleString()} 人
+
+
+
+ {segment.characteristics.map((char, i) => (
+
+ {char}
+
+ ))}
+
+
+ 人均价值: ¥{segment.value}
+
+
+ ))}
+
+
+
+
+ {/* 兴趣标签热度 */}
+
+
+
+
+ 兴趣标签热度
+
+
+
+
+ {interestTags.map((item, index) => (
+
+
+
+
{item.tag}
+
+ {item.count.toLocaleString()} 人
+ 热度 {item.heat}
+
+
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/dashboard/page.tsx b/app/platform/dashboard/page.tsx
new file mode 100644
index 0000000..53a8b04
--- /dev/null
+++ b/app/platform/dashboard/page.tsx
@@ -0,0 +1,399 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Users, TrendingUp, Database, Activity, Zap, DollarSign, BarChart3, RefreshCw, AlertCircle, CheckCircle2, Clock, ArrowUpRight, ArrowDownRight, Cpu, HardDrive, Globe, Shield } from 'lucide-react'
+import { Progress } from "@/components/ui/progress"
+import { LineChart, Line, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'
+
+export default function PlatformDashboard() {
+ const [refreshing, setRefreshing] = useState(false)
+ const [lastUpdate, setLastUpdate] = useState(new Date())
+
+ const monthlyData = [
+ { month: '1月', users: 3.85, value: 98.5 },
+ { month: '2月', users: 3.92, value: 102.5 },
+ { month: '3月', users: 4.05, value: 108.5 },
+ { month: '4月', users: 4.12, value: 114.2 },
+ { month: '5月', users: 4.21, value: 119.8 },
+ { month: '6月', users: 4.29, value: 125.8 },
+ ]
+
+ const levelData = [
+ { name: 'S级', value: 3.0, color: '#8b5cf6' },
+ { name: 'A级', value: 11.0, color: '#3b82f6' },
+ { name: 'B级', value: 25.0, color: '#10b981' },
+ { name: 'C级', value: 40.0, color: '#f59e0b' },
+ { name: 'D级', value: 21.0, color: '#9ca3af' },
+ ]
+
+ // 模拟真实平台数据
+ const platformStats = {
+ totalUsers: 4285670000, // 42.8亿用户
+ totalProjects: 156, // 156个项目
+ totalEnterprises: 48, // 48家企业
+ totalWeChatAccounts: 892, // 892个微信号
+ dataCoverage: 87.3, // 数据覆盖率
+ assetValue: 12580000000, // 125.8亿资产价值
+ todayGrowth: 2845000, // 今日新增用户
+ activeRate: 68.5, // 活跃率
+ aiModelStatus: "running", // AI运行状态
+ dataSync: 94.2, // 数据同步进度
+ }
+
+ // 项目分布数据
+ const projectDistribution = [
+ { name: "美妆行业", projects: 42, users: 1285000000, value: 3850000000, growth: 12.5 },
+ { name: "教育培训", projects: 28, users: 856000000, value: 2280000000, growth: 8.3 },
+ { name: "电商零售", projects: 35, users: 1124000000, value: 3560000000, growth: 15.2 },
+ { name: "金融服务", projects: 18, users: 624000000, value: 1950000000, growth: 6.8 },
+ { name: "其他行业", projects: 33, users: 396670000, value: 940000000, growth: 4.2 },
+ ]
+
+ // 价值评分分布 (S/A/B/C/D级)
+ const valueDistribution = [
+ { level: "S", count: 128456700, percentage: 3.0, avgValue: 580, color: "bg-purple-500" },
+ { level: "A", count: 471424550, percentage: 11.0, avgValue: 320, color: "bg-blue-500" },
+ { level: "B", count: 1071416750, percentage: 25.0, avgValue: 180, color: "bg-green-500" },
+ { level: "C", count: 1714283500, percentage: 40.0, avgValue: 85, color: "bg-yellow-500" },
+ { level: "D", count: 900088500, percentage: 21.0, avgValue: 25, color: "bg-gray-400" },
+ ]
+
+ // AI模型运行数据
+ const aiModels = [
+ { name: "数据清洗模型", status: "running", accuracy: 96.8, processedToday: 2845000, avgTime: 1.2 },
+ { name: "用户标签模型", status: "running", accuracy: 94.5, processedToday: 2845000, avgTime: 0.8 },
+ { name: "价值预测模型", status: "running", accuracy: 91.2, processedToday: 1580000, avgTime: 2.5 },
+ { name: "流失预警模型", status: "training", accuracy: 88.9, processedToday: 0, avgTime: 0 },
+ ]
+
+ // 数据流转实时状态
+ const dataFlow = {
+ incoming: 4250, // 每秒接入数据
+ processing: 3890, // 每秒处理数据
+ outgoing: 3650, // 每秒输出数据
+ queueSize: 12580, // 队列大小
+ }
+
+ const refreshData = async () => {
+ setRefreshing(true)
+ // 模拟刷新延迟
+ await new Promise((resolve) => setTimeout(resolve, 1000))
+ setLastUpdate(new Date())
+ setRefreshing(false)
+ }
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(1)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ const formatCurrency = (num: number): string => {
+ if (num >= 100000000) return `${(num / 100000000).toFixed(1)}亿`
+ if (num >= 10000) return `${(num / 10000).toFixed(1)}万`
+ return num.toString()
+ }
+
+ return (
+
+
+
+
平台总览
+
神射手数据资产中台 - 实时监控
+
+
+
+
+ 系统正常运行
+
+
+
+ 刷新
+
+
+ 最后更新: {lastUpdate.toLocaleTimeString("zh-CN")}
+
+
+
+
+ {/* 核心指标 */}
+
+
+
+
+
+ 用户资产总量
+
+
+
+
+ {formatNumber(platformStats.totalUsers)}
+
+
+
+
+{formatNumber(platformStats.todayGrowth)}
+
今日新增
+
+
+ 活跃率: {platformStats.activeRate}%
+
+
+
+
+
+
+
+
+ 数据资产价值
+
+
+
+
+ ¥{formatCurrency(platformStats.assetValue)}
+
+
+
+ +15.8%
+ 本月增长
+
+
+ 人均价值: ¥{(platformStats.assetValue / platformStats.totalUsers).toFixed(2)}
+
+
+
+
+
+
+
+
+ 项目与企业
+
+
+
+
+
+ 企业数
+ {platformStats.totalEnterprises}
+
+
+ 项目数
+ {platformStats.totalProjects}
+
+
+ 微信号
+ {platformStats.totalWeChatAccounts}
+
+
+
+
+
+
+
+
+
+ AI运行状态
+
+
+
+
+
+
+ 平均准确率
+ 92.9%
+
+
+ 今日处理
+ {formatNumber(7270000)}
+
+
+ 平均耗时
+ 1.2s
+
+
+
+
+
+
+
+
+
+
+
+ 用户增长趋势
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 资产价值趋势
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 价值评分分布
+
+
+
+
+
+ `${name} ${value}%`}
+ outerRadius={80}
+ fill="#8884d8"
+ dataKey="value"
+ >
+ {levelData.map((entry, index) => (
+ |
+ ))}
+
+
+
+
+
+ {valueDistribution.map((item, index) => (
+
+
+ {item.level}
+
+
{formatNumber(item.count)}
+
+ ))}
+
+
+
+
+
+
+
+
+ 数据流转实时状态
+
+
+
+
+
+
+
{dataFlow.incoming}/s
+
+
+
+
+ 数据处理
+
+
{dataFlow.processing}/s
+
+
+
+
{dataFlow.outgoing}/s
+
+
+
+
+ 队列大小
+
+
{dataFlow.queueSize}
+
+
+
+
+
+
+ {/* 项目分布 */}
+
+
+
+
+ 项目运营与企业分布
+
+
+
+
+ {projectDistribution.map((item, index) => (
+
+
+
+
{item.name}
+
+ {item.projects} 项目
+
+
+
+
+
+
+
用户数
+
{formatNumber(item.users)}
+
+
+
资产价值
+
¥{formatCurrency(item.value)}
+
+
+
人均价值
+
¥{(item.value / item.users).toFixed(2)}
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/data-management/page.tsx b/app/platform/data-management/page.tsx
new file mode 100644
index 0000000..4bd9b68
--- /dev/null
+++ b/app/platform/data-management/page.tsx
@@ -0,0 +1,348 @@
+"use client"
+
+import { useState } from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Database, RefreshCw, CheckCircle2, AlertTriangle, Search, FileText, Upload, Download, Filter, TrendingUp, Zap, Tag } from 'lucide-react'
+import { Progress } from "@/components/ui/progress"
+
+export default function DataManagement() {
+ const [searchQuery, setSearchQuery] = useState("")
+
+ // 数据源管理
+ const dataSources = [
+ {
+ id: 1,
+ name: "私域系统数据源",
+ type: "微信生态",
+ status: "active",
+ lastSync: "2分钟前",
+ users: 2850000000,
+ syncRate: 98.5,
+ dataSize: "850TB",
+ },
+ {
+ id: 2,
+ name: "电商平台数据",
+ type: "淘宝/京东",
+ status: "active",
+ lastSync: "5分钟前",
+ users: 680000000,
+ syncRate: 95.2,
+ dataSize: "210TB",
+ },
+ {
+ id: 3,
+ name: "表单收集数据",
+ type: "第三方表单",
+ status: "active",
+ lastSync: "10分钟前",
+ users: 425000000,
+ syncRate: 92.8,
+ dataSize: "125TB",
+ },
+ {
+ id: 4,
+ name: "碰撞补全数据",
+ type: "数据碰撞",
+ status: "syncing",
+ lastSync: "正在同步",
+ users: 280000000,
+ syncRate: 76.3,
+ dataSize: "95TB",
+ },
+ {
+ id: 5,
+ name: "项目API数据源",
+ type: "外部API",
+ status: "active",
+ lastSync: "1分钟前",
+ users: 50670000,
+ syncRate: 99.1,
+ dataSize: "18TB",
+ },
+ ]
+
+ // 数据清洗进度
+ const cleaningTasks = [
+ { name: "手机号格式校验", total: 4285670000, processed: 4200000000, progress: 98.0, errors: 1250000 },
+ { name: "重复数据去除", total: 4285670000, processed: 3850000000, progress: 89.8, errors: 85000000 },
+ { name: "缺失字段补全", total: 4285670000, processed: 3250000000, progress: 75.8, errors: 125000000 },
+ { name: "异常值检测", total: 4285670000, processed: 4100000000, progress: 95.7, errors: 8500000 },
+ ]
+
+ // 标签系统统计
+ const tagStats = {
+ totalTags: 1258,
+ systemTags: 485,
+ customTags: 773,
+ activeRules: 2850,
+ todayTagged: 2845000,
+ }
+
+ // 数据质量检测
+ const qualityChecks = [
+ { type: "重复数据", count: 85420000, percentage: 2.0, severity: "warning" },
+ { type: "异常数据", count: 12850000, percentage: 0.3, severity: "error" },
+ { type: "缺失字段", count: 325680000, percentage: 7.6, severity: "warning" },
+ { type: "格式错误", count: 5280000, percentage: 0.12, severity: "error" },
+ ]
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(1)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
数据管理
+
全平台数据源管理、清洗与质量监控
+
+
+
+
+ 上传数据
+
+
+
+ 导出报告
+
+
+
+
+
+
+ 数据源管理
+ 数据清洗
+ 标签系统
+ 质量检测
+
+
+ {/* 数据源管理 */}
+
+ {/* 搜索栏 */}
+
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 bg-white/5 border-white/10"
+ />
+
+
+
+ 筛选
+
+
+
+ {/* 数据源列表 */}
+
+ {dataSources.map((source) => (
+
+
+
+
+
+
+
+
+
{source.name}
+
{source.type}
+
+
+
+
+ {source.status === "active" ? (
+ <>
+
+ 运行中
+ >
+ ) : (
+ <>
+
+ 同步中
+ >
+ )}
+
+
+
+ 同步
+
+
+
+
+
+
+
用户数量
+
{formatNumber(source.users)}
+
+
+
同步率
+
{source.syncRate}%
+
+
+
数据量
+
{source.dataSize}
+
+
+
最后同步
+
{source.lastSync}
+
+
+
+
+
+
+ ))}
+
+
+
+ {/* 数据清洗 */}
+
+
+ {cleaningTasks.map((task, index) => (
+
+
+
+
+ {task.name}
+
+
+
+
+
+ 进度
+ {task.progress}%
+
+
+
+
+
已处理
+
{formatNumber(task.processed)}
+
+
+
异常数据
+
{formatNumber(task.errors)}
+
+
+
+
+
+ ))}
+
+
+
+ {/* 标签系统 */}
+
+
+
+
+
+ {tagStats.totalTags}
+ 标签总数
+
+
+
+
+
+ {tagStats.systemTags}
+ 系统标签
+
+
+
+
+
+ {tagStats.customTags}
+ 自定义标签
+
+
+
+
+
+ {tagStats.activeRules}
+ 活跃规则
+
+
+
+
+
+ {formatNumber(tagStats.todayTagged)}
+ 今日打标
+
+
+
+
+
+
+ 标签管理
+
+
+
+ 标签详细管理界面开发中...
+
+
+
+
+
+ {/* 质量检测 */}
+
+
+ {qualityChecks.map((check, index) => (
+
+
+
+
+ {check.severity === "error" ? (
+
+ ) : (
+
+ )}
+
{check.type}
+
+
+ {check.severity === "error" ? "严重" : "警告"}
+
+
+
+
+ 问题数量
+ {formatNumber(check.count)}
+
+
+ 占比
+ {check.percentage}%
+
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/user-portrait/page.tsx b/app/platform/user-portrait/page.tsx
new file mode 100644
index 0000000..cf52140
--- /dev/null
+++ b/app/platform/user-portrait/page.tsx
@@ -0,0 +1,277 @@
+"use client"
+
+import { useState } from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Users, Search, Tag, TrendingUp, Filter, UserCircle, Mail, Phone, MapPin, Calendar, Activity, Target } from 'lucide-react'
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+
+export default function UserPortrait() {
+ const [searchQuery, setSearchQuery] = useState("")
+
+ // 用户群体分布
+ const userSegments = [
+ { name: "高价值用户", count: 128456700, percentage: 3.0, avgValue: 580, color: "purple" },
+ { name: "活跃用户", count: 1285670000, percentage: 30.0, avgValue: 280, color: "blue" },
+ { name: "沉默用户", count: 1714283500, percentage: 40.0, avgValue: 85, color: "yellow" },
+ { name: "流失预警", count: 857134000, percentage: 20.0, avgValue: 45, color: "orange" },
+ { name: "新增用户", count: 300125800, percentage: 7.0, avgValue: 120, color: "green" },
+ ]
+
+ // 标签分类统计
+ const tagCategories = [
+ { name: "基础属性", count: 485, usage: 4285670000, coverage: 100 },
+ { name: "行为标签", count: 328, usage: 3256780000, coverage: 76 },
+ { name: "兴趣偏好", count: 256, usage: 2570000000, coverage: 60 },
+ { name: "消费能力", count: 89, usage: 1714283500, coverage: 40 },
+ { name: "自定义标签", count: 100, usage: 857134000, coverage: 20 },
+ ]
+
+ // 最近用户示例
+ const recentUsers = [
+ {
+ id: "U001285",
+ name: "张**",
+ phone: "138****5678",
+ level: "S",
+ tags: ["高净值", "美妆爱好者", "VIP客户"],
+ value: 5800,
+ lastActive: "2小时前",
+ },
+ {
+ id: "U002456",
+ name: "李**",
+ phone: "186****1234",
+ level: "A",
+ tags: ["活跃用户", "教育培训", "复购客户"],
+ value: 3200,
+ lastActive: "5小时前",
+ },
+ {
+ id: "U003789",
+ name: "王**",
+ phone: "159****9876",
+ level: "B",
+ tags: ["潜力用户", "电商购物", "新客户"],
+ value: 1800,
+ lastActive: "1天前",
+ },
+ {
+ id: "U004123",
+ name: "赵**",
+ phone: "177****5432",
+ level: "C",
+ tags: ["普通用户", "低频互动"],
+ value: 850,
+ lastActive: "3天前",
+ },
+ ]
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(1)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ const getLevelColor = (level: string) => {
+ const colors = {
+ S: "border-purple-500/50 text-purple-400 bg-purple-500/10",
+ A: "border-blue-500/50 text-blue-400 bg-blue-500/10",
+ B: "border-green-500/50 text-green-400 bg-green-500/10",
+ C: "border-yellow-500/50 text-yellow-400 bg-yellow-500/10",
+ D: "border-gray-500/50 text-gray-400 bg-gray-500/10",
+ }
+ return colors[level as keyof typeof colors] || colors.D
+ }
+
+ const getSegmentColor = (color: string) => {
+ const colors = {
+ purple: "from-purple-500/20 to-purple-900/20 border-purple-500/30",
+ blue: "from-blue-500/20 to-blue-900/20 border-blue-500/30",
+ green: "from-green-500/20 to-green-900/20 border-green-500/30",
+ yellow: "from-yellow-500/20 to-yellow-900/20 border-yellow-500/30",
+ orange: "from-orange-500/20 to-orange-900/20 border-orange-500/30",
+ }
+ return colors[color as keyof typeof colors]
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
用户画像
+
用户管理、标签体系与群体分析
+
+
+
+
+ 高级筛选
+
+
+
+ 创建用户群
+
+
+
+
+
+
+ 用户群体
+ 标签体系
+ 用户列表
+
+
+ {/* 用户群体分布 */}
+
+
+ {userSegments.map((segment, index) => (
+
+
+ {segment.name}
+
+
+
+
{formatNumber(segment.count)}
+
占比 {segment.percentage}%
+
+
人均价值
+
¥{segment.avgValue}
+
+
+
+
+ ))}
+
+
+ {/* 用户增长趋势 */}
+
+
+
+
+ 用户增长趋势
+
+
+
+
+ 用户增长趋势图表区域
+
+
+
+
+
+ {/* 标签体系 */}
+
+
+ {tagCategories.map((category, index) => (
+
+
+
+
+
+
+
+
+
{category.name}
+
{category.count} 个标签
+
+
+
+ 覆盖率 {category.coverage}%
+
+
+
+
+
标签数量
+
{category.count}
+
+
+
使用用户
+
{formatNumber(category.usage)}
+
+
+
覆盖率
+
{category.coverage}%
+
+
+
+
+ ))}
+
+
+
+ {/* 用户列表 */}
+
+ {/* 搜索栏 */}
+
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 bg-white/5 border-white/10"
+ />
+
+
+
+ 筛选
+
+
+
+ {/* 用户卡片列表 */}
+
+ {recentUsers.map((user) => (
+
+
+
+
+
+
+ {user.name[0]}
+
+
+
+
+ {user.name}
+
+ {user.level}级
+
+
+
+
+
+
+
+
+ {user.tags.map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/app/platform/value-assessment/page.tsx b/app/platform/value-assessment/page.tsx
new file mode 100644
index 0000000..4429773
--- /dev/null
+++ b/app/platform/value-assessment/page.tsx
@@ -0,0 +1,322 @@
+"use client"
+
+import { useState } from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { DollarSign, TrendingUp, BarChart3, Calculator, Target, Users, ArrowUpRight, ArrowDownRight } from 'lucide-react'
+import { Progress } from "@/components/ui/progress"
+
+export default function ValueAssessment() {
+ // 价值评估模型数据
+ const valueModels = [
+ {
+ name: "RFM价值模型",
+ description: "基于最近购买、购买频率、购买金额",
+ totalValue: 8560000000,
+ avgValue: 199.8,
+ coverage: 92.5,
+ status: "active",
+ },
+ {
+ name: "用户生命周期价值",
+ description: "预测用户终身价值(LTV)",
+ totalValue: 12580000000,
+ avgValue: 293.5,
+ coverage: 78.3,
+ status: "active",
+ },
+ {
+ name: "行为价值模型",
+ description: "基于用户行为数据评估",
+ totalValue: 6780000000,
+ avgValue: 158.2,
+ coverage: 85.7,
+ status: "training",
+ },
+ ]
+
+ // 项目价值分布
+ const projectValues = [
+ { name: "美妆行业项目A", users: 45600000, value: 2856000000, growth: 15.8, level: "A" },
+ { name: "教育培训项目B", users: 32800000, value: 1968000000, growth: 12.3, level: "A" },
+ { name: "电商零售项目C", users: 58900000, value: 3534000000, growth: 18.5, level: "S" },
+ { name: "金融服务项目D", users: 28500000, value: 1995000000, growth: 8.7, level: "B" },
+ { name: "本地生活项目E", users: 19200000, value: 1152000000, growth: 6.5, level: "B" },
+ ]
+
+ // 微信号价值排名
+ const wechatRanking = [
+ { name: "微信号001", users: 2856000, value: 168560000, avgValue: 59.0, rank: 1 },
+ { name: "微信号002", users: 2345000, value: 145780000, avgValue: 62.2, rank: 2 },
+ { name: "微信号003", users: 1980000, value: 128640000, avgValue: 65.0, rank: 3 },
+ { name: "微信号004", users: 1756000, value: 112340000, avgValue: 64.0, rank: 4 },
+ { name: "微信号005", users: 1520000, value: 95600000, avgValue: 62.9, rank: 5 },
+ ]
+
+ // 价值增长趋势
+ const growthTrend = [
+ { month: "1月", value: 9850000000, growth: 8.5 },
+ { month: "2月", value: 10250000000, growth: 4.1 },
+ { month: "3月", value: 10850000000, growth: 5.9 },
+ { month: "4月", value: 11420000000, growth: 5.3 },
+ { month: "5月", value: 11980000000, growth: 4.9 },
+ { month: "6月", value: 12580000000, growth: 5.0 },
+ ]
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(1)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ const formatCurrency = (num: number): string => {
+ if (num >= 100000000) return `${(num / 100000000).toFixed(1)}亿`
+ if (num >= 10000) return `${(num / 10000).toFixed(1)}万`
+ return num.toString()
+ }
+
+ const getLevelColor = (level: string) => {
+ const colors = {
+ S: "border-purple-500/50 text-purple-400 bg-purple-500/10",
+ A: "border-blue-500/50 text-blue-400 bg-blue-500/10",
+ B: "border-green-500/50 text-green-400 bg-green-500/10",
+ C: "border-yellow-500/50 text-yellow-400 bg-yellow-500/10",
+ D: "border-gray-500/50 text-gray-400 bg-gray-500/10",
+ }
+ return colors[level as keyof typeof colors] || colors.D
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
价值评估
+
用户价值分析、项目价值统计与预测
+
+
+
+
+ 价值计算器
+
+
+
+ 生成报告
+
+
+
+
+ {/* 核心价值指标 */}
+
+
+
+
+
+ 平台总价值
+
+
+
+ ¥{formatCurrency(12580000000)}
+
+
+
+
+
+
+
+
+ 人均价值
+
+
+
+ ¥293.5
+
+
+
+
+
+
+
+
+ 价值覆盖率
+
+
+
+ 85.5%
+ 已评估用户占比
+
+
+
+
+
+
+ 价值模型
+ 项目价值
+ 微信号排名
+ 增长趋势
+
+
+ {/* 价值模型 */}
+
+ {valueModels.map((model, index) => (
+
+
+
+
+
{model.name}
+
{model.description}
+
+
+ {model.status === "active" ? "运行中" : "训练中"}
+
+
+
+
+
+
+
模型总价值
+
¥{formatCurrency(model.totalValue)}
+
+
+
人均价值
+
¥{model.avgValue}
+
+
+
覆盖率
+
{model.coverage}%
+
+
+
+
+
+ ))}
+
+
+ {/* 项目价值 */}
+
+
+ {projectValues.map((project, index) => (
+
+
+
+
+
{project.name}
+
+ {project.level}级项目
+
+
+
+
+
+
+
用户数
+
{formatNumber(project.users)}
+
+
+
项目价值
+
¥{formatCurrency(project.value)}
+
+
+
人均价值
+
+ ¥{(project.value / project.users).toFixed(2)}
+
+
+
+
增长率
+
{project.growth}%
+
+
+
+
+ ))}
+
+
+
+ {/* 微信号排名 */}
+
+
+ {wechatRanking.map((wechat, index) => (
+
+
+
+
+ {wechat.rank}
+
+
+
{wechat.name}
+
{formatNumber(wechat.users)} 用户
+
+
+
¥{formatCurrency(wechat.value)}
+
人均 ¥{wechat.avgValue}
+
+
+
+
+ ))}
+
+
+
+ {/* 增长趋势 */}
+
+
+
+
+
+ 价值增长趋势
+
+
+
+
+ {growthTrend.map((item, index) => (
+
+
+
{item.month}
+
¥{formatCurrency(item.value)}
+
+
+
+ ))}
+
+
+
+
+
+
+ )
+}
diff --git a/app/tag-portrait/crowd/loading.tsx b/app/tag-portrait/crowd/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/tag-portrait/crowd/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/tag-portrait/crowd/page.tsx b/app/tag-portrait/crowd/page.tsx
new file mode 100644
index 0000000..e409f5a
--- /dev/null
+++ b/app/tag-portrait/crowd/page.tsx
@@ -0,0 +1,346 @@
+"use client"
+
+import { useState } from "react"
+import { Target, Plus, Search, Users, Download, Share2, Trash2, Filter, BarChart3, PieChart } from "lucide-react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import { Checkbox } from "@/components/ui/checkbox"
+
+interface CrowdPack {
+ id: string
+ name: string
+ description: string
+ userCount: number
+ rules: string[]
+ createdAt: string
+ updatedAt: string
+ status: "active" | "expired" | "computing"
+ distribution: { label: string; value: number; color: string }[]
+}
+
+const MOCK_CROWDS: CrowdPack[] = [
+ {
+ id: "1",
+ name: "高价值活跃用户",
+ description: "价值评分>80 AND 近7天活跃",
+ userCount: 125678901,
+ rules: ["价值评分 > 80", "最后登录 < 7天", "消费金额 > 1000"],
+ createdAt: "2025-12-10",
+ updatedAt: "2025-12-12",
+ status: "active",
+ distribution: [
+ { label: "25-35岁", value: 45, color: "bg-blue-500" },
+ { label: "35-45岁", value: 30, color: "bg-green-500" },
+ { label: "其他", value: 25, color: "bg-gray-300" },
+ ],
+ },
+ {
+ id: "2",
+ name: "流失预警用户",
+ description: "流失风险>0.7 AND 近30天无消费",
+ userCount: 34567890,
+ rules: ["流失风险 > 0.7", "最后消费 > 30天", "活跃度等级 = 低"],
+ createdAt: "2025-12-08",
+ updatedAt: "2025-12-12",
+ status: "active",
+ distribution: [
+ { label: "一线城市", value: 35, color: "bg-purple-500" },
+ { label: "二线城市", value: 40, color: "bg-orange-500" },
+ { label: "其他", value: 25, color: "bg-gray-300" },
+ ],
+ },
+ {
+ id: "3",
+ name: "新注册潜力用户",
+ description: "注册<30天 AND 有首购",
+ userCount: 8901234,
+ rules: ["注册时间 < 30天", "首购完成 = 是", "消费金额 > 100"],
+ createdAt: "2025-12-05",
+ updatedAt: "2025-12-11",
+ status: "computing",
+ distribution: [
+ { label: "女性", value: 55, color: "bg-pink-500" },
+ { label: "男性", value: 45, color: "bg-blue-500" },
+ ],
+ },
+ {
+ id: "4",
+ name: "品牌忠诚用户",
+ description: "复购率>50% AND 品牌偏好明确",
+ userCount: 56789012,
+ rules: ["复购率 > 50%", "品牌偏好 != 空", "消费频次 > 3次/月"],
+ createdAt: "2025-12-01",
+ updatedAt: "2025-12-10",
+ status: "active",
+ distribution: [
+ { label: "高端消费", value: 60, color: "bg-yellow-500" },
+ { label: "中端消费", value: 30, color: "bg-green-500" },
+ { label: "其他", value: 10, color: "bg-gray-300" },
+ ],
+ },
+]
+
+const AVAILABLE_CONDITIONS = [
+ { category: "用户属性", options: ["性别", "年龄段", "城市等级", "注册时间"] },
+ { category: "行为标签", options: ["活跃度等级", "消费等级", "复购率", "最后登录", "最后消费"] },
+ { category: "价值标签", options: ["价值评分", "RFM评分", "CLV预测值"] },
+ { category: "风险标签", options: ["流失风险", "欺诈风险"] },
+ { category: "AI标签", options: ["品牌偏好", "价格敏感度", "内容偏好"] },
+]
+
+export default function CrowdSelectionPage() {
+ const [crowds, setCrowds] = useState(MOCK_CROWDS)
+ const [searchQuery, setSearchQuery] = useState("")
+ const [isCreating, setIsCreating] = useState(false)
+ const [selectedConditions, setSelectedConditions] = useState([])
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ const totalUsers = crowds.reduce((sum, c) => sum + c.userCount, 0)
+
+ return (
+
+ {/* Header */}
+
+
+
setIsCreating(!isCreating)}
+ className="bg-gradient-to-r from-blue-500 to-purple-500 text-white"
+ >
+
+ 创建人群包
+
+
+
+ {/* Create Panel */}
+ {isCreating && (
+
+
+ 创建人群包
+
+
+
+
+
+
+
+ {AVAILABLE_CONDITIONS.map((group) => (
+
+
{group.category}
+
+ {group.options.map((option) => (
+
+ {
+ if (checked) {
+ setSelectedConditions([...selectedConditions, option])
+ } else {
+ setSelectedConditions(selectedConditions.filter((c) => c !== option))
+ }
+ }}
+ />
+
+
+ ))}
+
+
+ ))}
+
+
+
+ {selectedConditions.length > 0 && (
+
+
+ 已选条件
+ {selectedConditions.length}个
+
+
+ {selectedConditions.map((cond) => (
+
+ {cond}
+ setSelectedConditions(selectedConditions.filter((c) => c !== cond))}
+ className="ml-1 text-gray-400 hover:text-gray-600"
+ >
+ x
+
+
+ ))}
+
+
+ )}
+
+
+ setIsCreating(false)}>
+ 取消
+
+ 预估人数
+ 保存人群包
+
+
+
+ )}
+
+ {/* Stats */}
+
+
+
+
+
+ 人群包数
+
+ {crowds.length}
+
+
+
+
+
+
+ 覆盖用户
+
+ {formatNumber(totalUsers)}
+
+
+
+
+
+
+ 可用条件
+
+
+ {AVAILABLE_CONDITIONS.reduce((sum, g) => sum + g.options.length, 0)}
+
+
+
+
+
+
+
+ 运算中
+
+
+ {crowds.filter((c) => c.status === "computing").length}
+
+
+
+
+
+ {/* Search */}
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 bg-white/60"
+ />
+
+
+ {/* Crowd List */}
+
+ {crowds
+ .filter((c) => c.name.toLowerCase().includes(searchQuery.toLowerCase()))
+ .map((crowd) => (
+
+
+
+
+
+
{crowd.name}
+
+ {crowd.status === "active" ? "生效中" : crowd.status === "computing" ? "计算中" : "已过期"}
+
+
+
{crowd.description}
+
+
+
{formatNumber(crowd.userCount)}
+
用户数
+
+
+
+
+
+ 筛选规则:
+ {crowd.rules.map((rule, i) => (
+
+ {rule}
+
+ ))}
+
+
+
+ {/* Distribution */}
+
+
+ {crowd.distribution.map((d, i) => (
+
+ ))}
+
+
+ {crowd.distribution.map((d, i) => (
+
+
+
+ {d.label} {d.value}%
+
+
+ ))}
+
+
+
+
+
更新于 {crowd.updatedAt}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+ )
+}
diff --git a/app/tag-portrait/page.tsx b/app/tag-portrait/page.tsx
new file mode 100644
index 0000000..152f99a
--- /dev/null
+++ b/app/tag-portrait/page.tsx
@@ -0,0 +1,12 @@
+"use client"
+
+import { useRouter } from "next/navigation"
+import { useEffect } from "react"
+
+export default function TagPortraitPage() {
+ const router = useRouter()
+ useEffect(() => {
+ router.replace("/tag-portrait/tags")
+ }, [router])
+ return null
+}
diff --git a/app/tag-portrait/portrait/loading.tsx b/app/tag-portrait/portrait/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/tag-portrait/portrait/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/tag-portrait/portrait/page.tsx b/app/tag-portrait/portrait/page.tsx
new file mode 100644
index 0000000..be14fa8
--- /dev/null
+++ b/app/tag-portrait/portrait/page.tsx
@@ -0,0 +1,273 @@
+"use client"
+
+import { useState } from "react"
+import { Search, Tags, Activity, TrendingUp, Calendar, MapPin, Phone, Mail, Star } from "lucide-react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import { Progress } from "@/components/ui/progress"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+
+interface UserProfile {
+ id: string
+ name: string
+ avatar: string
+ phone: string
+ email: string
+ city: string
+ registerDate: string
+ lastActive: string
+ tags: { name: string; type: string }[]
+ valueScore: number
+ valueLevel: string
+ rfmScores: { r: number; f: number; m: number }
+ behaviors: { name: string; count: number; trend: string }[]
+ timeline: { date: string; event: string; type: string }[]
+}
+
+const MOCK_USER: UserProfile = {
+ id: "U10086",
+ name: "张明华",
+ avatar: "/professional-chinese-man.jpg",
+ phone: "138****5678",
+ email: "zhang****@qq.com",
+ city: "上海市",
+ registerDate: "2023-05-15",
+ lastActive: "2025-12-12 14:30:00",
+ tags: [
+ { name: "高价值用户", type: "value" },
+ { name: "高复购高客单", type: "behavior" },
+ { name: "品牌忠诚", type: "ai" },
+ { name: "25-35岁", type: "basic" },
+ { name: "一线城市", type: "basic" },
+ { name: "活跃用户", type: "behavior" },
+ { name: "低流失风险", type: "model" },
+ { name: "科技爱好者", type: "ai" },
+ ],
+ valueScore: 92,
+ valueLevel: "S",
+ rfmScores: { r: 95, f: 88, m: 90 },
+ behaviors: [
+ { name: "登录次数", count: 156, trend: "+12%" },
+ { name: "浏览商品", count: 892, trend: "+8%" },
+ { name: "下单次数", count: 45, trend: "+15%" },
+ { name: "分享次数", count: 28, trend: "+5%" },
+ ],
+ timeline: [
+ { date: "2025-12-12 14:30", event: "浏览商品: iPhone 16 Pro", type: "browse" },
+ { date: "2025-12-12 10:15", event: "完成订单: #ORD20251212001", type: "order" },
+ { date: "2025-12-11 18:20", event: "添加收藏: MacBook Pro", type: "favorite" },
+ { date: "2025-12-11 09:00", event: "登录App", type: "login" },
+ { date: "2025-12-10 20:30", event: "分享商品到微信", type: "share" },
+ ],
+}
+
+const TAG_COLORS: Record = {
+ value: "bg-yellow-100 text-yellow-700",
+ behavior: "bg-green-100 text-green-700",
+ ai: "bg-purple-100 text-purple-700",
+ basic: "bg-blue-100 text-blue-700",
+ model: "bg-orange-100 text-orange-700",
+}
+
+const EVENT_COLORS: Record = {
+ browse: "bg-blue-500",
+ order: "bg-green-500",
+ favorite: "bg-yellow-500",
+ login: "bg-gray-500",
+ share: "bg-purple-500",
+}
+
+export default function UserPortraitPage() {
+ const [searchQuery, setSearchQuery] = useState("")
+ const [selectedUser, setSelectedUser] = useState(MOCK_USER)
+
+ const handleSearch = () => {
+ // 模拟搜索
+ console.log("Searching:", searchQuery)
+ }
+
+ return (
+
+ {/* Header */}
+
+
+ {/* Search */}
+
+
+
+ setSearchQuery(e.target.value)}
+ onKeyPress={(e) => e.key === "Enter" && handleSearch()}
+ className="pl-10 bg-white/60"
+ />
+
+
搜索
+
+
+ {/* User Profile Card */}
+
+ {/* Left: Basic Info */}
+
+
+
+
+ {selectedUser.name.charAt(0)}
+
+
+
{selectedUser.name}
+
ID: {selectedUser.id}
+
+
+
+ {selectedUser.valueLevel}级用户
+
+
+
+
+
+
+
+
+
{selectedUser.phone}
+
+
+
+ {selectedUser.email}
+
+
+
+ {selectedUser.city}
+
+
+
+ 注册于 {selectedUser.registerDate}
+
+
+
+
最后活跃 {selectedUser.lastActive}
+
+
+
+ {/* Value Score */}
+
+
+ 用户价值分
+ {selectedUser.valueScore}
+
+
+
+
+
+
+ {/* Middle: Tags & RFM */}
+
+
+
+
+ 用户标签
+
+
+
+
+ {selectedUser.tags.map((tag, i) => (
+
+ {tag.name}
+
+ ))}
+
+
+
+
RFM模型评分
+
+
+
+ R - 最近消费
+ {selectedUser.rfmScores.r}
+
+
+
+
+
+ F - 消费频率
+ {selectedUser.rfmScores.f}
+
+
+
+
+
+ M - 消费金额
+ {selectedUser.rfmScores.m}
+
+
+
+
+
+
+
+
+ {/* Right: Behaviors & Timeline */}
+
+
+
+
+
+ 行为指标
+
+
+ 行为轨迹
+
+
+
+
+ {selectedUser.behaviors.map((behavior, i) => (
+
+
{behavior.name}
+
+ {behavior.count}
+
+
+ {behavior.trend}
+
+
+
+ ))}
+
+
+
+
+ {selectedUser.timeline.map((event, i) => (
+
+
+
+ {i < selectedUser.timeline.length - 1 &&
}
+
+
+
{event.event}
+
{event.date}
+
+
+ ))}
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/tag-portrait/tags/loading.tsx b/app/tag-portrait/tags/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/tag-portrait/tags/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/tag-portrait/tags/page.tsx b/app/tag-portrait/tags/page.tsx
new file mode 100644
index 0000000..15dfae6
--- /dev/null
+++ b/app/tag-portrait/tags/page.tsx
@@ -0,0 +1,491 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Tags,
+ Plus,
+ Search,
+ ChevronRight,
+ ChevronDown,
+ Users,
+ Cpu,
+ Brain,
+ FileText,
+ CheckCircle,
+ AlertTriangle,
+ Settings,
+} from "lucide-react"
+import { Card, CardContent } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog"
+import { Label } from "@/components/ui/label"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Textarea } from "@/components/ui/textarea"
+
+interface TagCategory {
+ id: string
+ name: string
+ icon: any
+ color: string
+ tags: Tag[]
+ expanded: boolean
+}
+
+interface Tag {
+ id: string
+ name: string
+ type: "basic" | "rule" | "model" | "ai"
+ status: "online" | "testing" | "offline"
+ coverage: number
+ userCount: number
+ rule?: string
+ lastUpdate: string
+}
+
+const TAG_TYPE_CONFIG = {
+ basic: { label: "基础标签", color: "bg-blue-100 text-blue-700", icon: FileText },
+ rule: { label: "规则标签", color: "bg-green-100 text-green-700", icon: Settings },
+ model: { label: "模型标签", color: "bg-purple-100 text-purple-700", icon: Cpu },
+ ai: { label: "AI标签", color: "bg-orange-100 text-orange-700", icon: Brain },
+}
+
+const STATUS_CONFIG = {
+ online: { label: "已上线", color: "bg-green-100 text-green-700" },
+ testing: { label: "测试中", color: "bg-yellow-100 text-yellow-700" },
+ offline: { label: "已下线", color: "bg-gray-100 text-gray-700" },
+}
+
+const INITIAL_CATEGORIES: TagCategory[] = [
+ {
+ id: "1",
+ name: "人口属性",
+ icon: Users,
+ color: "text-blue-600",
+ expanded: true,
+ tags: [
+ {
+ id: "t1",
+ name: "性别",
+ type: "basic",
+ status: "online",
+ coverage: 99.5,
+ userCount: 4012345678,
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t2",
+ name: "年龄段",
+ type: "rule",
+ status: "online",
+ coverage: 95.2,
+ userCount: 3825678901,
+ rule: "根据身份证计算",
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t3",
+ name: "城市等级",
+ type: "rule",
+ status: "online",
+ coverage: 88.7,
+ userCount: 3567890123,
+ rule: "一线/新一线/二线/三线/其他",
+ lastUpdate: "2025-12-11",
+ },
+ {
+ id: "t4",
+ name: "职业预测",
+ type: "model",
+ status: "testing",
+ coverage: 72.3,
+ userCount: 2908765432,
+ lastUpdate: "2025-12-10",
+ },
+ ],
+ },
+ {
+ id: "2",
+ name: "消费行为",
+ icon: Tags,
+ color: "text-green-600",
+ expanded: true,
+ tags: [
+ {
+ id: "t5",
+ name: "消费等级",
+ type: "rule",
+ status: "online",
+ coverage: 82.5,
+ userCount: 3318765432,
+ rule: "近90天消费金额分档",
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t6",
+ name: "高复购高客单",
+ type: "rule",
+ status: "online",
+ coverage: 15.2,
+ userCount: 611543210,
+ rule: "近30天消费次数>3 AND 客单价>500",
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t7",
+ name: "价格敏感型",
+ type: "ai",
+ status: "online",
+ coverage: 28.6,
+ userCount: 1152172345,
+ lastUpdate: "2025-12-11",
+ },
+ {
+ id: "t8",
+ name: "品牌偏好",
+ type: "ai",
+ status: "testing",
+ coverage: 45.8,
+ userCount: 1845098765,
+ lastUpdate: "2025-12-10",
+ },
+ ],
+ },
+ {
+ id: "3",
+ name: "社交互动",
+ icon: Users,
+ color: "text-purple-600",
+ expanded: false,
+ tags: [
+ {
+ id: "t9",
+ name: "活跃度等级",
+ type: "rule",
+ status: "online",
+ coverage: 78.9,
+ userCount: 3176543210,
+ rule: "近7天登录次数分档",
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t10",
+ name: "内容偏好",
+ type: "ai",
+ status: "online",
+ coverage: 65.4,
+ userCount: 2632098765,
+ lastUpdate: "2025-12-11",
+ },
+ {
+ id: "t11",
+ name: "社交影响力",
+ type: "model",
+ status: "online",
+ coverage: 55.2,
+ userCount: 2222345678,
+ lastUpdate: "2025-12-10",
+ },
+ ],
+ },
+ {
+ id: "4",
+ name: "风险等级",
+ icon: AlertTriangle,
+ color: "text-red-600",
+ expanded: false,
+ tags: [
+ {
+ id: "t12",
+ name: "流失风险",
+ type: "model",
+ status: "online",
+ coverage: 100,
+ userCount: 4028567890,
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t13",
+ name: "欺诈风险",
+ type: "model",
+ status: "online",
+ coverage: 100,
+ userCount: 4028567890,
+ lastUpdate: "2025-12-12",
+ },
+ {
+ id: "t14",
+ name: "高流失风险用户",
+ type: "rule",
+ status: "online",
+ coverage: 8.5,
+ userCount: 342428270,
+ rule: "流失风险概率>0.7",
+ lastUpdate: "2025-12-12",
+ },
+ ],
+ },
+]
+
+export default function TagManagementPage() {
+ const [categories, setCategories] = useState(INITIAL_CATEGORIES)
+ const [searchQuery, setSearchQuery] = useState("")
+ const [filterType, setFilterType] = useState("all")
+ const [isAddDialogOpen, setIsAddDialogOpen] = useState(false)
+
+ const toggleCategory = (id: string) => {
+ setCategories((prev) => prev.map((cat) => (cat.id === id ? { ...cat, expanded: !cat.expanded } : cat)))
+ }
+
+ const allTags = categories.flatMap((cat) => cat.tags)
+ const stats = {
+ totalTags: allTags.length,
+ onlineTags: allTags.filter((t) => t.status === "online").length,
+ avgCoverage: (allTags.reduce((sum, t) => sum + t.coverage, 0) / allTags.length).toFixed(1),
+ totalCovered: allTags.reduce((sum, t) => sum + t.userCount, 0),
+ }
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
+ {/* Stats */}
+
+
+
+
+
+ 总标签数
+
+ {stats.totalTags}
+
+
+
+
+
+
+ 已上线
+
+ {stats.onlineTags}
+
+
+
+
+
+
+ 平均覆盖率
+
+ {stats.avgCoverage}%
+
+
+
+
+
+
+ 标签类型
+
+
+
+ 基础 {allTags.filter((t) => t.type === "basic").length}
+
+
+ 规则 {allTags.filter((t) => t.type === "rule").length}
+
+
+ 模型 {allTags.filter((t) => t.type === "model").length}
+
+
+ AI {allTags.filter((t) => t.type === "ai").length}
+
+
+
+
+
+
+ {/* Search & Filter */}
+
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 bg-white/60"
+ />
+
+
+
+
+ {/* Tag Tree */}
+
+ {categories.map((category) => (
+
+ toggleCategory(category.id)}
+ className="w-full flex items-center justify-between p-4 hover:bg-gray-50 transition-colors"
+ >
+
+
+
+
+
+
{category.name}
+
{category.tags.length} 个标签
+
+
+ {category.expanded ? (
+
+ ) : (
+
+ )}
+
+
+ {category.expanded && (
+
+
+ {category.tags
+ .filter((tag) => {
+ const matchesSearch = tag.name.toLowerCase().includes(searchQuery.toLowerCase())
+ const matchesType = filterType === "all" || tag.type === filterType
+ return matchesSearch && matchesType
+ })
+ .map((tag) => {
+ const TypeConfig = TAG_TYPE_CONFIG[tag.type]
+ const TypeIcon = TypeConfig.icon
+
+ return (
+
+
+
+
+
+ {tag.name}
+ {TypeConfig.label}
+
+ {STATUS_CONFIG[tag.status].label}
+
+
+ {tag.rule &&
{tag.rule}
}
+
+
+
+
+
{tag.coverage}%
+
覆盖率
+
+
+
{formatNumber(tag.userCount)}
+
用户数
+
+
+
+
+
+
+ )
+ })}
+
+
+ )}
+
+ ))}
+
+
+ )
+}
diff --git a/app/user-portrait/page.tsx b/app/user-portrait/page.tsx
index cf52140..340728a 100644
--- a/app/user-portrait/page.tsx
+++ b/app/user-portrait/page.tsx
@@ -6,13 +6,12 @@ import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
-import { Users, Search, Tag, TrendingUp, Filter, UserCircle, Mail, Phone, MapPin, Calendar, Activity, Target } from 'lucide-react'
+import { Search, Tag, TrendingUp, Filter, Phone, Activity, Target } from "lucide-react"
import { Avatar, AvatarFallback } from "@/components/ui/avatar"
export default function UserPortrait() {
const [searchQuery, setSearchQuery] = useState("")
- // 用户群体分布
const userSegments = [
{ name: "高价值用户", count: 128456700, percentage: 3.0, avgValue: 580, color: "purple" },
{ name: "活跃用户", count: 1285670000, percentage: 30.0, avgValue: 280, color: "blue" },
@@ -21,7 +20,6 @@ export default function UserPortrait() {
{ name: "新增用户", count: 300125800, percentage: 7.0, avgValue: 120, color: "green" },
]
- // 标签分类统计
const tagCategories = [
{ name: "基础属性", count: 485, usage: 4285670000, coverage: 100 },
{ name: "行为标签", count: 328, usage: 3256780000, coverage: 76 },
@@ -30,7 +28,6 @@ export default function UserPortrait() {
{ name: "自定义标签", count: 100, usage: 857134000, coverage: 20 },
]
- // 最近用户示例
const recentUsers = [
{
id: "U001285",
@@ -79,40 +76,39 @@ export default function UserPortrait() {
const getLevelColor = (level: string) => {
const colors = {
- S: "border-purple-500/50 text-purple-400 bg-purple-500/10",
- A: "border-blue-500/50 text-blue-400 bg-blue-500/10",
- B: "border-green-500/50 text-green-400 bg-green-500/10",
- C: "border-yellow-500/50 text-yellow-400 bg-yellow-500/10",
- D: "border-gray-500/50 text-gray-400 bg-gray-500/10",
+ S: "bg-purple-100 text-purple-700 border-purple-200",
+ A: "bg-blue-100 text-blue-700 border-blue-200",
+ B: "bg-green-100 text-green-700 border-green-200",
+ C: "bg-yellow-100 text-yellow-700 border-yellow-200",
+ D: "bg-gray-100 text-gray-700 border-gray-200",
}
return colors[level as keyof typeof colors] || colors.D
}
const getSegmentColor = (color: string) => {
const colors = {
- purple: "from-purple-500/20 to-purple-900/20 border-purple-500/30",
- blue: "from-blue-500/20 to-blue-900/20 border-blue-500/30",
- green: "from-green-500/20 to-green-900/20 border-green-500/30",
- yellow: "from-yellow-500/20 to-yellow-900/20 border-yellow-500/30",
- orange: "from-orange-500/20 to-orange-900/20 border-orange-500/30",
+ purple: "from-purple-500 to-purple-600",
+ blue: "from-blue-500 to-blue-600",
+ green: "from-green-500 to-green-600",
+ yellow: "from-yellow-400 to-orange-500",
+ orange: "from-orange-500 to-red-500",
}
return colors[color as keyof typeof colors]
}
return (
-
- {/* Header */}
-
+
+
-
用户画像
-
用户管理、标签体系与群体分析
+
用户画像
+
用户管理、标签体系与群体分析
-
-
+
+
高级筛选
-
+
创建用户群
@@ -120,27 +116,38 @@ export default function UserPortrait() {
-
- 用户群体
- 标签体系
- 用户列表
+
+
+ 用户群体
+
+
+ 标签体系
+
+
+ 用户列表
+
- {/* 用户群体分布 */}
{userSegments.map((segment, index) => (
-
+
- {segment.name}
+ {segment.name}
-
{formatNumber(segment.count)}
-
占比 {segment.percentage}%
+
{formatNumber(segment.count)}
+
占比 {segment.percentage}%
-
人均价值
-
¥{segment.avgValue}
+
人均价值
+
¥{segment.avgValue}
@@ -148,54 +155,52 @@ export default function UserPortrait() {
))}
- {/* 用户增长趋势 */}
-
+
-
+
用户增长趋势
-
+
用户增长趋势图表区域
- {/* 标签体系 */}
{tagCategories.map((category, index) => (
-
+
-
-
+
+
-
{category.name}
-
{category.count} 个标签
+
{category.name}
+
{category.count} 个标签
-
+
覆盖率 {category.coverage}%
-
标签数量
-
{category.count}
+
标签数量
+
{category.count}
-
使用用户
-
{formatNumber(category.usage)}
+
使用用户
+
{formatNumber(category.usage)}
-
覆盖率
-
{category.coverage}%
+
覆盖率
+
{category.coverage}%
@@ -204,9 +209,7 @@ export default function UserPortrait() {
- {/* 用户列表 */}
- {/* 搜索栏 */}
@@ -214,35 +217,37 @@ export default function UserPortrait() {
placeholder="搜索用户手机号、姓名、标签..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
- className="pl-10 bg-white/5 border-white/10"
+ className="pl-10 bg-white/60 backdrop-blur-md border-gray-200"
/>
-
+
筛选
- {/* 用户卡片列表 */}
{recentUsers.map((user) => (
-
+
-
+
{user.name[0]}
- {user.name}
+ {user.name}
{user.level}级
-
+
{user.phone}
@@ -255,13 +260,13 @@ export default function UserPortrait() {
-
用户价值
-
¥{user.value}
+
用户价值
+
¥{user.value}
{user.tags.map((tag, index) => (
-
+
{tag}
))}
diff --git a/app/value-assessment/page.tsx b/app/value-assessment/page.tsx
index 4429773..61b047f 100644
--- a/app/value-assessment/page.tsx
+++ b/app/value-assessment/page.tsx
@@ -1,15 +1,13 @@
"use client"
-import { useState } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
-import { DollarSign, TrendingUp, BarChart3, Calculator, Target, Users, ArrowUpRight, ArrowDownRight } from 'lucide-react'
+import { DollarSign, TrendingUp, BarChart3, Calculator, Users, ArrowUpRight } from "lucide-react"
import { Progress } from "@/components/ui/progress"
export default function ValueAssessment() {
- // 价值评估模型数据
const valueModels = [
{
name: "RFM价值模型",
@@ -37,7 +35,6 @@ export default function ValueAssessment() {
},
]
- // 项目价值分布
const projectValues = [
{ name: "美妆行业项目A", users: 45600000, value: 2856000000, growth: 15.8, level: "A" },
{ name: "教育培训项目B", users: 32800000, value: 1968000000, growth: 12.3, level: "A" },
@@ -46,7 +43,6 @@ export default function ValueAssessment() {
{ name: "本地生活项目E", users: 19200000, value: 1152000000, growth: 6.5, level: "B" },
]
- // 微信号价值排名
const wechatRanking = [
{ name: "微信号001", users: 2856000, value: 168560000, avgValue: 59.0, rank: 1 },
{ name: "微信号002", users: 2345000, value: 145780000, avgValue: 62.2, rank: 2 },
@@ -55,7 +51,6 @@ export default function ValueAssessment() {
{ name: "微信号005", users: 1520000, value: 95600000, avgValue: 62.9, rank: 5 },
]
- // 价值增长趋势
const growthTrend = [
{ month: "1月", value: 9850000000, growth: 8.5 },
{ month: "2月", value: 10250000000, growth: 4.1 },
@@ -80,109 +75,117 @@ export default function ValueAssessment() {
const getLevelColor = (level: string) => {
const colors = {
- S: "border-purple-500/50 text-purple-400 bg-purple-500/10",
- A: "border-blue-500/50 text-blue-400 bg-blue-500/10",
- B: "border-green-500/50 text-green-400 bg-green-500/10",
- C: "border-yellow-500/50 text-yellow-400 bg-yellow-500/10",
- D: "border-gray-500/50 text-gray-400 bg-gray-500/10",
+ S: "bg-purple-100 text-purple-700 border-purple-200",
+ A: "bg-blue-100 text-blue-700 border-blue-200",
+ B: "bg-green-100 text-green-700 border-green-200",
+ C: "bg-yellow-100 text-yellow-700 border-yellow-200",
+ D: "bg-gray-100 text-gray-700 border-gray-200",
}
return colors[level as keyof typeof colors] || colors.D
}
return (
-
- {/* Header */}
-
+
+
-
价值评估
-
用户价值分析、项目价值统计与预测
+
价值评估
+
用户价值分析、项目价值统计与预测
-
- {/* 核心价值指标 */}
-
-
+
+
-
+
平台总价值
- ¥{formatCurrency(12580000000)}
+ ¥{formatCurrency(12580000000)}
-
-
+5.0%
-
本月增长
+
+
+5.0%
+
本月增长
-
+
-
-
+
+
人均价值
- ¥293.5
+ ¥293.5
-
-
+2.8%
-
环比提升
+
+
+2.8%
+
环比提升
-
+
-
-
+
+
价值覆盖率
- 85.5%
- 已评估用户占比
+ 85.5%
+ 已评估用户占比
-
- 价值模型
- 项目价值
- 微信号排名
- 增长趋势
+
+
+ 价值模型
+
+
+ 项目价值
+
+
+ 微信号排名
+
+
+ 增长趋势
+
- {/* 价值模型 */}
{valueModels.map((model, index) => (
-
+
-
{model.name}
-
{model.description}
+
{model.name}
+
{model.description}
{model.status === "active" ? "运行中" : "训练中"}
@@ -192,60 +195,59 @@ export default function ValueAssessment() {
-
模型总价值
-
¥{formatCurrency(model.totalValue)}
+
模型总价值
+
¥{formatCurrency(model.totalValue)}
-
人均价值
-
¥{model.avgValue}
+
人均价值
+
¥{model.avgValue}
-
覆盖率
-
{model.coverage}%
+
覆盖率
+
{model.coverage}%
-
+
))}
- {/* 项目价值 */}
{projectValues.map((project, index) => (
-
+
-
{project.name}
+
{project.name}
{project.level}级项目
-
-
+{project.growth}%
+
+
+{project.growth}%
-
用户数
-
{formatNumber(project.users)}
+
用户数
+
{formatNumber(project.users)}
-
项目价值
-
¥{formatCurrency(project.value)}
+
项目价值
+
¥{formatCurrency(project.value)}
-
人均价值
-
+
人均价值
+
¥{(project.value / project.users).toFixed(2)}
-
增长率
-
{project.growth}%
+
增长率
+
{project.growth}%
@@ -254,33 +256,24 @@ export default function ValueAssessment() {
- {/* 微信号排名 */}
{wechatRanking.map((wechat, index) => (
-
+
{wechat.rank}
-
{wechat.name}
-
{formatNumber(wechat.users)} 用户
+
{wechat.name}
+
{formatNumber(wechat.users)} 用户
-
¥{formatCurrency(wechat.value)}
-
人均 ¥{wechat.avgValue}
+
¥{formatCurrency(wechat.value)}
+
人均 ¥{wechat.avgValue}
@@ -289,11 +282,10 @@ export default function ValueAssessment() {
- {/* 增长趋势 */}
-
+
-
+
价值增长趋势
@@ -301,14 +293,17 @@ export default function ValueAssessment() {
{growthTrend.map((item, index) => (
-
+
-
{item.month}
-
¥{formatCurrency(item.value)}
+
{item.month}
+
¥{formatCurrency(item.value)}
-
-
+{item.growth}%
+
+
+{item.growth}%
))}
diff --git a/app/value-model/assessment/loading.tsx b/app/value-model/assessment/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/value-model/assessment/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/value-model/assessment/page.tsx b/app/value-model/assessment/page.tsx
new file mode 100644
index 0000000..e3f3319
--- /dev/null
+++ b/app/value-model/assessment/page.tsx
@@ -0,0 +1,320 @@
+"use client"
+
+import { useState } from "react"
+import {
+ BarChart3,
+ Plus,
+ Play,
+ Search,
+ Users,
+ Clock,
+ CheckCircle,
+ XCircle,
+ RefreshCw,
+ Download,
+ Filter,
+} from "lucide-react"
+import { Card, CardContent } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import { Progress } from "@/components/ui/progress"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { CreateAssessmentTaskDialog } from "@/components/dialogs/create-assessment-task-dialog"
+
+interface AssessmentTask {
+ id: string
+ name: string
+ model: string
+ targetCrowd: string
+ userCount: number
+ status: "running" | "completed" | "failed" | "scheduled"
+ progress: number
+ createdAt: string
+ completedAt: string | null
+ schedule: string
+ resultSummary?: {
+ avgScore: number
+ highValue: number
+ mediumValue: number
+ lowValue: number
+ }
+}
+
+const MOCK_TASKS: AssessmentTask[] = [
+ {
+ id: "1",
+ name: "全量用户CLV评估",
+ model: "CLV预测模型 v2.3.1",
+ targetCrowd: "全部用户",
+ userCount: 4028567890,
+ status: "completed",
+ progress: 100,
+ createdAt: "2025-12-12 00:00:00",
+ completedAt: "2025-12-12 03:45:00",
+ schedule: "每周一",
+ resultSummary: {
+ avgScore: 65.8,
+ highValue: 15.2,
+ mediumValue: 45.6,
+ lowValue: 39.2,
+ },
+ },
+ {
+ id: "2",
+ name: "活跃用户RFM评分",
+ model: "RFM评分模型 v1.5.0",
+ targetCrowd: "近30天活跃用户",
+ userCount: 1256789012,
+ status: "running",
+ progress: 67,
+ createdAt: "2025-12-12 10:00:00",
+ completedAt: null,
+ schedule: "每天",
+ },
+ {
+ id: "3",
+ name: "流失风险预警",
+ model: "流失预警模型 v3.1.2",
+ targetCrowd: "沉默用户",
+ userCount: 456789012,
+ status: "completed",
+ progress: 100,
+ createdAt: "2025-12-11 22:00:00",
+ completedAt: "2025-12-12 00:30:00",
+ schedule: "每天",
+ resultSummary: {
+ avgScore: 0.45,
+ highValue: 8.5,
+ mediumValue: 25.3,
+ lowValue: 66.2,
+ },
+ },
+ {
+ id: "4",
+ name: "高价值用户细分",
+ model: "用户分群模型 v1.0.0",
+ targetCrowd: "价值评分>80用户",
+ userCount: 125678901,
+ status: "scheduled",
+ progress: 0,
+ createdAt: "2025-12-12 14:00:00",
+ completedAt: null,
+ schedule: "每周",
+ },
+ {
+ id: "5",
+ name: "欺诈风险扫描",
+ model: "欺诈检测模型 v2.0.0",
+ targetCrowd: "近7天交易用户",
+ userCount: 89012345,
+ status: "failed",
+ progress: 45,
+ createdAt: "2025-12-12 08:00:00",
+ completedAt: null,
+ schedule: "实时",
+ },
+]
+
+const STATUS_CONFIG = {
+ running: { label: "运行中", color: "bg-blue-100 text-blue-700", icon: RefreshCw },
+ completed: { label: "已完成", color: "bg-green-100 text-green-700", icon: CheckCircle },
+ failed: { label: "失败", color: "bg-red-100 text-red-700", icon: XCircle },
+ scheduled: { label: "已排期", color: "bg-yellow-100 text-yellow-700", icon: Clock },
+}
+
+export default function AssessmentServicePage() {
+ const [tasks, setTasks] = useState
(MOCK_TASKS)
+ const [searchQuery, setSearchQuery] = useState("")
+ const [statusFilter, setStatusFilter] = useState("all")
+ const [showCreateDialog, setShowCreateDialog] = useState(false)
+
+ const formatNumber = (num: number): string => {
+ if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B`
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
+ return num.toString()
+ }
+
+ const filteredTasks = tasks.filter((task) => {
+ const matchesSearch = task.name.toLowerCase().includes(searchQuery.toLowerCase())
+ const matchesStatus = statusFilter === "all" || task.status === statusFilter
+ return matchesSearch && matchesStatus
+ })
+
+ const stats = {
+ total: tasks.length,
+ running: tasks.filter((t) => t.status === "running").length,
+ completed: tasks.filter((t) => t.status === "completed").length,
+ totalEvaluated: tasks.filter((t) => t.status === "completed").reduce((sum, t) => sum + t.userCount, 0),
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
setShowCreateDialog(true)}
+ >
+
+ 创建评估任务
+
+
+
+ {/* Stats */}
+
+
+
+
+
+ 总任务数
+
+ {stats.total}
+
+
+
+
+
+
+ 运行中
+
+ {stats.running}
+
+
+
+
+
+
+ 已完成
+
+ {stats.completed}
+
+
+
+
+
+
+ 已评估用户
+
+ {formatNumber(stats.totalEvaluated)}
+
+
+
+
+ {/* Filters */}
+
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 bg-white/60"
+ />
+
+
+
+
+ {/* Task List */}
+
+ {filteredTasks.map((task) => {
+ const StatusIcon = STATUS_CONFIG[task.status].icon
+
+ return (
+
+
+
+
+
+
{task.name}
+
+
+ {STATUS_CONFIG[task.status].label}
+
+
+
+ 模型: {task.model}
+ 目标: {task.targetCrowd}
+ 用户数: {formatNumber(task.userCount)}
+ 周期: {task.schedule}
+
+
+
+ {task.status === "completed" && (
+
+
+ 导出
+
+ )}
+ {(task.status === "scheduled" || task.status === "failed") && (
+
+
+ 执行
+
+ )}
+
+
+
+ {task.status === "running" && (
+
+
+ 执行进度
+ {task.progress}%
+
+
+
+ )}
+
+ {task.resultSummary && (
+
+
+
{task.resultSummary.avgScore}
+
平均分
+
+
+
{task.resultSummary.highValue}%
+
高价值
+
+
+
{task.resultSummary.mediumValue}%
+
中价值
+
+
+
{task.resultSummary.lowValue}%
+
低价值
+
+
+ )}
+
+
+ 创建时间: {task.createdAt}
+ {task.completedAt && 完成时间: {task.completedAt}}
+
+
+
+ )
+ })}
+
+
+ {/* Create Task Dialog */}
+
+
+ )
+}
diff --git a/app/value-model/models/loading.tsx b/app/value-model/models/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/value-model/models/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/value-model/models/page.tsx b/app/value-model/models/page.tsx
new file mode 100644
index 0000000..b057d59
--- /dev/null
+++ b/app/value-model/models/page.tsx
@@ -0,0 +1,358 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Boxes,
+ Plus,
+ Search,
+ Play,
+ Settings,
+ CheckCircle,
+ Clock,
+ AlertTriangle,
+ GitBranch,
+ BarChart3,
+ Cpu,
+ TrendingUp,
+} from "lucide-react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import { Progress } from "@/components/ui/progress"
+import { UploadModelDialog } from "@/components/dialogs/upload-model-dialog"
+
+interface Model {
+ id: string
+ name: string
+ type: "preset" | "custom"
+ category: "clv" | "rfm" | "churn" | "fraud" | "segment"
+ version: string
+ status: "online" | "training" | "testing" | "offline"
+ accuracy: number
+ precision: number
+ recall: number
+ f1Score: number
+ lastTrained: string
+ inputFeatures: string[]
+ outputFormat: string
+ updateFrequency: string
+ description: string
+}
+
+const MOCK_MODELS: Model[] = [
+ {
+ id: "1",
+ name: "CLV预测模型",
+ type: "preset",
+ category: "clv",
+ version: "v2.3.1",
+ status: "online",
+ accuracy: 87.5,
+ precision: 85.2,
+ recall: 89.1,
+ f1Score: 87.1,
+ lastTrained: "2025-12-10",
+ inputFeatures: ["历史消费金额", "消费频次", "注册时长", "活跃度"],
+ outputFormat: "CLV分数 (0-100)",
+ updateFrequency: "每周",
+ description: "基于用户历史行为预测客户终身价值",
+ },
+ {
+ id: "2",
+ name: "RFM评分模型",
+ type: "preset",
+ category: "rfm",
+ version: "v1.5.0",
+ status: "online",
+ accuracy: 92.3,
+ precision: 91.5,
+ recall: 93.2,
+ f1Score: 92.3,
+ lastTrained: "2025-12-11",
+ inputFeatures: ["最近消费时间", "消费频率", "消费金额"],
+ outputFormat: "R/F/M各维度评分 (0-100)",
+ updateFrequency: "每天",
+ description: "基于RFM模型的用户价值分层",
+ },
+ {
+ id: "3",
+ name: "流失预警模型",
+ type: "preset",
+ category: "churn",
+ version: "v3.1.2",
+ status: "online",
+ accuracy: 85.8,
+ precision: 87.3,
+ recall: 84.2,
+ f1Score: 85.7,
+ lastTrained: "2025-12-09",
+ inputFeatures: ["活跃度变化", "消费趋势", "投诉记录", "登录频次"],
+ outputFormat: "流失概率 (0-1)",
+ updateFrequency: "每天",
+ description: "预测用户未来30天流失概率",
+ },
+ {
+ id: "4",
+ name: "欺诈检测模型",
+ type: "preset",
+ category: "fraud",
+ version: "v2.0.0",
+ status: "online",
+ accuracy: 96.2,
+ precision: 94.8,
+ recall: 97.5,
+ f1Score: 96.1,
+ lastTrained: "2025-12-08",
+ inputFeatures: ["交易金额", "交易频率", "设备信息", "地理位置"],
+ outputFormat: "欺诈风险等级 (低/中/高)",
+ updateFrequency: "实时",
+ description: "实时检测可疑交易行为",
+ },
+ {
+ id: "5",
+ name: "用户分群模型",
+ type: "custom",
+ category: "segment",
+ version: "v1.0.0",
+ status: "training",
+ accuracy: 78.5,
+ precision: 76.2,
+ recall: 80.1,
+ f1Score: 78.1,
+ lastTrained: "2025-12-12",
+ inputFeatures: ["消费行为", "浏览偏好", "互动记录", "人口属性"],
+ outputFormat: "用户群体标签",
+ updateFrequency: "每周",
+ description: "基于多维特征的用户自动分群",
+ },
+]
+
+const CATEGORY_CONFIG = {
+ clv: { label: "CLV模型", color: "bg-blue-100 text-blue-700" },
+ rfm: { label: "RFM模型", color: "bg-green-100 text-green-700" },
+ churn: { label: "流失预警", color: "bg-orange-100 text-orange-700" },
+ fraud: { label: "欺诈检测", color: "bg-red-100 text-red-700" },
+ segment: { label: "用户分群", color: "bg-purple-100 text-purple-700" },
+}
+
+const STATUS_CONFIG = {
+ online: { label: "已上线", color: "bg-green-100 text-green-700", icon: CheckCircle },
+ training: { label: "训练中", color: "bg-blue-100 text-blue-700", icon: Cpu },
+ testing: { label: "测试中", color: "bg-yellow-100 text-yellow-700", icon: Clock },
+ offline: { label: "已下线", color: "bg-gray-100 text-gray-700", icon: AlertTriangle },
+}
+
+export default function ModelManagementPage() {
+ const [models, setModels] = useState(MOCK_MODELS)
+ const [searchQuery, setSearchQuery] = useState("")
+ const [selectedModel, setSelectedModel] = useState(null)
+ const [showUploadDialog, setShowUploadDialog] = useState(false)
+
+ const stats = {
+ total: models.length,
+ online: models.filter((m) => m.status === "online").length,
+ avgAccuracy: (models.reduce((sum, m) => sum + m.accuracy, 0) / models.length).toFixed(1),
+ presetModels: models.filter((m) => m.type === "preset").length,
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
setShowUploadDialog(true)}
+ >
+
+ 上传自定义模型
+
+
+
+ {/* Stats */}
+
+
+
+
+
+ 总模型数
+
+ {stats.total}
+
+
+
+
+
+
+ 已上线
+
+ {stats.online}
+
+
+
+
+
+
+ 平均准确率
+
+ {stats.avgAccuracy}%
+
+
+
+
+
+
+ 预置模型
+
+ {stats.presetModels}
+
+
+
+
+ {/* Search */}
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 bg-white/60"
+ />
+
+
+ {/* Model List */}
+
+ {models
+ .filter((m) => m.name.toLowerCase().includes(searchQuery.toLowerCase()))
+ .map((model) => {
+ const StatusIcon = STATUS_CONFIG[model.status].icon
+
+ return (
+
setSelectedModel(model)}
+ >
+
+
+
+
+
{model.name}
+
+ {CATEGORY_CONFIG[model.category].label}
+
+
+
{model.description}
+
+
+
+ {STATUS_CONFIG[model.status].label}
+
+
+
+
+
+
{model.accuracy}%
+
准确率
+
+
+
{model.precision}%
+
精确率
+
+
+
{model.recall}%
+
召回率
+
+
+
{model.f1Score}%
+
F1分数
+
+
+
+
+
+ 版本: {model.version}
+ 更新: {model.updateFrequency}
+
+
+
+
+
+ )
+ })}
+
+
+ {/* Model Detail Panel */}
+ {selectedModel && (
+
+
+
+
+ 模型详情: {selectedModel.name}
+
+
+
+
+
+
输入特征
+
+ {selectedModel.inputFeatures.map((feature, i) => (
+
+ ))}
+
+
+
+
输出格式
+
+ {selectedModel.outputFormat}
+
+
+
模型指标
+
+
+
+ 准确率
+ {selectedModel.accuracy}%
+
+
+
+
+
+ 精确率
+ {selectedModel.precision}%
+
+
+
+
+
+ 召回率
+ {selectedModel.recall}%
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ )
+}
diff --git a/app/value-model/page.tsx b/app/value-model/page.tsx
new file mode 100644
index 0000000..260a3e9
--- /dev/null
+++ b/app/value-model/page.tsx
@@ -0,0 +1,12 @@
+"use client"
+
+import { useRouter } from "next/navigation"
+import { useEffect } from "react"
+
+export default function ValueModelPage() {
+ const router = useRouter()
+ useEffect(() => {
+ router.replace("/value-model/models")
+ }, [router])
+ return null
+}
diff --git a/app/value-model/reports/loading.tsx b/app/value-model/reports/loading.tsx
new file mode 100644
index 0000000..f15322a
--- /dev/null
+++ b/app/value-model/reports/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return null
+}
diff --git a/app/value-model/reports/page.tsx b/app/value-model/reports/page.tsx
new file mode 100644
index 0000000..71aa875
--- /dev/null
+++ b/app/value-model/reports/page.tsx
@@ -0,0 +1,237 @@
+"use client"
+
+import { useState } from "react"
+import { Download, Share2, Eye, Calendar, TrendingUp, TrendingDown, BarChart3, PieChart } from "lucide-react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+
+interface Report {
+ id: string
+ name: string
+ type: "distribution" | "trend" | "comparison"
+ period: string
+ generatedAt: string
+ metrics: {
+ label: string
+ value: string
+ change?: number
+ }[]
+ chartData?: any
+}
+
+const MOCK_REPORTS: Report[] = [
+ {
+ id: "1",
+ name: "用户价值分布报告",
+ type: "distribution",
+ period: "2025年12月",
+ generatedAt: "2025-12-12 06:00:00",
+ metrics: [
+ { label: "S级用户", value: "5.2%", change: 0.3 },
+ { label: "A级用户", value: "12.8%", change: 0.5 },
+ { label: "B级用户", value: "28.5%", change: -0.2 },
+ { label: "C级用户", value: "35.2%", change: -0.4 },
+ { label: "D级用户", value: "18.3%", change: -0.2 },
+ ],
+ },
+ {
+ id: "2",
+ name: "价值趋势对比报告",
+ type: "trend",
+ period: "近6个月",
+ generatedAt: "2025-12-12 06:00:00",
+ metrics: [
+ { label: "平均CLV", value: "¥2,856", change: 12.5 },
+ { label: "高价值用户占比", value: "18.0%", change: 2.3 },
+ { label: "用户价值总量", value: "¥125.6B", change: 8.7 },
+ { label: "人均贡献", value: "¥31.2", change: 5.2 },
+ ],
+ },
+ {
+ id: "3",
+ name: "项目价值排名报告",
+ type: "comparison",
+ period: "2025年12月",
+ generatedAt: "2025-12-11 22:00:00",
+ metrics: [
+ { label: "#1 华东区项目", value: "¥28.5B", change: 15.2 },
+ { label: "#2 华南区项目", value: "¥22.3B", change: 12.8 },
+ { label: "#3 华北区项目", value: "¥18.9B", change: 8.5 },
+ { label: "#4 西南区项目", value: "¥15.6B", change: 10.2 },
+ { label: "#5 华中区项目", value: "¥12.8B", change: 6.3 },
+ ],
+ },
+ {
+ id: "4",
+ name: "流失风险分析报告",
+ type: "distribution",
+ period: "2025年12月",
+ generatedAt: "2025-12-12 00:00:00",
+ metrics: [
+ { label: "高风险用户", value: "8.5%", change: -1.2 },
+ { label: "中风险用户", value: "25.3%", change: 0.5 },
+ { label: "低风险用户", value: "66.2%", change: 0.7 },
+ { label: "预计流失数", value: "34.2M", change: -5.8 },
+ ],
+ },
+]
+
+const TYPE_CONFIG = {
+ distribution: { label: "分布报告", color: "bg-blue-100 text-blue-700", icon: PieChart },
+ trend: { label: "趋势报告", color: "bg-green-100 text-green-700", icon: TrendingUp },
+ comparison: { label: "对比报告", color: "bg-purple-100 text-purple-700", icon: BarChart3 },
+}
+
+export default function AssessmentReportsPage() {
+ const [reports, setReports] = useState(MOCK_REPORTS)
+ const [selectedPeriod, setSelectedPeriod] = useState("month")
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
+
+ 批量导出
+
+
+
+
+ {/* Summary Cards */}
+
+
+
+
+
+ 用户价值总量
+
+ ¥125.6B
+
+
+ 较上月增长 8.7%
+
+
+
+
+
+
+
+
+ 高价值用户占比
+
+ 18.0%
+
+
+ 较上月提升 2.3%
+
+
+
+
+
+
+
+ ¥2,856
+
+
+ 较上月增长 12.5%
+
+
+
+
+
+ {/* Report List */}
+
+ {reports.map((report) => {
+ const TypeIcon = TYPE_CONFIG[report.type].icon
+
+ return (
+
+
+
+
+
+ {report.name}
+
+
+ {TYPE_CONFIG[report.type].label}
+
+
+
周期: {report.period}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {report.metrics.map((metric, i) => (
+
+
{metric.label}
+
+ {metric.value}
+ {metric.change !== undefined && (
+ 0
+ ? "bg-green-100 text-green-700"
+ : metric.change < 0
+ ? "bg-red-100 text-red-700"
+ : "bg-gray-100 text-gray-700"
+ }
+ >
+ {metric.change > 0 ? (
+
+ ) : metric.change < 0 ? (
+
+ ) : null}
+ {metric.change > 0 ? "+" : ""}
+ {metric.change}%
+
+ )}
+
+
+ ))}
+
+
+
+ 生成时间: {report.generatedAt}
+
+
+
+ )
+ })}
+
+
+ )
+}
diff --git a/components/dialogs/ai-cleaning-logs-dialog.tsx b/components/dialogs/ai-cleaning-logs-dialog.tsx
new file mode 100644
index 0000000..49a005f
--- /dev/null
+++ b/components/dialogs/ai-cleaning-logs-dialog.tsx
@@ -0,0 +1,144 @@
+"use client"
+
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { FileText, Download, RefreshCw, Brain, CheckCircle, XCircle, Clock } from "lucide-react"
+
+interface AICleaningLogsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ ruleName?: string
+}
+
+const AI_LOGS = [
+ {
+ time: "14:35:12",
+ type: "system",
+ message: "AI清洗任务启动",
+ details: "规则: 用户数据智能清洗 | 模型: GPT-4",
+ },
+ {
+ time: "14:35:13",
+ type: "ai",
+ message: "分析提示词",
+ details: "解析清洗意图: 手机号格式化、邮箱校验、地址补全",
+ },
+ {
+ time: "14:35:15",
+ type: "system",
+ message: "读取数据批次 1/10",
+ details: "共 12,895 条记录",
+ },
+ {
+ time: "14:35:18",
+ type: "ai",
+ message: "AI分析完成",
+ details: "发现 156 条需要清洗的记录, 置信度范围: 0.72-0.98",
+ },
+ {
+ time: "14:35:20",
+ type: "review",
+ message: "自动审核通过",
+ details: "142 条记录置信度 >= 0.95, 已自动应用",
+ },
+ {
+ time: "14:35:21",
+ type: "review",
+ message: "待人工审核",
+ details: "14 条记录置信度 < 0.95, 等待审核",
+ },
+ {
+ time: "14:35:25",
+ type: "system",
+ message: "批次 1 处理完成",
+ details: "成功: 12,881 | 待审核: 14 | 跳过: 0",
+ },
+ {
+ time: "14:36:45",
+ type: "ai",
+ message: "AI建议",
+ details: "检测到 '86-' 前缀手机号模式, 建议添加自动化规则",
+ },
+]
+
+export function AICleaningLogsDialog({ open, onOpenChange, ruleName }: AICleaningLogsDialogProps) {
+ const getTypeIcon = (type: string) => {
+ switch (type) {
+ case "ai":
+ return
+ case "review":
+ return
+ case "error":
+ return
+ default:
+ return
+ }
+ }
+
+ const getTypeBadge = (type: string) => {
+ switch (type) {
+ case "ai":
+ return AI
+ case "review":
+ return 审核
+ case "error":
+ return 错误
+ default:
+ return 系统
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/alert-rule-settings-dialog.tsx b/components/dialogs/alert-rule-settings-dialog.tsx
new file mode 100644
index 0000000..2766332
--- /dev/null
+++ b/components/dialogs/alert-rule-settings-dialog.tsx
@@ -0,0 +1,238 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Switch } from "@/components/ui/switch"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Settings, Bell, Users, Clock } from "lucide-react"
+import { Checkbox } from "@/components/ui/checkbox"
+
+interface AlertRuleSettingsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ rule?: {
+ name: string
+ condition: string
+ severity: string
+ }
+}
+
+export function AlertRuleSettingsDialog({ open, onOpenChange, rule }: AlertRuleSettingsDialogProps) {
+ const [activeTab, setActiveTab] = useState("condition")
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/api-doc-dialog.tsx b/components/dialogs/api-doc-dialog.tsx
new file mode 100644
index 0000000..a751ad0
--- /dev/null
+++ b/components/dialogs/api-doc-dialog.tsx
@@ -0,0 +1,222 @@
+"use client"
+
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { Code, Copy, ExternalLink } from "lucide-react"
+
+interface APIDocDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ api?: {
+ name: string
+ endpoint: string
+ method: string
+ description: string
+ }
+}
+
+export function APIDocDialog({ open, onOpenChange, api }: APIDocDialogProps) {
+ const copyToClipboard = (text: string) => {
+ navigator.clipboard.writeText(text)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/api-key-management-dialog.tsx b/components/dialogs/api-key-management-dialog.tsx
new file mode 100644
index 0000000..97658a8
--- /dev/null
+++ b/components/dialogs/api-key-management-dialog.tsx
@@ -0,0 +1,164 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Badge } from "@/components/ui/badge"
+import { Key, Copy, Eye, EyeOff, Plus, Trash2, CheckCircle } from "lucide-react"
+
+interface ApiKeyManagementDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+const MOCK_KEYS = [
+ {
+ id: 1,
+ name: "生产环境密钥",
+ key: "sk_live_xxxxxxxxxxxx",
+ created: "2024-12-01",
+ lastUsed: "刚刚",
+ status: "active",
+ },
+ {
+ id: 2,
+ name: "测试环境密钥",
+ key: "sk_test_xxxxxxxxxxxx",
+ created: "2024-11-15",
+ lastUsed: "3天前",
+ status: "active",
+ },
+ {
+ id: 3,
+ name: "开发调试密钥",
+ key: "sk_dev_xxxxxxxxxxxx",
+ created: "2024-10-20",
+ lastUsed: "1周前",
+ status: "inactive",
+ },
+]
+
+export function ApiKeyManagementDialog({ open, onOpenChange }: ApiKeyManagementDialogProps) {
+ const [keys, setKeys] = useState(MOCK_KEYS)
+ const [showKey, setShowKey] = useState(null)
+ const [newKeyName, setNewKeyName] = useState("")
+ const [showNewKeyForm, setShowNewKeyForm] = useState(false)
+ const [copiedId, setCopiedId] = useState(null)
+
+ const copyKey = (id: number, key: string) => {
+ navigator.clipboard.writeText(key)
+ setCopiedId(id)
+ setTimeout(() => setCopiedId(null), 2000)
+ }
+
+ const createKey = () => {
+ if (newKeyName) {
+ setKeys([
+ ...keys,
+ {
+ id: Date.now(),
+ name: newKeyName,
+ key: `sk_live_${Math.random().toString(36).substr(2, 12)}`,
+ created: new Date().toISOString().split("T")[0],
+ lastUsed: "从未",
+ status: "active",
+ },
+ ])
+ setNewKeyName("")
+ setShowNewKeyForm(false)
+ }
+ }
+
+ const deleteKey = (id: number) => {
+ setKeys(keys.filter((k) => k.id !== id))
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/api-monitor-dialog.tsx b/components/dialogs/api-monitor-dialog.tsx
new file mode 100644
index 0000000..0e21553
--- /dev/null
+++ b/components/dialogs/api-monitor-dialog.tsx
@@ -0,0 +1,168 @@
+"use client"
+
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Card, CardContent } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Activity, Clock, Zap, AlertTriangle, CheckCircle } from "lucide-react"
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from "recharts"
+
+interface APIMonitorDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ api?: {
+ name: string
+ endpoint: string
+ }
+}
+
+const LATENCY_DATA = [
+ { time: "00:00", p50: 28, p95: 45, p99: 68 },
+ { time: "04:00", p50: 25, p95: 42, p99: 62 },
+ { time: "08:00", p50: 32, p95: 55, p99: 85 },
+ { time: "12:00", p50: 45, p95: 78, p99: 120 },
+ { time: "16:00", p50: 42, p95: 72, p99: 110 },
+ { time: "20:00", p50: 35, p95: 58, p99: 88 },
+]
+
+const QPS_DATA = [
+ { time: "00:00", qps: 450 },
+ { time: "04:00", qps: 280 },
+ { time: "08:00", qps: 850 },
+ { time: "12:00", qps: 1200 },
+ { time: "16:00", qps: 1100 },
+ { time: "20:00", qps: 780 },
+]
+
+const ERROR_DATA = [
+ { time: "00:00", rate: 0.1 },
+ { time: "04:00", rate: 0.05 },
+ { time: "08:00", rate: 0.15 },
+ { time: "12:00", rate: 0.3 },
+ { time: "16:00", rate: 0.2 },
+ { time: "20:00", rate: 0.12 },
+]
+
+export function APIMonitorDialog({ open, onOpenChange, api }: APIMonitorDialogProps) {
+ return (
+
+ )
+}
diff --git a/components/dialogs/api-settings-dialog.tsx b/components/dialogs/api-settings-dialog.tsx
new file mode 100644
index 0000000..de6bd0f
--- /dev/null
+++ b/components/dialogs/api-settings-dialog.tsx
@@ -0,0 +1,186 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Switch } from "@/components/ui/switch"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Settings, Shield, Zap, Bell } from "lucide-react"
+
+interface APISettingsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ api?: {
+ name: string
+ endpoint: string
+ }
+}
+
+export function APISettingsDialog({ open, onOpenChange, api }: APISettingsDialogProps) {
+ const [activeTab, setActiveTab] = useState("basic")
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/batch-recalculate-dialog.tsx b/components/dialogs/batch-recalculate-dialog.tsx
new file mode 100644
index 0000000..3cea6ce
--- /dev/null
+++ b/components/dialogs/batch-recalculate-dialog.tsx
@@ -0,0 +1,170 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Label } from "@/components/ui/label"
+import { Checkbox } from "@/components/ui/checkbox"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Progress } from "@/components/ui/progress"
+import { RefreshCw, Database, Clock, AlertTriangle } from "lucide-react"
+
+interface BatchRecalculateDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+const DATA_SOURCES = [
+ { id: "1", name: "存客宝-用户主库", records: 128956342 },
+ { id: "2", name: "触客宝-行为数据", records: 89234567 },
+ { id: "3", name: "数智员工-账号API", records: 45678901 },
+]
+
+const AI_RULES = [
+ { id: 1, name: "用户数据智能清洗", selected: true },
+ { id: 2, name: "交易流水异常检测", selected: true },
+ { id: 3, name: "聊天记录语义清洗", selected: false },
+]
+
+export function BatchRecalculateDialog({ open, onOpenChange }: BatchRecalculateDialogProps) {
+ const [isProcessing, setIsProcessing] = useState(false)
+ const [progress, setProgress] = useState(0)
+ const [selectedRules, setSelectedRules] = useState(AI_RULES.filter((r) => r.selected).map((r) => r.id))
+ const [scope, setScope] = useState("incremental")
+
+ const handleStart = () => {
+ setIsProcessing(true)
+ setProgress(0)
+ const interval = setInterval(() => {
+ setProgress((prev) => {
+ if (prev >= 100) {
+ clearInterval(interval)
+ setIsProcessing(false)
+ return 100
+ }
+ return prev + 10
+ })
+ }, 500)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/cleaning-rule-logs-dialog.tsx b/components/dialogs/cleaning-rule-logs-dialog.tsx
new file mode 100644
index 0000000..bbe805c
--- /dev/null
+++ b/components/dialogs/cleaning-rule-logs-dialog.tsx
@@ -0,0 +1,178 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { FileText, CheckCircle, XCircle, Clock, Download, RefreshCw } from "lucide-react"
+
+interface CleaningRuleLogsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ ruleName?: string
+}
+
+const MOCK_LOGS = [
+ {
+ id: 1,
+ timestamp: "2025-12-16 14:35:12",
+ level: "INFO",
+ message: "开始执行清洗任务",
+ details: "任务ID: task_20251216_143512",
+ },
+ {
+ id: 2,
+ timestamp: "2025-12-16 14:35:13",
+ level: "INFO",
+ message: "连接源数据库成功",
+ details: "MySQL: 10.88.182.62:3305",
+ },
+ {
+ id: 3,
+ timestamp: "2025-12-16 14:35:15",
+ level: "INFO",
+ message: "读取源数据",
+ details: "共读取 128,956 条记录",
+ },
+ {
+ id: 4,
+ timestamp: "2025-12-16 14:35:18",
+ level: "WARN",
+ message: "发现异常数据",
+ details: "25 条记录手机号格式不规范",
+ },
+ {
+ id: 5,
+ timestamp: "2025-12-16 14:35:22",
+ level: "INFO",
+ message: "执行清洗规则",
+ details: "应用规则: 手机号标准化",
+ },
+ {
+ id: 6,
+ timestamp: "2025-12-16 14:35:45",
+ level: "INFO",
+ message: "数据写入完成",
+ details: "成功写入 128,931 条, 跳过 25 条",
+ },
+ {
+ id: 7,
+ timestamp: "2025-12-16 14:35:46",
+ level: "INFO",
+ message: "清洗任务完成",
+ details: "总耗时: 34秒, 错误率: 0.02%",
+ },
+]
+
+const EXECUTION_HISTORY = [
+ { id: 1, time: "2025-12-16 14:35", status: "success", processed: 128956, errors: 25, duration: "34秒" },
+ { id: 2, time: "2025-12-16 13:35", status: "success", processed: 125832, errors: 18, duration: "32秒" },
+ { id: 3, time: "2025-12-16 12:35", status: "success", processed: 130215, errors: 22, duration: "36秒" },
+ { id: 4, time: "2025-12-16 11:35", status: "failed", processed: 45000, errors: 1250, duration: "15秒" },
+ { id: 5, time: "2025-12-16 10:35", status: "success", processed: 128500, errors: 20, duration: "33秒" },
+]
+
+export function CleaningRuleLogsDialog({ open, onOpenChange, ruleName }: CleaningRuleLogsDialogProps) {
+ const [selectedExecution, setSelectedExecution] = useState(EXECUTION_HISTORY[0])
+
+ const getLevelColor = (level: string) => {
+ switch (level) {
+ case "INFO":
+ return "text-blue-600 bg-blue-50"
+ case "WARN":
+ return "text-amber-600 bg-amber-50"
+ case "ERROR":
+ return "text-red-600 bg-red-50"
+ default:
+ return "text-slate-600 bg-slate-50"
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/cleaning-rule-settings-dialog.tsx b/components/dialogs/cleaning-rule-settings-dialog.tsx
new file mode 100644
index 0000000..2d8af2a
--- /dev/null
+++ b/components/dialogs/cleaning-rule-settings-dialog.tsx
@@ -0,0 +1,223 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Switch } from "@/components/ui/switch"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Settings, Code, Clock, Bell } from "lucide-react"
+
+interface CleaningRuleSettingsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ rule?: {
+ id: string
+ name: string
+ description: string
+ type: string
+ sourceTable: string
+ targetTable: string
+ status: string
+ }
+}
+
+export function CleaningRuleSettingsDialog({ open, onOpenChange, rule }: CleaningRuleSettingsDialogProps) {
+ const [activeTab, setActiveTab] = useState("basic")
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/create-alert-rule-dialog.tsx b/components/dialogs/create-alert-rule-dialog.tsx
new file mode 100644
index 0000000..d94d6f2
--- /dev/null
+++ b/components/dialogs/create-alert-rule-dialog.tsx
@@ -0,0 +1,166 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
+import { Checkbox } from "@/components/ui/checkbox"
+
+interface CreateAlertRuleDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+export function CreateAlertRuleDialog({ open, onOpenChange }: CreateAlertRuleDialogProps) {
+ const [formData, setFormData] = useState({
+ name: "",
+ metric: "",
+ operator: "gt",
+ threshold: "",
+ duration: "5",
+ severity: "warning",
+ channels: [] as string[],
+ })
+
+ const toggleChannel = (channel: string) => {
+ setFormData({
+ ...formData,
+ channels: formData.channels.includes(channel)
+ ? formData.channels.filter((c) => c !== channel)
+ : [...formData.channels, channel],
+ })
+ }
+
+ const handleSubmit = () => {
+ console.log("创建告警规则:", formData)
+ onOpenChange(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/create-assessment-task-dialog.tsx b/components/dialogs/create-assessment-task-dialog.tsx
new file mode 100644
index 0000000..b7be014
--- /dev/null
+++ b/components/dialogs/create-assessment-task-dialog.tsx
@@ -0,0 +1,136 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
+import { Users, Database } from "lucide-react"
+
+interface CreateAssessmentTaskDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+export function CreateAssessmentTaskDialog({ open, onOpenChange }: CreateAssessmentTaskDialogProps) {
+ const [formData, setFormData] = useState({
+ name: "",
+ model: "",
+ targetType: "all",
+ crowdId: "",
+ schedule: "once",
+ scheduleTime: "",
+ })
+
+ const handleSubmit = () => {
+ console.log("创建评估任务:", formData)
+ onOpenChange(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/create-cleaning-rule-dialog.tsx b/components/dialogs/create-cleaning-rule-dialog.tsx
new file mode 100644
index 0000000..662b61f
--- /dev/null
+++ b/components/dialogs/create-cleaning-rule-dialog.tsx
@@ -0,0 +1,114 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+
+interface CreateCleaningRuleDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+export function CreateCleaningRuleDialog({ open, onOpenChange }: CreateCleaningRuleDialogProps) {
+ const [formData, setFormData] = useState({
+ name: "",
+ description: "",
+ type: "",
+ sourceTable: "",
+ targetTable: "",
+ })
+
+ const handleSubmit = () => {
+ console.log("创建清洗规则:", formData)
+ onOpenChange(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/create-package-dialog.tsx b/components/dialogs/create-package-dialog.tsx
new file mode 100644
index 0000000..8560bd0
--- /dev/null
+++ b/components/dialogs/create-package-dialog.tsx
@@ -0,0 +1,184 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { Badge } from "@/components/ui/badge"
+import { X, Plus } from "lucide-react"
+
+interface CreatePackageDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+export function CreatePackageDialog({ open, onOpenChange }: CreatePackageDialogProps) {
+ const [formData, setFormData] = useState({
+ name: "",
+ description: "",
+ conditions: [] as { field: string; operator: string; value: string }[],
+ tags: [] as string[],
+ })
+ const [newTag, setNewTag] = useState("")
+
+ const addCondition = () => {
+ setFormData({
+ ...formData,
+ conditions: [...formData.conditions, { field: "", operator: "", value: "" }],
+ })
+ }
+
+ const removeCondition = (index: number) => {
+ setFormData({
+ ...formData,
+ conditions: formData.conditions.filter((_, i) => i !== index),
+ })
+ }
+
+ const addTag = () => {
+ if (newTag && !formData.tags.includes(newTag)) {
+ setFormData({ ...formData, tags: [...formData.tags, newTag] })
+ setNewTag("")
+ }
+ }
+
+ const removeTag = (tag: string) => {
+ setFormData({ ...formData, tags: formData.tags.filter((t) => t !== tag) })
+ }
+
+ const handleSubmit = () => {
+ console.log("创建流量包:", formData)
+ onOpenChange(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/package-preview-dialog.tsx b/components/dialogs/package-preview-dialog.tsx
new file mode 100644
index 0000000..9b3895b
--- /dev/null
+++ b/components/dialogs/package-preview-dialog.tsx
@@ -0,0 +1,105 @@
+"use client"
+
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Download, Users, TrendingUp, Clock } from "lucide-react"
+
+interface PackagePreviewDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ packageData?: {
+ name: string
+ description: string
+ users: number
+ tags: string[]
+ }
+}
+
+const MOCK_USERS = [
+ { id: "U001", name: "张**", phone: "138****1234", rfmScore: 92, clvScore: 85, tags: ["高价值", "活跃"] },
+ { id: "U002", name: "李**", phone: "139****5678", rfmScore: 88, clvScore: 79, tags: ["高价值", "VIP"] },
+ { id: "U003", name: "王**", phone: "137****9012", rfmScore: 85, clvScore: 82, tags: ["高价值", "活跃"] },
+ { id: "U004", name: "赵**", phone: "136****3456", rfmScore: 91, clvScore: 88, tags: ["高价值", "忠诚"] },
+ { id: "U005", name: "刘**", phone: "135****7890", rfmScore: 87, clvScore: 76, tags: ["高价值"] },
+]
+
+export function PackagePreviewDialog({ open, onOpenChange, packageData }: PackagePreviewDialogProps) {
+ return (
+
+ )
+}
diff --git a/components/dialogs/publish-api-dialog.tsx b/components/dialogs/publish-api-dialog.tsx
new file mode 100644
index 0000000..7e8fdae
--- /dev/null
+++ b/components/dialogs/publish-api-dialog.tsx
@@ -0,0 +1,192 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Code, Plus, X } from "lucide-react"
+
+interface PublishApiDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+export function PublishApiDialog({ open, onOpenChange }: PublishApiDialogProps) {
+ const [formData, setFormData] = useState({
+ name: "",
+ description: "",
+ endpoint: "/api/v1/",
+ method: "GET",
+ params: [] as { name: string; type: string; required: boolean; desc: string }[],
+ rateLimit: "1000",
+ })
+
+ const addParam = () => {
+ setFormData({
+ ...formData,
+ params: [...formData.params, { name: "", type: "string", required: false, desc: "" }],
+ })
+ }
+
+ const removeParam = (index: number) => {
+ setFormData({
+ ...formData,
+ params: formData.params.filter((_, i) => i !== index),
+ })
+ }
+
+ const handleSubmit = () => {
+ console.log("发布API:", formData)
+ onOpenChange(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/schedule-calendar-dialog.tsx b/components/dialogs/schedule-calendar-dialog.tsx
new file mode 100644
index 0000000..df5311b
--- /dev/null
+++ b/components/dialogs/schedule-calendar-dialog.tsx
@@ -0,0 +1,121 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { ChevronLeft, ChevronRight } from "lucide-react"
+
+interface ScheduleCalendarDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+const MOCK_SCHEDULE = [
+ {
+ day: 12,
+ tasks: [
+ { name: "数据同步", type: "sync" },
+ { name: "CLV训练", type: "model" },
+ ],
+ },
+ { day: 13, tasks: [{ name: "标签计算", type: "tagging" }] },
+ {
+ day: 14,
+ tasks: [
+ { name: "数据清洗", type: "cleaning" },
+ { name: "RFM评估", type: "model" },
+ ],
+ },
+ { day: 15, tasks: [{ name: "流失预警", type: "model" }] },
+ { day: 16, tasks: [{ name: "数据同步", type: "sync" }] },
+ { day: 18, tasks: [{ name: "用户分群", type: "tagging" }] },
+ { day: 20, tasks: [{ name: "数据清洗", type: "cleaning" }] },
+]
+
+const TYPE_COLORS: Record = {
+ sync: "bg-blue-100 text-blue-700",
+ cleaning: "bg-green-100 text-green-700",
+ tagging: "bg-purple-100 text-purple-700",
+ model: "bg-orange-100 text-orange-700",
+}
+
+export function ScheduleCalendarDialog({ open, onOpenChange }: ScheduleCalendarDialogProps) {
+ const [currentMonth, setCurrentMonth] = useState(new Date(2025, 11))
+
+ const daysInMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 0).getDate()
+ const firstDayOfMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth(), 1).getDay()
+
+ const days = Array.from({ length: daysInMonth }, (_, i) => i + 1)
+ const emptyDays = Array.from({ length: firstDayOfMonth }, (_, i) => i)
+
+ const getTasksForDay = (day: number) => {
+ return MOCK_SCHEDULE.find((s) => s.day === day)?.tasks || []
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/task-detail-dialog.tsx b/components/dialogs/task-detail-dialog.tsx
new file mode 100644
index 0000000..0fb110a
--- /dev/null
+++ b/components/dialogs/task-detail-dialog.tsx
@@ -0,0 +1,228 @@
+"use client"
+
+import { useState } from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { Progress } from "@/components/ui/progress"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { Play, Pause, RefreshCw, Clock, CheckCircle, XCircle } from "lucide-react"
+
+interface TaskDetailDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ task?: {
+ id: string
+ name: string
+ type: string
+ status: string
+ progress: number
+ schedule: string
+ lastRun: string
+ nextRun: string
+ duration: string
+ }
+}
+
+const TASK_LOGS = [
+ { time: "14:35:12", level: "INFO", message: "任务开始执行" },
+ { time: "14:35:13", level: "INFO", message: "连接数据源成功" },
+ { time: "14:35:15", level: "INFO", message: "开始读取数据 (批次 1/10)" },
+ { time: "14:35:22", level: "INFO", message: "批次 1 处理完成, 共 12,895 条" },
+ { time: "14:35:25", level: "INFO", message: "开始读取数据 (批次 2/10)" },
+ { time: "14:35:32", level: "WARN", message: "批次 2 发现 3 条异常数据" },
+ { time: "14:35:35", level: "INFO", message: "批次 2 处理完成, 共 12,456 条" },
+ { time: "14:36:02", level: "INFO", message: "任务进度: 67%" },
+]
+
+const EXECUTION_STATS = [
+ { label: "总处理记录", value: "128,956" },
+ { label: "成功记录", value: "128,931" },
+ { label: "失败记录", value: "25" },
+ { label: "平均速度", value: "3,800 条/秒" },
+ { label: "内存使用", value: "2.4 GB" },
+ { label: "CPU使用", value: "45%" },
+]
+
+export function TaskDetailDialog({ open, onOpenChange, task }: TaskDetailDialogProps) {
+ const [activeTab, setActiveTab] = useState("overview")
+
+ const getStatusBadge = (status: string) => {
+ switch (status) {
+ case "running":
+ return (
+
+
+ 运行中
+
+ )
+ case "completed":
+ return (
+
+
+ 已完成
+
+ )
+ case "failed":
+ return (
+
+
+ 失败
+
+ )
+ case "waiting":
+ return (
+
+
+ 等待中
+
+ )
+ default:
+ return {status}
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/components/dialogs/upload-model-dialog.tsx b/components/dialogs/upload-model-dialog.tsx
new file mode 100644
index 0000000..0c4b508
--- /dev/null
+++ b/components/dialogs/upload-model-dialog.tsx
@@ -0,0 +1,193 @@
+"use client"
+
+import { useState } from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Upload, FileCode, CheckCircle } from "lucide-react"
+
+interface UploadModelDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+}
+
+export function UploadModelDialog({ open, onOpenChange }: UploadModelDialogProps) {
+ const [step, setStep] = useState(1)
+ const [formData, setFormData] = useState({
+ name: "",
+ category: "",
+ description: "",
+ inputFeatures: "",
+ outputFormat: "",
+ updateFrequency: "",
+ })
+ const [fileUploaded, setFileUploaded] = useState(false)
+
+ const handleFileUpload = () => {
+ setFileUploaded(true)
+ }
+
+ const handleSubmit = () => {
+ console.log("上传模型:", formData)
+ onOpenChange(false)
+ setStep(1)
+ setFileUploaded(false)
+ }
+
+ return (
+