feat(global-header): 重构全局头部组件及样式优化
- 完全重写 GlobalHeader 组件结构,改用 div 语义及自定义样式替代原antd a-menu - 新增 Logo 区域包含图标和标题,支持点击跳转首页功能 - 实现导航菜单动态渲染,根据路由权限过滤显示 - 用户区域支持未登录和已登录两种状态切换 - 未登录时展示登录、注册按钮,支持路由跳转 - 已登录时显示用户头像、用户名及下拉菜单,包含个人中心、设置和退出登录操作 - 引入 Arco Design 图标组件优化视觉表现 - 完善登出流程,清理本地Token并提示用户 - 优化响应式布局和交互体验,提升用户界面整体一致性与可用性
This commit is contained in:
@@ -1,41 +1,211 @@
|
||||
<template>
|
||||
<div id="userLoginView">
|
||||
<h2 style="margin-bottom: 16px">用户登录</h2>
|
||||
<a-form
|
||||
style="max-width: 480px; margin: 0 auto"
|
||||
label-align="left"
|
||||
auto-label-width
|
||||
:model="form"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<a-form-item field="userAccount" label="账号">
|
||||
<a-input v-model="form.userAccount" placeholder="请输入账号" />
|
||||
</a-form-item>
|
||||
<a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码">
|
||||
<a-input-password
|
||||
v-model="form.userPassword"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" html-type="submit" style="width: 120px">
|
||||
登录
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<h2 class="login-title">欢迎登录 AI OJ</h2>
|
||||
<p class="login-subtitle">AI Online Judge By MeowRain</p>
|
||||
|
||||
<a-form
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
@submit="handleSubmit"
|
||||
layout="vertical"
|
||||
class="login-form"
|
||||
>
|
||||
<a-form-item field="userAccount" label="账号" validate-trigger="blur">
|
||||
<a-input
|
||||
v-model="form.userAccount"
|
||||
placeholder="请输入账号"
|
||||
size="large"
|
||||
allow-clear
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-user />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item field="userPassword" label="密码" validate-trigger="blur">
|
||||
<a-input-password
|
||||
v-model="form.userPassword"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
allow-clear
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-lock />
|
||||
</template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<div class="form-actions">
|
||||
<a-checkbox v-model="rememberMe">记住我</a-checkbox>
|
||||
<a-link>忘记密码?</a-link>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
long
|
||||
size="large"
|
||||
:loading="loading"
|
||||
>
|
||||
登录
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<div class="register-link">
|
||||
还没有账号?
|
||||
<a-link @click="goToRegister">立即注册</a-link>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import { reactive, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Message } from "@arco-design/web-vue";
|
||||
import { IconUser, IconLock } from "@arco-design/web-vue/es/icon";
|
||||
import { login } from "@/api/auth";
|
||||
import { setTokens } from "@/utils/token";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import ACCESS_ENUM from "@/access/accessEnum";
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const form = reactive({
|
||||
userAccount: "",
|
||||
userPassword: "",
|
||||
});
|
||||
|
||||
const handleSubmit = async () => {
|
||||
console.log(form);
|
||||
const rules = {
|
||||
userAccount: [
|
||||
{ required: true, message: "请输入账号" },
|
||||
{ minLength: 4, message: "账号不能少于4位" },
|
||||
],
|
||||
userPassword: [
|
||||
{ required: true, message: "请输入密码" },
|
||||
{ minLength: 8, message: "密码不能少于8位" },
|
||||
],
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
const rememberMe = ref(false);
|
||||
|
||||
const handleSubmit = async (data: any) => {
|
||||
if (data.errors) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await login({
|
||||
userAccount: form.userAccount,
|
||||
userPassword: form.userPassword,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
Message.success("登录成功!");
|
||||
|
||||
// 存储 token
|
||||
setTokens(response.data.accessToken, response.data.refreshToken);
|
||||
|
||||
// 更新用户状态
|
||||
userStore.updateUserLoginStatus({
|
||||
userName: response.data.userAccount,
|
||||
userRole: ACCESS_ENUM.USER,
|
||||
});
|
||||
|
||||
// 跳转到首页
|
||||
router.push("/home");
|
||||
} else {
|
||||
Message.error(response.message || "登录失败");
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("登录失败:", error);
|
||||
Message.error(error.response?.data?.message || "登录失败,请稍后重试");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const goToRegister = () => {
|
||||
router.push("/user/register");
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#userLoginView {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.login-title {
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.login-subtitle {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #86909c;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
:deep(.arco-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
:deep(.arco-form-item-label-col) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
:deep(.arco-form-item-label) {
|
||||
font-weight: 500;
|
||||
color: #1d2129;
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.register-link {
|
||||
text-align: center;
|
||||
color: #86909c;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user