/* ========================================================================
* PLC 调试页面 — 指示灯/按键 + out 绑定 + 勾选删除 + 增量刷新
* ======================================================================== */
var PlcDebugLeds = []; // [{saddr:'', desc:'', val:0}]
var PlcDebugButtons = []; // [{saddr:'', desc:'', val:0}]
var PlcDebugPage = (function() {
var outSignals = [];
var ledChecked = {}; // {idx: true}
var btnChecked = {}; // {idx: true}
var signalChecked = {}; // {idx: true} 信号选择列勾选
function getOutSignals() {
if (typeof App !== 'undefined' && App.getSignalData) {
var out = App.getSignalData('out');
if (Array.isArray(out) && out.length > 0) return out;
}
return outSignals;
}
function showSignalPicker(callback) {
var sigs = getOutSignals();
if (sigs.length === 0) { alert('暂无 out 已注册信号,请先在注册(out)页面添加信号'); return; }
var html = '
'
+ '
绑定 out 信号 '
+ '
';
for (var i = 0; i < sigs.length; i++) {
var s = sigs[i];
html += '
'
+ '' + fmtVal(s.saddr) + ' '
+ (s.desc ? ' ' + fmtVal(s.desc) + ' ' : '')
+ '' + (s.val !== undefined ? fmtVal(s.val) : '-') + ' '
+ '
';
}
html += '
取消 ';
var div = document.createElement('div');
div.innerHTML = html;
document.body.appendChild(div.firstElementChild);
document.getElementById('plc-modal-cancel').onclick = closeModal;
var rows = document.querySelectorAll('.plc-sig-row');
for (var j = 0; j < rows.length; j++) {
rows[j].onclick = function() {
var saddr = this.getAttribute('data-saddr');
var desc = this.getAttribute('data-desc') || '';
closeModal();
if (confirm('确定绑定信号 ' + saddr + ' 吗?')) { callback(saddr, desc); }
};
}
}
function closeModal() { var m = document.getElementById('plc-modal'); if (m) m.remove(); }
function refreshOutData() {
var sigs = getOutSignals();
if (Array.isArray(sigs)) outSignals = sigs;
for (var i = 0; i < PlcDebugLeds.length; i++) {
var found = findSignal(PlcDebugLeds[i].saddr);
PlcDebugLeds[i].val = found ? found.val : 0;
}
for (var j = 0; j < PlcDebugButtons.length; j++) {
var found2 = findSignal(PlcDebugButtons[j].saddr);
PlcDebugButtons[j].val = found2 ? found2.val : 0;
}
}
function findSignal(saddr) {
for (var i = 0; i < outSignals.length; i++) {
if (outSignals[i].saddr === saddr) return outSignals[i];
}
return null;
}
function countChecked(obj) { var n = 0; for (var k in obj) { if (obj.hasOwnProperty(k)) n++; } return n; }
function updateDelBtn() {
var ledCnt = countChecked(ledChecked);
var btnCnt = countChecked(btnChecked);
var total = ledCnt + btnCnt;
var el = document.getElementById('plc-del-btn');
if (el) {
el.textContent = '🗑 删除选中' + (total > 0 ? '(' + total + ')' : '');
el.disabled = (total === 0);
}
}
/* ---- 增量刷新: 只更新 val 文本, 不重建 DOM (add/del 时才全重建) ---- */
function incrRefresh() {
refreshOutData();
// 指示灯: 逐个更新 val 文本和样式
for (var i = 0; i < PlcDebugLeds.length; i++) {
var valEl = document.getElementById('led-val-' + i);
var iconEl = document.getElementById('led-icon-' + i);
var on = (parseFloat(PlcDebugLeds[i].val) > 0);
if (valEl) valEl.textContent = '(' + PlcDebugLeds[i].val + ')';
if (valEl) valEl.style.color = on ? '#4CAF50' : '#999';
if (iconEl) { iconEl.className = 'plc-led' + (on ? ' plc-led-on' : ''); }
}
// 按键: 逐个更新 val 文本
for (var j = 0; j < PlcDebugButtons.length; j++) {
var bValEl = document.getElementById('btn-val-' + j);
if (bValEl) bValEl.textContent = '(' + PlcDebugButtons[j].val + ')';
}
}
function renderAll() {
refreshOutData();
var html = '';
html += ''
+ '⚙ 手动置数 '
+ '🔄 刷新 '
+ ' '
+ '🗑 删除选中 '
+ '🚪 退出置数 '
+ '
';
html += ''
+ '💡 增加指示灯 '
+ ' '
+ '🔘 增加按键 '
+ '
';
html += '';
// 指示灯
html += '
💡 指示灯 ';
for (var i = 0; i < PlcDebugLeds.length; i++) {
var led = PlcDebugLeds[i];
var on = (parseFloat(led.val) > 0);
var chk = ledChecked[i] ? ' checked' : '';
html += '
'
+ ' '
+ '💡 '
+ ''
+ (led.saddr ? '' + fmtVal(led.saddr) + ' (' + fmtVal(led.val) + ') '
+ (led.desc ? ' ' + fmtVal(led.desc) + ' ' : '')
: '未绑定 ')
+ '
';
}
html += '
';
// 信号选择列
html += '
';
html += '
📋 Out 信号 ';
html += '
';
html += '← ';
html += '→ ';
html += '
';
html += '
';
if (outSignals.length === 0) {
html += '
暂无 out 信号
';
}
else
{
for (var s = 0; s < outSignals.length; s++) {
var sig = outSignals[s];
var sigChk = signalChecked[s] ? ' checked' : '';
html += '
'
+ ' '
+ '' + fmtVal(sig.saddr) + ' '
+ (sig.desc ? '' + fmtVal(sig.desc) + ' ' : '')
+ '' + fmtVal(sig.val) + ' '
+ '
';
}
}
html += '
';
// 按键
html += '
🔘 按键 ';
for (var j = 0; j < PlcDebugButtons.length; j++) {
var btn = PlcDebugButtons[j];
var chk2 = btnChecked[j] ? ' checked' : '';
html += '
'
+ ' '
+ '🔘 '
+ ''
+ (btn.saddr ? '' + fmtVal(btn.saddr) + ' (' + fmtVal(btn.val) + ') '
+ (btn.desc ? ' ' + fmtVal(btn.desc) + ' ' : '')
: '未绑定 ')
+ '
';
}
html += '
';
document.getElementById('plc-content').innerHTML = html;
// ---- 事件绑定 ----
document.getElementById('plc-add-led').onclick = function() {
PlcDebugLeds.push({ saddr: '', desc: '', val: 0 });
renderAll();
};
document.getElementById('plc-add-btn').onclick = function() {
PlcDebugButtons.push({ saddr: '', desc: '', val: 0 });
renderAll();
};
// 删除选中
document.getElementById('plc-del-btn').onclick = function() {
var delLeds = [], delBtns = [];
for (var k in ledChecked) { if (ledChecked.hasOwnProperty(k)) delLeds.push(parseInt(k)); }
for (var k in btnChecked) { if (btnChecked.hasOwnProperty(k)) delBtns.push(parseInt(k)); }
var total = delLeds.length + delBtns.length;
if (total === 0) return;
if (!confirm('确定删除 ' + total + ' 个控件?')) return;
delLeds.sort(function(a,b){return b-a;});
delBtns.sort(function(a,b){return b-a;});
for (var a = 0; a < delLeds.length; a++) PlcDebugLeds.splice(delLeds[a], 1);
for (var b = 0; b < delBtns.length; b++) PlcDebugButtons.splice(delBtns[b], 1);
ledChecked = {}; btnChecked = {};
renderAll();
};
// LED 点击
var ledIcons = document.querySelectorAll('.plc-led');
for (var k = 0; k < ledIcons.length; k++) {
ledIcons[k].onclick = function() {
var idx = parseInt(this.getAttribute('data-led-idx'));
if (PlcDebugLeds[idx].saddr) {
if (!confirm('当前绑定: ' + PlcDebugLeds[idx].saddr + ', 是否修改绑定?')) return;
}
showSignalPicker(function(saddr, desc) {
PlcDebugLeds[idx].saddr = saddr;
PlcDebugLeds[idx].desc = desc || '';
renderAll();
});
};
}
// 按钮点击
var btnIcons = document.querySelectorAll('.plc-btn-icon');
for (var m = 0; m < btnIcons.length; m++) {
btnIcons[m].onclick = function() {
var idx = parseInt(this.getAttribute('data-btn-idx'));
if (!PlcDebugButtons[idx].saddr) {
showSignalPicker(function(saddr, desc) {
PlcDebugButtons[idx].saddr = saddr;
PlcDebugButtons[idx].desc = desc || '';
PlcDebugButtons[idx].val = 0;
renderAll();
});
return;
}
var newVal = (PlcDebugButtons[idx].val == 1) ? 0 : 1;
PlcDebugButtons[idx].val = newVal;
WsClient.send({ curd:'set', signal_type:'out', saddr:PlcDebugButtons[idx].saddr, signal_data:String(newVal), setting_zone:'0' });
showToast('✅ 已发送翻转: ' + PlcDebugButtons[idx].saddr + ' → ' + newVal);
incrRefresh();
};
}
// 勾选框
var allCbs = document.querySelectorAll('.plc-cb');
for (var n = 0; n < allCbs.length; n++) {
allCbs[n].onclick = function(e) {
e.stopPropagation();
var ledIdx = this.getAttribute('data-led-idx');
var btnIdx = this.getAttribute('data-btn-idx');
if (ledIdx !== null) {
if (this.checked) ledChecked[ledIdx] = true; else delete ledChecked[ledIdx];
} else if (btnIdx !== null) {
if (this.checked) btnChecked[btnIdx] = true; else delete btnChecked[btnIdx];
}
updateDelBtn();
};
}
// 信号选择列勾选框
var sigCbs = document.querySelectorAll('.plc-sig-cb');
for (var p = 0; p < sigCbs.length; p++) {
sigCbs[p].onclick = function(e) {
e.stopPropagation();
var sigIdx = parseInt(this.getAttribute('data-sig-idx'));
if (!isNaN(sigIdx)) {
if (this.checked) signalChecked[sigIdx] = true; else delete signalChecked[sigIdx];
}
};
}
// 信号选择列整行点击切换勾选
var sigRows = document.querySelectorAll('.plc-sig-check-item');
for (var q = 0; q < sigRows.length; q++) {
sigRows[q].onclick = function(e) {
if (e.target.tagName === 'INPUT') return;
var cb = this.querySelector('.plc-sig-cb');
if (cb) {
cb.checked = !cb.checked;
var sigIdx = parseInt(cb.getAttribute('data-sig-idx'));
if (!isNaN(sigIdx)) {
if (cb.checked) signalChecked[sigIdx] = true; else delete signalChecked[sigIdx];
}
}
};
}
// 左箭头 → 添加到指示灯
var arrowLeft = document.getElementById('plc-arrow-left');
if (arrowLeft) {
arrowLeft.onclick = function(e) {
e.stopPropagation();
var added = 0;
for (var k in signalChecked) {
if (signalChecked.hasOwnProperty(k)) {
var idx = parseInt(k);
if (idx >= 0 && idx < outSignals.length) {
PlcDebugLeds.push({ saddr: outSignals[idx].saddr, desc: outSignals[idx].desc || '', val: outSignals[idx].val });
added++;
}
}
}
if (added > 0) {
showToast('✅ 已添加 ' + added + ' 个信号到指示灯');
signalChecked = {};
renderAll();
}
else {
showToast('⚠️ 请先勾选信号');
}
};
}
// 右箭头 → 添加到按键
var arrowRight = document.getElementById('plc-arrow-right');
if (arrowRight) {
arrowRight.onclick = function(e) {
e.stopPropagation();
var added = 0;
for (var k in signalChecked) {
if (signalChecked.hasOwnProperty(k)) {
var idx = parseInt(k);
if (idx >= 0 && idx < outSignals.length) {
PlcDebugButtons.push({ saddr: outSignals[idx].saddr, desc: outSignals[idx].desc || '', val: outSignals[idx].val });
added++;
}
}
}
if (added > 0) {
showToast('✅ 已添加 ' + added + ' 个信号到按键');
signalChecked = {};
renderAll();
}
else {
showToast('⚠️ 请先勾选信号');
}
};
}
document.getElementById('plc-refresh').onclick = function() {
refreshOutData();
renderAll();
showToast('🔄 已刷新');
};
var manualBtn = document.getElementById('plc-manual-set');
var exitBtn = document.getElementById('plc-exit-set');
if (manualBtn) manualBtn.onclick = function() { alert('手动置数功能待实现'); };
if (exitBtn) exitBtn.onclick = function() { alert('退出置数功能待实现'); };
}
function showToast(msg) {
var t = document.getElementById('plc-toast');
if (!t) {
t = document.createElement('div');
t.id = 'plc-toast';
t.style.cssText = 'position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:6px;z-index:9999;font-size:14px;box-shadow:0 4px 12px rgba(0,0,0,0.3);transition:opacity 0.3s;pointer-events:none';
document.body.appendChild(t);
}
t.textContent = msg; t.style.opacity = '1';
clearTimeout(t._timer);
t._timer = setTimeout(function() { t.style.opacity = '0'; }, 1200);
}
return {
render: function(container) {
ledChecked = {}; btnChecked = {}; signalChecked = {};
container.innerHTML = ''
+ ''
+ '
';
renderAll();
},
onEnter: function() { refreshOutData(); renderAll(); },
onLeave: function() {},
onData: function(data) {
if (Array.isArray(data)) { outSignals = data; }
incrRefresh();
}
};
})();