feat: 优化页面

This commit is contained in:
yarnom 2025-09-09 15:58:53 +08:00
parent 480c0f7404
commit 6025bdcbba

View File

@ -79,6 +79,15 @@
background-color: #0056b3;
}
/* 覆盖设备列表按钮的全局 button 样式,确保文字不是白色且背景为白色 */
#deviceListInline button {
background-color: #ffffff;
color: #1f2937; /* tailwind: text-gray-800 */
}
#deviceListInline button:hover {
background-color: #f9fafb; /* tailwind: hover:bg-gray-50 */
}
.chart-container {
margin-bottom: 20px;
border: 1px solid #ddd;
@ -154,16 +163,24 @@
<body class="text-[14px] md:text-[15px]">
<div class="header p-2 text-center border-b border-gray-200">
<h1 class="text-2xl md:text-3xl font-semibold py-7">测斜仪数据</h1>
</div>
<div class="content-narrow py-5">
<div class="system-info bg-gray-100 p-3 mb-5 rounded text-sm leading-6">
<strong>在线设备:</strong> <span id="onlineDevices">0</span>
<span class="mx-2">|</span>
<strong>总设备:</strong> <a href="#" id="showDeviceList" class="text-blue-600 hover:text-blue-700"><span id="totalDevices">0</span></a>
</div>
<!-- 设备列表(内联显示) -->
<div id="devicesInline" class="mb-5 p-3 border rounded bg-white">
<div class="flex items-center justify-between mb-3">
<div class="flex items-center gap-4">
<strong class="text-sm text-gray-700">设备列表</strong>
</div>
<span class="text-xs text-gray-600">最后一次在线时间</span>
</div>
<div id="deviceListInline" class="flex flex-col gap-2"></div>
</div>
<div class="controls flex flex-col gap-4 mb-5 p-4 border rounded bg-white">
<div class="control-row">
<div class="control-group">
<label for="deviceInput" class="text-sm text-gray-600">设备编号:</label>
@ -185,6 +202,7 @@
</select>
</div>
</div>
<div class="control-row">
<div class="control-group">
<label for="limitSelect" class="text-sm text-gray-600">显示记录数:</label>
@ -209,9 +227,10 @@
<button id="queryBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded text-sm">查询数据</button>
</div>
</div>
</div>
<!-- 图表区域 -->
<div class="chart-container rounded-md">
@ -237,24 +256,6 @@
</tbody>
</table>
</div>
<!-- 设备列表弹窗 -->
<div id="deviceModal" class="hidden fixed inset-0 bg-black/30 z-[2000] items-center justify-center">
<div class="bg-white w-[90%] max-w-[720px] max-h-[70vh] rounded-lg shadow-2xl flex flex-col">
<div class="px-5 py-3 border-b border-gray-200 relative">
<strong class="text-sm">选择设备</strong>
<button id="closeDeviceModal" class="absolute right-5 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700"></button>
</div>
<div id="deviceList" class="flex-1 overflow-y-auto py-2"></div>
<div class="px-3 py-2 border-t border-gray-200 flex items-center justify-between bg-white">
<div class="flex items-center gap-3 text-xs text-gray-600">
<button id="prevPage" class="px-2 py-1 border border-gray-300 rounded bg-white hover:bg-gray-50">&lt; 上一页</button>
<span><span id="currentPage">1</span> 页,共 <span id="totalPages">1</span></span>
<button id="nextPage" class="px-2 py-1 border border-gray-300 rounded bg-white hover:bg-gray-50">下一页 &gt;</button>
</div>
</div>
</div>
</div>
</div>
<!-- 内联JavaScript -->
@ -266,8 +267,6 @@
let devices = [];
let selectedDeviceID = '';
let currentPage = 1;
let itemsPerPage = 10;
let selectedMetric = 'x';
@ -314,19 +313,7 @@
const metricSelect = document.getElementById('metricSelect');
if (metricSelect) metricSelect.addEventListener('change', function(){ selectedMetric = this.value; updateChart(currentSensorData); });
const openBtn = document.getElementById('openDeviceModal');
const showList = document.getElementById('showDeviceList');
const closeBtn = document.getElementById('closeDeviceModal');
if (openBtn) openBtn.addEventListener('click', openDeviceModal);
if (showList) showList.addEventListener('click', function(e){ e.preventDefault(); openDeviceModal(); });
if (closeBtn) closeBtn.addEventListener('click', closeDeviceModal);
const prev = document.getElementById('prevPage');
const next = document.getElementById('nextPage');
if (prev) prev.addEventListener('click', function(){ updateDeviceList(currentPage - 1); });
if (next) next.addEventListener('click', function(){ updateDeviceList(currentPage + 1); });
const modal = document.getElementById('deviceModal');
if (modal) modal.addEventListener('click', function(e){ if (e.target === modal) { closeDeviceModal(); }});
// 统计信息已融合到设备列表区域,无需额外滚动链接
}
function findDeviceByInput() {
@ -448,65 +435,60 @@
});
}
function openDeviceModal() {
const modal = document.getElementById('deviceModal');
if (modal) {
modal.classList.remove('hidden');
modal.classList.add('flex');
updateDeviceList(1);
}
}
function closeDeviceModal() {
const modal = document.getElementById('deviceModal');
if (modal) {
modal.classList.add('hidden');
modal.classList.remove('flex');
}
}
function updateDeviceList(page) {
if (!devices || devices.length === 0) return;
const totalPages = Math.max(1, Math.ceil(devices.length / itemsPerPage));
currentPage = Math.min(Math.max(1, page), totalPages);
const cur = document.getElementById('currentPage');
const tot = document.getElementById('totalPages');
if (cur) cur.textContent = currentPage;
if (tot) tot.textContent = totalPages;
const prev = document.getElementById('prevPage');
const next = document.getElementById('nextPage');
if (prev) prev.disabled = currentPage <= 1;
if (next) next.disabled = currentPage >= totalPages;
const startIdx = (currentPage - 1) * itemsPerPage;
const endIdx = Math.min(startIdx + itemsPerPage, devices.length);
const list = devices.slice(startIdx, endIdx);
const container = document.getElementById('deviceList');
// 渲染内联设备列表(按最后上报排序,新→旧)
function renderDeviceListInline() {
const container = document.getElementById('deviceListInline');
if (!container) return;
container.innerHTML = '';
list.forEach(d => {
const onlineDot = d.online ? '<span class="inline-block w-2 h-2 rounded-full bg-green-500 mr-2"></span>' : '<span class="inline-block w-2 h-2 rounded-full bg-gray-400 mr-2"></span>';
const lastSeen = d.last_seen ? new Date(d.last_seen).toLocaleString() : '—';
const item = document.createElement('div');
item.className = 'device-item px-5 py-3 border-b border-gray-100 flex justify-between items-center cursor-pointer hover:bg-gray-50';
item.innerHTML = `
<div class="flex items-center gap-2">
${onlineDot}
<span class="font-mono">${d.device_id}</span>
<span class="text-xs text-gray-500">(探头: ${d.sensor_count})</span>
</div>
<div class="text-xs text-gray-500">最后上报: ${lastSeen}</div>
`;
if (!devices || devices.length === 0) {
const empty = document.createElement('div');
empty.className = 'text-gray-500 text-sm';
empty.textContent = '没有设备';
container.appendChild(empty);
return;
}
const view = devices.slice().sort((a,b) => {
const ta = a.last_seen ? new Date(a.last_seen).getTime() : 0;
const tb = b.last_seen ? new Date(b.last_seen).getTime() : 0;
return tb - ta; // 新→旧
});
view.forEach(d => {
const onlineDot = d.online ? '<span class=\"inline-block w-2 h-2 rounded-full bg-green-500\"></span>' : '<span class=\"inline-block w-2 h-2 rounded-full bg-gray-400\"></span>';
const lastSeen = (() => {
if (!d.last_seen) return '—';
const dt = new Date(d.last_seen);
const y = dt.getFullYear();
const m = (dt.getMonth()+1).toString().padStart(2,'0');
const day = dt.getDate().toString().padStart(2,'0');
const hh = dt.getHours().toString().padStart(2,'0');
const mm = dt.getMinutes().toString().padStart(2,'0');
const ss = dt.getSeconds().toString().padStart(2,'0');
return `${y}/${m}/${day} ${hh}:${mm}:${ss}`;
})();
const isSelected = d.device_id === selectedDeviceID;
const item = document.createElement('button');
item.type = 'button';
// 一行一个,左右布局:左侧设备信息,右侧最后在线时间
item.className = 'w-full px-3 py-2 border rounded text-sm bg-white hover:bg-gray-50 flex items-center justify-between transition text-gray-800 ' + (isSelected ? 'ring-2 ring-blue-400' : '');
const leftHtml = `<span class=\"flex items-center gap-2\">${onlineDot}
<span class=\"font-mono\">${d.device_id}</span>
<span class=\"text-xs text-gray-600\">(探头: ${d.sensor_count})</span></span>`;
const rightHtml = `<span class=\"text-xs text-gray-700 font-mono\">${lastSeen}</span>`;
item.innerHTML = leftHtml + rightHtml;
item.addEventListener('click', () => {
selectedDeviceID = d.device_id;
const input = document.getElementById('deviceInput');
if (input) input.value = selectedDeviceID;
closeDeviceModal();
renderDeviceListInline();
loadSensors();
});
container.appendChild(item);
});
}
// updateDeviceList 已移除,改用 renderDeviceListInline()
function loadDevices() {
fetch('/api/devices')
.then(r => r.json())
@ -516,6 +498,7 @@
if (total) total.textContent = devices.length;
const onlineEl = document.getElementById('onlineDevices');
if (onlineEl) onlineEl.textContent = devices.filter(d => d.online).length;
renderDeviceListInline();
// 默认选择 1513343 设备(若存在)并自动加载
if (!selectedDeviceID) {