完善查询函数
This commit is contained in:
@@ -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: '查询边缘节点失败',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}) => {
|
||||
try {
|
||||
setError(null)
|
||||
setLoading(true)
|
||||
try {
|
||||
const result = await getEdgeNodes(page, size, filters)
|
||||
if (!result.success) {
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
// 计算偏移量
|
||||
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,
|
||||
}))
|
||||
const data = result.data
|
||||
console.log(data)
|
||||
setData(data.items)
|
||||
setTotal(data.total)
|
||||
setPage(data.page)
|
||||
setSize(data.size)
|
||||
|
||||
setData(validatedData)
|
||||
setTotalItems(result.totalCount || 0)
|
||||
setError(null)
|
||||
}
|
||||
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>
|
||||
<FormControl>
|
||||
<Input placeholder="输入MAC地址" {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@@ -233,7 +209,9 @@ export default function Edge() {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>公网IP</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="输入公网IP" {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@@ -242,7 +220,9 @@ export default function Edge() {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>城市</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="输入城市名称" {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@@ -252,14 +232,16 @@ export default function Edge() {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>运营商</FormLabel>
|
||||
<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"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user