chore: 以本地为准,上传全部并替换 GitHub

This commit is contained in:
卡若
2026-02-03 11:36:53 +08:00
parent 1219166526
commit b404bf546e
131 changed files with 37618 additions and 3930 deletions

View File

@@ -1,234 +1,709 @@
"use client"
import { useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Input } from "@/components/ui/input"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import {
FileText, Download, Share2, Clock, Eye, Sparkles,
BarChart3, Users, TrendingUp, Calendar, Plus, Trash2
import {
FileText,
Plus,
Download,
RefreshCw,
Eye,
Calendar,
Users,
TrendingUp,
PieChart,
BarChart3,
Clock,
CheckCircle2,
Loader2,
Send,
Mail,
MessageSquare,
Play,
Sparkles,
} from "lucide-react"
const reportTemplates = [
{ id: "1", name: "用户增长分析报告", description: "分析用户增长趋势和渠道效果", icon: TrendingUp },
{ id: "2", name: "用户画像洞察报告", description: "深度分析用户特征和行为偏好", icon: Users },
{ id: "3", name: "数据质量评估报告", description: "评估数据完整性和准确性", icon: BarChart3 },
{ id: "4", name: "营销效果分析报告", description: "评估营销活动ROI和转化效果", icon: TrendingUp },
]
// 报告规则接口
interface ReportRule {
id: string
name: string
templateId: string
schedule: string
enabled: boolean
isDefault: boolean
config: {
dateRange: string
includeCharts: boolean
sendTo: string[]
format: 'pdf' | 'html' | 'markdown'
}
promptTemplate: string
}
const recentReports = [
// 报告模板
interface ReportTemplate {
id: string
name: string
description: string
type: 'daily' | 'weekly' | 'monthly' | 'custom'
sections: string[]
icon: string
}
// 默认报告规则
const DEFAULT_RULES: ReportRule[] = [
{
id: "r1",
name: "2024年1月用户增长分析报告",
template: "用户增长分析报告",
createdAt: "2024-01-15 14:30",
status: "completed",
pages: 12,
id: 'rule_daily',
name: '每日运营日报规则',
templateId: 'tpl_daily',
schedule: '每日 23:59',
enabled: true,
isDefault: true,
config: {
dateRange: 'today',
includeCharts: true,
sendTo: ['admin@company.com'],
format: 'pdf',
},
promptTemplate: `生成每日运营日报,包含以下内容:
1. 核心指标
- 总用户数及日增量
- 活跃用户数及活跃率
- 新增用户数
2. 用户活跃
- 各等级用户活跃情况
- 活跃时段分布
3. 渠道消息
- 各渠道消息量统计
- 响应时间分析
4. AI查询统计
- 查询次数
- 平均响应时间
- 热门查询类型
输出格式:结构化报告,包含数据表格和趋势描述`,
},
{
id: "r2",
name: "高价值用户画像洞察",
template: "用户画像洞察报告",
createdAt: "2024-01-14 10:20",
status: "completed",
pages: 8,
id: 'rule_weekly',
name: '周度数据质量规则',
templateId: 'tpl_weekly',
schedule: '每周日 00:00',
enabled: true,
isDefault: true,
config: {
dateRange: 'week',
includeCharts: true,
sendTo: ['data@company.com'],
format: 'pdf',
},
promptTemplate: `生成周度数据质量报告:
1. 质量概览
- 数据完整度评分
- 数据准确度评分
- 本周质量趋势
2. 清洗统计
- 清洗记录数
- 格式化字段数
- 异常数据处理
3. 去重效果
- 去重前后对比
- 重复率统计
4. 数据完整度
- 各字段填充率
- 缺失字段分析`,
},
{
id: "r3",
name: "Q4数据质量评估",
template: "数据质量评估报告",
createdAt: "2024-01-10 16:45",
status: "generating",
pages: 0,
id: 'rule_monthly',
name: '月度资产报告规则',
templateId: 'tpl_monthly',
schedule: '每月1日 08:00',
enabled: true,
isDefault: true,
config: {
dateRange: 'month',
includeCharts: true,
sendTo: ['admin@company.com', 'ceo@company.com'],
format: 'pdf',
},
promptTemplate: `生成月度用户资产报告:
1. 资产总览
- 用户总资产价值
- 月度变化趋势
- 核心指标汇总
2. 用户增长
- 新增用户分析
- 流失用户分析
- 净增长情况
3. RFM分析
- RFM评分分布
- 各等级用户占比
- 价值迁移分析
4. 流量池分布
- 各流量池规模
- 月度变化
- 转化分析
5. 标签覆盖
- 标签覆盖率
- 热门标签TOP10`,
},
]
export default function AIReportPage() {
const [showCreateDialog, setShowCreateDialog] = useState(false)
const [selectedTemplate, setSelectedTemplate] = useState("")
const [reportConfig, setReportConfig] = useState({
name: "",
dateRange: "last_30_days",
userSegment: "all",
customPrompt: "",
})
// 预定义报告模板
const REPORT_TEMPLATES: ReportTemplate[] = [
{
id: 'tpl_daily',
name: '每日运营日报',
description: '包含当日用户活跃、渠道消息、AI查询等实时数据汇总',
type: 'daily',
sections: ['核心指标', '用户活跃', '渠道消息', 'AI查询统计'],
icon: '📊',
},
{
id: 'tpl_weekly',
name: '周度数据质量报告',
description: '数据清洗、去重、补全等质量指标周度汇总',
type: 'weekly',
sections: ['质量概览', '清洗统计', '去重效果', '数据完整度'],
icon: '📈',
},
{
id: 'tpl_monthly',
name: '月度用户资产报告',
description: '用户增长、RFM分布、流量池变化等核心资产指标',
type: 'monthly',
sections: ['资产总览', '用户增长', 'RFM分析', '流量池分布', '标签覆盖'],
icon: '📑',
},
{
id: 'tpl_rfm',
name: 'RFM分析报告',
description: '详细的RFM评分分布和用户价值分层分析',
type: 'custom',
sections: ['RFM概览', '评分分布', '等级分层', '价值趋势'],
icon: '💎',
},
{
id: 'tpl_portrait',
name: '用户画像报告',
description: '用户画像特征分析,包含地域、年龄、偏好等维度',
type: 'custom',
sections: ['画像概览', '地域分布', '行为特征', '偏好分析'],
icon: '👤',
},
{
id: 'tpl_traffic',
name: '流量池分析报告',
description: '各流量池用户规模、转化率、价值贡献分析',
type: 'custom',
sections: ['池规模', '转化漏斗', '价值贡献', '增长趋势'],
icon: '🏊',
},
]
// 生成的报告
interface GeneratedReport {
id: string
templateId: string
title: string
generatedAt: string
status: 'ready' | 'generating'
content?: string
metrics: {
totalUsers: number
activeUsers: number
newUsers: number
rfmAvg: number
}
}
const GENERATED_REPORTS: GeneratedReport[] = [
{
id: 'rpt_1',
templateId: 'tpl_monthly',
title: '2024年1月用户资产月报',
generatedAt: '2024-02-01 08:00',
status: 'ready',
metrics: { totalUsers: 2013000000, activeUsers: 450000000, newUsers: 15000000, rfmAvg: 52.3 },
},
{
id: 'rpt_2',
templateId: 'tpl_weekly',
title: '本周数据质量报告',
generatedAt: '2024-01-28 00:00',
status: 'ready',
metrics: { totalUsers: 2013000000, activeUsers: 320000000, newUsers: 2500000, rfmAvg: 51.8 },
},
{
id: 'rpt_3',
templateId: 'tpl_daily',
title: '今日运营日报',
generatedAt: '2024-01-30 23:59',
status: 'ready',
metrics: { totalUsers: 2013000000, activeUsers: 45000000, newUsers: 350000, rfmAvg: 52.5 },
},
]
export default function ReportPage() {
const [reports, setReports] = useState<GeneratedReport[]>(GENERATED_REPORTS)
const [rules, setRules] = useState<ReportRule[]>(DEFAULT_RULES)
const [activeTab, setActiveTab] = useState("templates")
const [generating, setGenerating] = useState<string | null>(null)
const [showGenerateDialog, setShowGenerateDialog] = useState(false)
const [selectedTemplate, setSelectedTemplate] = useState<ReportTemplate | null>(null)
const [showPreviewDialog, setShowPreviewDialog] = useState(false)
const [previewReport, setPreviewReport] = useState<GeneratedReport | null>(null)
const [showRuleDialog, setShowRuleDialog] = useState(false)
const [selectedRule, setSelectedRule] = useState<ReportRule | null>(null)
const [editingPrompt, setEditingPrompt] = 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(0)}K`
return num.toLocaleString()
}
// 通过Skill生成报告
const generateReport = async (template: ReportTemplate) => {
setGenerating(template.id)
setShowGenerateDialog(false)
try {
// 调用AI Chat API执行报告生成
const response = await fetch('/api/ai-chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: `生成${template.name},包含以下章节:${template.sections.join('、')}`
})
})
const data = await response.json()
// 添加新报告到列表
const newReport: GeneratedReport = {
id: `rpt_${Date.now()}`,
templateId: template.id,
title: `${template.name} - ${new Date().toLocaleDateString()}`,
generatedAt: new Date().toLocaleString(),
status: 'ready',
content: data.success ? data.response?.content : '报告生成失败',
metrics: {
totalUsers: 2013000000,
activeUsers: 450000000,
newUsers: 15000000,
rfmAvg: 52.3,
},
}
setReports([newReport, ...reports])
} catch (error) {
console.error('报告生成失败:', error)
} finally {
setGenerating(null)
}
}
const openPreview = (report: GeneratedReport) => {
setPreviewReport(report)
setShowPreviewDialog(true)
}
return (
<div className="space-y-6">
{/* 页面标题 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-foreground"></h1>
<p className="text-muted-foreground">AI自动生成数据分析报告</p>
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50/30 to-purple-50/20">
<div className="p-6 space-y-6">
{/* 顶部标题 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-gray-900"></h1>
<p className="text-sm text-gray-500 mt-1">AI自动生成数据分析报告</p>
</div>
<Button onClick={() => setShowGenerateDialog(true)}>
<Plus className="h-4 w-4 mr-2" />
</Button>
</div>
<Button onClick={() => setShowCreateDialog(true)}>
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
{/* 报告模板 */}
<div>
<h2 className="text-lg font-semibold mb-4"></h2>
<div className="grid gap-4 md:grid-cols-4">
{reportTemplates.map((template) => (
<Card
key={template.id}
className="cursor-pointer hover:border-primary transition-colors"
onClick={() => {
setSelectedTemplate(template.id)
setShowCreateDialog(true)
}}
>
<CardContent className="pt-6">
<div className="flex flex-col items-center text-center">
<div className="p-3 rounded-full bg-primary/10 mb-3">
<template.icon className="h-6 w-6 text-primary" />
</div>
<h3 className="font-medium mb-1">{template.name}</h3>
<p className="text-sm text-muted-foreground">{template.description}</p>
{/* 标签页 */}
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className="bg-white/80 backdrop-blur">
<TabsTrigger value="templates"></TabsTrigger>
<TabsTrigger value="rules"></TabsTrigger>
<TabsTrigger value="history"></TabsTrigger>
</TabsList>
{/* 报告模板 */}
<TabsContent value="templates" className="mt-4">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{REPORT_TEMPLATES.map(template => (
<Card
key={template.id}
className="border-0 shadow-sm bg-white/80 hover:shadow-lg transition-all cursor-pointer group"
>
<CardContent className="p-5">
<div className="flex items-start justify-between mb-3">
<span className="text-3xl">{template.icon}</span>
<Badge variant="outline">{
template.type === 'daily' ? '日报' :
template.type === 'weekly' ? '周报' :
template.type === 'monthly' ? '月报' : '自定义'
}</Badge>
</div>
<h3 className="font-bold text-gray-900 text-lg mb-1">{template.name}</h3>
<p className="text-sm text-gray-500 mb-3">{template.description}</p>
<div className="flex flex-wrap gap-1 mb-4">
{template.sections.map((section, i) => (
<Badge key={i} variant="secondary" className="text-xs">{section}</Badge>
))}
</div>
<Button
className="w-full"
onClick={() => generateReport(template)}
disabled={generating === template.id}
>
{generating === template.id ? (
<><Loader2 className="h-4 w-4 animate-spin mr-2" />...</>
) : (
<><Play className="h-4 w-4 mr-2" /></>
)}
</Button>
</CardContent>
</Card>
))}
</div>
</TabsContent>
{/* 规则配置 */}
<TabsContent value="rules" className="mt-4 space-y-3">
{rules.map(rule => {
const template = REPORT_TEMPLATES.find(t => t.id === rule.templateId)
return (
<Card key={rule.id} className="border-0 shadow-sm bg-white/80 backdrop-blur">
<CardContent className="p-4">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="p-2.5 rounded-xl bg-gradient-to-r from-purple-500 to-blue-500 text-2xl">
{template?.icon || '📄'}
</div>
<div>
<div className="flex items-center gap-2">
<h3 className="font-semibold text-gray-900">{rule.name}</h3>
{rule.isDefault && <Badge variant="outline" className="text-xs"></Badge>}
{rule.enabled ? (
<Badge className="bg-green-100 text-green-700"></Badge>
) : (
<Badge className="bg-gray-100 text-gray-700"></Badge>
)}
</div>
<p className="text-sm text-gray-500">{template?.name}</p>
<div className="flex items-center gap-4 text-xs text-gray-400 mt-1">
<span className="flex items-center gap-1">
<Clock className="h-3 w-3" />
{rule.schedule}
</span>
<span>: {rule.config.format.toUpperCase()}</span>
<span>: {rule.config.sendTo.join(', ')}</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => {
setSelectedRule(rule)
setEditingPrompt(rule.promptTemplate)
setShowRuleDialog(true)
}}
>
</Button>
<Button
variant={rule.enabled ? "outline" : "default"}
size="sm"
onClick={() => setRules(rules.map(r => r.id === rule.id ? { ...r, enabled: !r.enabled } : r))}
>
{rule.enabled ? '禁用' : '启用'}
</Button>
</div>
</div>
</CardContent>
</Card>
)
})}
</TabsContent>
{/* 历史报告 */}
<TabsContent value="history" className="mt-4">
<Card className="border-0 shadow-sm bg-white/80">
<CardContent className="p-4">
<div className="space-y-3">
{reports.map(report => {
const template = REPORT_TEMPLATES.find(t => t.id === report.templateId)
return (
<div key={report.id} className="flex items-center justify-between p-4 rounded-xl bg-gray-50 hover:bg-gray-100 transition-colors">
<div className="flex items-center gap-4">
<div className="p-2.5 rounded-xl bg-white text-2xl">
{template?.icon || '📄'}
</div>
<div>
<h3 className="font-semibold text-gray-900">{report.title}</h3>
<div className="flex items-center gap-4 mt-1 text-xs text-gray-500">
<span className="flex items-center gap-1">
<Clock className="h-3 w-3" />
{report.generatedAt}
</span>
<span className="flex items-center gap-1">
<Users className="h-3 w-3" />
{formatNumber(report.metrics.totalUsers)}
</span>
<span>RFM均值: {report.metrics.rfmAvg}</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={() => openPreview(report)}>
<Eye className="h-4 w-4" />
</Button>
<Button variant="outline" size="sm">
<Download className="h-4 w-4" />
</Button>
<Button variant="outline" size="sm">
<Send className="h-4 w-4" />
</Button>
</div>
</div>
)
})}
</div>
</CardContent>
</Card>
))}
</div>
</div>
</TabsContent>
</Tabs>
{/* 最近报告 */}
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{recentReports.map((report) => (
<div
key={report.id}
className="flex items-center justify-between p-4 border rounded-lg hover:bg-muted/50 transition-colors"
>
<div className="flex items-center gap-4">
<div className="p-2 rounded-lg bg-primary/10">
<FileText className="h-5 w-5 text-primary" />
{/* 生成报告弹窗 */}
<Dialog open={showGenerateDialog} onOpenChange={setShowGenerateDialog}>
<DialogContent className="max-w-lg">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>AI将自动生成分析报告</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label></Label>
<Select onValueChange={(v) => setSelectedTemplate(REPORT_TEMPLATES.find(t => t.id === v) || null)}>
<SelectTrigger>
<SelectValue placeholder="选择报告模板" />
</SelectTrigger>
<SelectContent>
{REPORT_TEMPLATES.map(template => (
<SelectItem key={template.id} value={template.id}>
{template.icon} {template.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{selectedTemplate && (
<div className="p-3 rounded-lg bg-purple-50">
<p className="text-sm text-gray-600 mb-2">{selectedTemplate.description}</p>
<div className="flex flex-wrap gap-1">
{selectedTemplate.sections.map((section, i) => (
<Badge key={i} variant="secondary" className="text-xs">{section}</Badge>
))}
</div>
<div>
<h4 className="font-medium">{report.name}</h4>
<div className="flex items-center gap-4 text-sm text-muted-foreground">
<span>{report.template}</span>
<span className="flex items-center gap-1">
<Clock className="h-3 w-3" />
{report.createdAt}
</span>
{report.status === "completed" && (
<span>{report.pages}</span>
</div>
)}
<div className="space-y-2">
<Label></Label>
<Select defaultValue="all">
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="today"></SelectItem>
<SelectItem value="week"></SelectItem>
<SelectItem value="month"></SelectItem>
</SelectContent>
</Select>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowGenerateDialog(false)}></Button>
<Button
onClick={() => selectedTemplate && generateReport(selectedTemplate)}
disabled={!selectedTemplate}
>
<Sparkles className="h-4 w-4 mr-2" />
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* 报告预览弹窗 */}
<Dialog open={showPreviewDialog} onOpenChange={setShowPreviewDialog}>
<DialogContent className="max-w-3xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>{previewReport?.title}</DialogTitle>
<DialogDescription>: {previewReport?.generatedAt}</DialogDescription>
</DialogHeader>
{previewReport && (
<div className="space-y-4 py-4">
{/* 核心指标 */}
<div className="grid grid-cols-4 gap-4">
<Card className="border bg-blue-50">
<CardContent className="p-3 text-center">
<div className="text-2xl font-bold text-blue-600">{formatNumber(previewReport.metrics.totalUsers)}</div>
<div className="text-xs text-gray-500"></div>
</CardContent>
</Card>
<Card className="border bg-green-50">
<CardContent className="p-3 text-center">
<div className="text-2xl font-bold text-green-600">{formatNumber(previewReport.metrics.activeUsers)}</div>
<div className="text-xs text-gray-500"></div>
</CardContent>
</Card>
<Card className="border bg-orange-50">
<CardContent className="p-3 text-center">
<div className="text-2xl font-bold text-orange-600">{formatNumber(previewReport.metrics.newUsers)}</div>
<div className="text-xs text-gray-500"></div>
</CardContent>
</Card>
<Card className="border bg-purple-50">
<CardContent className="p-3 text-center">
<div className="text-2xl font-bold text-purple-600">{previewReport.metrics.rfmAvg}</div>
<div className="text-xs text-gray-500">RFM均值</div>
</CardContent>
</Card>
</div>
{/* 报告内容 */}
<Card className="border">
<CardContent className="p-4">
<h4 className="font-medium text-gray-900 mb-3"></h4>
<div className="prose prose-sm text-gray-600">
{previewReport.content || (
<div className="space-y-2">
<p></p>
<p><strong>:</strong> {formatNumber(previewReport.metrics.totalUsers)}{((previewReport.metrics.activeUsers / previewReport.metrics.totalUsers) * 100).toFixed(1)}%</p>
<p><strong>:</strong> RFM评分{previewReport.metrics.rfmAvg}0.5</p>
<p><strong>:</strong> {formatNumber(previewReport.metrics.newUsers)}8.2%</p>
</div>
)}
</div>
</CardContent>
</Card>
</div>
)}
<DialogFooter>
<Button variant="outline" onClick={() => setShowPreviewDialog(false)}></Button>
<Button variant="outline">
<Download className="h-4 w-4 mr-2" />
PDF
</Button>
<Button>
<Send className="h-4 w-4 mr-2" />
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* 规则编辑弹窗 */}
<Dialog open={showRuleDialog} onOpenChange={setShowRuleDialog}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>{selectedRule?.name}</DialogDescription>
</DialogHeader>
{selectedRule && (
<div className="space-y-4 py-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label></Label>
<Input value={selectedRule.schedule} readOnly className="bg-gray-50" />
</div>
<div className="space-y-2">
<Label></Label>
<Select defaultValue={selectedRule.config.format}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="pdf">PDF</SelectItem>
<SelectItem value="html">HTML</SelectItem>
<SelectItem value="markdown">Markdown</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="flex items-center gap-2">
{report.status === "generating" ? (
<Badge className="bg-blue-100 text-blue-700">
<Sparkles className="h-3 w-3 mr-1 animate-pulse" />
</Badge>
) : (
<>
<Button variant="outline" size="sm">
<Eye className="h-4 w-4 mr-1" />
</Button>
<Button variant="outline" size="sm">
<Download className="h-4 w-4 mr-1" />
</Button>
<Button variant="outline" size="sm">
<Share2 className="h-4 w-4" />
</Button>
</>
)}
<div className="space-y-2">
<Label></Label>
<Input defaultValue={selectedRule.config.sendTo.join(', ')} placeholder="多个邮箱用逗号分隔" />
</div>
<div className="space-y-2">
<Label> <span className="text-gray-400 text-xs">(AI根据此提示词生成报告内容)</span></Label>
<Textarea
value={editingPrompt}
onChange={(e) => setEditingPrompt(e.target.value)}
rows={12}
className="font-mono text-sm"
/>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* 创建报告弹窗 */}
<Dialog open={showCreateDialog} onOpenChange={setShowCreateDialog}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>AI将自动生成分析报告</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label></Label>
<Input
placeholder="输入报告名称"
value={reportConfig.name}
onChange={(e) => setReportConfig({...reportConfig, name: e.target.value})}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label></Label>
<Select
value={reportConfig.dateRange}
onValueChange={(v) => setReportConfig({...reportConfig, dateRange: v})}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="last_7_days">7</SelectItem>
<SelectItem value="last_30_days">30</SelectItem>
<SelectItem value="last_90_days">90</SelectItem>
<SelectItem value="custom"></SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<Select
value={reportConfig.userSegment}
onValueChange={(v) => setReportConfig({...reportConfig, userSegment: v})}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="high_value"></SelectItem>
<SelectItem value="new_users"></SelectItem>
<SelectItem value="active"></SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label></Label>
<Textarea
placeholder="输入额外的分析要求,例如:重点分析转化漏斗、对比上月数据等"
value={reportConfig.customPrompt}
onChange={(e) => setReportConfig({...reportConfig, customPrompt: e.target.value})}
/>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowCreateDialog(false)}></Button>
<Button>
<Sparkles className="mr-2 h-4 w-4" />
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}
<DialogFooter>
<Button variant="outline" onClick={() => setShowRuleDialog(false)}></Button>
<Button onClick={() => {
if (selectedRule) {
setRules(rules.map(r => r.id === selectedRule.id ? { ...r, promptTemplate: editingPrompt } : r))
}
setShowRuleDialog(false)
}}>
<CheckCircle2 className="h-4 w-4 mr-2" />
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
)
}