feat: 设备日志增加时间范围查询 + CSV 导出
- 查询 API 增加 date_from/date_to 参数(前端日期+时间选择器) - 新增 /api/device-logs/export CSV 导出端点 - 新增 export_device_logs() 模型函数(全量不分页) - 删除校验放宽:允许纯时间范围作为删除条件 - 前端增加导出 CSV 按钮,遵循 test_data 页面模式
This commit is contained in:
@@ -17,7 +17,16 @@
|
||||
<option value="tcp_disconnect">TCP断开</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
时间范围:
|
||||
<input type="date" id="search-date-from">
|
||||
<input type="time" id="search-time-from" step="1" style="width:110px;" title="起始时间(时:分:秒)">
|
||||
至
|
||||
<input type="date" id="search-date-to">
|
||||
<input type="time" id="search-time-to" step="1" style="width:110px;" title="截止时间(时:分:秒)">
|
||||
</label>
|
||||
<button onclick="searchLogs(1)" class="btn-search">查询</button>
|
||||
<button onclick="exportCSV()" class="btn-export">导出 CSV</button>
|
||||
{% if current_user.role == 'admin' %}
|
||||
<button onclick="confirmDeleteLogs()" class="btn-delete">🗑 删除</button>
|
||||
{% endif %}
|
||||
@@ -44,13 +53,25 @@
|
||||
<script>
|
||||
let currentPage = 1, totalPages = 1;
|
||||
|
||||
function getDatetime(dateId, timeId) {
|
||||
const d = document.getElementById(dateId).value;
|
||||
const t = document.getElementById(timeId).value;
|
||||
if (!d) return "";
|
||||
if (!t) return d; // 纯日期 → 后端自动补时间
|
||||
return d + " " + t; // 完整 datetime
|
||||
}
|
||||
|
||||
async function searchLogs(page = 1) {
|
||||
currentPage = page;
|
||||
const serial = document.getElementById("search-serial").value;
|
||||
const event_type = document.getElementById("search-event").value;
|
||||
const date_from = getDatetime("search-date-from", "search-time-from");
|
||||
const date_to = getDatetime("search-date-to", "search-time-to");
|
||||
const params = new URLSearchParams({page, per_page: 30});
|
||||
if (serial) params.set("serial", serial);
|
||||
if (event_type) params.set("event_type", event_type);
|
||||
if (date_from) params.set("date_from", date_from);
|
||||
if (date_to) params.set("date_to", date_to);
|
||||
|
||||
const resp = await fetch(`/api/device-logs?${params}`);
|
||||
const data = await resp.json();
|
||||
@@ -120,20 +141,41 @@ function escHtml(s) {
|
||||
return String(s || '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
// ─── 导出 CSV ────────────────────────────────────
|
||||
|
||||
function exportCSV() {
|
||||
const serial = document.getElementById("search-serial").value;
|
||||
const event_type = document.getElementById("search-event").value;
|
||||
const date_from = getDatetime("search-date-from", "search-time-from");
|
||||
const date_to = getDatetime("search-date-to", "search-time-to");
|
||||
const params = new URLSearchParams();
|
||||
if (serial) params.set("serial", serial);
|
||||
if (event_type) params.set("event_type", event_type);
|
||||
if (date_from) params.set("date_from", date_from);
|
||||
if (date_to) params.set("date_to", date_to);
|
||||
|
||||
// 直接打开下载链接
|
||||
window.location.href = `/api/device-logs/export?${params}`;
|
||||
}
|
||||
|
||||
// ─── 删除 ────────────────────────────────────────
|
||||
|
||||
async function confirmDeleteLogs() {
|
||||
const serial = document.getElementById("search-serial").value;
|
||||
const event_type = document.getElementById("search-event").value;
|
||||
if (!serial && !event_type) {
|
||||
alert("请至少输入设备序列号或选择事件类型作为删除条件");
|
||||
const date_from = getDatetime("search-date-from", "search-time-from");
|
||||
const date_to = getDatetime("search-date-to", "search-time-to");
|
||||
if (!serial && !event_type && !date_from && !date_to) {
|
||||
alert("请至少输入设备序列号、选择事件类型或指定时间范围作为删除条件");
|
||||
return;
|
||||
}
|
||||
const msg = `确认删除设备日志?\n条件: serial=${serial || '(无)'} type=${event_type || '(无)'}\n此操作不可撤销!`;
|
||||
const msg = `确认删除设备日志?\n条件: serial=${serial || '(无)'} type=${event_type || '(无)'} time=${date_from||'(无)'}~${date_to||'(无)'}\n此操作不可撤销!`;
|
||||
if (!confirm(msg)) return;
|
||||
|
||||
const resp = await fetch("/api/device-logs/delete", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({serial, event_type}),
|
||||
body: JSON.stringify({serial, event_type, date_from, date_to}),
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.ok) {
|
||||
|
||||
Reference in New Issue
Block a user