feat(All) 修改结果展示样式,增加测试地区覆盖范围

This commit is contained in:
2025-12-19 15:21:55 +08:00
parent 2f6831336e
commit 1a0815759e
15 changed files with 1336 additions and 368 deletions

View File

@@ -6,10 +6,17 @@ export interface IpInfoResponse {
ip: string
}
export interface LatencyTestResponse {
nodeId: string
latency: number | null
success: boolean
export interface BatchMeasurementResponse {
measurementId: string
}
export interface BatchResultResponse {
status: 'in-progress' | 'finished'
results: Array<{
nodeId: string
latency: number | null
success: boolean
}>
}
export async function fetchUserIp(): Promise<string> {
@@ -19,34 +26,67 @@ export async function fetchUserIp(): Promise<string> {
return data.ip
}
export async function testLatency(
targetIp: string,
nodeId: string
): Promise<LatencyResult> {
const res = await fetch(`${API_BASE}/latency`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ targetIp, nodeId }),
})
if (!res.ok) {
return { nodeId, latency: null, status: 'failed' }
}
const data: LatencyTestResponse = await res.json()
return {
nodeId: data.nodeId,
latency: data.latency,
status: data.success ? 'success' : 'failed',
}
}
export async function testAllNodes(
targetIp: string,
target: string,
onProgress: (result: LatencyResult) => void
): Promise<void> {
const promises = TEST_NODES.map(async (node) => {
onProgress({ nodeId: node.id, latency: null, status: 'testing' })
const result = await testLatency(targetIp, node.id)
onProgress(result)
for (const node of TEST_NODES) {
onProgress({ nodeId: node.id, latency: null, status: 'pending' })
}
const res = await fetch(`${API_BASE}/latency/batch`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ target }),
})
await Promise.all(promises)
if (!res.ok) {
for (const node of TEST_NODES) {
onProgress({ nodeId: node.id, latency: null, status: 'failed' })
}
return
}
const { measurementId }: BatchMeasurementResponse = await res.json()
for (const node of TEST_NODES) {
onProgress({ nodeId: node.id, latency: null, status: 'testing' })
}
const startTime = Date.now()
const timeout = 60000
const completedNodes = new Set<string>()
while (Date.now() - startTime < timeout) {
await new Promise(r => setTimeout(r, 800))
const pollRes = await fetch(`${API_BASE}/latency/batch/${measurementId}`)
if (!pollRes.ok) continue
const data: BatchResultResponse = await pollRes.json()
for (const result of data.results) {
if (result.success && !completedNodes.has(result.nodeId)) {
completedNodes.add(result.nodeId)
onProgress({
nodeId: result.nodeId,
latency: result.latency,
status: 'success'
})
}
}
if (data.status === 'finished') {
for (const result of data.results) {
if (!completedNodes.has(result.nodeId)) {
onProgress({
nodeId: result.nodeId,
latency: result.latency,
status: result.success ? 'success' : 'failed'
})
}
}
break
}
}
}