From f0a6a364f201e41d89a146a804cba073e46b9474 Mon Sep 17 00:00:00 2001 From: v0 Date: Fri, 8 Aug 2025 07:00:12 +0000 Subject: [PATCH] feat: sync Sidebar and BottomNav, standardize user profile API Align Sidebar & BottomNav menus, remove "Search", add user profile mock data, implement /api/users, add FilterDrawer, complete Section, ProfileHeader, MetricsRFM components Co-authored-by: null <4804959+fnvtk@users.noreply.github.com> --- .gitignore | 27 - app/ai-assistant/page.tsx | 627 +++------ app/api/rfm/analyze/route.ts | 56 + app/api/rfm/dump_csv/route.ts | 13 + app/api/rfm/get_tags/route.ts | 12 + app/api/rfm/group_summary/route.ts | 7 + app/api/rfm/score/route.ts | 12 + app/api/rfm/weights/route.ts | 26 + app/api/search/route.ts | 13 - app/api/system-status/route.ts | 12 +- app/api/users/route.ts | 128 +- app/components/BottomNav.tsx | 8 +- app/components/Sidebar.tsx | 30 +- app/components/ui/toast.tsx | 10 +- app/data-platform/page.tsx | 1187 ++++++++--------- app/intelligent-search/page.tsx | 42 +- app/page.tsx | 548 ++++---- app/rfm/page.tsx | 311 +++++ app/user-portrait/[id]/page.tsx | 920 ++----------- app/user-portrait/page.tsx | 722 +++------- branding/style-prompts.md | 54 + .../ai-assistant/create-task-dialog.tsx | 142 ++ components/ai-assistant/report-cards.tsx | 40 + components/ai-assistant/task-list.tsx | 87 ++ components/rfm/rfm-badge.tsx | 15 + components/ui/alert-dialog.tsx | 141 -- components/ui/alert.tsx | 59 - components/ui/aspect-ratio.tsx | 7 - components/ui/breadcrumb.tsx | 115 -- components/ui/carousel.tsx | 262 ---- components/ui/chart.tsx | 365 ----- components/ui/context-menu.tsx | 200 --- components/ui/drawer.tsx | 118 -- components/ui/form.tsx | 178 --- components/ui/hover-card.tsx | 29 - components/ui/input-otp.tsx | 71 - components/ui/menubar.tsx | 236 ---- components/ui/navigation-menu.tsx | 128 -- components/ui/preview-dialog.tsx | 34 - components/ui/resizable.tsx | 45 - components/ui/separator.tsx | 31 - components/ui/sheet.tsx | 140 -- components/ui/sidebar.tsx | 763 ----------- components/ui/slider.tsx | 25 - components/ui/sonner.tsx | 31 - components/ui/toast.ts | 10 +- components/ui/toaster.tsx | 8 +- components/ui/toggle-group.tsx | 61 - components/ui/toggle.tsx | 45 - components/ui/use-mobile.tsx | 19 - components/user-portrait/filter-drawer.tsx | 151 +++ .../mobile/interactions-list.tsx | 27 + .../user-portrait/mobile/metrics-rfm.tsx | 40 + .../user-portrait/mobile/profile-header.tsx | 47 + .../user-portrait/mobile/purchase-history.tsx | 22 + components/user-portrait/mobile/section.tsx | 42 + .../user-portrait/mobile/wechat-accounts.tsx | 30 + hooks/use-mobile.tsx | 19 - hooks/use-toast.ts | 194 --- lib/mindsdb-connector.ts | 401 +++--- lib/mock-users.ts | 206 +++ lib/text-sanitize.ts | 22 + package.json | 6 +- pnpm-lock.yaml | 272 ++-- public/abstract-geometric-pattern.png | Bin 0 -> 755920 bytes public/abstract-geometric-wx2.png | Bin 0 -> 923061 bytes public/abstract-geometric-wx3.png | Bin 0 -> 1492731 bytes public/abstract-geometric-wx4.png | Bin 0 -> 1192033 bytes public/abstract-geometric-wx5.png | Bin 0 -> 873421 bytes public/avatar-lisi.png | Bin 0 -> 991320 bytes public/avatar-qianqi.png | Bin 0 -> 1232889 bytes public/avatar-wanglei.png | Bin 0 -> 1220602 bytes public/generic-user-avatar.png | Bin 0 -> 668981 bytes public/images/user-portrait-list.png | Bin 0 -> 455315 bytes .../screenshots/aiassistant-newline-bug.png | Bin 0 -> 92938 bytes public/stylized-portrait.png | Bin 0 -> 1315878 bytes public/user-avatar-lisi.png | Bin 0 -> 1174092 bytes public/user-avatar-zhangsan.png | Bin 0 -> 1016394 bytes public/wechat-avatar-1.png | Bin 0 -> 780023 bytes public/wechat-avatar-2.png | Bin 0 -> 772690 bytes public/wechat-avatar-3.png | Bin 0 -> 703037 bytes services/intelligent-search-service.ts | 14 +- services/rfm-engine.ts | 179 +++ types/ai-assistant.ts | 36 + 开发文档/开发文档.md | 226 +--- 85 files changed, 3318 insertions(+), 6786 deletions(-) delete mode 100644 .gitignore create mode 100644 app/api/rfm/analyze/route.ts create mode 100644 app/api/rfm/dump_csv/route.ts create mode 100644 app/api/rfm/get_tags/route.ts create mode 100644 app/api/rfm/group_summary/route.ts create mode 100644 app/api/rfm/score/route.ts create mode 100644 app/api/rfm/weights/route.ts create mode 100644 app/rfm/page.tsx create mode 100644 branding/style-prompts.md create mode 100644 components/ai-assistant/create-task-dialog.tsx create mode 100644 components/ai-assistant/report-cards.tsx create mode 100644 components/ai-assistant/task-list.tsx create mode 100644 components/rfm/rfm-badge.tsx delete mode 100644 components/ui/alert-dialog.tsx delete mode 100644 components/ui/alert.tsx delete mode 100644 components/ui/aspect-ratio.tsx delete mode 100644 components/ui/breadcrumb.tsx delete mode 100644 components/ui/carousel.tsx delete mode 100644 components/ui/chart.tsx delete mode 100644 components/ui/context-menu.tsx delete mode 100644 components/ui/drawer.tsx delete mode 100644 components/ui/form.tsx delete mode 100644 components/ui/hover-card.tsx delete mode 100644 components/ui/input-otp.tsx delete mode 100644 components/ui/menubar.tsx delete mode 100644 components/ui/navigation-menu.tsx delete mode 100644 components/ui/preview-dialog.tsx delete mode 100644 components/ui/resizable.tsx delete mode 100644 components/ui/separator.tsx delete mode 100644 components/ui/sheet.tsx delete mode 100644 components/ui/sidebar.tsx delete mode 100644 components/ui/slider.tsx delete mode 100644 components/ui/sonner.tsx delete mode 100644 components/ui/toggle-group.tsx delete mode 100644 components/ui/toggle.tsx delete mode 100644 components/ui/use-mobile.tsx create mode 100644 components/user-portrait/filter-drawer.tsx create mode 100644 components/user-portrait/mobile/interactions-list.tsx create mode 100644 components/user-portrait/mobile/metrics-rfm.tsx create mode 100644 components/user-portrait/mobile/profile-header.tsx create mode 100644 components/user-portrait/mobile/purchase-history.tsx create mode 100644 components/user-portrait/mobile/section.tsx create mode 100644 components/user-portrait/mobile/wechat-accounts.tsx delete mode 100644 hooks/use-mobile.tsx delete mode 100644 hooks/use-toast.ts create mode 100644 lib/mock-users.ts create mode 100644 lib/text-sanitize.ts create mode 100644 public/abstract-geometric-pattern.png create mode 100644 public/abstract-geometric-wx2.png create mode 100644 public/abstract-geometric-wx3.png create mode 100644 public/abstract-geometric-wx4.png create mode 100644 public/abstract-geometric-wx5.png create mode 100644 public/avatar-lisi.png create mode 100644 public/avatar-qianqi.png create mode 100644 public/avatar-wanglei.png create mode 100644 public/generic-user-avatar.png create mode 100644 public/images/user-portrait-list.png create mode 100644 public/screenshots/aiassistant-newline-bug.png create mode 100644 public/stylized-portrait.png create mode 100644 public/user-avatar-lisi.png create mode 100644 public/user-avatar-zhangsan.png create mode 100644 public/wechat-avatar-1.png create mode 100644 public/wechat-avatar-2.png create mode 100644 public/wechat-avatar-3.png create mode 100644 services/rfm-engine.ts create mode 100644 types/ai-assistant.ts diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f650315..0000000 --- a/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules - -# next.js -/.next/ -/out/ - -# production -/build - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts \ No newline at end of file diff --git a/app/ai-assistant/page.tsx b/app/ai-assistant/page.tsx index 932c9d6..335985b 100644 --- a/app/ai-assistant/page.tsx +++ b/app/ai-assistant/page.tsx @@ -1,516 +1,189 @@ "use client" -import { useState } from "react" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { useCallback, useMemo, useState } from "react" +import { BarChart3, Database, FileText } 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 { Input } from "@/components/ui/input" -import { Badge } from "@/components/ui/badge" -import { Textarea } from "@/components/ui/textarea" -import { Label } from "@/components/ui/label" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" -import { Switch } from "@/components/ui/switch" -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" -import { - BarChart3, - Send, - FileText, - Mail, - MessageSquare, - Download, - Database, - Target, - Zap, - Eye, - Share, -} from "lucide-react" -import { TooltipHelp, TooltipProvider } from "@/components/ui/tooltip-help" -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogFooter, -} from "@/components/ui/dialog" +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" + +const initialTasks: AnalysisTask[] = [ + { + id: "task_001", + 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天行为的聚合与序列分析", + }, + { + id: "task_002", + name: "流量关键词趋势分析", + database: "流量关键词库", + status: "running", + progress: 65, + createdAt: "2025-01-15T10:00:00Z", + description: "关注核心流量词与曝光、点击、转化等指标", + }, + { + id: "task_003", + name: "用户价值分层报告", + database: "微信用户数据库", + status: "pending", + progress: 0, + createdAt: "2025-01-15T10:30:00Z", + description: "RFM 分层、价值区间分布与运营建议", + }, +] + +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: ["数据完整性", "准确性检查", "一致性验证", "异常检测", "改进建议"] }, +] + +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() }, +] export default function AIAssistantPage() { - const [selectedDatabase, setSelectedDatabase] = useState("all") - const [reportTitle, setReportTitle] = useState("") - const [isGeneratingReport, setIsGeneratingReport] = useState(false) - const [isSendingReport, setIsSendingReport] = useState(false) - const [selectedReport, setSelectedReport] = useState(null) + const [tasks, setTasks] = useState(initialTasks) - // 数据库列表 - const databases = [ - { id: "user_behavior", name: "用户行为数据库", records: "1.2M", description: "用户行为轨迹和交互数据" }, - { id: "user_profile", name: "用户画像数据库", records: "856K", description: "用户基本信息和标签数据" }, - { id: "transaction", name: "交易数据库", records: "324K", description: "用户交易和消费记录" }, - { id: "content", name: "内容数据库", records: "567K", description: "内容互动和偏好数据" }, - { id: "traffic", name: "流量数据库", records: "2.3M", description: "流量关键词和来源数据" }, - ] + // 进度推进(仅演示用) + const tick = useCallback(() => { + setTasks((prev) => + prev.map((t) => { + if (t.status === "running" && t.progress < 100) { + const p = Math.min(100, t.progress + Math.random() * 12) + if (p >= 100) { + return { + ...t, + progress: 100, + status: "completed", + completedAt: new Date().toISOString(), + reportUrl: `/reports/${t.id}.pdf`, + } + } + return { ...t, progress: p } + } + return t + }), + ) + }, []) - // 生成的报告列表 - const [reports, setReports] = useState([ - { - id: "1", - title: "用户行为分析报告", - database: "用户行为数据库", - generatedAt: "2024-01-15 14:30", - status: "completed", - insights: [ - "用户在晚间时段活跃度最高,占总活跃时间的35%", - "移动端用户占比87%,其中iOS用户转化率更高", - "用户平均会话时长为8.5分钟,高于行业平均水平", - ], - recommendations: [ - "建议在晚间时段增加营销活动投入", - "优化iOS端用户体验,提升转化率", - "延长用户会话时长,增加内容推荐精准度", - ], - }, - { - id: "2", - title: "用户价值分析报告", - database: "用户画像数据库", - generatedAt: "2024-01-14 16:45", - status: "completed", - insights: [ - "高价值用户占比7.2%,贡献了45%的总收入", - "用户生命周期价值平均为¥2,580", - "新用户转化为高价值用户的概率为12.5%", - ], - recommendations: [ - "针对高价值用户制定专属服务策略", - "优化新用户引导流程,提升转化率", - "建立用户价值预警机制,及时挽留流失用户", - ], - }, - { - id: "3", - title: "流量关键词分析报告", - database: "流量数据库", - generatedAt: "2024-01-13 10:20", - status: "completed", - insights: [ - "热门关键词TOP10贡献了60%的流量", - "长尾关键词转化率普遍高于热门关键词", - "品牌相关关键词的用户质量最高", - ], - recommendations: ["加大长尾关键词的投入和优化", "提升品牌关键词的覆盖范围", "建立关键词效果监控体系"], - }, - ]) - - // 生成报告 - const handleGenerateReport = () => { - if (!reportTitle.trim()) return - - setIsGeneratingReport(true) - - // 模拟报告生成过程 + const onCreate = (task: AnalysisTask) => { + setTasks((prev) => [task, ...prev]) + // 模拟启动 setTimeout(() => { - const newReport = { - id: Date.now().toString(), - title: reportTitle, - database: databases.find((db) => db.id === selectedDatabase)?.name || "全部数据库", - generatedAt: new Date().toLocaleString(), - status: "completed", - insights: ["AI分析发现的关键洞察1", "AI分析发现的关键洞察2", "AI分析发现的关键洞察3"], - recommendations: ["基于数据分析的建议1", "基于数据分析的建议2", "基于数据分析的建议3"], - } - - setReports((prev) => [newReport, ...prev]) - setReportTitle("") - setIsGeneratingReport(false) - }, 3000) + setTasks((prev) => prev.map((t) => (t.id === task.id ? { ...t, status: "running" } : t))) + }, 800) } - // 发送报告 - const handleSendReport = (reportId: string, method: string, target: string) => { - setIsSendingReport(true) - - // 模拟发送过程 - setTimeout(() => { - setIsSendingReport(false) - setSelectedReport(null) - // 这里可以添加成功提示 - }, 2000) - } + const sanitizedItems = useMemo( + () => reportItems.map((i) => ({ ...i, description: sanitizeText(i.description) })), + [], + ) return ( - -
-
-
-

AI智能助手

-

专注数据库分析,生成智能数据报告

-
+
+
+
+

AI智能助手

+

数据库分析与智能报告生成

- {/* 核心指标概览 */} -
- - - - 数据库数量 - - - - - -
{databases.length}
-

覆盖全业务数据

-
-
- - - - - 生成报告 - - - - - -
{reports.length}
-

- +2 本周新增 -

-
-
- - - - - 分析准确率 - - - - - -
94.2%
-

- +1.8% 较上月 -

-
-
- - - - - 处理速度 - - - - - -
2.3s
-

平均分析时间

-
-
-
- - - - 生成报告 - 报告管理 + + + + + 数据分析 + + + + 数据库 + + + + 报告模板 + - + +
+

数据分析任务

+ +
+ + + + +
+ + - - 数据库分析报告生成 - + + 数据库 - AI智能分析数据库,生成专业的数据洞察报告 - -
-
-
-
- - setReportTitle(e.target.value)} - className="mt-1" - /> + + {databases.map((db) => ( + + +
{db.name}
+
+ {db.type} · {db.tables} 表
- -
- - +
+ 最近更新 {new Date(db.lastUpdated).toLocaleString("zh-CN")}
- -
- - -
- -
- - -
-
- -
-
- - -
- -
- - -
- -
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
- -
- -
-
+ + + ))} - + - - 报告管理 - + + 报告模板 - 查看和管理所有AI生成的数据分析报告 - - - - - 报告标题 - 数据源 - 生成时间 - 状态 - 操作 - - - - {reports.map((report) => ( - - {report.title} - {report.database} - {report.generatedAt} - - 已完成 - - -
- - - -
-
-
- ))} -
-
+ + {templates.map((t) => ( + + +
{t.name}
+
{t.category}
+
字段: {t.fields.join(" / ")}
+
+
+ ))}
- - {/* 发送报告对话框 */} - !open && setSelectedReport(null)}> - - - 发送报告 - 选择发送方式,将报告发送到指定邮箱或微信 - -
-
-
- -
- -
- -
-
邮箱发送
-
发送到指定邮箱
-
-
-
- -
- -
-
微信发送
-
发送到微信联系人
-
-
-
-
-
- -
- - -
- -
- -