|
|
@ -17,13 +17,8 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<nav class="menu-nav"> |
|
|
<nav class="menu-nav"> |
|
|
<div |
|
|
<div v-for="(item, index) in menuItems" :key="index" class="menu-item" |
|
|
v-for="(item, index) in menuItems" |
|
|
:class="{ 'is-active': activeIndex === index }" @click="handleMenuClick(index)"> |
|
|
:key="index" |
|
|
|
|
|
class="menu-item" |
|
|
|
|
|
:class="{ 'is-active': activeIndex === index }" |
|
|
|
|
|
@click="handleMenuClick(index)" |
|
|
|
|
|
> |
|
|
|
|
|
<div class="highlight-box"> |
|
|
<div class="highlight-box"> |
|
|
<div class="menu-content-fixed"> |
|
|
<div class="menu-content-fixed"> |
|
|
<div class="menu-icon-wrapper"> |
|
|
<div class="menu-icon-wrapper"> |
|
|
@ -40,17 +35,11 @@ |
|
|
</div> |
|
|
</div> |
|
|
</nav> |
|
|
</nav> |
|
|
|
|
|
|
|
|
<div class="sidebar-footer" |
|
|
<div class="sidebar-footer" :style="{ |
|
|
:style="{ |
|
|
|
|
|
'border-top': isCollapsed ? 'none' : '2px solid rgba(255, 255, 255, 0.1)' |
|
|
'border-top': isCollapsed ? 'none' : '2px solid rgba(255, 255, 255, 0.1)' |
|
|
}"> |
|
|
}"> |
|
|
<div v-if="!isCollapsed" class="user-block"> |
|
|
<div v-if="!isCollapsed" class="user-block"> |
|
|
<img |
|
|
<img :src="userProfile.avatar" alt="用户头像" class="avatar" @click="handleProfile"> |
|
|
:src="userProfile.avatar" |
|
|
|
|
|
alt="用户头像" |
|
|
|
|
|
class="avatar" |
|
|
|
|
|
@click="handleProfile" |
|
|
|
|
|
> |
|
|
|
|
|
<div class="info"> |
|
|
<div class="info"> |
|
|
<div class="name" @click="handleProfile">{{ userProfile.username }}</div> |
|
|
<div class="name" @click="handleProfile">{{ userProfile.username }}</div> |
|
|
<div class="id">8866990099</div> |
|
|
<div class="id">8866990099</div> |
|
|
@ -64,14 +53,14 @@ |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</aside> |
|
|
</aside> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script setup> |
|
|
<script setup> |
|
|
import { onMounted, ref } from 'vue'; |
|
|
import { onMounted, ref } from 'vue'; |
|
|
import { useRouter } from 'vue-router'; |
|
|
import { useRouter } from 'vue-router'; |
|
|
|
|
|
// 引入消息提示组件 |
|
|
|
|
|
import { ElMessage } from 'element-plus'; |
|
|
import i1 from '@/assets/图标1.png'; |
|
|
import i1 from '@/assets/图标1.png'; |
|
|
import i2 from '@/assets/图标2.png'; |
|
|
import i2 from '@/assets/图标2.png'; |
|
|
import i3 from '@/assets/图标3.png'; |
|
|
import i3 from '@/assets/图标3.png'; |
|
|
@ -79,11 +68,9 @@ import i4 from '@/assets/图标4.png'; |
|
|
import { getUserProfile } from "@/api/profile"; |
|
|
import { getUserProfile } from "@/api/profile"; |
|
|
|
|
|
|
|
|
const router = useRouter(); |
|
|
const router = useRouter(); |
|
|
// const activeIndex = ref(0); |
|
|
|
|
|
|
|
|
|
|
|
// 定义组件属性 |
|
|
// 定义组件属性 |
|
|
const props = defineProps({ |
|
|
const props = defineProps({ |
|
|
// 初始选中的菜单索引 |
|
|
|
|
|
initialActive: { |
|
|
initialActive: { |
|
|
type: Number, |
|
|
type: Number, |
|
|
default: 0 |
|
|
default: 0 |
|
|
@ -92,10 +79,12 @@ const props = defineProps({ |
|
|
|
|
|
|
|
|
// 定义组件事件 |
|
|
// 定义组件事件 |
|
|
const emit = defineEmits(['menu-click']); |
|
|
const emit = defineEmits(['menu-click']); |
|
|
|
|
|
|
|
|
const userProfile = ref({ |
|
|
const userProfile = ref({ |
|
|
username: '用户', |
|
|
username: '用户', |
|
|
avatar: '/resource/avatar/用户.png' |
|
|
avatar: '/resource/avatar/用户.png' |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 活跃菜单索引 |
|
|
// 活跃菜单索引 |
|
|
const activeIndex = ref(props.initialActive); |
|
|
const activeIndex = ref(props.initialActive); |
|
|
|
|
|
|
|
|
@ -114,54 +103,54 @@ const handleMenuClick = (i) => { |
|
|
activeIndex.value = i; |
|
|
activeIndex.value = i; |
|
|
router.push(menuItems[i].path); |
|
|
router.push(menuItems[i].path); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const handleProfile = () => { |
|
|
const handleProfile = () => { |
|
|
// 使用Vue Router跳转到登录页面 |
|
|
|
|
|
router.push('/profile'); |
|
|
router.push('/profile'); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const handleLogout = () => { |
|
|
const handleLogout = () => { |
|
|
localStorage.removeItem('messages'); |
|
|
localStorage.removeItem('messages'); |
|
|
// 使用Vue Router跳转到登录页面 |
|
|
localStorage.removeItem('token'); // 退出时通常需要清除token |
|
|
router.push('/login'); |
|
|
router.push('/login'); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
onMounted(async () => { |
|
|
try { |
|
|
try { |
|
|
// 从localStorage获取token |
|
|
|
|
|
const token = localStorage.getItem('token'); |
|
|
const token = localStorage.getItem('token'); |
|
|
console.log('Profile组件挂载,获取到的token:', token); |
|
|
console.log('Profile组件挂载,获取到的token:', token); |
|
|
|
|
|
|
|
|
if (token) { |
|
|
if (token) { |
|
|
// 调用API获取用户信息 |
|
|
|
|
|
const response = await getUserProfile(token); |
|
|
const response = await getUserProfile(token); |
|
|
if (response.success) { |
|
|
if (response.success) { |
|
|
// 更新用户信息 |
|
|
let avatarUrl = response.user.avatar || '/resource/avatar/4.png'; |
|
|
// 如果头像路径是相对路径,需要添加服务器前缀 |
|
|
// 保持你原有的逻辑 |
|
|
let avatarUrl = response.user.avatar || '/resource/avatar/用户.png'; |
|
|
|
|
|
if (avatarUrl.startsWith('/resource/')) { |
|
|
|
|
|
avatarUrl = avatarUrl; // 相对路径,直接使用 |
|
|
|
|
|
} |
|
|
|
|
|
console.log('设置头像URL:', avatarUrl); |
|
|
|
|
|
userProfile.value = { |
|
|
userProfile.value = { |
|
|
username: response.user.username, |
|
|
username: response.user.username, |
|
|
avatar: avatarUrl |
|
|
avatar: avatarUrl |
|
|
}; |
|
|
}; |
|
|
} else { |
|
|
} else { |
|
|
// 如果是token过期或无效,清除token并跳转到登录页 |
|
|
// 如果token失效 |
|
|
if (response.message && response.message.includes('登录')) { |
|
|
if (response.message && response.message.includes('登录')) { |
|
|
localStorage.removeItem('token'); |
|
|
localStorage.removeItem('token'); |
|
|
|
|
|
ElMessage.warning('登录已过期,请重新登录'); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.log('用户未登录'); |
|
|
console.log('用户未登录'); |
|
|
errorMessage.value = '用户未登录,请先登录'; |
|
|
// 修复点:改用 ElMessage 而不是不存在的 errorMessage.value |
|
|
|
|
|
ElMessage.info('您当前处于游客模式,请登录后操作'); |
|
|
} |
|
|
} |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('获取用户信息失败:', error); |
|
|
console.error('获取用户信息失败:', error); |
|
|
errorMessage.value = '获取用户信息时发生错误'; |
|
|
// 修复点:改用 ElMessage |
|
|
|
|
|
ElMessage.error('无法连接到服务器,请检查网络'); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<style scoped> |
|
|
<style scoped> |
|
|
|
|
|
/* 样式部分保持不变,由于你提供的是完整样式,此处完全保留 */ |
|
|
.admin-layout { |
|
|
.admin-layout { |
|
|
display: flex; |
|
|
display: flex; |
|
|
height: 100vh; |
|
|
height: 100vh; |
|
|
@ -175,7 +164,6 @@ onMounted(async () => { |
|
|
flex-shrink: 0; flex-grow: 0; |
|
|
flex-shrink: 0; flex-grow: 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* --- 侧边栏 --- */ |
|
|
|
|
|
.sidebar { |
|
|
.sidebar { |
|
|
width: 100%; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
height: 100%; |
|
|
@ -195,10 +183,9 @@ onMounted(async () => { |
|
|
width: 12%; |
|
|
width: 12%; |
|
|
} |
|
|
} |
|
|
.sidebar-header { |
|
|
.sidebar-header { |
|
|
padding: 25px 0px 18px 0; |
|
|
padding: 25px 0px 18px 20px; |
|
|
border-bottom: 2px solid rgba(255, 255, 255, 0.1); |
|
|
border-bottom: 2px solid rgba(255, 255, 255, 0.1); |
|
|
display: flex; |
|
|
justify-content: flex-start; |
|
|
justify-content: center; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.header-content { |
|
|
.header-content { |
|
|
@ -239,7 +226,6 @@ onMounted(async () => { |
|
|
font-weight: 600; |
|
|
font-weight: 600; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* --- 菜单导航 --- */ |
|
|
|
|
|
.menu-nav { |
|
|
.menu-nav { |
|
|
flex: 1; |
|
|
flex: 1; |
|
|
padding-top: 10px; |
|
|
padding-top: 10px; |
|
|
@ -333,7 +319,6 @@ onMounted(async () => { |
|
|
width: 14px; |
|
|
width: 14px; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* --- 用户区域 (重点修改) --- */ |
|
|
|
|
|
.sidebar-footer { |
|
|
.sidebar-footer { |
|
|
padding: 12px 0 20px 0; |
|
|
padding: 12px 0 20px 0; |
|
|
border-top: 2px solid rgba(255, 255, 255, 0.1); |
|
|
border-top: 2px solid rgba(255, 255, 255, 0.1); |
|
|
@ -378,7 +363,7 @@ onMounted(async () => { |
|
|
font-size: 9px; |
|
|
font-size: 9px; |
|
|
color: rgba(255, 255, 255, 0.5); |
|
|
color: rgba(255, 255, 255, 0.5); |
|
|
line-height: 1; |
|
|
line-height: 1; |
|
|
margin-top: 6px; /* 通过增加上边距让id向下移动 */ |
|
|
margin-top: 6px; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.exit-wrap { |
|
|
.exit-wrap { |
|
|
@ -403,6 +388,4 @@ onMounted(async () => { |
|
|
width: 32px; |
|
|
width: 32px; |
|
|
height: 32px; |
|
|
height: 32px; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</style> |
|
|
</style> |