10 changed files with 576 additions and 37 deletions
|
After Width: | Height: | Size: 357 KiB |
|
After Width: | Height: | Size: 9.3 MiB |
@ -0,0 +1,382 @@ |
|||||
|
<template> |
||||
|
<div class="index_loginPage__K_bGK login-wrap"> |
||||
|
<div class="index_banner__1d8CU"> |
||||
|
<div class="index_rootContainer"> |
||||
|
<b class="title">扫码登录</b> |
||||
|
<p class="sub_title mt32">打开 <b>微信</b> 扫码登录</p> |
||||
|
<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" --> |
||||
|
<div class="attention gap10"> |
||||
|
<el-checkbox v-model="checked"></el-checkbox> |
||||
|
<b>登录即代表同意 <a @click="jumpDoc">《用户协议》</a>和 <a @click="jumpDoc">《隐私条款》</a></b> |
||||
|
</div> |
||||
|
<p class="tip">若无账号,请先联系客服注册</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="style_footerWrapper"> |
||||
|
<div class="left flex"> |
||||
|
<img src="@/assets/doctor_h5.svg" alt=""> |
||||
|
<div> |
||||
|
<b>手机端</b> |
||||
|
<p>微信扫码体验</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="center"> |
||||
|
<p><b>入驻指南</b>个人入驻 组织(医院等)入驻</p> |
||||
|
<p><b>人工咨询</b>扫左侧码,进入手机端-我的-页面底部“联系我们”</p> |
||||
|
</div> |
||||
|
<div class="right"> |
||||
|
<p><b>网站备案</b>© 2012-2025 something , <a href="">Inc. All rights 测试</a></p> |
||||
|
<p></p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script> |
||||
|
import VueQr from 'vue-qr' |
||||
|
export default { |
||||
|
components: { |
||||
|
VueQr |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
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> |
||||
|
<style lang="scss" scoped> |
||||
|
.index_banner__1d8CU { |
||||
|
align-items: center; |
||||
|
background-image: url(../assets/login_backImg.svg); |
||||
|
background-size: cover; |
||||
|
display: flex; |
||||
|
flex: 1 1; |
||||
|
justify-content: flex-end; |
||||
|
-webkit-transition: padding-right .5s; |
||||
|
transition: padding-right .5s; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.index_rootContainer { |
||||
|
background: #fff; |
||||
|
border-radius: 16px; |
||||
|
box-shadow: 0 6px 40px 0 rgba(53, 76, 166, .08); |
||||
|
display: inline-block; |
||||
|
flex-shrink: 0; |
||||
|
height: 480px; |
||||
|
overflow: hidden; |
||||
|
width: 432px; |
||||
|
margin-right: 192px; |
||||
|
padding: 40px; |
||||
|
box-sizing: border-box; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
.title { |
||||
|
font-family: Microsoft YaHei; |
||||
|
font-size: 22px; |
||||
|
font-weight: bold; |
||||
|
line-height: normal; |
||||
|
text-align: center; |
||||
|
letter-spacing: 0.08em; |
||||
|
color: #1E2226; |
||||
|
} |
||||
|
|
||||
|
.sub_title { |
||||
|
font-family: Microsoft YaHei; |
||||
|
font-size: 12px; |
||||
|
font-weight: normal; |
||||
|
line-height: normal; |
||||
|
letter-spacing: 0.08em; |
||||
|
color: #626573; |
||||
|
margin-top: 32px; |
||||
|
margin-bottom: 12px; |
||||
|
} |
||||
|
|
||||
|
.img { |
||||
|
width: 192px; |
||||
|
height: 192px; |
||||
|
background: #006AFF; |
||||
|
margin: 0 auto; |
||||
|
margin-bottom: 32px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.attention, |
||||
|
.tip { |
||||
|
font-size: 12px; |
||||
|
font-weight: normal; |
||||
|
line-height: 13px; |
||||
|
letter-spacing: 0.08em; |
||||
|
color: #626573; |
||||
|
text-align: center; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
|
||||
|
b { |
||||
|
font-size: 12px; |
||||
|
font-weight: normal; |
||||
|
|
||||
|
a { |
||||
|
text-decoration: none; |
||||
|
color: #006AFF; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.attention { |
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.style_footerWrapper { |
||||
|
background: #f3f4f6; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
padding: 46px 49px; |
||||
|
width: 100%; |
||||
|
height: 192px; |
||||
|
box-sizing: border-box; |
||||
|
gap: 72px; |
||||
|
|
||||
|
b { |
||||
|
font-size: 12px; |
||||
|
font-weight: bold; |
||||
|
line-height: 13px; |
||||
|
letter-spacing: 0.08em; |
||||
|
color: #1E2226; |
||||
|
} |
||||
|
|
||||
|
.left { |
||||
|
gap: 12px; |
||||
|
|
||||
|
div { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 8px; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
img { |
||||
|
width: 97px; |
||||
|
height: 100px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.center, |
||||
|
.right { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 24px; |
||||
|
text-align: left; |
||||
|
|
||||
|
p { |
||||
|
display: flex; |
||||
|
gap: 8px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.style_iconWrapper__3qi7l { |
||||
|
flex-basis: 80px; |
||||
|
} |
||||
|
|
||||
|
.index_loginPage__K_bGK { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
height: 100vh; |
||||
|
min-width: 1200px; |
||||
|
} |
||||
|
|
||||
|
#ecomLoginForm { |
||||
|
height: 280px; |
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue