完善查询函数
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
'use server'
|
'use server'
|
||||||
|
|
||||||
import { Page, Res } from '@/lib/api'
|
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 = {
|
export type AllocationStatus = {
|
||||||
city: string
|
city: string
|
||||||
@@ -134,7 +134,13 @@ export async function getGatewayConfig(page?: number, filters?: {
|
|||||||
.from(gateway)
|
.from(gateway)
|
||||||
.leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash))
|
.leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash))
|
||||||
.leftJoin(edge, eq(edge.macaddr, gateway.edge))
|
.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)`)
|
.orderBy(sql`inet_aton(gateway.inner_ip)`)
|
||||||
.offset((page - 1) * 250)
|
.offset((page - 1) * 250)
|
||||||
.limit(250),
|
.limit(250),
|
||||||
@@ -210,7 +216,7 @@ export async function getCityNodeCount() {
|
|||||||
export type Edge = {
|
export type Edge = {
|
||||||
id: number
|
id: number
|
||||||
macaddr: string
|
macaddr: string
|
||||||
city: string
|
city: string | null
|
||||||
public: string
|
public: string
|
||||||
isp: string
|
isp: string
|
||||||
single: number | boolean
|
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
|
macaddr?: string
|
||||||
public?: string
|
public?: string
|
||||||
city?: string
|
city?: string
|
||||||
isp?: string
|
isp?: string
|
||||||
},
|
}): Promise<Res<Page<Edge>>> {
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const offset = Math.max(0, (page - 1)) * size
|
page = Math.max(1, page)
|
||||||
const limit = Math.min(100, Math.max(10, size))
|
size = Math.min(100, Math.max(10, size))
|
||||||
|
|
||||||
const [total, data] = await Promise.all([
|
const condition = and(
|
||||||
drizzle.$count(edge, eq(edge.active, 1)),
|
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
|
drizzle
|
||||||
.select({
|
.select({
|
||||||
id: edge.id,
|
id: edge.id,
|
||||||
@@ -247,25 +283,26 @@ export async function getEdgeNodes(page: number, size: number, props?: {
|
|||||||
})
|
})
|
||||||
.from(edge)
|
.from(edge)
|
||||||
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
|
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
|
||||||
.where(eq(edge.active, 1))
|
.where(condition)
|
||||||
.orderBy(edge.id)
|
.orderBy(edge.id)
|
||||||
.offset(offset)
|
.offset(page * size - size)
|
||||||
.limit(limit),
|
.limit(size),
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
success: true,
|
||||||
totalCount: total,
|
data: {
|
||||||
currentPage: Math.floor(offset / limit) + 1,
|
total: total[0].value,
|
||||||
totalPages: Math.ceil(total / limit),
|
page,
|
||||||
|
size,
|
||||||
|
items,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('Edge nodes query error:', error)
|
console.error('Edge nodes query error:', error)
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
data: [],
|
|
||||||
error: '查询边缘节点失败',
|
error: '查询边缘节点失败',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
|||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import { Button } from '@/components/ui/button'
|
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 { Input } from '@/components/ui/input'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
// 定义表单验证规则
|
// 定义表单验证规则
|
||||||
const filterSchema = z.object({
|
const filterSchema = z.object({
|
||||||
macaddr: z.string().optional(),
|
macaddr: z.string(),
|
||||||
public: z.string().optional(),
|
public: z.string(),
|
||||||
city: z.string().optional(),
|
city: z.string(),
|
||||||
isp: z.string().optional(),
|
isp: z.string(),
|
||||||
})
|
})
|
||||||
|
|
||||||
type FilterFormValues = z.infer<typeof filterSchema>
|
type FilterFormValues = z.infer<typeof filterSchema>
|
||||||
@@ -28,9 +28,9 @@ export default function Edge() {
|
|||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
|
||||||
// 分页状态
|
// 分页状态
|
||||||
const [currentPage, setCurrentPage] = useState(1)
|
const [page, setPage] = useState(1)
|
||||||
const [itemsPerPage, setItemsPerPage] = useState(100) // 默认100条
|
const [size, setSize] = useState(100)
|
||||||
const [totalItems, setTotalItems] = useState(0)
|
const [total, setTotal] = useState(0)
|
||||||
|
|
||||||
// 初始化表单
|
// 初始化表单
|
||||||
const form = useForm<FilterFormValues>({
|
const form = useForm<FilterFormValues>({
|
||||||
@@ -43,57 +43,53 @@ export default function Edge() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
const fetchData = async (page: number, size: number) => {
|
||||||
fetchData({})
|
const filters = form.getValues()
|
||||||
}, [currentPage, itemsPerPage])
|
|
||||||
|
|
||||||
const fetchData = async (val: {
|
setLoading(true)
|
||||||
macaddr?: string
|
|
||||||
public?: string
|
|
||||||
city?: string
|
|
||||||
isp?: string
|
|
||||||
}) => {
|
|
||||||
try {
|
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)
|
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) {
|
catch (error) {
|
||||||
console.error('Failed to fetch edge nodes:', error)
|
setError('获取边缘节点数据失败' + (error instanceof Error ? `: ${error.message}` : ''))
|
||||||
setError(error instanceof Error ? error.message : '获取边缘节点数据失败')
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = async (values: FilterFormValues) => {
|
const onSubmit = () => {
|
||||||
setCurrentPage(1)
|
fetchData(page, size)
|
||||||
const filters = {
|
}
|
||||||
macaddr: values.macaddr || undefined,
|
|
||||||
public: values.public || undefined,
|
|
||||||
city: values.city || undefined,
|
|
||||||
isp: values.isp || undefined,
|
|
||||||
}
|
|
||||||
|
|
||||||
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节点格式化
|
// 多IP节点格式化
|
||||||
@@ -165,32 +161,9 @@ export default function Edge() {
|
|||||||
return `${Math.floor(seconds / 86400)}天`
|
return `${Math.floor(seconds / 86400)}天`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理页码变化
|
useEffect(() => {
|
||||||
const handlePageChange = (page: number) => {
|
fetchData(page, size)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loading) return (
|
if (loading) return (
|
||||||
<div className="bg-white shadow p-6">
|
<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>
|
<h2 className="text-xl font-semibold text-gray-800 mb-4">节点列表</h2>
|
||||||
<div className="text-center py-8 text-red-600">{error}</div>
|
<div className="text-center py-8 text-red-600">{error}</div>
|
||||||
<button
|
<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"
|
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">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<FormField
|
<FormField
|
||||||
|
control={form.control}
|
||||||
name="macaddr"
|
name="macaddr"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>MAC地址</FormLabel>
|
<FormLabel>MAC地址</FormLabel>
|
||||||
<Input placeholder="输入MAC地址" {...field} />
|
<FormControl>
|
||||||
|
<Input placeholder="输入MAC地址" {...field} />
|
||||||
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -233,7 +209,9 @@ export default function Edge() {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>公网IP</FormLabel>
|
<FormLabel>公网IP</FormLabel>
|
||||||
<Input placeholder="输入公网IP" {...field} />
|
<FormControl>
|
||||||
|
<Input placeholder="输入公网IP" {...field} />
|
||||||
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -242,7 +220,9 @@ export default function Edge() {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>城市</FormLabel>
|
<FormLabel>城市</FormLabel>
|
||||||
<Input placeholder="输入城市名称" {...field} />
|
<FormControl>
|
||||||
|
<Input placeholder="输入城市名称" {...field} />
|
||||||
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -252,14 +232,16 @@ export default function Edge() {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>运营商</FormLabel>
|
<FormLabel>运营商</FormLabel>
|
||||||
<Input placeholder="输入运营商" {...field} />
|
<FormControl>
|
||||||
|
<Input placeholder="输入运营商" {...field} />
|
||||||
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Button type="submit" className="mt-5 py-2 bg-blue-600 hover:bg-blue-700">
|
<Button type="submit" className="mt-5 py-2 bg-blue-600 hover:bg-blue-700">
|
||||||
查询
|
查询
|
||||||
</Button>
|
</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>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -333,12 +315,11 @@ export default function Edge() {
|
|||||||
|
|
||||||
{/* 分页 */}
|
{/* 分页 */}
|
||||||
<Pagination
|
<Pagination
|
||||||
page={currentPage}
|
page={page}
|
||||||
size={itemsPerPage}
|
size={size}
|
||||||
total={totalItems}
|
total={total}
|
||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onSizeChange={handleSizeChange}
|
onSizeChange={handleSizeChange}
|
||||||
className="mt-4"
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user