"use client" import { zodResolver } from "@hookform/resolvers/zod" import { format } from "date-fns" import Link from "next/link" import { useRouter, useSearchParams } from "next/navigation" import { Suspense, useState } from "react" import { Controller, useForm } from "react-hook-form" import { z } from "zod" import { getChannel } from "@/actions/channel" 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 { Field, FieldError, FieldGroup, FieldLabel, } from "@/components/ui/field" import { Input } from "@/components/ui/input" import type { Channel } from "@/models/channel" type FilterValues = { batch_no?: string user_phone?: string resource_no?: string proxy_host?: string proxy_port?: number node_ip?: string expired_at_start?: Date expired_at_end?: Date } const filterSchema = z .object({ batch_no: z.string().optional(), user_phone: z.string().optional(), resource_no: z.string().optional(), proxy_host: z.string().optional(), proxy_port: z.string().optional(), node_ip: z.string().optional(), expired_at_start: z.string().optional(), expired_at_end: z.string().optional(), }) .superRefine((data, ctx) => { if (data.expired_at_start && data.expired_at_end) { const start = new Date(data.expired_at_start) const end = new Date(data.expired_at_end) if (end < start) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "结束时间不能早于开始时间", path: ["expired_at_end"], }) } } }) type FilterSchema = z.infer const ispMap: Record = { 1: "电信", 2: "联通", 3: "移动", } export default function ChannelPage() { const router = useRouter() const searchParams = useSearchParams() const userId = searchParams.get("userId") const userPhone = searchParams.get("phone") const [filters, setFilters] = useState({}) const { control, handleSubmit, reset } = useForm({ resolver: zodResolver(filterSchema), defaultValues: { batch_no: "", user_phone: "", resource_no: "", proxy_port: "", proxy_host: "", node_ip: "", expired_at_start: "", expired_at_end: "", }, }) const table = useDataTable((page, size) => getChannel({ page, size, user_id: Number(userId), ...filters }), ) const onFilter = handleSubmit(data => { const result: FilterValues = {} if (data.batch_no?.trim()) result.batch_no = data.batch_no.trim() if (data.user_phone?.trim()) result.user_phone = data.user_phone.trim() if (data.resource_no?.trim()) result.resource_no = data.resource_no.trim() if (data.proxy_host?.trim()) result.proxy_host = data.proxy_host.trim() if (data.proxy_port?.trim()) result.proxy_port = Number(data.proxy_port.trim()) if (data.node_ip?.trim()) result.node_ip = data.node_ip.trim() if (data.expired_at_start) result.expired_at_start = new Date(data.expired_at_start) if (data.expired_at_end) result.expired_at_end = new Date(data.expired_at_end) setFilters(result) table.pagination.onPageChange(1) }) return (
用户会员号: {userPhone}
( 批次号 {fieldState.error?.message} )} /> ( 套餐号 {fieldState.error?.message} )} /> ( 代理IP {fieldState.error?.message} )} /> ( 代理端口 {fieldState.error?.message} )} /> ( 节点 {fieldState.error?.message} )} /> ( 开始时间 {fieldState.error?.message} )} /> ( 结束时间 {fieldState.error?.message} )} />
{...table} columns={[ { header: "会员号", accessorFn: row => row.user?.phone || "", }, { header: "套餐号", accessorKey: "resource.resource_no", cell: ({ row }) => { const resource_no = row.original.resource?.resource_no const type = row.original.resource?.type return ( {resource_no} ) }, }, { header: "批次号", accessorKey: "batch_no" }, { header: "节点", accessorFn: row => row.ip || row.edge_ref || row.edge_id, }, { header: "自动配置", cell: ({ row }) => { const prov = row.original.filter_prov const city = row.original.filter_city const isp = row.original.filter_isp const parts = [] if (prov && prov !== "all") parts.push(prov) if (city && city !== "all") parts.push(city) if (isp && isp !== "all") { parts.push(ispMap[Number(isp)] || isp) } return (
{parts.length > 0 ? parts.join(" / ") : "不限"}
) }, }, { header: "网关地址", accessorKey: "host", cell: ({ row }) => { return ( {row.original.host}:{row.original.port} ) }, }, { header: "认证方式", cell: ({ row }) => { const channel = row.original const hasWhitelist = channel.whitelists && channel.whitelists.trim() !== "" const hasAuth = channel.username && channel.password return (
{hasWhitelist ? (
白名单
{channel.whitelists.split(",").map(ip => ( {ip.trim()} ))}
) : hasAuth ? (
账号密码 {channel.username}:{channel.password}
) : ( 无认证 )}
) }, }, { header: "过期时间", accessorKey: "expired_at", cell: ({ row }) => format( new Date(row.original.expired_at), "yyyy-MM-dd HH:mm:ss", ), }, ]} />
) }