fix(personal-center): 个人头像更新
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
||||||
import { request } from '../request';
|
import { request } from '../request';
|
||||||
import { clearUserRouteCache } from './route';
|
import { clearUserRouteCache } from './route';
|
||||||
import type { ServiceRequestResult } from './shared';
|
import { type ServiceRequestResult, mapServiceResult, normalizeStringId } from './shared';
|
||||||
|
|
||||||
/** 后端登录返回 */
|
/** 后端登录返回 */
|
||||||
interface BackendLoginToken {
|
interface BackendLoginToken {
|
||||||
@@ -38,6 +38,14 @@ interface BackendMyProfileDetailDTO {
|
|||||||
position?: Api.SystemManage.PostSimple | null;
|
position?: Api.SystemManage.PostSimple | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BackendFileDTO {
|
||||||
|
id: string | number;
|
||||||
|
configId: string | number;
|
||||||
|
name?: string | null;
|
||||||
|
path: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
let userInfoPromise: Promise<ServiceRequestResult<BackendUserInfoDTO>> | null = null;
|
let userInfoPromise: Promise<ServiceRequestResult<BackendUserInfoDTO>> | null = null;
|
||||||
|
|
||||||
/** 将后端 token 结构转换成前端现有结构 */
|
/** 将后端 token 结构转换成前端现有结构 */
|
||||||
@@ -187,6 +195,23 @@ export function fetchUpdateMyProfile(data: Api.Auth.UpdateMyProfileParams) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 修改当前登录人密码 */
|
/** 修改当前登录人密码 */
|
||||||
|
export async function fetchUpdateMyAvatar(file: File) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
const result = await request<BackendFileDTO>({
|
||||||
|
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-avatar`,
|
||||||
|
method: 'put',
|
||||||
|
data: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
return mapServiceResult(result as ServiceRequestResult<BackendFileDTO>, data => ({
|
||||||
|
...data,
|
||||||
|
id: normalizeStringId(data.id),
|
||||||
|
configId: normalizeStringId(data.configId)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchUpdateMyPassword(data: Api.Auth.UpdateMyPasswordParams) {
|
export function fetchUpdateMyPassword(data: Api.Auth.UpdateMyPasswordParams) {
|
||||||
return request<boolean>({
|
return request<boolean>({
|
||||||
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-password`,
|
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-password`,
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onActivated, onMounted, ref } from 'vue';
|
import { computed, onActivated, onMounted, ref } from 'vue';
|
||||||
import { userGenderRecord } from '@/constants/business';
|
import { userGenderRecord } from '@/constants/business';
|
||||||
import { fetchGetMyProfileDetail, fetchUpdateMyProfile } from '@/service/api';
|
import { fetchGetMyProfileDetail, fetchUpdateMyAvatar } from '@/service/api';
|
||||||
import { buildFileProxyUrl, uploadFile } from '@/service/api/file';
|
|
||||||
import { useAuthStore } from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import { useAppStore } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import ProfileInfoDialog from './modules/profile-info-dialog.vue';
|
import ProfileInfoDialog from './modules/profile-info-dialog.vue';
|
||||||
import ProfilePasswordDialog from './modules/profile-password-dialog.vue';
|
import ProfilePasswordDialog from './modules/profile-password-dialog.vue';
|
||||||
import { buildProfileUpdatePayload, formatProfileDateTime, resolveProfileRoleLabels } from './modules/profile-model';
|
import { formatProfileDateTime, resolveProfileRoleLabels } from './modules/profile-model';
|
||||||
|
|
||||||
defineOptions({ name: 'MyProfile' });
|
defineOptions({ name: 'MyProfile' });
|
||||||
|
|
||||||
@@ -22,6 +21,8 @@ const profileInfoVisible = ref(false);
|
|||||||
const passwordVisible = ref(false);
|
const passwordVisible = ref(false);
|
||||||
const avatarInputRef = ref<HTMLInputElement | null>(null);
|
const avatarInputRef = ref<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
const MAX_AVATAR_SIZE = 5 * 1024 * 1024;
|
||||||
|
|
||||||
const descriptionColumns = computed(() => (appStore.isMobile ? 1 : 2));
|
const descriptionColumns = computed(() => (appStore.isMobile ? 1 : 2));
|
||||||
const displayName = computed(() => profile.value?.nickname?.trim() || profile.value?.username || '--');
|
const displayName = computed(() => profile.value?.nickname?.trim() || profile.value?.username || '--');
|
||||||
const displayUsername = computed(() => profile.value?.username?.trim() || '--');
|
const displayUsername = computed(() => profile.value?.username?.trim() || '--');
|
||||||
@@ -41,6 +42,7 @@ const genderText = computed(() => {
|
|||||||
|
|
||||||
return $t(userGenderRecord[value]);
|
return $t(userGenderRecord[value]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const roleLabels = computed(() => {
|
const roleLabels = computed(() => {
|
||||||
const roles = profile.value?.roles ?? [];
|
const roles = profile.value?.roles ?? [];
|
||||||
|
|
||||||
@@ -57,16 +59,6 @@ function getAvatarText() {
|
|||||||
return name === '--' ? 'CN' : name.slice(0, 1).toUpperCase();
|
return name === '--' ? 'CN' : name.slice(0, 1).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEditableProfileValues(current: Api.Auth.MyProfileDetail): Api.Auth.UpdateMyProfileParams {
|
|
||||||
return {
|
|
||||||
nickname: current.nickname ?? '',
|
|
||||||
email: current.email ?? '',
|
|
||||||
mobile: current.mobile ?? '',
|
|
||||||
sex: current.sex ?? 1,
|
|
||||||
avatar: current.avatar ?? ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadProfile() {
|
async function loadProfile() {
|
||||||
const userId = authStore.userInfo.userId;
|
const userId = authStore.userInfo.userId;
|
||||||
|
|
||||||
@@ -75,9 +67,7 @@ async function loadProfile() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error } = await fetchGetMyProfileDetail({
|
const { data, error } = await fetchGetMyProfileDetail({ userId });
|
||||||
userId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
profile.value = data;
|
profile.value = data;
|
||||||
@@ -115,21 +105,14 @@ async function handleAvatarChange(event: Event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarSubmitting.value = true;
|
if (file.size > MAX_AVATAR_SIZE) {
|
||||||
|
window.$message?.error('头像图片大小不能超过 5MB');
|
||||||
const uploadResult = await uploadFile(file, 'avatar');
|
|
||||||
|
|
||||||
if (uploadResult.error) {
|
|
||||||
avatarSubmitting.value = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const avatar = buildFileProxyUrl(uploadResult.data.configId, uploadResult.data.path);
|
avatarSubmitting.value = true;
|
||||||
const payload = buildProfileUpdatePayload({
|
|
||||||
...getEditableProfileValues(profile.value),
|
const updateResult = await fetchUpdateMyAvatar(file);
|
||||||
avatar
|
|
||||||
});
|
|
||||||
const updateResult = await fetchUpdateMyProfile(payload);
|
|
||||||
|
|
||||||
avatarSubmitting.value = false;
|
avatarSubmitting.value = false;
|
||||||
|
|
||||||
@@ -212,7 +195,7 @@ onActivated(() => {
|
|||||||
|
|
||||||
<ElDescriptions :column="descriptionColumns" border>
|
<ElDescriptions :column="descriptionColumns" border>
|
||||||
<ElDescriptionsItem label="用户名">{{ displayUsername }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="用户名">{{ displayUsername }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="昵称">{{ displayName }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="名称">{{ displayName }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="手机号">{{ mobileText }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="手机号">{{ mobileText }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="邮箱">{{ emailText }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="邮箱">{{ emailText }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="性别">{{ genderText }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="性别">{{ genderText }}</ElDescriptionsItem>
|
||||||
|
|||||||
Reference in New Issue
Block a user