feat: enhance user profile with detailed tags and asset evaluation

Optimize user detail page for asset assessment and tag info.

#VERCEL_SKIP

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
v0
2025-08-21 05:32:37 +00:00
parent 9bb0ee2758
commit afc77439bb
25 changed files with 2421 additions and 1645 deletions

View File

@@ -1,71 +1,105 @@
"use client"
import { useCallback, useMemo, useState } from "react"
import { BarChart3, Database, FileText } from 'lucide-react'
import { TrendingUp, FileText, Sparkles } from "lucide-react"
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
import { Button } from "@/components/ui/button"
import { Textarea } from "@/components/ui/textarea"
import TaskList from "@/components/ai-assistant/task-list"
import CreateTaskDialog from "@/components/ai-assistant/create-task-dialog"
import ReportCards from "@/components/ai-assistant/report-cards"
import { sanitizeText } from "@/lib/text-sanitize"
import type { AnalysisTask, DatabaseInfo, ReportItem, ReportTemplate } from "@/types/ai-assistant"
import type { AnalysisTask, ReportItem, ReportTemplate } from "@/types/ai-assistant"
const initialTasks: AnalysisTask[] = [
{
id: "task_001",
name: "用户行为分析报告",
database: "微信用户数据",
name: "用户资产价值评估报告",
database: "用户数据",
status: "completed",
progress: 100,
createdAt: "2025-01-15T09:00:00Z",
completedAt: "2025-01-15T09:30:00Z",
reportUrl: "/reports/user-behavior-analysis.pdf",
description: "基于近30天行为的聚合与序列分析",
reportUrl: "/reports/user-asset-evaluation.pdf",
description: "基于RFM模型和行为数据的用户资产价值评估",
},
{
id: "task_002",
name: "流量关键词趋势分析",
database: "流量关键词库",
name: "高价值用户画像分析",
database: "用户池数据",
status: "running",
progress: 65,
createdAt: "2025-01-15T10:00:00Z",
description: "关注核心流量词与曝光、点击、转化等指标",
description: "识别高价值用户特征和行为模式",
},
{
id: "task_003",
name: "用户价值分层报告",
database: "微信用户数据",
name: "用户生命周期价值预测",
database: "用户数据",
status: "pending",
progress: 0,
createdAt: "2025-01-15T10:30:00Z",
description: "RFM 分层、价值区间分布与运营建议",
description: "预测用户未来价值和流失风险",
},
]
const databases: DatabaseInfo[] = [
{ id: "db_001", name: "微信用户数据库", type: "MySQL", tables: 25, records: 4000000000, lastUpdated: "2025-01-15T11:00:00Z" },
{ id: "db_002", name: "流量关键词库", type: "PostgreSQL", tables: 8, records: 150000, lastUpdated: "2025-01-15T10:45:00Z" },
{ id: "db_003", name: "用户行为日志", type: "MongoDB", tables: 12, records: 1500000000, lastUpdated: "2025-01-15T11:15:00Z" },
]
const templates: ReportTemplate[] = [
{ id: "template_001", name: "用户画像分析报告", description: "深度分析用户特征、行为模式和价值分层", category: "用户分析", fields: ["用户基本信息", "RFM分析", "行为轨迹", "价值评估", "推荐策略"] },
{ id: "template_002", name: "流量趋势分析报告", description: "分析关键词搜索趋势和流量变化", category: "流量分析", fields: ["关键词热度", "搜索趋势", "竞争分析", "机会识别", "优化建议"] },
{ id: "template_003", name: "业务运营报告", description: "综合业务数据分析和运营建议", category: "运营分析", fields: ["核心指标", "增长分析", "用户留存", "转化漏斗", "运营建议"] },
{ id: "template_004", name: "数据质量报告", description: "评估数据完整性、准确性和一致性", category: "数据质量", fields: ["数据完整性", "准确性检查", "一致性验证", "异常检测", "改进建议"] },
{
id: "template_001",
name: "用户资产评估报告",
description: "全面评估用户资产价值和投资回报",
category: "资产评估",
fields: ["资产总值", "RFM分析", "价值分层", "投资回报", "增值建议"],
isEditable: true,
},
{
id: "template_002",
name: "用户价值分析报告",
description: "深度分析用户价值构成和增长潜力",
category: "价值分析",
fields: ["价值构成", "增长趋势", "潜力评估", "风险分析", "优化策略"],
isEditable: true,
},
{
id: "template_003",
name: "用户生命周期报告",
description: "分析用户生命周期各阶段的价值贡献",
category: "生命周期",
fields: ["阶段划分", "价值贡献", "转化率", "留存分析", "提升方案"],
isEditable: true,
},
]
const reportItems: ReportItem[] = [
{ id: "rpt-1", title: "用户行为分析报告", source: "数据源:微信用户数据库", description: '本报告基于近30天互动行为输出用户行为模式与高频路径。\\n"]]}', updatedAt: new Date().toISOString() },
{ id: "rpt-2", title: "流量关键词趋势分析", source: "数据源:流量关键词库", description: '追踪 000000 类流量词及其曝光、点击、转化趋势,适配日/周/月视角。\\n" ]]}', updatedAt: new Date().toISOString() },
{ id: "rpt-3", title: "用户价值分层报告", source: "数据源:微信用户数据库", description: '结合 RFM 得分与标签,给出 S/A/B/C/D 分层与经营建议。\\n" ]] }', updatedAt: new Date().toISOString() },
{
id: "rpt-1",
title: "用户资产评估报告",
source: "数据源:用户池",
description: "基于用户行为和交易数据,评估用户资产价值和投资回报率。",
updatedAt: new Date().toISOString(),
},
{
id: "rpt-2",
title: "高价值用户分析",
source: "数据源:用户池",
description: "识别和分析高价值用户的特征、行为模式和价值贡献。",
updatedAt: new Date().toISOString(),
},
{
id: "rpt-3",
title: "用户价值预测模型",
source: "数据源:用户池",
description: "基于机器学习预测用户未来价值和生命周期价值。",
updatedAt: new Date().toISOString(),
},
]
export default function AIAssistantPage() {
const [tasks, setTasks] = useState<AnalysisTask[]>(initialTasks)
const [editingTemplate, setEditingTemplate] = useState<string | null>(null)
const [templateContent, setTemplateContent] = useState<string>("")
// 进度推进(仅演示用)
const tick = useCallback(() => {
setTasks((prev) =>
prev.map((t) => {
@@ -95,28 +129,36 @@ export default function AIAssistantPage() {
}, 800)
}
const sanitizedItems = useMemo(
() => reportItems.map((i) => ({ ...i, description: sanitizeText(i.description) })),
[],
)
const handleEditTemplate = (templateId: string) => {
setEditingTemplate(templateId)
const template = templates.find((t) => t.id === templateId)
setTemplateContent(template?.fields.join("\n") || "")
}
const handleSaveTemplate = () => {
// 保存模板逻辑
setEditingTemplate(null)
setTemplateContent("")
}
const sanitizedItems = useMemo(() => reportItems.map((i) => ({ ...i, description: sanitizeText(i.description) })), [])
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-indigo-50">
<div className="container mx-auto px-4 py-8">
<div className="mb-6">
<h1 className="text-3xl font-bold">AI智能助手</h1>
<p className="text-gray-600"></p>
<h1 className="text-3xl font-bold flex items-center gap-2">
<Sparkles className="h-8 w-8 text-blue-500" />
AI智能助手
</h1>
<p className="text-gray-600"></p>
</div>
<Tabs defaultValue="analysis" className="space-y-6">
<TabsList className="grid w-full grid-cols-3">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="analysis" className="flex items-center gap-2">
<BarChart3 className="w-4 h-4" />
</TabsTrigger>
<TabsTrigger value="databases" className="flex items-center gap-2">
<Database className="w-4 h-4" />
<TrendingUp className="w-4 h-4" />
</TabsTrigger>
<TabsTrigger value="templates" className="flex items-center gap-2">
<FileText className="w-4 h-4" />
@@ -126,8 +168,8 @@ export default function AIAssistantPage() {
<TabsContent value="analysis" className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-xl font-semibold"></h2>
<CreateTaskDialog databases={databases} templates={templates} onCreate={onCreate} />
<h2 className="text-xl font-semibold"></h2>
<CreateTaskDialog databases={[]} templates={templates} onCreate={onCreate} />
</div>
<TaskList tasks={tasks} onTick={tick} />
@@ -135,38 +177,12 @@ export default function AIAssistantPage() {
<ReportCards items={sanitizedItems} />
</TabsContent>
<TabsContent value="databases">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Database className="w-4 h-4" />
</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{databases.map((db) => (
<Card key={db.id} className="border">
<CardContent className="p-4 space-y-1">
<div className="font-medium">{db.name}</div>
<div className="text-sm text-gray-600">
{db.type} · {db.tables}
</div>
<div className="text-xs text-gray-500">
{new Date(db.lastUpdated).toLocaleString("zh-CN")}
</div>
</CardContent>
</Card>
))}
</CardContent>
</Card>
</TabsContent>
<TabsContent value="templates">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileText className="w-4 h-4" />
</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
@@ -175,7 +191,29 @@ export default function AIAssistantPage() {
<CardContent className="p-4 space-y-2">
<div className="font-medium">{t.name}</div>
<div className="text-sm text-gray-600">{t.category}</div>
<div className="text-xs text-gray-500">: {t.fields.join(" / ")}</div>
<div className="text-xs text-gray-500">{t.description}</div>
{editingTemplate === t.id ? (
<div className="space-y-2">
<Textarea
value={templateContent}
onChange={(e) => setTemplateContent(e.target.value)}
placeholder="编辑模板字段..."
className="text-xs"
/>
<div className="flex gap-2">
<Button size="sm" onClick={handleSaveTemplate}>
</Button>
<Button size="sm" variant="outline" onClick={() => setEditingTemplate(null)}>
</Button>
</div>
</div>
) : (
<Button size="sm" variant="outline" onClick={() => handleEditTemplate(t.id)} className="w-full">
</Button>
)}
</CardContent>
</Card>
))}