diff --git a/edc-web/app/models.py b/edc-web/app/models.py index 42087a3..85b1048 100644 --- a/edc-web/app/models.py +++ b/edc-web/app/models.py @@ -149,11 +149,12 @@ def get_latest_test_state(dnt_id: int) -> dict | None: conn.close() -def get_test_data(page: int = 1, per_page: int = 20, +def get_test_data(page: int = 1, per_page: int = 100, serial: str = "", date_from: str = "", date_to: str = "", test_mode: str = "", - data_source: str = "") -> tuple[list[dict], int]: - """分页查询测试数据(JOIN dnt_info),返回 (records, total) + data_source: str = "", + detector_serial: str = "") -> tuple[list[dict], int]: + """分页查询测试数据(JOIN dnt_info),最多返回最近 6000 条,返回 (records, total) test_mode: ''=全部, '0'=灵敏度, '1'=波动 data_source: ''=全部, 'B2', 'B4' @@ -166,6 +167,9 @@ def get_test_data(page: int = 1, per_page: int = 20, if serial: where.append("d.serial LIKE %s") params.append(f"%{serial}%") + if detector_serial: + where.append("t.detector_serial LIKE %s") + params.append(f"%{detector_serial}%") if date_from: where.append("t.create_time >= %s") params.append(date_from if len(date_from) > 10 else date_from) @@ -181,17 +185,21 @@ def get_test_data(page: int = 1, per_page: int = 20, where_clause = " AND ".join(where) if where else "1=1" - # count + # count — 最多 6000 条 cur.execute( - f"SELECT COUNT(*) as total FROM tb_state_tst t " - f"JOIN dnt_info d ON t.dnt_id = d.id WHERE {where_clause}", + f"SELECT COUNT(*) as total FROM (" + f"SELECT 1 FROM tb_state_tst t " + f"JOIN dnt_info d ON t.dnt_id = d.id " + f"WHERE {where_clause} ORDER BY t.id DESC LIMIT 6000" + f") sub", params, ) total = cur.fetchone()["total"] - # data + # data — 子查询限 6000 后再分页 offset = (page - 1) * per_page cur.execute( + f"SELECT * FROM (" f"SELECT t.*, d.serial, " f"c.coil_num, c.name as coil_name, " f"sc.simulate_num, sc.name as car_name " @@ -200,7 +208,8 @@ def get_test_data(page: int = 1, per_page: int = 20, f"LEFT JOIN tb_coil_info c ON t.coil_id = c.id " f"LEFT JOIN tb_simulate_car sc ON t.simulate_car_id = sc.id " f"WHERE {where_clause} " - f"ORDER BY t.id DESC LIMIT %s OFFSET %s", + f"ORDER BY t.id DESC LIMIT 6000" + f") sub ORDER BY id DESC LIMIT %s OFFSET %s", params + [per_page, offset], ) records = cur.fetchall() @@ -212,8 +221,9 @@ def get_test_data(page: int = 1, per_page: int = 20, def get_all_test_data_for_export(serial: str = "", date_from: str = "", date_to: str = "", test_mode: str = "", - data_source: str = "") -> list[dict]: - """导出全部数据 + data_source: str = "", + detector_serial: str = "") -> list[dict]: + """导出全部数据(最多最近 6000 条) test_mode: ''=全部, '0'=灵敏度, '1'=波动 data_source: ''=全部, 'B2', 'B4' @@ -226,6 +236,9 @@ def get_all_test_data_for_export(serial: str = "", date_from: str = "", if serial: where.append("d.serial LIKE %s") params.append(f"%{serial}%") + if detector_serial: + where.append("t.detector_serial LIKE %s") + params.append(f"%{detector_serial}%") if date_from: where.append("t.create_time >= %s") params.append(date_from if len(date_from) > 10 else date_from) @@ -248,7 +261,7 @@ def get_all_test_data_for_export(serial: str = "", date_from: str = "", f"JOIN dnt_info d ON t.dnt_id = d.id " f"LEFT JOIN tb_coil_info c ON t.coil_id = c.id " f"LEFT JOIN tb_simulate_car sc ON t.simulate_car_id = sc.id " - f"WHERE {where_clause} ORDER BY t.id DESC", + f"WHERE {where_clause} ORDER BY t.id DESC LIMIT 6000", params, ) return cur.fetchall() diff --git a/edc-web/app/routes/test_data.py b/edc-web/app/routes/test_data.py index 3cb8862..cc42ef4 100644 --- a/edc-web/app/routes/test_data.py +++ b/edc-web/app/routes/test_data.py @@ -21,15 +21,16 @@ def test_data_page(): def api_test_data(): """分页查询测试数据""" page = request.args.get("page", 1, type=int) - per_page = request.args.get("per_page", 20, type=int) + per_page = request.args.get("per_page", 100, type=int) serial = request.args.get("serial", "", type=str) + detector_serial = request.args.get("detector_serial", "", type=str) date_from = request.args.get("date_from", "", type=str) date_to = request.args.get("date_to", "", type=str) test_mode = request.args.get("test_mode", "", type=str) data_source = request.args.get("data_source", "", type=str) records, total = get_test_data(page, per_page, serial, date_from, date_to, - test_mode, data_source) + test_mode, data_source, detector_serial) return jsonify({ "records": records, "total": total, @@ -42,29 +43,33 @@ def api_test_data(): @bp.route("/api/test-data/chart") @login_required def api_chart_data(): - """返回图表所需全部数据(不分页)""" + """返回图表所需全部数据(不分页,最多 6000 条)""" serial = request.args.get("serial", "", type=str) + detector_serial = request.args.get("detector_serial", "", type=str) date_from = request.args.get("date_from", "", type=str) date_to = request.args.get("date_to", "", type=str) test_mode = request.args.get("test_mode", "", type=str) data_source = request.args.get("data_source", "", type=str) records = get_all_test_data_for_export(serial, date_from, date_to, - test_mode, data_source) + test_mode, data_source, + detector_serial) return jsonify({"records": records, "total": len(records)}) @bp.route("/api/test-data/export") @login_required def api_export(): - """导出测试数据为 CSV""" + """导出测试数据为 CSV(最多 6000 条)""" serial = request.args.get("serial", "", type=str) + detector_serial = request.args.get("detector_serial", "", type=str) date_from = request.args.get("date_from", "", type=str) date_to = request.args.get("date_to", "", type=str) test_mode = request.args.get("test_mode", "", type=str) data_source = request.args.get("data_source", "", type=str) records = get_all_test_data_for_export(serial, date_from, date_to, - test_mode, data_source) + test_mode, data_source, + detector_serial) output = io.StringIO() writer = csv.writer(output) diff --git a/edc-web/app/static/js/test_data.js b/edc-web/app/static/js/test_data.js index b9af44a..4be9060 100644 --- a/edc-web/app/static/js/test_data.js +++ b/edc-web/app/static/js/test_data.js @@ -28,12 +28,11 @@ const VIEWS = { label: '全部数据', data_source: '', // '' = 不过滤 cols: [ - { key: 'id', title: 'ID' }, - { key: 'serial', title: '设备编码' }, + { key: 'create_time', title: '时间', render: r => fmtTime(r.create_time) }, + { key: 'serial', title: '设备编码', render: r => (r.serial || '').slice(-6) }, { 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' ? '是' : '否') }, { key: 'fault_info', title: '故障信息', render: r => r.data_source === 'B4' ? '-' : `${escHtml(r.fault_info || '-')}` }, { key: 'relay_out', title: '继电器', render: r => fmtRelay(r.relay_out) }, @@ -58,18 +57,17 @@ const VIEWS = { { key: 'near_dist', title: '最近距离(mm)', render: r => r.data_source === 'B2' ? '-' : (r.near_dist != null ? r.near_dist + ' ' : '-') }, { key: 'far_dist', title: '最远距离(mm)', render: r => r.data_source === 'B2' ? '-' : (r.far_dist != null ? r.far_dist + ' ' : '-') }, { key: 'env', title: '测试环境', render: r => envLabel(r) }, - { key: 'create_time', title: '时间', render: r => fmtTime(r.create_time) }, + { key: 'test_mode', title: '测试模式', render: r => r.test_mode === 1 ? '波动' : '灵敏度' }, ], }, b2: { label: '灵敏度测试', data_source: 'B2', cols: [ - { key: 'id', title: 'ID' }, - { key: 'serial', title: '设备编码' }, + { key: 'create_time', title: '时间', render: r => fmtTime(r.create_time) }, + { key: 'serial', title: '设备编码', render: r => (r.serial || '').slice(-6) }, { 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 => `${escHtml(r.fault_info || '-')}` }, { key: 'relay_out', title: '继电器', render: r => fmtRelay(r.relay_out) }, @@ -82,15 +80,15 @@ const VIEWS = { { 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) }, + { key: 'test_mode', title: '测试模式', render: r => r.test_mode === 1 ? '波动' : '灵敏度' }, ], }, b4: { label: '波动测试', data_source: 'B4', cols: [ - { key: 'id', title: 'ID' }, - { key: 'serial', title: '设备编码' }, + { key: 'create_time', title: '时间', render: r => fmtTime(r.create_time) }, + { key: 'serial', title: '设备编码', render: r => (r.serial || '').slice(-6) }, { key: 'detector_serial', title: '车检器序列号', render: r => r.detector_serial || '-' }, { key: 'remain_count', title: '剩余次数' }, { key: 'work_freq', title: '工作频率(Hz)' }, @@ -102,7 +100,7 @@ const VIEWS = { { key: 'b4_leave_dist', title: '释放高度(mm)' }, { key: 'relay_out', title: '继电器', render: r => fmtRelay(r.relay_out) }, { key: 'env', title: '测试环境', render: r => envLabel(r) }, - { key: 'create_time', title: '时间', render: r => fmtTime(r.create_time) }, + { key: 'test_mode', title: '测试模式', render: r => r.test_mode === 1 ? '波动' : '灵敏度' }, ], }, }; @@ -193,14 +191,16 @@ function getDatetime(dateId, timeId) { async function searchData(page = 1) { currentPage = page; const serial = document.getElementById("search-serial").value; + const detectorSerial = document.getElementById("search-detector-serial").value; const dateFrom = getDatetime("search-date-from", "search-time-from"); const dateTo = getDatetime("search-date-to", "search-time-to"); const v = VIEWS[currentView]; - const perPage = parseInt(document.getElementById("per-page").value) || 20; + const perPage = parseInt(document.getElementById("per-page").value) || 100; const params = new URLSearchParams({ page, per_page: perPage }); if (serial) params.set("serial", serial); + if (detectorSerial) params.set("detector_serial", detectorSerial); if (dateFrom) params.set("date_from", dateFrom); if (dateTo) params.set("date_to", dateTo); // 按 data_source 过滤(全部不过滤) @@ -271,12 +271,14 @@ function renderPagination() { function exportCSV() { const serial = document.getElementById("search-serial").value; + const detectorSerial = document.getElementById("search-detector-serial").value; const dateFrom = getDatetime("search-date-from", "search-time-from"); const dateTo = getDatetime("search-date-to", "search-time-to"); const v = VIEWS[currentView]; const params = new URLSearchParams(); if (serial) params.set("serial", serial); + if (detectorSerial) params.set("detector_serial", detectorSerial); if (dateFrom) params.set("date_from", dateFrom); if (dateTo) params.set("date_to", dateTo); if (v.data_source) params.set("data_source", v.data_source); @@ -364,6 +366,7 @@ async function loadChart() { if (!container || container.style.display === 'none') return; const serial = document.getElementById('search-serial').value; + const detectorSerial = document.getElementById('search-detector-serial').value; const dateFrom = getDatetime('search-date-from', 'search-time-from'); const dateTo = getDatetime('search-date-to', 'search-time-to'); const v = VIEWS[currentView]; @@ -373,6 +376,7 @@ async function loadChart() { const params = new URLSearchParams(); if (serial) params.set('serial', serial); + if (detectorSerial) params.set('detector_serial', detectorSerial); if (dateFrom) params.set('date_from', dateFrom); if (dateTo) params.set('date_to', dateTo); if (ds) params.set('data_source', ds); diff --git a/edc-web/app/templates/test_data.html b/edc-web/app/templates/test_data.html index ad8c995..28a60fa 100644 --- a/edc-web/app/templates/test_data.html +++ b/edc-web/app/templates/test_data.html @@ -21,7 +21,11 @@