RTU/test/web_root/index.html

294 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; }
.table-container { margin-bottom: 20px; }
.table-title { font-size: 16px; font-weight: bold; margin-bottom: 8px; color: #2c3e50; }
.table-wrapper {
max-height: 320px;
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; align-items: flex-end; }
.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>setting_zone</label>
<input id="setting_zone" value="0" placeholder="0">
</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>
<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 信号(当前定值区:<span id="currentZone">0</span></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_val</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');
const currentZoneSpan = document.getElementById('currentZone');
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 setting_zone = document.getElementById('setting_zone').value.trim();
currentZoneSpan.textContent = setting_zone;
const types = ['out', 'in', 'yk', 'ao', 'param'];
types.forEach(type => {
const arr = root[type];
const body = tableBodies[type];
body.innerHTML = '';
if (!Array.isArray(arr)) return;
arr.forEach((item, index) => {
if (!item.saddr) return;
if (type === 'param') {
const zoneList = item.setting_zone_list || [];
const match = zoneList.find(z => z.id === setting_zone);
if (!match) return;
const tr = body.insertRow();
tr.innerHTML = `
<td>${index+1}</td>
<td>${item.saddr}</td>
<td>${item.desc || '-'}</td>
<td>${item.type || '-'}</td>
<td>${match.val || '-'}</td>
<td>${ctrlTypeMap[item.ctrl_type] || item.ctrl_type}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
<td>${item.unit || '-'}</td>
<td>${match.default_val || '-'}</td>
`;
} else {
addNormalRow(type, item, index+1);
}
});
});
}
function addNormalRow(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>
`;
if (type === 'yk') html += `<td>${ctrlTypeMap[item.ctrl_type] || item.ctrl_type}</td>`;
if (type === 'ao') {
html += `
<td>${ctrlTypeMap[item.ctrl_type] || 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 setting_zone = document.getElementById('setting_zone').value.trim();
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,
setting_zone: setting_zone,
signal_data: data
};
ws.send(JSON.stringify(msg));
addLog(`sent: ${JSON.stringify(msg)}`, 'send');
parseData(JSON.parse(ws._lastData || '{}'));
}
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>