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

<!--登录弹窗组件-->
<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>