新增通道列表查询页面

This commit is contained in:
2025-04-28 17:41:54 +08:00
parent b20ec85db9
commit b44888a6d7
16 changed files with 290 additions and 117 deletions

View File

@@ -0,0 +1,184 @@
'use client'
import {useEffect, useState} from 'react'
import {useStatus} from '@/lib/states'
import {PageRecord} from '@/lib/api'
import {Channel} from '@/lib/models'
import Page from '@/components/page'
import DataTable from '@/components/data-table'
import {toast} from 'sonner'
import {listChannels} from '@/actions/channel'
import {format} from 'date-fns'
import {Form, FormField} from '@/components/ui/form'
import {z} from 'zod'
import {useForm} from 'react-hook-form'
import {zodResolver} from '@hookform/resolvers/zod'
import DatePicker from '@/components/date-picker'
import {Button} from '@/components/ui/button'
import {EraserIcon, SearchIcon} from 'lucide-react'
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/components/ui/select'
export type ChannelsPageProps = {}
export default function ChannelsPage(props: ChannelsPageProps) {
// ======================
// data
// ======================
const [status, setStatus] = useStatus()
const [data, setData] = useState<PageRecord<Channel>>({
page: 1,
size: 10,
total: 0,
list: [],
})
const refresh = async (page: number, size: number) => {
try {
setStatus('load')
// 筛选条件
const filter = filterForm.getValues()
const auth_type = filter.auth_type ? parseInt(filter.auth_type) : undefined
// 请求数据
console.log({
page, size, ...filter, auth_type,
})
const resp = await listChannels({
page, size, ...filter, auth_type,
})
if (!resp.success) {
throw new Error(resp.message)
}
// 更新数据
setData(resp.data)
setStatus('done')
}
catch (e) {
setStatus('fail')
console.error(e)
toast.error('获取提取结果失败', {
description: (e as Error).message,
})
}
}
useEffect(() => {
refresh(data.page, data.size).then()
}, [])
// ======================
// filter
// ======================
const filterSchema = z.object({
auth_type: z.enum(['0', '1', '2']),
expire_after: z.date().optional(),
expire_before: z.date().optional(),
})
type FilterSchema = z.infer<typeof filterSchema>
const filterForm = useForm<FilterSchema>({
resolver: zodResolver(filterSchema),
defaultValues: {
auth_type: '0',
expire_after: undefined,
expire_before: undefined,
},
})
const filterHandler = filterForm.handleSubmit(async value => {
await refresh(data.page, data.size)
})
// ======================
// render
// ======================
return (
<Page>
<section className={`flex justify-between`}>
<div></div>
<Form form={filterForm} handler={filterHandler} className={`flex-none flex gap-4 items-end`}>
<FormField<FilterSchema, 'auth_type'> name={`auth_type`} label={<span className={`text-sm`}></span>}>
{({field}) => (
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className={`h-9 w-36`}>
<SelectValue placeholder={`选择认证方式`}/>
</SelectTrigger>
<SelectContent>
<SelectItem value={'0'}></SelectItem>
<SelectItem value={'1'}>IP </SelectItem>
<SelectItem value={'2'}></SelectItem>
</SelectContent>
</Select>
)}
</FormField>
<fieldset className={`flex flex-col gap-2 items-start`}>
<div>
<legend className={`block text-sm`}></legend>
</div>
<div className={`flex gap-1 items-center`}>
<FormField<FilterSchema, 'expire_after'> name={`expire_after`}>
{({field}) => (
<DatePicker placeholder={`选择开始时间`} {...field} format={`yyyy-MM-dd`}/>
)}
</FormField>
<span>-</span>
<FormField<FilterSchema, 'expire_before'> name={`expire_before`}>
{({field}) => (
<DatePicker placeholder={`选择结束时间`} {...field} format={`yyyy-MM-dd`}/>
)}
</FormField>
</div>
</fieldset>
<Button className={`h-9`}>
<SearchIcon/>
</Button>
<Button theme={`outline`} className={`h-9`} onClick={() => filterForm.reset()}>
<EraserIcon/>
</Button>
</Form>
</section>
<DataTable
status={status}
data={data.list}
pagination={{
page: data.page,
size: data.size,
total: data.total,
onPageChange: (page) => refresh(page, data.size),
onSizeChange: (size) => refresh(1, size),
}}
columns={[
{
header: '代理地址', cell: ({row}) => `${row.original.proxy_host}:${row.original.proxy_port}`,
},
{
header: '认证方式', cell: ({row}) => {
return <div className={`flex flex-col gap-1`}>
{row.original.auth_ip && (<>
<span className={`text-weak`}>IP </span>
<span>{row.original.user_host}</span>
</>)}
{row.original.auth_pass && (<>
<span className={`text-weak`}></span>
<span>{row.original.username}:{row.original.password}</span>
</>)}
</div>
},
},
{
header: '过期时间', cell: ({row}) => format(row.original.expiration, 'yyyy-MM-dd HH:mm:ss'),
},
{
header: '操作', cell: ({row}) => <span>-</span>,
},
]}
/>
</Page>
)
}