Files
devstar-create-from-template/templates/user/auth/signin_wechat_qr_inner.tmpl

208 lines
6.8 KiB
Handlebars
Raw Normal View History

2025-08-25 15:46:12 +08:00
{{/* 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}}