Initial commit: FunConnect project with server, relay, client and admin panel
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
101
client/ui/src/components/ConnectionStatus.tsx
Normal file
101
client/ui/src/components/ConnectionStatus.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useConfigStore } from '../stores/configStore'
|
||||
|
||||
type ConnectionState = 'connected' | 'connecting' | 'disconnected' | 'error'
|
||||
|
||||
interface ConnectionStatusProps {
|
||||
showDetails?: boolean
|
||||
}
|
||||
|
||||
export function ConnectionStatus({ showDetails = false }: ConnectionStatusProps) {
|
||||
const { config } = useConfigStore()
|
||||
const [status, setStatus] = useState<ConnectionState>('connecting')
|
||||
const [latency, setLatency] = useState<number | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const checkConnection = async () => {
|
||||
if (!config?.server_url) {
|
||||
setStatus('disconnected')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const start = performance.now()
|
||||
const response = await fetch(`${config.server_url}/api/v1/health`, {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
})
|
||||
const elapsed = Math.round(performance.now() - start)
|
||||
|
||||
if (response.ok) {
|
||||
setStatus('connected')
|
||||
setLatency(elapsed)
|
||||
} else {
|
||||
setStatus('error')
|
||||
setLatency(null)
|
||||
}
|
||||
} catch {
|
||||
setStatus('disconnected')
|
||||
setLatency(null)
|
||||
}
|
||||
}
|
||||
|
||||
checkConnection()
|
||||
const interval = setInterval(checkConnection, 30000)
|
||||
return () => clearInterval(interval)
|
||||
}, [config?.server_url])
|
||||
|
||||
const statusConfig = {
|
||||
connected: {
|
||||
color: 'bg-green-500',
|
||||
text: '已连接',
|
||||
icon: '🟢',
|
||||
},
|
||||
connecting: {
|
||||
color: 'bg-yellow-500 animate-pulse',
|
||||
text: '连接中',
|
||||
icon: '🟡',
|
||||
},
|
||||
disconnected: {
|
||||
color: 'bg-red-500',
|
||||
text: '未连接',
|
||||
icon: '🔴',
|
||||
},
|
||||
error: {
|
||||
color: 'bg-orange-500',
|
||||
text: '连接异常',
|
||||
icon: '🟠',
|
||||
},
|
||||
}
|
||||
|
||||
const { color, text, icon } = statusConfig[status]
|
||||
|
||||
if (!showDetails) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`w-2 h-2 rounded-full ${color}`} />
|
||||
<span className="text-xs text-gray-400">{text}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-3 px-3 py-2 bg-gray-800/50 rounded-lg">
|
||||
<span className="text-sm">{icon}</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-white">{config?.server_name || 'FunMC'}</p>
|
||||
<p className="text-xs text-gray-400 truncate">{config?.server_url}</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-xs text-gray-400">{text}</p>
|
||||
{latency !== null && (
|
||||
<p className={`text-xs font-mono ${
|
||||
latency < 100 ? 'text-green-400' :
|
||||
latency < 300 ? 'text-yellow-400' : 'text-red-400'
|
||||
}`}>
|
||||
{latency}ms
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user