"use client" import { zodResolver } from "@hookform/resolvers/zod" import { format } from "date-fns" import { useRouter } from "next/navigation" import { Suspense, useCallback } from "react" import { Controller, useForm } from "react-hook-form" import { z } from "zod" import { getPageCusts } from "@/actions/cust" import { Auth } from "@/components/auth" import { DataTable, useDataTable } from "@/components/data-table" import { Page } from "@/components/page" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Field, FieldError, FieldLabel } from "@/components/ui/field" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { ScopeBalanceActivityReadOfUser, ScopeBatchReadOfUser, ScopeBillReadOfUser, ScopeChannelReadOfUser, ScopeCouponWriteAssign, ScopeResourceRead, ScopeTradeReadOfUser, ScopeUserWrite, ScopeUserWriteBalance, ScopeUserWriteBalanceDec, ScopeUserWriteBalanceInc, } from "@/lib/scopes" import type { User } from "@/models/user" import { AddUserDialog } from "./create" import { DeductionDialog } from "./deduction" import { DepositDialog } from "./deposit" import { UpdateDialog } from "./update" type FilterValues = { account?: string name?: string identified?: boolean enabled?: boolean created_at_start?: Date created_at_end?: Date } const filterSchema = z .object({ account: z.string().optional(), name: z.string().optional(), identified: z.string().optional(), enabled: z.string().optional(), created_at_start: z.string().optional(), created_at_end: z.string().optional(), }) .superRefine((data, ctx) => { if (data.created_at_start && data.created_at_end) { const start = new Date(data.created_at_start) const end = new Date(data.created_at_end) if (end < start) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "结束时间不能早于开始时间", path: ["created_at_end"], }) } } }) type FormValues = z.infer export default function CustPage() { const router = useRouter() const { control, handleSubmit, reset, getValues } = useForm({ resolver: zodResolver(filterSchema), defaultValues: { account: "", name: "", identified: "all", enabled: "all", created_at_start: "", created_at_end: "", }, }) const fetchUsers = useCallback( (page: number, size: number) => { const result: FilterValues = {} const filters = getValues() console.log(filters, "filters") if (filters.account?.trim()) result.account = filters.account.trim() if (filters.name?.trim()) result.name = filters.name.trim() if (filters.identified && filters.identified !== "all") result.identified = filters.identified === "1" if (filters.enabled && filters.enabled !== "all") result.enabled = filters.enabled === "1" if (filters.created_at_start) result.created_at_start = new Date(filters.created_at_start) if (filters.created_at_end) result.created_at_end = new Date(filters.created_at_end) return getPageCusts({ page, size, ...result }) }, [getValues], ) const table = useDataTable(fetchUsers) const onFilter = handleSubmit(() => { table.pagination.onPageChange(1) }) const refreshTable = useCallback(() => { table.refresh() }, [table]) return (
( 账号/手机号/邮箱 {fieldState.error?.message} )} /> ( 姓名 {fieldState.error?.message} )} /> ( 实名状态 {fieldState.error?.message} )} /> ( 账号状态 {fieldState.error?.message} )} /> ( 开始时间 {fieldState.error?.message} )} /> ( 结束时间 {fieldState.error?.message} )} />
{...table} classNames={{ root: "flex-auto overflow-hidden" }} columns={[ { header: "手机", accessorKey: "phone" }, { header: "创建时间", accessorKey: "created_at", cell: ({ row }) => format( new Date(row.original.created_at), "yyyy-MM-dd HH:mm:ss", ), }, { header: "客户来源", accessorKey: "source", cell: ({ row }) => { const sourceMap: Record = { 0: "官网注册", 1: "管理员添加", 2: "代理商注册", 3: "代理商添加", } return sourceMap[row.original.source] ?? "官网注册" }, }, { header: "余额", accessorKey: "balance", cell: ({ row }) => { const balance = Number(row.original.balance) || 0 return ( 0 ? "text-green-500" : "text-orange-500" } > ¥{balance.toFixed(2)} ) }, }, { header: "账号", accessorKey: "username" }, { header: "账号状态", accessorKey: "status", cell: ({ row }) => (row.original.status === 1 ? "正常" : "禁用"), }, { header: "客户经理", accessorKey: "admin.name" }, { header: "姓名", accessorKey: "name" }, { header: "身份证号", accessorKey: "id_no", cell: ({ row }) => { const idNo = row.original.id_no return idNo ? `${idNo.slice(0, 6)}****${idNo.slice(-4)}` : "" }, }, { header: "实名状态", accessorKey: "id_type", cell: ({ row }) => ( {row.original.id_type === 1 ? "已认证" : "未认证"} ), }, { header: "最后登录时间", accessorKey: "last_login", cell: ({ row }) => row.original.last_login ? format( new Date(row.original.last_login), "yyyy-MM-dd HH:mm:ss", ) : "", }, { header: "最后登录IP", accessorKey: "last_login_ip", cell: ({ row }) => row.original.last_login_ip || "", }, { header: "折扣", accessorKey: "discount.name" }, { header: "联系方式", cell: ({ row }) => { const qq = row.original.contact_qq || "" const wechat = row.original.contact_wechat || "" const hasQQ = qq.trim() !== "" const hasWechat = wechat.trim() !== "" if (!hasQQ && !hasWechat) return null return (
{hasWechat &&
微信:{wechat}
} {hasQQ &&
QQ:{qq}
}
) }, }, { id: "action", meta: { pin: "right" }, header: "操作", cell: ({ row }) => { const user = row.original return (
router.push( `/client/trade?userId=${user.id}&phone=${user.phone}`, ) } > 交易明细 router.push( `/client/billing?userId=${user.id}&phone=${user.phone}`, ) } > 账单详情 router.push( `/client/resources?userId=${user.id}&phone=${user.phone}`, ) } > 套餐管理 router.push( `/client/batch?userId=${user.id}&phone=${user.phone}`, ) } > 提取记录 router.push( `/client/channel?userId=${user.id}&phone=${user.phone}`, ) } > IP管理 router.push( `/client/balance?userId=${user.id}&phone=${user.phone}`, ) } > 余额明细 router.push( `/client/coupon?userId=${user.id}&phone=${user.phone}`, ) } > 优惠券
) }, }, ]} />
) }