|
|
@ -15,7 +15,8 @@
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 登录表单 -->
|
|
|
|
<!-- 登录表单 -->
|
|
|
|
<form @submit.prevent="login" class="login-form">
|
|
|
|
<button @click="login" v-if="false">测试登录</button>
|
|
|
|
|
|
|
|
<form @submit.prevent="Login1" class="login-form">
|
|
|
|
<div class="input-group">
|
|
|
|
<div class="input-group">
|
|
|
|
<!-- 用户标识输入框(用户名/邮箱/手机) -->
|
|
|
|
<!-- 用户标识输入框(用户名/邮箱/手机) -->
|
|
|
|
<input
|
|
|
|
<input
|
|
|
@ -70,195 +71,177 @@
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
<script setup name="UserLogin">
|
|
|
|
import { ref, computed } from 'vue';
|
|
|
|
import { ref, computed } from 'vue';
|
|
|
|
import axios from 'axios';
|
|
|
|
import axios from 'axios';
|
|
|
|
import request from '@/utils/request';
|
|
|
|
import request from '@/utils/request';
|
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
import { useUserStore } from '@/stores/user.ts';
|
|
|
|
import { useUserStore } from '@/stores/user.js';
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
const currentType = ref('username'); // 当前选择的登录方式
|
|
|
|
name: 'UserLogin',
|
|
|
|
const cooldown = ref(0); // 验证码发送倒计时
|
|
|
|
//TODO: 引入props, { emit }然后实现登陆成功跳转
|
|
|
|
const userStore = useUserStore(); // 引入用户状态管理
|
|
|
|
setup() {
|
|
|
|
const emit = defineEmits(['toggleForm', 'LoginSuccess']); // 定义事件
|
|
|
|
const currentType = ref('username'); //当前选择的登录方式
|
|
|
|
// 登录方式
|
|
|
|
const cooldown = ref(0); //验证码发送倒计时
|
|
|
|
const loginTypes = [
|
|
|
|
const userStore = useUserStore(); //引入用户状态管理
|
|
|
|
{ label: '用户名登录', value: 'username' },
|
|
|
|
//登录方式
|
|
|
|
{ label: '邮箱登录', value: 'email' },
|
|
|
|
const loginTypes = [
|
|
|
|
{ label: '手机登录', value: 'phone' }
|
|
|
|
{ label: '用户名登录', value: 'username' },
|
|
|
|
];
|
|
|
|
{ label: '邮箱登录', value: 'email' },
|
|
|
|
|
|
|
|
{ label: '手机登录', value: 'phone' }
|
|
|
|
// 登录数据对象
|
|
|
|
];
|
|
|
|
const loginForm = ref({
|
|
|
|
|
|
|
|
userFlag: '', // 用户标识
|
|
|
|
//登录数据对象
|
|
|
|
password: '', // 密码
|
|
|
|
const loginForm = ref({
|
|
|
|
verifyCode: '', // 验证码(邮箱/手机登录时使用)
|
|
|
|
userFlag: '', // 用户标识
|
|
|
|
remember: false // 记住登录状态
|
|
|
|
password: '', // 密码
|
|
|
|
});
|
|
|
|
verifyCode: '', // 验证码(邮箱/手机登录时使用)
|
|
|
|
|
|
|
|
remember: false // 记住登录状态
|
|
|
|
// 输入框类型
|
|
|
|
});
|
|
|
|
const inputType = computed(() => {
|
|
|
|
|
|
|
|
switch (currentType.value) {
|
|
|
|
//输入框类型
|
|
|
|
case 'email':
|
|
|
|
const inputType = computed(() => {
|
|
|
|
return 'email'; // 邮箱输入类型
|
|
|
|
switch(currentType.value) {
|
|
|
|
case 'phone':
|
|
|
|
case 'email': return 'email'; // 邮箱输入类型
|
|
|
|
return 'tel'; // 电话号码输入类型
|
|
|
|
case 'phone': return 'tel'; // 电话号码输入类型
|
|
|
|
default:
|
|
|
|
default: return 'text'; // 默认文本输入类型
|
|
|
|
return 'text'; // 默认文本输入类型
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//输入框提示文字
|
|
|
|
// 输入框提示文字
|
|
|
|
const placeholder = computed(() => {
|
|
|
|
const placeholder = computed(() => {
|
|
|
|
switch(currentType.value) {
|
|
|
|
switch (currentType.value) {
|
|
|
|
case 'username': return '请输入用户名';
|
|
|
|
case 'username':
|
|
|
|
case 'email': return '请输入邮箱';
|
|
|
|
return '请输入用户名';
|
|
|
|
case 'phone': return '请输入手机号';
|
|
|
|
case 'email':
|
|
|
|
default: return '';
|
|
|
|
return '请输入邮箱';
|
|
|
|
}
|
|
|
|
case 'phone':
|
|
|
|
});
|
|
|
|
return '请输入手机号';
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return '';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 判断是否显示验证码输入框
|
|
|
|
|
|
|
|
const showVerifyCode = computed(() => {
|
|
|
|
|
|
|
|
return ['email', 'phone'].includes(currentType.value);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 验证输入框是否有效
|
|
|
|
|
|
|
|
const isValidInput = computed(() => {
|
|
|
|
|
|
|
|
const value = loginForm.value.userFlag;
|
|
|
|
|
|
|
|
if (!value) return false; // 输入不能为空
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (currentType.value) {
|
|
|
|
|
|
|
|
case 'email':
|
|
|
|
|
|
|
|
return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+$/.test(value);
|
|
|
|
|
|
|
|
case 'phone':
|
|
|
|
|
|
|
|
return /^1[3-9]\d{9}$/.test(value);
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return value.length > 0; // 用户名非空
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//判断是否显示验证码输入框
|
|
|
|
// 验证表单
|
|
|
|
const showVerifyCode = computed(() => {
|
|
|
|
const isvalidForm = computed(() => {
|
|
|
|
return ['email', 'phone'].includes(currentType.value);
|
|
|
|
if (!isValidInput.value) return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//验证输入框是否有效
|
|
|
|
if (showVerifyCode.value) {
|
|
|
|
const isValidInput = computed(() => {
|
|
|
|
return loginForm.value.verifyCode.length === 6; // 验证码长度
|
|
|
|
const value = loginForm.value.userFlag
|
|
|
|
} else {
|
|
|
|
if(!value) return false; //输入不能为空
|
|
|
|
return loginForm.value.password.length >= 6; // 密码长度
|
|
|
|
|
|
|
|
}
|
|
|
|
switch(currentType.value) {
|
|
|
|
});
|
|
|
|
case 'email':
|
|
|
|
|
|
|
|
return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+$/.test(value);
|
|
|
|
|
|
|
|
case 'phone':
|
|
|
|
|
|
|
|
return /^1[3-9]\d{9}$/.test(value);
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return value.length > 0; //用户名非空
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//验证表单
|
|
|
|
// 发送验证码(用于邮箱和手机登录)
|
|
|
|
const isvalidForm = computed(() => {
|
|
|
|
async function sendCode() {
|
|
|
|
if(!isValidInput.value) return false;
|
|
|
|
if (cooldown.value > 0 || !isValidInput.value) return; // 在冷却时间内,不允许重复发送
|
|
|
|
|
|
|
|
|
|
|
|
if(showVerifyCode.value){
|
|
|
|
try {
|
|
|
|
return loginForm.value.verifyCode.length === 6; //验证码长度
|
|
|
|
// TODO: 后端发送验证码请求
|
|
|
|
} else {
|
|
|
|
const response = await axios.post('/user/sendCode', {
|
|
|
|
return loginForm.value.password.length >= 6; //密码长度
|
|
|
|
type: currentType.value,
|
|
|
|
}
|
|
|
|
target: loginForm.value.userFlag
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 发送验证码(用于邮箱和手机登录)
|
|
|
|
if (response.data.success) {
|
|
|
|
async function sendCode() {
|
|
|
|
// 开始60秒倒计时
|
|
|
|
if (cooldown.value > 0 || !isValidInput.value) return; //在冷却时间内,不允许重复发送
|
|
|
|
cooldown.value = 60;
|
|
|
|
|
|
|
|
const timer = setInterval(() => {
|
|
|
|
try {
|
|
|
|
cooldown.value--;
|
|
|
|
//TODO:后端发送验证码请求
|
|
|
|
if (cooldown.value <= 0) {
|
|
|
|
const response = await axios.post('/user/sendCode', {
|
|
|
|
clearInterval(timer);
|
|
|
|
type: currentType.value,
|
|
|
|
|
|
|
|
target: loginForm.value.userFlag
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (response.data.success) {
|
|
|
|
|
|
|
|
//开始60秒倒计时
|
|
|
|
|
|
|
|
cooldown.value = 60;
|
|
|
|
|
|
|
|
const timer = setInterval(() => {
|
|
|
|
|
|
|
|
cooldown.value--;
|
|
|
|
|
|
|
|
if (cooldown.value <= 0) {
|
|
|
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
}, 1000);
|
|
|
|
console.error('发送验证码失败:', error);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error('发送验证码失败:', error);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//前端测试登录
|
|
|
|
|
|
|
|
function Login1() {
|
|
|
|
|
|
|
|
userStore.login({
|
|
|
|
|
|
|
|
avatar:require('@/assets/default-avatar/boy_1.png'),
|
|
|
|
|
|
|
|
userName: '珈人一号'
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
emit('LoginSuccess');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 登录
|
|
|
|
|
|
|
|
async function login() {
|
|
|
|
|
|
|
|
if (!isvalidForm.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const loginData = {
|
|
|
|
|
|
|
|
userFlag: loginForm.value.userFlag,
|
|
|
|
|
|
|
|
password: loginForm.value.password
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//登录
|
|
|
|
if (showVerifyCode.value) {
|
|
|
|
/*
|
|
|
|
loginData.verifyCode = loginForm.value.verifyCode; // 验证码
|
|
|
|
function login1() {
|
|
|
|
}
|
|
|
|
userStore.login({
|
|
|
|
|
|
|
|
avatar: '/assets/default-avatar/boy_1.png',
|
|
|
|
|
|
|
|
userName: '珈人一号'
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function login() {
|
|
|
|
|
|
|
|
if (!isvalidForm.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const loginData = {
|
|
|
|
|
|
|
|
userFlag: loginForm.value.userFlag,
|
|
|
|
|
|
|
|
password: loginForm.value.password
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (showVerifyCode.value) {
|
|
|
|
|
|
|
|
loginData.verifyCode = loginForm.value.verifyCode; //验证码
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//post请求登录接口
|
|
|
|
// post请求登录接口
|
|
|
|
const response = await request.post('/user/login', loginData);
|
|
|
|
const response = await request.post('/user/login', loginData);
|
|
|
|
|
|
|
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
|
|
|
//登录成功,保存token到本地存储
|
|
|
|
|
|
|
|
//还应读入用户数据,后续设计
|
|
|
|
|
|
|
|
const { accessToken, refreshToken } = response.data;
|
|
|
|
|
|
|
|
localStorage.setItem('accessToken', accessToken);
|
|
|
|
|
|
|
|
localStorage.setItem('refreshToken', refreshToken);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
userStore.login({
|
|
|
|
|
|
|
|
avatar: '/assets/default-avatar/boy_1.png',
|
|
|
|
|
|
|
|
userName: '珈人一号'
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ElMessage({
|
|
|
|
|
|
|
|
message: '登录成功',
|
|
|
|
|
|
|
|
type: 'success',
|
|
|
|
|
|
|
|
duration: 500
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
//TODO:跳转到目标页面
|
|
|
|
|
|
|
|
//or 关闭登录弹窗
|
|
|
|
|
|
|
|
}else{
|
|
|
|
|
|
|
|
//登录失败
|
|
|
|
|
|
|
|
ElMessage({
|
|
|
|
|
|
|
|
message: '登陆失败,用户名或密码错误',
|
|
|
|
|
|
|
|
type: 'error',
|
|
|
|
|
|
|
|
duration: 500
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
if (response.code === 200) {
|
|
|
|
console.error('登录失败:', error);
|
|
|
|
// 登录成功,保存token到本地存储
|
|
|
|
alert(error.response?.message ||'登录失败,请稍后重试');
|
|
|
|
const { accessToken, refreshToken } = response.data;
|
|
|
|
}
|
|
|
|
localStorage.setItem('accessToken', accessToken);
|
|
|
|
}
|
|
|
|
localStorage.setItem('refreshToken', refreshToken);
|
|
|
|
|
|
|
|
|
|
|
|
//切换登陆方式时重置表单
|
|
|
|
userStore.login({
|
|
|
|
const switchLoginType = (type) => {
|
|
|
|
avatar: '/assets/default-avatar/boy_1.png',
|
|
|
|
currentType.value = type;
|
|
|
|
userName: '珈人一号'
|
|
|
|
loginForm.value.userFlag = '';
|
|
|
|
});
|
|
|
|
loginForm.value.password = '';
|
|
|
|
|
|
|
|
loginForm.value.verifyCode = '';
|
|
|
|
ElMessage({
|
|
|
|
|
|
|
|
message: '登录成功',
|
|
|
|
|
|
|
|
type: 'success',
|
|
|
|
|
|
|
|
duration: 500
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: 跳转到目标页面或关闭登录弹窗
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 登录失败
|
|
|
|
|
|
|
|
ElMessage({
|
|
|
|
|
|
|
|
message: '登陆失败,用户名或密码错误',
|
|
|
|
|
|
|
|
type: 'error',
|
|
|
|
|
|
|
|
duration: 500
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
// 返回模板需要使用的数据和方法
|
|
|
|
console.error('登录失败:', error);
|
|
|
|
return {
|
|
|
|
alert(error.response?.message || '登录失败,请稍后重试');
|
|
|
|
currentType,
|
|
|
|
|
|
|
|
loginTypes,
|
|
|
|
|
|
|
|
loginForm,
|
|
|
|
|
|
|
|
inputType,
|
|
|
|
|
|
|
|
placeholder,
|
|
|
|
|
|
|
|
showVerifyCode,
|
|
|
|
|
|
|
|
cooldown,
|
|
|
|
|
|
|
|
sendCode,
|
|
|
|
|
|
|
|
//login1,
|
|
|
|
|
|
|
|
login,
|
|
|
|
|
|
|
|
switchLoginType,
|
|
|
|
|
|
|
|
isValidInput
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 切换登录方式时重置表单
|
|
|
|
|
|
|
|
const switchLoginType = (type) => {
|
|
|
|
|
|
|
|
currentType.value = type;
|
|
|
|
|
|
|
|
loginForm.value.userFlag = '';
|
|
|
|
|
|
|
|
loginForm.value.password = '';
|
|
|
|
|
|
|
|
loginForm.value.verifyCode = '';
|
|
|
|
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
<style scoped>
|
|
|
|