208 lines
6.8 KiB
Handlebars
208 lines
6.8 KiB
Handlebars
{{/* 引入微信公众号二维码扫码注册、登录错误信息一次性提示信息 ctx.Flash.Error() 显示容器 */}}
|
||
{{template "base/alert" .}}
|
||
|
||
|
||
{{if .wechatQRScanSuccess}}
|
||
<!-- 扫码成功只做提示 -->
|
||
<div class="ui info message">
|
||
<p class="text center">{{ctx.Locale.Tr "settings.wechat_update_success"}}</p>
|
||
</div>
|
||
|
||
{{else}}
|
||
|
||
{{/* ============================================================= 扫码失败,需要扫码 - 开始 ============================================================= */}}
|
||
{{if .PageIsSignIn}}
|
||
<h4 class="ui top attached header center">
|
||
{{ctx.Locale.Tr "settings.wechat_qr_prompt"}}
|
||
</h4>
|
||
{{end}}
|
||
|
||
<div class="ui attached segment">
|
||
<form class="ui form tw-max-w-2xl tw-m-auto" method="post">
|
||
<div class="wechat-qr-container">
|
||
<img id="idWechatQr" class="wechat-qr-image" src="{{.wechatQrCodeUrl}}" alt="Wechat Official Accout QR Code Ticket {{.wechatQrTicket}}" />
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
|
||
<style>
|
||
.wechat-qr-container {
|
||
text-align: center; /* 将文本内容居中 */
|
||
position: relative; /* 添加相对定位 */
|
||
}
|
||
|
||
.wechat-qr-container {
|
||
text-align: center;
|
||
position: relative;
|
||
width: 100%;
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.wechat-qr-image {
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
width: 50%;
|
||
height: 50%;
|
||
}
|
||
|
||
.expire-mask {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.7); /* 半透明黑色遮罩 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 150%;
|
||
color: white;
|
||
text-shadow: 2px 2px 4px #000; /* 添加字体阴影效果 */
|
||
cursor: pointer;
|
||
/* 确保边框和内边距不会影响宽高 */
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.expire-mask .refresh-text {
|
||
color: #4183c4; /* 链接蓝色 */
|
||
text-decoration: underline;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
</style>
|
||
|
||
|
||
<script>
|
||
|
||
let timeoutQrTicketPolling = {{.wechatQrExpireSeconds}} * 1000 // 微信带参数临时二维码过期时间毫秒值
|
||
let isQrTicketWaitingPolling = true
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
|
||
// 提示微信二维码已经过期,停止轮询,并对二维码进行高斯模糊处理
|
||
const idTimeoutWechatQrExpires = setTimeout(
|
||
() => {
|
||
if (isQrTicketWaitingPolling){
|
||
/* 停止轮询 */
|
||
isQrTicketWaitingPolling = false;
|
||
|
||
/* 创建遮罩层 */
|
||
const qrContainer = document.querySelector('.wechat-qr-container');
|
||
const expireMask = document.createElement('div');
|
||
expireMask.className = 'expire-mask';
|
||
expireMask.innerHTML = `
|
||
<div>{{ctx.Locale.Tr "settings.wechat_qr_expired"}}</div><br/>
|
||
{{svg "octicon-sync" 36}}
|
||
`;
|
||
expireMask.addEventListener('click', () => window.location.reload());
|
||
qrContainer.appendChild(expireMask);
|
||
}
|
||
},
|
||
timeoutQrTicketPolling
|
||
);
|
||
|
||
// 定时查询微信二维码扫描状态
|
||
const idIntervalWechatQrPolling = setInterval(() => {
|
||
if (isQrTicketWaitingPolling) {
|
||
checkWechatQrTicketStatus( "{{ .wechatQrTicket }}" );
|
||
} else {
|
||
// 当不再需要轮询时,清除定时器
|
||
clearInterval(idIntervalWechatQrPolling);
|
||
}
|
||
},
|
||
1000); // 每秒执行一次
|
||
|
||
});
|
||
|
||
|
||
/*
|
||
* 查询后台二维码扫描状态
|
||
*
|
||
* GET https://${window.location.host}/api/wechat/login/qr/check-status?ticket=${ticket}&_=${currentTimestamp}
|
||
* 请求参数:
|
||
* - ticket:微信公众号带参数二维码兑换凭证
|
||
* - _ : 携带时间戳作为随机值,保证每次请求都能到达后端服务器,防止HTTP GET请求被浏览器缓存
|
||
* 响应:
|
||
* - 若用户未扫码,返回结果:{
|
||
code: 10001,
|
||
msg: "用户未扫码"
|
||
}
|
||
* - 若用户完成扫码,返回结果:{
|
||
code: 0,
|
||
msg:"扫码登录成功",
|
||
data: {
|
||
FromUserName: `${WechatQrScannerName}`
|
||
}
|
||
}
|
||
*/
|
||
function checkWechatQrTicketStatus(qrTicket) {
|
||
const urlCheckWechatQrTicketStatus = `${window.location.origin}/api/wechat/login/qr/check-status?` +
|
||
`ticket=${qrTicket}&` + `_=${Date.now()}`
|
||
|
||
if (!isQrTicketWaitingPolling)
|
||
return
|
||
|
||
fetch(urlCheckWechatQrTicketStatus)
|
||
.then(response => {
|
||
if (!response.ok) {
|
||
throw new Error('Network response was not ok');
|
||
}
|
||
return response.json();
|
||
})
|
||
.then(data => {
|
||
if (data.code === 0 && data.data.is_scanned) { // 标识扫码成功
|
||
console.log(data);
|
||
onLoginSuccess(qrTicket, data.data);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('There was a problem with the fetch operation:', error);
|
||
});
|
||
}
|
||
|
||
|
||
function onLoginSuccess(qrTicket, qrStatus) {
|
||
|
||
// 1. 停止微信二维码轮询和过期判断
|
||
isQrTicketWaitingPolling = false;
|
||
|
||
// 2. 移除二维码 img 标签
|
||
const qrImageElement = document.getElementById('idWechatQr')
|
||
if (qrImageElement) {
|
||
qrImageElement.parentNode.removeChild(qrImageElement);
|
||
}
|
||
|
||
// 3. 处理用户登录凭证 跳转到后端
|
||
switch (window.location.pathname) {
|
||
case '/user/login/wechat':
|
||
// 登录页面扫码成功
|
||
if (qrStatus.is_binded) {
|
||
// 已绑定用户跳转登录成功页面 /user/login/wechat/success?ticket=${qrTicket}
|
||
window.location.href = `${window.location.origin}/user/login/wechat/success?ticket=${qrTicket}&_=${Date.now()}`;
|
||
} else {
|
||
// 未绑定用户跳转到注册页 /user/sign_up?ticket=${qrTicket}
|
||
alert(`微信用户 ${qrStatus.openid} 未注册!\n\n请点击确定继续注册账号,或者改用密码登录后进入用户设置页面扫码绑定微信`)
|
||
window.location.href = `${window.location.origin}/user/sign_up?ticket=${qrTicket}&_=${Date.now()}`;
|
||
}
|
||
break;
|
||
case '/user/settings/account':
|
||
const confirmPrompt = '{{ctx.Locale.Tr "settings.wechat_bind_confirm" "${openid}" }}'.replace("${openid}", qrStatus.openid);
|
||
if (window.confirm(confirmPrompt)) {
|
||
// 绑定微信页面扫码成功:绑定成功页面 /user/settings/account/wechat/success?ticket=${qrTicket}
|
||
window.location.href = `${window.location.origin}/user/settings/account/wechat/bind-success?ticket=${qrTicket}&_=${Date.now()}`
|
||
}
|
||
break;
|
||
default:
|
||
console.log(`尚未支持的扫码页面 ${window.location.pathname}`);
|
||
alert(`微信用户 ${qrStatus.openid} 已成功扫码,但本页面不支持进一步操作,请联系管理员`);
|
||
}
|
||
}
|
||
|
||
|
||
</script>
|
||
|
||
{{/* ============================================================= 扫码失败,需要扫码 - 结束 ============================================================= */}}
|
||
{{end}}
|