feat: H5 点单微信密码支付中转页(落在已登记 /hqhd/dingdan/)

This commit is contained in:
XingQue committed 2026-08-12 19:39:29 +08:00
1 parent 644fd47f0a
commit f6cd0bc747
4 files changed
+116 -1

No files matched your search

+2 -1
View File
@@ -1,6 +1,6 @@
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .views import CreateOrderView, WechatPayNotifyView, AlipayPayNotifyView, alipay_pay_page, wx_native_pay_page, WxNativeScanPayView, \
from .views import CreateOrderView, WechatPayNotifyView, AlipayPayNotifyView, alipay_pay_page, wx_h5_jsapi_pay_page, wx_native_pay_page, WxNativeScanPayView, \
PaymentFailView, PaymentVerifyView, ContinuePayView, DingdanHuoquView, DingdanXiangqingView, JiedanView, \
ShangpinLeixingView, ShangjiaPaifaView, ShangjiaDingdanHuoquView, ShangjiaJiesuanView, \
ShangjiaDingdanXiangqingView, ShangjiaChufaShenqingView, ShangjiaTuikuanShenqingView, \
@@ -24,6 +24,7 @@ urlpatterns = [
path('alipay-notify/', csrf_exempt(AlipayPayNotifyView.as_view()), name='老板下单支付宝支付回调'),
path('fubei-notify/', csrf_exempt(FubeiPayNotifyView.as_view()), name='付呗支付回调'),
path('alipay-pay/', csrf_exempt(alipay_pay_page), name='支付宝H5中转页'),
path('wx-h5-pay/', csrf_exempt(wx_h5_jsapi_pay_page), name='H5点单微信密码支付中转页'),
path('wx-native-pay/', csrf_exempt(wx_native_pay_page), name='微信Native扫码中转页'),
path('wx-native-scan-pay', WxNativeScanPayView.as_view(), name='微信小程序码扫码支付'),
path('shibai', PaymentFailView.as_view(), name='老板支付失败接口'),
+2
View File
@@ -10,6 +10,7 @@ from .payment import (
CreateOrderView,
ContinuePayView,
alipay_pay_page,
wx_h5_jsapi_pay_page,
wx_native_pay_page,
WxNativeScanPayView,
)
@@ -78,6 +79,7 @@ __all__ = [
"PaymentFailView", "WechatPayNotifyView", "AlipayPayNotifyView", "PaymentVerifyView", "CreateOrderView",
"ContinuePayView",
"alipay_pay_page",
"wx_h5_jsapi_pay_page",
"wx_native_pay_page",
"WxNativeScanPayView",
"DingdanHuoquView", "DingdanXiangqingView", "JiedanView",
+10
View File
@@ -530,6 +530,16 @@ def alipay_pay_page(request):
return render(request, 'alipay/pay.html', {})
def wx_h5_jsapi_pay_page(request):
"""H5 点单密码支付中转页(落在已登记的 /hqhd/dingdan/ 授权目录)。
不是扫码。仅把 WeixinJSBridge 调起挪到商户已配置的目录下,
避免 /xqh5/ 报「当前页面的URL未注册」。
支付参数由同域 sessionStorage 传入(前端写入)。
"""
return render(request, 'wechat/h5_jsapi_pay.html', {})
def wx_native_pay_page(request):
"""相册可扫的 HTTPS 中转页:OAuth 取服务号 openid → JSAPI → 直接出密码。
+102
View File
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>微信支付</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f7f7f7; }
.wrap { max-width: 420px; margin: 0 auto; padding: 56px 24px; text-align: center; }
.logo { width: 64px; height: 64px; margin: 0 auto 20px; border-radius: 14px; background: #07c160; color: #fff; font-size: 34px; line-height: 64px; font-weight: 700; }
.title { font-size: 20px; font-weight: 600; color: #111; margin-bottom: 10px; }
.sub { font-size: 14px; color: #888; line-height: 1.6; margin-bottom: 36px; }
.btn {
display: block; width: 100%; padding: 16px; font-size: 17px; font-weight: 600;
border: none; border-radius: 10px; background: #07c160; color: #fff;
}
.btn[disabled] { opacity: 0.6; }
</style>
</head>
<body>
<div class="wrap">
<div class="logo">微</div>
<div class="title">微信支付</div>
<div class="sub" id="tip">正在调起支付...</div>
<button class="btn" type="button" id="payBtn">立即支付</button>
</div>
<script>
(function () {
var STORAGE_KEY = 'wx_h5_jsapi_pay';
var tip = document.getElementById('tip');
var btn = document.getElementById('payBtn');
var payload = null;
try {
payload = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || 'null');
} catch (e) {
payload = null;
}
var pay = payload && payload.pay ? payload.pay : null;
var returnUrl = (payload && payload.returnUrl) || '';
function setTip(t) { tip.innerText = t; }
function goBack() {
try { sessionStorage.removeItem(STORAGE_KEY); } catch (e) {}
if (returnUrl) {
location.replace(returnUrl);
return;
}
history.length > 1 ? history.back() : setTip('支付完成,请返回点单页');
}
function invokePay() {
if (!pay || !pay.timeStamp || !pay.nonceStr || !pay.package || !pay.paySign) {
setTip('支付参数丢失,请返回重新下单');
return;
}
if (typeof WeixinJSBridge === 'undefined') {
setTip('请在微信内打开');
return;
}
var appId = pay.appId || pay.appid || '';
if (!appId) {
setTip('缺少 appId,请返回重试');
return;
}
btn.disabled = true;
WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId: appId,
timeStamp: String(pay.timeStamp),
nonceStr: pay.nonceStr,
package: pay.package,
signType: pay.signType || 'MD5',
paySign: pay.paySign
}, function (res) {
btn.disabled = false;
var msg = (res && res.err_msg) || '';
if (msg === 'get_brand_wcpay_request:ok') {
setTip('支付成功,正在返回...');
setTimeout(goBack, 400);
} else if (msg.indexOf('cancel') >= 0) {
setTip('已取消,可再次点击支付');
} else {
setTip(msg || '支付未完成,请重试');
}
});
}
btn.onclick = invokePay;
if (!pay) {
setTip('支付参数丢失,请返回点单页重新下单');
return;
}
if (typeof WeixinJSBridge === 'undefined') {
document.addEventListener('WeixinJSBridgeReady', invokePay, false);
} else {
setTimeout(invokePay, 80);
}
})();
</script>
</body>
</html>