diff --git a/dashboard/src/components/shared/Logo.vue b/dashboard/src/components/shared/Logo.vue
index 2b77ccefa..6a071d979 100644
--- a/dashboard/src/components/shared/Logo.vue
+++ b/dashboard/src/components/shared/Logo.vue
@@ -5,7 +5,7 @@
-
{{ title }}
+
{{ title }}
{{ subtitle }}
diff --git a/dashboard/src/scss/components/_VTextField.scss b/dashboard/src/scss/components/_VTextField.scss
index c74c9dadc..b9572aa74 100644
--- a/dashboard/src/scss/components/_VTextField.scss
+++ b/dashboard/src/scss/components/_VTextField.scss
@@ -10,6 +10,69 @@
.v-field__outline {
color: rgb(var(--v-theme-inputBorder));
}
+
+// 亮色主题样式
+.v-theme--PurpleTheme .v-text-field .v-field__outline {
+ --v-field-border-width: 2px !important;
+ --v-field-border-opacity: 1 !important;
+ color: rgba(149, 117, 205, 0.6) !important;
+ border-color: rgba(149, 117, 205, 0.6) !important;
+}
+
+.v-theme--PurpleTheme .v-text-field:hover .v-field__outline {
+ --v-field-border-width: 2px !important;
+ --v-field-border-opacity: 1 !important;
+ color: rgba(149, 117, 205, 0.6) !important;
+ border-color: rgba(149, 117, 205, 0.6) !important;
+}
+
+.v-theme--PurpleTheme .v-text-field .v-field--focused .v-field__outline {
+ --v-field-border-width: 2.5px !important;
+ --v-field-border-opacity: 1 !important;
+ color: rgba(149, 117, 205, 0.8) !important;
+ border-color: rgba(149, 117, 205, 0.8) !important;
+}
+
+// 深色主题样式
+.v-theme--PurpleThemeDark .v-text-field .v-field {
+ background-color: rgba(255, 255, 255, 0.08) !important;
+}
+
+.v-theme--PurpleThemeDark .v-text-field .v-field__outline {
+ --v-field-border-width: 2px !important;
+ --v-field-border-opacity: 1 !important;
+ color: rgba(255, 255, 255, 0.5) !important;
+ border-color: rgba(255, 255, 255, 0.5) !important;
+}
+
+.v-theme--PurpleThemeDark .v-text-field:hover .v-field__outline {
+ --v-field-border-width: 2px !important;
+ --v-field-border-opacity: 1 !important;
+ color: rgba(255, 255, 255, 0.7) !important;
+ border-color: rgba(255, 255, 255, 0.7) !important;
+}
+
+.v-theme--PurpleThemeDark .v-text-field .v-field--focused .v-field__outline {
+ --v-field-border-width: 2.5px !important;
+ --v-field-border-opacity: 1 !important;
+ color: rgb(129, 102, 176) !important;
+ border-color: rgb(126, 99, 171) !important;
+}
+
+.v-theme--PurpleThemeDark .v-text-field input {
+ color: #ffffff !important;
+ font-weight: 500;
+}
+
+.v-theme--PurpleThemeDark .v-text-field .v-field__label {
+ color: rgba(255, 255, 255, 0.8) !important;
+}
+
+.v-theme--PurpleThemeDark .v-text-field .v-field__prepend-inner .v-icon,
+.v-theme--PurpleThemeDark .v-text-field .v-field__append-inner .v-icon {
+ color: rgba(255, 255, 255, 0.8) !important;
+}
+
.inputWithbg {
.v-field--variant-outlined {
background-color: rgba(0, 0, 0, 0.025);
diff --git a/dashboard/src/views/authentication/auth/LoginPage.vue b/dashboard/src/views/authentication/auth/LoginPage.vue
index 63caeda47..2eeb78cc9 100644
--- a/dashboard/src/views/authentication/auth/LoginPage.vue
+++ b/dashboard/src/views/authentication/auth/LoginPage.vue
@@ -9,6 +9,14 @@ import {useCustomizerStore} from "@/stores/customizer";
const cardVisible = ref(false);
const router = useRouter();
const authStore = useAuthStore();
+const customizer = useCustomizerStore();
+
+// 主题切换函数
+function toggleTheme() {
+ customizer.SET_UI_THEME(
+ customizer.uiTheme === 'PurpleThemeDark' ? 'PurpleTheme' : 'PurpleThemeDark'
+ );
+}
onMounted(() => {
// 检查用户是否已登录,如果已登录则重定向
@@ -27,6 +35,25 @@ onMounted(() => {
+
+
+
+
+ mdi-weather-night
+
+ 切换到深色主题
+
+
+
+
{
+
+
+
+
+ mdi-white-balance-sunny
+
+ 切换到浅色主题
+
+
+
+
{
height: 100vh;
width: 100%;
position: relative;
- background: linear-gradient(135deg, #ebf5fd 0%, #e0e9f8 100%);
+ background:
+ linear-gradient(-45deg,
+ #faf9f7 0%,
+ #f9f2f1 25%,
+ #f1f9f9 50%,
+ #f9f3f7 75%,
+ #faf9f7 100%
+ );
+ background-size: 400% 400%;
+ animation: gradientShift 15s ease infinite;
overflow: hidden;
}
@@ -82,17 +137,38 @@ onMounted(() => {
height: 100vh;
width: 100%;
position: relative;
- background: linear-gradient(135deg, #1a1b1c 0%, #1d1e21 100%);
+ background:
+ linear-gradient(-45deg,
+ #1e1f21 0%,
+ #221e25 25%,
+ #1e2225 50%,
+ #221f23 75%,
+ #1e1f21 100%
+ );
+ background-size: 400% 400%;
+ animation: gradientShift 15s ease infinite;
overflow: hidden;
}
+@keyframes gradientShift {
+ 0% {
+ background-position: 0% 50%;
+ }
+ 50% {
+ background-position: 100% 50%;
+ }
+ 100% {
+ background-position: 0% 50%;
+ }
+}
+
.login-background {
position: absolute;
width: 200%;
height: 200%;
top: -50%;
left: -50%;
- background: radial-gradient(circle, rgba(94, 53, 177, 0.03) 0%, rgba(30, 136, 229, 0.06) 70%);
+ background: radial-gradient(circle, rgba(94, 53, 177, 0.02) 0%, rgba(94, 53, 177, 0.03) 70%);
z-index: 0;
animation: rotate 60s linear infinite;
}
@@ -103,7 +179,7 @@ onMounted(() => {
height: 200%;
top: -50%;
left: -50%;
- background-color: var(--v-theme-surface);
+ background: radial-gradient(circle, rgba(114, 46, 209, 0.03) 0%, rgba(114, 46, 209, 0.04) 70%);
z-index: 0;
animation: rotate 60s linear infinite;
}
@@ -117,23 +193,85 @@ onMounted(() => {
}
}
+.theme-toggle-container {
+ position: absolute;
+ top: 20px;
+ right: 20px;
+ z-index: 10;
+}
+
+.theme-toggle-btn {
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+}
+
.login-card {
max-width: 520px;
width: 90%;
+ position: relative;
color: var(--v-theme-primaryText) !important;
- border-radius: 12px !important;
- border-color: var(--v-theme-border) !important;
- box-shadow: 0 8px 30px rgba(0, 0, 0, 0.07) !important;
- background-color: var(--v-theme-surface) !important;
+ border-radius: 16px !important;
+ border: 1px solid rgba(94, 53, 177, 0.15) !important;
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08) !important;
+ background: #f8f6fc !important;
+ backdrop-filter: blur(10px);
transform: translateY(20px);
opacity: 0;
- transition: all 0.5s ease;
+ transition: transform 0.5s ease, opacity 0.5s ease, border-color 0.3s ease, box-shadow 0.3s ease;
z-index: 1;
+ &::before {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: calc(100% + 4px);
+ height: calc(100% + 4px);
+ transform: translate(-50%, -50%);
+ border-radius: 18px;
+ border: 2px solid rgba(94, 53, 177, 0);
+ transition: border-color 0.3s ease;
+ pointer-events: none;
+ z-index: -1;
+ }
+
&.card-visible {
transform: translateY(0);
opacity: 1;
}
+
+ &:hover {
+ border-color: rgba(158, 126, 222, 0.99) !important;
+ box-shadow: 0 12px 40px rgba(175, 145, 230, 0.741) !important;
+ transform: translateY(-2px);
+
+ &::before {
+ border-color: rgba(156, 114, 239, 0.907);
+ }
+ }
+}
+
+.login-page-container-dark .login-card {
+ border: 1px solid rgba(110, 60, 180, 0.692) !important;
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3) !important;
+ background: #2a2733 !important;
+
+ &::before {
+ border: 2px solid rgba(114, 46, 209, 0);
+ }
+
+ &:hover {
+ border-color: rgba(160, 118, 219, 0.782) !important;
+ box-shadow: 0 12px 40px rgba(99, 44, 175, 0.462) !important;
+ transform: translateY(-2px);
+
+ &::before {
+ border-color: rgba(114, 46, 209, 0.15);
+ }
+ }
}
.logo-wrapper {
@@ -145,8 +283,12 @@ onMounted(() => {
}
.custom-divider {
- border-color: rgba(0, 0, 0, 0.05) !important;
- opacity: 0.8;
+ border-color: rgba(94, 53, 177, 0.1) !important;
+ opacity: 1;
+}
+
+.login-page-container-dark .custom-divider {
+ border-color: rgba(114, 46, 209, 0.08) !important;
}
.loginBox {
diff --git a/dashboard/src/views/authentication/authForms/AuthLogin.vue b/dashboard/src/views/authentication/authForms/AuthLogin.vue
index bacd72ddd..bc43d5575 100644
--- a/dashboard/src/views/authentication/authForms/AuthLogin.vue
+++ b/dashboard/src/views/authentication/authForms/AuthLogin.vue
@@ -77,6 +77,7 @@ async function validate(values: any, { setErrors }: any) {
:disabled="valid"
type="submit"
elevation="2"
+
>
登录
@@ -146,6 +147,7 @@ async function validate(values: any, { setErrors }: any) {
height: 48px;
transition: all 0.3s ease;
letter-spacing: 0.5px;
+ border-radius: 8px !important;
&:hover {
transform: translateY(-2px);