"use client" import { useEffect, useState } from "react" import { toast } from "sonner" import { CustomerForm, type CustomerFormSavePayload } from "@/components/customer-form" import { ProjectDialog } from "@/components/project-dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { linkConversationToCustomer } from "@/lib/api/agent" import { fetchCustomers, saveCustomerProfile, type AdminCustomer } from "@/lib/api/customer" import { linkTicketToCustomer } from "@/lib/api/ticket" export type CustomerLinkOrCreateDialogProps = { open: boolean onOpenChange: (open: boolean) => void /** 传入时会话侧:关联已有或新建后绑定该会话 */ conversationId?: number | null /** 传入时工单侧:关联已有或新建后绑定该工单 */ ticketId?: number | null /** 绑定成功或仅新建成功后的回调 */ onSuccess?: () => void | Promise } const createFormId = "customer-link-or-create-form" export function CustomerLinkOrCreateDialog({ open, onOpenChange, conversationId, ticketId, onSuccess, }: CustomerLinkOrCreateDialogProps) { const [searchText, setSearchText] = useState("") const [searching, setSearching] = useState(false) const [results, setResults] = useState([]) const [showCreate, setShowCreate] = useState(false) const [linkingId, setLinkingId] = useState(null) const [saving, setSaving] = useState(false) useEffect(() => { if (!open) { return } setSearchText("") setResults([]) setShowCreate(false) setLinkingId(null) }, [open]) const runSearch = async () => { const q = searchText.trim() if (!q) { toast.error("请输入关键词(姓名、手机、邮箱、公司、联系方式等)") return } setSearching(true) try { const data = await fetchCustomers({ keyword: q, page: 1, limit: 50, status: 0, }) setResults(data.results) if (data.results.length === 0) { toast.message("未找到匹配客户,可点击下方填写新客户") } } catch (e) { toast.error(e instanceof Error ? e.message : "搜索失败") } finally { setSearching(false) } } const handleLinkExisting = async (customer: AdminCustomer) => { if (!conversationId && !ticketId) { toast.success(`已选择客户:${customer.name || `#${customer.id}`}`) onOpenChange(false) await onSuccess?.() return } setLinkingId(customer.id) try { if (conversationId) { await linkConversationToCustomer({ conversationId, customerId: customer.id, }) } if (ticketId) { await linkTicketToCustomer({ ticketId, customerId: customer.id, }) } toast.success("已关联客户") onOpenChange(false) await onSuccess?.() } catch (e) { toast.error(e instanceof Error ? e.message : "关联失败") } finally { setLinkingId(null) } } const onCreateSave = async (payload: CustomerFormSavePayload) => { setSaving(true) try { const created = await saveCustomerProfile(payload) if (conversationId) { await linkConversationToCustomer({ conversationId, customerId: created.id, }) } if (ticketId) { await linkTicketToCustomer({ ticketId, customerId: created.id, }) } if (conversationId || ticketId) { toast.success(conversationId ? "已创建客户并关联当前会话" : "已创建客户并关联当前工单") } else { toast.success("已创建客户") } onOpenChange(false) await onSuccess?.() } catch (e) { toast.error(e instanceof Error ? e.message : "保存失败") } finally { setSaving(false) } } const description = ( <> 先搜索已有客户; {conversationId || ticketId ? `选中即可关联当前${conversationId ? "会话" : "工单"}。` : "未接入上下文时仅创建或定位客户。"} 若无结果,可填写下方新客户 {conversationId || ticketId ? `,保存后将自动关联${conversationId ? "会话" : "工单"}。` : "。"} ) return ( onOpenChange(nextOpen)} title="关联或创建客户" description={description} allowFullscreen size="xl" footer={
{showCreate ? ( ) : null}
} >
setSearchText(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); void runSearch(); } }} />
{results.length > 0 ? (
    {results.map((row) => (
  • {row.name || `客户 #${row.id}`} {row.primaryMobile} {row.primaryEmail}
    {row.company?.name ? (
    {row.company.name}
    ) : null}
  • ))}
) : null}
{showCreate ? ( ) : null}
); }