680 lines
23 KiB
JavaScript
680 lines
23 KiB
JavaScript
// 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);
|
||
}
|
||
|
||
function formatMoney(v) {
|
||
var n = Number(v || 0);
|
||
if (!isFinite(n)) {
|
||
n = 0;
|
||
}
|
||
// 统一口径:两位小数 + 千分位
|
||
try {
|
||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||
} catch (e) {
|
||
return n.toFixed(2);
|
||
}
|
||
}
|
||
|
||
function formatPct(ratio, digits) {
|
||
var d = (digits == null) ? 1 : Number(digits);
|
||
if (!isFinite(d) || d < 0) {
|
||
d = 1;
|
||
}
|
||
var r = Number(ratio || 0);
|
||
if (!isFinite(r)) {
|
||
r = 0;
|
||
}
|
||
return (r * 100).toFixed(d);
|
||
}
|
||
|
||
// 续费缺订阅治理:绑定成功后自动滚动到顶部提示区(让运营立刻看到 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);
|
||
}
|
||
}
|
||
|
||
// 平台订单详情页:当从仪表盘/列表跳转到某个治理锚点(例如 #add-payment-receipt)时,自动展开对应 <details>。
|
||
// 说明:避免“跳过去但面板是折叠的”,造成运营以为没跳到。
|
||
(function () {
|
||
if (!window.location || !window.location.hash) {
|
||
return;
|
||
}
|
||
|
||
var h = String(window.location.hash || '');
|
||
var map = {
|
||
'#add-payment-receipt': 'details#add-payment-receipt',
|
||
'#add-refund-receipt': 'details#add-refund-receipt',
|
||
};
|
||
|
||
if (map[h]) {
|
||
var d = qs(map[h]);
|
||
if (d) {
|
||
d.open = true;
|
||
}
|
||
}
|
||
})();
|
||
|
||
// 平台订单列表页:当从批次页等入口带 #filters 跳转过来时,自动展开筛选面板并定位。
|
||
// 说明:筛选面板会记忆折叠状态(localStorage);若运营之前手动收起,再跳转回来可能看不到筛选条件。
|
||
(function () {
|
||
if (!window.location || String(window.location.hash || '') !== '#filters') {
|
||
return;
|
||
}
|
||
|
||
var d = qs('#filters');
|
||
if (!d) {
|
||
return;
|
||
}
|
||
|
||
// 若是 <details>,确保展开
|
||
if (String(d.tagName || '').toLowerCase() === 'details') {
|
||
d.open = true;
|
||
}
|
||
|
||
// 轻量定位(不强依赖 smooth)
|
||
try {
|
||
d.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||
} catch (e) {
|
||
try {
|
||
d.scrollIntoView();
|
||
} catch (e2) {}
|
||
}
|
||
})();
|
||
|
||
// 通用:表单提交后禁用按钮,避免运营重复点击造成重复请求
|
||
// 用法: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)
|
||
// 用法:<details data-role="collapsible" data-storage-key="xxx">
|
||
(function () {
|
||
// 兼容历史:旧实现要求 data-role="collapsible";现在只要存在 data-storage-key 就启用记忆。
|
||
var nodes = document.querySelectorAll('details[data-storage-key], 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) {}
|
||
});
|
||
});
|
||
})();
|
||
|
||
// 仪表盘:列宽一致(趋势/收费工作台 与 最近平台订单同列宽度一致)
|
||
// 说明:用户明确需求是“宽度一致”,不是高度一致。
|
||
// 方案:基于 CSS Grid 的列宽天然一致;这里不再做任何 JS 对齐(避免误解/副作用)。
|
||
// 保留 data-role 供测试与未来渐进增强定位用。
|
||
|
||
// 仪表盘:迷你图表(趋势图渐进增强)
|
||
// 说明:不引入图表库,避免构建链;用 div bar 方式渲染。
|
||
(function () {
|
||
var el = qs('[data-role="platform-order-trend-7d-chart"][data-points]');
|
||
if (!el) {
|
||
return;
|
||
}
|
||
|
||
var raw = el.getAttribute('data-points') || '[]';
|
||
var points = [];
|
||
try {
|
||
points = JSON.parse(raw) || [];
|
||
} catch (e) {
|
||
points = [];
|
||
}
|
||
|
||
if (!points || points.length === 0) {
|
||
el.classList.add('is-empty');
|
||
el.textContent = '暂无趋势数据';
|
||
return;
|
||
}
|
||
|
||
var max = 0;
|
||
points.forEach(function (p) {
|
||
var v = Number(p && p.paid_sum ? p.paid_sum : 0);
|
||
if (v > max) {
|
||
max = v;
|
||
}
|
||
});
|
||
if (!max || max <= 0) {
|
||
max = 1;
|
||
}
|
||
|
||
// 渐进增强:从下方表格复用“日期→订单集合”链接口径(避免硬编码 URL 规则)。
|
||
var dateToHref = {};
|
||
try {
|
||
var links = document.querySelectorAll('[data-role="platform-order-trend-7d"] a.link');
|
||
links.forEach(function (a) {
|
||
var d = String((a.textContent || '')).trim();
|
||
if (!d) {
|
||
return;
|
||
}
|
||
dateToHref[d] = String(a.getAttribute('href') || '');
|
||
});
|
||
} catch (e) {
|
||
dateToHref = {};
|
||
}
|
||
|
||
// 清空(避免 SSR/重复执行污染)
|
||
el.innerHTML = '';
|
||
|
||
points.forEach(function (p) {
|
||
var paid = Number(p && p.paid_sum ? p.paid_sum : 0);
|
||
var h = Math.round(Math.max(6, (paid / max) * 72));
|
||
|
||
var date = (p && p.date) ? String(p.date) : '';
|
||
var href = (date && dateToHref[date]) ? String(dateToHref[date]) : '';
|
||
|
||
var bar = document.createElement(href ? 'a' : 'div');
|
||
bar.className = 'adm-mini-chart-bar' + (href ? ' adm-mini-chart-bar-link' : '');
|
||
bar.style.height = h + 'px';
|
||
if (href) {
|
||
bar.setAttribute('href', href);
|
||
bar.setAttribute('role', 'link');
|
||
bar.setAttribute('aria-label', '进入当日订单集合:' + date);
|
||
}
|
||
|
||
var countNum = Number(p && p.count != null ? p.count : 0);
|
||
if (!isFinite(countNum) || countNum < 0) {
|
||
countNum = 0;
|
||
}
|
||
var avg = countNum > 0 ? (paid / countNum) : 0;
|
||
bar.title = date + '|订单 ' + String(countNum) + ' 单|已付 ¥' + formatMoney(paid) + '|单均 ¥' + formatMoney(avg);
|
||
|
||
el.appendChild(bar);
|
||
});
|
||
})();
|
||
|
||
// 仪表盘:迷你排行(近7天站点收入 Top5)
|
||
(function () {
|
||
var el = qs('[data-role="merchant-revenue-rank-7d-chart"][data-points]');
|
||
if (!el) {
|
||
return;
|
||
}
|
||
|
||
var raw = el.getAttribute('data-points') || '[]';
|
||
var points = [];
|
||
try {
|
||
points = JSON.parse(raw) || [];
|
||
} catch (e) {
|
||
points = [];
|
||
}
|
||
|
||
if (!points || points.length === 0) {
|
||
el.classList.add('is-empty');
|
||
el.textContent = '暂无排行数据';
|
||
return;
|
||
}
|
||
|
||
var max = 0;
|
||
points.forEach(function (p) {
|
||
var v = Number(p && p.paid_sum ? p.paid_sum : 0);
|
||
if (v > max) {
|
||
max = v;
|
||
}
|
||
});
|
||
if (!max || max <= 0) {
|
||
max = 1;
|
||
}
|
||
|
||
// 渐进增强:从下方表格复用“站点→订单集合”链接口径(避免硬编码/避免 merchant_id=1 命中 10 的误匹配)。
|
||
var merchantIdToHref = {};
|
||
try {
|
||
var merchantLinks = document.querySelectorAll('[data-role="merchant-revenue-rank-7d"] a.link[href*="merchant_id="]');
|
||
merchantLinks.forEach(function (a) {
|
||
var href = String(a.getAttribute('href') || '');
|
||
var m = href.match(/[?&]merchant_id=(\d+)/);
|
||
if (!m) {
|
||
return;
|
||
}
|
||
merchantIdToHref[String(m[1])] = href;
|
||
});
|
||
} catch (e) {
|
||
merchantIdToHref = {};
|
||
}
|
||
|
||
el.innerHTML = '';
|
||
|
||
points.forEach(function (p, idx) {
|
||
var paid = Number(p && p.paid_sum ? p.paid_sum : 0);
|
||
var ratio = Math.max(0, Math.min(1, paid / max));
|
||
|
||
var mid = Number(p && p.merchant_id != null ? p.merchant_id : 0);
|
||
if (!isFinite(mid) || mid < 0) {
|
||
mid = 0;
|
||
}
|
||
var href = merchantIdToHref[String(mid)] ? String(merchantIdToHref[String(mid)]) : '';
|
||
|
||
var row = document.createElement(href ? 'a' : 'div');
|
||
row.className = 'adm-mini-rank-row' + (href ? ' adm-mini-rank-row-link' : '');
|
||
if (href) {
|
||
row.setAttribute('href', href);
|
||
}
|
||
|
||
var name = document.createElement('div');
|
||
name.className = 'adm-mini-rank-name';
|
||
var mname = (p && p.name) ? String(p.name) : ('#' + (idx + 1));
|
||
name.textContent = mname;
|
||
// tooltip:显示完整名称(避免 ellipsis 后看不到)
|
||
name.title = mname;
|
||
|
||
var wrap = document.createElement('div');
|
||
wrap.className = 'adm-mini-rank-bar-wrap';
|
||
|
||
var bar = document.createElement('div');
|
||
bar.className = 'adm-mini-rank-bar';
|
||
bar.style.width = Math.round(ratio * 100) + '%';
|
||
|
||
wrap.appendChild(bar);
|
||
|
||
var val = document.createElement('div');
|
||
val.className = 'adm-mini-rank-value';
|
||
val.textContent = '¥' + formatMoney(paid);
|
||
|
||
var cntText = String(p && p.count != null ? p.count : 0);
|
||
row.title = 'Top' + (idx + 1) + ':' + mname + '|已付 ¥' + formatMoney(paid) + '|订单数 ' + cntText;
|
||
|
||
row.appendChild(name);
|
||
row.appendChild(wrap);
|
||
row.appendChild(val);
|
||
|
||
// a 标签:避免默认下划线影响视觉(由 CSS 控制);并提升可访问性。
|
||
if (href) {
|
||
row.setAttribute('role', 'link');
|
||
row.setAttribute('aria-label', '进入站点订单集合:' + mname);
|
||
}
|
||
|
||
el.appendChild(row);
|
||
});
|
||
})();
|
||
|
||
// 仪表盘:迷你占比(套餐订单占比 Top5)
|
||
(function () {
|
||
var el = qs('[data-role="plan-order-share-top5-chart"][data-points]');
|
||
if (!el) {
|
||
return;
|
||
}
|
||
|
||
var raw = el.getAttribute('data-points') || '[]';
|
||
var points = [];
|
||
try {
|
||
points = JSON.parse(raw) || [];
|
||
} catch (e) {
|
||
points = [];
|
||
}
|
||
|
||
var total = Number(el.getAttribute('data-total') || 0);
|
||
if (!total || total <= 0) {
|
||
total = 0;
|
||
}
|
||
|
||
if (!points || points.length === 0 || total === 0) {
|
||
el.classList.add('is-empty');
|
||
el.textContent = '暂无占比数据';
|
||
return;
|
||
}
|
||
|
||
// 渐进增强:从下方表格复用“套餐→订单集合”链接口径(避免硬编码 URL 规则)。
|
||
var planIdToHref = {};
|
||
try {
|
||
var planLinks = document.querySelectorAll('[data-role="plan-order-share-top5"] a.link[href*="plan_id="]');
|
||
planLinks.forEach(function (a) {
|
||
var href = String(a.getAttribute('href') || '');
|
||
var m = href.match(/[?&]plan_id=(\d+)/);
|
||
if (!m) {
|
||
return;
|
||
}
|
||
planIdToHref[String(m[1])] = href;
|
||
});
|
||
} catch (e) {
|
||
planIdToHref = {};
|
||
}
|
||
|
||
// 视觉口径:bar 宽度按 Top5 内最大值归一(更易读);百分比仍按 total 分母计算。
|
||
var maxCnt = 0;
|
||
points.forEach(function (p) {
|
||
var v = Number(p && p.count ? p.count : 0);
|
||
if (v > maxCnt) {
|
||
maxCnt = v;
|
||
}
|
||
});
|
||
if (!maxCnt || maxCnt <= 0) {
|
||
maxCnt = 1;
|
||
}
|
||
|
||
el.innerHTML = '';
|
||
|
||
points.forEach(function (p, idx) {
|
||
var cnt = Number(p && p.count ? p.count : 0);
|
||
var ratio = total > 0 ? Math.max(0, Math.min(1, cnt / total)) : 0;
|
||
var barRatio = maxCnt > 0 ? Math.max(0, Math.min(1, cnt / maxCnt)) : 0;
|
||
|
||
var pid = Number(p && p.plan_id != null ? p.plan_id : 0);
|
||
if (!isFinite(pid) || pid < 0) {
|
||
pid = 0;
|
||
}
|
||
var href = planIdToHref[String(pid)] ? String(planIdToHref[String(pid)]) : '';
|
||
|
||
var row = document.createElement(href ? 'a' : 'div');
|
||
row.className = 'adm-mini-share-row' + (href ? ' adm-mini-share-row-link' : '');
|
||
if (href) {
|
||
row.setAttribute('href', href);
|
||
}
|
||
|
||
var name = document.createElement('div');
|
||
name.className = 'adm-mini-share-name';
|
||
var pname = (p && p.name) ? String(p.name) : ('#' + (idx + 1));
|
||
name.textContent = pname;
|
||
// tooltip:显示完整名称(避免 ellipsis 后看不到)
|
||
name.title = pname;
|
||
|
||
var wrap = document.createElement('div');
|
||
wrap.className = 'adm-mini-share-bar-wrap';
|
||
|
||
var bar = document.createElement('div');
|
||
bar.className = 'adm-mini-share-bar';
|
||
bar.style.width = Math.round(barRatio * 100) + '%';
|
||
|
||
wrap.appendChild(bar);
|
||
|
||
var val = document.createElement('div');
|
||
val.className = 'adm-mini-share-value';
|
||
val.textContent = formatPct(ratio, 1) + '%';
|
||
|
||
row.title = 'Top' + (idx + 1) + ':' + pname + '|' + cnt + ' 单|占比 ' + formatPct(ratio, 1) + '%';
|
||
|
||
row.appendChild(name);
|
||
row.appendChild(wrap);
|
||
row.appendChild(val);
|
||
|
||
// a 标签:避免默认下划线影响视觉(由 CSS 控制);并提升可访问性。
|
||
if (href) {
|
||
row.setAttribute('role', 'link');
|
||
row.setAttribute('aria-label', '进入套餐订单集合:' + pname);
|
||
}
|
||
|
||
el.appendChild(row);
|
||
});
|
||
})();
|
||
|
||
// 通用:将后端 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);
|
||
})();
|
||
|
||
// 通用:复制到剪贴板(有权限限制/兼容降级)
|
||
function copyToClipboard(text) {
|
||
var t = String(text || '');
|
||
if (!t) {
|
||
return Promise.reject(new Error('empty'));
|
||
}
|
||
|
||
if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
|
||
return navigator.clipboard.writeText(t);
|
||
}
|
||
|
||
return new Promise(function (resolve, reject) {
|
||
try {
|
||
var ta = document.createElement('textarea');
|
||
ta.value = t;
|
||
ta.setAttribute('readonly', 'readonly');
|
||
ta.style.position = 'fixed';
|
||
ta.style.top = '-1000px';
|
||
ta.style.left = '-1000px';
|
||
document.body.appendChild(ta);
|
||
ta.select();
|
||
var ok = document.execCommand('copy');
|
||
document.body.removeChild(ta);
|
||
ok ? resolve() : reject(new Error('copy_failed'));
|
||
} catch (e) {
|
||
reject(e);
|
||
}
|
||
});
|
||
}
|
||
|
||
function toastSuccess(text) {
|
||
try {
|
||
var container = qs('[data-role="toast-container"]');
|
||
if (!container) {
|
||
return false;
|
||
}
|
||
|
||
var t = document.createElement('div');
|
||
t.className = 'toast toast-success';
|
||
t.setAttribute('role', 'status');
|
||
|
||
var c = document.createElement('div');
|
||
c.className = 'toast-content';
|
||
c.textContent = String(text || '');
|
||
|
||
t.appendChild(c);
|
||
container.appendChild(t);
|
||
|
||
setTimeout(function () {
|
||
try {
|
||
container.removeChild(t);
|
||
} catch (e) {}
|
||
}, 2500);
|
||
|
||
return true;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 批次页:一键复制 run_id(渐进增强)
|
||
(function(){
|
||
var btn = qs('[data-action="copy-run-id"][data-run-id]');
|
||
if(!btn){return;}
|
||
|
||
btn.addEventListener('click', function(){
|
||
var runId = btn.getAttribute('data-run-id') || '';
|
||
copyToClipboard(runId).then(function(){
|
||
if (toastSuccess('已复制 run_id:' + runId)) {
|
||
return;
|
||
}
|
||
try { window.alert('已复制 run_id:' + runId); } catch (e) {}
|
||
}).catch(function(){
|
||
try { window.alert('复制失败,请手动复制 run_id:' + runId); } catch (e) {}
|
||
});
|
||
});
|
||
})();
|
||
|
||
function absoluteUrl(href) {
|
||
var h = String(href || '');
|
||
if (!h) {
|
||
return '';
|
||
}
|
||
// 已是绝对链接
|
||
if (h.indexOf('http://') === 0 || h.indexOf('https://') === 0) {
|
||
return h;
|
||
}
|
||
// 仅将站内相对路径补齐为绝对链接
|
||
if (h.indexOf('/') === 0 && window.location && window.location.origin) {
|
||
return String(window.location.origin) + h;
|
||
}
|
||
return h;
|
||
}
|
||
|
||
// 批次页:一键复制治理集合链接(例如:本批次失败 / 按Top原因)
|
||
(function(){
|
||
var btns = document.querySelectorAll('[data-action="copy-link"][data-href]');
|
||
if(!btns || btns.length === 0){return;}
|
||
|
||
function markCopied(btn, ok) {
|
||
try {
|
||
var orig = btn.getAttribute('data-orig-text');
|
||
if (!orig) {
|
||
orig = String(btn.textContent || '');
|
||
btn.setAttribute('data-orig-text', orig);
|
||
}
|
||
|
||
var nextText = ok ? '已复制' : '复制失败';
|
||
btn.textContent = nextText;
|
||
btn.disabled = true;
|
||
|
||
setTimeout(function(){
|
||
try {
|
||
btn.textContent = orig;
|
||
btn.disabled = false;
|
||
} catch (e) {}
|
||
}, 1200);
|
||
} catch (e) {}
|
||
}
|
||
|
||
btns.forEach(function(btn){
|
||
btn.addEventListener('click', function(){
|
||
var href = btn.getAttribute('data-href') || '';
|
||
var label = btn.getAttribute('data-label') || '链接';
|
||
|
||
var abs = absoluteUrl(href);
|
||
copyToClipboard(abs).then(function(){
|
||
markCopied(btn, true);
|
||
|
||
if (toastSuccess('已复制' + label + '链接')) {
|
||
return;
|
||
}
|
||
try { window.alert('已复制' + label + '链接'); } catch (e) {}
|
||
}).catch(function(){
|
||
markCopied(btn, false);
|
||
try { window.alert('复制失败,请手动复制' + label + '链接'); } catch (e) {}
|
||
});
|
||
});
|
||
});
|
||
})();
|
||
|
||
// 续费缺订阅治理:订单详情页“绑定订阅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();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
})();
|