/* ======================================================================== * 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} 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 = ''; 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 += '

🔘 按键

'; 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(); }; } 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 = {}; container.innerHTML = '' + '' + '
'; renderAll(); }, onEnter: function() { refreshOutData(); renderAll(); }, onLeave: function() {}, onData: function(data) { if (Array.isArray(data)) { outSignals = data; } incrRefresh(); } }; })();