From 480714172ee81c74f9a460a1a367b52b5430fc78 Mon Sep 17 00:00:00 2001 From: caozehui <2427765068@qq.com> Date: Fri, 15 May 2026 16:05:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(personal-center):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E4=BF=A1=E6=81=AF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + src/service/api/auth.ts | 94 ++++ src/store/modules/auth/index.ts | 15 +- src/typings/api/auth.d.ts | 34 ++ .../personal-center/my-profile/index.vue | 435 +++++++++++++++++- .../modules/profile-info-dialog.vue | 136 ++++++ .../my-profile/modules/profile-model.ts | 27 ++ .../modules/profile-password-dialog.vue | 181 ++++++++ 8 files changed, 921 insertions(+), 2 deletions(-) create mode 100644 src/views/personal-center/my-profile/modules/profile-info-dialog.vue create mode 100644 src/views/personal-center/my-profile/modules/profile-model.ts create mode 100644 src/views/personal-center/my-profile/modules/profile-password-dialog.vue diff --git a/.gitignore b/.gitignore index 94b43ea..a93d054 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ yarn.lock # Temp /codeTemp/* +SKILL.md diff --git a/src/service/api/auth.ts b/src/service/api/auth.ts index 9d5d7d2..2128128 100644 --- a/src/service/api/auth.ts +++ b/src/service/api/auth.ts @@ -19,6 +19,25 @@ interface BackendUserInfoDTO { buttons?: string[] | null; } +interface BackendMyProfileDetailDTO { + id?: string | number | null; + userId?: string | number | null; + username?: string | null; + userName?: string | null; + nickname?: string | null; + company?: string | null; + email?: string | null; + mobile?: string | null; + sex?: Api.SystemManage.UserGender | null; + avatar?: string | null; + loginIp?: string | null; + loginDate?: string | null; + createTime?: string | null; + roles?: Api.SystemManage.RoleSimple[] | null; + dept?: Api.SystemManage.DeptSimple | null; + position?: Api.SystemManage.PostSimple | null; +} + let userInfoPromise: Promise> | null = null; /** 将后端 token 结构转换成前端现有结构 */ @@ -39,6 +58,42 @@ function mapUserInfo(data: BackendUserInfoDTO): Api.Auth.UserInfo { }; } +function safeStringId(value: string | number | null | undefined): string | null { + return value === null || value === undefined ? null : String(value); +} + +// eslint-disable-next-line complexity +function mapMyProfileDetail(data: BackendMyProfileDetailDTO, fallbackUserId = ''): Api.Auth.MyProfileDetail { + const baseInfo = { + userId: String(data.id ?? data.userId ?? fallbackUserId ?? ''), + username: data.username ?? data.userName ?? '', + nickname: data.nickname ?? '', + deptId: safeStringId(data.dept?.id), + deptName: data.dept?.name ?? '', + positionId: safeStringId(data.position?.id), + positionName: data.position?.name ?? '' + }; + + const contactInfo = { + company: data.company ?? null, + email: data.email ?? '', + mobile: data.mobile ?? '', + sex: data.sex ?? 0, + avatar: data.avatar ?? '' + }; + + const extraInfo = { + roles: data.roles ?? [], + dept: data.dept ?? null, + position: data.position ?? null, + loginIp: data.loginIp ?? '', + loginDate: data.loginDate ?? null, + createTime: data.createTime ?? null + }; + + return { ...baseInfo, ...contactInfo, ...extraInfo }; +} + export function clearUserInfoCache() { userInfoPromise = null; } @@ -101,6 +156,45 @@ export async function fetchGetUserInfo(force = false): Promise> { + const result = await request({ + url: `${SYSTEM_SERVICE_PREFIX}/user/profile/get`, + method: 'get' + }); + + if (result.error || !result.data) { + return result as ServiceRequestResult; + } + + return { + ...result, + data: mapMyProfileDetail(result.data, options.userId ?? '') + }; +} + +/** 更新当前登录人基础资料 */ +export function fetchUpdateMyProfile(data: Api.Auth.UpdateMyProfileParams) { + return request({ + url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update`, + method: 'put', + data + }); +} + +/** 修改当前登录人密码 */ +export function fetchUpdateMyPassword(data: Api.Auth.UpdateMyPasswordParams) { + return request({ + url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-password`, + method: 'put', + data + }); +} + /** * 刷新 token * diff --git a/src/store/modules/auth/index.ts b/src/store/modules/auth/index.ts index 94e5701..588eee8 100644 --- a/src/store/modules/auth/index.ts +++ b/src/store/modules/auth/index.ts @@ -172,6 +172,18 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { return false; } + async function refreshUserInfo() { + const { data: info, error } = await fetchGetUserInfo(true); + + if (!error) { + Object.assign(userInfo, info); + + return true; + } + + return false; + } + async function initUserInfo() { const hasToken = getToken(); @@ -194,6 +206,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { loginLoading, resetStore, login, - initUserInfo + initUserInfo, + refreshUserInfo }; }); diff --git a/src/typings/api/auth.d.ts b/src/typings/api/auth.d.ts index 25d7904..93286b0 100644 --- a/src/typings/api/auth.d.ts +++ b/src/typings/api/auth.d.ts @@ -17,5 +17,39 @@ declare namespace Api { roles: string[]; buttons: string[]; } + + interface MyProfileDetail { + userId: string; + username: string; + nickname?: string | null; + deptId?: string | null; + deptName?: string | null; + positionId?: string | null; + positionName?: string | null; + company?: string | null; + email?: string | null; + mobile?: string | null; + sex?: Api.SystemManage.UserGender | null; + avatar?: string | null; + roles: Api.SystemManage.RoleSimple[]; + dept?: Api.SystemManage.DeptSimple | null; + position?: Api.SystemManage.PostSimple | null; + loginIp?: string | null; + loginDate?: string | null; + createTime?: string | null; + } + + interface UpdateMyProfileParams { + nickname?: string | null; + email?: string | null; + mobile?: string | null; + sex?: Api.SystemManage.UserGender | null; + avatar?: string | null; + } + + interface UpdateMyPasswordParams { + oldPassword: string; + newPassword: string; + } } } diff --git a/src/views/personal-center/my-profile/index.vue b/src/views/personal-center/my-profile/index.vue index 63ed180..a3aeb8e 100644 --- a/src/views/personal-center/my-profile/index.vue +++ b/src/views/personal-center/my-profile/index.vue @@ -1,3 +1,436 @@ + + + + diff --git a/src/views/personal-center/my-profile/modules/profile-info-dialog.vue b/src/views/personal-center/my-profile/modules/profile-info-dialog.vue new file mode 100644 index 0000000..c1b8a25 --- /dev/null +++ b/src/views/personal-center/my-profile/modules/profile-info-dialog.vue @@ -0,0 +1,136 @@ + + + diff --git a/src/views/personal-center/my-profile/modules/profile-model.ts b/src/views/personal-center/my-profile/modules/profile-model.ts new file mode 100644 index 0000000..11729b7 --- /dev/null +++ b/src/views/personal-center/my-profile/modules/profile-model.ts @@ -0,0 +1,27 @@ +import dayjs from 'dayjs'; + +function getNullableText(value?: string | null) { + return value?.trim() || null; +} + +export function formatProfileDateTime(value?: string | number | null) { + if (!value) { + return '--'; + } + + return dayjs(value).format('YYYY-MM-DD HH:mm:ss'); +} + +export function resolveProfileRoleLabels(roles: Api.SystemManage.RoleSimple[]) { + return roles.map(role => role.name?.trim() || role.code || role.id); +} + +export function buildProfileUpdatePayload(form: Api.Auth.UpdateMyProfileParams): Api.Auth.UpdateMyProfileParams { + return { + nickname: getNullableText(form.nickname), + email: getNullableText(form.email), + mobile: getNullableText(form.mobile), + sex: form.sex ?? null, + avatar: getNullableText(form.avatar) + }; +} diff --git a/src/views/personal-center/my-profile/modules/profile-password-dialog.vue b/src/views/personal-center/my-profile/modules/profile-password-dialog.vue new file mode 100644 index 0000000..4d91224 --- /dev/null +++ b/src/views/personal-center/my-profile/modules/profile-password-dialog.vue @@ -0,0 +1,181 @@ + + + + +