"use client" import { useEffect, useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 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 RfmBadge from "@/components/rfm/rfm-badge" import { Download, BarChart3, Sparkles, Upload, SlidersHorizontal } from 'lucide-react' type AnalyzeResult = { user_id: string rfm_score: { R: number; F: number; M: number; total: number; grade: "S" | "A" | "B" | "C" | "D" } tags: { emotion?: "积极" | "中性" | "消极" behavior?: string[] intent?: "弱意图" | "中等意图" | "强意图" lifecycle?: "新用户" | "活跃用户" | "沉睡用户" | "流失风险" value?: "高" | "中" | "低" } created_at: string updated_at: string } export default function RfmPage() { const [form, setForm] = useState({ user_id: "wxid_demo_01", last_active: new Date().toISOString(), interactions: 12, amount: 880, chat_logs: "想了解一下价格;今天有活动吗", source: "wechat", useAI: false, }) const [weights, setWeights] = useState<{ R: number; F: number; M: number }>({ R: 0.5, F: 0.3, M: 0.2 }) const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [summary, setSummary] = useState(null) useEffect(() => { ;(async () => { const res = await fetch("/api/rfm/weights") const data = await res.json() if (data.success) setWeights(data.data) })() }, []) const analyze = async () => { setLoading(true) try { const res = await fetch("/api/rfm/analyze", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...form, chat_logs: form.chat_logs.split(";").map((s) => s.trim()).filter(Boolean), }), }) const data = await res.json() if (data.success) { setResult(data.data[0]) } } finally { setLoading(false) } } const loadSummary = async () => { const res = await fetch("/api/rfm/group_summary") const data = await res.json() if (data.success) setSummary(data.data) } const exportCsv = () => { window.open("/api/rfm/dump_csv", "_blank") } const onUploadCsv = async (file: File) => { const text = await file.text() const lines = text.split(/\r?\n/).filter(Boolean) if (lines.length <= 1) return const header = lines[0].split(",").map((s) => s.trim()) const payload = lines.slice(1).map((line) => { const cols = line.split(",") const row: any = {} header.forEach((h, i) => (row[h] = cols[i])) return { user_id: row.user_id, last_active: row.last_active, interactions: Number(row.interactions || 0), amount: Number(row.amount || 0), chat_logs: (row.chat_logs || "").split(";").filter(Boolean), source: row.source || "import", } }) await fetch("/api/rfm/analyze", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }) await loadSummary() } const saveWeights = async () => { // normalize via API const res = await fetch("/api/rfm/weights", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ R: Math.max(0.0001, weights.R), F: Math.max(0.0001, weights.F), M: Math.max(0.0001, weights.M), }), }) const data = await res.json() if (data.success) setWeights(data.data) } return (

RFM 智能标签引擎

{/* 权重配置 */} 权重配置(R/F/M) {(["R", "F", "M"] as const).map((k) => (
setWeights((p) => ({ ...p, [k]: Number(e.target.value) }))} />
))}
{/* 在线分析 */} 在线分析
setForm((p) => ({ ...p, user_id: e.target.value }))} placeholder="wxid_xxx 或手机号散列等" />
setForm((p) => ({ ...p, last_active: new Date(e.target.value).toISOString() }))} />
setForm((p) => ({ ...p, interactions: Number(e.target.value) }))} min={0} />
setForm((p) => ({ ...p, amount: Number(e.target.value) }))} min={0} />