Files
new-cashier/jeepay-ui-agent/src/views/user/Forget.vue
2024-05-23 14:39:33 +08:00

521 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>