源文件
This commit is contained in:
520
jeepay-ui-agent/src/views/user/Forget.vue
Normal file
520
jeepay-ui-agent/src/views/user/Forget.vue
Normal file
@@ -0,0 +1,520 @@
|
||||
<template>
|
||||
<div id="userLayout" :class="['user-layout-wrapper']">
|
||||
<div class="top">
|
||||
<div class="header">
|
||||
<img :src="oemSiteInfo.sysLogoUrl" style="height: 30px">
|
||||
</div>
|
||||
<!-- <a class="mch-url" href="#">
|
||||
<span>商户登录</span>
|
||||
<i class="bi bi-arrow-right-short" />
|
||||
</a> -->
|
||||
</div>
|
||||
<div class="container" :style="[{background: 'url(' + oemSiteInfo.mgr.loginPageBGImgUrl + ')'}, {backgroundSize:'cover' }, {backgroundPosition: 'center top'}, {backgroundRepeat:'no-repeat'}]">
|
||||
<div class="user-layout-lang" />
|
||||
<div class="user-layout-content">
|
||||
<!-- 错误提示信息 -->
|
||||
<a-alert v-if="showLoginErrorInfo" type="error" showIcon style="margin-bottom: 24px;" :message="showLoginErrorInfo" />
|
||||
<div class="main">
|
||||
<div class="desc">找回密码</div>
|
||||
<a-form ref="formLogin" class="user-layout-login" :model="formState" :rules="vdata.rules" @submit="handleSubmit">
|
||||
<a-form-item name="phone" class="input-item">
|
||||
<login-text-up v-model:value="formState.phone" :isLogin="true" placeholder="手机号" />
|
||||
</a-form-item>
|
||||
<div class="code-body" >
|
||||
<div class="code code-layout-item" style="display: flex;justify-content:center">
|
||||
<a-form-item name="vercode" class="input-item">
|
||||
<login-text-up v-model:value="formState.vercode" :isLogin="true" placeholder="图形验证码" />
|
||||
</a-form-item>
|
||||
|
||||
<div class="code-img" style="position: relative;">
|
||||
<img v-show="vercodeImgSrc" :src="vercodeImgSrc" @click="refVercode()">
|
||||
<div v-show="isOverdue" class="vercode-mask" @click="refVercode()">
|
||||
已过期 请刷新
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="code">
|
||||
<a-form-item name="code" class="input-item">
|
||||
<login-text-up v-model:value="formState.code" :isLogin="true" placeholder="请输入验证码" />
|
||||
</a-form-item>
|
||||
|
||||
<div>
|
||||
<a-button type="primary" :disabled="vdata.isDisabled" style="height: 40px;margin-left: 10px" @click="sendSMS()">{{ vdata.codeBtnText }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item name="newPwd" class="input-item">
|
||||
<login-text-up v-model:value="formState.newPwd" :isLogin="true" placeholder="请输入新密码" isPassword="password" />
|
||||
</a-form-item>
|
||||
<a-form-item name="confirmPwd" class="input-item">
|
||||
<login-text-up v-model:value="formState.confirmPwd" :isLogin="true" placeholder="请确认新密码" isPassword="password" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item style="margin-bottom: 30px;">
|
||||
<!-- 忘记密码 -->
|
||||
<a class="forge-password" style="float: right;" @click="toLogin">去登录 >></a>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button
|
||||
size="large"
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
class="login-button submit"
|
||||
:loading="loginBtnLoadingFlag"
|
||||
style="width: 100%"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
确认
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="footer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { sendSmsCode, retrieve } from '@/api/login'
|
||||
import { $getPasswordRules } from '@/api/manage'
|
||||
import router from '@/router'
|
||||
import { vercode } from '@/api/login'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { useOem } from '@/store/modules/oem'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
let loginBtnLoadingFlag = false // 登录按钮是否显示 加载状态
|
||||
let showLoginErrorInfo = ref('') // 是否显示登录错误面板信息
|
||||
let timer: number = -1
|
||||
|
||||
let formLogin = ref()
|
||||
// 获取网站信息
|
||||
const oemSiteInfo = useOem().getSiteInfo()
|
||||
let isOverdue = ref(false) // 设置过期样式
|
||||
let vercodeImgSrc = ref('') // 验证码图片
|
||||
let vercodeToken = ref('') // 验证码验证token
|
||||
let formState = reactive({
|
||||
vercode:'',
|
||||
phone: '',
|
||||
code: '',
|
||||
newPwd: '',
|
||||
confirmPwd: '',
|
||||
})
|
||||
|
||||
const vdata = reactive({
|
||||
visibleCode:false,
|
||||
codeBtnText : '发送短信验证码',
|
||||
isDisabled : false,
|
||||
passwordRules: /^$/, //密码规则
|
||||
passwordRulesText: '', //密码规则提示文字
|
||||
rules : {
|
||||
phone: [{ required: true, pattern: /^1\d{10}$/, message: '请输入正确的手机号', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
||||
newPwd: [
|
||||
{ required: false, trigger: 'blur' }, {
|
||||
validator: (rule, value) => {
|
||||
if (!vdata.passwordRules.test(formState.newPwd)) {
|
||||
return Promise.reject(vdata.passwordRulesText)
|
||||
} else if(formState.newPwd !== formState.confirmPwd) {
|
||||
return Promise.reject('新密码与确认新密码不一致')
|
||||
} else return Promise.resolve()
|
||||
}
|
||||
}
|
||||
],
|
||||
confirmPwd: [{ required: false, trigger: 'blur' }, {
|
||||
validator: (rule, value) => {
|
||||
if (!vdata.passwordRules.test(formState.confirmPwd)) {
|
||||
return Promise.reject(vdata.passwordRulesText)
|
||||
} else if(formState.newPwd !== formState.confirmPwd) {
|
||||
return Promise.reject('新密码与确认新密码不一致')
|
||||
} else return Promise.resolve()
|
||||
}
|
||||
}]
|
||||
}
|
||||
})
|
||||
onMounted(()=>{
|
||||
getPasswordRules()
|
||||
refVercode()
|
||||
})
|
||||
|
||||
function getPasswordRules () { // 获取密码规则
|
||||
$getPasswordRules().then(res => {
|
||||
vdata.passwordRules = new RegExp(res.regexpRules)
|
||||
vdata.passwordRulesText = res.errTips
|
||||
})
|
||||
}
|
||||
// handler
|
||||
function handleSubmit (){
|
||||
formLogin.value.validate().then(valid =>{
|
||||
let params = {
|
||||
phone: formState.phone,
|
||||
code: formState.code,
|
||||
newPwd: formState.newPwd,
|
||||
vercode: formState.vercode,
|
||||
vercodeToken: vercodeToken.value,
|
||||
}
|
||||
retrieve(params).then((res) => {
|
||||
message.success('修改成功')
|
||||
router.push({ path: '/user/login' }) // 校验成功,返回登录页
|
||||
}).catch(err => {
|
||||
showLoginErrorInfo = (err.msg || JSON.stringify(err))
|
||||
loginBtnLoadingFlag = false
|
||||
})
|
||||
}).catch(valid =>{})
|
||||
}
|
||||
|
||||
function sendSMS () { // 发送短信验证
|
||||
if (!formState.phone) {
|
||||
return message.error('请输入手机号!')
|
||||
}
|
||||
// 校验手机号
|
||||
const reg = /^[1][0-9]{10}$/
|
||||
if (!reg.test(formState.phone)) {
|
||||
return message.error('请输入正确的手机号!')
|
||||
}
|
||||
|
||||
if (!vercodeToken.value) {
|
||||
return message.error('请输入验证码!')
|
||||
}
|
||||
if (!formState.vercode) {
|
||||
return message.error('请输入验证码!')
|
||||
}
|
||||
|
||||
vdata.isDisabled = true
|
||||
|
||||
sendSmsCode({ phone: formState.phone, smsType: 'retrieve', vercode: formState.vercode, vercodeToken: vercodeToken.value})
|
||||
.then(res => { return message.success('发送成功!')
|
||||
}).catch(err => {
|
||||
showLoginErrorInfo = (err.msg || JSON.stringify(err))
|
||||
loginBtnLoadingFlag = false
|
||||
// 出错后三秒停止计时
|
||||
setTimeout(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
vdata.isDisabled = false
|
||||
vdata.codeBtnText = '发送短信验证码'
|
||||
}, 500)
|
||||
})
|
||||
|
||||
let time = 60 // 重发验证码时间
|
||||
vdata.codeBtnText = `${time}秒后重新发送`
|
||||
const timer = setInterval(() => {
|
||||
time -= 1
|
||||
vdata.codeBtnText = `${time}秒后重新发送`
|
||||
if (time === 0) {
|
||||
clearInterval(timer)
|
||||
vdata.isDisabled = false
|
||||
vdata.codeBtnText = '发送短信验证码'
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 忘记密码跳转页面
|
||||
function toLogin () {
|
||||
router.push({ name: 'login', path: '/user/login' })
|
||||
}
|
||||
function refVercode() {
|
||||
// 刷新图片验证码
|
||||
// 获取图形验证码
|
||||
vercode().then((res) => {
|
||||
vercodeImgSrc.value = res.imageBase64Data
|
||||
vercodeToken.value = res.vercodeToken
|
||||
|
||||
isOverdue.value = false
|
||||
|
||||
if (timer) clearInterval(timer) // 如果多次点击则清除已有的定时器
|
||||
// 超过60秒提示过期刷新
|
||||
timer = window.setInterval(() => {
|
||||
res.expireTime--
|
||||
if (res.expireTime <= 0) {
|
||||
isOverdue.value = true
|
||||
clearInterval(timer)
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
function sendSMSCode(){
|
||||
vdata.visibleCode = true;
|
||||
refVercode()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#userLayout.user-layout-wrapper {
|
||||
height: 100%;
|
||||
.top {
|
||||
height: 80px;
|
||||
padding: 0 35px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
.mch-url {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
span{
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover{
|
||||
color: steelblue;
|
||||
.bi{
|
||||
transform: translateX(10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.bi{
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center; //修改这一项来决定登录对话框的水平位置,flex-start == left; center == center; flex-end == right
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: calc(100vh - 80px);
|
||||
background: #f0f2f5 url(/src/assets/svg/background.svg) no-repeat 50%;
|
||||
background-size: cover;
|
||||
//padding: 50px 0 84px;
|
||||
position: relative;
|
||||
transition: 0.3s ease;
|
||||
|
||||
.user-layout-lang {
|
||||
width: 100%;
|
||||
// height: 40px;
|
||||
// line-height: 44px;
|
||||
height: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.user-layout-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: 0.3s ease;
|
||||
input {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 50px 30px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
background: #fff;
|
||||
border-top: 1px solid #e7eaf3;
|
||||
align-items: center;
|
||||
transition: all 0.3s , border 0s ease;
|
||||
.ant-form{
|
||||
max-width: 300px;
|
||||
}
|
||||
.desc {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.04em;
|
||||
color: #2691ff;
|
||||
margin-bottom: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
.input-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
// position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
|
||||
.links {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
a {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
transition: all 0.3s;
|
||||
&:not(:last-child) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.copyright {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//登录页响应式的调整
|
||||
@media screen and (min-width:769px) and (max-width:1024px){
|
||||
.container {
|
||||
padding: 0 100px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width:1025px) and (max-width:1366px){
|
||||
.container {
|
||||
padding: 0 150px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width:1367px) and (max-width:1600px){
|
||||
.container {
|
||||
padding: 0 250px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width:1601px){
|
||||
.container {
|
||||
padding: 0 300px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-layout-login {
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.forge-password {
|
||||
font-size: 14px;
|
||||
color: @jee-theme;
|
||||
}
|
||||
|
||||
button.login-button {
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-login-other {
|
||||
text-align: left;
|
||||
margin-top: 24px;
|
||||
line-height: 22px;
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.code-input {
|
||||
width: 216px;
|
||||
}
|
||||
.code-img {
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
margin-left: 10px;
|
||||
|
||||
}
|
||||
}
|
||||
.submit {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.container_bg{
|
||||
position: fixed;
|
||||
background: transparent;
|
||||
width: 20%;
|
||||
height: 20%;
|
||||
top: 2%;
|
||||
left: 5%;
|
||||
}
|
||||
.code-body {
|
||||
// padding-bottom: 20px;
|
||||
padding-left: 1px;
|
||||
width: 314px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
12
jeepay-ui-agent/src/views/user/H5MchApplyment.vue
Normal file
12
jeepay-ui-agent/src/views/user/H5MchApplyment.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<JeepayH5MchApplymentPage />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
||||
import { provide } from 'vue'
|
||||
|
||||
|
||||
// 向所有子组件注入参数: 配置模式: mgrApplyment / agentApplyment / mchApplyment
|
||||
provide('configMode', 'agentApplyment')
|
||||
|
||||
</script>
|
||||
11
jeepay-ui-agent/src/views/user/H5MchApplymentOption.vue
Normal file
11
jeepay-ui-agent/src/views/user/H5MchApplymentOption.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<JeepayH5MchApplymentOptionPage />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
||||
import { provide } from 'vue'
|
||||
|
||||
// 向所有子组件注入参数: 配置模式: mgrApplyment / agentApplyment / mchApplyment
|
||||
provide('configMode', 'agentApplyment')
|
||||
|
||||
</script>
|
||||
929
jeepay-ui-agent/src/views/user/Login.vue
Normal file
929
jeepay-ui-agent/src/views/user/Login.vue
Normal file
@@ -0,0 +1,929 @@
|
||||
<template>
|
||||
<!-- <div class="content-header">-->
|
||||
<!-- <img :src="oemSiteInfo.sysLogoUrl" style="height: 30px">-->
|
||||
<!-- <div class="but-content">-->
|
||||
<!-- <div class="mch-app" @click="open()">获取{{ $SYS_NAME_MAP.AGENT_APP }}APP/小程序</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div
|
||||
class="content-body"
|
||||
:style="[{ background: 'url(' + oemSiteInfo.agent.loginPageBGImgUrl + ')' }, { backgroundSize: 'cover' }, { backgroundPosition: 'center top' }, { backgroundRepeat: 'no-repeat' }]"
|
||||
>
|
||||
<div class="content-main" :style="{ justifyContent: calcChildrenPosition() }">
|
||||
<!-- 轮播图部分 -->
|
||||
<div v-if="vdata.loginBgType == 1" class="banner-content" :style="{ order: calcPosition() }">
|
||||
<JeepayBanner :bannerList="vdata.bannerList" height="500px" />
|
||||
</div>
|
||||
<!-- 表单内容区域 -->
|
||||
<div class="user-layout-content">
|
||||
<!-- 错误提示信息 -->
|
||||
<a-alert
|
||||
v-if="showLoginErrorInfo"
|
||||
type="error"
|
||||
showIcon
|
||||
style="margin-bottom: 24px"
|
||||
:message="showLoginErrorInfo"
|
||||
/>
|
||||
<div class="main">
|
||||
<div class="tab-box">
|
||||
<div class="desc">服务商登录</div>
|
||||
<div class="tab">
|
||||
<!-- 密码登录 -->
|
||||
<a v-if="tabSign !== 'password'" class="operation-class" @click="tab('password')">密码登录</a>
|
||||
<span v-if="tabSign !== 'password' && tabSign !== 'message'" style="margin: 0 10px">|</span>
|
||||
<!-- 短信登录 -->
|
||||
<a v-if="tabSign !== 'message'" class="operation-class" @click="tab('message')">短信登录</a>
|
||||
<!-- <span v-if="tabSign !== 'QrCode'" style="margin: 0 10px">|</span>-->
|
||||
<!-- 短信登录 -->
|
||||
<!-- <a v-if="tabSign !== 'QrCode'" class="operation-class" @click="tab('QrCode')">扫码登录</a>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-form
|
||||
v-if="tabSign === 'password'"
|
||||
ref="formPwdLogin"
|
||||
class="user-layout-login"
|
||||
:model="formState"
|
||||
:rules="loginrules"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<a-form-item name="username" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.username"
|
||||
:disabled="!vdata.googleIsShow"
|
||||
:isLogin="true"
|
||||
:placeholder="vdata.googleIsShow ? '登录名/手机号' : ''"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="password" class="input-item" style="margin-bottom: -20px !important">
|
||||
<login-text-up
|
||||
v-model:value="formState.password"
|
||||
:disabled="!vdata.googleIsShow"
|
||||
:isLogin="true"
|
||||
:placeholder="vdata.googleIsShow ? '密码' : ''"
|
||||
isPassword="password"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<div class="code-body">
|
||||
<div class="code-layout" :class="{ googleShow: !vdata.googleIsShow }">
|
||||
<div class="code code-layout-item">
|
||||
<a-form-item name="vercode" class="input-item">
|
||||
<login-text-up v-model:value="formState.vercode" :isLogin="true" placeholder="图形验证码" />
|
||||
</a-form-item>
|
||||
|
||||
<div class="code-img" style="position: relative; background: #ddd">
|
||||
<img v-show="vercodeImgSrc" :src="vercodeImgSrc" @click="refVercode()">
|
||||
<div v-show="isOverdue" class="vercode-mask" @click="refVercode()">已过期 请刷新</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item v-if="!vdata.googleIsShow" name="mfaCode" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.mfaCode"
|
||||
style="width: 300px"
|
||||
placeholder="安全码"
|
||||
:isLogin="true"
|
||||
:isGoogle="'false'"
|
||||
class="code-layout-item"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-tag v-if="!vdata.googleIsShow" color="orange">您已开启虚拟MFA验证,请输入MFA动态安全码。</a-tag>
|
||||
<a-form-item >
|
||||
<!-- 自动登录 -->
|
||||
<!-- <a-checkbox v-model="isAutoLogin">自动登录</a-checkbox> -->
|
||||
|
||||
<!-- 忘记密码 -->
|
||||
<a class="operation-class" style="float: right" @click="toForgetPwd">忘记密码?</a>
|
||||
<!-- 注册 -->
|
||||
<a class="operation-class" style="float: left" @click="toRegister">注册</a>
|
||||
|
||||
<!-- <a-form-item name="checked">-->
|
||||
<!-- <a-checkbox-->
|
||||
<!-- v-model:checked="formState.checked"-->
|
||||
<!-- @click.stop.prevent="check"-->
|
||||
<!-- >我已阅读并同意<a-->
|
||||
<!-- class="forge-password"-->
|
||||
<!-- @click.stop.prevent="serviceAgreement"-->
|
||||
<!-- >《服务协议》</a-->
|
||||
<!-- >和<a class="forge-password" @click.stop.prevent="privacyPolicy"-->
|
||||
<!-- >《隐私政策》</a-->
|
||||
<!-- ></a-checkbox-->
|
||||
<!-- >-->
|
||||
<!-- </a-form-item>-->
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="checked">
|
||||
<a-checkbox class="checked_size" v-model:checked="formState.checked" @click.stop.prevent="check">我已阅读并同意</a-checkbox>
|
||||
<a class="forge-password checked_size" @click.stop.prevent="serviceAgreement">《服务协议》</a> <a class="forge-password checked_size" @click.stop.prevent="privacyPolicy">《隐私政策》</a>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-form
|
||||
v-if="tabSign === 'message'"
|
||||
ref="formLogin"
|
||||
class="user-layout-login"
|
||||
:model="formState"
|
||||
:rules="vdata.rules"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<a-form-item name="phone" class="input-item">
|
||||
<login-text-up v-model:value="formState.phone" :isLogin="true" placeholder="手机号" />
|
||||
</a-form-item>
|
||||
<div class="code-bodysms" >
|
||||
<div class="code code-layout-item" style="display: flex;justify-content:center">
|
||||
<a-form-item name="vercode" class="input-item">
|
||||
<login-text-up v-model:value="formState.vercode" :isLogin="true" placeholder="图形验证码" />
|
||||
</a-form-item>
|
||||
|
||||
<div class="code-img" style="position: relative;">
|
||||
<img v-show="vercodeImgSrc" :src="vercodeImgSrc" @click="refVercode()">
|
||||
<div v-show="isOverdue" class="vercode-mask" @click="refVercode()">
|
||||
已过期 请刷新
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="code">
|
||||
<a-form-item name="code" class="input-item">
|
||||
<login-text-up v-model:value="formState.code" :isLogin="true" placeholder="请输入验证码" />
|
||||
</a-form-item>
|
||||
<div>
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="vdata.isDisabled"
|
||||
style="height: 40px; margin-left: 10px"
|
||||
@click="sendSMS()"
|
||||
>
|
||||
{{ vdata.codeBtnText }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="code">-->
|
||||
<!-- <a-form-item name="vercode" class="input-item" />-->
|
||||
<!-- </div>-->
|
||||
<a-form-item>
|
||||
<!-- 忘记密码 -->
|
||||
<a class="operation-class" style="float: right" @click="toForgetPwd">忘记密码?</a>
|
||||
<!-- 注册 -->
|
||||
<a class="operation-class" style="float: left" @click="toRegister">注册</a>
|
||||
</a-form-item>
|
||||
|
||||
<!-- <a-form-item name="checked">-->
|
||||
<!-- <a-checkbox v-model:checked="formState.checked" @click.stop.prevent="check" >我已阅读并同意<a class="forge-password" @click.stop.prevent="serviceAgreement" >《服务协议》</a >和<a class="forge-password" @click.stop.prevent="privacyPolicy" >《隐私政策》</a ></a-checkbox >-->
|
||||
<!-- </a-form-item>-->
|
||||
<a-form-item name="checked">
|
||||
<a-checkbox class="checked_size" v-model:checked="formState.checked" @click.stop.prevent="check">我已阅读并同意</a-checkbox>
|
||||
<a class="forge-password checked_size" @click.stop.prevent="serviceAgreement">《服务协议》</a> <a class="forge-password checked_size" @click.stop.prevent="privacyPolicy">《隐私政策》</a>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<QrLogin v-if="tabSign === 'QrCode'" />
|
||||
<a-button
|
||||
v-if="tabSign !== 'QrCode'"
|
||||
size="large"
|
||||
type="primary"
|
||||
:loading="loginBtnLoadingFlag"
|
||||
style="width: 100%"
|
||||
@click="debounceTime"
|
||||
>
|
||||
{{ vdata.submitText }}
|
||||
</a-button>
|
||||
<div class="fws-login-box-p" ><a :href='mchDomainName+"/login"' target="_blank">商户端登陆入口</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-footer">
|
||||
<JeepayFooterInfo />
|
||||
</div>
|
||||
</div>
|
||||
<previewImg ref="refPrevImg" />
|
||||
|
||||
<a-modal
|
||||
v-model:visible="vdata.visible"
|
||||
:title="vdata.toastTitle"
|
||||
:footer="null"
|
||||
width="70%"
|
||||
>
|
||||
<div style="height: 70vh; overflow: auto" v-html="vdata.toastContent" />
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { sendSmsCode, phoneLogin } from '@/api/login'
|
||||
import { $getTreaty } from "@/api/manage";
|
||||
import { message } from 'ant-design-vue'
|
||||
import { timeFix } from '@/utils/util'
|
||||
import { vercode } from '@/api/login'
|
||||
import { login,$getUploadImgSize } from '@/api/login'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import router from '@/router'
|
||||
import { ref, onMounted, reactive, getCurrentInstance, h } from 'vue'
|
||||
import { useOem } from '@/store/modules/oem'
|
||||
import { debounce } from '@/utils/throttle'
|
||||
import QrLogin from './components/QrLogin.vue'
|
||||
import previewImg from '@/layouts/components/previewImg.vue'
|
||||
import JeepayFooterInfo from '@/components/link/JeepayUIComponents/JeepayFooterInfo/JeepayFooterInfo.vue'
|
||||
import JeepayBanner from '@/components/link/JeepayUIComponents/JeepayBanner/JeepayBanner.vue'
|
||||
// 获取网站信息
|
||||
const oemSiteInfo = useOem().getSiteInfo()
|
||||
const mchDomainName = oemSiteInfo.mchDomainName??"" as any
|
||||
// 防抖函数
|
||||
const debounceTime = debounce(handleSubmit, 500)
|
||||
let loginPosition = ref('') // 决定登录框水平位置 左中右?
|
||||
let loginPageCardPosition = oemSiteInfo.agent.loginPageCardPosition
|
||||
if (loginPageCardPosition === 'right') {
|
||||
loginPosition.value = 'flex-end'
|
||||
} else if (loginPageCardPosition === 'center') {
|
||||
loginPosition.value = 'center'
|
||||
} else if (loginPageCardPosition === 'left') {
|
||||
loginPosition.value = 'flex-start'
|
||||
}
|
||||
const refPrevImg: any = ref(null) // 二维码 预览组件实例
|
||||
// 获取全局函数
|
||||
const { $infoBox, $SYS_NAME_MAP } = getCurrentInstance()!.appContext.config.globalProperties
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
let isOverdue = ref(false) // 设置过期样式
|
||||
let isAutoLogin = true // 是否是自动登录
|
||||
let loginBtnLoadingFlag = ref(false) // 登录按钮是否显示 加载状态
|
||||
let showLoginErrorInfo = ref('') // 是否显示登录错误面板信息
|
||||
let timer: number = -1
|
||||
let vercodeImgSrc = ref('') // 验证码图片
|
||||
let vercodeToken = ref('') // 验证码验证token
|
||||
|
||||
let formLogin = ref()
|
||||
let formPwdLogin = ref()
|
||||
let tabSign = ref('password')
|
||||
let formState: any = reactive({
|
||||
checked: false
|
||||
})
|
||||
const vdata = reactive({
|
||||
visible: false, // 对话框
|
||||
checked: false,
|
||||
toastContent: "", // 对话框内容
|
||||
toastTitle: "", // 对话框标题
|
||||
googleIsShow: true, // 是否让谷歌输入框展示
|
||||
submitText: '登录',
|
||||
codeBtnText: '发送短信验证码',
|
||||
isDisabled: false,
|
||||
rules: {
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^1\d{10}$/,
|
||||
message: '请输入正确的手机号',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
checked: [
|
||||
{
|
||||
type: "boolean",
|
||||
required: true,
|
||||
message: "请勾选用户" +
|
||||
"隐私协议",
|
||||
trigger: "check",
|
||||
},
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (formState.checked) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject("请勾选用户隐私协议");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
||||
},
|
||||
bannerList: oemSiteInfo.agent?.bannerConfig ? JSON.parse(oemSiteInfo.agent?.bannerConfig) : [], //轮播数据
|
||||
loginBgType: oemSiteInfo.agent.loginBgType
|
||||
})
|
||||
const loginrules: any = reactive({
|
||||
username: [{ required: true, message: '请输入登录名/手机号', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
vercode: [
|
||||
{ required: true, message: '请输入验证码', trigger: 'blur' },
|
||||
{ max: 4, message: '验证码长度错误', trigger: 'blur' }
|
||||
],
|
||||
checked: [
|
||||
{
|
||||
type: "boolean",
|
||||
required: true,
|
||||
message: "请勾选用户隐私协议",
|
||||
trigger: "check",
|
||||
},
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (formState.checked) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject("请勾选用户隐私协议");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
onMounted(() => {
|
||||
refVercode()
|
||||
})
|
||||
|
||||
// handler
|
||||
function handleSubmit() {
|
||||
if (tabSign.value === 'password') {
|
||||
formPwdLogin.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
// 请求登录
|
||||
loginBtnLoadingFlag.value = true
|
||||
passwordLogin()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error)
|
||||
})
|
||||
} else if (tabSign.value === 'message') {
|
||||
formLogin.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
// 请求登录
|
||||
loginBtnLoadingFlag.value = true
|
||||
messageLogin()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error)
|
||||
})
|
||||
}
|
||||
|
||||
// that.form.validateFields({ force: true } (err, values) => {
|
||||
// if (!err) {
|
||||
// const loginParams = { ...values }
|
||||
// loginParams.username = values.username
|
||||
// loginParams.password = values.password
|
||||
// loginParams.vercode = values.usercode
|
||||
// loginParams.vercodeToken = that.vercodeToken
|
||||
// that.loginBtnLoadingFlag = true // 登录按钮显示加载loading
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
// 密码登录
|
||||
function passwordLogin() {
|
||||
let loginParams = {
|
||||
username: formState.username,
|
||||
password: formState.password,
|
||||
vercode: formState.vercode,
|
||||
vercodeToken: vercodeToken.value,
|
||||
googleCode: formState.mfaCode
|
||||
}
|
||||
login(loginParams)
|
||||
.then((bizData) => {
|
||||
loginBtnLoadingFlag.value = false
|
||||
//域名跳转
|
||||
if(bizData.oemSiteUrl){
|
||||
var domainName = document.domain;
|
||||
if(domainName !== bizData.oemSiteUrl){
|
||||
window.location.href = "https://"+bizData.oemSiteUrl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bizData['isMFA']) {
|
||||
vdata.submitText = '确认登录'
|
||||
vdata.googleIsShow = false
|
||||
delete loginrules?.vercode
|
||||
loginrules.mfaCode = [{ required: true, message: '请输入安全码', trigger: 'blur' }] as any
|
||||
return
|
||||
}
|
||||
|
||||
userStore.putToken(bizData['iToken'])
|
||||
$getUploadImgSize().then(res=>{
|
||||
localStorage.setItem('uploadImgSize',res.applymentImgUploadSize)
|
||||
})
|
||||
router.push({ path: '/' })
|
||||
// 延迟 1 秒显示欢迎信息
|
||||
setTimeout(() => {
|
||||
let lastLoginTimeStr = bizData['lastLoginTime'] ? '上次登录时间:' + bizData['lastLoginTime'] : ''
|
||||
$infoBox.notification.success({
|
||||
message: '欢迎',
|
||||
description: [h('p', `${timeFix()},欢迎回来`), h('p', lastLoginTimeStr)]
|
||||
})
|
||||
}, 1000)
|
||||
showLoginErrorInfo.value = ''
|
||||
|
||||
// router.push('/merchant/list')
|
||||
})
|
||||
.catch((err) => {
|
||||
loginBtnLoadingFlag.value = false
|
||||
showLoginErrorInfo.value = err.msg || JSON.stringify(err)
|
||||
})
|
||||
}
|
||||
// 服务协议
|
||||
function serviceAgreement() {
|
||||
vdata.visible = true;
|
||||
vdata.toastTitle = "服务协议";
|
||||
// message.success('服务协议')
|
||||
getTreaty("服务协议");
|
||||
}
|
||||
// 隐私政策
|
||||
function privacyPolicy() {
|
||||
vdata.visible = true;
|
||||
vdata.toastTitle = "隐私政策";
|
||||
getTreaty("隐私政策");
|
||||
}
|
||||
// 隐私协议与服务政策
|
||||
const getTreaty = (name) => {
|
||||
$getTreaty().then((res) => {
|
||||
name === "服务协议"
|
||||
? (vdata.toastContent = res.agentServiceAgreement)
|
||||
: (vdata.toastContent = res.agentPrivacyPolicy);
|
||||
});
|
||||
};
|
||||
// 勾选用户协议
|
||||
function check() {
|
||||
formState.checked = !formState.checked;
|
||||
}
|
||||
// 短信登录
|
||||
function messageLogin() {
|
||||
let loginParams = {
|
||||
phone: formState.phone,
|
||||
code: formState.code
|
||||
}
|
||||
phoneLogin(loginParams)
|
||||
.then((bizData) => {
|
||||
loginBtnLoadingFlag.value = false
|
||||
//域名跳转
|
||||
if(bizData.oemSiteUrl){
|
||||
var domainName = document.domain;
|
||||
if(domainName !== bizData.oemSiteUrl){
|
||||
window.location.href = "https://"+bizData.oemSiteUrl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
userStore.putToken(bizData['iToken'])
|
||||
$getUploadImgSize().then(res=>{
|
||||
localStorage.setItem('uploadImgSize',res.applymentImgUploadSize)
|
||||
})
|
||||
router.push({ path: '/' })
|
||||
// 延迟 1 秒显示欢迎信息
|
||||
setTimeout(() => {
|
||||
let lastLoginTimeStr = bizData['lastLoginTime'] ? '上次登录时间:' + bizData['lastLoginTime'] : ''
|
||||
$infoBox.notification.success({
|
||||
message: '欢迎',
|
||||
description: [h('p', `${timeFix()},欢迎回来`), h('p', lastLoginTimeStr)]
|
||||
})
|
||||
}, 1000)
|
||||
showLoginErrorInfo.value = ''
|
||||
})
|
||||
.catch((err) => {
|
||||
loginBtnLoadingFlag.value = false
|
||||
showLoginErrorInfo.value = err.msg || JSON.stringify(err)
|
||||
})
|
||||
}
|
||||
|
||||
function refVercode() {
|
||||
// 刷新图片验证码
|
||||
// 获取图形验证码
|
||||
vercode().then((res) => {
|
||||
vercodeImgSrc.value = res.imageBase64Data
|
||||
vercodeToken.value = res.vercodeToken
|
||||
|
||||
isOverdue.value = false
|
||||
|
||||
if (timer) clearInterval(timer) // 如果多次点击则清除已有的定时器
|
||||
// 超过60秒提示过期刷新
|
||||
timer = window.setInterval(() => {
|
||||
res.expireTime--
|
||||
if (res.expireTime <= 0) {
|
||||
isOverdue.value = true
|
||||
clearInterval(timer)
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
// 切换密码登录
|
||||
function tab(sign) {
|
||||
tabSign.value = sign
|
||||
}
|
||||
|
||||
function sendSMS() {
|
||||
// 发送短信验证
|
||||
if (!formState.phone) {
|
||||
return message.error('请输入手机号!')
|
||||
}
|
||||
// 校验手机号
|
||||
const reg = /^1[0-9]{10}$/
|
||||
if (!reg.test(formState.phone)) {
|
||||
return message.error('请输入正确的手机号!')
|
||||
}
|
||||
|
||||
if (!vercodeToken.value) {
|
||||
return message.error('请输入验证码!')
|
||||
}
|
||||
if (!formState.vercode) {
|
||||
return message.error('请输入验证码!')
|
||||
}
|
||||
|
||||
vdata.isDisabled = true
|
||||
|
||||
sendSmsCode({ phone: formState.phone, smsType: 'auth', vercode: formState.vercode, vercodeToken: vercodeToken.value})
|
||||
.then((res) => {
|
||||
return message.success('发送成功!')
|
||||
})
|
||||
.catch((err) => {
|
||||
vdata.isDisabled = false
|
||||
showLoginErrorInfo = err.msg || JSON.stringify(err)
|
||||
loginBtnLoadingFlag.value = false
|
||||
// 出错后三秒停止计时
|
||||
setTimeout(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
vdata.isDisabled = false
|
||||
vdata.codeBtnText = '发送短信验证码'
|
||||
}, 500)
|
||||
})
|
||||
|
||||
let time = 60 // 重发验证码时间
|
||||
vdata.codeBtnText = `${time}秒后重新发送`
|
||||
const timer = setInterval(() => {
|
||||
time -= 1
|
||||
vdata.codeBtnText = `${time}秒后重新发送`
|
||||
if (time === 0) {
|
||||
clearInterval(timer)
|
||||
vdata.isDisabled = false
|
||||
vdata.codeBtnText = '发送短信验证码'
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 忘记密码跳转页面
|
||||
function toForgetPwd() {
|
||||
router.push({ name: 'forget', path: '/user/forget' })
|
||||
}
|
||||
|
||||
// 注册页面
|
||||
function toRegister() {
|
||||
router.push({ name: 'register', path: '/user/register' })
|
||||
}
|
||||
|
||||
// 监听回车事件
|
||||
document.onkeydown = function (e) {
|
||||
const theEvent = e || window.event
|
||||
let code = theEvent.keyCode || theEvent.which || theEvent.charCode
|
||||
if (code == 13) {
|
||||
//回车键的键值为13
|
||||
debounceTime()
|
||||
}
|
||||
}
|
||||
const open = () => {
|
||||
refPrevImg.value.open()
|
||||
}
|
||||
console.log('oemSiteInfo', oemSiteInfo)
|
||||
const calcPosition = () => {
|
||||
return loginPosition.value == 'center' ? 1 : loginPosition.value == 'left' ? 1 : 0
|
||||
}
|
||||
const calcChildrenPosition = () => {
|
||||
return vdata.loginBgType == 1 ? 'space-between' : loginPosition.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 去除浏览器默认填充数据时,输入框的背景色
|
||||
/deep/ input:-webkit-autofill,
|
||||
textarea:-webkit-autofill,
|
||||
select:-webkit-autofill {
|
||||
box-shadow: inset 0 0 0 1000px #fff !important;
|
||||
}
|
||||
|
||||
// 新布局
|
||||
.content-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
padding: 0 50px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 80px;
|
||||
background-color: hsla(100, 100, 100, 0.85);
|
||||
backdrop-filter: blur(50px) saturate(180%);
|
||||
}
|
||||
|
||||
.content-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
object-fit: cover;
|
||||
padding: 0 10vw;
|
||||
padding-top: 80px;
|
||||
min-height: 100vh;
|
||||
|
||||
.content-main {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// flex-direction: row-reverse;
|
||||
.banner-content {
|
||||
// flex: 1;
|
||||
// order: 1;
|
||||
width: 50vw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表单部分样式
|
||||
.user-layout-content {
|
||||
|
||||
transition: 0.3s ease;
|
||||
|
||||
input {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 35px 30px;
|
||||
box-sizing: border-box;
|
||||
min-width: 360px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
background: #fff;
|
||||
box-shadow: 0 30px 60px -35px rgb(0 0 0 / 10%);
|
||||
border: 1px solid #e7eaf3;
|
||||
align-items: center;
|
||||
border-radius: 15px;
|
||||
transition: all 0.3s, border 0s ease;
|
||||
|
||||
.ant-form {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.tab-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--ant-primary-color);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-item {
|
||||
height: 65px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
// position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
|
||||
.links {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
|
||||
a {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
transition: all 0.3s;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.copyright {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//登录页响应式的调整
|
||||
@media screen and (min-width: 769px) and (max-width: 1024px) {
|
||||
.container {
|
||||
padding: 0 100px;
|
||||
min-height: 700px;
|
||||
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) and (max-width: 1366px) {
|
||||
.container {
|
||||
padding: 0 150px;
|
||||
min-height: 700px;
|
||||
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) and (max-width: 1600px) {
|
||||
.container {
|
||||
padding: 0 250px;
|
||||
min-height: 700px;
|
||||
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1601px) {
|
||||
.container {
|
||||
padding: 0 300px;
|
||||
min-height: 700px;
|
||||
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.code-body {
|
||||
padding-top: 20px;
|
||||
width: 300px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.code-layout {
|
||||
display: flex;
|
||||
width: 600px;
|
||||
transition: 0.3s;
|
||||
|
||||
.code-layout-item {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.googleShow {
|
||||
margin-left: -300px;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.tab {
|
||||
.operation-class {
|
||||
color: #b0afb3;
|
||||
}
|
||||
}
|
||||
|
||||
.themeColor {
|
||||
color: var(--ant-primary-color);
|
||||
}
|
||||
|
||||
.user-layout-login {
|
||||
label {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.operation-class {
|
||||
font-size: 14px;
|
||||
color: @jee-theme;
|
||||
}
|
||||
|
||||
button.login-button {
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-login-other {
|
||||
text-align: left;
|
||||
margin-top: 24px;
|
||||
line-height: 22px;
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.code-input {
|
||||
width: 216px;
|
||||
}
|
||||
|
||||
.code-img {
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
background-color: #ddd;
|
||||
margin-left: 10px;
|
||||
|
||||
img {
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submit {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vercode-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
opacity: 0.8;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.but-content {
|
||||
display: flex;
|
||||
|
||||
.mch-app {
|
||||
background-color: rgba(0, 0, 0, .03);
|
||||
color: #666;
|
||||
border-radius: 5px;
|
||||
padding: 8px 28px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.checked_size{
|
||||
font-size: 10px !important;
|
||||
}
|
||||
</style>
|
||||
492
jeepay-ui-agent/src/views/user/PhoneLogin.vue
Normal file
492
jeepay-ui-agent/src/views/user/PhoneLogin.vue
Normal file
@@ -0,0 +1,492 @@
|
||||
<template>
|
||||
<div id="userLayout" :class="['user-layout-wrapper']">
|
||||
<div class="top">
|
||||
<div class="header">
|
||||
<img src="@/assets/svg/logo/logo-icon.svg" style="height: 30px;">
|
||||
<img src="@/assets/svg/logo/logo-text.svg" style="height: 25px;margin-left: 5px;">
|
||||
</div>
|
||||
<a class="mch-url" href="#" />
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="user-layout-lang" />
|
||||
<div class="user-layout-content">
|
||||
<!-- 错误提示信息 -->
|
||||
<a-alert v-if="showLoginErrorInfo" type="error" showIcon style="margin-bottom: 24px;" :message="showLoginErrorInfo" />
|
||||
<div class="main">
|
||||
<div class="desc">短信登录</div>
|
||||
<a-form ref="formLogin" class="user-layout-login" :model="formState" :rules="vdata.rules" @submit="handleSubmit">
|
||||
<a-form-item name="phone" class="input-item">
|
||||
<login-text-up v-model:value="formState.phone" :isLogin="true" placeholder="手机号" />
|
||||
</a-form-item>
|
||||
<div class="code">
|
||||
<a-form-item name="code" class="input-item">
|
||||
<login-text-up v-model:value="formState.code" :isLogin="true" placeholder="请输入验证码" />
|
||||
</a-form-item>
|
||||
<div>
|
||||
<a-button type="primary" :disabled="vdata.isDisabled" style="height: 40px;margin-left: 10px" @click="sendSMS()">{{ vdata.codeBtnText }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-form-item style="margin-bottom: 30px;">
|
||||
<!-- 普通登录 -->
|
||||
<a class="operation-class" @click="generalLogin">普通登录</a>
|
||||
<!-- 忘记密码 -->
|
||||
<a class="operation-class" style="float: right;" @click="toForgetPwd">忘记密码?</a>
|
||||
<!-- 注册 -->
|
||||
<a class="operation-class" style="float: right;margin-right: 20px" @click="toRegister">注册</a>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button
|
||||
size="large"
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
class="login-button submit"
|
||||
:loading="loginBtnLoadingFlag"
|
||||
style="width: 100%"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
登录
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div class="footer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { sendSmsCode } from '@/api/login'
|
||||
import { timeFix } from '@/utils/util'
|
||||
import { vercode } from '@/api/login'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { phoneLogin } from '@/api/login'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import router from '@/router'
|
||||
import {ref, onMounted, reactive, getCurrentInstance, h} from 'vue'
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
document.getElementById('userLayout')?.click()
|
||||
}, 100)
|
||||
|
||||
// 获取全局函数
|
||||
const { $infoBox } = getCurrentInstance()!.appContext.config.globalProperties
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
let loginBtnLoadingFlag = ref(false) // 登录按钮是否显示 加载状态
|
||||
let showLoginErrorInfo = ref('') // 是否显示登录错误面板信息
|
||||
let formLogin = ref()
|
||||
let isOverdue = ref(false) // 设置过期样式
|
||||
let vercodeImgSrc = ref('') // 验证码图片
|
||||
let vercodeToken = ref('') // 验证码验证token
|
||||
|
||||
let formState: any = reactive({
|
||||
phone: '',
|
||||
code: '',
|
||||
})
|
||||
|
||||
const vdata = reactive({
|
||||
codeBtnText : '发送短信验证码',
|
||||
isDisabled : false,
|
||||
|
||||
rules: {
|
||||
phone: [{ required: true, pattern: /^1\d{10}$/, message: '请输入正确的手机号', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
||||
}
|
||||
})
|
||||
onMounted(() => {})
|
||||
|
||||
// handler
|
||||
function handleSubmit (){
|
||||
|
||||
let loginParams = {
|
||||
phone: formState.phone,
|
||||
code: formState.code,
|
||||
}
|
||||
formLogin.value.validate().then(() => {
|
||||
// 请求登录
|
||||
loginBtnLoadingFlag.value = true
|
||||
phoneLogin(loginParams).then((bizData) => {
|
||||
loginBtnLoadingFlag.value = false
|
||||
userStore.putToken(bizData['iToken'])
|
||||
|
||||
router.push({ path: '/' })
|
||||
// 延迟 1 秒显示欢迎信息
|
||||
setTimeout(() => {
|
||||
|
||||
let lastLoginTimeStr = bizData['lastLoginTime'] ? '上次登录时间:' + bizData['lastLoginTime'] : ''
|
||||
$infoBox.notification.success({message: '欢迎', description: [h('p', `${timeFix()},欢迎回来`), h('p', lastLoginTimeStr)] })
|
||||
|
||||
}, 1000)
|
||||
showLoginErrorInfo.value = ''
|
||||
|
||||
// router.push('/merchant/list')
|
||||
}).catch( err => {
|
||||
loginBtnLoadingFlag.value = false
|
||||
showLoginErrorInfo.value = (err.msg || JSON.stringify(err))
|
||||
})
|
||||
}).catch(error => {
|
||||
console.log('error', error)
|
||||
})
|
||||
}
|
||||
|
||||
// 普通登录跳转页面
|
||||
function generalLogin () {
|
||||
router.push({ name: 'login', path: '/user/login' })
|
||||
}
|
||||
|
||||
// 忘记密码跳转页面
|
||||
function toForgetPwd () {
|
||||
router.push({ name: 'forget', path: '/user/forget' })
|
||||
}
|
||||
|
||||
// 注册页面
|
||||
function toRegister () {
|
||||
router.push({ name: 'register', path: '/user/register' })
|
||||
}
|
||||
|
||||
// 监听回车事件
|
||||
document.onkeydown = function (e) {
|
||||
var theEvent = e || window.event
|
||||
var code = theEvent.keyCode || theEvent.which || theEvent.charCode
|
||||
if (code == 13) { //回车键的键值为13
|
||||
handleSubmit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function sendSMS () { // 发送短信验证
|
||||
if (!formState.phone) {
|
||||
return message.error('请输入手机号!')
|
||||
}
|
||||
// 校验手机号
|
||||
const reg = /^[1][0-9]{10}$/
|
||||
if (!reg.test(formState.phone)) {
|
||||
return message.error('请输入正确的手机号!')
|
||||
}
|
||||
vdata.isDisabled = true
|
||||
|
||||
sendSmsCode({ phone: formState.phone, smsType: 'auth', vercode: formState.vercode, vercodeToken: vercodeToken.value})
|
||||
.then(res => {
|
||||
return message.success('发送成功!')
|
||||
}).catch(err => {
|
||||
vdata.isDisabled = false
|
||||
showLoginErrorInfo = (err.msg || JSON.stringify(err))
|
||||
loginBtnLoadingFlag.value = false
|
||||
// 出错后三秒停止计时
|
||||
setTimeout(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
vdata.isDisabled = false
|
||||
vdata.codeBtnText = '发送短信验证码'
|
||||
}, 500)
|
||||
})
|
||||
|
||||
let time = 60 // 重发验证码时间
|
||||
vdata.codeBtnText = `${time}秒后重新发送`
|
||||
const timer = setInterval(() => {
|
||||
time -= 1
|
||||
vdata.codeBtnText = `${time}秒后重新发送`
|
||||
if (time === 0) {
|
||||
clearInterval(timer)
|
||||
vdata.isDisabled = false
|
||||
vdata.codeBtnText = '发送短信验证码'
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 去除浏览器默认填充数据时,输入框的背景色
|
||||
/deep/ input:-webkit-autofill,
|
||||
textarea:-webkit-autofill,
|
||||
select:-webkit-autofill {
|
||||
box-shadow: inset 0 0 0 1000px #fff !important;
|
||||
}
|
||||
#userLayout.user-layout-wrapper {
|
||||
height: 100%;
|
||||
.top {
|
||||
height: 80px;
|
||||
padding: 0 35px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
.mch-url {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
span{
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover{
|
||||
color: steelblue;
|
||||
.bi{
|
||||
transform: translateX(10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.bi{
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center; //修改这一项来决定登录对话框的水平位置,flex-start == left; center == center; flex-end == right
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: calc(100vh - 80px);
|
||||
background: #f0f2f5 url(/src/assets/svg/background.svg) no-repeat 50%;
|
||||
background-size: cover;
|
||||
//padding: 50px 0 84px;
|
||||
position: relative;
|
||||
transition: 0.3s ease;
|
||||
|
||||
.user-layout-lang {
|
||||
width: 100%;
|
||||
// height: 40px;
|
||||
// line-height: 44px;
|
||||
height: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.user-layout-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: 0.3s ease;
|
||||
input {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 50px 30px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
background: #fff;
|
||||
border-top: 1px solid #e7eaf3;
|
||||
align-items: center;
|
||||
transition: all 0.3s , border 0s ease;
|
||||
.ant-form{
|
||||
max-width: 300px;
|
||||
}
|
||||
.desc {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.04em;
|
||||
color: #2691ff;
|
||||
margin-bottom: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
.input-item {
|
||||
height: 65px;
|
||||
margin:0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
// position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
|
||||
.links {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
a {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
transition: all 0.3s;
|
||||
&:not(:last-child) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.copyright {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//登录页响应式的调整
|
||||
@media screen and (min-width:769px) and (max-width:1024px){
|
||||
.container {
|
||||
padding: 0 100px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width:1025px) and (max-width:1366px){
|
||||
.container {
|
||||
padding: 0 150px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width:1367px) and (max-width:1600px){
|
||||
.container {
|
||||
padding: 0 250px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width:1601px){
|
||||
.container {
|
||||
padding: 0 300px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: @login-align;
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main{
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #E7EAF3 ;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-layout-login {
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.operation-class {
|
||||
font-size: 14px;
|
||||
color: @jee-theme;
|
||||
}
|
||||
|
||||
button.login-button {
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-login-other {
|
||||
text-align: left;
|
||||
margin-top: 24px;
|
||||
line-height: 22px;
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.code-input {
|
||||
width: 216px;
|
||||
}
|
||||
.code-img {
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
background-color: #ddd;
|
||||
margin-left: 10px;
|
||||
img{
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.submit {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.vercode-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
opacity: 0.8;
|
||||
text-align:center;
|
||||
line-height: 40px;
|
||||
color:#fff;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
689
jeepay-ui-agent/src/views/user/Register.vue
Normal file
689
jeepay-ui-agent/src/views/user/Register.vue
Normal file
@@ -0,0 +1,689 @@
|
||||
<template>
|
||||
<div id="userLayout" :class="['user-layout-wrapper']">
|
||||
<div class="top" style="display: none">
|
||||
<!-- <div class="header">-->
|
||||
<!-- <img :src="oemSiteInfo.sysLogoUrl" style="height: 30px;">-->
|
||||
<!-- </div>-->
|
||||
<!-- <a class="mch-url" href="#">
|
||||
<span>服务商登录</span>
|
||||
<i class="bi bi-arrow-right-short" />
|
||||
</a> -->
|
||||
</div>
|
||||
<div
|
||||
class="container"
|
||||
:style="[
|
||||
{ background: 'url(' + oemSiteInfo.agent.loginPageBGImgUrl + ')' },
|
||||
{ backgroundSize: 'cover' },
|
||||
{ backgroundPosition: 'center top' },
|
||||
{ backgroundRepeat: 'no-repeat' },
|
||||
]"
|
||||
>
|
||||
<div class="user-layout-lang" />
|
||||
<div class="user-layout-content">
|
||||
<!-- 错误提示信息 -->
|
||||
<a-alert
|
||||
v-if="showRegisterErrorInfo"
|
||||
type="error"
|
||||
showIcon
|
||||
style="margin-bottom: 15px"
|
||||
:message="showRegisterErrorInfo"
|
||||
/>
|
||||
<div class="main">
|
||||
<div class="desc">服务商注册</div>
|
||||
<a-form
|
||||
ref="formRegister"
|
||||
class="user-layout-login"
|
||||
:model="formState"
|
||||
:rules="vdata.rules"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<!-- <a-form-item name="agentName" class="input-item">-->
|
||||
<!-- <login-text-up-->
|
||||
<!-- v-model:value="formState.agentName"-->
|
||||
<!-- placeholder="服务商名称"-->
|
||||
<!-- />-->
|
||||
<!-- </a-form-item>-->
|
||||
<a-form-item name="phone" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.phone"
|
||||
placeholder="手机号"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<div class="code-body">
|
||||
<div
|
||||
class="code code-layout-item"
|
||||
style="display: flex; justify-content: center"
|
||||
>
|
||||
<a-form-item name="vercode" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.vercode"
|
||||
:isLogin="true"
|
||||
placeholder="图形验证码"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<div class="code-img" style="position: relative">
|
||||
<img
|
||||
v-show="vercodeImgSrc"
|
||||
:src="vercodeImgSrc"
|
||||
@click="refVercode()"
|
||||
/>
|
||||
<div
|
||||
v-show="isOverdue"
|
||||
class="vercode-mask"
|
||||
@click="refVercode()"
|
||||
>
|
||||
已过期 请刷新
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="code">
|
||||
<a-form-item name="code" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.code"
|
||||
placeholder="请输入验证码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<div>
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="vdata.isDisabled"
|
||||
style="height: 40px; margin-left: 10px"
|
||||
@click="sendSMS()"
|
||||
>{{ vdata.codeBtnText }}</a-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item name="password" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.password"
|
||||
placeholder="登录密码"
|
||||
isPassword="password"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="confirmPwd" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.confirmPwd"
|
||||
placeholder="确认登录密码"
|
||||
isPassword="password"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="inviteCode" class="input-item">
|
||||
<login-text-up
|
||||
v-model:value="formState.inviteCode"
|
||||
placeholder="请输入邀请码(选填)"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="checked">
|
||||
<a-checkbox
|
||||
class="checked_size"
|
||||
v-model:checked="formState.checked"
|
||||
@click.stop.prevent="check"
|
||||
>我已阅读并同意<a
|
||||
class="forge-password checked_size"
|
||||
@click.stop.prevent="serviceAgreement"
|
||||
>《服务协议》</a
|
||||
>和<a class="forge-password checked_size" @click.stop.prevent="privacyPolicy"
|
||||
>《隐私政策》</a
|
||||
></a-checkbox
|
||||
>
|
||||
</a-form-item>
|
||||
<a-form-item class="input-item">
|
||||
<a class="forge-password checked_size_login" style="float: right" @click="toLogin"
|
||||
>去登录 >></a
|
||||
>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button
|
||||
size="large"
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
class="login-button submit"
|
||||
:loading="loginBtnLoadingFlag"
|
||||
style="width: 100%"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
注册
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="footer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-modal
|
||||
v-model:visible="vdata.visible"
|
||||
:title="vdata.toastTitle"
|
||||
:footer="null"
|
||||
width="70%"
|
||||
>
|
||||
<div style="height: 70vh; overflow: auto" v-html="vdata.toastContent" />
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { sendSmsCode, register, $getPasswordRules } from "@/api/login";
|
||||
import { $getTreaty } from "@/api/manage";
|
||||
import router from "@/router";
|
||||
import { useRoute } from "vue-router";
|
||||
import { message } from "ant-design-vue";
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useOem } from "@/store/modules/oem";
|
||||
import { vercode } from "@/api/login";
|
||||
|
||||
// 获取网站信息
|
||||
const oemSiteInfo = useOem().getSiteInfo();
|
||||
|
||||
let loginPosition = ref(""); // 决定登录框水平位置 左中右?
|
||||
let loginPageCardPosition = oemSiteInfo.agent.loginPageCardPosition;
|
||||
if (loginPageCardPosition === "right") {
|
||||
loginPosition.value = "flex-end";
|
||||
} else if (loginPageCardPosition === "center") {
|
||||
loginPosition.value = "center";
|
||||
} else if (loginPageCardPosition === "left") {
|
||||
loginPosition.value = "flex-start";
|
||||
}
|
||||
|
||||
let loginBtnLoadingFlag = false; // 登录按钮是否显示 加载状态
|
||||
let showRegisterErrorInfo = ref(""); // 是否显示登录错误面板信息
|
||||
let timer: number = -1;
|
||||
let formRegister = ref();
|
||||
let isOverdue = ref(false); // 设置过期样式
|
||||
let vercodeImgSrc = ref(""); // 验证码图片
|
||||
let vercodeToken = ref(""); // 验证码验证token
|
||||
|
||||
let formState: any = reactive({
|
||||
agentName: "",
|
||||
phone: "",
|
||||
code: "",
|
||||
password: "",
|
||||
confirmPwd: "",
|
||||
checked: false,
|
||||
inviteCode: null,
|
||||
});
|
||||
|
||||
const vdata = reactive({
|
||||
visibleCode:false,
|
||||
codeBtnText: "发送验证码",
|
||||
visible: false, // 对话框
|
||||
toastContent: "", // 对话框内容
|
||||
toastTitle: "", // 对话框标题
|
||||
isDisabled: false,
|
||||
checked: false,
|
||||
passwordRules: /^$/, //密码规则
|
||||
passwordRulesText: "", //密码规则提示文字
|
||||
rules: {
|
||||
agentName: [
|
||||
{ required: true, message: "请输入服务商名称", trigger: "blur" },
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^1\d{10}$/,
|
||||
message: "请输入正确的手机号",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
|
||||
password: [
|
||||
{ required: false, trigger: "blur" },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (!vdata.passwordRules.test(formState.password)) {
|
||||
return Promise.reject(vdata.passwordRulesText);
|
||||
} else if (formState.password !== formState.confirmPwd) {
|
||||
return Promise.reject("两次输入密码不一致");
|
||||
} else return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
confirmPwd: [
|
||||
{ required: true, trigger: "blur", message: "请输入确认登录密码" },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (!vdata.passwordRules.test(formState.password)) {
|
||||
return Promise.reject(vdata.passwordRulesText);
|
||||
} else if (formState.password !== formState.confirmPwd) {
|
||||
return Promise.reject("两次输入密码不一致");
|
||||
} else return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
checked: [
|
||||
{
|
||||
type: "boolean",
|
||||
required: true,
|
||||
message: "请勾选用户隐私协议",
|
||||
trigger: "check",
|
||||
},
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (formState.checked) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject("请勾选用户隐私协议");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
formState.inviteCode = useRoute().query.c;
|
||||
getPasswordRules();
|
||||
refVercode();
|
||||
});
|
||||
|
||||
|
||||
function refVercode() {
|
||||
// 刷新图片验证码
|
||||
// 获取图形验证码
|
||||
vercode().then((res) => {
|
||||
vercodeImgSrc.value = res.imageBase64Data;
|
||||
vercodeToken.value = res.vercodeToken;
|
||||
|
||||
isOverdue.value = false;
|
||||
|
||||
if (timer) clearInterval(timer); // 如果多次点击则清除已有的定时器
|
||||
// 超过60秒提示过期刷新
|
||||
timer = window.setInterval(() => {
|
||||
res.expireTime--;
|
||||
if (res.expireTime <= 0) {
|
||||
isOverdue.value = true;
|
||||
clearInterval(timer);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
function sendSMSCode() {
|
||||
vdata.visibleCode = true;
|
||||
refVercode();
|
||||
}
|
||||
|
||||
function getPasswordRules() {
|
||||
// 获取密码规则
|
||||
$getPasswordRules().then((res) => {
|
||||
vdata.passwordRules = new RegExp(res.regexpRules);
|
||||
vdata.passwordRulesText = res.errTips;
|
||||
});
|
||||
}
|
||||
|
||||
// handler
|
||||
function handleSubmit() {
|
||||
formRegister.value
|
||||
.validate()
|
||||
.then((valid) => {
|
||||
let params = {
|
||||
agentName: formState.phone,
|
||||
phone: formState.phone,
|
||||
code: formState.code,
|
||||
confirmPwd: formState.confirmPwd,
|
||||
inviteCode: formState.inviteCode,
|
||||
};
|
||||
register(params)
|
||||
.then((res) => {
|
||||
message.success("注册成功");
|
||||
router.push({ path: "/user/login" }); // 校验成功,返回登录页
|
||||
})
|
||||
.catch((err) => {
|
||||
showRegisterErrorInfo = err.msg || JSON.stringify(err);
|
||||
loginBtnLoadingFlag = false;
|
||||
});
|
||||
})
|
||||
.catch((valid) => {});
|
||||
}
|
||||
|
||||
function sendSMS() {
|
||||
// 发送短信验证
|
||||
if (!formState.phone) {
|
||||
return message.error("请输入手机号!");
|
||||
}
|
||||
// 校验手机号
|
||||
const reg = /^[1][0-9]{10}$/;
|
||||
if (!reg.test(formState.phone)) {
|
||||
return message.error("请输入正确的手机号!");
|
||||
}
|
||||
vdata.isDisabled = true;
|
||||
|
||||
sendSmsCode({
|
||||
phone: formState.phone,
|
||||
smsType: "register",
|
||||
vercode: formState.vercode,
|
||||
vercodeToken: vercodeToken.value,
|
||||
})
|
||||
.then((res) => {
|
||||
return message.success("发送成功!");
|
||||
})
|
||||
.catch((err) => {
|
||||
vdata.isDisabled = false;
|
||||
showRegisterErrorInfo = err.msg || JSON.stringify(err);
|
||||
loginBtnLoadingFlag = false;
|
||||
// 出错后三秒停止计时
|
||||
setTimeout(() => {
|
||||
if (timer) clearInterval(timer);
|
||||
vdata.isDisabled = false;
|
||||
vdata.codeBtnText = "发送短信验证码";
|
||||
}, 500);
|
||||
});
|
||||
|
||||
let time = 60; // 重发验证码时间
|
||||
vdata.codeBtnText = `${time}秒后重新发送`;
|
||||
const timer = setInterval(() => {
|
||||
time -= 1;
|
||||
vdata.codeBtnText = `${time}秒后重新发送`;
|
||||
if (time === 0) {
|
||||
clearInterval(timer);
|
||||
vdata.isDisabled = false;
|
||||
vdata.codeBtnText = "发送短信验证码";
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 跳转页面
|
||||
function toLogin() {
|
||||
router.push({ name: "login", path: "/user/login" });
|
||||
}
|
||||
|
||||
// 服务协议
|
||||
function serviceAgreement() {
|
||||
vdata.visible = true;
|
||||
vdata.toastTitle = "服务协议";
|
||||
// message.success('服务协议')
|
||||
getTreaty("服务协议");
|
||||
}
|
||||
|
||||
// 隐私政策
|
||||
function privacyPolicy() {
|
||||
vdata.visible = true;
|
||||
vdata.toastTitle = "隐私政策";
|
||||
getTreaty("隐私政策");
|
||||
}
|
||||
|
||||
// 隐私协议与服务政策
|
||||
const getTreaty = (name) => {
|
||||
$getTreaty().then((res) => {
|
||||
name === "服务协议"
|
||||
? (vdata.toastContent = res.agentServiceAgreement)
|
||||
: (vdata.toastContent = res.agentPrivacyPolicy);
|
||||
});
|
||||
};
|
||||
|
||||
// 勾选用户协议
|
||||
function check() {
|
||||
formState.checked = !formState.checked;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#userLayout.user-layout-wrapper {
|
||||
height: 100%;
|
||||
.top {
|
||||
height: 80px;
|
||||
padding: 0 35px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
.mch-url {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover {
|
||||
color: steelblue;
|
||||
.bi {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.bi {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center; //修改这一项来决定登录对话框的水平位置,flex-start == left; center == center; flex-end == right
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
//height: calc(100vh - 80px);
|
||||
height: calc(100vh + 0px) !important;
|
||||
background: #f0f2f5 url(/src/assets/svg/background.svg) no-repeat 50%;
|
||||
background-size: cover;
|
||||
//padding: 50px 0 84px;
|
||||
position: relative;
|
||||
transition: 0.3s ease;
|
||||
|
||||
.user-layout-lang {
|
||||
width: 100%;
|
||||
// height: 40px;
|
||||
// line-height: 44px;
|
||||
height: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.user-layout-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: 0.3s ease;
|
||||
input {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 50px 30px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
background: #fff;
|
||||
border-top: 1px solid #e7eaf3;
|
||||
align-items: center;
|
||||
transition: all 0.3s, border 0s ease;
|
||||
.ant-form {
|
||||
max-width: 300px;
|
||||
}
|
||||
.desc {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.04em;
|
||||
color: #2691ff;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.input-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
// position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
|
||||
.links {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
a {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
transition: all 0.3s;
|
||||
&:not(:last-child) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.copyright {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
//登录页响应式的调整
|
||||
@media screen and (min-width: 769px) and (max-width: 1024px) {
|
||||
.container {
|
||||
padding: 0 100px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: v-bind(loginPosition);
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1025px) and (max-width: 1366px) {
|
||||
.container {
|
||||
padding: 0 150px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: v-bind(loginPosition);
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1367px) and (max-width: 1600px) {
|
||||
.container {
|
||||
padding: 0 250px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: v-bind(loginPosition);
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1601px) {
|
||||
.container {
|
||||
padding: 0 300px;
|
||||
min-height: 700px;
|
||||
height: calc(100vh - 80px);
|
||||
align-items: v-bind(loginPosition);
|
||||
.user-layout-content {
|
||||
width: 360px;
|
||||
height: auto;
|
||||
.main {
|
||||
width: 360px;
|
||||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||||
border: 0.0625rem solid #e7eaf3;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-layout-login {
|
||||
label {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.forge-password {
|
||||
font-size: 14px;
|
||||
color: @jee-theme;
|
||||
}
|
||||
|
||||
button.login-button {
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-login-other {
|
||||
text-align: left;
|
||||
margin-top: 24px;
|
||||
line-height: 22px;
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.code-input {
|
||||
width: 216px;
|
||||
}
|
||||
.code-img {
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.submit {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.checked_size {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
.checked_size_login {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
143
jeepay-ui-agent/src/views/user/components/QrLogin.vue
Normal file
143
jeepay-ui-agent/src/views/user/components/QrLogin.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="qr-wrapper">
|
||||
<QrcodeVue v-if="qrcodeNo" :value="qrcodeNo" :size="200" class="qrcode" />
|
||||
<div class="qr-tips" v-if="qrTips">
|
||||
{{ qrTips }}
|
||||
<div class="tips-img">
|
||||
<img src="@/assets/login/Refresh.svg" v-if="qrTips.includes('刷新')" @click="qrRefresh" alt="" />
|
||||
<img src="@/assets/login/success.svg" v-if="qrTips.includes('成功')" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="qr-mantle" v-if="qrTips"></div>
|
||||
</div>
|
||||
<div class="qr-footer">请使用{{ $SYS_NAME_MAP.AGENT_APP }}APP扫码登录</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCurrentInstance, h, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
// 导入全局函数
|
||||
const { $infoBox, $SYS_NAME_MAP } = getCurrentInstance().appContext.config.globalProperties
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import router from '@/router'
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
import { timeFix } from '@/utils/util'
|
||||
import { QrCodeLogin } from '@/api/login'
|
||||
|
||||
onMounted(() => {
|
||||
QrCode()
|
||||
createInterval()
|
||||
})
|
||||
let qrTips = ref('')
|
||||
let qrcodeNo = ref('')
|
||||
const qrStatus = {
|
||||
scaned: () => {
|
||||
qrTips.value = '扫码成功请确认登录'
|
||||
},
|
||||
expried: () => {
|
||||
qrTips.value = '二维码过期请刷新'
|
||||
clear()
|
||||
},
|
||||
canceled: () => {
|
||||
qrTips.value = '用户取消登录请刷新'
|
||||
clear()
|
||||
},
|
||||
confirmed: (res) => {
|
||||
login(res)
|
||||
}
|
||||
}
|
||||
const userStore = useUserStore()
|
||||
let interval = null
|
||||
const createInterval = () => {
|
||||
interval = setInterval(() => {
|
||||
QrCode()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
const QrCode = () => {
|
||||
QrCodeLogin({ qrcodeNo: qrcodeNo.value }).then((res) => {
|
||||
const { qrcodeStatus, iToken } = res
|
||||
if (res.qrcodeNo) qrcodeNo.value = res.qrcodeNo
|
||||
|
||||
if (qrcodeStatus && qrcodeStatus !== 'waiting') {
|
||||
qrStatus[qrcodeStatus](res)
|
||||
}
|
||||
})
|
||||
}
|
||||
//刷洗二维码
|
||||
const qrRefresh = () => {
|
||||
qrTips.value = ''
|
||||
qrcodeNo.value = ''
|
||||
QrCode()
|
||||
createInterval()
|
||||
}
|
||||
//扫码成功登录函数
|
||||
const login = (val) => {
|
||||
userStore.putToken(val['iToken'])
|
||||
router.push({ path: '/' })
|
||||
setTimeout(() => {
|
||||
let lastLoginTimeStr = val['lastLoginTime'] ? '上次登录时间:' + val['lastLoginTime'] : ''
|
||||
$infoBox.notification.success({
|
||||
message: '欢迎',
|
||||
description: [h('p', `${timeFix()},欢迎回来`), h('p', lastLoginTimeStr)]
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
const clear = () => {
|
||||
clearInterval(interval)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
clear()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.qr-wrapper {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
|
||||
.qr-tips {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 9999999999;
|
||||
font-size: 16px;
|
||||
white-space: nowrap;
|
||||
letter-spacing: 2px;
|
||||
padding: 10px 15px;
|
||||
border-radius: 5px;
|
||||
color: #fff;
|
||||
|
||||
.tips-img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin: 15px auto;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qr-mantle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.qr-footer {
|
||||
margin: 15px 0;
|
||||
font-size: 16px;
|
||||
color: var(--ant-primary-color);
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user