go_rain_dtu/static/index.html
2025-05-15 16:36:52 +08:00

332 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>气象站数据监控</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.header {
padding: 10px;
text-align: center;
border-bottom: 1px solid #ddd;
background-color: #f8f9fa;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 15px;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #fff;
}
.control-group {
display: flex;
align-items: center;
gap: 5px;
}
select, input, button {
padding: 5px 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
button {
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #0056b3;
}
.chart-container {
margin-bottom: 20px;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
background-color: #fff;
}
.table-container {
overflow-x: auto;
margin-top: 20px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #fff;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 12px 8px;
text-align: left;
}
th {
background-color: #f8f9fa;
font-weight: bold;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:hover {
background-color: #f5f5f5;
}
@media (max-width: 768px) {
.controls {
flex-direction: column;
}
.control-group {
width: 100%;
}
select, input {
width: 100%;
}
}
</style>
</head>
<body>
<div class="header">
<h1>气象站数据监控</h1>
</div>
<div class="container">
<div class="controls">
<div class="control-group">
<label for="interval">数据粒度:</label>
<select id="interval">
<option value="5min">5分钟</option>
<option value="30min">30分钟</option>
<option value="1hour" selected>1小时</option>
</select>
</div>
<div class="control-group">
<label for="startDate">开始时间:</label>
<input type="datetime-local" id="startDate">
</div>
<div class="control-group">
<label for="endDate">结束时间:</label>
<input type="datetime-local" id="endDate">
</div>
<div class="control-group">
<button onclick="queryData()">查询</button>
<button onclick="exportData()">导出数据</button>
</div>
</div>
<div class="chart-container">
<canvas id="mainChart"></canvas>
</div>
<div class="table-container">
<table>
<thead>
<tr>
<th>时间</th>
<th>降雨量(mm)</th>
<th>平均温度(℃)</th>
<th>平均湿度(%)</th>
<th>平均风速(m/s)</th>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
</div>
</div>
<script>
let mainChart = null;
// 初始化日期选择器
function initDatePickers() {
const now = new Date();
const yesterday = new Date(now);
yesterday.setDate(yesterday.getDate() - 1);
document.getElementById('startDate').value = formatDateTime(yesterday);
document.getElementById('endDate').value = formatDateTime(now);
}
// 格式化日期时间
function formatDateTime(date) {
return date.toISOString().slice(0, 16);
}
// 查询数据
function queryData() {
const interval = document.getElementById('interval').value;
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
fetch(`/api/data?interval=${interval}&start=${startDate}&end=${endDate}`)
.then(response => response.json())
.then(data => {
updateChart(data);
updateTable(data);
})
.catch(error => {
console.error('Error:', error);
alert('获取数据失败,请检查网络连接');
});
}
// 更新图表
function updateChart(data) {
const ctx = document.getElementById('mainChart').getContext('2d');
if (mainChart) {
mainChart.destroy();
}
const labels = data.map(item => {
const date = new Date(item.timestamp);
// 格式化为中文日期时间格式
return 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');
});
mainChart = new Chart(ctx, {
data: {
labels: labels,
datasets: [
{
type: 'bar',
label: '降雨量(mm)',
data: data.map(item => item.rainfall),
backgroundColor: 'rgba(54, 162, 235, 0.5)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1,
yAxisID: 'y-rainfall',
},
{
type: 'line',
label: '温度(℃)',
data: data.map(item => item.avg_temperature),
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.5)',
tension: 0.1,
yAxisID: 'y-temp',
}
]
},
options: {
responsive: true,
interaction: {
mode: 'index',
intersect: false,
},
scales: {
'y-rainfall': {
type: 'linear',
position: 'left',
title: {
display: true,
text: '降雨量(mm)'
},
grid: {
drawOnChartArea: false
}
},
'y-temp': {
type: 'linear',
position: 'right',
title: {
display: true,
text: '温度(℃)'
}
}
}
}
});
}
// 更新表格
function updateTable(data) {
const tbody = document.getElementById('tableBody');
tbody.innerHTML = '';
data.forEach(item => {
const row = document.createElement('tr');
const date = new Date(item.timestamp);
// 格式化为中文日期时间格式
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 = `
<td>${formattedDate}</td>
<td>${item.rainfall.toFixed(1)}</td>
<td>${item.avg_temperature.toFixed(1)}</td>
<td>${item.avg_humidity.toFixed(1)}</td>
<td>${item.avg_wind_speed.toFixed(1)}</td>
`;
tbody.appendChild(row);
});
}
// 导出数据
function exportData() {
const data = mainChart.data;
let csv = '时间,降雨量(mm),温度(℃),湿度(%),风速(m/s)\n';
for (let i = 0; i < data.labels.length; i++) {
csv += `${data.labels[i]},${data.datasets[0].data[i]},${data.datasets[1].data[i]}\n`;
}
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = '气象站数据.csv';
link.click();
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
initDatePickers();
queryData();
});
</script>
</body>
</html>