优化性能
This commit is contained in:
172
frontend/src/components/LoginForm.vue
Normal file
172
frontend/src/components/LoginForm.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div class="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20 shadow-2xl">
|
||||
<form @submit.prevent="handleLogin" class="space-y-6">
|
||||
<!-- 用户名输入框 -->
|
||||
<div>
|
||||
<label for="username" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
用户名
|
||||
</label>
|
||||
<input
|
||||
id="username"
|
||||
v-model="loginForm.username"
|
||||
type="text"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入用户名"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
密码
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 记住我 -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
id="remember-me"
|
||||
v-model="loginForm.rememberMe"
|
||||
type="checkbox"
|
||||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-white/20 rounded bg-white/10"
|
||||
/>
|
||||
<label for="remember-me" class="ml-2 block text-sm text-slate-200">
|
||||
记住我
|
||||
</label>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<button
|
||||
type="button"
|
||||
@click="handleForgotPassword"
|
||||
class="text-slate-300 hover:text-white transition-colors"
|
||||
>
|
||||
忘记密码?
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="authStore.loading"
|
||||
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
>
|
||||
<span v-if="authStore.loading" class="flex items-center justify-center">
|
||||
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
登录中...
|
||||
</span>
|
||||
<span v-else>登录</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useToast } from 'vue-toastification'
|
||||
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const toast = useToast()
|
||||
|
||||
// 登录表单数据
|
||||
const loginForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
rememberMe: false
|
||||
})
|
||||
|
||||
// 登录处理函数
|
||||
const handleLogin = async () => {
|
||||
if (!loginForm.username || !loginForm.password) {
|
||||
toast.error('请填写完整的登录信息')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await authStore.login({
|
||||
username: loginForm.username,
|
||||
password: loginForm.password
|
||||
})
|
||||
|
||||
// 如果选择记住我,保存登录信息到本地存储
|
||||
if (loginForm.rememberMe) {
|
||||
localStorage.setItem('rememberedUser', JSON.stringify({
|
||||
username: loginForm.username,
|
||||
password: loginForm.password
|
||||
}))
|
||||
} else {
|
||||
localStorage.removeItem('rememberedUser')
|
||||
}
|
||||
|
||||
router.push('/dashboard')
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
// 根据不同的错误类型显示不同的错误信息
|
||||
if (error.response?.status === 401) {
|
||||
const errorMessage = error.response?.data?.error || '用户名或密码错误'
|
||||
const remainingAttempts = error.response?.data?.remainingAttempts
|
||||
|
||||
if (errorMessage.includes('锁定')) {
|
||||
toast.error(errorMessage)
|
||||
} else if (errorMessage.includes('禁用') || errorMessage.includes('inactive')) {
|
||||
toast.error('您的账户尚未激活,请联系管理员激活账户')
|
||||
} else {
|
||||
if (remainingAttempts !== undefined) {
|
||||
toast.error(`用户名或密码错误,还剩${remainingAttempts}次尝试机会`)
|
||||
} else {
|
||||
toast.error('用户名或密码错误,请检查后重试')
|
||||
}
|
||||
}
|
||||
} else if (error.response?.status === 400) {
|
||||
toast.error(error.response?.data?.message || '请求参数错误')
|
||||
} else if (error.response?.status === 500) {
|
||||
toast.error('服务器内部错误,请稍后重试')
|
||||
} else if (error.code === 'NETWORK_ERROR') {
|
||||
toast.error('网络连接失败,请检查网络连接')
|
||||
} else {
|
||||
toast.error(error.response?.data?.message || '登录失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 忘记密码处理函数
|
||||
const handleForgotPassword = () => {
|
||||
toast.info('请联系管理员')
|
||||
}
|
||||
|
||||
// 页面加载时检查是否有记住的登录信息
|
||||
const loadRememberedUser = () => {
|
||||
const remembered = localStorage.getItem('rememberedUser')
|
||||
if (remembered) {
|
||||
try {
|
||||
const userData = JSON.parse(remembered)
|
||||
loginForm.username = userData.username || ''
|
||||
loginForm.rememberMe = true
|
||||
} catch (error) {
|
||||
console.error('解析记住的用户信息失败:', error)
|
||||
localStorage.removeItem('rememberedUser')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 页面挂载时初始化
|
||||
onMounted(() => {
|
||||
loadRememberedUser()
|
||||
})
|
||||
</script>
|
||||
148
frontend/src/components/RegisterForm.vue
Normal file
148
frontend/src/components/RegisterForm.vue
Normal file
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div class="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20 shadow-2xl">
|
||||
<form @submit.prevent="handleRegister" class="space-y-6">
|
||||
<!-- 用户名输入框 -->
|
||||
<div>
|
||||
<label for="regUsername" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
用户名
|
||||
</label>
|
||||
<input
|
||||
id="regUsername"
|
||||
v-model="registerForm.username"
|
||||
type="text"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入用户名"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<div>
|
||||
<label for="regPassword" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
密码
|
||||
</label>
|
||||
<input
|
||||
id="regPassword"
|
||||
v-model="registerForm.password"
|
||||
type="password"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 确认密码输入框 -->
|
||||
<div>
|
||||
<label for="confirmPassword" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
确认密码
|
||||
</label>
|
||||
<input
|
||||
id="confirmPassword"
|
||||
v-model="registerForm.confirmPassword"
|
||||
type="password"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请再次输入密码"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="authStore.loading"
|
||||
class="w-full bg-gradient-to-r from-green-600 to-blue-600 hover:from-green-700 hover:to-blue-700 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 focus:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
|
||||
>
|
||||
<span v-if="authStore.loading" class="flex items-center justify-center">
|
||||
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
注册中...
|
||||
</span>
|
||||
<span v-else>注册</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, defineEmits } from 'vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useToast } from 'vue-toastification'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const toast = useToast()
|
||||
const emit = defineEmits(['registered'])
|
||||
|
||||
// 注册表单数据
|
||||
const registerForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
})
|
||||
|
||||
// 注册处理函数
|
||||
const handleRegister = async () => {
|
||||
if (!registerForm.username || !registerForm.password || !registerForm.confirmPassword) {
|
||||
toast.error('请填写完整的注册信息')
|
||||
return
|
||||
}
|
||||
// 验证用户名格式
|
||||
if (!/^[a-zA-Z0-9_]+$/.test(registerForm.username)) {
|
||||
toast.error('用户名只能包含字母、数字和下划线')
|
||||
return
|
||||
}
|
||||
// 验证用户名长度
|
||||
if (registerForm.username.length < 3 || registerForm.username.length > 30) {
|
||||
toast.error('用户名长度必须在3-30个字符之间')
|
||||
return
|
||||
}
|
||||
// 验证密码长度
|
||||
if (registerForm.password.length < 8) {
|
||||
toast.error('密码长度至少8个字符')
|
||||
return
|
||||
}
|
||||
if (registerForm.password !== registerForm.confirmPassword) {
|
||||
toast.error('两次输入的密码不一致')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await authStore.register({
|
||||
username: registerForm.username,
|
||||
password: registerForm.password,
|
||||
confirmPassword: registerForm.confirmPassword
|
||||
})
|
||||
|
||||
toast.success('注册成功!请等待管理员激活您的账户。')
|
||||
|
||||
// 注册成功时清空注册表单
|
||||
registerForm.username = ''
|
||||
registerForm.password = ''
|
||||
registerForm.confirmPassword = ''
|
||||
|
||||
emit('registered')
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('注册错误详情:', error)
|
||||
console.error('错误响应:', error.response.data.error)
|
||||
|
||||
// 根据不同的错误类型显示不同的错误信息
|
||||
if (error.response?.status === 400) {
|
||||
const details = error.response?.data?.error
|
||||
if (details) {
|
||||
// 显示具体的验证错误信息
|
||||
const errorMessages = details
|
||||
toast.error(`注册失败: ${errorMessages}`)
|
||||
}
|
||||
} else if (error.response?.status === 409) {
|
||||
toast.error('用户名已存在,请使用其他信息')
|
||||
} else if (error.response?.status === 500) {
|
||||
toast.error('服务器内部错误,请稍后重试')
|
||||
} else if (error.code === 'NETWORK_ERROR') {
|
||||
toast.error('网络连接失败,请检查网络连接')
|
||||
} else {
|
||||
toast.error(error.response?.data?.message || '注册失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -53,145 +53,10 @@
|
||||
</div>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<div v-if="currentMode === 'login'" class="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20 shadow-2xl">
|
||||
<form @submit.prevent="handleLogin" class="space-y-6">
|
||||
<!-- 用户名输入框 -->
|
||||
<div>
|
||||
<label for="username" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
用户名
|
||||
</label>
|
||||
<input
|
||||
id="username"
|
||||
v-model="loginForm.username"
|
||||
type="text"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入用户名"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
密码
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 记住我 -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
id="remember-me"
|
||||
v-model="loginForm.rememberMe"
|
||||
type="checkbox"
|
||||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-white/20 rounded bg-white/10"
|
||||
/>
|
||||
<label for="remember-me" class="ml-2 block text-sm text-slate-200">
|
||||
记住我
|
||||
</label>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<button
|
||||
type="button"
|
||||
@click="handleForgotPassword"
|
||||
class="text-slate-300 hover:text-white transition-colors"
|
||||
>
|
||||
忘记密码?
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="authStore.loading"
|
||||
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
>
|
||||
<span v-if="authStore.loading" class="flex items-center justify-center">
|
||||
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
登录中...
|
||||
</span>
|
||||
<span v-else>登录</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<LoginForm v-if="currentMode === 'login'" />
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<div v-if="currentMode === 'register'" class="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20 shadow-2xl">
|
||||
<form @submit.prevent="handleRegister" class="space-y-6">
|
||||
<!-- 用户名输入框 -->
|
||||
<div>
|
||||
<label for="regUsername" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
用户名
|
||||
</label>
|
||||
<input
|
||||
id="regUsername"
|
||||
v-model="registerForm.username"
|
||||
type="text"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入用户名"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<div>
|
||||
<label for="regPassword" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
密码
|
||||
</label>
|
||||
<input
|
||||
id="regPassword"
|
||||
v-model="registerForm.password"
|
||||
type="password"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 确认密码输入框 -->
|
||||
<div>
|
||||
<label for="confirmPassword" class="block text-sm font-medium text-slate-200 mb-2">
|
||||
确认密码
|
||||
</label>
|
||||
<input
|
||||
id="confirmPassword"
|
||||
v-model="registerForm.confirmPassword"
|
||||
type="password"
|
||||
required
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-slate-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||
placeholder="请再次输入密码"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="authStore.loading"
|
||||
class="w-full bg-gradient-to-r from-green-600 to-blue-600 hover:from-green-700 hover:to-blue-700 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 focus:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
|
||||
>
|
||||
<span v-if="authStore.loading" class="flex items-center justify-center">
|
||||
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
注册中...
|
||||
</span>
|
||||
<span v-else>注册</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<RegisterForm v-if="currentMode === 'register'" @registered="switchToLogin" />
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<div v-if="authStore.error" class="mt-4 p-3 bg-red-500/20 border border-red-500/30 rounded-lg">
|
||||
@@ -208,184 +73,31 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, defineAsyncComponent } from 'vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import LoginForm from '@/components/LoginForm.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const toast = useToast()
|
||||
|
||||
const RegisterForm = defineAsyncComponent(() => import('@/components/RegisterForm.vue'))
|
||||
|
||||
// 当前模式:login 或 register
|
||||
const currentMode = ref<'login' | 'register'>('login')
|
||||
|
||||
// 成功消息
|
||||
const successMessage = ref('')
|
||||
|
||||
// 登录表单数据
|
||||
const loginForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
rememberMe: false
|
||||
})
|
||||
|
||||
// 注册表单数据
|
||||
const registerForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
})
|
||||
|
||||
// 登录处理函数
|
||||
const handleLogin = async () => {
|
||||
if (!loginForm.username || !loginForm.password) {
|
||||
toast.error('请填写完整的登录信息')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await authStore.login({
|
||||
username: loginForm.username,
|
||||
password: loginForm.password
|
||||
})
|
||||
|
||||
// 如果选择记住我,保存登录信息到本地存储
|
||||
if (loginForm.rememberMe) {
|
||||
localStorage.setItem('rememberedUser', JSON.stringify({
|
||||
username: loginForm.username,
|
||||
password: loginForm.password
|
||||
}))
|
||||
} else {
|
||||
localStorage.removeItem('rememberedUser')
|
||||
}
|
||||
|
||||
router.push('/dashboard')
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
// 根据不同的错误类型显示不同的错误信息
|
||||
if (error.response?.status === 401) {
|
||||
const errorMessage = error.response?.data?.error || '用户名或密码错误'
|
||||
const remainingAttempts = error.response?.data?.remainingAttempts
|
||||
|
||||
if (errorMessage.includes('锁定')) {
|
||||
toast.error(errorMessage)
|
||||
} else if (errorMessage.includes('禁用') || errorMessage.includes('inactive')) {
|
||||
toast.error('您的账户尚未激活,请联系管理员激活账户')
|
||||
} else {
|
||||
if (remainingAttempts !== undefined) {
|
||||
toast.error(`用户名或密码错误,还剩${remainingAttempts}次尝试机会`)
|
||||
} else {
|
||||
toast.error('用户名或密码错误,请检查后重试')
|
||||
}
|
||||
}
|
||||
} else if (error.response?.status === 400) {
|
||||
toast.error(error.response?.data?.message || '请求参数错误')
|
||||
} else if (error.response?.status === 500) {
|
||||
toast.error('服务器内部错误,请稍后重试')
|
||||
} else if (error.code === 'NETWORK_ERROR') {
|
||||
toast.error('网络连接失败,请检查网络连接')
|
||||
} else {
|
||||
toast.error(error.response?.data?.message || '登录失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册处理函数
|
||||
const handleRegister = async () => {
|
||||
if (!registerForm.username || !registerForm.password || !registerForm.confirmPassword) {
|
||||
toast.error('请填写完整的注册信息')
|
||||
return
|
||||
}
|
||||
|
||||
// 验证用户名格式
|
||||
if (!/^[a-zA-Z0-9_]+$/.test(registerForm.username)) {
|
||||
toast.error('用户名只能包含字母、数字和下划线')
|
||||
return
|
||||
}
|
||||
|
||||
// 验证用户名长度
|
||||
if (registerForm.username.length < 3 || registerForm.username.length > 30) {
|
||||
toast.error('用户名长度必须在3-30个字符之间')
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码长度
|
||||
if (registerForm.password.length < 8) {
|
||||
toast.error('密码长度至少8个字符')
|
||||
return
|
||||
}
|
||||
|
||||
if (registerForm.password !== registerForm.confirmPassword) {
|
||||
toast.error('两次输入的密码不一致')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await authStore.register({
|
||||
username: registerForm.username,
|
||||
password: registerForm.password,
|
||||
confirmPassword: registerForm.confirmPassword
|
||||
})
|
||||
|
||||
successMessage.value = '注册成功!您的账户已创建,请等待管理员激活后即可登录。'
|
||||
toast.success('注册成功!请等待管理员激活您的账户。')
|
||||
|
||||
// 注册成功时清空注册表单
|
||||
registerForm.username = ''
|
||||
registerForm.password = ''
|
||||
registerForm.confirmPassword = ''
|
||||
|
||||
// 切换到登录模式
|
||||
const switchToLogin = () => {
|
||||
currentMode.value = 'login'
|
||||
} catch (error: any) {
|
||||
console.error('注册错误详情:', error)
|
||||
console.error('错误响应:', error.response.data.error)
|
||||
|
||||
// 根据不同的错误类型显示不同的错误信息
|
||||
if (error.response?.status === 400) {
|
||||
const details = error.response?.data?.error
|
||||
if (details) {
|
||||
// 显示具体的验证错误信息
|
||||
const errorMessages = details
|
||||
toast.error(`注册失败: ${errorMessages}`)
|
||||
}
|
||||
} else if (error.response?.status === 409) {
|
||||
toast.error('用户名已存在,请使用其他信息')
|
||||
} else if (error.response?.status === 500) {
|
||||
toast.error('服务器内部错误,请稍后重试')
|
||||
} else if (error.code === 'NETWORK_ERROR') {
|
||||
toast.error('网络连接失败,请检查网络连接')
|
||||
} else {
|
||||
toast.error(error.response?.data?.message || '注册失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
successMessage.value = '注册成功!您的账户已创建,请等待管理员激活后即可登录。'
|
||||
}
|
||||
|
||||
// 忘记密码处理函数
|
||||
const handleForgotPassword = () => {
|
||||
toast.info('请联系管理员')
|
||||
}
|
||||
|
||||
// 页面加载时检查是否有记住的登录信息
|
||||
const loadRememberedUser = () => {
|
||||
const remembered = localStorage.getItem('rememberedUser')
|
||||
if (remembered) {
|
||||
try {
|
||||
const userData = JSON.parse(remembered)
|
||||
loginForm.username = userData.username || ''
|
||||
loginForm.rememberMe = true
|
||||
} catch (error) {
|
||||
console.error('解析记住的用户信息失败:', error)
|
||||
localStorage.removeItem('rememberedUser')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 页面挂载时初始化
|
||||
onMounted(() => {
|
||||
loadRememberedUser()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user