
<van-field v-model="phoneNumber" placeholder="请输入接收人手机号">
<div slot="left-icon">
<div class="img">
<img src="./images/[email protected]" alt />
</div>
</div>
</van-field>

<template >
<div class="d-flex flex-column align-center page-container">
<div class="avatar-wrapper d-flex align-center justify-center">
<img src="./images/[email protected]" class="avatar">
</div>
<div class="input-wrapper d-flex flex-column justify-center">
<div class="phone-input">
<van-field :placeholder="busiType === 2 ? '请输入您的账号或手机号' : '请输入手机号'" v-model="phoneNumber" class="ov_input" type="number" :maxlength='11' :error-message="phoneNumberErrorMessage"></van-field>
<i :class="['iconfont iconcuowu-', phoneNumber.length > 0 ? '' : 'hide']" @click="phoneNumber = ''"></i>
</div>
<div class="phone-input" v-if="busiType === 2">
<van-field placeholder="请输入密码" v-model="passwd" class="ov_input" :type="showPasswd ? 'text' : 'password'"></van-field>
<i :class="['van-icon icon-eye', showPasswd ? 'van-icon-closed-eye' : 'van-icon-eye']" @click="showPasswd = !showPasswd"></i>
</div>
<div class="d-flex align-center justify-space-between" v-else>
<div class="code-input flex-grow-1">
<van-field placeholder="请输入验证码" v-model="inputCode"></van-field>
</div>
<van-button plain type="primary" class="flex-shrink-0 ov_btn" :color="$theme" @click="getVerificationCode" :disabled="coolDown">{
{
!coolDown ? '获取验证码' : `${
coolDownTime}秒后重新获取`}}</van-button>
</div>
<van-button :color="$theme" class="btn-login" @click="login">登录</van-button>
</div>
<div class="forget" v-if="busiType === 2" @click="$router.replace('/password-edit')"><span class="theme-text">忘记密码?</span></div>
<div class="contact-tip" v-if="busiType === 2" @click="$router.push('/contact')">没有账号,请<span class="theme-text">联系商家</span>></div>
</div>
</template>
<script>
import {
mapGetters, mapMutations, mapActions } from 'vuex';
import {
Toast } from 'vant';
import {
phoneNumberValidReg } from '@/utils/reg';
import {
loginByMobile, getVerificationCode, loginOutWechat, loginByPwd,
} from '@/API/login';
import {
getUserByOpenId } from '@/API/wechat';
import {
isWechat } from '@/utils/wechat';
import {
getURLSearchParams, getDecodeParams, getEncodeURI } from '@/utils/URLSearchParams';
function cacheUserInfo(sysAccount, dataString) {
localStorage.setItem(`${
sysAccount}_info`, dataString);
}
let fromPath = '/';
const coolDownTime = 60;
export default {
beforeRouteEnter(to, from, next) {
fromPath = from.path;
next();
},
name: 'login',
data: () => ({
phoneNumber: '',
inputCode: '',
verificationCode: '',
coolDown: false,
coolDownTime,
coolDownInterval: null,
custNo: null,
passwd: null,
showPasswd: false,
}),
computed: {
...mapGetters('user', {
openId: 'openId',
basOpenId: 'basOpenId',
info: 'info',
}),
...mapGetters('business', {
busiType: 'busiType',
}),
...mapGetters({
sysAccount: 'sysAccount',
fromPath: 'fromPath',
}),
phoneNumberErrorMessage() {
if (!this.phoneNumber.length) {
return '';
}
if (this.phoneNumber.length === 11) {
return phoneNumberValidReg.test(this.phoneNumber) ? '' : '手机号码格式错误';
}
return '';
},
},
mounted() {
const custNo = getURLSearchParams('custNo') || (getURLSearchParams('params') ? getDecodeParams(getURLSearchParams('params'), 'custNo') : '');
if (custNo && custNo != 'null') {
this.custNo = custNo;
}
},
methods: {
...mapMutations('user', {
setLoginState: 'setLoginState',
setUserInfo: 'setUserInfo',
}),
getVerificationCode() {
if (this.coolDown) {
return;
}
if (!this.phoneNumber || this.phoneNumber.length !== 11 || !phoneNumberValidReg.test(this.phoneNumber)) {
return this.$toast('请输入正确手机号码');
}
Toast.loading('验证码发送中');
this.validatePhoneNumber().then(() => {
getVerificationCode(this.phoneNumber).then(({
data }) => {
Toast.clear();
this.$toast('验证码发送成功');
this.verificationCode = data;
this.coolDown = true;
this.coolDownInterval = setInterval(() => {
if (this.coolDownTime > 0) {
this.coolDownTime -= 1;
} else {
this.coolDown = false;
clearInterval(this.coolDownInterval);
this.coolDownInterval = null;
}
}, 1000);
});
}).catch((err) => {
this.$toast(JSON.stringify(err));
});
},
login() {
this.validatePhoneNumber().then(() => {
if (!this.inputCode && this.busiType !== 2) {
return this.$toast('请填写验证码');
}
if (!this.passwd && this.busiType === 2) {
return this.$toast('请填写密码');
}
if (this.busiType === 2) {
return this.fetchLoginWithPwd();
}
if (isWechat) {
return this.fetchLoginInWechat();
}
return this.fetchLoginOutWechat();
})
.catch((err) => this.$toast(err.message));
},
fetchLoginInWechat() {
const openId = this.openId || window.localStorage.getItem('openId') || window.sessionStorage.getItem('openId');
const basOpenId = this.basOpenId || window.localStorage.getItem(`${
this.sysAccount}_basOpenId`) || window.sessionStorage.getItem(`${
this.sysAccount}_basOpenId`);
return loginByMobile({
mobile: this.phoneNumber, smsNumber: this.inputCode, openId, basOpenId, custNo: this.custNo,
}).then(({
data, returnMsg }) => {
if (!data) {
this.$toast(returnMsg);
} else {
this.setLoginState(true);
this.setUserInfo(data);
if (isWechat) {
getUserByOpenId(openId)
.then(({
data: respInfo }) => {
this.setUserInfo(respInfo);
cacheUserInfo(this.sysAccount, JSON.stringify(respInfo));
});
} else {
this.setUserInfo(data);
cacheUserInfo(this.sysAccount, JSON.stringify(data));
}
this.$router.push({
path: fromPath,
});
}
});
},
fetchLoginOutWechat() {
return loginOutWechat({
mobile: this.phoneNumber, verifyCode: this.inputCode, parentNo: this.custNo,
}).then(({
data, returnMsg }) => {
if (!data) {
this.$toast(returnMsg);
} else {
this.setLoginState(true);
this.setUserInfo(data);
cacheUserInfo(this.sysAccount, JSON.stringify(data));
this.$router.push({
path: fromPath,
});
}
});
},
fetchLoginWithPwd() {
const openId = this.openId || window.localStorage.getItem('openId') || window.sessionStorage.getItem('openId');
const basOpenId = this.basOpenId || window.localStorage.getItem(`${
this.sysAccount}_basOpenId`) || window.sessionStorage.getItem(`${
this.sysAccount}_basOpenId`);
return loginByPwd({
mobile: this.phoneNumber, parentNo: this.custNo, pwd: this.passwd, openId, basOpenId,
}).then(({
data, returnMsg }) => {
if (returnMsg.includes('密码错误')) {
this.$toast(returnMsg);
} else if (!data) {
this.$router.push('/contact');
} else {
this.setLoginState(true);
this.setUserInfo(data);
cacheUserInfo(this.sysAccount, JSON.stringify(data));
this.$router.push({
path: fromPath,
});
}
});
},
validatePhoneNumber() {
return new Promise((resolve, reject) => {
if (!this.phoneNumber) {
reject(new Error('请填写手机号码'));
}
if (!phoneNumberValidReg.test(this.phoneNumber)) {
reject(new Error('手机号码不合法'));
}
resolve();
});
},
},
watch: {
coolDown(v) {
if (!v) {
this.coolDownTime = coolDownTime;
}
},
},
};
</script>
<style lang="scss" scoped>
.page-container{
background-color: #fff;
min-height: 100vh;
;
box-sizing: border-box;
}
.avatar-wrapper{
width: 175px;
height: 175px;
border-radius: 50%;
border: 1px solid #efefef;
margin-top: 100px;
margin-bottom: 126px;
box-sizing: border-box;
padding: 12.5px;
.avatar{
width: 100%;
height: 100%;
}
}
.input-wrapper{
width: 100%;
padding-left: 70px;
padding-right: 70px;
box-sizing: border-box;
}
.code-input,.phone-input{
box-sizing: border-box;
border: 1px solid #efefef;
border-radius: 5px;
position: relative;
overflow: hidden;
}
.phone-input{
padding: 6PX 60PX 6PX 20PX;
margin-bottom: 40px;
.iconcuowu-{
position: absolute;
font-size: 28px;
color: var(--themeColor);
right: 5px;
top: calc(50% - 24px);
transition: transform 0.3s ease;
padding: 10PX;
&.hide{
transform: translateX(48px);
}
}
.icon-eye {
position: absolute;
font-size: 28px;
right: 5px;
top: calc(50% - 24px);
transition: transform 0.3s ease;
padding: 10PX;
}
}
.code-input{
padding: 6PX 20PX;
margin-right: 36px;
}
.ov_btn{
height: 58PX;
border-radius: 5px;
}
.ov_input{
&::after{
border-bottom: none;
}
}
.btn-login{
margin-top: 160px;
}
.contact-tip {
font-size: 12px;
margin-top: 60px;
}
.forget {
font-size: 12px;
margin-top: 60px;
transform: translateX(118px);
border-bottom:1px #52d1a8 solid
}
</style>
**修改密码或者忘记密码:**加粗样式****
```javascript
<template>
<div class="main">
<div class="banner-top">
<van-form validate-first @submit="onSubmit" ref="editForm" autocomplete="off">
<van-field
type="number"
v-model="tel"
class="tel"
name="tel"
label="手机号"
placeholder="请输入你的账号或手机号"
:rules="userInfoRules.tel"
></van-field>
<van-field
class="code"
v-model="code"
name="code"
label="验证码"
placeholder="请输入你的验证码"
:rules="userInfoRules.code"
>
<template #button>
<van-count-down :time="1000*60" format="ss s" v-if="timeShow" @finish="timeShow=false" />
<van-button
size="small"
@click="sendSms"
native-type="button"
class="sms-btn"
v-else
>获取验证码</van-button>
</template>
</van-field>
<van-field
v-model="password"
class="password"
name="新密码"
label="新密码"
placeholder="请输入6位数字密码"
:rules="userInfoRules.password"
:type="showPasswd ? 'text' : 'password'"
>
<span slot="right-icon">
<i
:class="['van-icon icon-eye', showPasswd ? 'van-icon-closed-eye' : 'van-icon-eye']"
@click="showPasswd = !showPasswd"
></i>
</span>
</van-field>
<van-field
v-model="surePassword"
class="sure-password"
name="确认新密码"
label="确认新密码"
placeholder="请再次输入新密码"
:rules="userInfoRules.surePassword"
:type="sureShowPasswd ? 'text' : 'password'"
>
<span slot="right-icon">
<i
:class="['van-icon icon-eye', sureShowPasswd ? 'van-icon-closed-eye' : 'van-icon-eye']"
@click="sureShowPasswd = !sureShowPasswd"
></i>
</span>
</van-field>
<div class="btn-box">
<!-- <van-button color="#52d1a8" type="info" native-type="submit" class="btn">确定修改</van-button> -->
<van-button color="#52d1a8" type="info" native-type="submit" class="btn">{
{
btn}}</van-button>
</div>
</van-form>
</div>
<div class="banner-foot"></div>
</div>
</template>
<script>
import Vue from 'vue';
import {
mapGetters, mapMutations, mapActions } from 'vuex';
import {
Field, NavBar, Form, CountDown,
} from 'vant';
import {
getVerificationCode } from '@/API/login';
import {
editPassword } from '@/API/info';
Vue.use(CountDown);
Vue.use(Form);
Vue.use(NavBar);
Vue.use(Field);
let fromPath = '/';
export default {
beforeRouteEnter(to, from, next) {
fromPath = from.path;
next();
},
name: 'password-edit',
data() {
return {
btn: '确定',
toAddress: fromPath,
timeShow: false,
tel: null,
code: null,
password: null,
surePassword: null,
showPasswd: false,
sureShowPasswd: false,
userInfoRules: {
tel: [
{
required: true, message: '请输入手机号' },
{
pattern: /^1[3|4|5|7|8]\d{9}$/, message: '手机号格式错误' },
],
code: [
{
required: true, message: '请输入验证码' },
{
pattern: /^\d{6}$/, message: '验证码格式错误' },
],
password: [
{
required: true, message: '输入新密码' },
{
pattern: /^\d{6}$/, message: '新密码应为6位数字' },
],
surePassword: [{
required: true, message: '请确定新密码' }],
},
};
},
created() {
console.log(this.toAddress, 99);
if (this.toAddress === '/user-info') {
this.btn = '修改密码';
} else {
this.btn = '确定';
}
},
methods: {
onSubmit(value) {
console.log(value);
if (this.password !== this.surePassword) {
return this.$toast('两次输入密码不一致,请确认后再试');
}
editPassword({
mobile: this.tel,
verifyCode: this.code,
pwd: this.password,
pwdType: 1,
}).then((res) => {
this.timeShow = false;
this.password = '';
this.surePassword = '';
this.code = '';
this.tel = '';
console.log(res, '修改成功');
this.$toast('密码设置成功');
this.$router.go(-1);
}).catch((err) => {
console.log(err, '修改密码请求失败');
});
},
async sendSms() {
try {
await this.$refs.editForm.validate('tel');
} catch (err) {
console.log('验证失败', err);
return;
}
console.log(12);
this.timeShow = true;
getVerificationCode(this.tel).then((res) => {
console.log(res);
});
},
},
};
</script>
<style lang="scss" scoped>
.main {
width: 100vw;
height: 100vh;
background: #ededed;
.banner-top {
width: 90%;
background-color: #fff;
margin-left: 5%;
border-radius: 6px;
transform: translateY(50px);
.sms-btn {
color: #52d1a8;
border: none;
}
}
}
/deep/.van-form {
background: #ededed;
.password,
.tel {
border-radius: 15px 15px 0 0;
}
.sure-password,
.code {
border-radius: 0 0 15px 15px;
}
.password,
.sure-password {
transform: translateY(10px);
}
}
.btn-box {
transform: translateY(67px);
color: #fff;
width: 100%;
.btn {
width: 90%;
margin-left: 5%;
border-radius: 4px;
letter-spacing: 2px;
}
}
</style>