alou 0.1.6

智能自动化工作流系统 - 基于Rust和Model Context Protocol (MCP)的智能体
Documentation
<template>
  <div class="user-avatar-wrapper">
    <button class="user-avatar" @click="toggleDropdown">
      <img 
        v-if="avatar" 
        :src="avatar" 
        :alt="name"
        class="avatar-image"
      />
      <div v-else class="avatar-placeholder">
        {{ initials }}
      </div>
    </button>

    <Transition name="dropdown">
      <div v-if="showDropdown" class="dropdown-menu">
        <div class="user-info">
          <div class="user-name">{{ name }}</div>
          <div class="user-email">{{ email }}</div>
        </div>
        
        <div class="dropdown-divider"></div>
        
        <button class="dropdown-item" @click="goToProfile">
          <span class="item-icon">👤</span>
          个人中心
        </button>
        
        <button class="dropdown-item" @click="goToSettings">
          <span class="item-icon">⚙️</span>
          设置
        </button>
        
        <div class="dropdown-divider"></div>
        
        <button class="dropdown-item logout" @click="handleLogout">
          <span class="item-icon">🚪</span>
          退出登录
        </button>
      </div>
    </Transition>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'

const props = defineProps<{
  name: string
  email?: string
  avatar?: string
}>()

const router = useRouter()
const authStore = useAuthStore()

const showDropdown = ref(false)

const initials = computed(() => {
  if (!props.name) return '?'
  const words = props.name.split(' ')
  if (words.length >= 2) {
    return (words[0][0] + words[1][0]).toUpperCase()
  }
  return props.name.slice(0, 2).toUpperCase()
})

function toggleDropdown() {
  showDropdown.value = !showDropdown.value
}

function closeDropdown() {
  showDropdown.value = false
}

function goToProfile() {
  closeDropdown()
  router.push('/profile')
}

function goToSettings() {
  closeDropdown()
  router.push('/settings')
}

async function handleLogout() {
  closeDropdown()
  await authStore.logout()
  router.push('/login')
}

// Close dropdown when clicking outside
function handleClickOutside(event: MouseEvent) {
  const target = event.target as HTMLElement
  if (!target.closest('.user-avatar-wrapper')) {
    closeDropdown()
  }
}

onMounted(() => {
  document.addEventListener('click', handleClickOutside)
})

onUnmounted(() => {
  document.removeEventListener('click', handleClickOutside)
})
</script>

<style scoped>
.user-avatar-wrapper {
  position: relative;
}

.user-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 2px solid #e0e0e0;
  background: none;
  padding: 0;
  cursor: pointer;
  transition: all 0.3s;
}

.user-avatar:hover {
  border-color: #667eea;
  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
}

.avatar-image {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

.avatar-placeholder {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 16px;
}

.dropdown-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 220px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  padding: 8px 0;
  z-index: 1000;
}

.user-info {
  padding: 12px 16px;
}

.user-name {
  font-weight: 600;
  color: #1a1a1a;
  margin-bottom: 4px;
}

.user-email {
  font-size: 13px;
  color: #666;
}

.dropdown-divider {
  height: 1px;
  background-color: #e0e0e0;
  margin: 8px 0;
}

.dropdown-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  background: none;
  border: none;
  text-align: left;
  font-size: 14px;
  color: #444;
  cursor: pointer;
  transition: background-color 0.2s;
}

.dropdown-item:hover {
  background-color: #f5f5f5;
}

.dropdown-item.logout {
  color: #c33;
}

.dropdown-item.logout:hover {
  background-color: #fee;
}

.item-icon {
  font-size: 18px;
}

/* Dropdown transition */
.dropdown-enter-active,
.dropdown-leave-active {
  transition: all 0.2s ease;
}

.dropdown-enter-from,
.dropdown-leave-to {
  opacity: 0;
  transform: translateY(-10px);
}
</style>