"use client" import { zodResolver } from "@hookform/resolvers/zod" import { ArrowRightLeftIcon } from "lucide-react" import { useEffect, useState } from "react" import { Controller, Resolver, useForm } from "react-hook-form" import { toast } from "sonner" import { z } from "zod/v4" import { OptionCombobox } from "@/components/option-combobox" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Field, FieldContent, FieldError, FieldLabel, } from "@/components/ui/field" import { Textarea } from "@/components/ui/textarea" import { assignConversation, transferConversation, fetchAgentProfilesAll, type AdminAgentProfile, } from "@/lib/api/admin" type ConversationTransferDialogProps = { open: boolean mode: "assign" | "transfer" conversationId: number | null onOpenChange: (open: boolean) => void onSuccess?: () => Promise | void } const transferSchema = z.object({ toUserId: z.string().trim().min(1, "请选择目标客服"), reason: z.string().trim(), }) type TransferForm = z.infer const emptyForm: TransferForm = { toUserId: "", reason: "", } const transferResolver = zodResolver(transferSchema as never) as Resolver< z.input, undefined, z.output > export function ConversationTransferDialog({ open, mode, conversationId, onOpenChange, onSuccess, }: ConversationTransferDialogProps) { return ( {open ? ( ) : null} ) } type ConversationTransferDialogBodyProps = { mode: "assign" | "transfer" conversationId: number | null onOpenChange: (open: boolean) => void onSuccess?: () => Promise | void } function ConversationTransferDialogBody({ mode, conversationId, onOpenChange, onSuccess, }: ConversationTransferDialogBodyProps) { const [saving, setSaving] = useState(false) const [loadingAgents, setLoadingAgents] = useState(false) const [agents, setAgents] = useState([]) const userOptions = agents.map((agent) => ({ value: String(agent.userId), label: agent.displayName || agent.nickname || agent.username || `客服 #${agent.userId}`, })) const form = useForm< z.input, undefined, z.output >({ resolver: transferResolver, defaultValues: emptyForm, }) const { control, handleSubmit, reset, register, formState: { errors }, } = form useEffect(() => { reset(emptyForm) }, [conversationId, reset]) useEffect(() => { setLoadingAgents(true) fetchAgentProfilesAll() .then((data) => { setAgents(data.filter((item) => item.serviceStatus === 0)) }) .catch((error) => { toast.error(error instanceof Error ? error.message : "加载客服列表失败") }) .finally(() => { setLoadingAgents(false) }) }, []) async function onFormSubmit(values: TransferForm) { if (!conversationId) { toast.error("会话不存在") return } const toUserId = Number(values.toUserId) const reason = values.reason.trim() setSaving(true) try { if (mode === "assign") { await assignConversation(conversationId, toUserId, reason) toast.success(`已分配会话:#${conversationId}`) } else { await transferConversation(conversationId, toUserId, reason) toast.success(`已转接会话:#${conversationId}`) } reset(emptyForm) onOpenChange(false) await onSuccess?.() } catch (error) { toast.error(error instanceof Error ? error.message : mode === "assign" ? "分配会话失败" : "转接会话失败") } finally { setSaving(false) } } const isAssign = mode === "assign" return ( {isAssign ? "分配会话" : "转接会话"} {/* 当前会话:{conversationId ? `#${conversationId}` : "-"} */}
目标客服 ( )} /> {isAssign ? "分配说明" : "转接原因"}