From a1a7e3f3b5e5c2088f1c7cd7f237d7e1f1dd0cf2 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Sun, 25 May 2025 11:12:03 +0800 Subject: [PATCH] update --- docker-compose.yml | 2 +- src/App.vue | 455 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 395 insertions(+), 62 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 15866f0..0d528f7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: build: context: . dockerfile: Dockerfile - image: tradus-web:1.3.20 + image: tradus-web:1.3.21 container_name: tradus-web ports: - '6000:80' diff --git a/src/App.vue b/src/App.vue index dace941..d4618f2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,18 +2,21 @@ import { RouterView, useRoute } from 'vue-router' import { computed, ref, onMounted, onUnmounted, watch } from 'vue' import { useUserStore } from './stores/user' +import { useThemeStore } from './stores/theme' import { authApi, http } from './services/api' const route = useRoute() const isStandalonePage = computed(() => route.meta.standalone) const userStore = useUserStore() +const themeStore = useThemeStore() const isAuthenticated = computed(() => userStore.isAuthenticated) const userInfo = computed(() => userStore.userInfo) const showMobileMenu = ref(false) const showUserMenu = ref(false) const showLoginModal = ref(false) const showResetPasswordModal = ref(false) +const showUserInfoModal = ref(false) const loginMode = ref('login') // 'login' 或 'register' // 获取用户信息 @@ -354,6 +357,7 @@ const handleLogout = () => { } showMobileMenu.value = false showUserMenu.value = false + showUserInfoModal.value = false } const toggleMobileMenu = () => { @@ -371,9 +375,6 @@ const closeMenus = (event: MouseEvent) => { if (!target.closest('.mobile-menu') && !target.closest('.menu-button')) { showMobileMenu.value = false } - if (!target.closest('.user-info-box') && !target.closest('.user-menu')) { - showUserMenu.value = false - } } const openAuthModal = (mode: 'login' | 'register') => { @@ -403,6 +404,23 @@ const openResetPasswordModal = () => { showResetPasswordModal.value = true } +// 打开用户信息模态框 +const openUserInfoModal = () => { + showUserInfoModal.value = true + showUserMenu.value = false + showMobileMenu.value = false +} + +// 关闭用户信息模态框 +const closeUserInfoModal = () => { + showUserInfoModal.value = false +} + +// 切换主题 +const toggleTheme = () => { + themeStore.toggleTheme() +} + onMounted(() => { document.addEventListener('click', closeMenus) if (isAuthenticated.value) { @@ -520,21 +538,17 @@ onUnmounted(() => {
-
+ - -
- -
@@ -572,21 +570,17 @@ onUnmounted(() => {
+ + +
@@ -2052,4 +2137,252 @@ html { .forgot-password-link:hover { text-decoration: underline; } + +/* 用户信息模态框样式 */ +.user-info-modal-container { + background-color: var(--color-bg-primary); + border-radius: var(--border-radius); + width: 90%; + max-width: 480px; + box-shadow: 0 4px 24px rgba(0, 0, 0, 0.2); + animation: modalSlideIn 0.3s ease; + overflow: hidden; +} + +.user-info-modal-content { + padding: 0; +} + +.user-profile-section { + display: flex; + align-items: center; + gap: 1.5rem; + padding: 2rem; + border-bottom: 1px solid var(--color-border); +} + +.user-avatar-large { + width: 4rem; + height: 4rem; + border-radius: 50%; + background: linear-gradient(135deg, var(--color-accent) 0%, rgba(51, 85, 255, 0.8) 100%); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.8rem; + font-weight: bold; + color: white; + box-shadow: 0 4px 12px rgba(51, 85, 255, 0.2); +} + +.user-basic-info { + flex: 1; +} + +.user-display-name { + font-size: 1.5rem; + font-weight: 600; + margin: 0; + color: var(--color-text-primary); +} + +.user-email { + font-size: 0.95rem; + margin: 0 0 0.75rem 0; + color: var(--color-text-secondary); +} + +.user-points-display { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 1rem; + font-weight: 500; +} + +.user-points-display .points-icon { + font-size: 1.2rem; + color: var(--color-accent); +} + +.user-points-display .points-text { + color: var(--color-text-primary); +} + +.settings-section { + padding: 1.5rem 2rem; +} + +.setting-item { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; +} + +.setting-info { + flex: 1; +} + +.setting-title { + font-size: 1rem; + font-weight: 500; + color: var(--color-text-primary); + margin-bottom: 0.25rem; +} + +.setting-description { + font-size: 0.85rem; + color: var(--color-text-secondary); +} + +.theme-toggle { + display: flex; + gap: 0.5rem; + background-color: var(--color-bg-secondary); + border-radius: 8px; + padding: 0.25rem; +} + +.theme-option { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.75rem; + border: none; + background: none; + border-radius: 6px; + font-size: 0.85rem; + font-weight: 500; + color: var(--color-text-secondary); + cursor: pointer; + transition: all 0.2s ease; +} + +.theme-option:hover { + background-color: var(--color-bg-hover); + color: var(--color-text-primary); +} + +.theme-option.active { + background-color: var(--color-accent); + color: white; +} + +.theme-option svg { + width: 16px; + height: 16px; + stroke: currentColor; +} + +.modal-actions { + padding: 1.5rem 2rem; + border-top: 1px solid var(--color-border); + background-color: var(--color-bg-secondary); +} + +.logout-button { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + padding: 0.875rem; + background-color: #ff4757; + color: white; + border: none; + border-radius: var(--border-radius); + font-size: 1rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.logout-button:hover { + background-color: #ff3742; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(255, 71, 87, 0.3); +} + +.logout-button svg { + stroke: currentColor; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + .user-info-modal-container { + width: 95%; + max-width: none; + } + + .user-profile-section { + padding: 1.5rem; + gap: 1rem; + } + + .user-avatar-large { + width: 3.5rem; + height: 3.5rem; + font-size: 1.5rem; + } + + .user-display-name { + font-size: 1.3rem; + } + + .settings-section { + padding: 1.25rem 1.5rem; + } + + .modal-actions { + padding: 1.25rem 1.5rem; + } + + .setting-item { + flex-direction: column; + align-items: stretch; + gap: 1rem; + } + + .theme-toggle { + align-self: stretch; + } + + .theme-option { + flex: 1; + justify-content: center; + } +} + +/* 更新info-icon样式 */ +.info-icon { + color: var(--color-text-secondary); + transition: all 0.2s ease; +} + +.user-info-box:hover .info-icon { + color: var(--color-accent); + transform: rotate(90deg); +} + +/* 用户邮箱显示样式 */ +.user-email-display { + font-size: 0.9rem; + font-weight: var(--font-weight-medium); + color: var(--color-text-primary); + transition: all 0.2s ease; + display: block; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 100%; +} + +.desktop-user-info .user-info-box:hover .user-email-display { + color: var(--color-accent); +} + +.mobile-user-info .user-info-box:hover .user-email-display { + color: var(--color-accent); +}