Files
realizemultiagent/shared/code/frontend/Login.vue
2026-04-02 00:59:42 +08:00

281 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 登录页面组件 - 前端代码 -->
<!-- 文件位置: shared/code/frontend/Login.vue -->
<!-- 创建时间: 2026-03-31 20:57 -->
<!-- 开发者: 前端工程师 (FE) -->
<template>
<div class="login-container">
<div class="login-card">
<h2 class="login-title">用户登录</h2>
<form @submit.prevent="handleLogin" class="login-form">
<div class="form-group">
<label for="username">用户名</label>
<input
id="username"
v-model="form.username"
type="text"
placeholder="请输入用户名"
required
:disabled="loading"
/>
</div>
<div class="form-group">
<label for="password">密码</label>
<input
id="password"
v-model="form.password"
type="password"
placeholder="请输入密码"
required
:disabled="loading"
/>
</div>
<div class="form-group">
<label for="captcha">验证码</label>
<div class="captcha-container">
<input
id="captcha"
v-model="form.captcha"
type="text"
placeholder="请输入验证码"
required
:disabled="loading"
/>
<img
:src="captchaImage"
alt="验证码"
class="captcha-image"
@click="refreshCaptcha"
/>
</div>
</div>
<div class="form-options">
<label class="remember-me">
<input type="checkbox" v-model="form.rememberMe" />
记住我
</label>
<a href="#" class="forgot-password">忘记密码</a>
</div>
<button
type="submit"
class="login-button"
:disabled="loading"
:class="{ 'loading': loading }"
>
{{ loading ? '登录中...' : '登录' }}
</button>
<div class="register-link">
还没有账号<a href="/register">立即注册</a>
</div>
</form>
<!-- 错误提示 -->
<div v-if="error" class="error-message">
{{ error }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'LoginPage',
data() {
return {
form: {
username: '',
password: '',
captcha: '',
rememberMe: false
},
captchaImage: '/api/captcha',
loading: false,
error: ''
};
},
methods: {
async handleLogin() {
this.loading = true;
this.error = '';
try {
const response = await this.$axios.post('/api/auth/login', this.form);
if (response.data.success) {
// 保存token
localStorage.setItem('token', response.data.token);
localStorage.setItem('user', JSON.stringify(response.data.user));
// 跳转到首页
this.$router.push('/dashboard');
// 显示成功消息
this.$notify({
title: '登录成功',
message: '欢迎回来!',
type: 'success'
});
} else {
this.error = response.data.error || '登录失败';
}
} catch (error) {
console.error('Login error:', error);
this.error = error.response?.data?.error || '网络错误,请稍后重试';
} finally {
this.loading = false;
}
},
refreshCaptcha() {
this.captchaImage = `/api/captcha?t=${Date.now()}`;
this.form.captcha = '';
}
},
mounted() {
// 页面加载时刷新验证码
this.refreshCaptcha();
}
};
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-card {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 400px;
}
.login-title {
text-align: center;
margin-bottom: 30px;
color: #333;
font-size: 24px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
color: #555;
font-weight: 500;
}
.form-group input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
transition: border-color 0.3s;
}
.form-group input:focus {
outline: none;
border-color: #667eea;
}
.captcha-container {
display: flex;
gap: 10px;
}
.captcha-image {
height: 40px;
border-radius: 5px;
cursor: pointer;
border: 1px solid #ddd;
}
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.remember-me {
display: flex;
align-items: center;
gap: 5px;
color: #555;
}
.forgot-password {
color: #667eea;
text-decoration: none;
}
.forgot-password:hover {
text-decoration: underline;
}
.login-button {
width: 100%;
padding: 12px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background 0.3s;
}
.login-button:hover:not(:disabled) {
background: #5a67d8;
}
.login-button:disabled {
background: #a0aec0;
cursor: not-allowed;
}
.login-button.loading {
position: relative;
}
.register-link {
text-align: center;
margin-top: 20px;
color: #666;
}
.register-link a {
color: #667eea;
text-decoration: none;
}
.register-link a:hover {
text-decoration: underline;
}
.error-message {
margin-top: 15px;
padding: 10px;
background: #fed7d7;
color: #c53030;
border-radius: 5px;
text-align: center;
}
</style>