2
0

feat:修改信息界面

This commit is contained in:
zhongzm
2024-12-11 15:00:03 +08:00
parent dd46f6b19f
commit 1d20f8c726

View File

@@ -0,0 +1,286 @@
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { useAuthStore } from '@/store/modules/auth';
import { message } from 'ant-design-vue';
import type { FormInstance } from 'ant-design-vue';
import type { RuleObject } from 'ant-design-vue/es/form';
import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs';
import { useRouter } from 'vue-router';
interface UserProfile {
username: string;
fullname: string;
birthdate: string;
email: string;
phonenumber: string;
sex: string;
}
const authStore = useAuthStore();
const formRef = ref<FormInstance>();
const loading = ref(false);
const formState = ref<UserProfile>({
username: '',
fullname: '',
birthdate: '',
email: '',
phonenumber: '',
sex: '0'
});
const { t } = useI18n();
const rules = computed<{ [k: string]: RuleObject | RuleObject[] }>(() => {
const validateUsername = async (_rule: RuleObject, value: string) => {
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) {
const { exists } = await authStore.checkUserRepeat({ username: value, authType: 'u' });
if (exists) {
return Promise.reject(t('page.login.register.usernameExists'));
}
}
return Promise.resolve();
};
const validatePhone = async (_rule: RuleObject, value: string) => {
if (!value) return Promise.resolve();
const phonePattern = /^1[3-9]\d{9}$/;
if (!phonePattern.test(value)) {
return Promise.reject(t('page.login.register.phoneInvalid'));
}
const currentPhone = authStore.userInfo?.user?.phonenumber;
if (value !== currentPhone) {
const { exists } = await authStore.checkUserRepeat({ phonenumber: value, authType: 'u' });
if (exists) {
return Promise.reject(t('page.login.register.phoneExists'));
}
}
return Promise.resolve();
};
const validateEmail = async (_rule: RuleObject, value: string) => {
if (!value) {
return Promise.reject(t('page.login.register.emailRequired'));
}
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
if (!emailPattern.test(value)) {
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'));
}
}
return Promise.resolve();
};
return {
username: [
{ required: true, message: t('page.login.register.usernameRequired'), trigger: 'change' },
{ validator: validateUsername, trigger: 'blur' }
],
fullname: [
{ required: true, message: t('page.login.register.fullNameRequired'), trigger: 'blur' }
],
email: [
{ required: true, message: t('page.login.register.emailRequired'), trigger: 'change' },
{ validator: validateEmail, trigger: 'blur' }
],
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())) {
return Promise.reject(t('page.login.register.birthDateInvalid'));
}
return Promise.resolve();
}
}
]
};
});
onMounted(async () => {
try {
const userInfo = authStore.userInfo?.user;
if (!userInfo) {
message.error(t('page.profile.getUserInfoFailed'));
return;
}
formState.value = {
username: userInfo.userName ?? '',
fullname: userInfo.nickName ?? '',
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'));
}
});
const handleSubmit = async () => {
try {
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
// };
// 这里需要调用后端 API 更新用户信息
// await authStore.updateUserProfile(updateData);
message.success(t('page.profile.updateSuccess'));
} catch (error) {
console.error('表单验证失败:', error);
message.error(t('page.profile.updateFailed'));
} finally {
loading.value = false;
}
};
const router = useRouter();
const handleBack = () => {
router.push('/userInfo/usercard');
};
</script>
<template>
<div class="profile-container">
<a-card :title="t('view.userInfo')" :bordered="false">
<template #extra>
<a-button @click="handleBack">
{{ t('page.login.common.back') }}
</a-button>
</template>
<a-form
ref="formRef"
:model="formState"
:rules="rules"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 16 }"
>
<a-form-item :label="t('page.login.register.username')" name="username">
<a-input
v-model:value="formState.username"
:placeholder="t('page.login.register.usernameLengthLimit')"
/>
</a-form-item>
<a-form-item :label="t('page.login.register.fullName')" name="fullname">
<a-input
v-model:value="formState.fullname"
:placeholder="t('page.login.register.fullName')"
/>
</a-form-item>
<a-form-item :label="t('page.login.register.birthDate')" name="birthdate">
<a-date-picker
v-model:value="formState.birthdate"
style="width: 100%"
:format="'YYYY-MM-DD'"
:placeholder="t('page.login.register.birthDatePlaceholder')"
/>
</a-form-item>
<a-form-item :label="t('page.login.register.email')" name="email">
<a-input
v-model:value="formState.email"
:placeholder="t('page.login.register.emailPlaceholder')"
/>
</a-form-item>
<a-form-item :label="t('page.login.register.phone')" name="phonenumber">
<a-input
v-model:value="formState.phonenumber"
:placeholder="t('page.login.register.phonePlaceholder')"
/>
</a-form-item>
<a-form-item :label="t('page.login.register.gender')" name="sex">
<a-radio-group v-model:value="formState.sex" class="w-full">
<a-radio value="0">{{ t('page.login.register.male') }}</a-radio>
<a-radio value="1">{{ t('page.login.register.female') }}</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item :wrapper-col="{
xs: { span: 24, offset: 0 }, // 移动端下占满宽度不偏移
sm: { span: 16, offset: 4 } // PC端保持原样
}" class="text-center">
<a-button type="primary" :loading="loading" @click="handleSubmit">
{{ t('common.confirm') }}
</a-button>
</a-form-item>
</a-form>
</a-card>
</div>
</template>
<style scoped>
.profile-container {
padding: 24px;
background-color: #f5f5f7;
min-height: 100vh;
}
:deep(.ant-card) {
max-width: 800px;
margin: 0 auto;
border-radius: 8px;
}
:deep(.ant-card-head-title) {
font-size: 18px;
font-weight: 600;
}
:deep(.ant-radio-group) {
display: flex;
justify-content: center;
gap: 32px;
}
:deep(.ant-form-item:last-child) {
margin-bottom: 0;
}
:deep(.ant-form-item:last-child .ant-form-item-control-input-content) {
display: flex;
justify-content: center;
}
/* 移动端适配 */
@media (max-width: 576px) {
:deep(.ant-form-item-control) {
max-width: 100% !important; /* 覆盖 ant-design-vue 的默认样式 */
}
:deep(.ant-form-item:last-child) {
margin-top: 24px;
}
}
</style>