"use client"; import { useState, useEffect, useCallback, useMemo } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { cn } from "@/lib/utils"; import { listProjects, projectsApi, customersApi, type ProjectRead, type CustomerRead, } from "@/lib/api/client"; import { Copy, Search, FileText, Eye, Pencil, Loader2 } from "lucide-react"; import { toast } from "sonner"; import ReactMarkdown from "react-markdown"; function parseTags(tagsStr: string | null | undefined): string[] { if (!tagsStr?.trim()) return []; return tagsStr .split(",") .map((t) => t.trim()) .filter(Boolean); } export function HistoricalReferences() { const [projects, setProjects] = useState([]); const [search, setSearch] = useState(""); const [selectedTag, setSelectedTag] = useState(""); const [loading, setLoading] = useState(true); const [previewProject, setPreviewProject] = useState(null); const [editProject, setEditProject] = useState(null); const [editRaw, setEditRaw] = useState(""); const [editMd, setEditMd] = useState(""); const [saving, setSaving] = useState(false); const [editCustomer, setEditCustomer] = useState(null); const [customerName, setCustomerName] = useState(""); const [customerContact, setCustomerContact] = useState(""); const [customerTags, setCustomerTags] = useState(""); const [savingCustomer, setSavingCustomer] = useState(false); const load = useCallback(async () => { setLoading(true); try { const data = await listProjects( selectedTag ? { customer_tag: selectedTag } : undefined ); setProjects(data); } catch (e) { toast.error("加载历史项目失败"); setProjects([]); } finally { setLoading(false); } }, [selectedTag]); useEffect(() => { load(); }, [load]); const allTags = useMemo(() => { const set = new Set(); projects.forEach((p) => parseTags(p.customer?.tags ?? null).forEach((t) => set.add(t)) ); return Array.from(set).sort(); }, [projects]); const filtered = useMemo(() => { let list = projects; if (search.trim()) { const q = search.toLowerCase(); list = list.filter( (p) => p.raw_requirement.toLowerCase().includes(q) || (p.ai_solution_md || "").toLowerCase().includes(q) ); } return list.slice(0, 50); }, [projects, search]); const groupedByCustomer = useMemo(() => { const map = new Map(); filtered.forEach((p) => { const name = p.customer?.name || "未关联客户"; const key = name; if (!map.has(key)) map.set(key, []); map.get(key)!.push(p); }); return Array.from(map.entries()).sort(([a], [b]) => a.localeCompare(b, "zh-CN")); }, [filtered]); const copySnippet = (text: string, label: string) => { if (!text) return; navigator.clipboard.writeText(text); toast.success(`已复制 ${label}`); }; const openPreview = (p: ProjectRead) => setPreviewProject(p); const openEdit = (p: ProjectRead) => { setEditProject(p); setEditRaw(p.raw_requirement); setEditMd(p.ai_solution_md || ""); }; const handleSaveEdit = async () => { if (!editProject) return; setSaving(true); try { await projectsApi.update(editProject.id, { raw_requirement: editRaw, ai_solution_md: editMd || null, }); toast.success("已保存"); setEditProject(null); load(); } catch (e) { toast.error("保存失败"); } finally { setSaving(false); } }; const openEditCustomer = (p: ProjectRead | null) => { if (!p?.customer) return; setEditCustomer(p.customer); setCustomerName(p.customer.name); setCustomerContact(p.customer.contact_info || ""); setCustomerTags(p.customer.tags || ""); }; const handleSaveCustomer = async () => { if (!editCustomer) return; setSavingCustomer(true); try { const updated = await customersApi.update(editCustomer.id, { name: customerName.trim() || editCustomer.name, contact_info: customerContact.trim() || null, tags: customerTags.trim() || null, }); toast.success("客户信息已保存"); // 更新本地 projects 中的 customer 信息 setProjects((prev) => prev.map((p) => p.customer_id === updated.id ? { ...p, customer: updated } : p ) ); setEditCustomer(null); } catch (e) { toast.error("保存客户失败"); } finally { setSavingCustomer(false); } }; return (
setSearch(e.target.value)} className="h-8 pl-7 text-xs" />
{loading ? (

加载中...

) : filtered.length === 0 ? (

暂无项目

) : ( groupedByCustomer.map(([customerName, items]) => (

{customerName}

{items.map((p) => (

项目 #{p.id} {p.customer?.tags && ( {parseTags(p.customer.tags).slice(0, 2).join(", ")} )}

{p.raw_requirement.slice(0, 80)}…

))}
)) )}
{/* 预览弹窗 */} setPreviewProject(null)}> 项目 #{previewProject?.id} {previewProject?.customer?.name && ( {previewProject.customer.name} )} 原始需求 方案
                {previewProject?.raw_requirement ?? ""}
              
{previewProject?.ai_solution_md ? ( {previewProject.ai_solution_md} ) : (

暂无方案

)}
{/* 二次编辑弹窗 */} !saving && setEditProject(null)}> 编辑 项目 #{editProject?.id}