fix(web): 弹窗登录注册后刷新顶栏,导出流程支持内嵌注册
弹窗登录/注册成功后隐藏 guest 顶栏并更新会员身份;导出打印 gate 内立即注册改为同层弹窗,注册完自动继续会员验证。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
'use strict';
|
||||
|
||||
var _gate = { index: null, opts: null };
|
||||
var MAIL_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16v12H4z"/><path d="M4 8l8 5 8-5"/></svg>';
|
||||
var LOCK_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="11" width="14" height="10" rx="1"/><path d="M8 11V8a4 4 0 118 0v3"/></svg>';
|
||||
|
||||
function esc(s) {
|
||||
if (s == null) return '';
|
||||
@@ -36,28 +38,36 @@
|
||||
toast('登录功能暂不可用,请刷新页面后重试', 'warn');
|
||||
}
|
||||
|
||||
function shellHtml(reason) {
|
||||
var mailIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16v12H4z"/><path d="M4 8l8 5 8-5"/></svg>';
|
||||
var lockIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="11" width="14" height="10" rx="1"/><path d="M8 11V8a4 4 0 118 0v3"/></svg>';
|
||||
function shellHtml(panel, reason) {
|
||||
var isReg = panel === 'register';
|
||||
var action = esc(reason || '导出或打印');
|
||||
return '<div class="soon-login-gate">' +
|
||||
'<header class="soon-login-gate__head">' +
|
||||
'<span class="soon-login-gate__eyebrow">登录</span>' +
|
||||
'<h3 class="soon-login-gate__title">登录后继续</h3>' +
|
||||
'<p class="soon-login-gate__desc">预览内' + esc(reason || '导出或打印') + '成品需先登录账号。</p>' +
|
||||
'</header>' +
|
||||
'<form class="soon-login-gate__form" data-role="login-form">' +
|
||||
'<span class="soon-login-gate__eyebrow">' + (isReg ? '注册' : '登录') + '</span>' +
|
||||
'<h3 class="soon-login-gate__title">' + (isReg ? '注册后继续' : '登录后继续') + '</h3>' +
|
||||
'<p class="soon-login-gate__desc">' +
|
||||
(isReg ? '注册并登录后即可' + action + '成品。' : '预览内' + action + '成品需先登录账号。') +
|
||||
'</p></header>' +
|
||||
'<form class="soon-login-gate__form" data-role="' + (isReg ? 'register' : 'login') + '-form">' +
|
||||
'<div class="soon-input-wrap soon-login-gate__field">' +
|
||||
'<span class="soon-input-icon" aria-hidden="true">' + mailIcon + '</span>' +
|
||||
'<span class="soon-input-icon" aria-hidden="true">' + MAIL_ICON + '</span>' +
|
||||
'<input type="email" name="email" required class="soon-input soon-login-gate__input" placeholder="邮箱" autocomplete="email">' +
|
||||
'</div>' +
|
||||
'<div class="soon-input-wrap soon-login-gate__field">' +
|
||||
'<span class="soon-input-icon" aria-hidden="true">' + lockIcon + '</span>' +
|
||||
'<input type="password" name="password" required class="soon-input soon-login-gate__input" placeholder="密码" autocomplete="current-password">' +
|
||||
'<span class="soon-input-icon" aria-hidden="true">' + LOCK_ICON + '</span>' +
|
||||
'<input type="password" name="password" required' +
|
||||
(isReg ? ' minlength="8"' : '') +
|
||||
' class="soon-input soon-login-gate__input" placeholder="' +
|
||||
(isReg ? '密码(至少 8 位)' : '密码') +
|
||||
'" autocomplete="' + (isReg ? 'new-password' : 'current-password') + '">' +
|
||||
'</div>' +
|
||||
'<p class="soon-login-gate__error" data-role="login-error" hidden></p>' +
|
||||
'<button type="submit" class="soon-btn soon-btn--block soon-login-gate__submit">登录</button>' +
|
||||
'<p class="soon-login-gate__links">还没有账号?<a href="register.web.html" target="_blank" rel="noopener">立即注册</a></p>' +
|
||||
'</form>' +
|
||||
'<p class="soon-login-gate__error" data-role="' + (isReg ? 'register' : 'login') + '-error" hidden></p>' +
|
||||
'<button type="submit" class="soon-btn soon-btn--block soon-login-gate__submit">' +
|
||||
(isReg ? '注册并登录' : '登录') +
|
||||
'</button>' +
|
||||
'<p class="soon-login-gate__links">' +
|
||||
(isReg ? '已有账号?<a href="#" data-action="show-login">去登录</a>' : '还没有账号?<a href="#" data-action="show-register">立即注册</a>') +
|
||||
'</p></form>' +
|
||||
'<footer class="soon-login-gate__foot">' +
|
||||
'<button type="button" class="soon-login-gate__stay" data-action="stay">继续设计</button>' +
|
||||
'</footer></div>';
|
||||
@@ -72,49 +82,59 @@
|
||||
if (typeof window.soonCleanupLayerMask === 'function') window.soonCleanupLayerMask();
|
||||
}
|
||||
|
||||
function bindModal(modal) {
|
||||
var form = modal.querySelector('[data-role="login-form"]');
|
||||
var errEl = modal.querySelector('[data-role="login-error"]');
|
||||
modal.addEventListener('click', function (e) {
|
||||
var stay = e.target.closest('[data-action="stay"]');
|
||||
if (stay) {
|
||||
e.preventDefault();
|
||||
closeGate();
|
||||
}
|
||||
function finishAuthSuccess() {
|
||||
var opts = _gate.opts;
|
||||
closeGate();
|
||||
var chain = typeof window.soonRefreshPortalAuthUi === 'function'
|
||||
? Promise.resolve(window.soonRefreshPortalAuthUi())
|
||||
: Promise.resolve();
|
||||
return chain.then(function () {
|
||||
if (typeof window.soonReloadRecentFiles === 'function') window.soonReloadRecentFiles();
|
||||
if (opts && typeof opts.onSuccess === 'function') opts.onSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
function storeTokens(data) {
|
||||
if (!data || !data.access_token) return false;
|
||||
localStorage.setItem('soon_access', data.access_token);
|
||||
if (data.refresh_token) localStorage.setItem('soon_refresh', data.refresh_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
function swapPanel(modal, panel) {
|
||||
if (!modal || !modal.parentNode) return;
|
||||
var parent = modal.parentNode;
|
||||
var reason = _gate.opts && _gate.opts.reason;
|
||||
modal.outerHTML = shellHtml(panel, reason);
|
||||
var root = parent.querySelector('.soon-login-gate');
|
||||
if (root) bindModal(root);
|
||||
}
|
||||
|
||||
function bindAuthForm(modal, role, path, failMsg) {
|
||||
var form = modal.querySelector('[data-role="' + role + '-form"]');
|
||||
if (!form) return;
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var errEl = modal.querySelector('[data-role="' + role + '-error"]');
|
||||
if (errEl) {
|
||||
errEl.hidden = true;
|
||||
errEl.textContent = '';
|
||||
}
|
||||
var email = (form.email && form.email.value || '').trim();
|
||||
var password = form.password ? form.password.value : '';
|
||||
fetch(apiBase() + '/auth/login', {
|
||||
fetch(apiBase() + path, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email: email, password: password }),
|
||||
}).then(function (r) { return r.json(); }).then(function (j) {
|
||||
if (!j.ok || !j.data || !j.data.access_token) {
|
||||
if (!j.ok || !storeTokens(j.data)) {
|
||||
if (errEl) {
|
||||
errEl.textContent = (j && j.message) || '登录失败';
|
||||
errEl.textContent = (j && j.message) || failMsg;
|
||||
errEl.hidden = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
localStorage.setItem('soon_access', j.data.access_token);
|
||||
if (j.data.refresh_token) localStorage.setItem('soon_refresh', j.data.refresh_token);
|
||||
var opts = _gate.opts;
|
||||
closeGate();
|
||||
var load = typeof window.soonLoadMembership === 'function'
|
||||
? window.soonLoadMembership(true)
|
||||
: Promise.resolve();
|
||||
load.then(function () {
|
||||
if (typeof window.soonRefreshPortalIdentity === 'function') window.soonRefreshPortalIdentity();
|
||||
if (typeof window.soonReloadRecentFiles === 'function') window.soonReloadRecentFiles();
|
||||
if (opts && typeof opts.onSuccess === 'function') opts.onSuccess();
|
||||
});
|
||||
finishAuthSuccess();
|
||||
}).catch(function () {
|
||||
if (errEl) {
|
||||
errEl.textContent = '网络错误,请稍后重试';
|
||||
@@ -124,7 +144,28 @@
|
||||
});
|
||||
}
|
||||
|
||||
function soonShowLoginGate(opts) {
|
||||
function bindModal(modal) {
|
||||
modal.addEventListener('click', function (e) {
|
||||
if (e.target.closest('[data-action="stay"]')) {
|
||||
e.preventDefault();
|
||||
closeGate();
|
||||
return;
|
||||
}
|
||||
if (e.target.closest('[data-action="show-register"]')) {
|
||||
e.preventDefault();
|
||||
swapPanel(modal, 'register');
|
||||
return;
|
||||
}
|
||||
if (e.target.closest('[data-action="show-login"]')) {
|
||||
e.preventDefault();
|
||||
swapPanel(modal, 'login');
|
||||
}
|
||||
});
|
||||
bindAuthForm(modal, 'login', '/auth/login', '登录失败');
|
||||
bindAuthForm(modal, 'register', '/auth/register', '注册失败');
|
||||
}
|
||||
|
||||
function openGate(opts, panel) {
|
||||
opts = opts || {};
|
||||
ensureLayer(function () {
|
||||
if (_gate.index != null) {
|
||||
@@ -141,7 +182,7 @@
|
||||
shadeClose: true,
|
||||
area: [width + 'px', 'auto'],
|
||||
offset: 'auto',
|
||||
content: shellHtml(opts.reason),
|
||||
content: shellHtml(panel, opts.reason),
|
||||
success: function (layero, index) {
|
||||
var layerEl = layero && layero[0] ? layero[0] : layero;
|
||||
if (layerEl && layerEl.classList) layerEl.classList.add('soon-layer--login-gate');
|
||||
@@ -153,7 +194,6 @@
|
||||
}
|
||||
var modal = layerEl.querySelector('.soon-login-gate');
|
||||
_gate.index = index;
|
||||
_gate.opts = opts;
|
||||
if (modal) bindModal(modal);
|
||||
},
|
||||
end: function () {
|
||||
@@ -163,5 +203,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
window.soonShowLoginGate = soonShowLoginGate;
|
||||
window.soonShowLoginGate = function (opts) { openGate(opts, 'login'); };
|
||||
window.soonShowRegisterGate = function (opts) { openGate(opts, 'register'); };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user