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>
This commit is contained in:
@@ -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<string | null>(null)
|
||||
const [tasks, setTasks] = useState<AnalysisTask[]>(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 (
|
||||
<TooltipProvider>
|
||||
<div className="container mx-auto p-6 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">AI智能助手</h1>
|
||||
<p className="text-muted-foreground mt-2">专注数据库分析,生成智能数据报告</p>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
{/* 核心指标概览 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
数据库数量
|
||||
<TooltipHelp content="可分析的数据库总数,包含用户、交易、行为等各类数据" />
|
||||
</CardTitle>
|
||||
<Database className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{databases.length}</div>
|
||||
<p className="text-xs text-muted-foreground">覆盖全业务数据</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
生成报告
|
||||
<TooltipHelp content="AI自动生成的数据分析报告总数" />
|
||||
</CardTitle>
|
||||
<FileText className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{reports.length}</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<span className="text-green-600">+2</span> 本周新增
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
分析准确率
|
||||
<TooltipHelp content="AI数据分析的准确率,基于历史验证结果计算" />
|
||||
</CardTitle>
|
||||
<Target className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">94.2%</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<span className="text-green-600">+1.8%</span> 较上月
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
处理速度
|
||||
<TooltipHelp content="AI分析处理的平均速度,包括数据读取和分析时间" />
|
||||
</CardTitle>
|
||||
<Zap className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">2.3s</div>
|
||||
<p className="text-xs text-muted-foreground">平均分析时间</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="generate" className="space-y-6">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="generate">生成报告</TabsTrigger>
|
||||
<TabsTrigger value="reports">报告管理</TabsTrigger>
|
||||
<Tabs defaultValue="analysis" className="space-y-6">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<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" />
|
||||
数据库
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="templates" className="flex items-center gap-2">
|
||||
<FileText className="w-4 h-4" />
|
||||
报告模板
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="generate" className="space-y-6">
|
||||
<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} />
|
||||
</div>
|
||||
|
||||
<TaskList tasks={tasks} onTick={tick} />
|
||||
|
||||
<ReportCards items={sanitizedItems} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="databases">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<BarChart3 className="h-5 w-5" />
|
||||
数据库分析报告生成
|
||||
<TooltipHelp content="选择数据库并配置分析参数,AI将自动生成详细的数据分析报告" />
|
||||
<Database className="w-4 h-4" />
|
||||
数据库
|
||||
</CardTitle>
|
||||
<CardDescription>AI智能分析数据库,生成专业的数据洞察报告</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="report-title">报告标题</Label>
|
||||
<Input
|
||||
id="report-title"
|
||||
placeholder="请输入报告标题..."
|
||||
value={reportTitle}
|
||||
onChange={(e) => setReportTitle(e.target.value)}
|
||||
className="mt-1"
|
||||
/>
|
||||
<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>
|
||||
<Label htmlFor="database-select">选择数据库</Label>
|
||||
<Select value={selectedDatabase} onValueChange={setSelectedDatabase}>
|
||||
<SelectTrigger id="database-select" className="mt-1">
|
||||
<SelectValue placeholder="选择要分析的数据库" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">全部数据库</SelectItem>
|
||||
{databases.map((db) => (
|
||||
<SelectItem key={db.id} value={db.id}>
|
||||
{db.name} ({db.records})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="text-xs text-gray-500">
|
||||
最近更新 {new Date(db.lastUpdated).toLocaleString("zh-CN")}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="analysis-type">分析类型</Label>
|
||||
<Select defaultValue="comprehensive">
|
||||
<SelectTrigger id="analysis-type" className="mt-1">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="comprehensive">综合分析</SelectItem>
|
||||
<SelectItem value="behavior">行为分析</SelectItem>
|
||||
<SelectItem value="value">价值分析</SelectItem>
|
||||
<SelectItem value="trend">趋势分析</SelectItem>
|
||||
<SelectItem value="conversion">转化分析</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="time-range">时间范围</Label>
|
||||
<Select defaultValue="30days">
|
||||
<SelectTrigger id="time-range" className="mt-1">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="7days">近7天</SelectItem>
|
||||
<SelectItem value="30days">近30天</SelectItem>
|
||||
<SelectItem value="90days">近90天</SelectItem>
|
||||
<SelectItem value="1year">近1年</SelectItem>
|
||||
<SelectItem value="custom">自定义</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="analysis-depth">分析深度</Label>
|
||||
<Select defaultValue="standard">
|
||||
<SelectTrigger id="analysis-depth" className="mt-1">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="basic">基础分析</SelectItem>
|
||||
<SelectItem value="standard">标准分析</SelectItem>
|
||||
<SelectItem value="deep">深度分析</SelectItem>
|
||||
<SelectItem value="expert">专家级分析</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="output-format">输出格式</Label>
|
||||
<Select defaultValue="detailed">
|
||||
<SelectTrigger id="output-format" className="mt-1">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="summary">摘要报告</SelectItem>
|
||||
<SelectItem value="detailed">详细报告</SelectItem>
|
||||
<SelectItem value="executive">高管报告</SelectItem>
|
||||
<SelectItem value="technical">技术报告</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>包含内容</Label>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="include-insights" defaultChecked />
|
||||
<Label htmlFor="include-insights">数据洞察</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="include-recommendations" defaultChecked />
|
||||
<Label htmlFor="include-recommendations">优化建议</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="include-charts" defaultChecked />
|
||||
<Label htmlFor="include-charts">图表分析</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="include-predictions" />
|
||||
<Label htmlFor="include-predictions">趋势预测</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
onClick={handleGenerateReport}
|
||||
disabled={isGeneratingReport || !reportTitle.trim()}
|
||||
className="px-8"
|
||||
>
|
||||
{isGeneratingReport ? (
|
||||
<>
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||
生成中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<BarChart3 className="h-4 w-4 mr-2" />
|
||||
生成AI分析报告
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="reports" className="space-y-6">
|
||||
<TabsContent value="templates">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<FileText className="h-5 w-5" />
|
||||
报告管理
|
||||
<TooltipHelp content="管理所有生成的AI分析报告,支持查看、下载和分享" />
|
||||
<FileText className="w-4 h-4" />
|
||||
报告模板
|
||||
</CardTitle>
|
||||
<CardDescription>查看和管理所有AI生成的数据分析报告</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>报告标题</TableHead>
|
||||
<TableHead>数据源</TableHead>
|
||||
<TableHead>生成时间</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead>操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{reports.map((report) => (
|
||||
<TableRow key={report.id}>
|
||||
<TableCell className="font-medium">{report.title}</TableCell>
|
||||
<TableCell>{report.database}</TableCell>
|
||||
<TableCell>{report.generatedAt}</TableCell>
|
||||
<TableCell>
|
||||
<Badge className="bg-green-100 text-green-800">已完成</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex space-x-2">
|
||||
<Button variant="ghost" size="sm">
|
||||
<Eye className="h-4 w-4 mr-1" />
|
||||
查看
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Download className="h-4 w-4 mr-1" />
|
||||
下载
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={() => setSelectedReport(report.id)}>
|
||||
<Share className="h-4 w-4 mr-1" />
|
||||
发送
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{templates.map((t) => (
|
||||
<Card key={t.id} className="border">
|
||||
<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>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{/* 发送报告对话框 */}
|
||||
<Dialog open={!!selectedReport} onOpenChange={(open) => !open && setSelectedReport(null)}>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>发送报告</DialogTitle>
|
||||
<DialogDescription>选择发送方式,将报告发送到指定邮箱或微信</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label>发送方式</Label>
|
||||
<div className="grid grid-cols-2 gap-4 mt-2">
|
||||
<Card className="cursor-pointer hover:bg-gray-50 p-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Mail className="h-6 w-6 text-blue-500" />
|
||||
<div>
|
||||
<div className="font-medium">邮箱发送</div>
|
||||
<div className="text-sm text-muted-foreground">发送到指定邮箱</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="cursor-pointer hover:bg-gray-50 p-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<MessageSquare className="h-6 w-6 text-green-500" />
|
||||
<div>
|
||||
<div className="font-medium">微信发送</div>
|
||||
<div className="text-sm text-muted-foreground">发送到微信联系人</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="send-target">发送目标</Label>
|
||||
<Input id="send-target" placeholder="请输入邮箱地址或微信号" className="mt-1" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="send-message">附加消息</Label>
|
||||
<Textarea id="send-message" placeholder="可选:添加附加消息" className="mt-1" rows={3} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>发送选项</Label>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="include-pdf" defaultChecked />
|
||||
<Label htmlFor="include-pdf">包含PDF版本</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="include-data" />
|
||||
<Label htmlFor="include-data">包含原始数据</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="schedule-send" />
|
||||
<Label htmlFor="schedule-send">定时发送</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setSelectedReport(null)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => handleSendReport(selectedReport!, "email", "target@example.com")}
|
||||
disabled={isSendingReport}
|
||||
>
|
||||
{isSendingReport ? (
|
||||
<>
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||
发送中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Send className="mr-2 h-4 w-4" />
|
||||
发送报告
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user