u
This commit is contained in:
1 parent
1da52dc4f4
commit
276644f473
223 files changed
+9609
-262
No files matched your search
@@ -1,14 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { loginApi } from '@/request/api/auth'
|
||||
import { loginByEmailCodeApi, loginByPasswordApi } from '@/request/api/auth'
|
||||
import { authCodeSendApi } from '@/request/api/auth/code'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { AuthCodeChannel, AuthCodePurpose } from '@/types/auth/code'
|
||||
import { validateEmail } from '@/utils/validate'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
|
||||
const loginOptions = [
|
||||
{
|
||||
label: '密码登录',
|
||||
value: '0',
|
||||
},
|
||||
{
|
||||
label: '验证码登录',
|
||||
value: '1',
|
||||
},
|
||||
]
|
||||
const loginMode = ref('0')
|
||||
|
||||
const carouselList = [
|
||||
{
|
||||
title: '值得信赖',
|
||||
@@ -37,59 +52,160 @@ const carouselList = [
|
||||
},
|
||||
]
|
||||
|
||||
// --- 发送验证码状态 & 倒计时 ---
|
||||
const sending = ref(false)
|
||||
const countdown = ref(0)
|
||||
let timer: number | undefined
|
||||
|
||||
function startCountdown(seconds = 60) {
|
||||
countdown.value = seconds
|
||||
timer = window.setInterval(() => {
|
||||
countdown.value -= 1
|
||||
if (countdown.value <= 0) {
|
||||
clearInterval(timer)
|
||||
timer = undefined
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const form = reactive<{
|
||||
loginCredential: string
|
||||
email: string
|
||||
password: string
|
||||
code: string
|
||||
rememberMe: boolean
|
||||
}>({
|
||||
loginCredential: '',
|
||||
email: '',
|
||||
password: '',
|
||||
code: '',
|
||||
rememberMe: true,
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const formRules = {
|
||||
loginCredential: [
|
||||
email: [
|
||||
{ required: true, message: '邮箱号不能为空', trigger: 'blur' },
|
||||
{ type: 'email', required: true, message: '邮箱格式错误', trigger: 'blur' },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '密码不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (loginMode.value === '0') {
|
||||
if (!value) {
|
||||
callback(new Error('密码不能为空'))
|
||||
return
|
||||
}
|
||||
}
|
||||
callback() // 校验通过
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
code: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (loginMode.value === '1') {
|
||||
if (!value) {
|
||||
callback(new Error('验证码不能为空'))
|
||||
return
|
||||
}
|
||||
}
|
||||
callback() // 校验通过
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const isEmailValid = computed(() => validateEmail(form.email))
|
||||
|
||||
const submitLoading = ref(false)
|
||||
|
||||
function handleSendEmailCode() {
|
||||
if (sending.value || countdown.value > 0 || !isEmailValid.value)
|
||||
return
|
||||
|
||||
sending.value = true
|
||||
|
||||
authCodeSendApi({
|
||||
channel: AuthCodeChannel.EMAIL,
|
||||
purpose: AuthCodePurpose.LOGIN,
|
||||
target: form.email,
|
||||
}).then((res) => {
|
||||
if (res.isSuccess) {
|
||||
ElMessage.success('发送成功')
|
||||
startCountdown()
|
||||
}
|
||||
else {
|
||||
sending.value = false
|
||||
ElMessage.error(res.message || '发送失败,请检查邮箱是否正确或稍后再试!')
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
|
||||
ElMessage.error('发送失败,请稍后再试')
|
||||
sending.value = false
|
||||
}).finally(() => {
|
||||
sending.value = false
|
||||
})
|
||||
}
|
||||
|
||||
async function submitForm(formEl: FormInstance | undefined) {
|
||||
if (!formEl)
|
||||
return
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true
|
||||
loginApi({
|
||||
loginCredential: form.loginCredential,
|
||||
password: form.password,
|
||||
}).then((res) => {
|
||||
if (res.isSuccess) {
|
||||
userStore.setUserInfo({
|
||||
id: res.data.id,
|
||||
account: res.data.account,
|
||||
email: res.data.email,
|
||||
name: res.data.name,
|
||||
token: res.data.token,
|
||||
avatar: res.data.avatar || '/no-avatar.png',
|
||||
})
|
||||
|
||||
ElMessage.success('登录成功')
|
||||
router.push('/')
|
||||
}
|
||||
else {
|
||||
ElMessage.error(res.message || '登录失败,请稍后再试!')
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
}).finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid)
|
||||
return
|
||||
|
||||
submitLoading.value = true
|
||||
|
||||
try {
|
||||
let res
|
||||
if (loginMode.value === '0') {
|
||||
// 密码登录
|
||||
res = await loginByPasswordApi({
|
||||
email: form.email,
|
||||
password: form.password,
|
||||
})
|
||||
}
|
||||
else {
|
||||
// 验证码登录
|
||||
res = await loginByEmailCodeApi({
|
||||
email: form.email,
|
||||
code: form.code,
|
||||
})
|
||||
}
|
||||
|
||||
if (res.isSuccess) {
|
||||
ElMessage.success('登录成功')
|
||||
|
||||
userStore.setUserInfo({
|
||||
user: {
|
||||
id: res.data.userId,
|
||||
name: res.data.userName,
|
||||
position: res.data.userPosition,
|
||||
role: res.data.userRole,
|
||||
},
|
||||
company: {
|
||||
id: res.data.companyId,
|
||||
logo: res.data.companyLogo,
|
||||
name: res.data.companyName,
|
||||
},
|
||||
token: res.data.token,
|
||||
})
|
||||
|
||||
router.push('/')
|
||||
}
|
||||
else {
|
||||
ElMessage.error(res.message || '登录失败,请稍后再试')
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
ElMessage.error('登录失败,请稍后再试')
|
||||
}
|
||||
finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -130,8 +246,19 @@ function navigateTo(path: string) {
|
||||
<h4 class="title">
|
||||
登录
|
||||
</h4>
|
||||
<div style="padding: 8px 0px;">
|
||||
<el-segmented
|
||||
v-model="loginMode" :options="loginOptions" size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p class="title-extra">
|
||||
输入你的 邮箱 和 密码 登录账户.
|
||||
<template v-if="loginMode === '0'">
|
||||
输入你的 邮箱 和 密码 登录系统
|
||||
</template>
|
||||
<template v-else-if="loginMode === '1'">
|
||||
输入你的 邮箱 和 验证码 登录系统
|
||||
</template>
|
||||
</p>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
@@ -141,11 +268,14 @@ function navigateTo(path: string) {
|
||||
label-position="top"
|
||||
hide-required-asterisk
|
||||
>
|
||||
<el-form-item label="邮箱" prop="loginCredential">
|
||||
<el-input v-model="form.loginCredential" placeholder="请输入邮箱" size="large" />
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" size="large" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="password">
|
||||
<el-form-item
|
||||
v-if="loginMode === '0'"
|
||||
prop="password"
|
||||
>
|
||||
<template #label>
|
||||
<span class="form-label-flex">
|
||||
<span>密码</span>
|
||||
@@ -155,11 +285,47 @@ function navigateTo(path: string) {
|
||||
<el-input
|
||||
v-model="form.password"
|
||||
placeholder="请输入密码"
|
||||
show-password
|
||||
size="large"
|
||||
@keyup.enter="submitForm(formRef)"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
v-else
|
||||
prop="code"
|
||||
>
|
||||
<template #label>
|
||||
<span class="form-label-flex">
|
||||
<span>密码</span>
|
||||
<span class="forgot" @click="navigateTo('/auth/forget')">忘记密码?</span>
|
||||
</span>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="form.code"
|
||||
placeholder="请输入邮箱验证码"
|
||||
class="email-code"
|
||||
size="large"
|
||||
:class="(sending || countdown > 0 || !isEmailValid) ? 'disabled' : ''"
|
||||
>
|
||||
<template #append>
|
||||
<el-button
|
||||
:disabled="sending || countdown > 0 || !isEmailValid"
|
||||
@click="handleSendEmailCode"
|
||||
>
|
||||
<template v-if="sending">
|
||||
发送中...
|
||||
</template>
|
||||
<template v-else-if="countdown > 0">
|
||||
{{ countdown }}s
|
||||
</template>
|
||||
<template v-else>
|
||||
发送验证码
|
||||
</template>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="form.rememberMe" label="记住我" class="remeber" />
|
||||
</el-form-item>
|
||||
@@ -257,6 +423,20 @@ function navigateTo(path: string) {
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.email-code {
|
||||
:deep(.el-input-group__append) {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
:deep(.el-input-group__append) {
|
||||
background-color: #f5f7fa;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remeber {
|
||||
:deep(.el-checkbox__inner) {
|
||||
@@ -267,6 +447,7 @@ function navigateTo(path: string) {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
|
||||
Reference in new issue
Block a user