fix: 🐛 头像更新问题

This commit is contained in:
H0nGzA1
2023-04-11 22:43:33 +08:00
parent 2f04f22904
commit 38494edea5
6 changed files with 70 additions and 34 deletions

View File

@@ -1,9 +1,5 @@
from rest_framework import serializers from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.parsers import FileUploadParser, FormParser, MultiPartParser
from dvadmin.system.models import FileList from dvadmin.system.models import FileList
from dvadmin.utils.json_response import SuccessResponse
from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet from dvadmin.utils.viewset import CustomModelViewSet

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="user-info-head" @click="editCropper()"> <div class="user-info-head" @click="editCropper()">
<el-avatar :size="100" :src="options.img" /> <el-avatar :size="100" :src="options.img" />
<el-dialog :title="title" v-model="open" width="600px" append-to-body @opened="modalOpened" @close="closeDialog"> <el-dialog :title="title" v-model="dialogVisiable" width="600px" append-to-body @opened="modalOpened" @close="closeDialog">
<el-row> <el-row>
<el-col class="flex justify-center"> <el-col class="flex justify-center">
<vue-cropper <vue-cropper
@@ -48,7 +48,7 @@
import 'vue-cropper/dist/index.css'; import 'vue-cropper/dist/index.css';
import { VueCropper } from 'vue-cropper'; import { VueCropper } from 'vue-cropper';
import { useUserInfo } from '/@/stores/userInfo'; import { useUserInfo } from '/@/stores/userInfo';
import { getCurrentInstance, nextTick, reactive, ref } from 'vue'; import { getCurrentInstance, nextTick, reactive, ref, computed, onMounted, defineExpose } from 'vue';
import { base64ToFile } from '/@/utils/tools'; import { base64ToFile } from '/@/utils/tools';
const userStore = useUserInfo(); const userStore = useUserInfo();
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
@@ -57,10 +57,26 @@ const open = ref(false);
const visible = ref(false); const visible = ref(false);
const title = ref('修改头像'); const title = ref('修改头像');
const emit = defineEmits(['uploadImg']); const emit = defineEmits(['uploadImg']);
const props = defineProps({
modelValue: {
type: Boolean,
default: false,
required: true,
},
});
const dialogVisiable = computed({
get() {
return props.modelValue;
},
set(newVal) {
emit('update:modelValue', newVal);
},
});
//图片裁剪数据 //图片裁剪数据
const options = reactive({ const options = reactive({
img: userStore.userInfos.avatar, // 裁剪图片的地址 img: userStore.userInfos.avatar, // 裁剪图片的地址
fileName: '',
autoCrop: true, // 是否默认生成截图框 autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度 autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度 autoCropHeight: 200, // 默认生成截图框高度
@@ -70,7 +86,7 @@ const options = reactive({
/** 编辑头像 */ /** 编辑头像 */
function editCropper() { function editCropper() {
open.value = true; dialogVisiable.value = true;
} }
/** 打开弹出层结束时的回调 */ /** 打开弹出层结束时的回调 */
function modalOpened() { function modalOpened() {
@@ -102,6 +118,7 @@ function beforeUpload(file) {
reader.readAsDataURL(file); reader.readAsDataURL(file);
reader.onload = () => { reader.onload = () => {
options.img = reader.result; options.img = reader.result;
options.fileName = file.name;
}; };
} }
} }
@@ -113,7 +130,7 @@ function uploadImg() {
img.src = data; img.src = data;
img.onload = async () => { img.onload = async () => {
let _data = compress(img); let _data = compress(img);
const imgFile = base64ToFile(_data, 'testname'); const imgFile = base64ToFile(_data, options.fileName);
emit('uploadImg', imgFile); emit('uploadImg', imgFile);
}; };
}); });
@@ -138,9 +155,17 @@ function compress(img) {
/** 关闭窗口 */ /** 关闭窗口 */
function closeDialog() { function closeDialog() {
options.img = userStore.userInfos.avatar;
options.visible = false; options.visible = false;
options.img = userStore.userInfos.avatar;
} }
const updateAvatar = (img) => {
options.img = img;
};
defineExpose({
updateAvatar,
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -39,7 +39,7 @@
<div class="layout-navbars-breadcrumb-user-icon"> <div class="layout-navbars-breadcrumb-user-icon">
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false"> <el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
<template #reference> <template #reference>
<el-badge :value="messageCenter.unread" :hidden="messageCenter.unread===0"> <el-badge :value="messageCenter.unread" :hidden="messageCenter.unread === 0">
<el-icon :title="$t('message.user.title4')"> <el-icon :title="$t('message.user.title4')">
<ele-Bell /> <ele-Bell />
</el-icon> </el-icon>
@@ -59,7 +59,7 @@
</div> </div>
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick"> <el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
<span class="layout-navbars-breadcrumb-user-link"> <span class="layout-navbars-breadcrumb-user-link">
<img :src="userInfos.photo" class="layout-navbars-breadcrumb-user-link-photo mr5" /> <img :src="userInfos.avatar" class="layout-navbars-breadcrumb-user-link-photo mr5" />
{{ userInfos.userName === '' ? 'common' : userInfos.userName }} {{ userInfos.userName === '' ? 'common' : userInfos.userName }}
<el-icon class="el-icon--right"> <el-icon class="el-icon--right">
<ele-ArrowDown /> <ele-ArrowDown />
@@ -68,7 +68,7 @@
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item> <el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
<el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item> <el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
<el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item> <el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item>
<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item> <el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
@@ -208,8 +208,8 @@ onMounted(() => {
}); });
//消息中心的未读数量 //消息中心的未读数量
import {messageCenterStore} from "/@/stores/messageCenter"; import { messageCenterStore } from '/@/stores/messageCenter';
const messageCenter = messageCenterStore() const messageCenter = messageCenterStore();
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,9 +1,7 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import Cookies from 'js-cookie';
import { UserInfosStates } from './interface'; import { UserInfosStates } from './interface';
import { Session } from '/@/utils/storage'; import { Session } from '/@/utils/storage';
import { request } from '../utils/service'; import { request } from '../utils/service';
/** /**
* 用户信息 * 用户信息
* @methods setUserInfos 设置用户信息 * @methods setUserInfos 设置用户信息
@@ -30,6 +28,18 @@ export const useUserInfo = defineStore('userInfo', {
}, },
}), }),
actions: { actions: {
async updateUserInfos() {
let userInfos: any = await this.getApiUserInfo();
this.userInfos.userName = userInfos.data.name;
this.userInfos.avatar = userInfos.data.avatar;
this.userInfos.name = userInfos.data.name;
this.userInfos.email = userInfos.data.email;
this.userInfos.mobile = userInfos.data.mobile;
this.userInfos.gender = userInfos.data.gender;
this.userInfos.dept_info = userInfos.data.dept_info;
this.userInfos.role_info = userInfos.data.role_info;
Session.set('userInfo', this.userInfos);
},
async setUserInfos() { async setUserInfos() {
// 存储用户信息到浏览器缓存 // 存储用户信息到浏览器缓存
if (Session.get('userInfo')) { if (Session.get('userInfo')) {
@@ -37,8 +47,7 @@ export const useUserInfo = defineStore('userInfo', {
} else { } else {
let userInfos: any = await this.getApiUserInfo(); let userInfos: any = await this.getApiUserInfo();
this.userInfos.userName = userInfos.data.name; this.userInfos.userName = userInfos.data.name;
this.userInfos.avatar = this.userInfos.avatar = userInfos.data.avatar;
userInfos.data.avatar || 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500';
this.userInfos.name = userInfos.data.name; this.userInfos.name = userInfos.data.name;
this.userInfos.email = userInfos.data.email; this.userInfos.email = userInfos.data.email;
this.userInfos.mobile = userInfos.data.mobile; this.userInfos.mobile = userInfos.data.mobile;

View File

@@ -67,6 +67,11 @@ export function errorCreate(msg: any, notification = true) {
// throw error; // throw error;
} }
/**
* @description base64转file
* @param {String} base64 base64字符串
* @param {String} fileName 文件名
*/
export function base64ToFile(base64: any, fileName: string) { export function base64ToFile(base64: any, fileName: string) {
// 将base64按照 , 进行分割 将前缀 与后续内容分隔开 // 将base64按照 , 进行分割 将前缀 与后续内容分隔开
let data = base64.split(','); let data = base64.split(',');

View File

@@ -6,9 +6,7 @@
<el-card shadow="hover" header="个人信息"> <el-card shadow="hover" header="个人信息">
<div class="personal-user"> <div class="personal-user">
<div class="personal-user-left"> <div class="personal-user-left">
<!-- <el-avatar :size="100" v-if="state.personalForm.avatar" :src="state.personalForm.avatar" /> --> <avatarSelector v-model="selectImgVisible" @uploadImg="uploadImg" ref="avatarSelectorRef"></avatarSelector>
<!-- <el-avatar :size="100" v-else src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" /> -->
<avatarSelector @uploadImg="uploadImg"></avatarSelector>
</div> </div>
<div class="personal-user-right"> <div class="personal-user-right">
<el-row> <el-row>
@@ -181,11 +179,11 @@ import { getBaseURL } from '/@/utils/baseUrl';
import { Session } from '/@/utils/storage'; import { Session } from '/@/utils/storage';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useUserInfo } from '/@/stores/userInfo'; import { useUserInfo } from '/@/stores/userInfo';
const userStore = useUserInfo(); import { successMessage } from '/@/utils/message';
// 头像裁剪组件 // 头像裁剪组件
const avatarSelector = defineAsyncComponent(() => import('/@/components/avatarSelector/index.vue')); const avatarSelector = defineAsyncComponent(() => import('/@/components/avatarSelector/index.vue'));
const avatarSelectorRef = ref(null);
// 当前时间提示语 // 当前时间提示语
const currentTime = computed(() => { const currentTime = computed(() => {
return formatAxis(new Date()); return formatAxis(new Date());
@@ -195,13 +193,9 @@ const rules = reactive({
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }], name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }], mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }],
}); });
// 定义变量内容
const uploadAvatar = reactive({ let selectImgVisible = ref(false);
action: getBaseURL() + 'api/system/file/',
headers: {
Authorization: 'JWT ' + Session.get('token'),
},
});
const state = reactive<PersonalState>({ const state = reactive<PersonalState>({
newsInfoList: [], newsInfoList: [],
personalForm: { personalForm: {
@@ -345,13 +339,20 @@ const settingPassword = () => {
}; };
const uploadImg = (data: any) => { const uploadImg = (data: any) => {
console.log(data);
let formdata = new FormData(); let formdata = new FormData();
formdata.append('key', 'test_file');
formdata.append('file', data); formdata.append('file', data);
api.uploadAvatar(formdata).then((res: any) => { api.uploadAvatar(formdata).then((res: any) => {
// userStore.setUserInfos() if (res.code === 2000) {
console.log(res); selectImgVisible.value = false;
state.personalForm.avatar = getBaseURL() + res.data.url;
api.updateUserInfo(state.personalForm).then((res: any) => {
successMessage('更新成功');
getUserInfo();
useUserInfo().updateUserInfos();
// @ts-ignore
avatarSelectorRef.value.updateAvatar(state.personalForm.avatar);
});
}
}); });
}; };
</script> </script>