feat(gateway): 新增接口11和61的鉴权与测试页
This commit is contained in:
@@ -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"));
|
||||
}
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user