const DIAGNOSIS_CONFIG = { port_open: { title: "端口开放", icon: "✓", class: "success" }, port_not_open: { title: "端口未开放", icon: "✗", class: "danger" }, likely_firewall: { title: "可能被防火墙拦截", icon: "⚠", class: "warning" }, likely_blocked: { title: "可能被墙或过滤", icon: "⊘", class: "danger" }, host_unreachable: { title: "主机不可达", icon: "✗", class: "danger" }, dns_failed: { title: "DNS 解析失败", icon: "✗", class: "danger" }, udp_ambiguous: { title: "UDP 状态不确定", icon: "?", class: "info" }, }; const STATUS_LABELS = { open: { text: "开放", class: "status-open" }, closed: { text: "关闭", class: "status-closed" }, filtered: { text: "被过滤", class: "status-filtered" }, unknown: { text: "不确定", class: "status-unknown" }, }; const form = document.getElementById("checkForm"); const submitBtn = document.getElementById("submitBtn"); const btnText = submitBtn.querySelector(".btn-text"); const btnLoading = submitBtn.querySelector(".btn-loading"); const errorBox = document.getElementById("errorBox"); const resultBox = document.getElementById("resultBox"); form.addEventListener("submit", async (e) => { e.preventDefault(); hideError(); resultBox.hidden = true; setLoading(true); const host = document.getElementById("host").value.trim(); const port = parseInt(document.getElementById("port").value, 10); const protocol = document.getElementById("protocol").value; try { const resp = await fetch("/api/check", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ host, port, protocol }), }); const json = await resp.json(); if (!resp.ok) { throw new Error(json.detail || json.error || "请求失败"); } if (!json.success || !json.data) { throw new Error(json.error || "检测失败"); } renderResult(json.data); } catch (err) { showError(err.message || "网络错误,请稍后重试"); } finally { setLoading(false); } }); function setLoading(loading) { submitBtn.disabled = loading; btnText.hidden = loading; btnLoading.hidden = !loading; } function showError(msg) { errorBox.textContent = msg; errorBox.hidden = false; } function hideError() { errorBox.hidden = true; } function renderResult(data) { const diag = DIAGNOSIS_CONFIG[data.diagnosis] || DIAGNOSIS_CONFIG.udp_ambiguous; const status = STATUS_LABELS[data.port_status] || STATUS_LABELS.unknown; const card = document.getElementById("diagnosisCard"); card.className = `diagnosis-card ${diag.class}`; document.getElementById("diagnosisIcon").textContent = diag.icon; document.getElementById("diagnosisTitle").textContent = diag.title; document.getElementById("diagnosisMessage").textContent = data.diagnosis_message; document.getElementById("elapsed").textContent = `耗时 ${data.elapsed_ms}ms`; document.getElementById("infoTarget").textContent = `${data.host}:${data.port} (${data.protocol.toUpperCase()})`; document.getElementById("infoIp").textContent = data.resolved_ip || "-"; document.getElementById("infoStatus").innerHTML = `${status.text}`; document.getElementById("infoReachable").textContent = data.host_reachable ? "是" : "否"; document.getElementById("infoLatency").textContent = data.latency_ms != null ? `${data.latency_ms} ms` : "-"; const list = document.getElementById("detailsList"); list.innerHTML = ""; (data.details || []).forEach((d) => { const li = document.createElement("li"); li.textContent = d; list.appendChild(li); }); resultBox.hidden = false; }