Files
X-Agents/web/src/views/Login.vue

181 lines
7.3 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useAuth } from '@/composables/useAuth'
const router = useRouter()
const route = useRoute()
const { login } = useAuth()
// 表单数据
const username = ref('')
const password = ref('')
const rememberMe = ref(false)
const isLoading = ref(false)
const showPassword = ref(false)
const errorMsg = ref('')
const successMsg = ref('')
// 检查是否从注册页跳转过来
onMounted(() => {
if (route.query.registered === 'true') {
successMsg.value = 'Account created successfully! Please sign in.'
}
})
// 登录处理
const handleLogin = async () => {
errorMsg.value = ''
if (!username.value || !password.value) {
errorMsg.value = 'Please enter username and password'
return
}
isLoading.value = true
try {
await login({
username: username.value,
password: password.value,
})
// 登录成功,跳转到 Dashboard
router.push('/chat')
} catch (error: any) {
errorMsg.value = error.message || 'Login failed, please check your credentials'
} finally {
isLoading.value = false
}
}
</script>
<template>
<div class="min-h-screen bg-dark-900 flex items-center justify-center p-4">
<!-- 背景装饰 -->
<div class="absolute inset-0 overflow-hidden">
<div class="absolute top-1/4 -left-20 w-80 h-80 bg-primary-orange/10 rounded-full blur-3xl"></div>
<div class="absolute bottom-1/4 -right-20 w-80 h-80 bg-primary-purple/10 rounded-full blur-3xl"></div>
</div>
<!-- 登录卡片 -->
<div class="w-full max-w-md relative">
<!-- Logo -->
<div class="text-center mb-8">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-primary-orange to-red-500 flex items-center justify-center mx-auto mb-4 shadow-lg shadow-primary-orange/20">
<i class="fa-solid fa-basketball text-white text-2xl"></i>
</div>
<h1 class="text-2xl font-bold text-white">Welcome back</h1>
<p class="text-gray-400 mt-2">Sign in to your account to continue</p>
</div>
<!-- 登录表单 -->
<div class="bg-dark-700 rounded-2xl p-8 shadow-xl border border-dark-500/50">
<!-- 成功提示 -->
<div v-if="successMsg" class="mb-4 p-3 bg-green-500/10 border border-green-500/30 rounded-lg text-green-400 text-sm flex items-center gap-2">
<i class="fa-solid fa-check-circle"></i>
{{ successMsg }}
</div>
<!-- 错误提示 -->
<div v-if="errorMsg" class="mb-4 p-3 bg-red-500/10 border border-red-500/30 rounded-lg text-red-400 text-sm flex items-center gap-2">
<i class="fa-solid fa-circle-exclamation"></i>
{{ errorMsg }}
</div>
<form @submit.prevent="handleLogin" class="space-y-5">
<!-- 用户名 -->
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">Username</label>
<div class="relative">
<i class="fa-solid fa-user absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input
v-model="username"
type="text"
placeholder="Enter username (admin)"
required
class="w-full bg-dark-600 border border-dark-500 rounded-xl py-3 pl-12 pr-4 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange focus:ring-1 focus:ring-primary-orange transition-colors"
>
</div>
</div>
<!-- 密码 -->
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">Password</label>
<div class="relative">
<i class="fa-solid fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input
v-model="password"
:type="showPassword ? 'text' : 'password'"
placeholder="Enter your password"
required
class="w-full bg-dark-600 border border-dark-500 rounded-xl py-3 pl-12 pr-12 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange focus:ring-1 focus:ring-primary-orange transition-colors"
>
<button
type="button"
@click="showPassword = !showPassword"
class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-300 transition-colors"
>
<i :class="['fa-solid', showPassword ? 'fa-eye-slash' : 'fa-eye']"></i>
</button>
</div>
</div>
<!-- 记住我 & 忘记密码 -->
<div class="flex items-center justify-between">
<label class="flex items-center cursor-pointer">
<input
v-model="rememberMe"
type="checkbox"
class="sr-only peer"
>
<div class="w-5 h-5 border-2 border-dark-400 rounded-md peer-checked:border-primary-orange peer-checked:bg-primary-orange transition-colors flex items-center justify-center">
<i v-if="rememberMe" class="fa-solid fa-check text-white text-xs"></i>
</div>
<span class="ml-2 text-sm text-gray-400">Remember me</span>
</label>
<a href="#" class="text-sm text-primary-orange hover:text-orange-400 transition-colors">Forgot password?</a>
</div>
<!-- 登录按钮 -->
<button
type="submit"
:disabled="isLoading"
class="w-full bg-gradient-to-r from-primary-orange to-red-500 hover:from-orange-500 hover:to-red-600 text-white font-semibold py-3 rounded-xl transition-all duration-300 shadow-lg shadow-primary-orange/20 hover:shadow-primary-orange/40 flex items-center justify-center gap-2 disabled:opacity-70 disabled:cursor-not-allowed"
>
<i v-if="isLoading" class="fa-solid fa-circle-notch fa-spin"></i>
<span>{{ isLoading ? 'Signing in...' : 'Sign in' }}</span>
</button>
</form>
<!-- 分割线 -->
<div class="relative my-6">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-dark-500"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-4 bg-dark-700 text-gray-500">Or continue with</span>
</div>
</div>
<!-- 第三方登录 -->
<div class="grid grid-cols-2 gap-3">
<button class="flex items-center justify-center gap-2 bg-dark-600 hover:bg-dark-500 border border-dark-500 rounded-xl py-2.5 text-gray-300 font-medium transition-colors">
<i class="fa-brands fa-google"></i>
<span>Google</span>
</button>
<button class="flex items-center justify-center gap-2 bg-dark-600 hover:bg-dark-500 border border-dark-500 rounded-xl py-2.5 text-gray-300 font-medium transition-colors">
<i class="fa-brands fa-github"></i>
<span>GitHub</span>
</button>
</div>
</div>
<!-- 注册链接 -->
<p class="text-center mt-6 text-gray-400">
Don't have an account?
<a @click="router.push('/signup')" class="text-primary-orange hover:text-orange-400 font-medium transition-colors cursor-pointer">Sign up</a>
</p>
</div>
</div>
</template>