6-1 个人中心页

src/views/profile/index.vue
<template><div class="profile-container"><el-card><template #header><div class="card-header"><span>关于我</span></div></template><div class="profile" v-if="userInfo"><div class="avatar"><img :src="avatar" alt="" /></div><h2>用户名:{{ userInfo.username }}</h2><h3>用户角色:{{ roleNames }}</h3><div v-if="userInfo.description"><span>个人说明</span><p>{{ userInfo.description }}</p></div></div></el-card></div></template><script lang="ts">import { computed, defineComponent } from 'vue'import { useStore } from '@/store'import defaultAvatar from '@/assets/logo.png'export default defineComponent({name: 'Profile',setup() {const store = useStore()const userInfo = computed(() => store.state.user.userInfo)const roleNames = computed(() => store.getters.roleNames)const avatar = computed(() => userInfo?.value?.avatar || defaultAvatar)return {userInfo,avatar,roleNames}}})</script><style lang="scss" scoped>.profile-container {width: 500px;margin: 10px auto;.profile {text-align: center;.avatar {width: 100px;height: 100px;border-radius: 50%;margin: 10px auto;img {width: 100%;height: 100%;}}}}</style>
路由注册
src/router/index.ts
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'import Layout from '@/layout/index.vue'// 看作是异步获取路由export const asyncRoutes: Array<RouteRecordRaw> = [{path: '/documentation',component: Layout, // 布局组件作为一级路由redirect: '/documentation/index',name: 'DocumentationLayout',children: [{path: 'index',name: 'Documentation',component: () => import(/* webpackChunkName: "documentation" */ '@/views/documentation/index.vue'),meta: {title: 'Documentation',icon: 'documentation',hidden: false, // 菜单栏不显示// 路由是否缓存 没有这个属性或false都会缓存 true不缓存noCache: true}}]},{path: '/async',component: Layout,redirect: '/async/index',name: 'AsyncLayout',children: [{path: 'index',name: 'Async',component: () => import(/* webpackChunkName: "async" */ '@/views/async.vue'),meta: {title: '动态路由',icon: 'guide'// 当guide路由激活时高亮选中的是 documentation/index菜单// activeMenu: '/documentation/index'}}]},{path: '/guide',component: Layout,redirect: '/guide/index',name: 'GuideLayout',meta: {title: 'GuideLay',icon: 'guide'},children: [{path: 'index',name: 'Guide',component: () => import(/* webpackChunkName: "guide" */ '@/views/guide/index.vue'),meta: {title: 'Guide',icon: 'guide'// 当guide路由激活时高亮选中的是 documentation/index菜单// activeMenu: '/documentation/index'}},{path: 'guide2',name: 'Guide2',component: () => import(/* webpackChunkName: "guide" */ '@/views/guide/index.vue'),meta: {title: 'Guide2',icon: 'guide'// 当guide路由激活时高亮选中的是 documentation/index菜单// activeMenu: '/documentation/index'}},{path: 'guide3',name: 'Guide3',component: () => import(/* webpackChunkName: "guide" */ '@/views/guide/index.vue'),meta: {title: 'Guide3',icon: 'guide'// 当guide路由激活时高亮选中的是 documentation/index菜单// activeMenu: '/documentation/index'}}]},{path: '/system',component: Layout,redirect: '/system/user',name: 'SystemLayout',meta: {title: 'System',icon: 'lock',alwaysShow: true // 根路由始终显示 哪怕只有一个子路由},children: [{path: 'menu',name: 'Menu Management',component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu/index.vue'),meta: {title: 'Menu Management',hidden: false,breadcrumb: false}},{path: 'role',name: 'Role Management',component: () => import(/* webpackChunkName: "role" */ '@/views/system/role/index.vue'),meta: {title: 'Role Management',hidden: false}},{path: 'user',name: 'User Management',component: () => import(/* webpackChunkName: "user" */ '@/views/system/user/index.vue'),meta: {title: 'User Management'}}]},{ // 外链路由path: '/external-link',component: Layout,children: [{path: 'https://www.baidu.com/',redirect: '/',meta: {title: 'External Link',icon: 'link'}}]},{ // 404一定放在要在最后面path: '/:pathMatch(.*)*',redirect: '/404',meta: {hidden: true}}]export const constantRoutes: Array<RouteRecordRaw> = [{path: '/',component: Layout,redirect: '/dashboard',name: 'DashboardLayout',children: [{path: 'dashboard',name: 'Dashboard',component: () => import(/* webpackChunkName: "dashboard" */ '@/views/dashboard/index.vue'),meta: {title: 'Dashboard',// icon: 'dashboard'icon: 'el-icon-platform-eleme',affix: true // 固定显示在tagsView中}}]},{path: '/redirect',component: Layout,meta: {hidden: true},name: 'Redirect',children: [{ // 带参数的动态路由正则匹配// https://next.router.vuejs.org/zh/guide/essentials/route-matching-syntax.html#%E5%8F%AF%E9%87%8D%E5%A4%8D%E7%9A%84%E5%8F%82%E6%95%B0path: '/redirect/:path(.*)', // 要匹配多级路由 应该加*号component: () => import('@/views/redirect/index.vue')}]},{path: '/login',name: 'Login',component: () => import('@/views/login/index.vue')},{path: '/profile',component: Layout,redirect: '/profile/index',name: 'ProfileLayout',children: [{path: 'index',name: 'Profile',component: () => import('@/views/profile/index.vue'),meta: {hidden: true,title: '个人中心'}}]},{path: '/401',component: Layout,name: '401Layout',children: [{path: '',component: () => import('@/views/error-page/401.vue'),meta: {title: '401',icon: '404',hidden: true}}]},{path: '/404',component: () => import('@/views/error-page/404.vue'),meta: {hidden: true // 404 hidden掉}}]export const routes = [...constantRoutes// ...asyncRoutes]const router = createRouter({history: createWebHashHistory(),routes})export default router
6-2 修改头像下拉选项
src/layout/components/avatar/index.vue
<template><el-dropdownclass="avatar-container"><div class="avatar-wrapper"><img :src="avatar" class="user-avatar"><i class="el-icon-caret-bottom" /></div><template #dropdown><el-dropdown-menu><el-dropdown-item v-if="username"><span style="display: block" :style="{fontWeight: '500'}">用户名:{{username}}</span></el-dropdown-item><router-link to="/"><el-dropdown-item>首页</el-dropdown-item></router-link><router-link to="/profile/index"><el-dropdown-item>个人中心</el-dropdown-item></router-link><el-dropdown-item divided @click="logout"><span style="display: block">退出登录</span></el-dropdown-item></el-dropdown-menu></template></el-dropdown></template><script lang="ts">import defaultAvatar from '@/assets/logo.png'import { defineComponent, getCurrentInstance, computed } from 'vue'import { useStore } from '@/store'export default defineComponent({setup() {const store = useStore()const { proxy } = getCurrentInstance()!const logout = () => {store.dispatch('user/logout').then(() => {proxy?.$message.success('退出登录')window.location.reload()})}const userInfo = computed(() => store.state.user.userInfo)const avatar = computed(() => userInfo.value?.avatar || defaultAvatar)const username = computed(() => userInfo.value?.username || '')// onMounted(() => {// // 获取用户信息// store.dispatch('user/getUserInfo')// })return {logout,avatar,username}}})</script><style lang="scss" scoped>.avatar-container {margin-right: 30px;.avatar-wrapper {margin-top: 5px;.user-avatar {width: 40px;height: 40px;border-radius: 10px;cursor: pointer;}.el-icon-caret-bottom {cursor: pointer;font-size: 12px;}}}</style>

