完善查询函数

This commit is contained in:
2025-10-14 12:34:12 +08:00
parent 4940e3a9d2
commit 6e9e7af780
3 changed files with 120 additions and 102 deletions

View File

View File

@@ -1,7 +1,7 @@
'use server'
import { Page, Res } from '@/lib/api'
import drizzle, { change, cityhash, count, desc, edge, eq, gateway, is, sql, token } from '@/lib/drizzle'
import drizzle, { and, change, cityhash, count, desc, edge, eq, gateway, is, sql, token } from '@/lib/drizzle'
export type AllocationStatus = {
city: string
@@ -134,7 +134,13 @@ export async function getGatewayConfig(page?: number, filters?: {
.from(gateway)
.leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash))
.leftJoin(edge, eq(edge.macaddr, gateway.edge))
.where(filters?.mac ? eq(gateway.macaddr, filters?.mac) : undefined)
.where(filters ? and(
filters.mac ? eq(gateway.macaddr, filters.mac) : undefined,
filters.public ? eq(edge.public, filters.public) : undefined,
filters.city ? eq(cityhash.city, filters.city) : undefined,
filters.user ? eq(gateway.user, filters.user) : undefined,
filters.inner_ip ? eq(gateway.network, filters.inner_ip) : undefined,
) : undefined)
.orderBy(sql`inet_aton(gateway.inner_ip)`)
.offset((page - 1) * 250)
.limit(250),
@@ -210,7 +216,7 @@ export async function getCityNodeCount() {
export type Edge = {
id: number
macaddr: string
city: string
city: string | null
public: string
isp: string
single: number | boolean
@@ -220,19 +226,49 @@ export type Edge = {
}
// 获取节点信息
export async function getEdgeNodes(page: number, size: number, props?: {
export async function getEdgeNodes(page: number, size: number, filters?: {
macaddr?: string
public?: string
city?: string
isp?: string
},
) {
}): Promise<Res<Page<Edge>>> {
try {
const offset = Math.max(0, (page - 1)) * size
const limit = Math.min(100, Math.max(10, size))
page = Math.max(1, page)
size = Math.min(100, Math.max(10, size))
const [total, data] = await Promise.all([
drizzle.$count(edge, eq(edge.active, 1)),
const condition = and(
eq(edge.active, 1),
filters?.macaddr ? eq(edge.macaddr, filters.macaddr) : undefined,
filters?.public ? eq(edge.public, filters.public) : undefined,
filters?.city ? eq(cityhash.city, filters.city) : undefined,
filters?.isp ? eq(edge.isp, filters.isp) : undefined,
)
console.log(drizzle
.select({
id: edge.id,
macaddr: edge.macaddr,
city: cityhash.city,
public: edge.public,
isp: edge.isp,
single: edge.single,
sole: edge.sole,
arch: edge.arch,
online: edge.online,
})
.from(edge)
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
.where(condition)
.orderBy(edge.id)
.offset(page * size - size)
.limit(size).toSQL().sql)
const [total, items] = await Promise.all([
drizzle
.select({ value: count() })
.from(edge)
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
.where(condition),
drizzle
.select({
id: edge.id,
@@ -247,25 +283,26 @@ export async function getEdgeNodes(page: number, size: number, props?: {
})
.from(edge)
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
.where(eq(edge.active, 1))
.where(condition)
.orderBy(edge.id)
.offset(offset)
.limit(limit),
.offset(page * size - size)
.limit(size),
])
return {
data,
totalCount: total,
currentPage: Math.floor(offset / limit) + 1,
totalPages: Math.ceil(total / limit),
success: true,
data: {
total: total[0].value,
page,
size,
items,
},
}
}
catch (error) {
console.error('Edge nodes query error:', error)
return {
success: false,
data: [],
error: '查询边缘节点失败',
}
}

View File

@@ -8,16 +8,16 @@ import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import { Form, FormField, FormItem, FormLabel } from '@/components/ui/form'
import { Form, FormControl, FormField, FormItem, FormLabel } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { cn } from '@/lib/utils'
// 定义表单验证规则
const filterSchema = z.object({
macaddr: z.string().optional(),
public: z.string().optional(),
city: z.string().optional(),
isp: z.string().optional(),
macaddr: z.string(),
public: z.string(),
city: z.string(),
isp: z.string(),
})
type FilterFormValues = z.infer<typeof filterSchema>
@@ -28,9 +28,9 @@ export default function Edge() {
const [error, setError] = useState<string | null>(null)
// 分页状态
const [currentPage, setCurrentPage] = useState(1)
const [itemsPerPage, setItemsPerPage] = useState(100) // 默认100条
const [totalItems, setTotalItems] = useState(0)
const [page, setPage] = useState(1)
const [size, setSize] = useState(100)
const [total, setTotal] = useState(0)
// 初始化表单
const form = useForm<FilterFormValues>({
@@ -43,57 +43,53 @@ export default function Edge() {
},
})
useEffect(() => {
fetchData({})
}, [currentPage, itemsPerPage])
const fetchData = async (page: number, size: number) => {
const filters = form.getValues()
const fetchData = async (val: {
macaddr?: string
public?: string
city?: string
isp?: string
}) => {
setLoading(true)
try {
const result = await getEdgeNodes(page, size, filters)
if (!result.success) {
throw new Error(result.error)
}
const data = result.data
console.log(data)
setData(data.items)
setTotal(data.total)
setPage(data.page)
setSize(data.size)
setError(null)
setLoading(true)
// 计算偏移量
const offset = (currentPage - 1) * itemsPerPage
const result = await getEdgeNodes(offset, itemsPerPage, val)
const validatedData = (result.data).map(item => ({
id: item.id,
macaddr: item.macaddr || '',
city: item.city || '',
public: item.public || '',
isp: item.isp || '',
single: item.single,
sole: item.sole,
arch: item.arch,
online: item.online,
}))
setData(validatedData)
setTotalItems(result.totalCount || 0)
}
catch (error) {
console.error('Failed to fetch edge nodes:', error)
setError(error instanceof Error ? error.message : '获取边缘节点数据失败')
setError('获取边缘节点数据失败' + (error instanceof Error ? `: ${error.message}` : ''))
}
finally {
setLoading(false)
}
}
const onSubmit = async (values: FilterFormValues) => {
setCurrentPage(1)
const filters = {
macaddr: values.macaddr || undefined,
public: values.public || undefined,
city: values.city || undefined,
isp: values.isp || undefined,
}
const onSubmit = () => {
fetchData(page, size)
}
fetchData(filters)
const onReset = () => {
form.reset()
fetchData(page, size)
}
// 处理页码变化
const handlePageChange = (page: number) => {
setPage(page)
fetchData(page, size)
}
// 处理每页显示数量变化
const handleSizeChange = (size: number) => {
setPage(1)
setSize(size)
fetchData(1, size)
}
// 多IP节点格式化
@@ -165,32 +161,9 @@ export default function Edge() {
return `${Math.floor(seconds / 86400)}`
}
// 处理页码变化
const handlePageChange = (page: number) => {
setCurrentPage(page)
const formValues = form.getValues()
const filters = {
macaddr: formValues.macaddr || '',
public: formValues.public || '',
city: formValues.city || '',
isp: formValues.isp || '',
}
fetchData(filters)
}
// 处理每页显示数量变化
const handleSizeChange = (size: number) => {
setItemsPerPage(size)
setCurrentPage(1)
const formValues = form.getValues()
const filters = {
macaddr: formValues.macaddr || '',
public: formValues.public || '',
city: formValues.city || '',
isp: formValues.isp || '',
}
fetchData(filters)
}
useEffect(() => {
fetchData(page, size)
}, [])
if (loading) return (
<div className="bg-white shadow p-6">
@@ -204,7 +177,7 @@ export default function Edge() {
<h2 className="text-xl font-semibold text-gray-800 mb-4"></h2>
<div className="text-center py-8 text-red-600">{error}</div>
<button
onClick={() => fetchData({})}
onClick={() => fetchData(page, size)}
className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors mx-auto block"
>
@@ -220,11 +193,14 @@ export default function Edge() {
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<div className="flex gap-4">
<FormField
control={form.control}
name="macaddr"
render={({ field }) => (
<FormItem>
<FormLabel>MAC地址</FormLabel>
<Input placeholder="输入MAC地址" {...field} />
<FormControl>
<Input placeholder="输入MAC地址" {...field} />
</FormControl>
</FormItem>
)}
/>
@@ -233,7 +209,9 @@ export default function Edge() {
render={({ field }) => (
<FormItem>
<FormLabel>IP</FormLabel>
<Input placeholder="输入公网IP" {...field} />
<FormControl>
<Input placeholder="输入公网IP" {...field} />
</FormControl>
</FormItem>
)}
/>
@@ -242,7 +220,9 @@ export default function Edge() {
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<Input placeholder="输入城市名称" {...field} />
<FormControl>
<Input placeholder="输入城市名称" {...field} />
</FormControl>
</FormItem>
)}
/>
@@ -252,14 +232,16 @@ export default function Edge() {
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<Input placeholder="输入运营商" {...field} />
<FormControl>
<Input placeholder="输入运营商" {...field} />
</FormControl>
</FormItem>
)}
/>
<Button type="submit" className="mt-5 py-2 bg-blue-600 hover:bg-blue-700">
</Button>
<Button type="button" variant="outline" className="mt-5 py-2" onClick={() => form.reset()}>
<Button type="button" variant="outline" className="mt-5 py-2" onClick={onReset}>
</Button>
</div>
@@ -333,12 +315,11 @@ export default function Edge() {
{/* 分页 */}
<Pagination
page={currentPage}
size={itemsPerPage}
total={totalItems}
page={page}
size={size}
total={total}
onPageChange={handlePageChange}
onSizeChange={handleSizeChange}
className="mt-4"
/>
</>
)}