Files
Django/templates/wechat/h5_jsapi_pay.html
T

260 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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: #111; color: #eee; }
.wrap { max-width: 640px; margin: 0 auto; padding: 24px 16px 48px; }
.title { font-size: 18px; font-weight: 700; margin-bottom: 8px; color: #fff; }
.sub { font-size: 14px; color: #aaa; line-height: 1.5; margin-bottom: 16px; word-break: break-all; }
.btn {
display: block; width: 100%; padding: 14px; font-size: 16px; font-weight: 600;
border: none; border-radius: 10px; background: #07c160; color: #fff; margin-bottom: 10px;
}
.btn.gray { background: #333; }
.btn[disabled] { opacity: 0.55; }
pre {
margin-top: 12px; padding: 12px; background: #000; color: #0f0;
font-size: 11px; line-height: 1.45; white-space: pre-wrap; word-break: break-all;
border-radius: 8px; max-height: 70vh; overflow: auto;
border: 1px solid #333;
}
.ok { color: #07c160; }
.err { color: #ff5a5a; }
</style>
</head>
<body>
<div class="wrap">
<div class="title">微信支付(诊断模式)</div>
<div class="sub" id="tip">初始化…</div>
<button class="btn" type="button" id="payBtn">立即支付 / 重试</button>
<button class="btn gray" type="button" id="copyBtn">复制下方全部诊断到剪贴板</button>
<pre id="log">loading…</pre>
</div>
<script>
(function () {
var STORAGE_KEY = 'wx_h5_jsapi_pay';
var tip = document.getElementById('tip');
var btn = document.getElementById('payBtn');
var copyBtn = document.getElementById('copyBtn');
var logEl = document.getElementById('log');
var lines = [];
var payload = null;
var pay = null;
var returnUrl = '';
function now() {
try { return new Date().toISOString(); } catch (e) { return String(Date.now()); }
}
function push() {
var args = Array.prototype.slice.call(arguments);
var s = '[' + now() + '] ' + args.map(function (x) {
if (x == null) return String(x);
if (typeof x === 'string') return x;
try { return JSON.stringify(x, null, 2); } catch (e) { return String(x); }
}).join(' ');
lines.push(s);
logEl.textContent = lines.join('\n\n');
try { console.log.apply(console, args); } catch (e) {}
}
function setTip(t, isErr) {
tip.innerHTML = t;
tip.className = 'sub ' + (isErr ? 'err' : '');
}
function safeGetStorage() {
try {
return sessionStorage.getItem(STORAGE_KEY);
} catch (e) {
push('sessionStorage.getItem 异常', String(e && e.message || e));
return null;
}
}
function dumpEnv(tag) {
var href = '';
var hash = '';
var origin = '';
var path = '';
var beforeHash = '';
try {
href = String(location.href || '');
hash = String(location.hash || '');
origin = String(location.origin || '');
path = String(location.pathname || '');
beforeHash = href.split('#')[0];
} catch (e) {
push('读 location 失败', String(e));
}
push('==== ' + tag + ' ====');
push('location.href', href);
push('微信校验用的 URL(# 前面)', beforeHash);
push('location.origin', origin);
push('location.pathname', path);
push('location.hash', hash);
push('document.URL', String(document.URL || ''));
push('document.referrer', String(document.referrer || '(空)'));
push('userAgent', String(navigator.userAgent || ''));
push('WeixinJSBridge', typeof WeixinJSBridge === 'undefined' ? 'undefined' : 'ready');
push('应匹配的授权目录前缀', 'https://www.abas.asia/hqhd/dingdan/');
push('beforeHash 是否以该前缀开头', beforeHash.indexOf('https://www.abas.asia/hqhd/dingdan/') === 0);
push('beforeHash 是否以 xqh5 开头', beforeHash.indexOf('https://www.abas.asia/xqh5/') === 0);
}
try {
var raw = safeGetStorage();
push('sessionStorage 原始长度', raw ? raw.length : 0);
push('sessionStorage 原始内容', raw || '(空,支付参数没带过来)');
payload = raw ? JSON.parse(raw) : null;
} catch (e) {
payload = null;
push('解析 sessionStorage JSON 失败', String(e && e.message || e));
}
pay = payload && payload.pay ? payload.pay : null;
returnUrl = (payload && payload.returnUrl) || '';
dumpEnv('页面加载');
push('payload.orderId', payload && payload.orderId);
push('payload.returnUrl', returnUrl || '(空)');
push('payload.ts', payload && payload.ts);
if (pay) {
push('pay.appId', pay.appId || pay.appid || '(空)');
push('pay.timeStamp', pay.timeStamp);
push('pay.nonceStr', pay.nonceStr);
push('pay.package', pay.package);
push('pay.signType', pay.signType || '(默认MD5)');
push('pay.paySign 前8位', String(pay.paySign || '').slice(0, 8));
push('pay.paySign 长度', String(pay.paySign || '').length);
push('完整 pay 对象', pay);
} else {
push('pay 对象', '(没有,无法调起支付)');
}
function goBack() {
try { sessionStorage.removeItem(STORAGE_KEY); } catch (e) {}
if (returnUrl) {
location.replace(returnUrl);
return;
}
history.length > 1 ? history.back() : setTip('支付完成,请返回点单页');
}
function invokePay() {
dumpEnv('点击/自动调起前');
if (!pay || !pay.timeStamp || !pay.nonceStr || !pay.package || !pay.paySign) {
setTip('支付参数丢失,请返回重新下单(见下方日志)', true);
push('中止:pay 参数不完整', pay);
return;
}
if (typeof WeixinJSBridge === 'undefined') {
setTip('WeixinJSBridge 不存在,请用微信内置浏览器打开', true);
push('中止:无 WeixinJSBridge');
return;
}
var appId = pay.appId || pay.appid || '';
if (!appId) {
setTip('缺少 appId', true);
push('中止:无 appId');
return;
}
var req = {
appId: appId,
timeStamp: String(pay.timeStamp),
nonceStr: pay.nonceStr,
package: pay.package,
signType: pay.signType || 'MD5',
paySign: pay.paySign
};
push('即将 WeixinJSBridge.invoke getBrandWCPayRequest', {
appId: req.appId,
timeStamp: req.timeStamp,
nonceStr: req.nonceStr,
package: req.package,
signType: req.signType,
paySign_len: String(req.paySign || '').length
});
setTip('正在调起微信支付…');
btn.disabled = true;
try {
WeixinJSBridge.invoke('getBrandWCPayRequest', req, function (res) {
btn.disabled = false;
dumpEnv('微信回调时');
push('微信回调 res 完整对象', res);
push('微信回调 JSON', (function () {
try { return JSON.stringify(res); } catch (e) { return String(res); }
})());
var msg = (res && res.err_msg) || '';
var errDesc = (res && (res.err_desc || res.errMsg || res.err_msg)) || '';
push('err_msg', msg);
push('err_desc/其它', errDesc);
// 把所有可枚举字段打出来
try {
var keys = [];
for (var k in res) {
if (Object.prototype.hasOwnProperty.call(res, k)) {
keys.push(k + '=' + res[k]);
}
}
push('res 所有字段', keys.join(' | '));
} catch (e) {}
if (msg === 'get_brand_wcpay_request:ok') {
setTip('<span class="ok">支付成功,正在返回…</span>');
setTimeout(goBack, 500);
} else if (msg.indexOf('cancel') >= 0) {
setTip('已取消,可点按钮重试');
} else {
setTip('<span class="err">支付失败:' + (msg || '未知') + '</span><br/>把下方绿色日志整段复制发给技术', true);
push('!!!! 支付失败,请把本页全部绿色日志复制发送 !!!!');
push('若含「URL未注册」,对照:微信校验 URL 必须落在商户 JSAPI 授权目录前缀下');
push('当前校验 URL', String(location.href || '').split('#')[0]);
push('调起用的 appId', appId);
try {
alert('支付失败诊断\n\n' + msg + '\n\nappId=' + appId + '\nURL=' + String(location.href || '').split('#')[0] + '\n\n完整日志在页面绿色区域,点「复制」');
} catch (e) {}
}
});
} catch (e) {
btn.disabled = false;
push('invoke 抛异常', String(e && e.message || e), e);
setTip('调起异常:' + String(e && e.message || e), true);
}
}
copyBtn.onclick = function () {
var text = logEl.textContent || '';
function ok() { setTip('已复制,去粘贴发给技术'); }
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(ok).catch(function () {
prompt('请手动全选复制:', text);
});
} else {
prompt('请手动全选复制:', text);
}
};
btn.onclick = invokePay;
if (!pay) {
setTip('支付参数丢失:请从星阙点单页重新点「确认支付」再跳进来', true);
push('提示:同域 sessionStorage 丢失常见于开了新窗口/清理缓存;请勿复制链接单独打开本页');
return;
}
setTip('参数已就绪,自动调起支付…');
if (typeof WeixinJSBridge === 'undefined') {
document.addEventListener('WeixinJSBridgeReady', invokePay, false);
push('等待 WeixinJSBridgeReady');
} else {
setTimeout(invokePay, 80);
}
})();
</script>
</body>
</html>