diff --git a/src/actions/channel.ts b/src/actions/channel.ts index bb78496..fad8c7d 100644 --- a/src/actions/channel.ts +++ b/src/actions/channel.ts @@ -2,6 +2,7 @@ import {callByUser, callPublic} from '@/actions/base' import {Channel} from '@/lib/models' import {PageRecord} from '@/lib/api' +import {BatchRecord} from '@/lib/models/batch' export async function listChannels(props: { page: number @@ -15,6 +16,10 @@ export async function listChannels(props: { return callByUser>('/api/channel/list', props) } +export async function extractRecord(props: {page: number, size: number}) { + return callByUser>('/api/batch/page', props) +} + type CreateChannelsResp = { host: string port: string diff --git a/src/app/admin/(dashboard)/_client/charts.tsx b/src/app/admin/(dashboard)/_client/charts.tsx index 65b7d82..ea164db 100644 --- a/src/app/admin/(dashboard)/_client/charts.tsx +++ b/src/app/admin/(dashboard)/_client/charts.tsx @@ -82,11 +82,6 @@ export default function Charts({initialData}: ChartsProps) { className={merge(`flex items-end gap-4 flex-wrap`)} handler={handler} form={form} > - 套餐编号}> - {({field}) => ( - - )} -
diff --git a/src/app/admin/channels/layout.tsx b/src/app/admin/channels/layout.tsx index 188acda..1750c59 100644 --- a/src/app/admin/channels/layout.tsx +++ b/src/app/admin/channels/layout.tsx @@ -1,6 +1,6 @@ import {ReactNode} from 'react' import {Metadata} from 'next' - +import {Suspense} from 'react' export async function generateMetadata(): Promise { return { title: 'IP管理 - 蓝狐代理', @@ -12,5 +12,5 @@ export type ChannelsLayoutProps = { } export default async function ChannelsLayout(props: ChannelsLayoutProps) { - return props.children + return {props.children} } diff --git a/src/app/admin/clients.tsx b/src/app/admin/clients.tsx index 19c8e9f..bd2e6ad 100644 --- a/src/app/admin/clients.tsx +++ b/src/app/admin/clients.tsx @@ -180,7 +180,7 @@ export function Navbar() { } label="我的套餐" expand={navbar}/> } label="IP 管理" expand={navbar}/> - } label="提取记录" expand={navbar}/> + } label="提取记录" expand={navbar}/> {/* } label="使用记录" expand={navbar}/> */} diff --git a/src/app/admin/record/layout.tsx b/src/app/admin/record/layout.tsx new file mode 100644 index 0000000..0e08c78 --- /dev/null +++ b/src/app/admin/record/layout.tsx @@ -0,0 +1,16 @@ +import {ReactNode} from 'react' +import {Metadata} from 'next' +import {Suspense} from 'react' +export async function generateMetadata(): Promise { + return { + title: '提取记录 - 蓝狐代理', + } +} + +export type RecordLayoutProps = { + children: ReactNode +} + +export default async function RecordLayout(props: RecordLayoutProps) { + return {props.children} +} diff --git a/src/app/admin/record/page.tsx b/src/app/admin/record/page.tsx new file mode 100644 index 0000000..d47eea2 --- /dev/null +++ b/src/app/admin/record/page.tsx @@ -0,0 +1,188 @@ +'use client' +import {useCallback, useEffect, useState} from 'react' +import {useStatus} from '@/lib/states' +import {PageRecord} from '@/lib/api' +import Page from '@/components/page' +import DataTable from '@/components/data-table' +import {toast} from 'sonner' +import {extractRecord} from '@/actions/channel' +import {BatchRecord} from '@/lib/models/batch' +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' + +export type RecordPageProps = {} + +export default function RecordPage(props: RecordPageProps) { + const [status, setStatus] = useStatus() + const [data, setData] = useState>({ + page: 1, + size: 10, + total: 0, + list: [], + }) + + // ====================== + // filter + // ====================== + + const filterSchema = z.object({ + time_start: z.date().optional(), + time_end: z.date().optional(), + }) + type FilterSchema = z.infer + + const filterForm = useForm({ + resolver: zodResolver(filterSchema), + defaultValues: { + time_start: undefined, + time_end: undefined, + }, + }) + + const fetchRecords = useCallback(async (page: number, size: number) => { + try { + setStatus('load') + // 获取筛选条件 + const filter = filterForm.getValues() + const result = await extractRecord({ + page, + size, + ...filter, + }) + + if (result.success && result.data) { + setData(result.data) + } + else { + throw new Error('获取数据失败') + } + setStatus('done') + } + catch (error) { + setStatus('fail') + console.error(error) + toast.error('获取提取结果失败', { + description: (error as Error).message, + }) + } + }, [filterForm, setStatus]) + + const filterHandler = filterForm.handleSubmit(async () => { + // 重置到第一页进行筛选 + await fetchRecords(1, data.size) + }) + + useEffect(() => { + fetchRecords(data.page, data.size).then() + }, [data.page, data.size, fetchRecords]) + + return ( + + {/* 筛选表单 */} +
+
+
+
+
+ 提取时间 +
+
+ name="time_start"> + {({field}) => ( + + )} + + - + name="time_end"> + {({field}) => ( + + )} + +
+
+ + + + +
+
+ + fetchRecords(page, data.size), + onSizeChange: size => fetchRecords(1, size), + }} + columns={[ + { + header: '批次号', + cell: ({row}) =>
{row.original.batch_no}
, + accessorKey: 'batch_no', + }, + { + header: 'IP地址', + cell: ({row}) =>
{row.original.ip}
, + accessorKey: 'ip', + }, + { + header: '运营商', + cell: ({row}) =>
{row.original.isp}
, + accessorKey: 'isp', + }, + { + header: '地区', + cell: ({row}) =>
{row.original.prov}
, + accessorKey: 'prov', + }, + { + header: '提取数量', + cell: ({row}) =>
{row.original.count}
, + accessorKey: 'count', + }, + { + header: '资源数量', + cell: ({row}) =>
{row.original.resource_id}
, + accessorKey: 'resource_id', + }, + { + header: '提取时间', + cell: ({row}) => { + return
{format(new Date(row.original.time), 'yyyy-MM-dd HH:mm:ss')}
+ }, + accessorKey: 'time', + }, + ]} + /> +
+ ) +} diff --git a/src/components/composites/purchase/long/right.tsx b/src/components/composites/purchase/long/right.tsx index 6dee7ef..c829d03 100644 --- a/src/components/composites/purchase/long/right.tsx +++ b/src/components/composites/purchase/long/right.tsx @@ -135,12 +135,14 @@ export default function Right() { ¥{price} -
  • - 总折扣 - - -¥{discounted} - -
  • + {discounted === 1 ? '' : ( +
  • + 总折扣 + + -¥{discounted} + +
  • + )} )} diff --git a/src/lib/models/batch.ts b/src/lib/models/batch.ts new file mode 100644 index 0000000..89a1f7e --- /dev/null +++ b/src/lib/models/batch.ts @@ -0,0 +1,11 @@ +export type BatchRecord = { + batch_no: string + ip: string + id: number + count: number + isp: string + resource_id: number + time: string + user_id: number + prov: string +}