Bläddra i källkod

feat:个人中心雏形

白白 1 år sedan
förälder
incheckning
267595c6e3
3 ändrade filer med 264 tillägg och 47 borttagningar
  1. 19 5
      src/layout/Header/Header.vue
  2. 49 42
      src/router/index.ts
  3. 196 0
      src/views/Profile.vue

+ 19 - 5
src/layout/Header/Header.vue

@@ -63,6 +63,9 @@
           <el-dropdown-menu>
             <el-dropdown-item command="logout">退出登录</el-dropdown-item>
           </el-dropdown-menu>
+          <el-dropdown-menu disabled="ture">
+            <el-dropdown-item command="profile">个人资料</el-dropdown-item>
+          </el-dropdown-menu>
         </template>
       </el-dropdown>
 <!--      <el-dropdown @command="handleCommand" style="position: absolute;top: 35%">-->
@@ -132,18 +135,29 @@
       localStorage.clear()
       store.clear()
       router.push({path: "/login"})
+    } else if(command==="profile"){
+      router.push({path: "/profile"})
     }
   }
 
   const route = useRoute()
   let activePage = ref('')
+
   //处理刷新页面时,菜单项和内容不匹配的问题
   onMounted(()=>{
-    let path = route.path.split('/')[2].charAt(0).toUpperCase()+route.path.split('/')[2].slice(1)
-    if(path === 'Assignment'){
-      activePage.value = 'MyWork'
-    }else {
-      activePage.value = path
+    let path = route.path.split('/')[1]
+    if(path == "profile"){
+      activePage.value = null
+    }
+
+    //找到/home/后的名字
+    if(route.path.split('/')[1] == "home"){
+      path = route.path.split('/')[2].charAt(0).toUpperCase()+route.path.split('/')[2].slice(1)
+      if(path === 'Assignment'){
+        activePage.value = 'MyWork'
+      }else {
+        activePage.value = path
+      }
     }
   })
 </script>

+ 49 - 42
src/router/index.ts

@@ -4,6 +4,7 @@ import {useStore} from "@/store";
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
   routes: [
+    // 定义公共页面
     {
       path: "/404",
       component: () => import("@/views/404.vue")
@@ -12,6 +13,8 @@ const router = createRouter({
       path: "/:catchAll(.*)",
       redirect: "/404"
     },
+
+    // 登录与注册
     {
       path: "/",
       redirect: "/login"
@@ -26,54 +29,19 @@ const router = createRouter({
       name: 'register', 
       component: () => import('../views/LoginPage/RegisterPage.vue')
     },
-    {
-      path: '/course',
-      name: 'course',
-      component: () => import('../views/CoursePage/CoursePage.vue')
-    },
-    {
-      path: "/admin/login",
-      name: 'adminLogin',
-      component: () => import("../views/AdminPage/LoginPage/AdminLoginPage.vue"),
-    },
-    {
-      path: "/manager",
-      name: "manager",
-      // redirect: '/manager/course',
-      component: () => import("../layout/AdminLayout/AdminLayout.vue"),
-      children: [
-        {
-          path: "course",
-          name: "courseManage",
-          component: () => import("../views/AdminPage/CourseManage/CourseManage.vue"),
-          meta: {
-            roles: ['ADMIN']
-          }
-        },
-        {
-          path: "user",
-          name: "userManage",
-          component: () => import("../views/AdminPage/UserManage/UserManage.vue"),
-          meta: {
-            roles: ['ADMIN']
-          }
-        },
-        {
-          path: "file",
-          name: "fileManage",
-          component: () => import("../views/AdminPage/FileManage/FileManage.vue"),
-          meta: {
-            roles: ['ADMIN']
-          }
-        },
-      ]
-    },
+
+    // 用户相关界面
     {
       path: '/home',
       name: 'home',
       redirect: '/home/courseSquare',
       component: () => import('../layout/Layout/Layout.vue'),
       children: [
+        {
+          path: "/profile",
+          name: "profile",
+          component: () => import('@/views/Profile.vue')
+        },
         {
           path: 'courseSquare',
           name: 'courseSquare',
@@ -134,6 +102,45 @@ const router = createRouter({
         },
       ]
     },
+
+    // 管理员相关界面
+    {
+      path: "/admin/login",
+      name: 'adminLogin',
+      component: () => import("../views/AdminPage/LoginPage/AdminLoginPage.vue"),
+    },
+    {
+      path: "/manager",
+      name: "manager",
+      // redirect: '/manager/course',
+      component: () => import("../layout/AdminLayout/AdminLayout.vue"),
+      children: [
+        {
+          path: "course",
+          name: "courseManage",
+          component: () => import("../views/AdminPage/CourseManage/CourseManage.vue"),
+          meta: {
+            roles: ['ADMIN']
+          }
+        },
+        {
+          path: "user",
+          name: "userManage",
+          component: () => import("../views/AdminPage/UserManage/UserManage.vue"),
+          meta: {
+            roles: ['ADMIN']
+          }
+        },
+        {
+          path: "file",
+          name: "fileManage",
+          component: () => import("../views/AdminPage/FileManage/FileManage.vue"),
+          meta: {
+            roles: ['ADMIN']
+          }
+        },
+      ]
+    },
   ]
 })
 

+ 196 - 0
src/views/Profile.vue

@@ -0,0 +1,196 @@
+<template>
+  <div class="personal-center">
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span style="font-size: 25px; font-weight: bold">个人中心</span>
+      </div>
+      <el-row :gutter="20">
+        <el-col :span="12" class="main-info">
+          <el-avatar :size="100" :src="user.userAvatar" />
+          <div>{{ user.name }}</div>
+          <div>{{ user.officialNumber }}</div>
+          <div>{{ user.officialEmail }}</div>
+        </el-col>
+        <el-col :span="12">
+          <el-descriptions title="账户信息" :column="1">
+            <template #extra>
+              <el-button type="primary" @click="visible=true">修改信息</el-button>
+            </template>
+            <el-descriptions-item label="用户名">{{ user.englishName }}</el-descriptions-item>
+            <el-descriptions-item label="性别">{{ user.gender }}</el-descriptions-item>
+            <el-descriptions-item label="注册时间">{{ user.createTime }}</el-descriptions-item>
+            <el-descriptions-item label="手机号">{{ user.phone }}</el-descriptions-item>
+            <el-descriptions-item label="生日">{{ user.birthday }}</el-descriptions-item>
+          </el-descriptions>
+        </el-col>
+      </el-row>
+    </el-card>
+  </div>
+
+  <el-dialog v-model="visible" title="编辑">
+    <el-form-item label="头像">
+      <el-upload
+          ref="uploadRef"
+          drag
+          action="/api/file"
+          multiple
+          v-model:file-list="fileList"
+          :limit="1"
+          :on-success="handleSuccess"
+          :on-error="handleError"
+          :on-exceed="handleExceed"
+          :on-change="handleChange"
+          list-type="picture-card"
+          accept=".png, .jpg"
+          :auto-upload="false"
+      >
+<!--        <el-icon class="el-icon&#45;&#45;upload"><upload-filled /></el-icon>-->
+        <div class="el-upload__text">
+          拖拽上传或<em>点击此处上传</em>
+        </div>
+<!--        <el-icon><Plus /></el-icon>-->
+        <template #tip>
+          <div class="el-upload__tip">
+            jpg/png 文件不大于 500kb
+          </div>
+        </template>
+      </el-upload>
+    </el-form-item>
+    <el-form :model="user" label-width="auto">
+      <el-form-item label="姓名" prop="courseName">
+        <el-input v-model="user.name" placeholder="请输入名称"></el-input>
+      </el-form-item>
+      <el-form-item label="学号" prop="courseName">
+        <el-input v-model="user.officialNumber" placeholder="请输入名称" disabled></el-input>
+      </el-form-item>
+      <el-form-item label="邮箱" prop="courseName">
+        <el-input v-model="user.officialEmail" placeholder="请输入名称" disabled></el-input>
+      </el-form-item>
+      <el-form-item label="用户名" prop="courseName">
+        <el-input v-model="user.englishName" placeholder="请输入名称"></el-input>
+      </el-form-item>
+      <el-form-item label="性别" prop="courseName">
+        <el-input v-model="user.gender" placeholder="请输入名称"></el-input>
+      </el-form-item>
+      <el-form-item label="手机号" prop="courseName">
+        <el-input v-model="user.phone" placeholder="请输入名称"></el-input>
+      </el-form-item>
+      <el-form-item label="生日" prop="courseName">
+        <el-input v-model="user.birthday" placeholder="请输入名称"></el-input>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="visible = false">取消</el-button>
+        <el-button type="primary" @click="submit">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+  import {onMounted, reactive, ref} from 'vue';
+  import {
+    ElCard,
+    ElRow,
+    ElCol,
+    ElAvatar,
+    ElButton,
+    ElDescriptions,
+    ElDescriptionsItem,
+    ElTable,
+    ElTableColumn,
+    ElMessage, type UploadUserFile, type UploadProps, type UploadFile, type UploadFiles
+  } from 'element-plus';
+    import useApis from "@/apis";
+    import {useStore} from "@/store";
+  import type {IUser} from "@/types/user";
+  import {Plus} from "@element-plus/icons-vue";
+
+  const apis = useApis()
+  const store = useStore()
+
+  const user = reactive<IUser>({} as IUser)
+  let visible = ref(false)
+  const uploadRef = ref()
+  // 用于编辑头像展示预览图片
+  const fileList = ref<UploadUserFile[]>([])
+
+  const fetchUserData = () => {
+    apis.findUserById(store.user.id)
+        .then((res:any) => {
+          Object.assign(user, res.data.data.records[0])
+        })
+        .catch((err:any) => {
+          ElMessage({
+            message: "获取用户信息失败:"+err,
+            type: "error"
+          })
+        })
+  }
+
+  const submit = () => {
+    alert("TODO")
+  }
+
+const handleSuccess: UploadProps['onSuccess'] = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  console.log("上传成功", response.data)
+  user.userAvatar = response.data
+}
+
+const handleError: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  console.log("上传失败", error)
+  console.log(error, uploadFile, uploadFiles)
+}
+
+const handleExceed = (files, fileList) => {
+  // console.log(files)
+  uploadRef.value.clearFiles()  //清空上传文件(限制一个,所以直接清空即可)
+  const file = files[0]
+  uploadRef.value.handleStart(file)  //重新上传
+}
+
+//选择文件
+const handleChange = (file,fileList) => {
+  // console.log(file)
+  const fileImgType = file.name.match(/\.([^\.]+)$/)[1];  //匹配文件格式(最后一个'.'后的格式)或者匹配file.raw.type
+  const isImageType = ['png','jpg'];
+  const isLt5KB = file.size / 1024  < 500;  //判断图片格式与大小
+  if (isImageType.indexOf(fileImgType)==-1) {
+    ElMessage.error('文件仅支持png、jpg格式')  //限制文件类型
+    uploadRef.value.clearFiles()  //清空上传文件
+    return false;
+  }
+  if (!isLt5KB) {
+    ElMessage.error('文件不能超过500kb!')  //限制文件大小
+    uploadRef.value.clearFiles()  //清空上传文件
+    return false;
+  }
+  apis.uploadFile(file.raw)
+      .then((res) => {
+        user.userAvatar = res.data.data
+      })
+      .catch((err) => {
+        console.log(err)
+      })
+}
+
+  onMounted(() => {
+    fetchUserData()
+  })
+</script>
+
+<style scoped>
+.personal-center {
+  padding: 20px;
+}
+
+.box-card {
+  width: 1000px;
+  margin: 0 auto;
+}
+
+.main-info div {
+  margin: 20px 0
+}
+</style>