|
@@ -1,43 +1,63 @@
|
|
|
<template>
|
|
|
- <div class="relative" @mouseleave="isOpen = false">
|
|
|
- <div @mouseenter="isOpen = true" class="flex items-center cursor-pointer">
|
|
|
- <img :src="user.profileImage" :alt="user.name" class="w-8 h-8 rounded-full mr-2" />
|
|
|
- <span class="text-gray-800">{{ user.name }}</span>
|
|
|
- </div>
|
|
|
+ <div class="relative">
|
|
|
+ <div @click="toggleMenu" class="flex items-center cursor-pointer">
|
|
|
+ <img :src="user.profileImage" :alt="user.name" class="w-8 h-8 rounded-full mr-2" />
|
|
|
+ <span class="text-gray-800">{{ user.name }}</span>
|
|
|
+ </div>
|
|
|
+ <transition name="fade">
|
|
|
<div v-if="isOpen" class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg z-10">
|
|
|
- <router-link to="/profile" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">个人资料</router-link>
|
|
|
- <router-link to="/change-password" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">修改密码</router-link>
|
|
|
- <a @click="logout" class="block px-4 py-2 text-gray-800 hover:bg-gray-100 cursor-pointer">登出</a>
|
|
|
+ <router-link @click="closeMenu" to="/profile" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">个人资料</router-link>
|
|
|
+ <router-link @click="closeMenu" to="/change-password" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">修改密码</router-link>
|
|
|
+ <a @click="logoutAndCloseMenu" class="block px-4 py-2 text-gray-800 hover:bg-gray-100 cursor-pointer">登出</a>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
-
|
|
|
- <script setup>
|
|
|
- import { ref } from 'vue';
|
|
|
- import { useStore } from 'vuex';
|
|
|
- import { useRouter } from 'vue-router';
|
|
|
-
|
|
|
- const store = useStore();
|
|
|
- const router = useRouter();
|
|
|
- const isOpen = ref(false);
|
|
|
-
|
|
|
- const user = store.getters['auth/user'];
|
|
|
-
|
|
|
- const logout = () => {
|
|
|
- store.dispatch('auth/logout');
|
|
|
- router.push('/');
|
|
|
- };
|
|
|
- </script>
|
|
|
-
|
|
|
- <style scoped>
|
|
|
- .relative {
|
|
|
- position: relative;
|
|
|
- }
|
|
|
- .absolute {
|
|
|
- position: absolute; /* 下拉菜单绝对定位 */
|
|
|
- top: 100%; /* 确保下拉菜单在 header 下面 */
|
|
|
- right: 0; /* 右对齐 */
|
|
|
- z-index: 10; /* 确保下拉菜单在其他元素之上 */
|
|
|
- }
|
|
|
-
|
|
|
- </style>
|
|
|
+ </transition>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref } from 'vue';
|
|
|
+import { useStore } from 'vuex';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+
|
|
|
+const store = useStore();
|
|
|
+const router = useRouter();
|
|
|
+const isOpen = ref(false);
|
|
|
+
|
|
|
+const user = store.getters['auth/user'];
|
|
|
+
|
|
|
+const toggleMenu = () => {
|
|
|
+ isOpen.value = !isOpen.value;
|
|
|
+};
|
|
|
+
|
|
|
+const closeMenu = () => {
|
|
|
+ isOpen.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+const logoutAndCloseMenu = () => {
|
|
|
+ store.dispatch('auth/logout');
|
|
|
+ router.push('/');
|
|
|
+ closeMenu();
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.relative {
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+.absolute {
|
|
|
+ position: absolute;
|
|
|
+ top: 100%;
|
|
|
+ right: 0;
|
|
|
+ z-index: 10;
|
|
|
+}
|
|
|
+
|
|
|
+.fade-enter-active,
|
|
|
+.fade-leave-active {
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.fade-enter-from,
|
|
|
+.fade-leave-to {
|
|
|
+ opacity: 0;
|
|
|
+}
|
|
|
+</style>
|