|
|
|
@ -4,8 +4,12 @@ |
|
|
|
<div class="index_rootContainer"> |
|
|
|
<b class="title">扫码登录</b> |
|
|
|
<p class="sub_title mt32">打开 <b>微信</b> 扫码登录</p> |
|
|
|
<div class=" mb32"> |
|
|
|
<vue-qr :text="url" :size="192" :dot-scale="1"></vue-qr> |
|
|
|
<div class=" mb32" v-if="status == 'waiting'"> |
|
|
|
<vue-qr :text="qrCodeUrl" :size="192" :dot-scale="1"></vue-qr> |
|
|
|
</div> |
|
|
|
<div class="refreshCode" v-if="status == 'expired'" @click="refreshCode"> |
|
|
|
<i class="el-icon-refresh"></i> |
|
|
|
刷新二维码 |
|
|
|
</div> |
|
|
|
<!-- :logo-src="logoUrl" |
|
|
|
:logo-scale="0.2" --> |
|
|
|
@ -43,15 +47,155 @@ export default { |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
url: 'https://example.com', |
|
|
|
logoUrl: '/path/to/logo.png', |
|
|
|
checked: false |
|
|
|
checked: true, |
|
|
|
qrCodeUrl: 'https://example.com', |
|
|
|
token: '', |
|
|
|
status: 'expired', // waiting, scanned, confirmed, expired, error |
|
|
|
loginTime:'', |
|
|
|
} |
|
|
|
}, |
|
|
|
created(){ |
|
|
|
// this.generateQRCode() |
|
|
|
}, |
|
|
|
beforeDestroy() { |
|
|
|
this.clearTimers(); |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
jumpDoc() { |
|
|
|
|
|
|
|
} |
|
|
|
}, |
|
|
|
// 刷新二维码 |
|
|
|
refreshCode() { |
|
|
|
|
|
|
|
}, |
|
|
|
async generateQRCode() { |
|
|
|
this.status = 'waiting'; |
|
|
|
this.qrCodeUrl = ''; |
|
|
|
|
|
|
|
try { |
|
|
|
await this.$http('POST', '/api/admin/generate_qrcode', { |
|
|
|
device_type: 'web', |
|
|
|
timestamp: Date.now() |
|
|
|
}).then(response => { |
|
|
|
this.token = response.data.token; |
|
|
|
this.qrCodeUrl = response.data.qr_code_url; |
|
|
|
|
|
|
|
// 开始轮询检查状态 |
|
|
|
this.startPolling(); |
|
|
|
|
|
|
|
// 设置二维码过期时间(5分钟) |
|
|
|
this.setExpireTimer(); |
|
|
|
}).catch(error => { |
|
|
|
console.error('生成二维码失败:', error); |
|
|
|
this.status = 'error'; |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
console.error('生成二维码失败:', error); |
|
|
|
this.status = 'error'; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 开始轮询检查扫码状态 |
|
|
|
startPolling() { |
|
|
|
this.clearTimers(); |
|
|
|
|
|
|
|
this.pollInterval = setInterval(async () => { |
|
|
|
if (this.status === 'confirmed' || this.status === 'expired' || this.status === 'error') { |
|
|
|
this.clearTimers(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
await this.$http('POST', '/api/admin/check_scan_status', { |
|
|
|
token: this.token |
|
|
|
}).then(response => { |
|
|
|
this.status = response.data.status; |
|
|
|
|
|
|
|
if (response.data.status === 'scanned') { |
|
|
|
// 扫码后等待确认 |
|
|
|
setTimeout(() => { |
|
|
|
this.handleLoginConfirm(); |
|
|
|
}, 2000); |
|
|
|
} else if (response.data.status === 'confirmed') { |
|
|
|
this.handleLoginSuccess(response.data); |
|
|
|
} else if (response.data.status === 'expired') { |
|
|
|
this.status = 'expired'; |
|
|
|
this.clearTimers(); |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
console.error('检查扫码状态失败:', error); |
|
|
|
this.status = 'error'; |
|
|
|
this.clearTimers(); |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
console.error('检查扫码状态失败:', error); |
|
|
|
this.status = 'error'; |
|
|
|
this.clearTimers(); |
|
|
|
} |
|
|
|
}, 2000); |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理登录确认 |
|
|
|
async handleLoginConfirm() { |
|
|
|
try { |
|
|
|
await this.$http('POST', '/api/admin/confirm_login', { |
|
|
|
token: this.token |
|
|
|
}).then(response => { |
|
|
|
if (response.data.success) { |
|
|
|
this.handleLoginSuccess(response.data); |
|
|
|
} else { |
|
|
|
this.status = 'expired'; |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
console.error('登录确认失败:', error); |
|
|
|
this.status = 'error'; |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
console.error('登录确认失败:', error); |
|
|
|
this.status = 'error'; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理登录成功 |
|
|
|
handleLoginSuccess(data) { |
|
|
|
this.status = 'confirmed'; |
|
|
|
this.userInfo = data.user_info; |
|
|
|
this.loginTime = new Date().toLocaleString(); |
|
|
|
|
|
|
|
// 保存登录状态 |
|
|
|
localStorage.setItem('authToken', data.auth_token); |
|
|
|
localStorage.setItem('nick', JSON.stringify(data.nick)); |
|
|
|
localStorage.setItem('userInfo', JSON.stringify(data.user_info)); |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
this.isLoggedIn = true; |
|
|
|
this.$emit('login-success', data); |
|
|
|
}, 1000); |
|
|
|
}, |
|
|
|
|
|
|
|
// 设置过期定时器 |
|
|
|
setExpireTimer() { |
|
|
|
this.expireTimer = setTimeout(() => { |
|
|
|
if (this.status !== 'confirmed') { |
|
|
|
this.status = 'expired'; |
|
|
|
this.clearTimers(); |
|
|
|
} |
|
|
|
}, 5 * 60 * 1000); // 5分钟过期 |
|
|
|
}, |
|
|
|
|
|
|
|
// 清除所有定时器 |
|
|
|
clearTimers() { |
|
|
|
if (this.pollInterval) { |
|
|
|
clearInterval(this.pollInterval); |
|
|
|
this.pollInterval = null; |
|
|
|
} |
|
|
|
if (this.expireTimer) { |
|
|
|
clearTimeout(this.expireTimer); |
|
|
|
this.expireTimer = null; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
@ -140,9 +284,34 @@ export default { |
|
|
|
margin-bottom: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.refreshCode { |
|
|
|
width: 172px; |
|
|
|
height: 172px; |
|
|
|
background: rgba(255, 255, 255, 0.3); |
|
|
|
backdrop-filter: blur(10px); |
|
|
|
-webkit-backdrop-filter: blur(10px); |
|
|
|
border-radius: 12px; |
|
|
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 10px; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
color: #626573; |
|
|
|
font-family: Arial, sans-serif; |
|
|
|
font-weight: bold; |
|
|
|
cursor: pointer; |
|
|
|
margin: 20px auto; |
|
|
|
i{ |
|
|
|
font-size: 28px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@media(max-width: 1420px) { |
|
|
|
.index_rootContainer { |
|
|
|
margin-right: 102px |
|
|
|
margin-right: 102px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|