// 应用主控制器 const WeatherApp = { cachedHistoryData: [], cachedForecastData: [], currentPage: 1, itemsPerPage: 10, filteredDevices: [], init() { // 初始化日期 WeatherUtils.initializeDateInputs(); // 初始化地图 WeatherMap.init(window.TIANDITU_KEY || ''); WeatherMap.loadStations(); // 定时刷新在线设备数 setInterval(() => this.updateOnlineDevices(), 30000); // 绑定 UI this.bindUI(); // 监听地图请求查询事件 window.addEventListener('query-history-data', () => this.queryHistoryData()); }, bindUI() { const stationInput = document.getElementById('stationInput'); if (stationInput) { stationInput.addEventListener('input', function() { this.value = this.value.toUpperCase().replace(/[^0-9A-F]/g, ''); }); stationInput.addEventListener('change', function() { const value = this.value.trim(); if (!value) return; if (/^[0-9A-F]+$/i.test(value)) { if (value.length <= 6) this.value = WeatherUtils.hexToDecimal(value); } else { const num = parseInt(value); if (!isNaN(num)) this.value = num.toString(); } }); } const showDeviceListBtn = document.getElementById('showDeviceList'); const modal = document.getElementById('deviceModal'); const closeBtn = document.querySelector('.close-modal'); const prevPageBtn = document.getElementById('prevPage'); const nextPageBtn = document.getElementById('nextPage'); // 由 Alpine 管理设备列表弹窗开关与分页,不再绑定以下事件 // if (showDeviceListBtn && modal) { // showDeviceListBtn.addEventListener('click', (e) => { // e.preventDefault(); // modal.style.display = 'block'; // this.updateDeviceList(1); // }); // } // if (prevPageBtn) { // prevPageBtn.addEventListener('click', () => { // if (this.currentPage > 1) this.updateDeviceList(this.currentPage - 1); // }); // } // if (nextPageBtn) { // nextPageBtn.addEventListener('click', () => { // const totalPages = Math.ceil(this.filteredDevices.length / this.itemsPerPage); // if (this.currentPage < totalPages) this.updateDeviceList(this.currentPage + 1); // }); // } // if (closeBtn && modal) { // closeBtn.addEventListener('click', () => modal.style.display = 'none'); // window.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; }); // } const deviceListEl = document.getElementById('deviceList'); if (deviceListEl && modal) { deviceListEl.addEventListener('click', (e) => { const deviceItem = e.target.closest('.device-item'); if (!deviceItem) return; const decimalId = deviceItem.getAttribute('data-decimal-id'); const input = document.getElementById('stationInput'); if (input) input.value = decimalId; // 关闭交给 Alpine: deviceModalOpen = false window.dispatchEvent(new CustomEvent('close-device-modal')); this.queryHistoryData(); }); } const showPastForecast = document.getElementById('showPastForecast'); if (showPastForecast) { showPastForecast.addEventListener('change', () => { WeatherTable.display(this.cachedHistoryData, this.cachedForecastData); }); } // 提供全局函数以兼容现有 HTML on* 绑定 window.switchLayer = (type) => WeatherMap.switchLayer(type); window.toggleMap = () => WeatherMap.toggleMap(); window.queryHistoryData = () => this.queryHistoryData(); }, // 更新设备列表 updateDeviceList(page = 1) { const deviceListContainer = document.getElementById('deviceList'); if (!deviceListContainer) return; deviceListContainer.innerHTML = ''; this.filteredDevices = (WeatherMap.stations || []) .filter(station => station.device_type === 'WH65LP') .sort((a, b) => { const aOnline = WeatherUtils.isDeviceOnline(a.last_update); const bOnline = WeatherUtils.isDeviceOnline(b.last_update); if (aOnline === bOnline) return 0; return aOnline ? -1 : 1; }); const totalPages = Math.ceil(this.filteredDevices.length / this.itemsPerPage) || 1; this.currentPage = Math.min(Math.max(1, page), totalPages); const currentPageEl = document.getElementById('currentPage'); const totalPagesEl = document.getElementById('totalPages'); const prevBtn = document.getElementById('prevPage'); const nextBtn = document.getElementById('nextPage'); if (currentPageEl) currentPageEl.textContent = this.currentPage; if (totalPagesEl) totalPagesEl.textContent = totalPages; if (prevBtn) prevBtn.disabled = this.currentPage <= 1; if (nextBtn) nextBtn.disabled = this.currentPage >= totalPages; const startIndex = (this.currentPage - 1) * this.itemsPerPage; const endIndex = startIndex + this.itemsPerPage; const currentDevices = this.filteredDevices.slice(startIndex, endIndex); currentDevices.forEach(device => { const isOnline = WeatherUtils.isDeviceOnline(device.last_update); const deviceItem = document.createElement('div'); deviceItem.className = 'device-item'; deviceItem.setAttribute('data-decimal-id', device.decimal_id); deviceItem.innerHTML = `
${device.decimal_id} | ${device.name} | ${device.location || '未知位置'}
${isOnline ? '在线' : '离线'} `; deviceListContainer.appendChild(deviceItem); }); if (this.filteredDevices.length === 0) { deviceListContainer.innerHTML = '
暂无WH65LP设备
'; } }, async updateOnlineDevices() { try { const response = await fetch('/api/system/status'); const data = await response.json(); const onlineEl = document.getElementById('onlineDevices'); if (onlineEl) onlineEl.textContent = data.online_devices; } catch (error) { console.error('更新在线设备数量失败:', error); } }, async queryHistoryData() { const decimalId = (document.getElementById('stationInput')?.value || '').trim(); if (!decimalId) { alert('请输入站点编号'); return; } if (!/^\d+$/.test(decimalId)) { alert('请输入有效的十进制编号'); return; } const startTime = document.getElementById('startDate').value; const endTime = document.getElementById('endDate').value; const interval = document.getElementById('interval').value; const forecastProvider = document.getElementById('forecastProvider').value; if (!startTime || !endTime) { alert('请选择开始和结束时间'); return; } try { const historyParams = new URLSearchParams({ decimal_id: decimalId, start_time: startTime.replace('T', ' ') + ':00', end_time: endTime.replace('T', ' ') + ':00', interval: interval }); const historyResponse = await fetch(`/api/data?${historyParams}`); if (!historyResponse.ok) throw new Error('查询历史数据失败'); const responseData = await historyResponse.json(); const historyData = Array.isArray(responseData) ? responseData : []; let forecastData = []; if (forecastProvider && interval === '1hour') { try { const hexID = WeatherUtils.decimalToHex(decimalId); const stationID = `RS485-${hexID}`; const forecastParams = new URLSearchParams({ station_id: stationID, from: startTime.replace('T', ' ') + ':00', to: endTime.replace('T', ' ') + ':00', provider: forecastProvider }); const forecastResponse = await fetch(`/api/forecast?${forecastParams}`); if (forecastResponse.ok) { const responseData = await forecastResponse.json(); forecastData = Array.isArray(responseData) ? responseData : []; console.log(`查询到 ${forecastData.length} 条预报数据`); } } catch (e) { console.warn('查询预报数据失败:', e); } } this.cachedHistoryData = historyData; this.cachedForecastData = forecastData; if (historyData.length === 0 && forecastData.length === 0) { alert('该时间段内无数据'); return; } const station = (WeatherMap.stations || []).find(s => s.decimal_id == decimalId); const stationInfoTitle = document.getElementById('stationInfoTitle'); if (stationInfoTitle) { if (station) { stationInfoTitle.innerHTML = ` ${station.location || '未知位置'} · 编号 ${decimalId} · 坐标 ${station.latitude ? station.latitude.toFixed(6) : '未知'}, ${station.longitude ? station.longitude.toFixed(6) : '未知'} `; } else { stationInfoTitle.innerHTML = `编号 ${decimalId}`; } } if (!WeatherMap.isMapCollapsed) WeatherMap.toggleMap(); WeatherChart.display(historyData, forecastData); WeatherTable.display(historyData, forecastData); const chartContainer = document.getElementById('chartContainer'); const tableContainer = document.getElementById('tableContainer'); if (chartContainer) chartContainer.classList.add('show'); if (tableContainer) tableContainer.classList.add('show'); setTimeout(() => { chartContainer?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }, 300); } catch (error) { console.error('查询数据失败:', error); alert('查询数据失败: ' + error.message); } } }; window.WeatherApp = WeatherApp; document.addEventListener('DOMContentLoaded', () => { WeatherApp.init(); });