Commit 11cbba4f by fanx

制作重置密码 登录页面

1 parent c31aae8b
.icon-sprite { display: inline-block; background-image: url(../images/sprite.png); background-size: 1676px 1036px; } .icon-sprite { display: inline-block; background-image: url(../images/sprite.png); background-size: 1676px 1036px; }
.icon-bg-common { width: 828px; height: 360px; background-position: 0px -432px; }
.icon-bg-login { width: 828px; height: 412px; background-position: 0px 0px; } .icon-bg-login { width: 828px; height: 412px; background-position: 0px 0px; }
.icon-bg-mine { width: 828px; height: 340px; background-position: -848px 0px; } .icon-bg-mine { width: 828px; height: 340px; background-position: -848px 0px; }
.icon-bg-navigation { width: 828px; height: 176px; background-position: -848px -566px; } .icon-bg-navigation { width: 828px; height: 176px; background-position: -848px -566px; }
.icon-bg-search { width: 828px; height: 186px; background-position: -848px -360px; } .icon-bg-search { width: 828px; height: 186px; background-position: -848px -360px; }
.icon-email { width: 36px; height: 36px; background-position: -344px -812px; }
.icon-logo { width: 224px; height: 224px; background-position: 0px -812px; } .icon-logo { width: 224px; height: 224px; background-position: 0px -812px; }
.icon-password { width: 36px; height: 36px; background-position: -344px -812px; } .icon-password { width: 36px; height: 36px; background-position: -400px -812px; }
.icon-user-question { width: 32px; height: 36px; background-position: -512px -812px; } .icon-user-question { width: 32px; height: 36px; background-position: -624px -812px; }
.icon-user { width: 36px; height: 36px; background-position: -400px -812px; } .icon-user { width: 36px; height: 36px; background-position: -456px -812px; }
.icon-verification { width: 36px; height: 36px; background-position: -456px -812px; } .icon-verification { width: 36px; height: 36px; background-position: -512px -812px; }
.icon-wechat { width: 80px; height: 78px; background-position: -244px -812px; } .icon-wechat { width: 80px; height: 78px; background-position: -244px -812px; }
.icon-bg-common { width: 828px; height: 360px; background-position: 0px -432px; }
\ No newline at end of file \ No newline at end of file
.icon-tel { width: 36px; height: 36px; background-position: -568px -812px; }
\ No newline at end of file \ No newline at end of file

467 KB | W: | H:

469 KB | W: | H:

src/assets/images/sprite.png
src/assets/images/sprite.png
src/assets/images/sprite.png
src/assets/images/sprite.png
  • 2-up
  • Swipe
  • Onion skin
<template> <template>
<div> <div>
<div class="sendCodeText" @click="sendCode" v-show="show">获取验证码</div> <div class="sendCodeText" :class="{active:isValue}" @click="sendCode" v-show="show">获取验证码</div>
<div class="coutdDownText" v-show="!show"><span class="second">{{time}}s</span>后重新获取</div> <div class="coutdDownText" v-show="!show"><span class="second">{{time}}s</span>后重新获取</div>
</div> </div>
</template> </template>
<script> <script>
import utils from "@/utils/"; import utils from "@/utils/";
let timer = null;
export default { export default {
name: 'SendVerificationCode', name: 'SendVerificationCode',
props: { props: {
...@@ -16,6 +17,9 @@ export default { ...@@ -16,6 +17,9 @@ export default {
phone: { phone: {
type: [Number, String], type: [Number, String],
}, },
email: {
type: String
},
data: { data: {
type: Object type: Object
} }
...@@ -23,12 +27,33 @@ export default { ...@@ -23,12 +27,33 @@ export default {
data() { data() {
return { return {
show: true, show: true,
time: 60 time: 60,
isValue: false
}
},
watch: {
// 监控 手机号有值 则获取验证码 增加蓝色
phone(val) {
if (val) {
this.isValue = true
} else {
this.isValue = false
} }
}, },
// 监控 邮箱号有值 则获取验证码 增加蓝色
email(val) {
if (val) {
this.isValue = true
} else {
this.isValue = false
}
},
},
methods: { methods: {
// 发送验证码
sendCode() { sendCode() {
console.log(this.data.type)
// 发送手机号验证码
if (this.data.type == 'phone') {
// 判断手机号不能为空 // 判断手机号不能为空
if (!this.phone) { if (!this.phone) {
Toast('请输入手机号') Toast('请输入手机号')
...@@ -39,10 +64,23 @@ export default { ...@@ -39,10 +64,23 @@ export default {
Toast("请输入正确的手机号码!"); Toast("请输入正确的手机号码!");
return return
} }
} else {
// 发送邮件验证码
if (!this.email) {
Toast('请输入邮箱')
return
}
if (!utils.emailRegCheck(this.email)) {
Toast("请输入正确的邮箱格式!");
return
}
}
this.time = this.coutDownNumber this.time = this.coutDownNumber
this.show = false // 显示倒计时 this.show = false // 显示倒计时
let timer = null;
if (timer) { if (timer) {
clearInterval(timer); clearInterval(timer);
} }
...@@ -59,11 +97,18 @@ export default { ...@@ -59,11 +97,18 @@ export default {
} }
}, 1000); }, 1000);
} }
},
destroyed() {
clearInterval(timer);
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.sendCodeText { .sendCodeText {
color: #9c9c9c;
font-size: 12px;
}
.active {
color: #106abc; color: #106abc;
} }
.coutdDownText { .coutdDownText {
......
const userRouter = [ const userRouter = [
{ {
path: '/user/login', path: '/user/login/phone',
name: 'Login', name: 'LoginPhone',
meta: { meta: {
title: '登录' title: '登录'
}, },
component: () => import(/* webpackChunkName: "login" */ '@/views/user/login.vue') // 登录 component: () => import(/* webpackChunkName: "loginPhone" */ '@/views/user/loginPhone.vue') // 手机号登录
},
{
path: '/user/login/username',
name: 'LoginUserName',
meta: {
title: '登录'
},
component: () => import(/* webpackChunkName: "login" */ '@/views/user/loginUserName.vue') // 账号密码登录
}, },
{ {
path: '/user/register', path: '/user/register',
...@@ -16,6 +24,14 @@ const userRouter = [ ...@@ -16,6 +24,14 @@ const userRouter = [
component: () => import(/* webpackChunkName: "register" */ '@/views/user/register.vue') // 注册 component: () => import(/* webpackChunkName: "register" */ '@/views/user/register.vue') // 注册
}, },
{ {
path: '/user/findPassword',
name: 'FindPassword',
meta: {
title: ''
},
component: () => import(/* webpackChunkName: "findPassword" */ '@/views/user/findPassword.vue') // 手机号找回密码 邮箱找回密码
},
{
path: '/user/resetPassword', path: '/user/resetPassword',
name: 'ResetPassword', name: 'ResetPassword',
meta: { meta: {
......
...@@ -13,11 +13,17 @@ const handlePromise = (promise) => { ...@@ -13,11 +13,17 @@ const handlePromise = (promise) => {
} }
const phoneRegCheck = (phoneNo) => { const phoneRegCheck = (phoneNo) => {
const mobileReg = /1[3-9]\d{9}/; const Reg = /1[3-9]\d{9}/;
return mobileReg.test(phoneNo); return Reg.test(phoneNo);
} }
const emailRegCheck = (email) => {
const Reg = /^[A-Za-z0-9-_\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
return Reg.test(email);
}
export default { export default {
handlePromise, handlePromise,
phoneRegCheck phoneRegCheck,
emailRegCheck
} }
\ No newline at end of file \ No newline at end of file
<template>
<div class="login_tabs">
<router-link to="/user/login/phone" :class="{active:type==1}">手机号登录</router-link>
<router-link to="/user/login/username" :class="{active:type==2}">账号密码登录</router-link>
<div class="bottom-border-1" v-show="type==1"></div>
<div class="bottom-border-2" v-show="type==2"></div>
</div>
</template>
<script>
export default {
name: 'LoginTabs',
props: {
type: {
type: Number,
default: 1
}
},
}
</script>
<style lang="less" scoped>
.login_tabs {
display: flex;
justify-content: center;
position: relative;
a {
position: relative;
color: #6c6c6c;
font-size: 16px;
width: 120px;
height: 30px;
text-align: center;
border-bottom: 1px solid #ccc;
&.active {
color: #106abc;
}
}
.bottom-border-1 {
position: absolute;
width: 80px;
border-bottom: 3px solid #106abc;
top: 26px;
left: 107px;
}
.bottom-border-2 {
position: absolute;
width: 80px;
border-bottom: 3px solid #106abc;
top: 26px;
right: 107px;
}
}
</style>
\ No newline at end of file \ No newline at end of file
<template>
<div class="login_others">
<div class="otherLogin_title">其他登录方式</div>
<div class="other_icon">
<div class="wechat">
<img :src="wechatIcon" alt="">
<span>微信快速登录</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'OtherLogin',
data() {
return {
wechatIcon: require('@/assets/icon/wechat.png'),
}
}
}
</script>
<style lang="less" scoped>
/** 其他登录方式 **/
.login_others {
display: flex;
flex: 1;
flex-direction: column;
justify-content: flex-end;
align-items: center;
padding-bottom: 20px;
.other_icon {
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 5px;
.wechat {
display: flex;
flex-direction: column;
align-items: center;
span {
color: #666;
font-size: 11px;
margin-top: 5px;
}
}
img {
// display: block;
width: 38px;
}
}
}
.otherLogin_title {
position: relative;
color: #666;
font-size: 14px;
&:before {
content: "";
position: absolute;
top: 10px;
left: -30px;
width: 25px;
border-bottom: 1px solid #cfcfcf;
}
&:after {
content: "";
position: absolute;
top: 10px;
right: -30px;
width: 25px;
border-bottom: 1px solid #cfcfcf;
}
}
</style>
\ No newline at end of file \ No newline at end of file
<template>
<div class="login_container">
<UserCommon>
<template slot="top">
<NafmHeader :isBgImg="false" :title="title" bgColor="transparent" />
</template>
</UserCommon>
<div class="login_content">
<div class="login_form_box">
<div class="login_form">
<van-field v-show="type=='phone'" v-model.trim="userName" clearable type="tel" maxlength="11" :left-icon="telIcon" placeholder="请输入手机号" />
<van-field v-show="type=='email'" v-model.trim="email" clearable :left-icon="emailIcon" placeholder="请输入邮箱" />
<van-field v-model="password" clearable label="" maxlength="6" :left-icon="VerificationIcon" placeholder="请输入验证码">
<template #button>
<SendVerificationCode :phone="userName" :email="email" :data="objParams" />
</template>
</van-field>
<div class="login_btn" :class="{loginActive:isBothValue}" @click="jumpResetPasswordPage">确定</div>
</div>
</div>
</div>
</div>
</template>
<script>
import UserCommon from '@/components/UserCommon'
import SendVerificationCode from '@/components/SendVerificationCode'
import utils from "@/utils/";
export default {
name: 'Login',
components: {
UserCommon,
SendVerificationCode
},
data() {
return {
userName: null,
password: "",
title: '',
type: null,
objParams: {},
email: '',
phone: '',
telIcon: require('@/assets/icon/tel.png'),
emailIcon: require('@/assets/icon/email.png'),
VerificationIcon: require('@/assets/icon/verification.png'),
passwordIcon: require('@/assets/icon/password.png'),
}
},
created() {
const { type } = this.$route.query
this.type = type
Object.assign(this.objParams, {
type
})
if (type == 'phone') {
this.title = '手机号找回'
} else {
this.title = '邮箱找回'
}
},
computed: {
isBothValue() {
if ((this.userName && this.password) || (this.email && this.password)) {
return true
} else {
return false
}
},
},
methods: {
jumpResetPasswordPage() {
const { type } = this.$route.query
if (type == 'phone') {
// 判断手机号不能为空
if (!this.userName) {
Toast('请输入手机号')
return
}
if (!utils.phoneRegCheck(this.userName)) {
Toast("请输入正确的手机号码!");
return
}
} else {
// 判断邮箱不能为空
if (!this.email) {
Toast('请输入邮箱')
return
}
if (!utils.emailRegCheck(this.email)) {
Toast("请输入正确的邮箱格式!");
return
}
}
if (!this.password) {
Toast('请输入验证码')
return
}
this.$router.push({
path: '/user/resetPassword'
})
}
}
}
</script>
<style lang="less" scoped>
@import "./less/login.less";
</style>
\ No newline at end of file \ No newline at end of file
.login_container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.login_content {
margin-top: 40px;
}
/deep/ .van-tabs__nav--line {
width: 60%;
margin: 0 auto;
}
/deep/ .van-tab {
border-bottom: 1px solid #b8cfe5;
}
/deep/ .van-tabs__line {
bottom: 4px;
}
.login_form_box{
display: flex;
align-items: center;
justify-content: center;
}
.login_form {
width: 330px;
margin-top: 20px;
}
/deep/ .van-cell:not(:last-child)::after {
border-bottom: 1px solid #efefef;
}
/deep/ .van-cell{
padding-right: 0 !important;
padding-left: 0 !important;
border-bottom: 1px solid #ebedf0;
}
/deep/ .van-cell:not(:last-child)::after{
border: none;
}
.form_second {
margin-top: 10px;
display: flex;
justify-content: space-between;
color: #999;
.checkbox {
/deep/ .van-checkbox__label {
color: #999;
}
}
.forget {
text-decoration: underline;
}
}
.login_btn {
width: 100%;
border-radius: 5px;
text-align: center;
height: 45px;
line-height: 45px;
color: #fff;
font-size: 16px;
margin-top: 40px;
background-image: linear-gradient(to right, #25A3DF, #106abc);
opacity: 0.3;
}
.loginActive {
opacity: 1;
}
.register_btn{
margin-top: 10px;
display: flex;
justify-content: flex-end;
color: #106ABC;
font-size: 13px;
}
\ No newline at end of file \ No newline at end of file
<template>
<div class="login_container">
<UserCommon>
<template slot="top">
<NafmHeader :isBgImg="false" bgColor="transparent" />
</template>
</UserCommon>
<div class="login_content">
<van-tabs @click="switchTab" :border="false" class="login_tabs" v-model="tabActive" swipeable>
<van-tab title="手机号登录" :name="1">
<div class="login_form">
<van-field v-model="userName" clearable type="tel" maxlength="11" :left-icon="userNameIcon" placeholder="请输入手机号" />
<van-field v-model="password" clearable label="" maxlength="16" :left-icon="passwordIcon" placeholder="请输入6-16位密码">
<template #button>
<SendVerificationCode :phone="userName" />
</template>
</van-field>
<div>
<van-button></van-button>
</div>
</div>
</van-tab>
<van-tab title="账号密码登录" :name="2">
<div class="login_form">
<van-field v-model="userName" clearable type="tel" maxlength="11" :left-icon="userNameIcon" placeholder="请输入手机号" />
<van-field v-model="password" clearable label="" maxlength="16" :left-icon="passwordIcon" placeholder="请输入6-16位密码" />
<div class="form_second">
<van-checkbox v-model="checked" checked-color="#106abc" class="checkbox" shape="square" icon-size="12px">记住密码</van-checkbox>
<span class="forget">忘记密码</span>
</div>
</div>
</van-tab>
</van-tabs>
</div>
<div class="login_others">
<div>其他登录方式</div>
<div>
<img src="require('@/assets/icon/wechat.png')" alt="">
</div>
</div>
</div>
</template>
<script>
import UserCommon from '@/components/UserCommon'
import SendVerificationCode from '@/components/SendVerificationCode'
export default {
name: 'Login',
components: {
UserCommon,
SendVerificationCode
},
data() {
return {
tabActive: 1,
userName: null,
password: "",
checked: false,
userNameIcon: require('@/assets/icon/user.png'),
passwordIcon: require('@/assets/icon/password.png'),
}
},
methods: {
handleBack() {
this.$router.back()
},
switchTab(name) {
this.tabActive = name
},
}
}
</script>
<style lang="less" scoped>
.login-container {
width: 100%;
height: 100%;
font-size: 40px;
}
.login_content {
margin-top: 40px;
}
/deep/ .van-tabs__nav--line {
width: 60%;
margin: 0 auto;
}
/deep/ .van-tab {
border-bottom: 1px solid #b8cfe5;
}
/deep/ .van-tabs__line {
bottom: 4px;
}
.login_form {
margin: 30px 42px 0 42px;
}
/deep/ .van-cell:not(:last-child)::after {
border-bottom: 1px solid #efefef;
}
.form_second {
margin-top: 10px;
display: flex;
justify-content: space-between;
color: #999;
.checkbox {
margin-left: 20px;
/deep/ .van-checkbox__label {
color: #999;
}
}
.forget {
text-decoration: underline;
}
}
// /deep/ .van-field__body input::-webkit-input-placeholder {
// color: #8F9196;
// }
</style>
\ No newline at end of file \ No newline at end of file
<template>
<div class="login_container">
<UserCommon>
<template slot="top">
<NafmHeader bgColor="transparent" />
</template>
</UserCommon>
<div class="login_content">
<LoginTabs :type="1" />
<div class="login_form_box">
<div class="login_form">
<van-field v-model.trim="phone" clearable type="tel" maxlength="11" :left-icon="phoneIcon" placeholder="请输入手机号" />
<van-field v-model.trim="password" clearable label="" type="tel" maxlength="6" :left-icon="VerificationIcon" placeholder="请输入验证码">
<template #button>
<SendVerificationCode :phone="phone" :data="objParams" />
</template>
</van-field>
<div class="login_btn" :class="{loginActive:isBothValue}" @click="handleLogin">登 录</div>
<div class="register_btn" @click="jumpRigster">立即注册</div>
</div>
</div>
</div>
<OtherLogin />
</div>
</template>
<script>
import UserCommon from '@/components/UserCommon'
import LoginTabs from './components/LoginTabs'
import OtherLogin from './components/OtherLogin'
import SendVerificationCode from '@/components/SendVerificationCode'
import utils from "@/utils/";
export default {
name: 'Login',
components: {
UserCommon,
LoginTabs,
OtherLogin,
SendVerificationCode
},
data() {
return {
phone: null,
password: "",
objParams: {
type: 'phone'
},
type: 'phone',
phoneIcon: require('@/assets/icon/user.png'),
VerificationIcon: require('@/assets/icon/verification.png'),
}
},
computed: {
isBothValue() {
if (this.phone && this.password) {
return true
} else {
return false
}
},
},
methods: {
// 登录操作
handleLogin() {
if (!this.phone) {
Toast('请输入手机号')
return
}
if (!utils.phoneRegCheck(this.phone)) {
Toast("请输入正确的手机号码!");
return
}
if (!this.password) {
Toast('请输入验证码')
return
}
// todo 请求接口
console.log(1)
},
// 跳转注册页面
jumpRigster() {
this.$router.push({
path: '/user/register'
})
},
}
}
</script>
<style lang="less" scoped>
@import "./less/login.less";
// /deep/ .van-field__body input::-webkit-input-placeholder {
// color: #8F9196;
// }
</style>
\ No newline at end of file \ No newline at end of file
<template>
<div class="login_container">
<UserCommon>
<template slot="top">
<NafmHeader bgColor="transparent" />
</template>
</UserCommon>
<div class="login_content">
<LoginTabs :type="2" />
<div class="login_form_box">
<div class="login_form">
<van-field v-model.trim="userName" clearable type="tel" maxlength="11" :left-icon="userNameIcon" placeholder="请输入手机号" />
<van-field v-model.trim="password" clearable type="password" label="" maxlength="16" :left-icon="passwordIcon" placeholder="请输入6-16位密码" />
<div class="form_second">
<van-checkbox v-model="checked" checked-color="#106abc" class="checkbox" shape="square" icon-size="12px">记住密码</van-checkbox>
<span class="forget" @click="controllForgetBox(true)">忘记密码</span>
</div>
<div class="login_btn" :class="{loginActive:isBothValue}" @click="handleLogin">登 录</div>
<div class="register_btn" @click="jumpRigster">立即注册</div>
</div>
</div>
</div>
<OtherLogin />
<van-action-sheet v-model="showForget" :actions="actionsForget" cancel-text="取消" close-on-click-action @cancel="controllForgetBox(false)" @select="selectForgetMethod" />
</div>
</template>
<script>
import UserCommon from '@/components/UserCommon'
import LoginTabs from './components/LoginTabs'
import OtherLogin from './components/OtherLogin'
import SendVerificationCode from '@/components/SendVerificationCode'
import utils from "@/utils/";
export default {
name: 'Login',
components: {
UserCommon,
LoginTabs,
OtherLogin,
SendVerificationCode
},
data() {
return {
userName: null,
password: "",
objParams: {
type: 'phone'
},
type: 'phone',
checked: false,
userNameIcon: require('@/assets/icon/user.png'),
passwordIcon: require('@/assets/icon/password.png'),
actionsForget: [{ name: '手机号找回', key: 'phone' }, { name: '邮箱找回', key: 'email' }],
showForget: false,
}
},
computed: {
isBothValue() {
if (this.userName && this.password) {
return true
} else {
return false
}
},
},
methods: {
// 登录操作
handleLogin() {
if (!this.userName) {
Toast('请输入手机号')
return
}
if (!utils.phoneRegCheck(this.userName)) {
Toast("请输入正确的手机号码!");
return
}
if (!this.password) {
Toast('请输入验证码')
return
}
// todo 请求接口
console.log(1)
},
// 跳转注册页面
jumpRigster() {
this.$router.push({
path: '/user/register'
})
},
// 打开/关闭 忘记密码框
controllForgetBox(value) {
this.showForget = value
},
// 选择方式找回密码
selectForgetMethod(value) {
this.$router.push({
path: '/user/findPassword',
query: {
type: value.key
}
})
},
}
}
</script>
<style lang="less" scoped>
@import "./less/login.less";
// /deep/ .van-field__body input::-webkit-input-placeholder {
// color: #8F9196;
// }
</style>
\ No newline at end of file \ No newline at end of file
<template> <template>
<div> <div class="login_container">
<NafmHeader /> <UserCommon>
<template slot="top">
<NafmHeader bgColor="transparent" />
</template>
</UserCommon>
<div class="login_content">
<div class="login_form_box">
<div class="login_form">
<van-field v-model.trim="password" clearable type="password" maxlength="16" :left-icon="passwordIcon" placeholder="请输入6-16位密码" />
<van-field v-model.trim="aginPassword" clearable type="password" maxlength="16" :left-icon="passwordIcon" placeholder="再次输入6-16位密码" />
<div class="login_btn" :class="{loginActive:isBothValue}" @click="handleReset">重 置</div>
</div>
</div>
</div>
</div> </div>
</template> </template>
<script>
import UserCommon from '@/components/UserCommon'
export default {
name: 'Login',
components: {
UserCommon,
},
data() {
return {
password: "",
aginPassword:"",
passwordIcon: require('@/assets/icon/password.png'),
}
},
computed: {
isBothValue() {
if (this.password && this.aginPassword) {
return true
} else {
return false
}
},
},
methods: {
// 登录操作
handleReset() {
if (!this.password) {
Toast('请输入密码')
return
}
if (!this.aginPassword) {
Toast('请再次输入密码')
return
}
if (this.password!=this.aginPassword) {
Toast('两次输入的密码不一致')
return
}
// todo 请求接口
console.log(1)
},
}
}
</script>
<style lang="less" scoped>
@import "./less/login.less";
</style>
\ No newline at end of file \ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!