(() => { const $ = (id) => document.getElementById(id); const form = $("measure-test"); const { endpoint, totalHeightLabel } = form.dataset; const fileInput = $("imageFile"); const submitButton = $("submitBtn"); const clearButton = $("clearBtn"); const copyButton = $("copyBtn"); const metrics = $("metricsBar"); const results = $("resultsArea"); const jsonContent = $("jsonContent"); const placeholder = $("imagePlaceholder"); const imageStack = $("imageStack"); const baseImage = $("baseImage"); const annotationImage = $("annotationImage"); let originalImageUrl; function setStatus(text, type = "") { const status = $("statusBar"); status.textContent = text; status.className = type ? "status " + type : "status"; } function resetResults() { results.classList.add("hidden"); metrics.classList.add("hidden"); jsonContent.textContent = ""; imageStack.hidden = true; placeholder.hidden = false; placeholder.textContent = "提交后显示叠加效果"; baseImage.removeAttribute("src"); annotationImage.removeAttribute("src"); if (originalImageUrl) { URL.revokeObjectURL(originalImageUrl); originalImageUrl = undefined; } } function updateOverlay() { baseImage.hidden = !$("showBase").checked; annotationImage.hidden = !$("showAnno").checked; annotationImage.style.opacity = $("annoOpacity").value / 100; } function renderMetrics(data) { const courts = data.four_courts || {}; const eyes = data.seven_eyes || {}; const items = [[totalHeightLabel, data.face_total_height_cm]]; if (form.hasAttribute("data-include-top-court")) items.push(["顶庭", courts.top_court_cm]); items.push( ["上庭", courts.upper_court_cm], ["中庭", courts.middle_court_cm], ["下庭", courts.lower_court_cm], ["单眼宽度", eyes.eye_width_cm], ["脸宽", eyes.face_width_cm], ["两眼间距", eyes.inter_eye_distance_cm], ); metrics.replaceChildren(); for (const [label, value] of items) { const card = document.createElement("div"); card.className = "metric"; card.innerHTML = '
cm
'; card.querySelector(".label").textContent = label; card.querySelector(".value span").textContent = value ?? "—"; metrics.append(card); } metrics.classList.remove("hidden"); } form.addEventListener("submit", async (event) => { event.preventDefault(); const selected = fileInput.files[0]; if (!selected) { setStatus("请先选择一张图片", "error"); return; } fileInput.disabled = submitButton.disabled = clearButton.disabled = true; submitButton.textContent = "⏳ 请求中..."; resetResults(); setStatus("正在请求 " + endpoint, "info"); try { const file = await window.downscaleImageFile(selected); const body = new FormData(); body.append("image_file", file); const start = performance.now(); const response = await window.hairClientFetch(endpoint, { method: "POST", body }); if (!response.headers.get("Content-Type")?.includes("application/json")) { throw new Error("服务返回 HTTP " + response.status + ",响应格式异常"); } const result = await response.json(); const elapsed = ((performance.now() - start) / 1000).toFixed(2); jsonContent.textContent = JSON.stringify(result, null, 2); results.classList.remove("hidden"); if (!response.ok || result.code !== 0) { setStatus(`请求失败 (${elapsed}s) · HTTP ${response.status} · code ${result.code} · ${result.message}`, "error"); placeholder.textContent = "请求失败,无标注图"; return; } const data = result.data; const annotationSrc = window.resolveImgSrc(data.annotated_image_url, data.annotated_image_base64, "image/png"); if (annotationSrc) { originalImageUrl = URL.createObjectURL(file); baseImage.src = originalImageUrl; annotationImage.src = annotationSrc; updateOverlay(); imageStack.hidden = false; placeholder.hidden = true; } else { placeholder.textContent = "服务未返回标注图"; } renderMetrics(data); setStatus(`请求成功 (${elapsed}s) · request_id ${result.request_id}`, "success"); } catch (error) { setStatus(error.message, "error"); } finally { fileInput.disabled = submitButton.disabled = clearButton.disabled = false; submitButton.textContent = "🚀 提交测试"; } }); $("showBase").addEventListener("change", updateOverlay); $("showAnno").addEventListener("change", updateOverlay); $("annoOpacity").addEventListener("input", updateOverlay); clearButton.addEventListener("click", () => { resetResults(); fileInput.value = ""; setStatus(""); }); copyButton.addEventListener("click", async () => { try { await navigator.clipboard.writeText(jsonContent.textContent); copyButton.textContent = "✅ 已复制"; setTimeout(() => { copyButton.textContent = "📋 复制"; }, 1500); } catch { setStatus("复制失败,请手动复制 JSON", "error"); } }); fileInput.addEventListener("change", () => { if (fileInput.files.length) setStatus("已选择 " + fileInput.files[0].name, "info"); }); fileInput.addEventListener("dragover", (event) => event.preventDefault()); fileInput.addEventListener("drop", (event) => { event.preventDefault(); if (event.dataTransfer.files.length) { fileInput.files = event.dataTransfer.files; fileInput.dispatchEvent(new Event("change")); } }); })();