import { zodResolver } from "@hookform/resolvers/zod" import { format } from "date-fns" import { Suspense, useCallback, useState } from "react" import { Controller, useForm } from "react-hook-form" import { toast } from "sonner" import z from "zod" import { issueCoupon } from "@/actions/coupon" import { getPageUser } from "@/actions/user" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Field, FieldError, FieldLabel } from "@/components/ui/field" import { Input } from "@/components/ui/input" import type { Coupon } from "@/models/coupon" import type { User } from "@/models/user" interface UserQueryParams { account?: string name?: string } const filterSchema = z.object({ phone: z.string().optional(), name: z.string().optional(), }) type FormValues = z.infer export function IssueCoupon(props: { coupon: Coupon; onSuccess?: () => void }) { const [open, setOpen] = useState(false) const [userList, setUserList] = useState([]) const [loading, setLoading] = useState(false) const [currentFilters, setCurrentFilters] = useState({}) const { control, handleSubmit, reset } = useForm({ resolver: zodResolver(filterSchema), defaultValues: { phone: "", name: "", }, }) const fetchUsers = useCallback(async (filters: UserQueryParams = {}) => { setLoading(true) try { setOpen(true) const res = await getPageUser(filters) if (res.success) { const data = Array.isArray(res.data) ? res.data : [res.data] setUserList(data) } else { toast.error(res.message || "获取用户失败") setUserList([]) } } catch (error) { const message = error instanceof Error ? error.message : error toast.error(`获取用户失败: ${message}`) } finally { setLoading(false) } }, []) const onFilter = handleSubmit((data: FormValues) => { const params: UserQueryParams = {} if (data.phone?.trim()) params.account = data.phone.trim() if (data.name?.trim()) params.name = data.name.trim() if (Object.keys(params).length === 0) { toast.info("请至少输入一个搜索条件") return } setCurrentFilters(params) fetchUsers(params) }) const handleReset = useCallback(() => { reset() setCurrentFilters({}) setUserList([]) }, [reset]) const handleIssueCoupon = useCallback( async (users: User[], coupon: Coupon) => { console.log(coupon, "couponcouponcoupon") const targetUser = users[0] if (!targetUser || !targetUser.id) { toast.error("用户信息无效") return } if (!coupon || !coupon.id) { toast.error("优惠券信息无效") return } if (coupon.status !== 1) { toast.error("优惠券不可用,请检查优惠券状态") return } try { const result = await issueCoupon({ coupon_id: coupon.id, user_id: targetUser.id, }) console.log({ coupon_id: coupon.id, user_id: targetUser.id, }) console.log(result, "resultresultresultresultresult") if (result.success) { toast.success( `成功发放优惠券给用户 ${targetUser.phone || targetUser.username}`, ) setOpen(false) handleReset() props.onSuccess?.() } else { toast.error("发放失败,请稍后重试") } } catch (error) { const message = error instanceof Error ? error.message : "发放失败" toast.error(`发放优惠券失败: ${message}`) } }, [props.onSuccess, handleReset], ) return ( { setOpen(newOpen) if (!newOpen) { handleReset() } }} > 发放优惠券
( 手机号 {fieldState.error?.message} )} />
加载中...}> {loading ? (
加载中...
) : userList.length === 0 ? (
暂无用户数据
) : (
{userList.map(user => (
{user.phone || "未绑定手机"}
{user.id_type === 1 ? "✓ 已认证" : "○ 未认证"} {user.status === 1 ? "正常" : "禁用"}
余额: 0 ? "text-green-600" : "text-orange-600" }`} > ¥{(Number(user.balance) || 0).toFixed(2)}
姓名: {user.name || ""}
账号: {user.username || ""}
客户经理: {user.admin?.name || ""}
客户来源: {(() => { const sourceMap: Record = { 0: "官网注册", 1: "管理员添加", 2: "代理商注册", 3: "代理商添加", } return sourceMap[user.source] ?? "官网注册" })()}
联系方式: {user.contact_wechat || ""}
创建时间: {user.created_at ? format(new Date(user.created_at), "yyyy-MM-dd") : ""}
最后登录: {user.last_login ? format( new Date(user.last_login), "yyyy-MM-dd HH:mm", ) : "-"}
登录IP: {user.last_login_ip || "-"}
))}
)}
) }