You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
512 lines
12 KiB
512 lines
12 KiB
<!--登录弹窗组件--> |
|
<template> |
|
<el-dialog |
|
class="user-login-dialog" |
|
v-model="dialogVisible" |
|
:align-center="true" |
|
:width="420" |
|
:append-to-body="true" |
|
:show-close="false" |
|
> |
|
<div class="login-count"> |
|
<!-- 登录弹窗 --> |
|
<div class="wrapper-count"> |
|
<span class="closeBtn iconfont icon-danchuangguanbi" @click="closeLogin"></span> |
|
|
|
<div class="wrapper"> |
|
<div class="title"> |
|
<span class="item_title" @click="current = 1" :class="current === 1 ? 'font18' : ''">登录/注册</span> |
|
<span class="item_title" @click="current = 2" :class="current === 2 ? 'font18' : ''">密码登录</span> |
|
</div> |
|
<div class="iconfont icon-erweima2" @click="current = 3"></div> |
|
<!--手机号--> |
|
<div class="item phone acea-row row-middle"> |
|
<div class="number mr-14px"><span class="iconfont icon-shoujihao"></span></div> |
|
<input type="text" placeholder="请输入手机号" v-model="formData.phone" class="w-90% text-14px text-#333" /> |
|
</div> |
|
<!--验证码--> |
|
<div |
|
v-show="current === 1 || current === 4 || current === 5" |
|
class="item phone verificat acea-row row-between-wrapper" |
|
> |
|
<div class="acea-row row-middle"> |
|
<div class="number mr-14px"><span class="iconfont icon-yanzhengma"></span></div> |
|
<input |
|
type="text" |
|
autocomplete="new-password" |
|
placeholder="请输入验证码" |
|
v-model="formData.captcha" |
|
class="text-14px text-#333" |
|
/> |
|
</div> |
|
<button |
|
class="code font-color cursors" |
|
:disabled="disabled" |
|
:class="disabled === true ? 'on' : ''" |
|
@click="handleSendcode()" |
|
> |
|
{{ text }} |
|
</button> |
|
</div> |
|
|
|
<!--密码登录--> |
|
<div v-show="current === 2"> |
|
<div class="item phone verificat acea-row"> |
|
<div class="number mr-14px"><span class="iconfont icon-mima"></span></div> |
|
<input |
|
type="password" |
|
class="text-14px text-#333 w-90%" |
|
placeholder="请输入密码" |
|
v-model="formData.password" |
|
/> |
|
</div> |
|
</div> |
|
|
|
<!--底部按钮--> |
|
<div class="checkbox-wrapper item_protocol acea-row row-middle" style="margin-top: 25px;"> |
|
<label class="well-check" style="line-height: 2"> |
|
<input type="checkbox" name="" value="" :checked="isAgreement" @click="isAgreement = !isAgreement" /> |
|
<i class="iconfont mr-7px icon" style="top: 11px"></i> |
|
<span>十天内免登录(公共场合慎选)</span> |
|
</label> |
|
</div> |
|
<div class="checkbox-wrapper item_protocol acea-row row-middle"> |
|
<label class="well-check" style="line-height: 2"> |
|
<input type="checkbox" name="" value="" :checked="isAgreement" @click="isAgreement = !isAgreement" /> |
|
<i class="iconfont mr-7px icon" style="top: 11px"></i> |
|
<span>我已阅读并同意</span> |
|
</label> |
|
<nuxt-link |
|
:to="{ path: `/users/agreement_rules`, query: { type: 'userinfo', name: '用户协议' } }" |
|
target="_blank" |
|
class="show_protocol" |
|
>《用户协议》 |
|
</nuxt-link> |
|
与 |
|
<nuxt-link |
|
:to="{ path: `/users/agreement_rules`, query: { type: 'userprivacyinfo', name: '隐私协议' } }" |
|
target="_blank" |
|
class="show_protocol" |
|
>《隐私协议》 |
|
</nuxt-link> |
|
</div> |
|
<div class="signIn bg-color" @click="handleLogin">登录</div> |
|
<div class="forgot-password"> |
|
<div class="left-btn">忘记密码</div> |
|
<div class="left-btn">注册</div> |
|
</div> |
|
</div> |
|
<div class="wxLogin wrapper" v-if="current === 3"> |
|
<div class="inner">扫码登录</div> |
|
<div class="iconfont icon-zhanghaodenglu1" @click="current = 1"></div> |
|
<div class="wxCode"> |
|
<span class="iconfont icon-erweimabianjiao"></span> |
|
<span class="iconfont icon-erweimabianjiao"></span> |
|
<span class="iconfont icon-erweimabianjiao"></span> |
|
<span class="iconfont icon-erweimabianjiao"></span> |
|
<img v-if="qrCode" :src="qrCode" /> |
|
</div> |
|
<div class="tip">请使用微信扫一扫登录</div> |
|
</div> |
|
</div> |
|
</div> |
|
<VerifitionVerify ref="verifyRef" :phone="formData.phone" @success="handlerOnVerSuccess"></VerifitionVerify> |
|
</el-dialog> |
|
</template> |
|
<script setup lang="ts"> |
|
import { PhoneReg } from '~/utils/validate' |
|
import { Debounce } from '~/utils/util' |
|
import { useUserStore } from '~/stores/user' |
|
import { loginMobile, loginPassword, registerVerify, userPhoneCodeApi } from '~/server/userApi' |
|
import feedback from '~/utils/feedback' |
|
import useOrder from '~/composables/useOrder' |
|
import {ref, reactive} from 'vue' |
|
const userStore = useUserStore() |
|
const emit = defineEmits(['onLoginSucceeded']) |
|
const handleEmit = () => { |
|
emit('onLoginSucceeded') |
|
} |
|
|
|
//是否勾选协议 |
|
const isAgreement = ref(false) |
|
|
|
// 登录提交数据 |
|
const formData = reactive({ |
|
captcha: '', |
|
phone: '', |
|
spreadPid: 0, |
|
password: '', |
|
}) |
|
|
|
//扫码登录二维码 |
|
const qrCode = ref('') |
|
|
|
//验证码 |
|
const { disabled, text, handleCodeSend } = useSmsCode() |
|
const isSendCode = ref(false) |
|
|
|
// 手机号码验证 |
|
const checkPhone = (rule: any, value: any, callback: any) => { |
|
if (!value) { |
|
return callback(new Error('请输入手机号码')) |
|
} |
|
setTimeout(() => { |
|
if (PhoneReg.test(value)) { |
|
callback() |
|
} else { |
|
callback(new Error('请输入有效的电话号码')) |
|
} |
|
}, 150) |
|
} |
|
|
|
// 手机号码验证 |
|
const inputPhone = (e: any) => { |
|
isSendCode.value = PhoneReg.test(e) |
|
} |
|
|
|
// 打开登录弹窗 |
|
const { bool: dialogVisible, DialogOpen, DialogClose } = useDialog() |
|
const open = () => { |
|
DialogOpen() |
|
} |
|
defineExpose({ open }) |
|
|
|
const colse = () => { |
|
DialogClose() |
|
formData.phone = '' |
|
formData.captcha = '' |
|
} |
|
//关闭登录弹窗 |
|
const closeLogin = () => { |
|
DialogClose() |
|
} |
|
|
|
// 获取验证码 |
|
const verifyRef = shallowRef() |
|
const handleSendcode = () => { |
|
if (!formData.phone) return feedback.msgWarning('请填写手机号') |
|
verifyRef.value.show() |
|
} |
|
|
|
// 发送成功后的回调 |
|
const handlerOnVerSuccess = async (e: any) => { |
|
await registerVerify({ phone: formData.phone }) |
|
feedback.msgSuccess('发送成功') |
|
handleCodeSend() |
|
} |
|
const agreementConfirm = async () => { |
|
if (isAgreement.value) { |
|
return |
|
} |
|
await feedback.confirm('确认已阅读并同意《服务协议》和《隐私政策》') |
|
isAgreement.value = true |
|
} |
|
|
|
// 登录按钮提交 |
|
//显示标识 1快速登录 2密码登录 |
|
const current = ref<number>(1) |
|
const { onGetCartCount } = useOrder() |
|
const handleLogin = Debounce(async () => { |
|
if (!formData.phone) return feedback.msgError('请填写手机号码') |
|
if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(formData.phone)) return feedback.msgError('请输入正确的手机号码') |
|
if (!isAgreement.value) return feedback.msgError('请勾选用户隐私协议') |
|
//快速登录 |
|
if (current.value === 1) { |
|
await getLoginMobile() |
|
} else { |
|
//账号密码登录 |
|
if (!formData.password) return feedback.msgError('请填写密码') |
|
await getloginPassword() |
|
} |
|
await colse() |
|
await handleEmit() //登录成功后操作 |
|
await onGetCartCount() |
|
},500) |
|
|
|
|
|
//密码登录 |
|
const getloginPassword = async () => { |
|
const params = { |
|
phone: formData.phone, |
|
password: formData.password, |
|
spreadPid: formData.spreadPid, |
|
} |
|
const data = await loginPassword(params) |
|
userStore.login(data.token) |
|
userStore.setUserInfo(data) |
|
} |
|
|
|
//快速/验证码登录 |
|
const getLoginMobile = async () => { |
|
const params = { |
|
phone: formData.phone, |
|
captcha: formData.captcha, |
|
spreadPid: formData.spreadPid, |
|
} |
|
const data = await loginMobile(params) |
|
userStore.login(data.token) |
|
userStore.setUserInfo(data) |
|
} |
|
</script> |
|
<style scoped lang="scss"> |
|
@import '@/assets/scss/checkbox.scss'; |
|
input::-webkit-input-placeholder { |
|
/* 修改placeholder颜色 */ |
|
color: #cccccc; |
|
} |
|
.login-count { |
|
width: 100%; |
|
height: 100%; |
|
background-color: rgba(0, 0, 0, 0.5); |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
z-index: 100; |
|
} |
|
|
|
.wrapper-count { |
|
position: relative; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 430px; |
|
height: 428px; |
|
background: #ffffff; |
|
border-radius: 16px 16px 16px 16px; |
|
opacity: 1; |
|
|
|
.closeBtn { |
|
color: #fff; |
|
position: absolute; |
|
top: -33px; |
|
right: -33px; |
|
text-align: center; |
|
font-size: 24px; |
|
cursor: pointer; |
|
} |
|
} |
|
.wrapper { |
|
position: relative; |
|
background-color: #fff; |
|
text-align: center; |
|
padding: 60px 0 0 0; |
|
margin: 0 auto; |
|
border-radius: 16px 16px 16px 16px; |
|
.font_red { |
|
color: #e93323; |
|
} |
|
|
|
.title { |
|
font-size: 18px; |
|
font-weight: 400; |
|
color: #999999; |
|
position: relative; |
|
|
|
.item_title { |
|
cursor: pointer; |
|
|
|
&:first-child { |
|
margin-right: 70px; |
|
} |
|
} |
|
|
|
.iconfont { |
|
position: absolute; |
|
top: -71px; |
|
right: 0; |
|
font-size: 60px; |
|
cursor: pointer; |
|
} |
|
} |
|
|
|
.item { |
|
width: 370px; |
|
height: 50px; |
|
border: 1px solid #cccccc; |
|
border-radius: 8px 8px 8px 8px; |
|
margin: 0 auto; |
|
padding: 0 14px; |
|
|
|
.code { |
|
height: 96%; |
|
border: 0; |
|
background-color: #fff; |
|
font-size: 14px; |
|
|
|
|
|
img { |
|
width: 100%; |
|
height: 100%; |
|
} |
|
|
|
&.on { |
|
color: #ccc !important; |
|
} |
|
} |
|
&.phone { |
|
margin-top: 30px; |
|
|
|
.number { |
|
height: 100%; |
|
line-height: 49px; |
|
color: #cccccc; |
|
} |
|
} |
|
|
|
&.pwd { |
|
margin-top: 20px; |
|
} |
|
|
|
&.verificat { |
|
margin-top: 20px; |
|
} |
|
|
|
input { |
|
/*height: 96%;*/ |
|
border: 0; |
|
outline: none; |
|
font-size: 14px; |
|
} |
|
} |
|
|
|
.signIn { |
|
width: 370px; |
|
height: 50px; |
|
border-radius: 8px 8px 8px 8px; |
|
text-align: center; |
|
line-height: 50px; |
|
margin: 15px auto 0 auto; |
|
color: #fff; |
|
cursor: pointer; |
|
background: linear-gradient(to right, #FFE9AF, #FF4E8D); |
|
} |
|
.forgot-password{ |
|
display: flex; |
|
justify-content: space-between; |
|
padding: 20px 30px; |
|
color: #8A8E99; |
|
font-size: 12px; |
|
} |
|
.fastLogin { |
|
margin-top: 14px; |
|
cursor: pointer; |
|
color: #cccccc; |
|
} |
|
|
|
.title + .iconfont { |
|
position: absolute; |
|
top: 0; |
|
right: 0; |
|
font-size: 46px; |
|
color: #282828; |
|
} |
|
|
|
&.wxLogin { |
|
position: relative; |
|
padding-top: 98px; |
|
|
|
.inner { |
|
position: absolute; |
|
top: 34px; |
|
left: 30px; |
|
font-size: 20px; |
|
color: #282828; |
|
} |
|
|
|
.icon-zhanghaodenglu1 { |
|
position: absolute; |
|
top: 0; |
|
right: 0; |
|
font-size: 46px; |
|
color: #282828; |
|
} |
|
} |
|
|
|
.wxCode { |
|
position: relative; |
|
width: 213px; |
|
height: 213px; |
|
padding: 10px; |
|
margin: 0 auto; |
|
|
|
img { |
|
display: block; |
|
width: 100%; |
|
} |
|
|
|
.iconfont { |
|
font-size: 22px; |
|
color: #cbcbcb; |
|
} |
|
|
|
.iconfont:nth-child(1) { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
} |
|
|
|
.iconfont:nth-child(2) { |
|
position: absolute; |
|
top: 0; |
|
right: 0; |
|
transform: rotate(90deg); |
|
} |
|
|
|
.iconfont:nth-child(3) { |
|
position: absolute; |
|
right: 0; |
|
bottom: 0; |
|
transform: rotate(180deg); |
|
} |
|
|
|
.iconfont:nth-child(4) { |
|
position: absolute; |
|
bottom: 0; |
|
left: 0; |
|
transform: rotate(270deg); |
|
} |
|
} |
|
|
|
.tip { |
|
margin-top: 20px; |
|
font-size: 16px; |
|
color: #666; |
|
} |
|
|
|
.item_protocol { |
|
margin: 0 auto 0; |
|
text-align: left; |
|
padding-left: 30px; |
|
font-size: 12px; |
|
|
|
.icon { |
|
width: 14px; |
|
height: 14px; |
|
} |
|
|
|
.show_protocol { |
|
color: #43A7E5; |
|
cursor: pointer; |
|
} |
|
|
|
.forget_password { |
|
float: right; |
|
color: #999999; |
|
cursor: pointer; |
|
|
|
.icon-wangjimima { |
|
display: inline-block; |
|
width: 12px; |
|
height: 12px; |
|
line-height: 12px; |
|
margin-right: 5px; |
|
position: relative; |
|
top: 1px; |
|
text-align: center; |
|
border: 1px solid #999999; |
|
border-radius: 100%; |
|
} |
|
} |
|
} |
|
} |
|
</style>
|
|
|