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.
513 lines
12 KiB
513 lines
12 KiB
1 year ago
|
<!--登录弹窗组件-->
|
||
|
<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>
|