提交
This commit is contained in:
1 parent
375a2c8df7
commit
ba7b7b8497
9 files changed
+343
-57
No files matched your search
@@ -37,6 +37,7 @@ export interface UserVO extends BaseEntity {
|
||||
phonenumber: string;
|
||||
sex: string;
|
||||
avatar: string;
|
||||
avatarUrl?: string;
|
||||
status: string;
|
||||
delFlag: string;
|
||||
loginIp: string;
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
<div class="avatar-container">
|
||||
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="userStore.avatar" class="user-avatar" />
|
||||
<ImagePreview v-if="userStore.avatar" class="user-avatar" :src="userStore.avatar" :width="24" :height="24" :is-oss-id="avatarIsOssId" />
|
||||
<img v-else :src="userStore.avatar" class="user-avatar" />
|
||||
<el-icon><caret-bottom /></el-icon>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
@@ -98,9 +99,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ComponentInternalInstance, computed, getCurrentInstance, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Hamburger from '@/components/Hamburger/index.vue';
|
||||
import TopNav from '@/components/TopNav/index.vue';
|
||||
import SearchMenu from './TopBar/search.vue';
|
||||
import ImagePreview from '@/components/ImagePreview/index.vue';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
@@ -129,6 +133,15 @@ const dynamic = ref(false);
|
||||
const tenantEnabled = ref(true);
|
||||
// 搜索菜单
|
||||
const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
|
||||
const avatarIsOssId = computed(() => {
|
||||
const avatar = userStore.avatar;
|
||||
if (!avatar) {
|
||||
return false;
|
||||
}
|
||||
const isHttp = /^https?:\/\//i.test(avatar);
|
||||
const isAbsolutePath = avatar.startsWith('/');
|
||||
return !isHttp && !isAbsolutePath;
|
||||
});
|
||||
|
||||
const openSearchMenu = () => {
|
||||
searchMenuRef.value?.openSearch();
|
||||
|
||||
@@ -13,6 +13,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
const userId = ref<string | number>('');
|
||||
const tenantId = ref<string>('');
|
||||
const avatar = ref('');
|
||||
const avatarUrl = ref('');
|
||||
const deptName = ref('');
|
||||
const phonenumber = ref('');
|
||||
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
|
||||
@@ -40,7 +41,9 @@ export const useUserStore = defineStore('user', () => {
|
||||
if (res) {
|
||||
const data = res.data;
|
||||
const user = data.user;
|
||||
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
||||
const avatarValue = user.avatar === '' || user.avatar === null || user.avatar === undefined ? '' : String(user.avatar);
|
||||
const previewUrl = user.avatarUrl || '';
|
||||
const profile = avatarValue || defAva;
|
||||
|
||||
if (data.roles && data.roles.length > 0) {
|
||||
// 验证返回的roles是否是一个非空数组
|
||||
@@ -52,6 +55,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
name.value = user.userName;
|
||||
nickname.value = user.nickName;
|
||||
avatar.value = profile;
|
||||
avatarUrl.value = previewUrl || (avatarValue ? '' : defAva);
|
||||
userId.value = user.userId;
|
||||
tenantId.value = user.tenantId;
|
||||
deptName.value = user.deptName;
|
||||
@@ -72,6 +76,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
|
||||
const setAvatar = (value: string) => {
|
||||
avatar.value = value;
|
||||
avatarUrl.value = value;
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -81,6 +86,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
name,
|
||||
nickname,
|
||||
avatar,
|
||||
avatarUrl,
|
||||
deptName,
|
||||
phonenumber,
|
||||
roles,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="user-info-head" @click="editCropper()">
|
||||
<img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
|
||||
<el-dialog v-model="open" :title="title" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
|
||||
<el-row>
|
||||
<el-row justify="center">
|
||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||
<vue-cropper
|
||||
v-if="visible"
|
||||
@@ -17,40 +17,23 @@
|
||||
@real-time="realTime"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||
<div class="avatar-upload-preview">
|
||||
<img :src="options.previews.url" :style="options.previews.img" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<br />
|
||||
<el-row>
|
||||
<el-col :lg="2" :md="2">
|
||||
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
|
||||
<el-button>
|
||||
选择
|
||||
<el-icon class="el-icon--right">
|
||||
<Upload />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
|
||||
<el-button icon="Plus" @click="changeScale(1)"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
|
||||
<el-button type="primary" @click="uploadImg()">提 交</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="avatar-actions">
|
||||
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
|
||||
<el-button>
|
||||
选择
|
||||
<el-icon class="el-icon--right">
|
||||
<Upload />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button icon="Plus" @click="changeScale(1)"></el-button>
|
||||
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
|
||||
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
|
||||
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
|
||||
<el-button type="primary" @click="uploadImg()">提 交</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -84,13 +67,13 @@ const title = ref('修改头像');
|
||||
const cropper = ref<any>({});
|
||||
//图片裁剪数据
|
||||
const options = reactive<Options>({
|
||||
img: userStore.avatar,
|
||||
img: userStore.avatarUrl || userStore.avatar,
|
||||
autoCrop: true,
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 200,
|
||||
fixedBox: true,
|
||||
outputType: 'png',
|
||||
fileName: '',
|
||||
fileName: 'avatar.png',
|
||||
previews: {},
|
||||
visible: false
|
||||
});
|
||||
@@ -134,14 +117,20 @@ const beforeUpload = (file: UploadRawFile): any => {
|
||||
/** 上传图片 */
|
||||
const uploadImg = async () => {
|
||||
cropper.value.getCropBlob(async (data: any) => {
|
||||
const formData = new FormData();
|
||||
formData.append('avatarfile', data, options.fileName);
|
||||
const res = await uploadAvatar(formData);
|
||||
open.value = false;
|
||||
options.img = res.data.imgUrl;
|
||||
userStore.setAvatar(options.img);
|
||||
proxy?.$modal.msgSuccess('修改成功');
|
||||
visible.value = false;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
const fileName = options.fileName || `avatar.${options.outputType || 'png'}`;
|
||||
formData.append('avatarfile', data, fileName);
|
||||
const res = await uploadAvatar(formData);
|
||||
await userStore.getInfo(); // 刷新用户信息以获取最新的oss_id
|
||||
options.img = res?.data?.imgUrl || userStore.avatarUrl || userStore.avatar;
|
||||
open.value = false;
|
||||
proxy?.$modal.msgSuccess('修改成功');
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('上传失败,请重试');
|
||||
} finally {
|
||||
visible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 实时预览 */
|
||||
@@ -150,7 +139,7 @@ const realTime = (data: any) => {
|
||||
};
|
||||
/** 关闭窗口 */
|
||||
const closeDialog = () => {
|
||||
options.img = userStore.avatar;
|
||||
options.img = userStore.avatarUrl || userStore.avatar;
|
||||
options.visible = false;
|
||||
};
|
||||
</script>
|
||||
@@ -179,4 +168,12 @@ const closeDialog = () => {
|
||||
line-height: 110px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.avatar-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user