mirror of
https://gitee.com/technical-laohu/mpay.git
synced 2025-09-17 09:16:40 +08:00
357 lines
15 KiB
HTML
357 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>收银台</title>
|
||
<link rel="stylesheet" href="/component/pear/css/pear.css" />
|
||
<script>
|
||
function detectBrowserEnvironment() {
|
||
const userAgent = navigator.userAgent.toLowerCase();
|
||
let environment = 'other';
|
||
if (userAgent.includes('micromessenger')) {
|
||
if (userAgent.includes('miniprogram')) {
|
||
environment = 'wxapp'; // 微信小程序
|
||
} else if (userAgent.includes('android') || userAgent.includes('iphone') || userAgent.includes('ipad')) {
|
||
environment = 'wxphone'; // 手机微信
|
||
} else {
|
||
environment = 'wxpc'; // PC微信
|
||
}
|
||
} else if (userAgent.includes('aliapp') || userAgent.includes('alipayclient')) {
|
||
if (userAgent.includes('android') || userAgent.includes('iphone') || userAgent.includes('ipad')) {
|
||
environment = 'aliphone'; // 手机支付宝
|
||
} else {
|
||
environment = 'alipc'; // PC支付宝
|
||
}
|
||
} else if (userAgent.includes('android') || userAgent.includes('iphone') || userAgent.includes('ipad')) {
|
||
// 先判断是否是已知的手机APP内置浏览器,如果不是则认为是手机浏览器
|
||
if (!userAgent.includes('micromessenger') && !userAgent.includes('aliapp') && !userAgent.includes('qq')) {
|
||
environment = 'phone'; // 手机浏览器
|
||
}
|
||
} else {
|
||
environment = 'pc'; // 剩下的情况认为是PC浏览器
|
||
}
|
||
return environment;
|
||
}
|
||
const payCode = '<?php echo $payUrl; ?>';
|
||
const codeType = '<?php echo htmlentities($code_type); ?>';
|
||
const payType = '<?php echo htmlentities($type); ?>';
|
||
const order = '<?php echo htmlentities($order_id); ?>';
|
||
const environment = detectBrowserEnvironment();
|
||
const payclient = '<?php echo htmlentities($payclient ?? ""); ?>';
|
||
if (payclient == 'Alipayf' && environment == 'aliphone') {
|
||
window.location.href = payCode;
|
||
}
|
||
</script>
|
||
<style>
|
||
body {
|
||
background: #f7f7f7;
|
||
}
|
||
|
||
.card {
|
||
margin: 18px auto 18px;
|
||
padding: 38px 16px 0px;
|
||
background: #fff;
|
||
-webkit-box-shadow: 0 3px 3px 0 hsla(0, 0%, 92.5%, .44);
|
||
box-shadow: 0 3px 3px 0 hsla(0, 0%, 92.5%, .44);
|
||
border-radius: 12px;
|
||
text-align: center;
|
||
padding-bottom: 38px;
|
||
}
|
||
|
||
.order {
|
||
width: 340px;
|
||
margin: 15px auto 21px;
|
||
background: #fbfbfb;
|
||
border-radius: 6px;
|
||
line-height: 42px;
|
||
text-align: left;
|
||
}
|
||
|
||
.order span {
|
||
color: #999;
|
||
font-size: 15px;
|
||
margin-left: 14px;
|
||
}
|
||
|
||
.goods_name {
|
||
font-weight: 500;
|
||
font-size: 12px;
|
||
color: #999;
|
||
border-bottom: 1px solid #f5f5f5;
|
||
padding-bottom: 20px;
|
||
}
|
||
|
||
.price {
|
||
color: #386cfa;
|
||
width: 100%;
|
||
text-align: center;
|
||
margin-top: 16px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.price>span:first-child {
|
||
font-size: 28px;
|
||
}
|
||
|
||
.price>span:last-child {
|
||
font-size: 17px;
|
||
}
|
||
|
||
.price span {
|
||
font-weight: 700;
|
||
}
|
||
|
||
.qrcode>img {
|
||
height: 200px;
|
||
}
|
||
|
||
.msg {
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.msg>p {
|
||
color: red;
|
||
font-weight: 700;
|
||
line-height: 2em;
|
||
}
|
||
|
||
.msg>p:nth-child(1) {
|
||
font-size: 17px;
|
||
}
|
||
|
||
.shanxinzha {
|
||
margin-top: 32px;
|
||
width: 100%;
|
||
text-align: center;
|
||
}
|
||
|
||
.shanxinzha p {
|
||
color: #999;
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
margin-left: 5px;
|
||
}
|
||
|
||
.note {
|
||
color: red;
|
||
font-size: 22px;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div id="app" class="layui-container">
|
||
<div class="layui-row">
|
||
<div class="card" style="padding-bottom: 18px;padding-top: 15px;">
|
||
<div style="text-align: center;">
|
||
<svg style="vertical-align: middle;" t="1610806307396" viewBox="0 0 1024 1024" version="1.1"
|
||
xmlns="http://www.w3.org/2000/svg" p-id="6171" width="26" height="26">
|
||
<path
|
||
d="M1024 199.18v410.38c0 110-89.54 199.18-200 199.18H200c-110.46 0-200-89.18-200-199.18V199.18C0 89.17 89.54 0 200 0h624c110.46 0 200 89.17 200 199.18z m-553.95 317v46.72q0.9 19.32 12 28.75t30.9 9.43q40.14 0 41.95-38.18v-47.58l86.6 0.45q11.73-0.9 18.49-8.76t7.67-19.54a33.48 33.48 0 0 0-7.67-19.32q-6.77-8.09-18.49-9h-86.6v-27.4l86.15-0.45q11.73-0.9 18.72-9a33.26 33.26 0 0 0 7.89-19.76q-0.9-11.23-7.67-18.42t-18.49-8.09h-66.3l69.91-113.2q9-11.68 9-24.71a50.37 50.37 0 0 0-4.28-15.27 24.48 24.48 0 0 0-7.22-9 27.29 27.29 0 0 0-9.92-4.49 74.75 74.75 0 0 0-12.4-1.8 43.43 43.43 0 0 0-19.4 7.19 54.51 54.51 0 0 0-14 13.48l-75.34 125.83L443 229.18A65.48 65.48 0 0 0 429 215a36.39 36.39 0 0 0-19.4-7.41q-18.49 2.25-25.26 10.11t-9 20.44a36.94 36.94 0 0 0 3.61 18.19 67.53 67.53 0 0 0 8.57 13.7l60.44 106H383q-12.18 0.9-18.72 8.09t-7.89 18.42q1.35 11.68 7.89 19.32t18.72 8.56l87.05 0.45v28.3H383q-12.18 0.9-18.72 8.09t-7.89 18.42a43.81 43.81 0 0 0 7.89 20.44q6.54 9.21 18.72 10.11h87.05z"
|
||
fill="#4375ff" p-id="6172"></path>
|
||
<path
|
||
d="M264.96 903.6m60.2 0l373.67 0q60.2 0 60.2 60.2l0 0q0 60.2-60.2 60.2l-373.67 0q-60.2 0-60.2-60.2l0 0q0-60.2 60.2-60.2Z"
|
||
fill="#4375ff" p-id="6173"></path>
|
||
</svg>
|
||
<img id="payType" style="vertical-align: middle;" src="" style="height:30px;">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layui-row">
|
||
<div class="card">
|
||
<div class="order"><span>商户订单号:<span id="order">
|
||
<?php echo htmlentities($out_trade_no); ?>
|
||
</span></span></div>
|
||
<div class="goods_name"><span>商品名称:<span id="goods_name">
|
||
<?php echo htmlentities($name); ?>
|
||
</span></span></div>
|
||
<div class="price"><span id="money">
|
||
<?php echo htmlentities($really_price); ?>
|
||
</span><span>元</span></div>
|
||
<div class="qrcode"><img id="qrcode" src="/static/img/loading.gif">
|
||
</div>
|
||
<!-- 添加跳转按钮 -->
|
||
<div style="margin: 16px auto;display: none;">
|
||
<button id="openApp" class="layui-btn layui-btn-normal">
|
||
打开支付应用
|
||
</button>
|
||
</div>
|
||
<div class="msg">
|
||
<p>请付款 <span class="note">
|
||
<?php echo htmlentities($really_price); ?>
|
||
</span> 元,注意不能多付或少付</p>
|
||
<p>付款后,请等待 5 秒查看</p>
|
||
<p id="divTime"></p>
|
||
</div>
|
||
<div class="shanxinzha">
|
||
<p id="payTypeText"></p>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script src="/component/layui/layui.js"></script>
|
||
<script src="/static/js/awesome-qr.min.js"></script>
|
||
<script>
|
||
const QR = AwesomeQR.AwesomeQR;
|
||
(async () => {
|
||
// 支付类型
|
||
const payTpeyImg = document.getElementById('payType');
|
||
const payTypeText = document.getElementById('payTypeText');
|
||
if (payType === 'wxpay') {
|
||
payTpeyImg.src = '/static/img/weixin.jpg';
|
||
payTypeText.innerText = '请使用微信扫码支付'
|
||
} else if (payType === 'alipay') {
|
||
payTpeyImg.src = '/static/img/alipay.jpg';
|
||
payTypeText.innerText = '请使用支付宝扫码支付'
|
||
} else if (payType === 'unionpay') {
|
||
payTpeyImg.src = '/static/img/unionpay.jpg';
|
||
payTypeText.innerText = '请使用云闪付扫码支付'
|
||
}
|
||
// 生成二维码
|
||
if (codeType == 0) {
|
||
if (payType === 'alipay' && environment === 'pc') {
|
||
// 解析网址
|
||
const url = new URL(payCode);
|
||
const queryParams = new URLSearchParams(url.search);
|
||
const qrcode = queryParams.get('qrcode');
|
||
const decodedQrcode = decodeURIComponent(qrcode);
|
||
document.getElementById('qrcode').src = await getQrcode(decodedQrcode, QR);
|
||
} else {
|
||
document.getElementById('qrcode').src = await getQrcode(payCode, QR);
|
||
}
|
||
} else {
|
||
document.getElementById('qrcode').src = payCode;
|
||
}
|
||
// 订单过期时间
|
||
let passtime = 0;
|
||
// 订单状态查询
|
||
let orderTimer = 0;
|
||
const queryOrder = async (url) => {
|
||
if (orderTimer) { clearTimeout(orderTimer); }
|
||
const res = await fetch(url);
|
||
const jsonData = await res.json();
|
||
orderTimer = setTimeout(() => { queryOrder(url) }, 1000);
|
||
if (jsonData.state === 1) {
|
||
clearTimeout(orderTimer);
|
||
layer.closeAll();
|
||
document.getElementById('divTime').innerHTML = '<small class="note">订单支付成功</small>';
|
||
document.getElementById('qrcode').src = '/static/img/pay_ok.png';// 输出支付成功提示图片
|
||
setTimeout(() => {
|
||
location.href = jsonData.return_url;
|
||
}, 1500);
|
||
}
|
||
passtime = jsonData.passtime;
|
||
if (passtime <= 0) {
|
||
clearTimeout(orderTimer);
|
||
}
|
||
timer(passtime);
|
||
}
|
||
queryOrder(`/getOrderState/${order}`);
|
||
})();
|
||
/* <?php if ($patt == 0 && $passtime > 0) { ?> */
|
||
// 验证支付结果
|
||
const id = '<?php echo htmlentities($id);?>';
|
||
const reVali = (step) => {
|
||
setTimeout(() => {
|
||
layer.confirm('是否已支付?', { icon: 3, title: '提示', closeBtn: 0 },
|
||
(index) => {
|
||
(async () => {
|
||
const res = await validatePayResult(id, 1);
|
||
if (res) { reVali(8000) }
|
||
})()
|
||
layer.close(index);
|
||
}, (index) => {
|
||
reVali(5000);
|
||
layer.close(index);
|
||
})
|
||
}, step);
|
||
}
|
||
reVali(10000);
|
||
// 验证支付结果
|
||
async function validatePayResult(id, patt) {
|
||
const lay = layer.load(2);
|
||
let data = { id: id, patt: patt };
|
||
const res1 = await fetch(`/validatePayResult`, { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
|
||
const rec1_info = await res1.json();
|
||
const info = await new Promise((resolve, reject) => {
|
||
setTimeout(() => {
|
||
data.patt = 0;
|
||
fetch(`/validatePayResult`, { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) })
|
||
.then((res2) => { return res2.json() }).then((rec2_info) => {
|
||
if (rec2_info.code == 0) {
|
||
layer.close(lay);
|
||
layer.msg('验证失败,稍后重新验证!');
|
||
resolve(true);
|
||
} else {
|
||
layer.close(lay);
|
||
layer.msg(rec2_info.msg);
|
||
resolve(false);
|
||
}
|
||
});
|
||
}, 5000);
|
||
})
|
||
return info;
|
||
}
|
||
/* <?php } ?> */
|
||
|
||
// 环境判断
|
||
if (payType === 'wxpay' && environment === 'aliphone') {
|
||
layer.alert('请使用微信打开此页面');
|
||
} else if (payType === 'alipay' && environment === 'wxphone') {
|
||
layer.alert('请使用支付宝打开此页面');
|
||
}
|
||
// 添加按钮控制逻辑
|
||
const openAppBtn = document.getElementById('openApp');
|
||
if (environment === 'phone') {
|
||
openAppBtn.parentNode.style.display = 'block';
|
||
if (payType === 'wxpay') {
|
||
openAppBtn.innerText = '截图并打开微信';
|
||
openAppBtn.className = 'layui-btn layui-btn-green';
|
||
openAppBtn.onclick = function () {
|
||
window.location.href = 'weixin://';
|
||
};
|
||
} else if (payType === 'alipay') {
|
||
openAppBtn.innerText = '打开支付宝付款';
|
||
openAppBtn.className = 'layui-btn layui-btn-normal';
|
||
openAppBtn.onclick = function () {
|
||
if (codeType == 0) {
|
||
const payUrl = encodeURIComponent(payCode);
|
||
window.location.href = 'alipays://platformapi/startapp?appId=20000067&&url=' + payUrl;
|
||
} else {
|
||
const currentUrl = encodeURIComponent(window.location.href);
|
||
window.location.href = 'alipays://platformapi/startapp?appId=20000067&&url=' + currentUrl;
|
||
}
|
||
};
|
||
}
|
||
}
|
||
// 生成二维码
|
||
async function getQrcode(text, QR) {
|
||
const qrcodeUrl = await new Promise((resolve) => {
|
||
new QR({
|
||
text: text,
|
||
size: 500,
|
||
}).draw().then((dataURL) => { resolve(dataURL); });
|
||
})
|
||
return qrcodeUrl;
|
||
}
|
||
// 倒计时
|
||
function timer(passtime) {
|
||
let minute = 0, second = 0; // 时间默认值
|
||
if (passtime > 0) {
|
||
minute = Math.floor(passtime / 60);
|
||
second = Math.floor(passtime) - (minute * 60);
|
||
}
|
||
if (passtime <= 0) {
|
||
document.getElementById('divTime').innerHTML = '<small class="note">订单二维码已过期</small>';
|
||
document.getElementById('qrcode').src = '/static/img/qrcode_timeout.png';// 输出过期二维码提示图片
|
||
} else {
|
||
document.getElementById('divTime').innerHTML = `二维码有效时间:<small class="note">${minute}</small>分<small class="note">${second}</small> 秒,失效勿付`;
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |