691 lines
26 KiB
HTML
691 lines
26 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;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
|
||
.latest-data {
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
background-color: #f8f9fa;
|
||
}
|
||
|
||
.latest-data h3 {
|
||
margin-top: 0;
|
||
margin-bottom: 10px;
|
||
color: #333;
|
||
}
|
||
|
||
.data-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||
gap: 10px;
|
||
}
|
||
|
||
.data-item {
|
||
padding: 8px;
|
||
border: 1px solid #eee;
|
||
border-radius: 4px;
|
||
background-color: white;
|
||
}
|
||
|
||
.data-label {
|
||
font-weight: bold;
|
||
color: #555;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.data-value {
|
||
font-size: 20px;
|
||
/*color: #007bff;*/
|
||
color: #555;
|
||
}
|
||
|
||
.data-unit {
|
||
font-size: 12px;
|
||
color: #777;
|
||
}
|
||
|
||
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 id="connectionStatus" style="display: inline-block; padding: 5px 10px; border-radius: 4px; margin-left: 10px; background-color: red; color: white;">
|
||
未连接
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<div class="controls">
|
||
<div class="control-group">
|
||
<label for="interval">数据粒度:</label>
|
||
<select id="interval">
|
||
<option value="1min">1分钟(测试用)</option>
|
||
<option value="5min" selected>5分钟</option>
|
||
<option value="30min">30分钟</option>
|
||
<option value="1hour">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="queryLatestData()">查询最新数据</button>
|
||
<button onclick="exportData()">导出数据</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 最新数据显示区域 -->
|
||
<div class="latest-data">
|
||
<h3>最新传感器数据 <span id="latest-time" style="font-weight: normal; font-size: 14px;"></span></h3>
|
||
<div class="data-grid">
|
||
<div class="data-item">
|
||
<div class="data-label">温度</div>
|
||
<div class="data-value" id="latest-temperature">--</div>
|
||
<div class="data-unit">℃</div>
|
||
</div>
|
||
<div class="data-item">
|
||
<div class="data-label">湿度</div>
|
||
<div class="data-value" id="latest-humidity">--</div>
|
||
<div class="data-unit">%</div>
|
||
</div>
|
||
<div class="data-item">
|
||
<div class="data-label">风速</div>
|
||
<div class="data-value" id="latest-wind-speed">--</div>
|
||
<div class="data-unit">m/s</div>
|
||
</div>
|
||
<div class="data-item">
|
||
<div class="data-label">风向</div>
|
||
<div class="data-value" id="latest-wind-direction">--</div>
|
||
<div class="data-unit">°</div>
|
||
</div>
|
||
<div class="data-item">
|
||
<div class="data-label">大气压</div>
|
||
<div class="data-value" id="latest-atm-pressure">--</div>
|
||
<div class="data-unit">kPa</div>
|
||
</div>
|
||
<div class="data-item">
|
||
<div class="data-label">太阳辐射</div>
|
||
<div class="data-value" id="latest-solar-radiation">--</div>
|
||
<div class="data-unit">W/m²</div>
|
||
</div>
|
||
<div class="data-item">
|
||
<div class="data-label">累计雨量</div>
|
||
<div class="data-value" id="latest-rainfall">--</div>
|
||
<div class="data-unit">mm</div>
|
||
</div>
|
||
</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>
|
||
<th>大气压(kPa)</th>
|
||
<th>太阳辐射(W/m²)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tableBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let mainChart = null;
|
||
let connectionCheckTimer = null;
|
||
|
||
// 检查连接状态
|
||
function checkConnectionStatus() {
|
||
fetch('/api/status')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
const statusElem = document.getElementById('connectionStatus');
|
||
if (data.connected) {
|
||
statusElem.style.backgroundColor = 'green';
|
||
if (data.count > 1) {
|
||
statusElem.textContent = `已连接: ${data.ip}:${data.port} (共${data.count}个设备)`;
|
||
} else {
|
||
statusElem.textContent = `已连接: ${data.ip}:${data.port}`;
|
||
}
|
||
} else {
|
||
statusElem.style.backgroundColor = 'red';
|
||
statusElem.textContent = '未连接';
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('获取连接状态失败:', error);
|
||
const statusElem = document.getElementById('connectionStatus');
|
||
statusElem.style.backgroundColor = 'red';
|
||
statusElem.textContent = '状态未知';
|
||
});
|
||
}
|
||
|
||
// 初始化日期选择器
|
||
function initDatePickers() {
|
||
// 获取当前北京时间(UTC+8)
|
||
const now = new Date();
|
||
|
||
// 设置开始时间为当天的0点(北京时间)
|
||
const today = new Date(now);
|
||
today.setHours(0, 0, 0, 0);
|
||
|
||
document.getElementById('startDate').value = formatDateTime(today);
|
||
document.getElementById('endDate').value = formatDateTime(now);
|
||
}
|
||
|
||
// 格式化日期时间为中国时区(UTC+8)
|
||
function formatDateTime(date) {
|
||
// 转换为ISO字符串,但不使用Z(表示UTC),而是使用+08:00表示中国时区
|
||
const year = date.getFullYear();
|
||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||
const day = date.getDate().toString().padStart(2, '0');
|
||
const hours = date.getHours().toString().padStart(2, '0');
|
||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||
|
||
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
||
}
|
||
|
||
// 查询历史数据
|
||
function queryData() {
|
||
const interval = document.getElementById('interval').value;
|
||
const startDate = document.getElementById('startDate').value;
|
||
const endDate = document.getElementById('endDate').value;
|
||
|
||
// 确保时间格式符合后端要求,添加本地时区信息
|
||
const startDateTime = new Date(startDate).toISOString();
|
||
const endDateTime = new Date(endDate).toISOString();
|
||
|
||
fetch(`/api/data?interval=${interval}&start=${startDateTime}&end=${endDateTime}`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
updateChart(data);
|
||
updateTable(data);
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('获取数据失败,请检查网络连接');
|
||
});
|
||
}
|
||
|
||
// 获取最新传感器数据(不触发设备查询)
|
||
function fetchLatestSensorData() {
|
||
fetch('/api/raw/latest')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (!data || !data.timestamp) {
|
||
console.log('No latest sensor data available');
|
||
return;
|
||
}
|
||
|
||
// 更新最新数据显示
|
||
document.getElementById('latest-time').textContent = `(${data.formatted_time})`;
|
||
document.getElementById('latest-temperature').textContent = data.temperature.toFixed(1);
|
||
document.getElementById('latest-humidity').textContent = data.humidity.toFixed(1);
|
||
document.getElementById('latest-wind-speed').textContent = data.wind_speed.toFixed(2);
|
||
document.getElementById('latest-wind-direction').textContent = data.wind_direction_360;
|
||
document.getElementById('latest-atm-pressure').textContent = data.atm_pressure.toFixed(1);
|
||
document.getElementById('latest-solar-radiation').textContent = data.solar_radiation;
|
||
document.getElementById('latest-rainfall').textContent = data.rainfall;
|
||
})
|
||
.catch(error => {
|
||
console.error('获取最新传感器数据失败:', error);
|
||
});
|
||
}
|
||
|
||
// 触发设备进行数据查询
|
||
function triggerDeviceQuery() {
|
||
return fetch('/api/trigger-query')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
console.log('触发设备查询结果:', data);
|
||
if (data.success) {
|
||
// 如果成功触发查询,等待3秒后获取新数据
|
||
return new Promise(resolve => {
|
||
setTimeout(() => {
|
||
console.log('等待3秒后获取新数据');
|
||
resolve(data);
|
||
}, 3000);
|
||
});
|
||
}
|
||
return data;
|
||
})
|
||
.catch(error => {
|
||
console.error('触发设备查询失败:', error);
|
||
return { success: false, message: '触发设备查询失败' };
|
||
});
|
||
}
|
||
|
||
// 触发设备进行数据查询并获取最新数据
|
||
function triggerQueryAndFetchData() {
|
||
const latestDataElement = document.querySelector('.latest-data');
|
||
latestDataElement.style.opacity = 0.5;
|
||
|
||
// 触发设备查询
|
||
return triggerDeviceQuery()
|
||
.then(() => {
|
||
// 获取最新传感器数据
|
||
return fetchLatestSensorData();
|
||
})
|
||
.then(() => {
|
||
// 恢复最新数据区域的不透明度
|
||
latestDataElement.style.opacity = 1;
|
||
})
|
||
.catch(error => {
|
||
console.error('触发查询并获取数据失败:', error);
|
||
// 恢复最新数据区域的不透明度
|
||
latestDataElement.style.opacity = 1;
|
||
});
|
||
}
|
||
|
||
// 查询最新数据
|
||
function queryLatestData() {
|
||
const interval = document.getElementById('interval').value;
|
||
|
||
// 根据粒度调整查询范围
|
||
let hours = 1;
|
||
if (interval === "1min") {
|
||
hours = 0.5; // 30分钟
|
||
} else if (interval === "5min") {
|
||
hours = 1; // 1小时
|
||
} else if (interval === "30min") {
|
||
hours = 6; // 6小时
|
||
} else {
|
||
hours = 24; // 1天
|
||
}
|
||
|
||
// 计算最近时间范围 - 使用当天0点到现在
|
||
const endTime = new Date();
|
||
const startTime = new Date(endTime);
|
||
startTime.setHours(0, 0, 0, 0); // 设置为当天0点
|
||
|
||
// 确保时间格式符合后端要求
|
||
const startDateTime = startTime.toISOString();
|
||
const endDateTime = endTime.toISOString();
|
||
|
||
// 加载状态指示
|
||
document.getElementById('mainChart').style.opacity = 0.5;
|
||
|
||
// 首先触发设备查询并获取最新数据
|
||
triggerQueryAndFetchData()
|
||
.then(() => {
|
||
// 获取聚合数据
|
||
return fetch(`/api/latest?interval=${interval}&start=${startDateTime}&end=${endDateTime}`);
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
updateChart(data);
|
||
updateTable(data);
|
||
|
||
// 恢复正常显示
|
||
document.getElementById('mainChart').style.opacity = 1;
|
||
|
||
// 自动更新日期选择器为最近查询的时间范围
|
||
document.getElementById('startDate').value = formatDateTime(startTime);
|
||
document.getElementById('endDate').value = formatDateTime(endTime);
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('获取最新数据失败,请检查网络连接');
|
||
// 恢复正常显示
|
||
document.getElementById('mainChart').style.opacity = 1;
|
||
});
|
||
}
|
||
|
||
// 加载历史数据(不触发设备查询)
|
||
function loadInitialData() {
|
||
const interval = document.getElementById('interval').value;
|
||
|
||
// 计算最近时间范围 - 使用当天0点到现在
|
||
const endTime = new Date();
|
||
const startTime = new Date(endTime);
|
||
startTime.setHours(0, 0, 0, 0); // 设置为当天0点
|
||
|
||
// 确保时间格式符合后端要求
|
||
const startDateTime = startTime.toISOString();
|
||
const endDateTime = endTime.toISOString();
|
||
|
||
// 获取聚合数据
|
||
fetch(`/api/latest?interval=${interval}&start=${startDateTime}&end=${endDateTime}`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
updateChart(data);
|
||
updateTable(data);
|
||
|
||
// 自动更新日期选择器为最近查询的时间范围
|
||
document.getElementById('startDate').value = formatDateTime(startTime);
|
||
document.getElementById('endDate').value = formatDateTime(endTime);
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('获取历史数据失败,请检查网络连接');
|
||
});
|
||
}
|
||
|
||
// 更新图表
|
||
function updateChart(data) {
|
||
const ctx = document.getElementById('mainChart').getContext('2d');
|
||
|
||
if (mainChart) {
|
||
mainChart.destroy();
|
||
}
|
||
|
||
// 按时间正序排列数据(从早到晚)
|
||
data.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
|
||
|
||
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');
|
||
});
|
||
|
||
// 是否使用自适应范围
|
||
const useAdaptiveScale = 1;
|
||
|
||
// 计算降雨量和温度的范围
|
||
let rainfallMin = 0;
|
||
let rainfallMax = 50;
|
||
let tempMin = -10;
|
||
let tempMax = 40;
|
||
|
||
if (useAdaptiveScale && data.length > 0) {
|
||
// 找出温度的最小值和最大值,并添加一些边距
|
||
const temps = data.map(item => item.avg_temperature);
|
||
tempMin = Math.floor(Math.min(...temps) - 5);
|
||
tempMax = Math.ceil(Math.max(...temps) + 5);
|
||
|
||
// 找出降雨量的最大值,并添加一些边距
|
||
const rainfalls = data.map(item => item.rainfall);
|
||
rainfallMax = Math.ceil(Math.max(...rainfalls) * 1.2) || 10; // 如果最大值是0,则默认为10
|
||
}
|
||
|
||
// 数据已经在DAO层正确转换了单位
|
||
// 不需要再做额外的单位转换
|
||
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
|
||
},
|
||
// 设置降雨量的范围
|
||
min: rainfallMin,
|
||
max: rainfallMax,
|
||
suggestedMax: Math.min(10, rainfallMax)
|
||
},
|
||
'y-temp': {
|
||
type: 'linear',
|
||
position: 'right',
|
||
title: {
|
||
display: true,
|
||
text: '温度(℃)'
|
||
},
|
||
// 设置温度的范围
|
||
min: tempMin,
|
||
max: tempMax,
|
||
suggestedMin: Math.max(0, tempMin),
|
||
suggestedMax: Math.min(30, tempMax)
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// 更新表格
|
||
function updateTable(data) {
|
||
const tbody = document.getElementById('tableBody');
|
||
tbody.innerHTML = '';
|
||
|
||
// 按时间倒序排列数据(从晚到早),这样最新的数据在表格顶部
|
||
const sortedData = [...data].sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
||
|
||
sortedData.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');
|
||
|
||
// 根据原始TCP服务器中的单位换算
|
||
// 原始的风速是实际值的100倍
|
||
// 温度和湿度是实际值的10倍
|
||
// 大气压是实际值的10倍
|
||
// 太阳辐射是原始值
|
||
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(2)}</td>
|
||
<td>${item.atm_pressure ? item.atm_pressure.toFixed(1) : 'N/A'}</td>
|
||
<td>${item.solar_radiation ? item.solar_radiation.toFixed(0) : 'N/A'}</td>
|
||
`;
|
||
tbody.appendChild(row);
|
||
});
|
||
}
|
||
|
||
// 导出数据
|
||
function exportData() {
|
||
// 从表格中获取完整数据
|
||
const tableRows = document.querySelectorAll('#tableBody tr');
|
||
let csv = '时间,降雨量(mm),温度(℃),湿度(%),风速(m/s),大气压(kPa),太阳辐射(W/m²)\n';
|
||
|
||
tableRows.forEach(row => {
|
||
const cells = row.querySelectorAll('td');
|
||
const rowData = [
|
||
cells[0].textContent, // 时间
|
||
cells[1].textContent, // 降雨量
|
||
cells[2].textContent, // 温度
|
||
cells[3].textContent, // 湿度
|
||
cells[4].textContent, // 风速
|
||
cells[5].textContent, // 大气压
|
||
cells[6].textContent // 太阳辐射
|
||
];
|
||
csv += rowData.join(',') + '\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();
|
||
loadInitialData(); // 加载历史数据,但不触发设备查询
|
||
fetchLatestSensorData(); // 获取最新传感器原始数据,但不触发设备查询
|
||
|
||
// 每30秒检查一次连接状态
|
||
checkConnectionStatus();
|
||
connectionCheckTimer = setInterval(checkConnectionStatus, 30000);
|
||
|
||
// 每分钟自动刷新最新传感器数据(不触发设备查询)
|
||
setInterval(fetchLatestSensorData, 60000);
|
||
});
|
||
|
||
// 页面卸载时清除定时器
|
||
window.addEventListener('beforeunload', function() {
|
||
if (connectionCheckTimer) {
|
||
clearInterval(connectionCheckTimer);
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |