This commit is contained in:
vee
2026-08-14 15:01:29 +08:00
parent 6d768aaef4
commit f77dda70fe
20 changed files with 1125 additions and 122 deletions
+73 -7
View File
@@ -26,6 +26,7 @@
let toastTimer = 0;
let settingsHydrated = false;
let activeView = "live";
let bootstrapResetComplete = false;
function buildShell() {
const sidebar = $(".v2-sidebar");
@@ -101,18 +102,24 @@
<div class="v2-calibration-seat-scene">
<div class="v2-calibration-floor-grid"></div>
<div id="calibrationSeatViewer" class="seat-model-host calibration-cartoon-viewer">
<canvas id="calibrationSeatCanvas" aria-label="自标定卡通风格三维座椅,可拖动旋转并滚轮缩放"></canvas>
<canvas id="calibrationSeatCanvas" aria-label="自标定三维座椅,拖动空白处旋转视角,拖动轴标签或座椅部件调节四轴"></canvas>
<div id="seatModelLoading" class="model-loading">
<span class="model-spinner"></span>
<strong>正在构建座椅数字孪生</strong>
<small>CALIBRATION · CARTOON TWIN</small>
</div>
<div class="orbit-hint">拖动旋转 · 滚轮缩放 · 双击复位</div>
<div class="orbit-hint">拖动空白处旋转 · 拖动轴标签或座椅部件调轴 · 滚轮缩放 · 双击复位</div>
</div>
<div class="v2-axis-tag tag-back">靠背 <b id="calibrationTagBack">0.0°</b></div>
<div class="v2-axis-tag tag-base">前后 <b id="calibrationTagLong">0.00 cm</b></div>
<div class="v2-axis-tag tag-leg">腿托 <b id="calibrationTagLeg">0.0°</b></div>
<div class="v2-axis-tag tag-height">高度 <b id="calibrationTagHeight">0.00 cm</b></div>
<svg class="v2-calibration-label-lines" id="calibrationSeatLabelLines" aria-hidden="true">
<line data-seat-label-line="backrest"></line>
<line data-seat-label-line="longitudinal"></line>
<line data-seat-label-line="legrest"></line>
<line data-seat-label-line="height"></line>
</svg>
<div class="v2-axis-tag tag-back" data-seat-axis-label="backrest" role="slider" tabindex="0" aria-label="拖动调节靠背" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="0" aria-disabled="true"><i></i><span>靠背 <b id="calibrationTagBack">0.0°</b></span></div>
<div class="v2-axis-tag tag-base" data-seat-axis-label="longitudinal" role="slider" tabindex="0" aria-label="拖动调节前后位置" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="0" aria-disabled="true"><i></i><span>前后 <b id="calibrationTagLong">0.00 cm</b></span></div>
<div class="v2-axis-tag tag-leg" data-seat-axis-label="legrest" role="slider" tabindex="0" aria-label="拖动调节腿托" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="0" aria-disabled="true"><i></i><span>腿托 <b id="calibrationTagLeg">0.0°</b></span></div>
<div class="v2-axis-tag tag-height" data-seat-axis-label="height" role="slider" tabindex="0" aria-label="拖动调节高度" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="0" aria-disabled="true"><i></i><span>高度 <b id="calibrationTagHeight">0.00 cm</b></span></div>
</div>
<div class="v2-calibration-operation">
<i></i><div><small>当前任务</small><strong id="calibrationOperationLabel">等待设备检测</strong></div><span>JOB <b id="calibrationJobId">—</b></span>
@@ -234,6 +241,7 @@
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.message || data.error || `HTTP ${response.status}`);
render(data);
return data;
}
async function run(action, success = "") {
@@ -300,6 +308,15 @@
renderWorkflow(state.operation.phase);
renderAxes(state.axes, controller.job_active, transport.state === "online");
renderSeat(state.axes);
const seatViewer = $("#calibrationSeatViewer");
const axisControlEnabled = transport.state === "online" && !controller.job_active;
if (seatViewer) {
seatViewer.dataset.axisControlEnabled = String(axisControlEnabled);
}
$$('[data-seat-axis-label]').forEach((label) => {
label.dataset.controlEnabled = String(axisControlEnabled);
label.setAttribute("aria-disabled", String(!axisControlEnabled));
});
renderVideo(state.video);
$("#calibrationStartAll").disabled =
transport.state !== "online" || controller.job_active;
@@ -411,6 +428,47 @@
$("#calibrationTagLeg").textContent = `${legrest.physical_value.toFixed(1)}°`;
$("#calibrationTagBack").textContent = `${backrest.physical_value.toFixed(1)}°`;
$("#calibrationTagHeight").textContent = `${height.physical_value.toFixed(2)} cm`;
[
["longitudinal", longitudinal],
["legrest", legrest],
["backrest", backrest],
["height", height],
].forEach(([name, axis]) => {
const label = $(`[data-seat-axis-label="${name}"]`);
if (!label) return;
label.setAttribute("aria-valuenow", String(Math.round(axis.permille)));
label.setAttribute("aria-valuetext", formatPhysical(axis, axis.permille));
});
}
function previewSeatAxis(event) {
if (!currentState?.axes?.length) return;
const viewer = $("#calibrationSeatViewer");
if (viewer?.dataset.axisControlEnabled !== "true") return;
const axisId = Number(event.detail?.axis);
const permille = Math.max(0, Math.min(1000, Number(event.detail?.permille)));
if (!Number.isInteger(axisId) || !Number.isFinite(permille)) return;
const axes = currentState.axes.map((axis) => ({ ...axis }));
const axis = axes.find((item) => item.id === axisId);
if (!axis) return;
axis.permille = permille;
axis.physical_value = axis.physical_range * permille / 1000;
const card = $(`.v2-calibration-axis-card[data-axis="${axisId}"]`);
if (card) {
const slider = $('input[type="range"]', card);
slider.value = String(permille);
$(".v2-calibration-axis-reading strong", card).textContent = formatPhysical(axis, permille);
}
renderSeat(axes);
}
function commitSeatAxis(event) {
const viewer = $("#calibrationSeatViewer");
if (viewer?.dataset.axisControlEnabled !== "true") return;
const axis = Number(event.detail?.axis);
const permille = Math.max(0, Math.min(1000, Math.round(Number(event.detail?.permille))));
if (!Number.isInteger(axis) || !Number.isFinite(permille)) return;
run(() => api("/move", { axis, permille }));
}
function renderVideo(video) {
@@ -542,7 +600,13 @@
closeEvents();
return;
}
fetchState().catch((error) => toast(`自标定服务连接失败:${error.message}`, true));
fetchState().then(async (state) => {
if (bootstrapResetComplete) return;
bootstrapResetComplete = true;
if (state.transport?.mode === "simulation") {
await api("/session/reset");
}
}).catch((error) => toast(`自标定服务连接失败:${error.message}`, true));
connectEvents();
}
@@ -583,6 +647,8 @@
});
window.addEventListener("cognitive-agent:module-change", activate);
window.addEventListener("cognitive-agent:demo-role-change", activate);
window.addEventListener("calibration-seat-axis-preview", previewSeatAxis);
window.addEventListener("calibration-seat-axis-commit", commitSeatAxis);
window.addEventListener("beforeunload", closeEvents);
}