feat: ¥1 首月特惠套餐(新店专享,每店限购一次,官网+App 同步上线)
- 后端:payPlans 新增 promo_first_month(¥1/30 天/标准版权益);下单强校验每店限购一次(仅 paid 计数,弃单可重下),已享用返回 409;新增 GET /license/promo-status 供前端置灰 - 官网:checkout 套餐段第二位插「🔥 首月特惠 ¥1」+ 推广横幅 + 划线原价 ¥299;首页价格区第二位插特惠卡(5 列);已享用自动置灰 - App:购买弹窗套餐段改三档(标准/特惠/高级),特惠选中显示推广横幅与划线价,已享用置灰并禁用提交 - 实付金额以 pay 侧为准,pay 需 seed promo_first_month 产品后生效 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
+41
-9
@@ -16,10 +16,15 @@ permalink: /checkout/
|
||||
<h2>选择套餐</h2>
|
||||
<div class="seg" id="planSeg">
|
||||
<button class="seg-btn on" data-v="standard">标准版</button>
|
||||
<button class="seg-btn promo" data-v="promo" id="promoSegBtn">🔥 首月特惠 ¥1</button>
|
||||
<button class="seg-btn" data-v="pro">高级版</button>
|
||||
</div>
|
||||
<div class="promo-banner" id="promoBanner" style="display:none">
|
||||
<b>新店专享 · 仅 ¥1 体验 30 天</b>
|
||||
解锁标准版全部功能,原价 ¥299,每个门店限购一次——试过才知道多省心。
|
||||
</div>
|
||||
<ul class="co-feats" id="planFeats"></ul>
|
||||
<div class="seg-label">计费周期</div>
|
||||
<div class="seg-label" id="cycleLabel">计费周期</div>
|
||||
<div class="seg" id="cycleSeg">
|
||||
<button class="seg-btn on" data-v="annual">年付 <span class="seg-tip">省两个月</span></button>
|
||||
<button class="seg-btn" data-v="monthly">月付</button>
|
||||
@@ -54,7 +59,7 @@ permalink: /checkout/
|
||||
<div class="co-card co-summary">
|
||||
<h2>费用汇总</h2>
|
||||
<div class="sum-row"><span id="sumName">标准版 · 年付</span><span id="sumBase">¥2,999</span></div>
|
||||
<div class="sum-row muted"><span>优惠</span><span>− ¥0</span></div>
|
||||
<div class="sum-row muted"><span>优惠</span><span id="sumOff">− ¥0</span></div>
|
||||
<div class="sum-div"></div>
|
||||
<div class="sum-total"><span class="lab">应付总额</span><span class="val" id="sumTotal">¥2,999</span></div>
|
||||
<div class="auth-alert" id="coErr" style="margin-top:12px"></div>
|
||||
@@ -80,6 +85,11 @@ permalink: /checkout/
|
||||
monthly: { biz: 'monthly_standard', price: 299 },
|
||||
annual: { biz: 'annual_standard', price: 2999 },
|
||||
},
|
||||
promo: {
|
||||
name: '首月特惠',
|
||||
feats: ['标准版全部功能,一分不少', '单门店 · 单仓库 · 2 台客户端', '1,000 张商品图片分享', '每个门店限购一次'],
|
||||
single: { biz: 'promo_first_month', price: 1, orig: 299 },
|
||||
},
|
||||
pro: {
|
||||
name: '高级版',
|
||||
feats: ['单门店 · 多仓库', '5 台客户端同时使用', '10,000 张商品图片分享', '免费 AI 周度 / 月度商业数据分析'],
|
||||
@@ -92,29 +102,51 @@ permalink: /checkout/
|
||||
var cycle = 'annual';
|
||||
|
||||
function fmt(n) { return '¥' + n.toLocaleString('zh-CN'); }
|
||||
function selected() { return plan === 'promo' ? PLANS.promo.single : PLANS[plan][cycle]; }
|
||||
function render() {
|
||||
var p = PLANS[plan], c = p[cycle];
|
||||
var days = cycle === 'annual' ? 365 : 30;
|
||||
var p = PLANS[plan], c = selected(), isPromo = plan === 'promo';
|
||||
var days = isPromo || cycle === 'monthly' ? 30 : 365;
|
||||
var cyc = isPromo ? '仅 ¥1 · 30 天' : (cycle === 'annual' ? '年付' : '月付');
|
||||
$('promoBanner').style.display = isPromo ? 'block' : 'none';
|
||||
$('cycleLabel').style.display = isPromo ? 'none' : '';
|
||||
$('cycleSeg').style.display = isPromo ? 'none' : '';
|
||||
$('planFeats').innerHTML = p.feats.map(function (f) {
|
||||
return '<li><svg class="ic"><use href="#i-check"/></svg>' + f + '</li>';
|
||||
}).join('');
|
||||
$('itName').textContent = p.name + '授权 · ' + (cycle === 'annual' ? '年付' : '月付');
|
||||
$('itName').textContent = p.name + '授权 · ' + cyc;
|
||||
$('itDur').textContent = days + ' 天授权 · 到期时间自动叠加';
|
||||
$('itAmt').textContent = fmt(c.price);
|
||||
$('sumName').textContent = p.name + ' · ' + (cycle === 'annual' ? '年付' : '月付');
|
||||
$('sumBase').textContent = fmt(c.price);
|
||||
$('sumName').textContent = p.name + (isPromo ? '(原价 ¥299/月)' : ' · ' + cyc);
|
||||
$('sumBase').textContent = fmt(isPromo ? c.orig : c.price);
|
||||
$('sumOff').textContent = '− ' + fmt(isPromo ? c.orig - c.price : 0);
|
||||
$('sumTotal').textContent = fmt(c.price);
|
||||
document.querySelectorAll('#planSeg .seg-btn').forEach(function (b) { b.classList.toggle('on', b.dataset.v === plan); });
|
||||
document.querySelectorAll('#cycleSeg .seg-btn').forEach(function (b) { b.classList.toggle('on', b.dataset.v === cycle); });
|
||||
}
|
||||
document.querySelectorAll('#planSeg .seg-btn').forEach(function (b) {
|
||||
b.addEventListener('click', function () { plan = b.dataset.v; render(); });
|
||||
b.addEventListener('click', function () {
|
||||
if (b.disabled) return;
|
||||
plan = b.dataset.v; render();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('#cycleSeg .seg-btn').forEach(function (b) {
|
||||
b.addEventListener('click', function () { cycle = b.dataset.v; render(); });
|
||||
});
|
||||
render();
|
||||
|
||||
// 首月特惠每店限一次:已享用则该档置灰不可选
|
||||
jiuAuth.authFetch(API, '/api/v1/license/promo-status')
|
||||
.then(function (r) { return r.ok ? r.json() : null; })
|
||||
.then(function (j) {
|
||||
if (!j || !j.data || !j.data.used) return;
|
||||
var b = $('promoSegBtn');
|
||||
b.disabled = true;
|
||||
b.classList.add('used');
|
||||
b.innerHTML = '首月特惠(已享受)';
|
||||
if (plan === 'promo') { plan = 'standard'; render(); }
|
||||
})
|
||||
.catch(function () {});
|
||||
|
||||
function showErr(msg) { var el = $('coErr'); el.textContent = msg; el.classList.add('show'); }
|
||||
$('coBtn').addEventListener('click', function () {
|
||||
$('coErr').classList.remove('show');
|
||||
@@ -122,7 +154,7 @@ permalink: /checkout/
|
||||
jiuAuth.authFetch(API, '/api/v1/license/purchase', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ biz_code: PLANS[plan][cycle].biz }),
|
||||
body: JSON.stringify({ biz_code: selected().biz }),
|
||||
})
|
||||
.then(function (r) {
|
||||
// authFetch 已自动用 refresh_token 续签重试过,仍 401 才是真过期
|
||||
|
||||
+24
-1
@@ -190,7 +190,7 @@ description: 岩美酒库管理系统——每一瓶酒一个编号,审核驱
|
||||
<h2>按门店付费,明码标价</h2>
|
||||
<p>先免费试用,再按需选档;时长兑换券续期,无隐藏费用、无自动扣款。</p>
|
||||
</div>
|
||||
<div class="plans p4">
|
||||
<div class="plans p5">
|
||||
<div class="plan">
|
||||
<div class="pname">免费版</div>
|
||||
<div class="price">¥0<small> / 30 天</small></div>
|
||||
@@ -202,6 +202,17 @@ description: 岩美酒库管理系统——每一瓶酒一个编号,审核驱
|
||||
</ul>
|
||||
<a class="btn ghost" data-plan="free" href="/register/">立即试用</a>
|
||||
</div>
|
||||
<div class="plan promo">
|
||||
<div class="pname">首月特惠</div>
|
||||
<div class="price">¥1<span class="was">¥299</span><small> / 30 天</small></div>
|
||||
<div class="psub">一块钱用一个月,每店限一次</div>
|
||||
<ul>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>标准版全部功能,一分不少</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>2 台客户端 · 1,000 张图片</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>试过才知道多省心</li>
|
||||
</ul>
|
||||
<a class="btn primary" data-plan="promo" id="promoPlanBtn" href="/register/">¥1 立即体验</a>
|
||||
</div>
|
||||
<div class="plan hot">
|
||||
<div class="pname">标准版</div>
|
||||
<div class="price">¥299<small> / 月</small></div>
|
||||
@@ -277,15 +288,27 @@ description: 岩美酒库管理系统——每一瓶酒一个编号,审核驱
|
||||
标准/高级按钮 → 「购买 / 续费」进 /checkout/;免费版按钮 → 「进入系统」。 */
|
||||
(function () {
|
||||
if (!window.jiuAuth || !jiuAuth.loggedIn()) return;
|
||||
var API = '{{ site.appBaseUrl }}';
|
||||
document.querySelectorAll('[data-plan]').forEach(function (a) {
|
||||
var plan = a.dataset.plan;
|
||||
if (plan === 'free') {
|
||||
a.textContent = '进入系统';
|
||||
a.href = '/app/';
|
||||
} else if (plan === 'promo') {
|
||||
a.href = '/checkout/?plan=promo';
|
||||
} else {
|
||||
a.textContent = '购买 / 续费';
|
||||
a.href = '/checkout/?plan=' + plan;
|
||||
}
|
||||
});
|
||||
// 首月特惠每店限一次:已享用则置灰
|
||||
jiuAuth.authFetch(API, '/api/v1/license/promo-status')
|
||||
.then(function (r) { return r.ok ? r.json() : null; })
|
||||
.then(function (j) {
|
||||
if (!j || !j.data || !j.data.used) return;
|
||||
var b = document.getElementById('promoPlanBtn');
|
||||
if (b) { b.textContent = '已享受过'; b.classList.remove('primary'); b.classList.add('ghost', 'disabled'); b.removeAttribute('href'); }
|
||||
})
|
||||
.catch(function () {});
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user