Compare commits
7 Commits
aa2815b5cc
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0ec79ca2f | ||
|
|
4b082e35df | ||
|
|
521cbe4107 | ||
|
|
4ac6cbb2fe | ||
|
|
0dfb928375 | ||
|
|
366c7f909a | ||
|
|
b4b7387b39 |
68
docs/reports/weekly-2026-06-12.md
Normal file
68
docs/reports/weekly-2026-06-12.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 周报 — 2026.06.09 ~ 2026.06.12
|
||||
|
||||
## 一、设备型号动态管理
|
||||
|
||||
**问题**:车检器型号名称(如 DLD110SV)在代码中硬编码,新增型号后测试操作页显示 `Unknown(3)` 或 `0x03`,测试信息页型号列显示 `-`。
|
||||
|
||||
**修复**:
|
||||
- **后端** `edc_server`:B2/B4 数据写入时,废弃硬编码 `{1:"PD132",2:"DLD110"}` 映射,改为查询 `tb_vechicle_base_test` 表获取 `type_num → dev_name`,带内存缓存避免高频 DB 查询。
|
||||
- **前端** `edc-web`:
|
||||
- `test_op.js` 工装配置概览面板、最新测试结果区域,从 `/api/vehicle-base-test` 动态获取型号映射。
|
||||
- `test_data.js` 测试信息页型号列,同样改为动态查询。
|
||||
- 每 5 秒自动刷新型号缓存,工装配置页新增型号后无需手动刷新。
|
||||
|
||||
## 二、测试操作页实时数据改进
|
||||
|
||||
**问题**:
|
||||
1. 工装本地按键触发的测试数据上报后,网页端无法实时显示,必须依赖网页端"开始"按钮。
|
||||
2. 数据轮询间隔偏长(5 秒),新记录无计数提示。
|
||||
|
||||
**实现**:
|
||||
- 新增被动轮询机制,**每 3 秒**自动拉取最新测试数据,覆盖工装本地按键和网页手动指令两种触发方式。
|
||||
- 自动化测试运行期间,被动轮询自动让位给 `pollProgress`(500ms 高频轮询),结束后无缝接回。
|
||||
- 「当前测试数据」标题旁新增 **B2 新记录条数**显示 `(N 条新记录)`,页面加载/自动化开始时自动复位。
|
||||
|
||||
## 三、角色权限体系
|
||||
|
||||
| 角色 | 权限 |
|
||||
|---|---|
|
||||
| `admin` | 全部功能(含用户管理、删除数据) |
|
||||
| `manager` | 管理功能(用户管理除外)— 工装配置、数据删除等 |
|
||||
| `analyst` | 仅测试数据查询/下载 + 修改密码 |
|
||||
| `operator` | 测试操作 + 测试数据查看(不含工装配置) |
|
||||
|
||||
- `analyst` 角色访问受限页面时自动跳转到测试数据页并提示。
|
||||
- 所有用户可自行修改密码。
|
||||
|
||||
## 四、设备日志管理
|
||||
|
||||
- 新增设备日志管理页面,记录设备 TCP 连接/断开、异常事件。
|
||||
- 支持按设备编码、事件类型、时间范围筛选。
|
||||
- 支持 **CSV 导出**,修复时区偏移 8 小时问题。
|
||||
- 设备列表页在线/离线状态每 5 秒实时刷新。
|
||||
- 后端 `device_status_monitor` 增加全表扫描,修正状态不一致问题。
|
||||
|
||||
## 五、UI/UX 优化
|
||||
|
||||
- **继电器输出格式化**:明确区分"✅有输出"/"❌无输出",前端直接显示 DB 字段。
|
||||
- **工装配置概览面板**:测试操作页顶部展示当前配置参数(型号、频率范围、线圈、车辆等),可折叠。
|
||||
- **测试信息页重构**:
|
||||
- 三视图切换(全部数据 / B2 灵敏度 / B4 波动),差异字段自动隐藏。
|
||||
- 表格支持横向滚动,列宽自适应不换行。
|
||||
- 故障信息列限制 12em 宽度,超长截断省略 + hover 显示全文。
|
||||
- 配置页频率/峰峰值前端显示与 DB 原始值双向转换修复。
|
||||
|
||||
## 六、Bug 修复
|
||||
|
||||
| 问题 | 修复 |
|
||||
|---|---|
|
||||
| 浏览器缓存导致工装参数 GET 返回旧数据 | 响应头 `Cache-Control: no-store` |
|
||||
| `renderLatest` 覆盖测试模式,灵敏度/波动显示回退 | 分离测试模式更新与数据渲染逻辑 |
|
||||
| 测试操作页工装配置修改后不同步 | 每 5 秒刷新 + 禁用缓存 |
|
||||
| 设备离线时仍可发送指令 | 在线状态检查,离线/通信不良时弹窗提示并阻止 |
|
||||
| HeartBeat 大小写不匹配,交互未记录 | 统一大小写匹配 |
|
||||
| 后端 `device_status_monitor` 状态不一致 | 增加 `dnt_info` 全表扫描修正 |
|
||||
|
||||
---
|
||||
|
||||
**总计提交**:vd_test_fixture 24 次,edc_server 8 次。
|
||||
@@ -942,3 +942,21 @@ def delete_device_logs(serial: str = "", event_type: str = "",
|
||||
return cnt
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
# ─── tb_pending_detector ───────────────────────────────────────────
|
||||
|
||||
def set_pending_detector_serial(dnt_id: int, detector_serial: str):
|
||||
"""设置待插入的车检器序列号(UPSERT)"""
|
||||
conn = get_conn()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""INSERT INTO tb_pending_detector (dnt_id, detector_serial)
|
||||
VALUES (%s, %s)
|
||||
ON DUPLICATE KEY UPDATE detector_serial = VALUES(detector_serial)""",
|
||||
(dnt_id, detector_serial),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
@@ -13,6 +13,7 @@ from app.models import (
|
||||
get_wave_records,
|
||||
clear_serialnet_records,
|
||||
insert_log,
|
||||
set_pending_detector_serial,
|
||||
)
|
||||
|
||||
bp = Blueprint("test_op", __name__)
|
||||
@@ -89,10 +90,15 @@ def api_automation_start():
|
||||
data = request.get_json()
|
||||
dnt_id = data.get("dnt_id")
|
||||
count = int(data.get("count", 1))
|
||||
detector_serial = (data.get("detector_serial") or "").strip()
|
||||
|
||||
device = get_device_by_id(dnt_id)
|
||||
target = f"{device['serial']}" if device else f"dnt_id={dnt_id}"
|
||||
|
||||
# 存储待插入的车检器序列号
|
||||
if detector_serial:
|
||||
set_pending_detector_serial(dnt_id, detector_serial)
|
||||
|
||||
# 清除旧记录,然后插入第一条 0xB0
|
||||
clear_serialnet_records(dnt_id)
|
||||
record_id = insert_serialnet(dnt_id, COMMANDS["B0"])
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
// 测试信息页 — 三视图 (全部 / B2 / B4)
|
||||
|
||||
// ─── 型号名称缓存 ─────────────────────────────────
|
||||
let devTypeNameCache = {};
|
||||
|
||||
async function initDevTypeNames() {
|
||||
try {
|
||||
const resp = await fetch('/api/vehicle-base-test');
|
||||
const tests = await resp.json();
|
||||
devTypeNameCache = {};
|
||||
tests.forEach(t => {
|
||||
if (t.type_num != null && t.dev_name) {
|
||||
devTypeNameCache[t.type_num] = t.dev_name;
|
||||
}
|
||||
});
|
||||
} catch (e) { console.error('加载型号名称失败:', e); }
|
||||
}
|
||||
|
||||
function getDevTypeName(subType) {
|
||||
if (subType == null || subType === 0) return '-';
|
||||
return devTypeNameCache[subType] || `Unknown(${subType})`;
|
||||
}
|
||||
|
||||
// ─── 视图定义 ───────────────────────────────────
|
||||
|
||||
const VIEWS = {
|
||||
@@ -9,7 +30,8 @@ const VIEWS = {
|
||||
cols: [
|
||||
{ key: 'id', title: 'ID' },
|
||||
{ key: 'serial', title: '设备编码' },
|
||||
{ key: 'model', title: '型号', render: r => r.sub_type === 1 ? 'PD132' : r.sub_type === 2 ? 'DLD110' : '-' },
|
||||
{ key: 'detector_serial', title: '车检器序列号', render: r => r.detector_serial || '-' },
|
||||
{ key: 'model', title: '型号', render: r => getDevTypeName(r.sub_type) },
|
||||
{ key: 'data_source', title: '来源' },
|
||||
{ key: 'test_mode', title: '测试模式', render: r => r.test_mode === 1 ? '波动' : '灵敏度' },
|
||||
{ key: 'iffinish', title: '完成', render: r => r.data_source === 'B4' ? '-' : (r.iffinish === '1' ? '是' : '否') },
|
||||
@@ -17,8 +39,8 @@ const VIEWS = {
|
||||
{ key: 'relay_out', title: '继电器', render: r => fmtRelay(r.relay_out) },
|
||||
{ key: 'ppvalue', title: '峰峰值(V)', render: r => r.data_source === 'B4' ? '-' : (r.ppvalue != null ? r.ppvalue.toFixed(2) : '-') },
|
||||
{ key: 'idle_freq', title: '开始频率(Hz)', render: r => r.data_source === 'B4' ? '-' : (r.idle_freq || '-') },
|
||||
{ key: 'enter_freq', title: '进入频率(Hz)', render: r => r.data_source === 'B4' ? '-' : (r.enter_freq || '-') },
|
||||
{ key: 'exit_freq', title: '离开频率(Hz)', render: r => r.data_source === 'B4' ? '-' : (r.exit_freq || '-') },
|
||||
{ key: 'enter_freq', title: '触发频率(Hz)', render: r => r.data_source === 'B4' ? '-' : (r.enter_freq || '-') },
|
||||
{ key: 'exit_freq', title: '释放频率(Hz)', render: r => r.data_source === 'B4' ? '-' : (r.exit_freq || '-') },
|
||||
{ key: 'enter_dist', title: '触发距离(mm)', render: r => {
|
||||
const v = r.data_source === 'B4' ? r.b4_enter_dist : r.enter_dist;
|
||||
return v != null ? v + ' ' : '-';
|
||||
@@ -27,8 +49,8 @@ const VIEWS = {
|
||||
const v = r.data_source === 'B4' ? r.b4_leave_dist : r.exit_dist;
|
||||
return v != null ? v + ' ' : '-';
|
||||
}},
|
||||
{ key: 'enter_speed', title: '进入速度(dm/s)', render: r => r.data_source === 'B4' ? '-' : toSpeed(r.enter_speed) },
|
||||
{ key: 'exit_speed', title: '离开速度(dm/s)', render: r => r.data_source === 'B4' ? '-' : toSpeed(r.exit_speed) },
|
||||
{ key: 'enter_speed', title: '触发速度(dm/s)', render: r => r.data_source === 'B4' ? '-' : toSpeed(r.enter_speed) },
|
||||
{ key: 'exit_speed', title: '释放速度(dm/s)', render: r => r.data_source === 'B4' ? '-' : toSpeed(r.exit_speed) },
|
||||
{ key: 'remain_count', title: '剩余次数', render: r => r.data_source === 'B2' ? '-' : (r.remain_count ?? '-') },
|
||||
{ key: 'work_freq', title: '工作频率(Hz)', render: r => r.data_source === 'B2' ? '-' : (r.work_freq ?? '-') },
|
||||
{ key: 'curr_dist', title: '当前距离(mm)', render: r => r.data_source === 'B2' ? '-' : (r.curr_dist != null ? r.curr_dist + ' ' : '-') },
|
||||
@@ -45,19 +67,20 @@ const VIEWS = {
|
||||
cols: [
|
||||
{ key: 'id', title: 'ID' },
|
||||
{ key: 'serial', title: '设备编码' },
|
||||
{ key: 'model', title: '型号', render: r => r.sub_type === 1 ? 'PD132' : r.sub_type === 2 ? 'DLD110' : '-' },
|
||||
{ key: 'detector_serial', title: '车检器序列号', render: r => r.detector_serial || '-' },
|
||||
{ key: 'model', title: '型号', render: r => getDevTypeName(r.sub_type) },
|
||||
{ key: 'test_mode', title: '测试模式', render: r => r.test_mode === 1 ? '波动' : '灵敏度' },
|
||||
{ key: 'iffinish', title: '完成', render: r => r.iffinish === '1' ? '是' : '否' },
|
||||
{ key: 'fault_info', title: '故障信息', render: r => `<span style="display:inline-block;max-width:12em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${escHtml(r.fault_info || '')}">${escHtml(r.fault_info || '-')}</span>` },
|
||||
{ key: 'relay_out', title: '继电器', render: r => fmtRelay(r.relay_out) },
|
||||
{ key: 'ppvalue', title: '峰峰值(V)', render: r => r.ppvalue?.toFixed(2) || '-' },
|
||||
{ key: 'idle_freq', title: '开始频率(Hz)' },
|
||||
{ key: 'enter_freq', title: '进入频率(Hz)' },
|
||||
{ key: 'exit_freq', title: '离开频率(Hz)' },
|
||||
{ key: 'enter_freq', title: '触发频率(Hz)' },
|
||||
{ key: 'exit_freq', title: '释放频率(Hz)' },
|
||||
{ key: 'enter_dist', title: '触发距离(mm)' },
|
||||
{ key: 'exit_dist', title: '释放距离(mm)' },
|
||||
{ key: 'enter_speed', title: '进入速度', render: r => toSpeed(r.enter_speed) },
|
||||
{ key: 'exit_speed', title: '离开速度', render: r => toSpeed(r.exit_speed) },
|
||||
{ key: 'enter_speed', title: '触发速度', render: r => toSpeed(r.enter_speed) },
|
||||
{ key: 'exit_speed', title: '释放速度', render: r => toSpeed(r.exit_speed) },
|
||||
{ key: 'env', title: '测试环境', render: r => envLabel(r) },
|
||||
{ key: 'create_time', title: '时间', render: r => fmtTime(r.create_time) },
|
||||
],
|
||||
@@ -68,6 +91,7 @@ const VIEWS = {
|
||||
cols: [
|
||||
{ key: 'id', title: 'ID' },
|
||||
{ key: 'serial', title: '设备编码' },
|
||||
{ key: 'detector_serial', title: '车检器序列号', render: r => r.detector_serial || '-' },
|
||||
{ key: 'remain_count', title: '剩余次数' },
|
||||
{ key: 'work_freq', title: '工作频率(Hz)' },
|
||||
{ key: 'curr_dist', title: '当前距离(mm)' },
|
||||
@@ -270,12 +294,12 @@ const CHART_SERIES = {
|
||||
b2: [
|
||||
{ key: 'ppvalue', name: '峰峰值', unit: 'V', yAxisIndex: 0 },
|
||||
{ key: 'idle_freq', name: '开始频率', unit: 'Hz', yAxisIndex: 0 },
|
||||
{ key: 'enter_freq', name: '进入频率', unit: 'Hz', yAxisIndex: 0 },
|
||||
{ key: 'exit_freq', name: '离开频率', unit: 'Hz', yAxisIndex: 0 },
|
||||
{ key: 'enter_dist', name: '进入距离', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'exit_dist', name: '离开距离', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'enter_speed', name: '进入速度', unit: 'dm/s',yAxisIndex: 2 },
|
||||
{ key: 'exit_speed', name: '离开速度', unit: 'dm/s',yAxisIndex: 2 },
|
||||
{ key: 'enter_freq', name: '触发频率', unit: 'Hz', yAxisIndex: 0 },
|
||||
{ key: 'exit_freq', name: '释放频率', unit: 'Hz', yAxisIndex: 0 },
|
||||
{ key: 'enter_dist', name: '触发距离', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'exit_dist', name: '释放距离', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'enter_speed', name: '触发速度', unit: 'dm/s',yAxisIndex: 2 },
|
||||
{ key: 'exit_speed', name: '释放速度', unit: 'dm/s',yAxisIndex: 2 },
|
||||
],
|
||||
b4: [
|
||||
{ key: 'work_freq', name: '工作频率', unit: 'Hz', yAxisIndex: 0 },
|
||||
@@ -283,8 +307,8 @@ const CHART_SERIES = {
|
||||
{ key: 'speed', name: '速度', unit: 'dm/s',yAxisIndex: 2 },
|
||||
{ key: 'near_dist', name: '最近距离', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'far_dist', name: '最远距离', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'b4_enter_dist', name: '进入高度', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'b4_leave_dist', name: '离开高度', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'b4_enter_dist', name: '触发高度', unit: 'mm', yAxisIndex: 1 },
|
||||
{ key: 'b4_leave_dist', name: '释放高度', unit: 'mm', yAxisIndex: 1 },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -457,7 +481,8 @@ async function loadChart() {
|
||||
// ─── 初始加载 ────────────────────────────────────
|
||||
|
||||
renderHead();
|
||||
searchData(1);
|
||||
// 先加载型号名称再查询数据,确保型号列正确渲染
|
||||
initDevTypeNames().then(() => searchData(1));
|
||||
|
||||
// ─── 删除(admin)─────────────────────────────────
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ let autoStartTime = "";
|
||||
let localSinceStr = "";
|
||||
let currentTestMode = null; // 0=灵敏度, 1=波动, null=未加载
|
||||
let currentDeviceState = null; // 当前设备状态 (0=离线 1=在线 2=通信不良 null=未加载)
|
||||
let devTypeNameCache = {}; // type_num → dev_name 映射(从 tb_vechicle_base_test)
|
||||
|
||||
let pollInterval = null;
|
||||
let nextCmdTimer = null; // 间隔等待定时器
|
||||
@@ -62,9 +63,12 @@ async function toggleAuto() {
|
||||
|
||||
async function startAuto() {
|
||||
if (!checkDeviceOnline()) return;
|
||||
const count = parseInt(document.getElementById("test-count").value) || 10;
|
||||
const count = parseInt(document.getElementById("test-count").value) || 1;
|
||||
if (count < 1) return;
|
||||
|
||||
// 读取车检器序列号
|
||||
const detectorSerial = document.getElementById("detector-serial").value.trim();
|
||||
|
||||
// 读取参数
|
||||
intervalMs = (parseFloat(document.getElementById("interval-sec").value) || 3) * 1000;
|
||||
timeoutMs = (parseFloat(document.getElementById("timeout-sec").value) || 10) * 1000;
|
||||
@@ -77,6 +81,8 @@ async function startAuto() {
|
||||
autoFailed = 0;
|
||||
autoRemaining = count;
|
||||
lastDoneCount = 0;
|
||||
newB2Count = 0;
|
||||
updateRecordCount();
|
||||
autoStartTime = new Date().toISOString();
|
||||
|
||||
const now = new Date();
|
||||
@@ -115,7 +121,7 @@ async function startAuto() {
|
||||
const resp = await fetch("/api/automation/start", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ dnt_id: DNT_ID, count }),
|
||||
body: JSON.stringify({ dnt_id: DNT_ID, count, detector_serial: detectorSerial }),
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.ok) {
|
||||
@@ -147,6 +153,9 @@ function stopAuto() {
|
||||
const btn = document.getElementById("btn-auto");
|
||||
btn.textContent = "开始";
|
||||
btn.className = "btn-start";
|
||||
|
||||
// 自动化结束 → 焦点回到车检器序列号输入框(全选),方便下一个车检器测试
|
||||
setTimeout(focusDetectorSerial, 100);
|
||||
}
|
||||
|
||||
// ─── 发送下一条 0xB0 ────────────────────────────
|
||||
@@ -217,9 +226,15 @@ async function pollProgress() {
|
||||
const stats = data.stats;
|
||||
|
||||
// ── 先渲染数据(放在所有 return 之前,避免完成时跳过渲染)──
|
||||
try { if (data.latest) renderLatest(data.latest); } catch (e) { console.error("renderLatest:", e); }
|
||||
try { if (data.latest) {
|
||||
if (data.latest.id !== lastLatestId) {
|
||||
lastLatestId = data.latest.id;
|
||||
if (data.latest.data_source === "B2") { newB2Count++; updateRecordCount(); }
|
||||
}
|
||||
renderLatest(data.latest);
|
||||
} } catch (e) { console.error("renderLatest:", e); }
|
||||
try { if (data.averages) renderAverages(data.averages); } catch (e) { console.error("renderAverages:", e); }
|
||||
try { if (data.latest_wave) renderLatestWave(data.latest_wave); } catch (e) { console.error("renderLatestWave:", e); }
|
||||
try { if (data.latest_wave) { renderLatestWave(data.latest_wave); lastWaveId = data.latest_wave.id; } } catch (e) { console.error("renderLatestWave:", e); }
|
||||
try { if (data.records && data.records.length) renderRecords(data.records); } catch (e) { console.error("renderRecords:", e); }
|
||||
|
||||
// 更新计数
|
||||
@@ -273,6 +288,19 @@ async function pollProgress() {
|
||||
|
||||
// ─── 页面加载时获取初始数据 ──────────────────────
|
||||
|
||||
async function loadDeviceTypeNames() {
|
||||
try {
|
||||
const resp = await fetch(`/api/vehicle-base-test`);
|
||||
const tests = await resp.json();
|
||||
devTypeNameCache = {};
|
||||
tests.forEach(t => {
|
||||
if (t.type_num != null && t.dev_name) {
|
||||
devTypeNameCache[t.type_num] = t.dev_name;
|
||||
}
|
||||
});
|
||||
} catch (e) { console.error("加载型号名称失败:", e); }
|
||||
}
|
||||
|
||||
async function loadTestMode() {
|
||||
try {
|
||||
const resp = await fetch(`/api/fixture/param/${DNT_ID}?_=${Date.now()}`);
|
||||
@@ -315,8 +343,8 @@ function renderConfigOverview(param) {
|
||||
}
|
||||
|
||||
// 型号
|
||||
const devTypeMap = {0: '未知', 1: 'PD132', 2: 'DLD110'};
|
||||
document.getElementById("cfg-dev-type").textContent = devTypeMap[param.DevType] || `0x${(param.DevType||0).toString(16)}`;
|
||||
document.getElementById("cfg-dev-type").textContent =
|
||||
devTypeNameCache[param.DevType] || `0x${(param.DevType || 0).toString(16)}`;
|
||||
|
||||
// 距离 (DB cm → 显示 mm)
|
||||
document.getElementById("cfg-reset-dis").textContent = param.RestDis != null ? param.RestDis * 10 : '-';
|
||||
@@ -369,19 +397,50 @@ function toggleConfig() {
|
||||
}
|
||||
|
||||
async function loadInitialData() {
|
||||
await loadDeviceTypeNames();
|
||||
await loadTestMode();
|
||||
refreshDeviceStatus();
|
||||
newB2Count = 0;
|
||||
updateRecordCount();
|
||||
try {
|
||||
const resp = await fetch(`/api/automation/${DNT_ID}/progress`);
|
||||
const data = await resp.json();
|
||||
if (data.latest) renderLatest(data.latest);
|
||||
if (data.latest_wave) renderLatestWave(data.latest_wave);
|
||||
if (data.latest) { renderLatest(data.latest); lastLatestId = data.latest.id; }
|
||||
if (data.latest_wave) { renderLatestWave(data.latest_wave); lastWaveId = data.latest_wave.id; }
|
||||
} catch (e) {
|
||||
// 初始加载静默失败
|
||||
}
|
||||
// 页面加载后焦点落到车检器序列号输入框(全选)
|
||||
setTimeout(focusDetectorSerial, 200);
|
||||
}
|
||||
loadInitialData();
|
||||
|
||||
// ─── 回车键触发"开始"按钮 ─────────────────────
|
||||
|
||||
/** 将焦点移到车检器序列号输入框并全选已有文本 */
|
||||
function focusDetectorSerial() {
|
||||
const input = document.getElementById("detector-serial");
|
||||
if (input) {
|
||||
input.focus();
|
||||
input.select();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const detectorInput = document.getElementById("detector-serial");
|
||||
if (detectorInput) {
|
||||
detectorInput.addEventListener("keydown", function(e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
const btn = document.getElementById("btn-auto");
|
||||
if (btn && !autoRunning) {
|
||||
btn.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ─── 设备状态异步刷新 ──────────────────────────
|
||||
|
||||
async function refreshDeviceStatus() {
|
||||
@@ -407,8 +466,45 @@ async function refreshDeviceStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
// 每 5 秒刷新设备状态 + 测试模式(工装页修改后能及时同步)
|
||||
// ─── 被动轮询:实时显示上报数据(工装本地按键 / 网页手动指令触发)───
|
||||
|
||||
let lastLatestId = 0; // 最新测试数据 ID,用于判断是否有新数据
|
||||
let lastWaveId = 0; // 最新波动数据 ID
|
||||
let newB2Count = 0; // 本轮新收到的 B2(灵敏度测试) 记录条数
|
||||
|
||||
function updateRecordCount() {
|
||||
const el = document.getElementById("new-record-count");
|
||||
if (el) el.textContent = newB2Count > 0 ? `(${newB2Count} 条新记录)` : "";
|
||||
}
|
||||
|
||||
async function refreshLatestData() {
|
||||
// 自动化运行中由 pollProgress 负责渲染,避免冲突
|
||||
if (autoRunning) return;
|
||||
try {
|
||||
const resp = await fetch(`/api/automation/${DNT_ID}/progress`);
|
||||
const data = await resp.json();
|
||||
if (data.latest && data.latest.id !== lastLatestId) {
|
||||
lastLatestId = data.latest.id;
|
||||
renderLatest(data.latest);
|
||||
// 仅 B2(灵敏度测试) 记录计数
|
||||
if (data.latest.data_source === "B2") {
|
||||
newB2Count++;
|
||||
updateRecordCount();
|
||||
}
|
||||
}
|
||||
if (data.latest_wave && data.latest_wave.id !== lastWaveId) {
|
||||
lastWaveId = data.latest_wave.id;
|
||||
renderLatestWave(data.latest_wave);
|
||||
}
|
||||
} catch (e) { /* 静默失败 */ }
|
||||
}
|
||||
|
||||
// 最新测试数据每 3 秒轮询
|
||||
setInterval(refreshLatestData, 3000);
|
||||
|
||||
// 每 5 秒刷新设备状态 + 测试模式 + 型号名称缓存(工装页修改后能及时同步)
|
||||
async function refreshAll() {
|
||||
await loadDeviceTypeNames();
|
||||
await loadTestMode();
|
||||
refreshDeviceStatus();
|
||||
}
|
||||
@@ -475,17 +571,23 @@ function fmtRelay(s) {
|
||||
|
||||
function renderLatest(data) {
|
||||
const div = document.getElementById("latest-result");
|
||||
// 优先使用 str_type,为空时从缓存查找
|
||||
let typeName = data.str_type;
|
||||
if (!typeName && data.sub_type != null) {
|
||||
typeName = devTypeNameCache[data.sub_type] || `Unknown(${data.sub_type})`;
|
||||
}
|
||||
div.innerHTML = `
|
||||
<p>设备型号:<strong>${data.str_type || '-'}</strong></p>
|
||||
<p>车检器序列号:<strong>${data.detector_serial || '-'}</strong></p>
|
||||
<p>设备型号:<strong>${typeName || '-'}</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.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>继电器:${fmtRelay(data.relay_out) || decodeRelay(data.relay_code)}</p>
|
||||
@@ -527,8 +629,8 @@ function renderLatestWave(data) {
|
||||
<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>触发高度 (B4):${data.b4_enter_dist || '-'} mm</p>
|
||||
<p>释放高度 (B4):${data.b4_leave_dist || '-'} mm</p>
|
||||
<p>继电器:${fmtRelay(data.relay_out) || decodeRelay(data.relay_code)}</p>
|
||||
<p>时间:${fmtTime(data.create_time)}</p>
|
||||
`;
|
||||
|
||||
@@ -58,17 +58,22 @@
|
||||
|
||||
<h3>自动化测试</h3>
|
||||
<div class="automation">
|
||||
<label>
|
||||
车检器序列号:
|
||||
<input type="text" id="detector-serial" placeholder="选填" style="width:180px;">
|
||||
</label>
|
||||
<br style="margin-bottom:8px;">
|
||||
<label>
|
||||
测试次数:
|
||||
<input type="number" id="test-count" value="10" min="1" max="9999">
|
||||
<input type="number" id="test-count" value="1" min="1" max="9999">
|
||||
</label>
|
||||
<label style="margin-left:16px;">
|
||||
间隔时间(秒):
|
||||
<input type="number" id="interval-sec" value="10" min="0" max="300" style="width:60px;">
|
||||
<input type="number" id="interval-sec" value="5" min="0" max="300" style="width:60px;">
|
||||
</label>
|
||||
<label style="margin-left:16px;">
|
||||
超时时间(秒):
|
||||
<input type="number" id="timeout-sec" value="5" min="1" max="600" style="width:60px;">
|
||||
<input type="number" id="timeout-sec" value="4" min="1" max="600" style="width:60px;">
|
||||
</label>
|
||||
<button id="btn-auto" class="btn-start" onclick="toggleAuto()">开始</button>
|
||||
<div class="progress-container">
|
||||
@@ -89,7 +94,7 @@
|
||||
|
||||
<!-- 右侧:测试信息显示区 -->
|
||||
<div class="test-info">
|
||||
<h3>当前测试数据</h3>
|
||||
<h3>当前测试数据 <span id="new-record-count" style="font-size:12px;color:#888;font-weight:normal;margin-left:8px;"></span></h3>
|
||||
<div id="latest-result">
|
||||
<p class="placeholder">等待设备上报...</p>
|
||||
</div>
|
||||
@@ -104,12 +109,12 @@
|
||||
<h3>自动化平均值</h3>
|
||||
<table id="avg-table">
|
||||
<tr><td>平均峰峰值</td><td id="avg-ppvalue">-</td><td>V</td></tr>
|
||||
<tr><td>平均开始工作频率</td><td id="avg-idle-freq">-</td><td>Hz</td></tr>
|
||||
<tr><td>平均进入工作频率</td><td id="avg-enter-freq">-</td><td>Hz</td></tr>
|
||||
<tr><td>平均进入距离</td><td id="avg-enter-dist">-</td><td>mm</td></tr>
|
||||
<tr><td>平均离开距离</td><td id="avg-exit-dist">-</td><td>mm</td></tr>
|
||||
<tr><td>平均进入速度</td><td id="avg-enter-speed">-</td><td>m/s</td></tr>
|
||||
<tr><td>平均离开速度</td><td id="avg-exit-speed">-</td><td>m/s</td></tr>
|
||||
<tr><td>平均开始频率</td><td id="avg-idle-freq">-</td><td>Hz</td></tr>
|
||||
<tr><td>平均触发频率</td><td id="avg-enter-freq">-</td><td>Hz</td></tr>
|
||||
<tr><td>平均触发距离</td><td id="avg-enter-dist">-</td><td>mm</td></tr>
|
||||
<tr><td>平均释放距离</td><td id="avg-exit-dist">-</td><td>mm</td></tr>
|
||||
<tr><td>平均触发速度</td><td id="avg-enter-speed">-</td><td>m/s</td></tr>
|
||||
<tr><td>平均释放速度</td><td id="avg-exit-speed">-</td><td>m/s</td></tr>
|
||||
</table>
|
||||
|
||||
<h3 style="margin-top:20px;">本轮测试明细</h3>
|
||||
@@ -117,7 +122,7 @@
|
||||
<table id="records-table" style="font-size:11px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th><th>串口状态</th><th>模式</th><th>峰峰值(V)</th><th>开始频率</th><th>进入距离</th><th>离开距离</th><th>速度(m/s)</th><th>时间</th>
|
||||
<th>#</th><th>串口状态</th><th>模式</th><th>峰峰值(V)</th><th>开始频率</th><th>触发距离</th><th>释放距离</th><th>速度(m/s)</th><th>时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
|
||||
Submodule edc_server updated: 3580f89552...a2f31b3bfe
Reference in New Issue
Block a user