Browse Source

1.个人中心。

jiaxiaoqiang 1 year ago
parent
commit
61b5536989

+ 13 - 11
src/api/system/user/index.ts

@@ -12,14 +12,20 @@ export function getUserInfoApi(): AxiosPromise {
   });
 }
 
+// 新增的获取用户详细信息的API
+export function getUserDetailApi(p: object): AxiosPromise {
+  return request({
+    url: "/api/v1/sys/user/get",
+    method: "post",
+    data: p,
+  });
+}
 /**
  * 获取用户分页列表
  *
  * @param queryParams
  */
-export function getUserList(
-    queryParams: any
-): AxiosPromise<any[]> {
+export function getUserList(queryParams: any): AxiosPromise<any[]> {
   return request({
     url: "/api/v1/sys/user/list",
     method: "post",
@@ -27,9 +33,7 @@ export function getUserList(
   });
 }
 
-export function getPostOptions(
-    queryParams?: any
-): AxiosPromise<OptionType[]> {
+export function getPostOptions(queryParams?: any): AxiosPromise<OptionType[]> {
   return request({
     url: "/api/v1/sys/post/list",
     method: "post",
@@ -42,9 +46,7 @@ export function getPostOptions(
  *
  * @param queryParams
  */
-export function getUserPage(
-  queryParams: any
-): AxiosPromise<PageResult<any[]>> {
+export function getUserPage(queryParams: any): AxiosPromise<PageResult<any[]>> {
   return request({
     url: "/api/v1/sys/user/page",
     method: "post",
@@ -75,7 +77,7 @@ export function updateUser(id: number, data: any) {
   return request({
     url: "/api/v1/sys/user/update",
     method: "post",
-    data: data,
+    data: { id: id, ...data },
   });
 }
 
@@ -102,7 +104,7 @@ export function deleteUsers(ids: any) {
   return request({
     url: "/api/v1/sys/user/del",
     method: "post",
-    data: {id: ids}
+    data: { id: ids },
   });
 }
 

+ 11 - 5
src/components/Upload/SingleUpload.vue

@@ -22,6 +22,7 @@ import {
   UploadFile,
   UploadProps,
 } from "element-plus";
+import { watch } from "vue";
 
 const props = defineProps({
   modelValue: {
@@ -34,9 +35,16 @@ const props = defineProps({
   },
 });
 
-const emit = defineEmits(["update:modelValue"]);
+const emit = defineEmits(["update:modelValue", "finished"]);
 const imgUrl = useVModel(props, "modelValue", emit);
-const photoSource = ref<string>("");
+const photoSource = ref<string>();
+
+watch(
+  () => props.modelValue,
+  (newVal) => {
+    photoSource.value = import.meta.env.VITE_APP_UPLOAD_URL + props.modelValue;
+  }
+);
 
 /**
  * 自定义图片上传
@@ -45,11 +53,9 @@ const photoSource = ref<string>("");
  */
 async function uploadFile(options: UploadRequestOptions): Promise<any> {
   const res: any = await uploadFileApi(options.file);
-  //绝对路径
-  // imgUrl.value = import.meta.env.VITE_APP_UPLOAD_URL + res.data;
-  //使用相对路径
   imgUrl.value = res.data.fileUrl + "";
   photoSource.value = import.meta.env.VITE_APP_UPLOAD_URL + res.data.fileUrl;
+  emit("finished");
 }
 
 /**

+ 103 - 70
src/layout/components/NavBar/components/NavbarRight.vue

@@ -2,11 +2,11 @@
   <div class="flex">
     <template v-if="!isMobile">
       <!--全屏 -->
-      <div class="setting-item" @click="toggle">
-        <svg-icon
-          :icon-class="isFullscreen ? 'fullscreen-exit' : 'fullscreen'"
-        />
-      </div>
+      <!--      <div class="setting-item" @click="toggle">-->
+      <!--        <svg-icon-->
+      <!--          :icon-class="isFullscreen ? 'fullscreen-exit' : 'fullscreen'"-->
+      <!--        />-->
+      <!--      </div>-->
 
       <!--      &lt;!&ndash; 布局大小 &ndash;&gt;
       <el-tooltip
@@ -24,17 +24,37 @@
     <!-- 用户头像 -->
     <el-dropdown class="setting-item" trigger="click">
       <div class="flex-center h100% p10px">
-        <img :src="userStore.user.avatar + '?imageView2/1/w/80/h/80'"
-          class="rounded-full mr-10px w24px w24px" />
-        <el-badge v-if="unReadMessageNum > 0" :value="unReadMessageNum" :max="10">
+        <img
+          v-if="userStore.user.avatar"
+          :src="getHeader"
+          object-fit="cover"
+          style="
+            width: 30px;
+            height: 30px;
+            border-radius: 15px;
+            margin-right: 10px;
+          "
+        />
+        <el-badge
+          v-if="unReadMessageNum > 0"
+          :value="unReadMessageNum"
+          :max="10"
+        >
           <span>{{ userStore.user.username }}</span>
         </el-badge>
         <span v-else>{{ userStore.user.username }}</span>
       </div>
       <template #dropdown>
         <el-dropdown-menu>
+          <el-dropdown-item divided @click="userCenter">
+            个人中心
+          </el-dropdown-item>
           <el-dropdown-item divided @click="openMessageDialog">
-            <el-badge v-if="unReadMessageNum > 0" :value="unReadMessageNum" :max="10">
+            <el-badge
+              v-if="unReadMessageNum > 0"
+              :value="unReadMessageNum"
+              :max="10"
+            >
               <span>消息中心</span>
             </el-badge>
             <span v-else>消息中心</span>
@@ -48,47 +68,46 @@
 
     <!-- 设置 -->
     <template v-if="defaultSettings.showSettings">
-      <div class="setting-item" @click="settingStore.settingsVisible = true">
-        <svg-icon icon-class="setting" />
-      </div>
+      <!--      <div class="setting-item" @click="settingStore.settingsVisible = true">-->
+      <!--        <svg-icon icon-class="setting" />-->
+      <!--      </div>-->
     </template>
 
     <el-dialog
-        v-model="dialog.visible"
-        :title="dialog.title"
-        width="980px"
-        min-height="800px"
-        @close="dialog.visible = false">
+      v-model="dialog.visible"
+      :title="dialog.title"
+      width="980px"
+      min-height="800px"
+      @close="dialog.visible = false"
+    >
       <el-tabs type="border-card" @tab-click="clickTab">
         <el-tab-pane label="通知消息">
           <div class="mainContentBox">
             <avue-crud
-                :option="options"
-                v-model:page="page"
-                :table-loading="loading"
-                @size-change="handleQuery"
-                @current-change="handleQuery"
-                :data="pageData"
-            >
-            </avue-crud>
+              :option="options"
+              v-model:page="page"
+              :table-loading="loading"
+              @size-change="handleQuery"
+              @current-change="handleQuery"
+              :data="pageData"
+            />
           </div>
         </el-tab-pane>
         <el-tab-pane label="系统消息">
           <div class="mainContentBox">
             <avue-crud
-                :option="options"
-                v-model:page="page1"
-                :table-loading="loading"
-                @size-change="handleQuery1"
-                @current-change="handleQuery1"
-                :data="pageData1"
-            >
-            </avue-crud>
+              :option="options"
+              v-model:page="page1"
+              :table-loading="loading"
+              @size-change="handleQuery1"
+              @current-change="handleQuery1"
+              :data="pageData1"
+            />
           </div>
         </el-tab-pane>
       </el-tabs>
-
     </el-dialog>
+    <UserCenter ref="userCenterRef" />
   </div>
 </template>
 <script setup>
@@ -100,14 +119,20 @@ import {
 } from "@/store";
 import defaultSettings from "@/settings";
 import { DeviceEnum } from "@/enums/DeviceEnum";
-import {userMessageNum,userMessage,readMessage} from "@/api/system/message"
+import UserCenter from "@/views/login/userCenter.vue";
+import { userMessageNum, userMessage, readMessage } from "@/api/system/message";
 const appStore = useAppStore();
 const options = ref({});
 const loading = ref(false);
 const tagsViewStore = useTagsViewStore();
 const userStore = useUserStore();
 const settingStore = useSettingsStore();
-const unReadMessageNum = ref(null)
+const unReadMessageNum = ref(null);
+const getHeader = computed(() => {
+  let url = import.meta.env.VITE_APP_UPLOAD_URL + userStore.user.avatar;
+  console.log("url", url);
+  return import.meta.env.VITE_APP_UPLOAD_URL + userStore.user.avatar;
+});
 const route = useRoute();
 const router = useRouter();
 const page = ref({ total: 0, currentPage: 1, pageSize: 10 });
@@ -118,22 +143,22 @@ const dialog = reactive({
   title: "消息管理",
   visible: false,
   type: "0",
-  state: "0"
+  state: "0",
 });
 
-const openMessageDialog = ()=>{
-  handleQuery()
-  dialog.visible = true
-}
+const openMessageDialog = () => {
+  handleQuery();
+  dialog.visible = true;
+};
 const isMobile = computed(() => appStore.device === DeviceEnum.MOBILE);
 
 const { isFullscreen, toggle } = useFullscreen();
 
-const checkUnReadMessageNum =() =>{
-  userMessageNum({}).then((data)=>{
-    unReadMessageNum.value = data.data
-  })
-}
+const checkUnReadMessageNum = () => {
+  userMessageNum({}).then((data) => {
+    unReadMessageNum.value = data.data;
+  });
+};
 options.value = {
   border: true,
   align: "center",
@@ -149,8 +174,7 @@ options.value = {
       label: "标题",
       prop: "title",
       width: 150,
-      overHidden: true
-
+      overHidden: true,
     },
     {
       label: "内容",
@@ -164,8 +188,8 @@ options.value = {
     },
     {
       label: "时间",
-      prop: "created"
-    }
+      prop: "created",
+    },
   ],
 };
 /**
@@ -202,28 +226,32 @@ const handleQuery = (params, done) => {
     pageSize: page.value.pageSize,
     pageNo: page.value.currentPage,
   };
-  queryMessageList(querySearch,page,pageData,done)
+  queryMessageList(querySearch, page, pageData, done);
 };
-const queryMessageList = (searchParams,pageObj,pageDataList,done) =>{
+const queryMessageList = (searchParams, pageObj, pageDataList, done) => {
   userMessage(searchParams)
-      .then(({ data }) => {
-        pageDataList.value = data.records;
-        pageObj.value.total = data.totalCount;
-        pageObj.value.currentPage = data.pageNo;
-        pageObj.value.pageSize = data.pageSize;
+    .then(({ data }) => {
+      pageDataList.value = data.records;
+      pageObj.value.total = data.totalCount;
+      pageObj.value.currentPage = data.pageNo;
+      pageObj.value.pageSize = data.pageSize;
 
-        if(data.records){
-          let unreadIds = data.records.filter((item)=>item.readState === '0').map((mes)=>mes.id)
-          if(unreadIds.length > 0){
-            readMessage(unreadIds).then((data)=>{})
-          }
+      if (data.records) {
+        let unreadIds = data.records
+          .filter((item) => item.readState === "0")
+          .map((mes) => mes.id);
+        if (unreadIds.length > 0) {
+          readMessage(unreadIds).then((data) => {});
         }
-      })
-      .finally(() => {
-        loading.value = false;
-        if (done) { done(); }
-      });
-}
+      }
+    })
+    .finally(() => {
+      loading.value = false;
+      if (done) {
+        done();
+      }
+    });
+};
 const handleQuery1 = (params, done) => {
   loading.value = true;
   const querySearch = {
@@ -231,12 +259,17 @@ const handleQuery1 = (params, done) => {
     pageSize: page1.value.pageSize,
     pageNo: page1.value.currentPage,
   };
-  queryMessageList(querySearch,page1,pageData1,done)
+  queryMessageList(querySearch, page1, pageData1, done);
 };
 
 onMounted(() => {
-  checkUnReadMessageNum()
+  checkUnReadMessageNum();
 });
+
+const userCenterRef = ref();
+const userCenter = () => {
+  userCenterRef.value && userCenterRef.value?.show();
+};
 </script>
 <style lang="scss" scoped>
 .setting-item {

+ 1 - 0
src/store/modules/user.ts

@@ -48,6 +48,7 @@ export const useUserStore = defineStore("user", () => {
           user.value.username = data.userName;
           user.value.roles = data.roles;
           user.value.deptId = data.deptId;
+          user.value.avatar = data.avatar;
 
           isGetAuth.value = true;
 

+ 133 - 0
src/views/login/userCenter.vue

@@ -0,0 +1,133 @@
+<template>
+  <el-dialog title="个人中心" v-model="visible" width="1200px">
+    <el-tabs v-model="activeName" class="demo-tabs">
+      <el-tab-pane label="基本资料" name="first">
+        <el-form label-position="right" label-width="60px" :model="userInfo">
+          <el-form-item label="头像">
+            <SingleUpload v-model="headUrl" @finished="uploadHeadFinish" />
+          </el-form-item>
+          <el-form-item label="昵称">
+            <div class="label" v-text="userInfo?.nickName"></div>
+          </el-form-item>
+          <el-form-item label="电话">
+            <div class="label" v-text="userInfo?.phone"></div>
+          </el-form-item>
+          <el-form-item label="邮箱">
+            <div class="label" v-text="userInfo?.email"></div>
+          </el-form-item>
+          <el-form-item label="部门">
+            <div class="label" v-text="userInfo?.deptNames"></div>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+      <el-tab-pane label="修改密码" name="second">
+        <el-form
+          ref="passwordFormRef"
+          :model="passwordForm"
+          status-icon
+          :rules="rules"
+          label-width="auto"
+          class="demo-ruleForm"
+        >
+          <el-form-item label="旧密码" prop="oldPassword">
+            <el-input
+              v-model="passwordForm.oldPassword"
+              type="password"
+              autocomplete="off"
+            />
+          </el-form-item>
+          <el-form-item label="新密码" prop="password">
+            <el-input
+              v-model="passwordForm.password"
+              type="password"
+              autocomplete="off"
+            />
+          </el-form-item>
+          <el-form-item label="确认密码" prop="confirmPassword">
+            <el-input type="password" v-model="passwordForm.confirmPassword" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="submitForm"> 修改密码 </el-button>
+            <el-button @click="resetForm">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+    </el-tabs>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import { getUserDetailApi, updateUser } from "@/api/system/user/index";
+import { useUserStoreHook } from "@/store/modules/user";
+import SingleUpload from "@/components/Upload/SingleUpload.vue";
+
+const userStore = useUserStoreHook();
+console.log(userStore.user);
+const activeName = ref("first");
+const visible = ref(false);
+const userInfo = ref<any>({});
+const headUrl = ref("");
+
+const show = () => {
+  visible.value = true;
+  getUserDetailApi({ id: userStore.user.userId }).then((res) => {
+    userInfo.value = res.data;
+    headUrl.value = res.data.avatar;
+  });
+};
+
+defineExpose({ show });
+
+const uploadHeadFinish = () => {
+  updateUser(userStore.user.userId, { avatar: headUrl.value }).then(() => {
+    ElMessage.success("头像上传成功");
+  });
+};
+// =============== 修改密码相关
+const passwordFormRef = ref();
+const passwordForm = ref({
+  oldPassword: "",
+  password: "",
+  confirmPassword: "",
+});
+const validatePass = (rule: any, value: any, callback: any) => {
+  if (value === "") {
+    callback(new Error("请输入"));
+  } else if (value !== passwordForm.value.password) {
+    callback(new Error("两次密码不一致,请重新输入!"));
+  } else {
+    callback();
+  }
+};
+const rules = reactive({
+  oldPassword: [{ required: true, trigger: "blur" }],
+  password: [{ required: true, trigger: "blur" }],
+  confirmPassword: [
+    { required: true, validator: validatePass, trigger: "blur" },
+  ],
+});
+
+const submitForm = () => {
+  passwordFormRef.value.validate((valid: boolean) => {
+    if (valid) {
+      updateUser(userStore.user.userId, {
+        password: passwordForm.value.password,
+      }).then(() => {
+        ElMessage.success("密码修改成功");
+        visible.value = false;
+        passwordFormRef.value.resetFields();
+      });
+    }
+  });
+};
+
+const resetForm = () => {
+  passwordFormRef.value.resetFields();
+};
+</script>
+
+<style scoped lang="scss">
+.lable {
+  font-weight: bolder;
+}
+</style>