/** * @file ui.js * @brief 通用 UI 组件 — Toast, Modal, Table, Icon, Utilities */ /* ================================================================== * SVG 内联图标 (Lucide 风格, 18×18) * ================================================================== */ var Icon = { _map: { monitor: '', dashboard: '', signal: '', link: '', zap: '', sliders: '', settings: '', database: '', bug: '', cpu: '', activity: '', terminal: '', check: '', plus: '', trash: '', edit: '', alert: '', }, get: function(name, cls) { return (this._map[name] || '').replace('class="icon-svg"', 'class="' + (cls || 'icon-svg') + '"'); } }; /* ================================================================== * Toast 通知 * ================================================================== */ function toast(msg, type) { type = type || 'info'; var el = document.createElement('div'); el.className = 'toast toast-' + type; el.textContent = msg; document.getElementById('toast-container').appendChild(el); setTimeout(function() { el.style.opacity = '0'; el.style.transition = 'opacity 0.3s'; }, 2500); setTimeout(function() { el.remove(); }, 2800); } /* ================================================================== * Modal 模态框 * ================================================================== */ function showModal(title, bodyHtml, onOk, okText) { okText = okText || I18n.t('toast.confirm'); var overlay = document.createElement('div'); overlay.className = 'modal-overlay'; overlay.innerHTML = '
| ' + I18n.t('signal.val') + ' | ' + I18n.t('signal.action') + ' |
|---|
' + I18n.t('signal.confirm_del_msg') + ' ' + esc(saddr) + '?
', function(ov) { WsClient.send({ saddr: saddr, signal_type: type, curd: 'del', setting_zone: '0' }); SignalStore.remove(type, saddr); Router.dispatch(Router.currentHash); toast(I18n.t('toast.del_sent') + ': ' + saddr, 'info'); ov.remove(); }, Icon.get('trash') + ' ' + I18n.t('signal.delete')); }, batchDel: function(type) { var checked = [].slice.call(document.querySelectorAll('#tbody-' + type + ' input[type=checkbox]:checked')); if (checked.length === 0) { toast(I18n.t('toast.no_selected'), 'error'); return; } showModal(I18n.t('signal.confirm_batch_del'), '' + I18n.t('signal.confirm_batch_msg') + ' ' + checked.length + ' ' + I18n.t('signal.confirm_batch_del') + '?
', function(ov) { checked.forEach(function(cb) { var saddr = cb.closest('tr').dataset.saddr; WsClient.send({ saddr: saddr, signal_type: type, curd: 'del', setting_zone: '0' }); }); toast(checked.length + ' ' + I18n.t('toast.batch_del_sent'), 'info'); ov.remove(); }, Icon.get('trash') + ' ' + I18n.t('signal.delete') + ' ' + checked.length); }, set: function(type, saddr) { showModal(I18n.t('signal.set_title') + ' \u2014 ' + esc(saddr), '', function(ov) { var val = getModalVal(ov, '#mf-val'); WsClient.send({ saddr: saddr, signal_type: type, curd: 'set', signal_data: val, setting_zone: '0' }); toast(I18n.t('toast.set_sent') + ': ' + saddr + ' = ' + val, 'success'); ov.remove(); }, I18n.t('signal.set')); } };