Files
vd_test_fixture/edc-web/app/static/js/test_op.js

376 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 测试操作页 — 间隔/超时机制
let autoRunning = false;
let autoTotal = 0;
let autoDone = 0;
let autoFailed = 0;
let autoRemaining = 0;
let autoStartTime = "";
let localSinceStr = "";
let pollInterval = null;
let nextCmdTimer = null; // 间隔等待定时器
let timeoutTimer = null; // 超时定时器
let timeoutAt = 0; // 超时时刻 (Date.now() + timeoutMs)
let lastDoneCount = 0; // 上一轮 done 数,检测新响应
let cmdSentAt = 0; // 最近一次发送 0xB0 时间
let intervalMs = 10000; // 默认 10s
let timeoutMs = 5000; // 默认 5s
// ─── 手动指令 ─────────────────────────────────
async function sendCmd(cmd) {
try {
const resp = await fetch("/api/command", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ dnt_id: DNT_ID, cmd }),
});
const data = await resp.json();
if (data.ok) {
console.log(`指令 ${cmd} 已下发: ${data.send_pkg}`);
}
} catch (e) {
alert("发送失败: " + e.message);
}
}
// ─── 自动化 ────────────────────────────────────
async function toggleAuto() {
if (!autoRunning) {
await startAuto();
} else {
stopAuto();
}
}
async function startAuto() {
const count = parseInt(document.getElementById("test-count").value) || 10;
if (count < 1) return;
// 读取参数
intervalMs = (parseFloat(document.getElementById("interval-sec").value) || 3) * 1000;
timeoutMs = (parseFloat(document.getElementById("timeout-sec").value) || 10) * 1000;
if (timeoutMs < 1000) timeoutMs = 1000;
// 重置
autoRunning = true;
autoTotal = count;
autoDone = 0;
autoFailed = 0;
autoRemaining = count;
lastDoneCount = 0;
autoStartTime = new Date().toISOString();
const now = new Date();
localSinceStr = now.getFullYear() + "-" +
String(now.getMonth() + 1).padStart(2, "0") + "-" +
String(now.getDate()).padStart(2, "0") + " " +
String(now.getHours()).padStart(2, "0") + ":" +
String(now.getMinutes()).padStart(2, "0") + ":" +
String(now.getSeconds()).padStart(2, "0");
// 显示开始时间
document.getElementById("auto-time").style.display = "block";
document.getElementById("time-start").textContent = new Date().toLocaleString();
document.getElementById("time-end").textContent = "-";
// 清空显示
resetAverages();
document.getElementById("latest-result").innerHTML = '<p class="placeholder">等待测试...</p>';
document.getElementById("latest-wave").innerHTML = '<p class="placeholder">暂无波动数据...</p>';
document.getElementById("progress-bar").style.width = "0%";
document.getElementById("progress-text").textContent = "0/" + count + " (0 失败)";
document.getElementById("stat-done").textContent = "0";
document.getElementById("stat-failed").textContent = "0";
document.getElementById("stat-remaining").textContent = count;
document.getElementById("auto-status").textContent = "";
document.querySelector("#records-table tbody").innerHTML = "";
document.getElementById("records-empty").style.display = "block";
const btn = document.getElementById("btn-auto");
btn.textContent = "结束";
btn.className = "btn-stop";
// 清除旧记录 + 插入第一条
try {
const resp = await fetch("/api/automation/start", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ dnt_id: DNT_ID, count }),
});
const data = await resp.json();
if (data.ok) {
cmdSentAt = Date.now();
timeoutAt = cmdSentAt + timeoutMs;
armTimeout();
setStatus(`已发送,超时 ${timeoutMs/1000}s...`);
}
} catch (e) {
console.error("启动失败:", e);
stopAuto();
}
// 启动轮询
pollInterval = setInterval(pollProgress, 500);
}
function stopAuto() {
autoRunning = false;
clearInterval(pollInterval);
pollInterval = null;
clearTimeout(nextCmdTimer);
nextCmdTimer = null;
clearTimeout(timeoutTimer);
timeoutTimer = null;
document.getElementById("auto-status").textContent = "";
document.getElementById("time-end").textContent = new Date().toLocaleString();
const btn = document.getElementById("btn-auto");
btn.textContent = "开始";
btn.className = "btn-start";
}
// ─── 发送下一条 0xB0 ────────────────────────────
async function sendNextCmd() {
if (!autoRunning) return;
if (autoRemaining <= 0) {
// 检查是否还有等待完成的
if (autoDone + autoFailed >= autoTotal) {
stopAuto();
return;
}
}
try {
const r = await fetch("/api/command", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ dnt_id: DNT_ID, cmd: "B0" }),
});
const rd = await r.json();
if (rd.ok) {
cmdSentAt = Date.now();
timeoutAt = cmdSentAt + timeoutMs;
armTimeout();
setStatus(`已发送,超时 ${timeoutMs/1000}s...`);
}
} catch (e) {
console.error("发送下一条失败:", e);
}
}
// ─── 超时定时器 ─────────────────────────────────
function armTimeout() {
clearTimeout(timeoutTimer);
timeoutTimer = setTimeout(onTimeout, timeoutMs + 500); // +500ms 容差
}
function onTimeout() {
if (!autoRunning) return;
// 超时:即使没收到回复也计数失败,立即发下一条
autoFailed++;
autoRemaining = autoTotal - autoDone - autoFailed;
if (autoRemaining < 0) autoRemaining = 0;
updateUI();
setStatus(`超时!立即发下一条...`);
console.log(`超时 (${timeoutMs}ms),失败数: ${autoFailed}`);
clearTimeout(nextCmdTimer);
nextCmdTimer = null;
if (autoRemaining > 0) {
sendNextCmd();
} else {
stopAuto();
}
}
// ─── 轮询 ──────────────────────────────────────
async function pollProgress() {
if (!autoRunning) return;
try {
const resp = await fetch(`/api/automation/${DNT_ID}/progress?since=${encodeURIComponent(localSinceStr)}`);
const data = await resp.json();
const stats = data.stats;
// 更新计数
const newDone = stats.done || 0;
const newFailed = stats.failed || 0;
if (newDone > lastDoneCount) {
// 收到新回复 → 清除超时,开始间隔等待
const delta = newDone - lastDoneCount;
lastDoneCount = newDone;
autoDone = newDone;
autoFailed = newFailed;
autoRemaining = autoTotal - autoDone - autoFailed;
if (autoRemaining < 0) autoRemaining = 0;
clearTimeout(timeoutTimer);
timeoutTimer = null;
clearTimeout(nextCmdTimer);
nextCmdTimer = null;
updateUI();
if (autoRemaining > 0) {
const wait = (intervalMs / 1000).toFixed(0);
setStatus(`收到 ${delta} 条回复,等待 ${wait}s...`);
nextCmdTimer = setTimeout(() => {
setStatus("发送中...");
sendNextCmd();
}, intervalMs);
} else {
setStatus("全部完成");
stopAuto();
return;
}
} else {
// 没有新回复,更新超时计数
autoFailed = newFailed;
autoRemaining = autoTotal - autoDone - autoFailed;
if (autoRemaining < 0) autoRemaining = 0;
// 检查是否全部完成
if (autoRemaining <= 0 && autoDone + autoFailed >= autoTotal) {
stopAuto();
return;
}
}
// 显示最新结果
if (data.latest) renderLatest(data.latest);
if (data.averages) renderAverages(data.averages);
if (data.latest_wave) renderLatestWave(data.latest_wave);
if (data.records) renderRecords(data.records);
} catch (e) {
console.error("轮询失败:", e);
}
}
// ─── UI ────────────────────────────────────────
function setStatus(msg) {
document.getElementById("auto-status").textContent = msg;
}
function updateUI() {
document.getElementById("stat-done").textContent = autoDone;
document.getElementById("stat-failed").textContent = autoFailed;
document.getElementById("stat-remaining").textContent = autoRemaining;
const total = autoTotal || 1;
const pct = Math.round((autoDone / total) * 100);
document.getElementById("progress-bar").style.width = pct + "%";
document.getElementById("progress-text").textContent =
`${autoDone}/${autoTotal} (${autoFailed} 失败)`;
}
function toSpeed(v) {
if (v === null || v === undefined || v === '') return '-';
return (parseFloat(v) / 10).toFixed(1);
}
function fmtTime(v) {
if (!v) return '-';
return String(v).replace('T', ' ').replace(/\.\d+/, '').substring(0, 19);
}
// ─── 显示最新结果 ──────────────────────────────
function renderLatest(data) {
const div = document.getElementById("latest-result");
div.innerHTML = `
<p>设备型号:<strong>${data.str_type || '-'}</strong></p>
<p>测试模式:<strong>${data.test_mode === 1 ? '波动测试' : '灵敏度测试'}</strong></p>
<p>峰峰值:${data.ppvalue?.toFixed(2) || '-'} V</p>
<p>开始工作频率:${data.idle_freq || '-'} Hz</p>
<p>进入工作频率:${data.enter_freq || '-'} Hz</p>
<p>离开工作频率:${data.exit_freq || '-'} Hz</p>
<p>进入距离:${data.enter_dist || '-'} mm</p>
<p>离开距离:${data.exit_dist || '-'} mm</p>
<p>进入速度:${toSpeed(data.enter_speed)} m/s</p>
<p>离开速度:${toSpeed(data.exit_speed)} m/s</p>
<p>是否完成:${data.iffinish === '1' ? '是' : '否'}</p>
<p>故障信息:${data.fault_info || '无'}</p>
<p>时间:${fmtTime(data.create_time)}</p>
`;
}
// ─── 显示平均值 ────────────────────────────────
function renderAverages(data) {
document.getElementById("avg-ppvalue").textContent = data.avg_ppvalue || "-";
document.getElementById("avg-idle-freq").textContent = data.avg_idle_freq || "-";
document.getElementById("avg-enter-freq").textContent = data.avg_enter_freq || "-";
document.getElementById("avg-enter-dist").textContent = data.avg_enter_dist || "-";
document.getElementById("avg-exit-dist").textContent = data.avg_exit_dist || "-";
document.getElementById("avg-enter-speed").textContent = data.avg_enter_speed || "-";
document.getElementById("avg-exit-speed").textContent = data.avg_exit_speed || "-";
}
function resetAverages() {
["ppvalue", "idle-freq", "enter-freq", "enter-dist", "exit-dist",
"enter-speed", "exit-speed"].forEach(id => {
document.getElementById("avg-" + id).textContent = "-";
});
}
// ─── 显示波动测试数据 ──────────────────────────
function renderLatestWave(data) {
const div = document.getElementById("latest-wave");
if (!data || !data.work_freq) {
div.innerHTML = '<p class="placeholder">暂无波动数据...</p>';
return;
}
div.innerHTML = `
<p>剩余次数:<strong>${data.remain_count || 0}</strong></p>
<p>工作频率:${data.work_freq || '-'} Hz</p>
<p>当前距离:${data.curr_dist || '-'} mm</p>
<p>当前速度:${toSpeed(data.speed)} m/s</p>
<p>最近距离:${data.near_dist || '-'} mm</p>
<p>最远距离:${data.far_dist || '-'} mm</p>
<p>进入高度 (B4)${data.b4_enter_dist || '-'} mm</p>
<p>离开高度 (B4)${data.b4_leave_dist || '-'} mm</p>
<p>继电器:${data.relay_out || '无'}</p>
<p>时间:${fmtTime(data.create_time)}</p>
`;
}
// ─── 显示本轮测试明细 ──────────────────────────
function renderRecords(records) {
if (!records || !records.length) {
document.getElementById("records-empty").style.display = "block";
document.getElementById("records-table").style.display = "none";
return;
}
document.getElementById("records-empty").style.display = "none";
document.getElementById("records-table").style.display = "";
const tbody = document.querySelector("#records-table tbody");
tbody.innerHTML = records.map((r, i) => `
<tr>
<td>${i + 1}</td>
<td style="color:${r.sn_state === 2 ? '#27ae60' : r.sn_state === 3 ? '#e74c3c' : '#888'}">
${r.sn_state === 2 ? 'OK' : r.sn_state === 3 ? '超时' : '?'}
</td>
<td>${r.test_mode === 1 ? '波动' : '灵敏度'}</td>
<td>${r.ppvalue?.toFixed(2) || '-'}</td>
<td>${r.idle_freq || '-'}</td>
<td>${r.enter_dist || '-'}</td>
<td>${r.exit_dist || '-'}</td>
<td>${toSpeed(r.enter_speed)}</td>
<td>${fmtTime(r.create_time)}</td>
</tr>
`).join("");
}