feat(gateway): 新增接口11和61的鉴权与测试页

This commit is contained in:
xsl
2026-11-10 22:03:41 +08:00
parent a63a0565d8
commit 49cee683ad
11 changed files with 464 additions and 12 deletions
+156
View File
@@ -0,0 +1,156 @@
(() => {
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 = '<div class="label"></div><div class="value"><span></span> <span class="unit">cm</span></div>';
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"));
}
});
})();