'use server' import { Page, Res } from '@/lib/api' import drizzle, { and, change, cityhash, count, desc, edge, eq, gateway, is, sql, token } from '@/lib/drizzle' import { cache } from 'react' export type AllocationStatus = { city: string count: number assigned: number } // 城市分配状态 export async function getAllocationStatus(hours: number = 24) { try { const c1 = drizzle .select({ cityId: edge.cityId, count: count().as('count'), }) .from(edge) .where(eq(edge.active, 1)) .groupBy(edge.cityId) .as('c1') const c2 = drizzle .select({ cityId: change.city, assigned: count().as('assigned'), }) .from(change) .where(sql`time > NOW() - INTERVAL ${hours} HOUR`) .groupBy(change.city) .as('c2') const result = await drizzle .select({ city: cityhash.city, count: sql`c1.count`, assigned: sql`ifnull(c2.assigned, 0)`, }) .from(cityhash) .leftJoin(c1, eq(c1.cityId, cityhash.id)) .leftJoin(c2, eq(c2.cityId, cityhash.id)) .where(sql`cityhash.macaddr is not null`) return { success: true, data: result, } } catch (error) { console.error('Allocation status query error:', error) const errorMessage = error instanceof Error ? error.message : 'Unknown error' return { success: false, data: [], error: '查询分配状态失败: ' + errorMessage, } } } export type GatewayInfo = { macaddr: string inner_ip: string setid: number enable: number } // 获取网关基本信息 export async function getGatewayInfo() { try { const result = await drizzle .select({ macaddr: token.macaddr, inner_ip: token.innerIp, setid: token.setid, enable: token.enable, }) .from(token) .orderBy(sql`cast(regexp_replace(token.inner_ip, '192.168.50.', '') as unsigned)`) return { success: true, data: result, } } catch (error) { console.error('Gateway info query error:', error) return { success: false, data: [], error: '查询网关信息失败', } } } export type GatewayConfig = { city: string | null edge: string user: string public: string | null inner_ip: string ischange: number isonline: number } // 网关配置 export const getGatewayConfig = cache(async (page?: number, filters?: { mac?: string public?: string city?: string user?: string inner_ip?: string }): Promise>> => { try { if (!page && !filters?.mac) { throw new Error('页码和MAC地址不能同时为空') } page = filters?.mac ? 1 : Math.max(1, page || 1) const condition = 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 const [total, result] = await Promise.all([ drizzle .select({ value: count(), }) .from(gateway) .leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash)) .leftJoin(edge, eq(edge.macaddr, gateway.edge)) .where(condition), drizzle .select({ city: cityhash.city, edge: gateway.edge, user: gateway.user, public: edge.public, inner_ip: gateway.network, ischange: gateway.ischange, isonline: gateway.isonline, }) .from(gateway) .leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash)) .leftJoin(edge, eq(edge.macaddr, gateway.edge)) .where(condition) .orderBy(sql`inet_aton(gateway.inner_ip)`) .offset((page - 1) * 250) .limit(250), ]) return { success: true, data: { total: total[0].value, page, size: 250, items: result, }, } } catch (error) { console.error('Gateway config query error:', error) return { success: false, error: '查询网关配置失败', } } }) export type CityNode = { city: string count: number hash: string label: string | null offset: number } // 城市节点数量分布 export async function getCityNodeCount() { try { const e = drizzle .select({ cityId: edge.cityId, count: count().as('count'), }) .from(edge) .where(eq(edge.active, 1)) .groupBy(edge.cityId) .as('e') const result = await drizzle .select({ city: cityhash.city, hash: cityhash.hash, label: cityhash.label, count: sql`ifnull(e.count, 0)`, offset: cityhash.offset, }) .from(cityhash) .leftJoin(e, eq(e.cityId, cityhash.id)) .groupBy(cityhash.hash) .orderBy(desc(sql`e.count`)) return { success: true, data: result, } } catch (error) { console.error('City node count query error:', error) return { success: false, data: [], error: '查询城市节点失败', } } } export type Edge = { id: number macaddr: string city: string | null public: string isp: string single: number | boolean sole: number | boolean arch: number online: number } // 获取节点信息 export async function getEdgeNodes(page: number, size: number, filters?: { macaddr?: string public?: string city?: string isp?: string }): Promise>> { try { page = Math.max(1, page) size = Math.min(100, Math.max(10, size)) 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, 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), ]) return { success: true, data: { total: total[0].value, page, size, items, }, } } catch (error) { console.error('Edge nodes query error:', error) return { success: false, error: '查询边缘节点失败', } } }