5fb269cc0a
- 保存先写本地缓存,登录后可选云端同步;退出登录不再因文件操作跳转登录 - 修复 Layui 遮罩残留、design2 保存后线条、toast 被 finally 提前关闭 - 保存过程恢复 loading spinner;成功提示 2.5 秒 - 云端 payload 瘦身与体积超限提示;后端 schema 迁移与 FileService 容错 Co-authored-by: Cursor <cursoragent@cursor.com>
266 lines
9.8 KiB
JavaScript
266 lines
9.8 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
var GATE_FEATURES = ['预览内导出成品', '预览内打印'];
|
|
var _gate = { index: null, payIndex: null, plan: null, gateOpts: null };
|
|
|
|
var pay = window.SoonMemberPay;
|
|
|
|
function esc(s) {
|
|
if (pay && pay.esc) return pay.esc(s);
|
|
if (s == null) return '';
|
|
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
}
|
|
|
|
function toast(msg, type) {
|
|
if (typeof window.soonToast === 'function') window.soonToast(msg, type);
|
|
}
|
|
|
|
function ensureLayer(cb) {
|
|
if (typeof layer !== 'undefined' && layer.open) {
|
|
if (layer.config) layer.config({ skin: 'soon-layer' });
|
|
cb();
|
|
return;
|
|
}
|
|
if (typeof layui !== 'undefined') {
|
|
layui.use(['layer'], function () {
|
|
window.layer = layui.layer;
|
|
layer.config({ skin: 'soon-layer' });
|
|
cb();
|
|
});
|
|
return;
|
|
}
|
|
toast('激活功能暂不可用,请刷新页面后重试', 'warn');
|
|
}
|
|
|
|
function planPriceDisplay(plan) {
|
|
if (!plan) return '';
|
|
return plan.price_display || (plan.price_cents / 100).toFixed(2);
|
|
}
|
|
|
|
function shellHtml(actionLabel, plan) {
|
|
var feat = GATE_FEATURES.map(function (t) {
|
|
return '<li>' + esc(t) + '</li>';
|
|
}).join('');
|
|
var price = plan ? planPriceDisplay(plan) : '—';
|
|
var channels = (pay && pay.displayChannels) ? pay.displayChannels() : ['alipay'];
|
|
var chHtml = channels.map(function (ch, i) {
|
|
var label = ch === 'wechat' ? '微信支付' : '支付宝';
|
|
return '<label class="soon-activate-channel' + (i === 0 ? ' is-active' : '') + '">' +
|
|
'<input type="radio" name="activate_channel" value="' + esc(ch) + '"' + (i === 0 ? ' checked' : '') + '>' +
|
|
esc(label) + '</label>';
|
|
}).join('');
|
|
return '<div class="soon-subscribe-modal soon-activate-modal">' +
|
|
'<header class="soon-subscribe-modal__head">' +
|
|
'<span class="soon-subscribe-modal__eyebrow">会员激活</span>' +
|
|
'<h3 class="soon-subscribe-modal__title">激活会员</h3>' +
|
|
'<p class="soon-subscribe-modal__desc">普通用户可使用全部设计工具;预览内' + esc(actionLabel || '导出或打印') + '需激活会员。</p>' +
|
|
'<ul class="soon-subscribe-modal__features">' + feat + '</ul>' +
|
|
'</header>' +
|
|
'<div class="soon-subscribe-modal__body">' +
|
|
'<div class="soon-activate-price"><span class="soon-activate-price__label">激活价格</span>' +
|
|
'<span class="soon-activate-price__value">¥' + esc(price) + '</span>' +
|
|
'<span class="soon-activate-price__hint">一次激活,永久有效</span></div>' +
|
|
'<div class="soon-activate-channels" data-role="channels">' + chHtml + '</div>' +
|
|
'<p class="soon-activate-load" data-role="plan-status"></p>' +
|
|
'</div>' +
|
|
'<footer class="soon-subscribe-modal__foot">' +
|
|
'<button type="button" class="soon-subscribe-modal__stay" data-action="stay">继续设计</button>' +
|
|
'<button type="button" class="soon-btn soon-subscribe-modal__pay" data-action="go-pay" disabled>立即激活</button>' +
|
|
'</footer></div>';
|
|
}
|
|
|
|
function closeGate(fireStay) {
|
|
var idx = _gate.index;
|
|
var payIdx = _gate.payIndex;
|
|
var opts = _gate.gateOpts;
|
|
_gate = { index: null, payIndex: null, plan: null, gateOpts: null };
|
|
if (typeof layer !== 'undefined') {
|
|
if (idx != null) layer.close(idx);
|
|
if (payIdx != null) layer.close(payIdx);
|
|
}
|
|
if (typeof window.soonCleanupLayerMask === 'function') window.soonCleanupLayerMask();
|
|
if (fireStay && opts && typeof opts.onStay === 'function') opts.onStay();
|
|
}
|
|
|
|
function selectedChannel(modal) {
|
|
var checked = modal.querySelector('input[name="activate_channel"]:checked');
|
|
return checked ? checked.value : 'alipay';
|
|
}
|
|
|
|
function onPaySuccess() {
|
|
var gateIdx = _gate.index;
|
|
var opts = _gate.gateOpts;
|
|
_gate.payIndex = null;
|
|
if (typeof layer !== 'undefined' && gateIdx != null) layer.close(gateIdx);
|
|
_gate = { index: null, payIndex: null, plan: null, gateOpts: null };
|
|
if (typeof window.soonCleanupLayerMask === 'function') window.soonCleanupLayerMask();
|
|
toast('恭喜您,会员已激活!', 'success');
|
|
if (typeof window.soonLoadMembership === 'function') {
|
|
window.soonLoadMembership(true).then(function () {
|
|
if (typeof window.soonRefreshPortalIdentity === 'function') window.soonRefreshPortalIdentity();
|
|
if (opts && typeof opts.onSuccess === 'function') opts.onSuccess();
|
|
});
|
|
return;
|
|
}
|
|
if (opts && typeof opts.onSuccess === 'function') opts.onSuccess();
|
|
}
|
|
|
|
function updatePayButton(modal) {
|
|
var btn = modal.querySelector('[data-action="go-pay"]');
|
|
var plan = _gate.plan;
|
|
if (!btn) return;
|
|
if (!plan) {
|
|
btn.disabled = true;
|
|
btn.textContent = '立即激活';
|
|
return;
|
|
}
|
|
btn.disabled = false;
|
|
btn.textContent = '立即激活 ¥' + planPriceDisplay(plan);
|
|
}
|
|
|
|
function loadPlan(modal) {
|
|
var statusEl = modal.querySelector('[data-role="plan-status"]');
|
|
if (!pay || !pay.apiGet) {
|
|
if (statusEl) statusEl.textContent = '激活模块未加载,请刷新页面';
|
|
updatePayButton(modal);
|
|
return;
|
|
}
|
|
if (statusEl) statusEl.textContent = '正在加载激活方案…';
|
|
updatePayButton(modal);
|
|
pay.apiGet('/plans').then(function (ps) {
|
|
if (!ps.ok) {
|
|
if (statusEl) statusEl.textContent = ps.message || '方案加载失败';
|
|
updatePayButton(modal);
|
|
return;
|
|
}
|
|
var items = (ps.data && ps.data.items) || [];
|
|
var plan = items[0] || null;
|
|
if (!plan) {
|
|
if (statusEl) statusEl.textContent = '暂无可用激活方案';
|
|
updatePayButton(modal);
|
|
return;
|
|
}
|
|
_gate.plan = plan;
|
|
if (statusEl) statusEl.textContent = '';
|
|
var priceEl = modal.querySelector('.soon-activate-price__value');
|
|
if (priceEl) priceEl.textContent = '¥' + planPriceDisplay(plan);
|
|
updatePayButton(modal);
|
|
}).catch(function () {
|
|
if (statusEl) statusEl.textContent = '网络错误,请稍后重试';
|
|
updatePayButton(modal);
|
|
});
|
|
}
|
|
|
|
function bindModal(modal) {
|
|
modal.addEventListener('click', function (e) {
|
|
var stay = e.target.closest('[data-action="stay"]');
|
|
if (stay) {
|
|
e.preventDefault();
|
|
closeGate(true);
|
|
return;
|
|
}
|
|
var goPay = e.target.closest('[data-action="go-pay"]');
|
|
if (goPay) {
|
|
e.preventDefault();
|
|
if (goPay.disabled || !_gate.plan || !pay || !pay.openPayModal) return;
|
|
if (_gate.payIndex != null) {
|
|
try { layer.close(_gate.payIndex); } catch (err) { /* ignore */ }
|
|
_gate.payIndex = null;
|
|
}
|
|
_gate.payIndex = pay.openPayModal({
|
|
planId: _gate.plan.id,
|
|
planName: _gate.plan.name,
|
|
priceDisplay: planPriceDisplay(_gate.plan),
|
|
channel: selectedChannel(modal),
|
|
shadeClose: true,
|
|
onPaid: onPaySuccess,
|
|
onClose: function () {
|
|
_gate.payIndex = null;
|
|
updatePayButton(modal);
|
|
},
|
|
});
|
|
}
|
|
var ch = e.target.closest('.soon-activate-channel');
|
|
if (ch) {
|
|
modal.querySelectorAll('.soon-activate-channel').forEach(function (el) {
|
|
el.classList.remove('is-active');
|
|
});
|
|
ch.classList.add('is-active');
|
|
var input = ch.querySelector('input[type="radio"]');
|
|
if (input) input.checked = true;
|
|
}
|
|
});
|
|
loadPlan(modal);
|
|
}
|
|
|
|
function soonShowActivateGate(opts) {
|
|
opts = opts || {};
|
|
if (!pay) {
|
|
toast('激活功能暂不可用,请刷新页面后重试', 'warn');
|
|
return;
|
|
}
|
|
if (pay.loadDisplayChannels) pay.loadDisplayChannels();
|
|
ensureLayer(function () {
|
|
if (_gate.index != null) {
|
|
try { layer.close(_gate.index); } catch (e) { /* ignore */ }
|
|
}
|
|
if (_gate.payIndex != null) {
|
|
try { layer.close(_gate.payIndex); } catch (e) { /* ignore */ }
|
|
}
|
|
_gate = { index: null, payIndex: null, plan: null, gateOpts: opts };
|
|
var width = Math.min(480, window.innerWidth - 32);
|
|
layer.open({
|
|
type: 1,
|
|
skin: 'soon-layer',
|
|
title: false,
|
|
closeBtn: 1,
|
|
fixed: true,
|
|
offset: 'auto',
|
|
shade: [0.68, '#000'],
|
|
shadeClose: true,
|
|
maxWidth: width,
|
|
area: [width + 'px', 'auto'],
|
|
content: shellHtml(opts.reason, null),
|
|
success: function (layero, index) {
|
|
var layerEl = layero && layero[0] ? layero[0] : layero;
|
|
if (layerEl && layerEl.classList) {
|
|
layerEl.classList.add('soon-layer--activate');
|
|
}
|
|
var content = layerEl && layerEl.querySelector ? layerEl.querySelector('.layui-layer-content') : null;
|
|
if (content) {
|
|
content.style.padding = '0';
|
|
content.style.overflow = 'visible';
|
|
}
|
|
var modal = layerEl.querySelector('.soon-activate-modal');
|
|
_gate.index = index;
|
|
_gate.gateOpts = opts;
|
|
if (modal) bindModal(modal);
|
|
requestAnimationFrame(function () {
|
|
if (typeof layer.style === 'function') layer.style(index);
|
|
});
|
|
},
|
|
end: function () {
|
|
var payIdx = _gate.payIndex;
|
|
if (payIdx != null) {
|
|
try { layer.close(payIdx); } catch (e) { /* ignore */ }
|
|
}
|
|
_gate = { index: null, payIndex: null, plan: null, gateOpts: null };
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
window.soonShowActivateGate = soonShowActivateGate;
|
|
|
|
if (!window._soonActivateFocusBound) {
|
|
window._soonActivateFocusBound = true;
|
|
window.addEventListener('focus', function () {
|
|
if (typeof window.soonLoadMembership !== 'function') return;
|
|
window.soonLoadMembership(true).then(function () {
|
|
if (typeof window.soonRefreshPortalIdentity === 'function') window.soonRefreshPortalIdentity();
|
|
});
|
|
});
|
|
}
|
|
})();
|