140 lines
5.8 KiB
HTML
140 lines
5.8 KiB
HTML
<link href="/static/member/css/common.css" rel="stylesheet" />
|
||
<style>
|
||
.uc-wrap { max-width: 900px; }
|
||
.plan-card { transition: 0.2s; }
|
||
.plan-card:hover { box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12); }
|
||
.plan-card .layui-card-body h1 { font-size: 34px; color: #009688; margin: 6px 0 12px; }
|
||
.plan-card li { line-height: 28px; color: #666; }
|
||
#payMethods { margin: 10px 0; }
|
||
</style>
|
||
|
||
<div class="uc-wrap">
|
||
<h2 style="text-align: center">选择适合您的套餐</h2>
|
||
<br />
|
||
<div class="layui-row layui-col-space20" id="planList">
|
||
{volist name="plans" id="plan"}
|
||
<div class="layui-col-md4">
|
||
<div class="layui-card plan-card">
|
||
<div class="layui-card-header">{$plan.title}</div>
|
||
<div class="layui-card-body">
|
||
<h1>¥{$plan.price}<span style="font-size: 16px">/月</span></h1>
|
||
<ul>
|
||
<li>{$plan.desc}</li>
|
||
</ul>
|
||
{if $plan.price == 0}
|
||
<button class="layui-btn layui-btn-primary layui-btn-fluid" onclick="pay({$plan.id})">当前版本</button>
|
||
{else}
|
||
<button class="layui-btn layui-btn-danger layui-btn-fluid" onclick="pay({$plan.id})">立即开通</button>
|
||
{/if}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{/volist}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 支付方式选择弹窗 -->
|
||
<div id="payModal" style="display: none; padding: 20px">
|
||
<div id="payMethods"></div>
|
||
<div id="payBox" style="margin-top: 15px; text-align: center"></div>
|
||
</div>
|
||
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
|
||
<script>
|
||
layui.use(['layer', 'http', 'form'], function () {
|
||
var layer = layui.layer, http = layui.http, form = layui.form, $ = layui.$;
|
||
|
||
// 套餐价格映射(用于免费判定)
|
||
var PLAN_PRICE = {};
|
||
{volist name = "plans" id = "plan" }
|
||
PLAN_PRICE[{ $plan.id }] = { $plan.price };
|
||
{/volist }
|
||
|
||
var curPlan = 0; // 当前选择的套餐
|
||
|
||
// 加载可用支付方式(插件通过 PaymentMethods 事件注入)
|
||
function loadMethods(cb) {
|
||
http.get('methods').then(function (res) {
|
||
if (res.code === 0 && res.data && res.data.length) {
|
||
cb(res.data);
|
||
} else {
|
||
layer.msg('暂无可用支付方式,请先安装支付插件', { icon: 2 });
|
||
cb([]);
|
||
}
|
||
}).catch(function () {
|
||
layer.msg('支付方式加载失败', { icon: 2 });
|
||
cb([]);
|
||
});
|
||
}
|
||
|
||
// 对外暴露:点击套餐按钮触发
|
||
window.pay = function (planId) {
|
||
curPlan = planId;
|
||
if (PLAN_PRICE[planId] == 0) {
|
||
http.post('create', { plan_id: planId, method: 'free' }).then(function (res) {
|
||
if (res.code === 0) { layer.msg('已开通' + (res.data.plan || ''), { icon: 1 }); }
|
||
else { layer.msg(res.message || '开通失败', { icon: 2 }); }
|
||
});
|
||
return;
|
||
}
|
||
loadMethods(function (methods) {
|
||
if (!methods.length) return;
|
||
var html = '<div class="layui-form">';
|
||
methods.forEach(function (m, i) {
|
||
html += '<input type="radio" name="payMethod" value="' + m.code + '" title="' + m.name + '" ' + (i === 0 ? 'checked' : '') + '>'
|
||
+ '<div class="layui-word-aux" style="margin:2px 0 10px;">' + (m.desc || '') + '</div>';
|
||
});
|
||
html += '</div><button class="layui-btn layui-btn-fluid" id="doPay">确认支付</button>';
|
||
$('#payMethods').html(html);
|
||
$('#payBox').empty();
|
||
form.render();
|
||
layer.open({ type: 1, title: '选择支付方式', area: '360px', content: $('#payModal') });
|
||
});
|
||
};
|
||
|
||
// 确认支付
|
||
$(document).on('click', '#doPay', function () {
|
||
var method = $('input[name="payMethod"]:checked').val();
|
||
http.post('create', { plan_id: curPlan, method: method }).then(function (res) {
|
||
if (res.code !== 0) { layer.msg(res.message || '创建订单失败', { icon: 2 }); return; }
|
||
var g = res.data || {};
|
||
if (g.type === 'error') {
|
||
layer.msg(g.message || '支付未配置完成,无法发起支付', { icon: 2 });
|
||
return;
|
||
}
|
||
if (g.type === 'redirect' && g.redirect_url) {
|
||
location.href = g.redirect_url;
|
||
} else if (g.type === 'qrcode' && g.qrcode_url) {
|
||
$('#payBox').empty().append('<div id="qrcode" style="display:inline-block;"></div><p style="color:#f60;margin-top:8px;">请使用' + (method === 'wechat' ? '微信' : '支付宝') + '扫码支付</p>');
|
||
new QRCode(document.getElementById('qrcode'), g.qrcode_url);
|
||
startPoll(g.order_sn);
|
||
} else if (g.type === 'form' && g.html) {
|
||
$('#payBox').html(g.html);
|
||
} else if (g.type === 'free') {
|
||
layer.msg('开通成功', { icon: 1 });
|
||
} else {
|
||
layer.msg('已生成支付,请按提示完成', { icon: 1 });
|
||
}
|
||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||
});
|
||
|
||
// 轮询订单支付状态。
|
||
// 注意:支付查询由各支付插件提供对应接口(如插件暴露 /user/payment/query),
|
||
// 框架不写死第三方路径。下方 demo 调用的 /paydemo/pay/query 为开发占位,
|
||
// 已在真实环境移除避免 404;接入支付插件后请在此调用插件提供的查询地址。
|
||
function startPoll(orderSn) {
|
||
if (window.__payTimer) { clearInterval(window.__payTimer); }
|
||
window.__payTimer = setInterval(function () {
|
||
// TODO: 替换为支付插件提供的订单查询接口(如 url('user/payment/query'))
|
||
// $.post(url('user/payment/query'), { order_sn: orderSn }, function (r) {
|
||
// if (r && r.code === 0 && r.data && r.data.paid) {
|
||
// clearInterval(window.__payTimer);
|
||
// window.__payTimer = null;
|
||
// layer.msg('支付成功,会员已开通', { icon: 1 });
|
||
// setTimeout(function () { location.reload(); }, 1200);
|
||
// }
|
||
// }, 'json');
|
||
}, 2000);
|
||
}
|
||
});
|
||
</script>
|