RTU/test/web_root/index.html

288 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XTU WEB DEBUG - Signal Monitor</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
.container { max-width: 1400px; margin: 0 auto; }
h1 { color: #333; text-align: center; }
.card { background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
input, select { padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; }
.saddr-input { width: 280px; }
select { width: 140px; }
button { padding: 8px 16px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
button.secondary { background: #2196F3; }
#status { padding: 6px 12px; border-radius: 20px; font-weight: bold; }
.status-connected { background: #4CAF50; color: white; }
.status-disconnected { background: #f44336; color: white; }
#log { background: #f8f9fa; height: 150px; padding: 10px; overflow-y: auto; font-family: monospace; font-size: 12px; }
.log-entry { margin: 4px 0; }
.log-receive { color: #2196F3; }
.log-send { color: #4CAF50; }
.log-error { color: #f44336; }
/* 表格容器:固定高度 + 滚动条最多显示8行 */
.table-container { margin-bottom: 20px; }
.table-title { font-size: 16px; font-weight: bold; margin-bottom: 8px; color: #2c3e50; }
.table-wrapper {
max-height: 320px; /* 刚好显示8行 */
overflow-y: auto; /* 超出自动滚动 */
border: 1px solid #eee;
border-radius: 4px;
}
.signalTable { width: 100%; border-collapse: collapse; background: white; }
.signalTable th {
position: sticky;
top: 0;
background: #2c3e50;
color: white;
padding: 12px;
text-align: left;
z-index: 10;
}
.signalTable td { padding: 10px; border-bottom: 1px solid #eee; }
.signalTable tr:hover { background: #f5f5f5; }
.form-row { display: flex; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.form-group { display: flex; flex-direction: column; }
</style>
</head>
<body>
<div class="container">
<h1>XTU WEB DEBUG - Signal Monitor</h1>
<div class="card">
<div class="form-row">
<div class="form-group">
<label>saddr *</label>
<input id="saddr" class="saddr-input" placeholder="iec.run_cnt">
</div>
<div class="form-group">
<label>signal_type *</label>
<select id="signal_type">
<option value="out">out</option>
<option value="in">in</option>
<option value="yk">yk</option>
<option value="ao">ao</option>
<option value="param">param</option>
</select>
</div>
<div class="form-group">
<label>curd *</label>
<select id="curd">
<option value="add">add</option>
<option value="set">set</option>
<option value="del">del</option>
</select>
</div>
<div class="form-group">
<label>signal_data</label>
<input id="signal_data" placeholder="(can empty)">
</div>
</div>
<button onclick="sendSignal()">Send</button>
<button onclick="clearForm()" class="secondary">Clear Form</button>
<button onclick="clearAllTables()" class="secondary">Clear All Tables</button>
</div>
<div class="card">
WebSocket Status: <span id="status" class="status-disconnected">Disconnected</span>
<button onclick="connectWS()" class="secondary">Connect</button>
</div>
<!-- 4个独立信号表格 + 滚动容器 -->
<div class="card">
<div class="table-container">
<div class="table-title">OUT 信号</div>
<div class="table-wrapper">
<table class="signalTable">
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th></tr></thead>
<tbody id="outBody"></tbody>
</table>
</div>
</div>
<div class="table-container">
<div class="table-title">IN 信号</div>
<div class="table-wrapper">
<table class="signalTable">
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th></tr></thead>
<tbody id="inBody"></tbody>
</table>
</div>
</div>
<div class="table-container">
<div class="table-title">YK 信号</div>
<div class="table-wrapper">
<table class="signalTable">
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th><th>ctrl_type</th></tr></thead>
<tbody id="ykBody"></tbody>
</table>
</div>
</div>
<div class="table-container">
<div class="table-title">AO 信号</div>
<div class="table-wrapper">
<table class="signalTable">
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th><th>ctrl_type</th><th>min</th><th>max</th><th>step</th><th>unit</th><th>default</th></tr></thead>
<tbody id="aoBody"></tbody>
</table>
</div>
</div>
<div class="table-container">
<div class="table-title">PARAM 信号</div>
<div class="table-wrapper">
<table class="signalTable">
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th><th>ctrl_type</th><th>min</th><th>max</th><th>step</th><th>unit</th><th>default</th></tr></thead>
<tbody id="paramBody"></tbody>
</table>
</div>
</div>
</div>
<div class="card">
<div id="log"></div>
</div>
</div>
<script>
let ws = null;
const tableBodies = {
out: document.getElementById('outBody'),
in: document.getElementById('inBody'),
yk: document.getElementById('ykBody'),
ao: document.getElementById('aoBody'),
param: document.getElementById('paramBody')
};
// 控制类型数字转文字映射
const ctrlTypeMap = {
0: "只读",
1: "直控",
2: "选控"
};
const log = document.getElementById('log');
const status = document.getElementById('status');
function addLog(msg, type = 'info') {
const t = new Date().toLocaleTimeString();
log.innerHTML += `<div class="log-entry"><span>[${t}]</span> <span class="log-${type}">${msg}</span></div>`;
log.scrollTop = log.scrollHeight;
}
function connectWS() {
if (ws) return;
const url = `${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${location.host}/ws`;
ws = new WebSocket(url);
ws.onopen = () => { status.textContent = 'Connected'; status.className = 'status-connected'; addLog('connected', 'info'); };
ws.onclose = () => { status.textContent = 'Disconnected'; status.className = 'status-disconnected'; ws = null; setTimeout(connectWS, 3000); };
ws.onerror = () => addLog('error', 'error');
ws.onmessage = (e) => {
try {
const data = JSON.parse(e.data);
addLog("received data", "receive");
parseData(data);
} catch (e) {
addLog("parse data error: " + e.message, "error");
}
};
}
// 每次收到数据,直接清空对应表格,重新渲染
function parseData(root) {
const types = ['out', 'in', 'yk', 'ao', 'param'];
types.forEach(type => {
const arr = root[type];
const body = tableBodies[type];
// 每次先清空表格
body.innerHTML = '';
if (Array.isArray(arr)) {
arr.forEach((item, index) => {
if (item.saddr) {
addRow(type, item, index + 1);
}
});
}
});
}
// 转换控制类型
function getCtrlText(val){
if(val === undefined || val === null) return "-";
return ctrlTypeMap[val] || val;
}
// 新增行
function addRow(type, item, index) {
const body = tableBodies[type];
const tr = body.insertRow();
let html = `
<td>${index}</td>
<td>${item.saddr}</td>
<td>${item.desc || '-'}</td>
<td>${item.type || '-'}</td>
<td>${item.val || '-'}</td>
`;
// yk 增加控制权限文字
if (type === 'yk') {
html += `<td>${getCtrlText(item.ctrl_type)}</td>`;
}
// ao 增加完整参数列
if (type === 'ao') {
html += `
<td>${getCtrlText(item.ctrl_type)}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
<td>${item.unit || '-'}</td>
<td>${item.default || '-'}</td>
`;
}
// param 增加完整参数列
if (type === 'param') {
html += `
<td>${getCtrlText(item.ctrl_type)}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
<td>${item.unit || '-'}</td>
<td>${item.default || '-'}</td>
`;
}
tr.innerHTML = html;
}
function sendSignal() {
const saddr = document.getElementById('saddr').value.trim();
const type = document.getElementById('signal_type').value;
const curd = document.getElementById('curd').value;
const data = document.getElementById('signal_data').value.trim();
if (!saddr) return addLog('saddr required', 'error');
if (!ws || ws.readyState !== 1) return addLog('not connected', 'error');
const msg = { saddr, signal_type: type, curd, signal_data: data };
ws.send(JSON.stringify(msg));
addLog(`sent: ${JSON.stringify(msg)}`, 'send');
}
function clearForm() {
document.getElementById('saddr').value = '';
document.getElementById('signal_data').value = '';
}
function clearAllTables() {
Object.values(tableBodies).forEach(body => body.innerHTML = '');
addLog('all tables cleared', 'info');
}
connectWS();
</script>
</body>
</html>