更新侧边栏改造使用路由结构,更新中间件重定向
This commit is contained in:
@@ -41,7 +41,7 @@ export default function LoginPage() {
|
|||||||
})
|
})
|
||||||
setAuth(true)
|
setAuth(true)
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
router.push('/dashboard')
|
router.push('/gatewayinfo')
|
||||||
router.refresh()
|
router.refresh()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
|
|||||||
if (error) return <ErrorCard title="节点分配状态" error={error} onRetry={fetchData} />
|
if (error) return <ErrorCard title="节点分配状态" error={error} onRetry={fetchData} />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col bg-white shadow p-6 overflow-hidden">
|
<div className="flex flex-col w-full bg-white shadow p-6 overflow-hidden">
|
||||||
<h2 className="text-lg font-semibold mb-4">节点分配状态</h2>
|
<h2 className="text-lg font-semibold mb-4">节点分配状态</h2>
|
||||||
|
|
||||||
<div className="mb-4 flex flex-wrap items-center gap-3">
|
<div className="mb-4 flex flex-wrap items-center gap-3">
|
||||||
@@ -30,7 +30,7 @@ export default function CityNodeStats() {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white p-6 overflow-hidden">
|
<div className="bg-white p-6 w-full overflow-hidden">
|
||||||
<h2 className="text-lg font-semibold mb-4">城市节点数量分布</h2>
|
<h2 className="text-lg font-semibold mb-4">城市节点数量分布</h2>
|
||||||
<div className="text-gray-600">加载中...</div>
|
<div className="text-gray-600">加载中...</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +38,7 @@ export default function CityNodeStats() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col bg-white p-6 overflow-hidden">
|
<div className="flex flex-col w-full bg-white p-6 overflow-hidden">
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<h2 className="text-lg font-semibold">城市节点数量分布</h2>
|
<h2 className="text-lg font-semibold">城市节点数量分布</h2>
|
||||||
<span className="text-sm text-gray-500">
|
<span className="text-sm text-gray-500">
|
||||||
@@ -166,14 +166,14 @@ export default function Edge() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (loading) return (
|
if (loading) return (
|
||||||
<div className="bg-white shadow p-6">
|
<div className="bg-white w-full shadow p-6">
|
||||||
<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">加载节点数据中...</div>
|
<div className="text-center py-8">加载节点数据中...</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (error) return (
|
if (error) return (
|
||||||
<div className="bg-white shadow p-6">
|
<div className="bg-white w-full shadow p-6">
|
||||||
<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
|
||||||
@@ -250,7 +250,7 @@ export default function Edge() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{data.length === 0 ? (
|
{data.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<div className="text-center w-full py-12">
|
||||||
<div className="text-gray-400 text-4xl mb-4">📋</div>
|
<div className="text-gray-400 text-4xl mb-4">📋</div>
|
||||||
<p className="text-gray-600">暂无节点数据</p>
|
<p className="text-gray-600">暂无节点数据</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -144,7 +144,7 @@ export default function Gatewayinfo() {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white shadow p-6 overflow-hidden">
|
<div className="bg-white w-full shadow p-6 overflow-hidden">
|
||||||
<h2 className="text-lg font-semibold mb-4">网关基本信息</h2>
|
<h2 className="text-lg font-semibold mb-4">网关基本信息</h2>
|
||||||
<div className="text-center py-8">加载网关信息中...</div>
|
<div className="text-center py-8">加载网关信息中...</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -153,7 +153,7 @@ export default function Gatewayinfo() {
|
|||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white shadow p-6">
|
<div className="bg-white w-full shadow p-6">
|
||||||
<h2 className="text-lg font-semibold mb-4">网关基本信息</h2>
|
<h2 className="text-lg font-semibold 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>
|
||||||
</div>
|
</div>
|
||||||
@@ -161,7 +161,7 @@ export default function Gatewayinfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col bg-white p-6 overflow-hidden">
|
<div className="flex flex-col w-full bg-white p-6 overflow-hidden">
|
||||||
<div className="flex gap-6">
|
<div className="flex gap-6">
|
||||||
<div className="flex flex-3 justify-between ">
|
<div className="flex flex-3 justify-between ">
|
||||||
<span className="text-lg pt-2 font-semibold mb-4">网关基本信息</span>
|
<span className="text-lg pt-2 font-semibold mb-4">网关基本信息</span>
|
||||||
@@ -220,14 +220,7 @@ export default function Gatewayinfo() {
|
|||||||
>
|
>
|
||||||
<TableCell className="px-4 py-2">
|
<TableCell className="px-4 py-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{/* <button
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/dashboard?tab=gateway&mac=${item.macaddr}`)
|
|
||||||
}}
|
|
||||||
className="font-mono text-blue-600 hover:text-blue-800 hover:underline cursor-pointer"
|
|
||||||
> */}
|
|
||||||
{item.macaddr}
|
{item.macaddr}
|
||||||
{/* </button> */}
|
|
||||||
<SmartCopyButton data={item.macaddr} />
|
<SmartCopyButton data={item.macaddr} />
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
103
src/app/(root)/layout.tsx
Normal file
103
src/app/(root)/layout.tsx
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { ReactNode, useState } from 'react'
|
||||||
|
import { useRouter, usePathname } from 'next/navigation'
|
||||||
|
import { logout } from '@/actions/auth'
|
||||||
|
import { LogOut } from 'lucide-react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default function DashboardLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const router = useRouter()
|
||||||
|
const pathname = usePathname()
|
||||||
|
|
||||||
|
const handleLogout = async () => {
|
||||||
|
setIsLoading(true)
|
||||||
|
try {
|
||||||
|
const response = await logout()
|
||||||
|
if (response) {
|
||||||
|
router.push('/login')
|
||||||
|
router.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('退出错误:', error)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isActive = (path: string) => {
|
||||||
|
return pathname === path
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-gray-100 w-screen h-screen flex flex-col overflow-hidden">
|
||||||
|
{/* 顶部导航栏 */}
|
||||||
|
<nav className="bg-white flex-none border-b h-16 shadow-sm">
|
||||||
|
<div className="px-4 sm:px-6">
|
||||||
|
<div className="flex justify-between h-16 items-center">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<h1 className="text-xl font-bold text-gray-900">网络节点管理系统</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 简化的退出按钮 */}
|
||||||
|
<button
|
||||||
|
onClick={handleLogout}
|
||||||
|
disabled={isLoading}
|
||||||
|
className="flex items-center space-x-2 px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 disabled:opacity-50 transition-colors"
|
||||||
|
>
|
||||||
|
<LogOut className="h-4 w-4" />
|
||||||
|
<span>{isLoading ? '退出中...' : '退出登录'}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* 主要内容区域 */}
|
||||||
|
<div className="flex flex-1 overflow-hidden">
|
||||||
|
{/* 侧边栏 */}
|
||||||
|
<div className="w-64 bg-gray-100 border-r border-gray-200 flex flex-col">
|
||||||
|
<nav className="flex-1 p-4 space-y-2">
|
||||||
|
<NavbarItem href="/gatewayinfo" active={isActive('/gatewayinfo')}>网关信息</NavbarItem>
|
||||||
|
<NavbarItem href="/gatewayConfig" active={isActive('/gatewayConfig')}>网关配置</NavbarItem>
|
||||||
|
<NavbarItem href="/gatewayMonitor" active={isActive('/gatewayMonitor')}>网关查询</NavbarItem>
|
||||||
|
<NavbarItem href="/cityNodeStats" active={isActive('/cityNodeStats')}>城市信息</NavbarItem>
|
||||||
|
<NavbarItem href="/allocationStatus" active={isActive('/allocationStatus')}>分配状态</NavbarItem>
|
||||||
|
<NavbarItem href="/edge" active={isActive('/edge')}>节点信息</NavbarItem>
|
||||||
|
<NavbarItem href="/settings" active={isActive('/settings')}>设置</NavbarItem>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 内容区域 */}
|
||||||
|
<div className="flex flex-3 w-full overflow-hidden">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavbarItem(props: {
|
||||||
|
href: string
|
||||||
|
active: boolean
|
||||||
|
children: ReactNode
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={props.href}
|
||||||
|
className={`block px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||||
|
props.active
|
||||||
|
? 'border-blue-500 text-blue-600'
|
||||||
|
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -123,8 +123,8 @@ export default function Settings() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white p-4 md:p-8">
|
<div className="bg-white p-6 flex w-full">
|
||||||
<div className="max-w-6xl mx-auto">
|
<div className="flex flex-col w-full">
|
||||||
<div className="flex justify-between items-center mb-6">
|
<div className="flex justify-between items-center mb-6">
|
||||||
<h1 className="text-3xl font-bold">用户管理</h1>
|
<h1 className="text-3xl font-bold">用户管理</h1>
|
||||||
<Button onClick={() => setIsCreateMode(!isCreateMode)}>
|
<Button onClick={() => setIsCreateMode(!isCreateMode)}>
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useState, useEffect, Suspense } from 'react'
|
|
||||||
import { useRouter, useSearchParams } from 'next/navigation'
|
|
||||||
import Gatewayinfo from './components/gatewayinfo'
|
|
||||||
import GatewayConfig from './components/gatewayConfig'
|
|
||||||
import GatewayConfigs from './components/gatewayConfigs'
|
|
||||||
import CityNodeStats from './components/cityNodeStats'
|
|
||||||
import AllocationStatus from './components/allocationStatus'
|
|
||||||
import Settings from './components/settings'
|
|
||||||
import Edge from './components/edge'
|
|
||||||
import { LogOut } from 'lucide-react'
|
|
||||||
import { logout } from '@/actions/auth'
|
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{ id: 'gatewayInfo', label: '网关信息' },
|
|
||||||
{ id: 'gateway', label: '网关配置' },
|
|
||||||
{ id: 'gateways', label: '网关查询' },
|
|
||||||
{ id: 'city', label: '城市信息' },
|
|
||||||
{ id: 'allocation', label: '分配状态' },
|
|
||||||
{ id: 'edge', label: '节点信息' },
|
|
||||||
{ id: 'setting', label: '设置' },
|
|
||||||
]
|
|
||||||
|
|
||||||
function DashboardContent() {
|
|
||||||
const [activeTab, setActiveTab] = useState('gatewayInfo')
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
const router = useRouter()
|
|
||||||
const searchParams = useSearchParams()
|
|
||||||
|
|
||||||
// 监听URL参数变化
|
|
||||||
useEffect(() => {
|
|
||||||
const urlTab = searchParams.get('tab')
|
|
||||||
if (urlTab && tabs.some(tab => tab.id === urlTab)) {
|
|
||||||
setActiveTab(urlTab)
|
|
||||||
}
|
|
||||||
}, [searchParams])
|
|
||||||
|
|
||||||
// 退出登录
|
|
||||||
const handleLogout = async () => {
|
|
||||||
setIsLoading(true)
|
|
||||||
try {
|
|
||||||
const response = await logout()
|
|
||||||
|
|
||||||
if (response) {
|
|
||||||
// 退出成功后跳转到登录页
|
|
||||||
router.push('/login')
|
|
||||||
router.refresh()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.error('退出失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('退出错误:', error)
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTabClick = (tabId: string) => {
|
|
||||||
setActiveTab(tabId)
|
|
||||||
// 更新 URL 参数
|
|
||||||
const params = new URLSearchParams()
|
|
||||||
params.set('tab', tabId)
|
|
||||||
router.push(`/dashboard?${params.toString()}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className=" bg-gray-100 w-screen h-screen flex flex-col">
|
|
||||||
<nav className="bg-white flex-none h-16 shadow-sm">
|
|
||||||
<div className="px-4 sm:px-6 lg:px-8">
|
|
||||||
<div className="flex justify-between h-16 items-center">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<h1 className="text-xl font-bold text-gray-900">网络节点管理系统</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 简化的退出按钮 */}
|
|
||||||
<button
|
|
||||||
onClick={handleLogout}
|
|
||||||
disabled={isLoading}
|
|
||||||
className="flex items-center space-x-2 px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 disabled:opacity-50 transition-colors"
|
|
||||||
>
|
|
||||||
<LogOut className="h-4 w-4" />
|
|
||||||
<span>{isLoading ? '退出中...' : '退出登录'}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div className="flex flex-3 overflow-hidden">
|
|
||||||
<div className="border-b border-gray-200 mb-6">
|
|
||||||
<nav className="flex flex-col w-64 -mb-px space-x-8">
|
|
||||||
{tabs.map(tab => (
|
|
||||||
<button
|
|
||||||
key={tab.id}
|
|
||||||
onClick={() => handleTabClick(tab.id)}
|
|
||||||
className={`py-2 px-1 h-12 border-b-2 font-medium text-sm ${
|
|
||||||
activeTab === tab.id
|
|
||||||
? 'border-blue-500 text-blue-600'
|
|
||||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{tab.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-6 border flex-auto">
|
|
||||||
{activeTab === 'gatewayInfo' && <Gatewayinfo />}
|
|
||||||
{activeTab === 'gateway' && <GatewayConfig />}
|
|
||||||
{activeTab === 'gateways' && <GatewayConfigs />}
|
|
||||||
{activeTab === 'city' && <CityNodeStats />}
|
|
||||||
{activeTab === 'allocation' && <AllocationStatus detailed />}
|
|
||||||
{activeTab === 'edge' && <Edge />}
|
|
||||||
{activeTab === 'setting' && <Settings />}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Dashboard() {
|
|
||||||
return (
|
|
||||||
<Suspense fallback={(
|
|
||||||
<div className=" bg-gray-100 flex items-center justify-center">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mx-auto"></div>
|
|
||||||
<p className="mt-4 text-gray-600">加载中...</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}>
|
|
||||||
<DashboardContent />
|
|
||||||
</Suspense>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import { findConfigs } from '@/actions/config'
|
|
||||||
import { gatewayConfigGet } from '@/actions/remote'
|
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
|
||||||
import { useState } from 'react'
|
|
||||||
import { Input } from '@/components/ui/input'
|
|
||||||
import { Button } from '@/components/ui/button'
|
|
||||||
|
|
||||||
type EdgeConfig = {
|
|
||||||
port?: string
|
|
||||||
edge?: string
|
|
||||||
city?: string
|
|
||||||
_index: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function DebugConfigPage() {
|
|
||||||
const [macaddr, setMacaddr] = useState('')
|
|
||||||
const [remotes, setRemotes] = useState<EdgeConfig[]>([])
|
|
||||||
const [locals, setLocals] = useState<EdgeConfig[]>([])
|
|
||||||
|
|
||||||
const fetch = async (macaddr: string) => {
|
|
||||||
try {
|
|
||||||
console.log('fetch', macaddr)
|
|
||||||
if (!macaddr) return
|
|
||||||
|
|
||||||
const rawLocal = await findConfigs({ macaddr })
|
|
||||||
console.log('raw local', rawLocal)
|
|
||||||
|
|
||||||
const rawRemote = await gatewayConfigGet({ macaddr })
|
|
||||||
console.log('raw remote', rawRemote)
|
|
||||||
|
|
||||||
setLocals(rawLocal.map(rule => ({
|
|
||||||
port: rule.network,
|
|
||||||
edge: rule.edge,
|
|
||||||
city: rule.cityhash,
|
|
||||||
_index: parseInt(rule.network.split('.')[3] || '0'),
|
|
||||||
})).sort((a, b) => a._index - b._index))
|
|
||||||
|
|
||||||
setRemotes(rawRemote.rules.map((rule) => {
|
|
||||||
const port = rule.network.find(n => !!n)
|
|
||||||
return ({
|
|
||||||
port: port,
|
|
||||||
edge: rule.edge.find(n => !!n),
|
|
||||||
city: rule.cityhash,
|
|
||||||
_index: port ? parseInt(port.split('.')[3]) : 0,
|
|
||||||
})
|
|
||||||
}).sort((a, b) => a._index - b._index))
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error('数据获取失败', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex-auto overflow-hidden flex flex-col p-6 gap-4.5">
|
|
||||||
<div className="flex-none flex gap-3">
|
|
||||||
<Input type="text" name="macaddr" value={macaddr} onChange={e => setMacaddr(e.target.value)} className="flex-none basis-60" />
|
|
||||||
<Button onClick={() => fetch(macaddr)}>查询</Button>
|
|
||||||
</div>
|
|
||||||
<Table>
|
|
||||||
<TableHeader>
|
|
||||||
<TableRow>
|
|
||||||
<TableHead>端口</TableHead>
|
|
||||||
<TableHead>节点</TableHead>
|
|
||||||
<TableHead>城市</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{!locals.length || !remotes.length ? (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={3} className="text-center">获取数据为空</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
) : locals.length !== remotes.length ? (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={3} className="text-center">本地和远程规则数量不匹配</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
) : (
|
|
||||||
locals.map((item, index) => (
|
|
||||||
<TableRow key={index}>
|
|
||||||
<TableCell>
|
|
||||||
{item.port === remotes[index].port ? (
|
|
||||||
<span className="text-green-500">{item.port}</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-red-500">{item.port} : {remotes[index].port}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
{item.edge === remotes[index].edge ? (
|
|
||||||
<span className="text-green-500">{item.edge}</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-red-500">{item.edge} : {remotes[index].edge}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
{item.city === remotes[index].city ? (
|
|
||||||
<span className="text-green-500">{item.city}</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-red-500">{item.city} : {remotes[index].city}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { ReactNode } from 'react'
|
|
||||||
|
|
||||||
export default async function DebugLayout(props: {
|
|
||||||
children: ReactNode
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="w-screen h-screen flex flex-col">
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
export default function LoadingCard({ title }: { title: string }) {
|
export default function LoadingCard({ title }: { title: string }) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white shadow p-6">
|
<div className="bg-white w-full shadow p-6">
|
||||||
<div className="animate-pulse">
|
<div className="animate-pulse">
|
||||||
<div className="h-6 bg-gray-200 rounded w-1/4 mb-4"></div>
|
<div className="h-6 bg-gray-200 rounded w-1/4 mb-4"></div>
|
||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export async function middleware(request: NextRequest) {
|
|||||||
|
|
||||||
// 给没有页面的路径添加跳转页面
|
// 给没有页面的路径添加跳转页面
|
||||||
if (request.nextUrl.pathname === '/') {
|
if (request.nextUrl.pathname === '/') {
|
||||||
return NextResponse.redirect(new URL('/dashboard', request.url))
|
return NextResponse.redirect(new URL('/gatewayinfo', request.url))
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.next()
|
return NextResponse.next()
|
||||||
|
|||||||
Reference in New Issue
Block a user