let sensorChart = null; let refreshInterval = null; let allSensors = []; let currentSensorData = []; // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', function() { // 初始化日期选择器为今天 initializeDatePickers(); // 加载所有传感器ID loadSensors(); // 添加事件监听器 setupEventListeners(); // 设置自动刷新 setupAutoRefresh(); }); // 初始化日期选择器 function initializeDatePickers() { const now = new Date(); const today = now.toISOString().split('T')[0]; const time = now.toTimeString().split(' ')[0].substring(0, 5); // 设置默认的开始时间为当天00:00 document.getElementById('startDate').value = `${today}T00:00`; // 设置默认的结束时间为当前时间 document.getElementById('endDate').value = `${today}T${time}`; } // 设置事件监听器 function setupEventListeners() { // 查询按钮 document.getElementById('queryBtn').addEventListener('click', function() { loadData(); }); // 重置按钮 document.getElementById('resetBtn').addEventListener('click', function() { resetFilters(); }); // 传感器选择变化 document.getElementById('sensorSelect').addEventListener('change', function() { loadData(); }); // 记录数限制变化 document.getElementById('limitSelect').addEventListener('change', function() { loadData(); }); // 导出CSV按钮 document.getElementById('exportBtn').addEventListener('click', function() { exportToCSV(); }); } // 设置自动刷新 function setupAutoRefresh() { const autoRefreshCheckbox = document.getElementById('autoRefresh'); // 初始化自动刷新 if (autoRefreshCheckbox.checked) { startAutoRefresh(); } // 监听复选框变化 autoRefreshCheckbox.addEventListener('change', function() { if (this.checked) { startAutoRefresh(); } else { stopAutoRefresh(); } }); } // 开始自动刷新 function startAutoRefresh() { if (refreshInterval) { clearInterval(refreshInterval); } refreshInterval = setInterval(loadData, 10000); // 10秒刷新一次 } // 停止自动刷新 function stopAutoRefresh() { if (refreshInterval) { clearInterval(refreshInterval); refreshInterval = null; } } // 重置筛选条件 function resetFilters() { initializeDatePickers(); document.getElementById('sensorSelect').value = 'all'; document.getElementById('limitSelect').value = '100'; loadData(); } // 加载所有传感器ID function loadSensors() { fetch('/api/sensors') .then(response => { if (!response.ok) { throw new Error('获取传感器列表失败'); } return response.json(); }) .then(data => { allSensors = data; updateSensorSelect(data); // 加载数据 loadData(); }) .catch(error => { console.error('加载传感器列表出错:', error); alert('加载传感器列表出错: ' + error.message); }); } // 更新传感器选择下拉框 function updateSensorSelect(sensors) { const select = document.getElementById('sensorSelect'); // 保留"所有传感器"选项 const allOption = select.querySelector('option[value="all"]'); select.innerHTML = ''; select.appendChild(allOption); if (sensors.length === 0) { const option = document.createElement('option'); option.value = ''; option.textContent = '没有可用的传感器'; select.appendChild(option); return; } sensors.forEach(id => { const option = document.createElement('option'); option.value = id; option.textContent = `传感器 ${id}`; select.appendChild(option); }); } // 加载传感器数据 function loadData() { const sensorID = document.getElementById('sensorSelect').value; const limit = document.getElementById('limitSelect').value; const startDate = document.getElementById('startDate').value; const endDate = document.getElementById('endDate').value; let url = '/api/data?'; let params = []; // 添加查询参数 if (sensorID !== 'all') { params.push(`sensor_id=${sensorID}`); } if (limit) { params.push(`limit=${limit}`); } if (startDate) { params.push(`start_date=${encodeURIComponent(startDate)}`); } if (endDate) { params.push(`end_date=${encodeURIComponent(endDate)}`); } url += params.join('&'); // 显示加载状态 document.getElementById('queryBtn').textContent = '加载中...'; fetch(url) .then(response => { if (!response.ok) { throw new Error('获取传感器数据失败'); } return response.json(); }) .then(data => { currentSensorData = data; updateTable(data); updateChart(data); document.getElementById('queryBtn').textContent = '查询数据'; }) .catch(error => { console.error('加载数据出错:', error); alert('加载数据出错: ' + error.message); document.getElementById('queryBtn').textContent = '查询数据'; }); } // 更新数据表格 function updateTable(data) { const tableBody = document.getElementById('tableBody'); tableBody.innerHTML = ''; if (data.length === 0) { const row = document.createElement('tr'); row.innerHTML = '没有数据'; tableBody.appendChild(row); return; } data.forEach(item => { const row = document.createElement('tr'); // 解析时间并调整为中国时间(UTC+8) const date = new Date(item.timestamp); // 减去8小时,因为数据库时间似乎比实际时间早了8小时 date.setHours(date.getHours() - 8); // 格式化为中文日期时间格式 const formattedDate = date.getFullYear() + '/' + (date.getMonth() + 1).toString().padStart(2, '0') + '/' + date.getDate().toString().padStart(2, '0') + ' ' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0') + ':' + date.getSeconds().toString().padStart(2, '0'); row.innerHTML = '' + item.id + '' + '' + item.sensor_id + '' + '' + item.x.toFixed(3) + '' + '' + item.y.toFixed(3) + '' + '' + item.z.toFixed(3) + '' + '' + formattedDate + ''; tableBody.appendChild(row); }); } // 更新图表 function updateChart(data) { // 准备图表数据 const chartData = prepareChartData(data); // 如果图表已经存在,销毁它 if (sensorChart) { sensorChart.destroy(); } // 获取图表Canvas const ctx = document.getElementById('sensorChart').getContext('2d'); // 创建新图表 sensorChart = new Chart(ctx, { type: 'line', data: chartData, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: '传感器数据趋势' }, tooltip: { callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label) { label += ': '; } if (context.parsed.y !== null) { label += context.parsed.y.toFixed(3); } return label; } } } }, scales: { x: { title: { display: true, text: '时间' } }, y: { title: { display: true, text: '值' } } } } }); } // 准备图表数据 function prepareChartData(data) { // 如果没有数据,返回空数据集 if (data.length === 0) { return { labels: [], datasets: [] }; } // 反转数据以便按时间先后顺序显示 const sortedData = [...data].sort((a, b) => { return new Date(a.timestamp) - new Date(b.timestamp); }); // 获取所有传感器ID let sensorIDs = [...new Set(sortedData.map(item => item.sensor_id))]; // 按传感器ID分组数据 let datasets = []; let labels = []; // 准备时间标签(使用第一个传感器的数据) if (sensorIDs.length > 0) { const firstSensorData = sortedData.filter(item => item.sensor_id === sensorIDs[0]); labels = firstSensorData.map(item => { const date = new Date(item.timestamp); date.setHours(date.getHours() - 8); // 调整时区 return date.toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); }); } // 定义颜色 const colors = [ 'rgb(75, 192, 192)', 'rgb(255, 99, 132)', 'rgb(54, 162, 235)', 'rgb(255, 205, 86)', 'rgb(153, 102, 255)', 'rgb(255, 159, 64)' ]; // 为X, Y, Z创建不同的数据集 const dataTypes = [ { key: 'x', label: 'X值' }, { key: 'y', label: 'Y值' }, { key: 'z', label: 'Z值' } ]; sensorIDs.forEach((sensorID, sensorIndex) => { const sensorData = sortedData.filter(item => item.sensor_id === sensorID); dataTypes.forEach((type, typeIndex) => { const colorIndex = (sensorIndex * dataTypes.length + typeIndex) % colors.length; datasets.push({ label: `传感器${sensorID} - ${type.label}`, data: sensorData.map(item => item[type.key]), fill: false, borderColor: colors[colorIndex], tension: 0.1 }); }); }); return { labels: labels, datasets: datasets }; } // 导出到CSV文件 function exportToCSV() { if (currentSensorData.length === 0) { alert('没有数据可导出'); return; } // 准备CSV内容 let csvContent = "ID,传感器ID,X值,Y值,Z值,时间戳\n"; currentSensorData.forEach(item => { // 解析时间并调整为中国时间 const date = new Date(item.timestamp); date.setHours(date.getHours() - 8); // 格式化日期 const formattedDate = date.getFullYear() + '/' + (date.getMonth() + 1).toString().padStart(2, '0') + '/' + date.getDate().toString().padStart(2, '0') + ' ' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0') + ':' + date.getSeconds().toString().padStart(2, '0'); // 添加一行数据 csvContent += item.id + "," + item.sensor_id + "," + item.x.toFixed(3) + "," + item.y.toFixed(3) + "," + item.z.toFixed(3) + "," + formattedDate + "\n"; }); // 创建Blob对象 const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); // 创建下载链接 const link = document.createElement("a"); const url = URL.createObjectURL(blob); // 设置下载属性 link.setAttribute("href", url); link.setAttribute("download", "sensor_data.csv"); // 添加到文档并点击 document.body.appendChild(link); link.click(); // 清理 document.body.removeChild(link); }