Files
xinfra/frontend/src/views/auth/Login.vue
T
wonder f1a63ee473 feat(frontend): 支持深色/浅色模式切换,统一主题变量体系
- 新增 useTheme composable,支持 light/dark 双主题,默认浅色模式
- 主题偏好持久化到 localStorage,支持跟随系统主题
- AppHeader 顶栏添加 Moon/Sunny 切换图标,带旋转过渡动效
- variables.css 重构为 :root(浅色)/:root.dark(深色)双套变量
- 新增标签色系(蓝/紫/琥珀/绿)、节点色系、阴影、发光效果等语义化变量
- 全组件硬编码颜色替换为 CSS 变量,消除跨主题不一致
- global.css 添加主题切换过渡动画(background/border/box-shadow)
- 涉及组件:AppHeader、AppSidebar、SubsystemCard、AuditLogTable
- 涉及页面:Dashboard、Resource、Cluster、Config、Task、Service、Login
2026-07-15 14:38:58 +08:00

199 lines
4.1 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.
<template>
<div class="login-container">
<div class="login-card">
<div class="login-header">
<div class="brand">
<div class="mark">xi</div>
xinfra
</div>
<h2>统一基础设施平台</h2>
<p>LDAP 账号登录</p>
</div>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-position="top"
@submit.prevent="handleLogin"
>
<el-form-item label="用户名" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
prefix-icon="User"
size="large"
/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="form.password"
type="password"
placeholder="请输入密码"
prefix-icon="Lock"
size="large"
show-password
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
size="large"
:loading="loading"
@click="handleLogin"
style="width: 100%"
>
登录
</el-button>
</el-form-item>
</el-form>
<div class="login-footer">
<p>统一 LDAP 账号,同账号同密码</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { useAuth } from '@/composables/useAuth'
import { ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
const router = useRouter()
const { login } = useAuth()
const formRef = ref<FormInstance>()
const loading = ref(false)
const form = reactive({
username: '',
password: '',
})
const rules: FormRules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
}
const handleLogin = async () => {
const valid = await formRef.value?.validate().catch(() => false)
if (!valid) return
loading.value = true
try {
await login(form.username, form.password)
ElMessage.success('登录成功')
router.push('/')
} catch {
// 错误已由 request 拦截器统一处理
} finally {
loading.value = false
}
}
</script>
<style scoped>
.login-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--bg-deep);
}
.login-card {
width: 400px;
background: var(--bg-panel);
border: 1px solid var(--line);
border-radius: 12px;
padding: 40px;
}
.login-header {
text-align: center;
margin-bottom: 32px;
}
.login-header .brand {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
font-size: 24px;
font-weight: 700;
margin-bottom: 12px;
}
.login-header .brand .mark {
width: 36px;
height: 36px;
border-radius: 8px;
background: linear-gradient(135deg, var(--accent), #1C8F69);
display: flex;
align-items: center;
justify-content: center;
font-family: var(--mono);
font-size: 16px;
font-weight: 600;
color: var(--bg-deep);
}
.login-header h2 {
margin: 0 0 8px;
font-size: 18px;
font-weight: 600;
}
.login-header p {
margin: 0;
color: var(--text-dim);
font-size: 14px;
}
.login-footer {
text-align: center;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--line-soft);
}
.login-footer p {
margin: 0;
color: var(--text-dim);
font-size: 12px;
}
:deep(.el-form-item__label) {
color: var(--text-mid);
}
:deep(.el-input__wrapper) {
background: var(--bg-panel-2);
border: 1px solid var(--line);
box-shadow: none;
}
:deep(.el-input__wrapper:hover) {
border-color: var(--hover-border);
}
:deep(.el-input__wrapper.is-focus) {
border-color: var(--accent);
}
:deep(.el-input__inner) {
color: var(--text-hi);
}
:deep(.el-button--primary) {
background: var(--accent);
border-color: var(--accent);
color: var(--bg-deep);
font-weight: 600;
}
:deep(.el-button--primary:hover) {
opacity: 0.9;
}
</style>