// SaaSShop Admin JS // 说明:用于增强总台管理的运营交互体验(尽量保持小而可治理)。 // 原则:不引入复杂构建链;以渐进增强为主,页面无 JS 也应可用。 (function () { if (window.__SAASSHOP_ADMIN_JS__) { return; } window.__SAASSHOP_ADMIN_JS__ = true; function qs(sel, root) { return (root || document).querySelector(sel); } // 续费缺订阅治理:绑定成功后自动滚动到顶部提示区(让运营立刻看到 success/warning/error) // 说明:由后端 redirect url 追加 attached_subscription=1 触发。 if (window.location && window.location.search && window.location.search.indexOf('attached_subscription=1') >= 0) { try { window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (e) { window.scrollTo(0, 0); } } // 通用:表单提交后禁用按钮,避免运营重复点击造成重复请求 // 用法:form 标记 data-action="disable-on-submit"。 (function () { var forms = document.querySelectorAll('form[data-action="disable-on-submit"]'); if (!forms || forms.length === 0) { return; } forms.forEach(function (form) { form.addEventListener('submit', function () { try { var btns = form.querySelectorAll('button, input[type="submit"]'); btns.forEach(function (b) { b.disabled = true; // 尽量不改文案(避免影响断言/文案口径);只做禁用 }); } catch (e) {} }); }); })(); // 通用:折叠面板(collapsible)记忆展开状态(localStorage) // 用法:
(function () { var nodes = document.querySelectorAll('details[data-role="collapsible"][data-storage-key]'); if (!nodes || nodes.length === 0) { return; } nodes.forEach(function (d) { var key = d.getAttribute('data-storage-key'); if (!key) { return; } try { var saved = window.localStorage.getItem(key); if (saved === 'open') { d.open = true; } else if (saved === 'closed') { d.open = false; } } catch (e) {} d.addEventListener('toggle', function () { try { window.localStorage.setItem(key, d.open ? 'open' : 'closed'); } catch (e) {} }); }); })(); // 通用:将后端 flash 信息同步到 toast(更像 Ant Design Pro 的反馈方式) // 说明:渐进增强。页面仍保留原本的提示块,不依赖 JS。 (function () { var container = qs('[data-role="toast-container"]'); if (!container) { return; } var flashNodes = document.querySelectorAll('[data-flash]'); if (!flashNodes || flashNodes.length === 0) { return; } function createToast(type, text) { var div = document.createElement('div'); div.className = 'toast toast-' + type; div.setAttribute('role', 'status'); var content = document.createElement('div'); content.className = 'toast-content'; content.textContent = text; var close = document.createElement('button'); close.type = 'button'; close.className = 'toast-close'; close.textContent = '×'; close.addEventListener('click', function () { try { container.removeChild(div); } catch (e) {} }); div.appendChild(content); div.appendChild(close); return div; } flashNodes.forEach(function (node) { var type = node.getAttribute('data-flash') || 'info'; var text = (node.textContent || '').trim(); if (!text) { return; } container.appendChild(createToast(type, text)); }); // 自动消失(success/warning),error 保留更久 setTimeout(function () { try { var toasts = container.querySelectorAll('.toast'); toasts.forEach(function (t) { var cls = t.className || ''; var isError = cls.indexOf('toast-error') >= 0; if (!isError) { container.removeChild(t); } }); } catch (e) {} }, 4500); setTimeout(function () { try { var toasts = container.querySelectorAll('.toast'); toasts.forEach(function (t) { try { container.removeChild(t); } catch (e) {} }); } catch (e) {} }, 9000); })(); // 续费缺订阅治理:订单详情页“绑定订阅ID”输入框,小交互增强: // - 输入后按 Enter 直接提交 // - 自动聚焦,减少点击 var attachInput = qs('#attach_site_subscription_id'); if (attachInput) { try { attachInput.focus(); } catch (e) {} attachInput.addEventListener('keydown', function (e) { if (e && (e.key === 'Enter' || e.keyCode === 13)) { var form = attachInput.form; if (form) { e.preventDefault(); form.submit(); } } }); } })();