diff --git a/src/service/api/auth.ts b/src/service/api/auth.ts index 7159a00..94e1bba 100644 --- a/src/service/api/auth.ts +++ b/src/service/api/auth.ts @@ -50,9 +50,16 @@ export function doDeleteLogout() { /** Get user info */ export function doGetUserInfo() { - return request({ url: '/u/user/getInfo' }); + return request({ url: '/u/user/getInfo',method:'get' }); +} +/** change user info */ +export function doChangeUserInfo(body: Api.Auth.ChangeInfoBody){ + return request({ + url:'/u/user/profile', + method:'put', + data:body + }); } - /** * Refresh token * diff --git a/src/store/modules/auth/index.ts b/src/store/modules/auth/index.ts index 3a51f97..c0aac7c 100644 --- a/src/store/modules/auth/index.ts +++ b/src/store/modules/auth/index.ts @@ -106,7 +106,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { return isSuccess; } - +//查询用户信息 async function refreshUserInfo() { const { data: info, error } = await doGetUserInfo(); if (!error) { @@ -115,6 +115,16 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { } return false; } + /**修改用户信息**/ + async function updateUserProfile(info: Api.Auth.ChangeInfoBody) { + try { + await doChangeUserInfo(info); + return true; + } catch (error) { + console.error('Failed to update user profile:', error); + return false; + } + } /** * 检查用户信息是否已存在 @@ -141,7 +151,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { endLoading(); return !error; } - +//二维码 async function captcha(email: string) { if (!email) { return null; @@ -161,6 +171,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { refreshUserInfo, register, captcha, - checkUserRepeat + checkUserRepeat, + updateUserProfile }; }); diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index 52efce7..507bbf0 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -104,6 +104,7 @@ declare namespace Api { delFlag: string; loginIp: string; loginDate: string; + birthDate:string; dept: Department.Dept; roles: Role[]; roleId: string; @@ -143,11 +144,11 @@ declare namespace Api { password: string; authType:string; email: string; - fullName: string; + fullName?: string; age: number; - address: string; - sex: string; - phonenumber: string; + address?: string; + sex?: string; + phonenumber?: string; } interface EmailCaptcha{ email:string; @@ -158,6 +159,16 @@ declare namespace Api { phonenumber?:string; authType: string; } + interface ChangeInfoBody{ + userId:number; + userName: string; + nickName?: string|undefined; + email: string; + phonenumber?: string|undefined; + sex?: string|undefined; + birthDate?:string|undefined; + age?:number; + } } /** diff --git a/src/typings/auto-imports.d.ts b/src/typings/auto-imports.d.ts index 125e622..f7cbfd4 100644 --- a/src/typings/auto-imports.d.ts +++ b/src/typings/auto-imports.d.ts @@ -53,6 +53,7 @@ declare global { const doAddDict: typeof import('../service/api/dict')['doAddDict'] const doAddMenu: typeof import('../service/api/menu')['doAddMenu'] const doAddPost: typeof import('../service/api/post')['doAddPost'] + const doChangeUserInfo: typeof import('../service/api/auth')['doChangeUserInfo'] const doCheckUserRepeat: typeof import('../service/api/auth')['doCheckUserRepeat'] const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept'] const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict'] diff --git a/src/views/userInfo/profile/index.vue b/src/views/userInfo/profile/index.vue index 07fd46a..a326162 100644 --- a/src/views/userInfo/profile/index.vue +++ b/src/views/userInfo/profile/index.vue @@ -34,11 +34,16 @@ const { t } = useI18n(); const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => { const validateUsername = async (_rule: RuleObject, value: string) => { + const currentUsername = authStore.userInfo?.user?.userName; + if (value === currentUsername) { + return Promise.resolve(); + } + if (value && (value.length < 4 || value.length > 20)) { return Promise.reject(t('page.login.register.usernameLengthLimit')); } - const currentUsername = authStore.userInfo?.user?.userName; - if (value && value !== currentUsername) { + + if (value) { const { exists } = await authStore.checkUserRepeat({ username: value, authType: 'u' }); if (exists) { return Promise.reject(t('page.login.register.usernameExists')); @@ -50,8 +55,10 @@ const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => { const validatePhone = async (_rule: RuleObject, value: string) => { if (!value) return Promise.resolve(); - const phonePattern = /^1[3-9]\d{9}$/; - if (!phonePattern.test(value)) { + const phonePattern = /^\+?([0-9]{1,3})?[-\s]?\d{6,15}$/; + + const cleanPhone = value.replace(/[-\s]/g, ''); + if (!phonePattern.test(cleanPhone)) { return Promise.reject(t('page.login.register.phoneInvalid')); } @@ -66,6 +73,11 @@ const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => { }; const validateEmail = async (_rule: RuleObject, value: string) => { + const currentEmail = authStore.userInfo?.user?.email; + if (value === currentEmail) { + return Promise.resolve(); + } + if (!value) { return Promise.reject(t('page.login.register.emailRequired')); } @@ -75,12 +87,9 @@ const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => { return Promise.reject(t('page.login.register.emailInvalid')); } - const currentEmail = authStore.userInfo?.user?.email; - if (value !== currentEmail) { - const { exists } = await authStore.checkUserRepeat({ email: value, authType: 'u' }); - if (exists) { - return Promise.reject(t('page.login.register.emailExists')); - } + const { exists } = await authStore.checkUserRepeat({ email: value, authType: 'u' }); + if (exists) { + return Promise.reject(t('page.login.register.emailExists')); } return Promise.resolve(); }; @@ -97,12 +106,22 @@ const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => { ], phonenumber: [{ validator: validatePhone, trigger: 'blur' }], birthdate: [ - { required: true, message: t('page.login.register.birthDateRequired') }, { validator: (_rule: RuleObject, value: string) => { - if (value && dayjs(value).isAfter(dayjs())) { + if (!value) return Promise.resolve(); + + const selectedDate = dayjs(value); + const today = dayjs(); + const minDate = today.subtract(120, 'year'); + + if (selectedDate.isAfter(today)) { return Promise.reject(t('page.login.register.birthDateInvalid')); } + + if (selectedDate.isBefore(minDate)) { + return Promise.reject(t('page.login.register.birthDateTooEarly')); + } + return Promise.resolve(); } } @@ -112,23 +131,27 @@ const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => { onMounted(async () => { try { + // 先刷新获取最新的用户信息 + await authStore.refreshUserInfo(); + const userInfo = authStore.userInfo?.user; if (!userInfo) { message.error(t('page.profile.getUserInfoFailed')); return; } + // 将获取到的用户信息填充到表单中 formState.value = { username: userInfo.userName ?? '', fullname: userInfo.nickName ?? '', - birthdate: '', + birthdate: userInfo.birthDate ?? '', // 添加出生日期 email: userInfo.email ?? '', phonenumber: userInfo.phonenumber ?? '', sex: userInfo.sex ?? '0' }; } catch (error) { console.error('Failed to get user info:', error); - message.error(t('page.profile.updateFailed')); + message.error(t('page.profile.getUserInfoFailed')); } }); @@ -137,20 +160,55 @@ const handleSubmit = async () => { await formRef.value?.validate(); loading.value = true; - // 构建更新数据,只包含后端接受的字段 - // const updateData = { - // userName: formState.value.username, - // nickName: formState.value.fullname, - // email: formState.value.email, - // phonenumber: formState.value.phonenumber, - // sex: formState.value.sex, - // age: formState.value.birthdate ? dayjs().diff(dayjs(formState.value.birthdate), 'year') : undefined - // }; + const userId = authStore.userInfo?.user?.userId; + if (!userId) { + message.error(t('page.profile.getUserInfoFailed')); + return; + } - // 这里需要调用后端 API 更新用户信息 - // await authStore.updateUserProfile(updateData); + // 构建基础更新数据 + const updateData: Api.Auth.ChangeInfoBody = { + userId, + userName: formState.value.username, + email: formState.value.email + }; - message.success(t('page.profile.updateSuccess')); + // 只在有值时添加可选字段 + if (formState.value.fullname) { + updateData.nickName = formState.value.fullname; + } + if (formState.value.phonenumber) { + updateData.phonenumber = formState.value.phonenumber; + } + if (formState.value.sex) { + updateData.sex = formState.value.sex; + } + if (formState.value.birthdate) { + updateData.birthDate = formState.value.birthdate; + updateData.age = dayjs().diff(dayjs(formState.value.birthdate), 'year'); + } + + // 调用更新接口 + const success = await authStore.updateUserProfile(updateData); + + if (success) { + await authStore.refreshUserInfo(); + // 更新表单数据以显示最新信息 + const userInfo = authStore.userInfo?.user; + if (userInfo) { + formState.value = { + username: userInfo.userName ?? '', + fullname: userInfo.nickName ?? '', + birthdate: userInfo.birthDate ?? '', + email: userInfo.email ?? '', + phonenumber: userInfo.phonenumber ?? '', + sex: userInfo.sex ?? '0' + }; + } + message.success(t('page.profile.updateSuccess')); + } else { + message.error(t('page.profile.updateFailed')); + } } catch (error) { console.error('表单验证失败:', error); message.error(t('page.profile.updateFailed')); @@ -201,6 +259,12 @@ const handleBack = () => { style="width: 100%" :format="'YYYY-MM-DD'" :placeholder="t('page.login.register.birthDatePlaceholder')" + :disabled-date="(current) => { + const today = dayjs(); + const minDate = today.subtract(120, 'year'); + return current && (current.isAfter(today) || current.isBefore(minDate)); + }" + :show-today="false" />