diff --git a/web/app.js b/web/app.js
index c014926..f3909e4 100644
--- a/web/app.js
+++ b/web/app.js
@@ -1,4 +1,4 @@
-const state = {
+const state = {
sources: [],
selectedSourceId: null,
tree: [],
@@ -155,6 +155,7 @@ async function selectSource(sourceId) {
state.selectedSourceId = sourceId;
state.selectedNodeIds.clear();
state.pointsPage = 1;
+ renderSources();
renderSelectedNodes();
await loadPoints();
await loadTree();
@@ -266,8 +267,8 @@ async function loadPoints() {
state.pointEls.clear();
pointList.innerHTML = '';
if (!items.length) {
- pointList.textContent = '暂无 Points';
- pointsPageInfo.textContent = `第 ${state.pointsPage} 页 / 共 1 页`;
+ pointList.innerHTML = '
| 暂无 Points |
';
+ pointsPageInfo.textContent = `${state.pointsPage} / 1`;
prevPointsBtn.disabled = true;
nextPointsBtn.disabled = true;
setStatus('Ready');
@@ -278,49 +279,46 @@ async function loadPoints() {
const monitor = item.point_monitor || null;
state.points.set(point.id, { point, monitor });
- const box = document.createElement('div');
- box.className = 'list-item';
+ const tr = document.createElement('tr');
- const row = document.createElement('div');
- row.className = 'row';
- row.innerHTML = `${point.name}`;
+ const tdName = document.createElement('td');
+ tdName.innerHTML = `${point.name}
${point.node_id}
`;
+
+ const tdValue = document.createElement('td');
+ const value = document.createElement('span');
+ value.className = 'point-value';
+ value.textContent = formatValue(monitor);
+ tdValue.appendChild(value);
const quality = monitor ? (monitor.quality || 'unknown').toLowerCase() : 'unknown';
+ const tdQuality = document.createElement('td');
const qualityBadge = document.createElement('span');
qualityBadge.className = `badge quality-${quality}`;
qualityBadge.textContent = quality.toUpperCase();
- row.appendChild(qualityBadge);
+ tdQuality.appendChild(qualityBadge);
+ const tdTime = document.createElement('td');
+ const ts = document.createElement('span');
+ ts.className = 'muted';
+ ts.textContent = monitor && monitor.timestamp ? monitor.timestamp : '--';
+ tdTime.appendChild(ts);
+
+ const tdAction = document.createElement('td');
const deleteBtn = document.createElement('button');
deleteBtn.className = 'danger';
- deleteBtn.textContent = '删除';
- deleteBtn.onclick = () => deletePoint(point.id);
- row.appendChild(deleteBtn);
+ deleteBtn.textContent = '×';
+ deleteBtn.title = '删除';
+ deleteBtn.style.cssText = 'width:22px;height:22px;padding:0;font-size:14px;';
+ deleteBtn.onclick = (e) => { e.stopPropagation(); deletePoint(point.id); };
+ tdAction.appendChild(deleteBtn);
- const valueRow = document.createElement('div');
- valueRow.className = 'row';
- const value = document.createElement('div');
- value.className = 'value';
- value.textContent = formatValue(monitor);
- const ts = document.createElement('div');
- ts.className = 'muted';
- ts.textContent = monitor && monitor.timestamp ? monitor.timestamp : '';
- valueRow.appendChild(value);
- valueRow.appendChild(ts);
+ tr.append(tdName, tdValue, tdQuality, tdTime, tdAction);
+ pointList.appendChild(tr);
- const meta = document.createElement('div');
- meta.className = 'muted';
- meta.textContent = `${point.id} / node: ${point.node_id}`;
-
- box.appendChild(row);
- box.appendChild(valueRow);
- box.appendChild(meta);
- pointList.appendChild(box);
-
- state.pointEls.set(point.id, { box, value, qualityBadge, ts });
+ state.pointEls.set(point.id, { box: tr, value, qualityBadge, ts });
});
const totalPages = Math.max(1, Math.ceil(state.pointsTotal / state.pointsPageSize));
- pointsPageInfo.textContent = `第 ${state.pointsPage} 页 / 共 ${totalPages} 页`;
+ pointsPageInfo.textContent = `${state.pointsPage} / ${totalPages}`;
prevPointsBtn.disabled = state.pointsPage <= 1;
nextPointsBtn.disabled = state.pointsPage >= totalPages;
setStatus('Ready');
diff --git a/web/index.html b/web/index.html
index 90b071f..9d40ae6 100644
--- a/web/index.html
+++ b/web/index.html
@@ -1,9 +1,9 @@
-
+
- PLC Control UI
+ PLC Control
@@ -14,41 +14,58 @@
-
+
Sources
-
+