feat(invite-code): one-time invite codes with rewards, usage log, import/export
- 一次性邀请码:批量生成(次数/有效期/备注/四类奖励)、原子消费防超发、 开启注册验证时奖励延迟发放(账本幂等键) - Zibll 兼容文本导入(points/balance/vip/vip_time/level_integral,分隔符可自定义, 第三段标识存为备注)、CSV 全字段导出与可回流文本导出 - 使用记录表 aksrt_invite_code_usage + 后台使用者列;注册表单 400ms 防抖实时校验 - 注册门控三模式(close/open/must)设置链路(PHP schema + admin SPA schema) - 契约测试覆盖建表/消费竞态/导入导出/备注全链路
This commit is contained in:
@@ -506,6 +506,37 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 邀请码输入实时校验(公开只读接口;提交时服务端仍是硬门禁)。
|
||||
function initInviteVerify(root) {
|
||||
root.querySelectorAll('input[data-invite-verify]').forEach(function (input) {
|
||||
if (input.dataset.inviteVerifyBound === '1') return;
|
||||
input.dataset.inviteVerifyBound = '1';
|
||||
var feedback = root.querySelector('[data-invite-feedback]');
|
||||
var timer = null;
|
||||
function setFeedback(text, isError) {
|
||||
if (!feedback) return;
|
||||
if (!text) { feedback.hidden = true; feedback.textContent = ''; feedback.classList.remove('is-error'); return; }
|
||||
feedback.hidden = false;
|
||||
feedback.textContent = text;
|
||||
feedback.classList.toggle('is-error', !!isError);
|
||||
}
|
||||
input.addEventListener('input', function () {
|
||||
if (timer) window.clearTimeout(timer);
|
||||
var code = input.value.trim();
|
||||
if (!code) { setFeedback(''); return; }
|
||||
timer = window.setTimeout(function () {
|
||||
window.fetch('/wp-json/aksrt/v1/invite-code/verify?code=' + encodeURIComponent(code), { credentials: 'same-origin' })
|
||||
.then(function (response) { return response.ok ? response.json() : null; })
|
||||
.then(function (payload) {
|
||||
if (!payload) { setFeedback(''); return; }
|
||||
setFeedback(payload.valid ? '邀请码有效。' : '邀请码无效或已用完。', !payload.valid);
|
||||
})
|
||||
.catch(function () { setFeedback(''); });
|
||||
}, 400);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initRoot(root) {
|
||||
root.querySelectorAll('input').forEach(function (input) {
|
||||
if (!input.hasAttribute('placeholder')) input.setAttribute('placeholder', ' ');
|
||||
@@ -521,6 +552,7 @@
|
||||
if (!button.getAttribute('aria-label')) button.setAttribute('aria-label', '显示密码');
|
||||
});
|
||||
setOAuthRedirect(root, root.dataset.redirectTo || '');
|
||||
initInviteVerify(root);
|
||||
var initial = root.dataset.initialTab || 'signin';
|
||||
if (initial === 'oauth' && window.matchMedia && window.matchMedia('(max-width: 767px)').matches) initial = 'signin';
|
||||
var mayActivateQr = initial !== 'oauth' || document.visibilityState === 'visible';
|
||||
|
||||
Reference in New Issue
Block a user