feat: update login page localization and enhance UI elements for better user experience

This commit is contained in:
jie committed 2026-03-13 13:46:07 +08:00
1 parent ce410666d9
commit c2204adf0c
2 files changed
+177 -59

No files matched your search

+2 -2
View File
@@ -31,8 +31,8 @@
"uptime": "可用率",
"support": "全天支持"
},
"welcomeTitle": "欢迎回来",
"welcomeSubtitle": "登录您的账户以继续",
"welcomeTitle": "授权管理平台",
"welcomeSubtitle": "登录您的账户",
"copyright": "© 2025 Cedar-V. 保留所有权利。"
},
"sidebar": {
+175 -57
View File
@@ -21,7 +21,7 @@
<!-- 品牌标识 -->
<div class="brand-header">
<div class="brand-logo">
<svg width="32" height="31" viewBox="0 0 54 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="48" height="48" viewBox="0 0 54 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.3125 11.4814L22.25 19.5947V22.7148L27.1191 13.0576L29.7393 18.1777L18.7988 40H0L13.5938 22.8037H14L13.8125 23.1201L7.46875 33.541H17.8438V16.9111L7.1875 25.6475L18.0312 10.1406L11.625 14.4463V14.2588L20.4375 0L26.3125 11.4814Z" fill="#ffffff"/>
<path d="M34.5498 39.9996H28.75L24.5938 32.8864L27.125 27.6246L34.5498 39.9996ZM41 39.9996H36.2705L27.9346 25.941L30.7188 20.1559L41 39.9996Z" fill="rgba(255,255,255,0.7)"/>
</svg>
@@ -76,7 +76,6 @@
:rules="loginRules"
@submit.prevent="handleLogin"
class="login-form"
size="large"
>
<el-form-item prop="username">
<el-input
@@ -84,7 +83,9 @@
:placeholder="t('login.usernamePlaceholder')"
:prefix-icon="User"
clearable
class="login-input"
:class="['login-input', { 'is-field-valid': fieldStatus.username }]"
size="large"
@blur="validateFieldOnBlur('username')"
/>
</el-form-item>
@@ -96,7 +97,9 @@
:prefix-icon="Lock"
show-password
clearable
class="login-input"
:class="['login-input', { 'is-field-valid': fieldStatus.password }]"
size="large"
@blur="validateFieldOnBlur('password')"
@keyup.enter="handleLogin"
/>
</el-form-item>
@@ -138,7 +141,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, onUnmounted } from 'vue'
import { ref, reactive, watch, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
@@ -166,6 +169,27 @@ const loginForm = reactive({
const rememberMe = ref(false)
const fieldStatus = reactive({
username: false,
password: false
})
watch(() => loginForm.username, (val) => { if (!val) fieldStatus.username = false })
watch(() => loginForm.password, (val) => { if (!val) fieldStatus.password = false })
async function validateFieldOnBlur(field: 'username' | 'password') {
if (!loginForm[field]) {
fieldStatus[field] = false
return
}
try {
await loginFormRef.value?.validateField(field)
fieldStatus[field] = true
} catch {
fieldStatus[field] = false
}
}
const loginRules: FormRules = {
username: [
{ required: true, message: () => t('login.error.usernameRequired'), trigger: 'blur' },
@@ -558,24 +582,24 @@ $phi-inv: 38.2%;
}
.wave-1 {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%23ffffff' fill-opacity='0.15' d='M0,160L48,176C96,192,192,224,288,213.3C384,203,480,149,576,138.7C672,128,768,160,864,181.3C960,203,1056,213,1152,192C1248,171,1344,117,1392,90.7L1440,64L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'%3E%3C/path%3E%3C/svg%3E");
animation: waveMove 18s linear infinite;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320' preserveAspectRatio='none'%3E%3Cpath fill='%23ffffff' fill-opacity='0.15' d='M0,192 C240,256 480,128 720,192 C960,256 1200,128 1440,192 L1440,320 L0,320 Z'%3E%3C/path%3E%3C/svg%3E");
animation: waveMove 12s linear infinite;
height: 240px;
:global([data-theme='dark']) & {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%2300ffc8' fill-opacity='0.12' d='M0,160L48,176C96,192,192,224,288,213.3C384,203,480,149,576,138.7C672,128,768,160,864,181.3C960,203,1056,213,1152,192C1248,171,1344,117,1392,90.7L1440,64L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'%3E%3C/path%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320' preserveAspectRatio='none'%3E%3Cpath fill='%2300ffc8' fill-opacity='0.12' d='M0,192 C240,256 480,128 720,192 C960,256 1200,128 1440,192 L1440,320 L0,320 Z'%3E%3C/path%3E%3C/svg%3E");
}
}
.wave-2 {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%23ffffff' fill-opacity='0.08' d='M0,224L48,213.3C96,203,192,181,288,181.3C384,181,480,203,576,224C672,245,768,267,864,250.7C960,235,1056,181,1152,165.3C1248,149,1344,171,1392,181.3L1440,192L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'%3E%3C/path%3E%3C/svg%3E");
animation: waveMove 14s linear infinite reverse;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320' preserveAspectRatio='none'%3E%3Cpath fill='%23ffffff' fill-opacity='0.08' d='M0,224 C360,160 720,288 1080,224 C1260,192 1350,240 1440,224 L1440,320 L0,320 Z'%3E%3C/path%3E%3C/svg%3E");
animation: waveMove 16s linear infinite reverse;
height: 200px;
bottom: 30px;
opacity: 0.2;
:global([data-theme='dark']) & {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%2300c8ff' fill-opacity='0.08' d='M0,224L48,213.3C96,203,192,181,288,181.3C384,181,480,203,576,224C672,245,768,267,864,250.7C960,235,1056,181,1152,165.3C1248,149,1344,171,1392,181.3L1440,192L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'%3E%3C/path%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320' preserveAspectRatio='none'%3E%3Cpath fill='%2300c8ff' fill-opacity='0.08' d='M0,224 C360,160 720,288 1080,224 C1260,192 1350,240 1440,224 L1440,320 L0,320 Z'%3E%3C/path%3E%3C/svg%3E");
opacity: 0.3;
}
}
@@ -609,14 +633,12 @@ $phi-inv: 38.2%;
top: 40px;
left: 48px;
display: flex;
align-items: center;
gap: 12px;
z-index: 10;
}
.brand-name {
font-family: 'Swis721 BlkCn BT', Arial, sans-serif;
font-size: 22px;
font-size: 30px;
font-weight: 600;
color: #ffffff;
letter-spacing: 0.5px;
@@ -746,7 +768,7 @@ $phi-inv: 38.2%;
.login-container {
width: 100%;
max-width: 340px;
max-width: 581px;
padding: 0 40px;
}
@@ -761,15 +783,15 @@ $phi-inv: 38.2%;
}
.login-header {
margin-bottom: 32px;
margin-bottom: 40px;
}
.title {
margin: 0 0 8px 0;
margin: 0 0 12px 0;
font-weight: 600;
font-size: 26px;
font-size: 32px;
line-height: 1.3;
color: #111827;
color: #1a1a1a;
:global([data-theme='dark']) & {
color: #f9fafb;
@@ -778,8 +800,10 @@ $phi-inv: 38.2%;
.subtitle {
margin: 0;
font-size: 14px;
color: #6b7280;
font-size: 16px;
color: #666666;
font-weight: 400;
line-height: 1.5;
:global([data-theme='dark']) & {
color: #9ca3af;
@@ -790,35 +814,43 @@ $phi-inv: 38.2%;
width: 100%;
}
.login-form :deep(.el-form-item) {
margin-bottom: 24px;
}
.login-input {
height: 48px;
}
.login-input :deep(.el-input__wrapper) {
height: 46px;
border-radius: 10px;
background-color: #ffffff;
border: 1px solid #e5e7eb;
box-shadow: none;
height: 48px !important;
min-height: 48px !important;
border-radius: 8px;
box-shadow: 0 0 0 1px #dbdbdb inset;
transition: all 0.25s ease;
padding: 0 14px;
padding: 0 16px;
padding-left: 0;
position: relative;
:global([data-theme='dark']) & {
background-color: #111827;
border-color: #374151;
box-shadow: 0 0 0 1px #374151 inset;
}
&:hover {
border-color: #d1d5db;
box-shadow: 0 0 0 1px #019c7c inset;
:global([data-theme='dark']) & {
border-color: #4b5563;
box-shadow: 0 0 0 1px #4b5563 inset;
}
}
&.is-focus {
border-color: #019c7c !important;
box-shadow: 0 0 0 4px rgba(1, 156, 124, 0.08) !important;
}
:global([data-theme='dark']) & {
border-color: #00c896 !important;
box-shadow: 0 0 0 4px rgba(0, 200, 150, 0.1) !important;
.login-input {
&.is-field-valid {
:deep(.el-input__wrapper) {
box-shadow: 0 0 0 1px #019c7c inset !important;
}
}
}
@@ -826,13 +858,14 @@ $phi-inv: 38.2%;
.login-input :deep(.el-input__inner) {
height: 100%;
font-size: 14px;
color: #111827;
color: #333333;
background-color: transparent;
border: none;
box-shadow: none;
padding-left: 56px;
&::placeholder {
color: #9ca3af;
color: #999999;
}
:global([data-theme='dark']) & {
@@ -845,36 +878,109 @@ $phi-inv: 38.2%;
}
.login-input :deep(.el-input__prefix) {
color: #9ca3af;
margin-right: 8px;
color: #019c7c;
margin-right: 0;
padding: 0;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
top: 0;
}
.login-input :deep(.el-input__prefix)::after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 1px;
height: 24px;
background-color: #e8e8e8;
:global([data-theme='dark']) & {
color: #6b7280;
background-color: #374151;
}
}
.login-input :deep(.el-input__prefix-inner) {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.login-input :deep(.el-input__icon),
.login-input :deep(.el-icon) {
font-size: 18px;
width: 18px;
height: 18px;
line-height: 1;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
.login-input :deep(.el-input__prefix-inner .el-icon) {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
/* 后缀图标(清除按钮、密码切换) */
.login-input :deep(.el-input__suffix) {
position: absolute;
right: 16px;
top: 0;
height: 100%;
display: flex;
align-items: center;
}
.login-input :deep(.el-input__suffix-inner) {
display: flex;
align-items: center;
gap: 8px;
}
.login-input :deep(.el-input__clear),
.login-input :deep(.el-input__password) {
color: #999999;
cursor: pointer;
&:hover {
color: #019c7c;
}
}
.login-button {
width: 100%;
height: 46px;
font-size: 14px;
height: 48px;
font-size: 16px;
font-weight: 500;
border-radius: 10px;
background: #111827;
border-radius: 8px;
background: #019c7c;
border: none;
margin-top: 8px;
margin-top: 32px;
transition: all 0.25s ease;
color: #ffffff;
:global([data-theme='dark']) & {
background: #00c896;
color: #000000;
background: #019c7c;
color: #ffffff;
}
&:hover {
background: #374151;
background: #018a6d;
transform: translateY(-1px);
:global([data-theme='dark']) & {
background: color.adjust(#00c896, $lightness: -5%);
background: #018a6d;
}
}
@@ -893,7 +999,7 @@ $phi-inv: 38.2%;
.forgot-link {
font-size: 13px;
color: #6b7280;
color: #999999;
transition: color 0.25s ease;
:global([data-theme='dark']) & {
@@ -904,14 +1010,14 @@ $phi-inv: 38.2%;
color: #019c7c;
:global([data-theme='dark']) & {
color: #00c896;
color: #019c7c;
}
}
}
.login-form :deep(.el-checkbox__label) {
font-size: 13px;
color: #374151;
color: #666666;
padding-left: 6px;
:global([data-theme='dark']) & {
@@ -920,8 +1026,8 @@ $phi-inv: 38.2%;
}
.login-form :deep(.el-checkbox__inner) {
border-radius: 5px;
border-color: #d1d5db;
border-radius: 4px;
border-color: #d9d9d9;
width: 16px;
height: 16px;
@@ -929,6 +1035,10 @@ $phi-inv: 38.2%;
border-color: #4b5563;
background-color: transparent;
}
&:hover {
border-color: #019c7c;
}
}
.login-form :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
@@ -936,8 +1046,16 @@ $phi-inv: 38.2%;
border-color: #019c7c;
:global([data-theme='dark']) & {
background-color: #00c896;
border-color: #00c896;
background-color: #019c7c;
border-color: #019c7c;
}
}
.login-form :deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
color: #019c7c;
:global([data-theme='dark']) & {
color: #019c7c;
}
}