From da63282a10cef2e7616c6fd769e24cdd6c8600e6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 16 Mar 2026 18:07:01 +0800 Subject: [PATCH] fix: bug --- backend/app/services/doc_service.py | 7 +- frontend/components/app-sidebar.tsx | 21 +- frontend/components/historical-references.tsx | 238 +++++++++++++----- 3 files changed, 197 insertions(+), 69 deletions(-) diff --git a/backend/app/services/doc_service.py b/backend/app/services/doc_service.py index ac31694..76cfb19 100644 --- a/backend/app/services/doc_service.py +++ b/backend/app/services/doc_service.py @@ -35,7 +35,7 @@ async def generate_quote_excel( } """ - async def _work() -> str: + def _work() -> str: template = Path(template_path) output = Path(output_path) output.parent.mkdir(parents=True, exist_ok=True) @@ -122,7 +122,7 @@ async def generate_contract_word( } """ - async def _work() -> str: + def _work() -> str: template = Path(template_path) output = Path(output_path) output.parent.mkdir(parents=True, exist_ok=True) @@ -148,7 +148,7 @@ async def generate_quote_pdf_from_data( that can be sent to customers. """ - async def _work() -> str: + def _work() -> str: output = Path(output_pdf_path) output.parent.mkdir(parents=True, exist_ok=True) @@ -195,4 +195,3 @@ async def generate_quote_pdf_from_data( return str(output) return await asyncio.to_thread(_work) - diff --git a/frontend/components/app-sidebar.tsx b/frontend/components/app-sidebar.tsx index 558e253..379e22c 100644 --- a/frontend/components/app-sidebar.tsx +++ b/frontend/components/app-sidebar.tsx @@ -10,6 +10,7 @@ import { Globe, FileStack, Settings2, + ChevronDown, } from "lucide-react"; import { cn } from "@/lib/utils"; import { Separator } from "@/components/ui/separator"; @@ -21,6 +22,7 @@ export function AppSidebar() { const pathname = usePathname(); const [cloudDocs, setCloudDocs] = useState([]); const [portalLinks, setPortalLinks] = useState([]); + const [projectArchiveOpen, setProjectArchiveOpen] = useState(false); const loadCloudDocs = useCallback(async () => { try { @@ -90,6 +92,24 @@ export function AppSidebar() { ))} + {/* 项目档案放在云文档之前,支持收纳折叠 */} +
+ +
+ {projectArchiveOpen && } +
@@ -156,7 +176,6 @@ export function AppSidebar() {
- {pathname === "/workspace" && } ); } diff --git a/frontend/components/historical-references.tsx b/frontend/components/historical-references.tsx index e7739a5..0604316 100644 --- a/frontend/components/historical-references.tsx +++ b/frontend/components/historical-references.tsx @@ -23,7 +23,9 @@ 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"; @@ -47,6 +49,11 @@ export function HistoricalReferences() { 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); @@ -85,9 +92,20 @@ export function HistoricalReferences() { (p.ai_solution_md || "").toLowerCase().includes(q) ); } - return list.slice(0, 20); + 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); @@ -119,12 +137,40 @@ export function HistoricalReferences() { } }; + 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 ( -
-

- - 历史参考 -

+
setCustomerName(e.target.value)} + /> +
+
+ + setCustomerContact(e.target.value)} + /> +
+
+ + setCustomerTags(e.target.value)} + placeholder="如:重点客户, 已签约" + /> +
+
+ + + + + +
); }