外观
个人中心
个人中心
介绍
个人中心页面实现了一个用户个人信息页面,包含左侧用户信息卡片和右侧可切换的用户基本信息与修改密码选项卡。
- 代码:src\views\Profile\Index.vue
vue
<template>
<div class="flex">
<el-card class="user w-1/3" shadow="hover">
<template #header>
<div class="card-header">
<span>{{ t('profile.user.title') }}</span>
</div>
</template>
<ProfileUser />
</el-card>
<el-card class="user ml-3 w-2/3" shadow="hover">
<div>
<el-tabs v-model="activeName" class="profile-tabs" style="height: 400px" tab-position="top">
<el-tab-pane :label="t('profile.info.basicInfo')" name="basicInfo">
<BasicInfo />
</el-tab-pane>
<el-tab-pane :label="t('profile.info.resetPwd')" name="resetPwd">
<ResetPwd />
</el-tab-pane>
</el-tabs>
</div>
</el-card>
</div>
</template>
个人信息子组件
ProfileUser 该 Vue 组件用于展示用户个人信息,从接口获取数据并展示用户名、手机号、邮箱、部门、岗位、角色及创建时间等字段,并使用了国际化([t()](javascript:void(0)))和时间格式化(formatDate)功能。
- 代码:src\views\Profile\components\ProfileUser.vue
vue
<template>
<div>
<div class="text-center">
<UserAvatar :img="userInfo?.avatar" />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<Icon class="mr-5px" icon="ep:user" />
{{ t('profile.user.username') }}
<div class="pull-right">{{ userInfo?.username }}</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="ep:phone" />
{{ t('profile.user.mobile') }}
<div class="pull-right">{{ userInfo?.mobile }}</div>
</li>
...
- 包含了 UserAvatar 头像上传组件。代码:src\views\Profile\components\UserAvatar.vue
vue
<template>
<div class="change-avatar">
<CropperAvatar
ref="cropperRef"
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
:showBtn="false"
:value="img"
width="120px"
@change="handelUpload"
/>
</div>
</template>
- 包含了 CropperAvatar 头像裁剪组件。代码:src\components\Cropper\src\CropperAvatar.vue
vue
<template>
<div class="user-info-head" @click="open()">
<el-avatar v-if="sourceValue" :src="sourceValue" alt="avatar" class="img-circle img-lg" />
<el-avatar v-if="!sourceValue" :src="avatar" alt="avatar" class="img-circle img-lg" />
<el-button v-if="showBtn" :class="`${prefixCls}-upload-btn`" @click="open()">
{{ btnText ? btnText : t('cropper.selectImage') }}
</el-button>
<CopperModal
ref="cropperModelRef"
:srcValue="sourceValue"
@upload-success="handleUploadSuccess"
/>
</div>
</template>
基本设置子组件
BasicInfo 该 Vue 组件实现用户基本信息的展示与编辑功能,使用了自定义 Form
组件和 Element Plus 的表单验证机制。
- 模板部分:
- 使用
<Form>
组件绑定表单数据 schema 和校验规则 rules。 - 自定义插槽
#sex
渲染性别选择的单选按钮组(男、女)。 - 页面底部显示“保存”和“重置”按钮,分别触发 submit() 和 init() 方法。
- 使用
- 脚本部分:
- 代码:src\views\Profile\components\BasicInfo.vue
vue
<template>
<Form ref="formRef" :labelWidth="200" :rules="rules" :schema="schema">
<template #sex="form">
<el-radio-group v-model="form['sex']">
<el-radio :value="1">{{ t('profile.user.man') }}</el-radio>
<el-radio :value="2">{{ t('profile.user.woman') }}</el-radio>
</el-radio-group>
</template>
</Form>
<div style="text-align: center">
<XButton :title="t('common.save')" type="primary" @click="submit()" />
<XButton :title="t('common.reset')" type="danger" @click="init()" />
</div>
</template>
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
import { FormSchema } from '@/types/form'
import type { FormExpose } from '@/components/Form'
import {
getUserProfile,
updateUserProfile,
UserProfileUpdateReqVO
} from '@/api/system/user/profile'
import { useUserStore } from '@/store/modules/user'
defineOptions({ name: 'BasicInfo' })
const { t } = useI18n()
const message = useMessage() // 消息弹窗
const userStore = useUserStore()
// 表单校验
const rules = reactive<FormRules>({
nickname: [{ required: true, message: t('profile.rules.nickname'), trigger: 'blur' }],
email: [
{ required: true, message: t('profile.rules.mail'), trigger: 'blur' },
{
type: 'email',
message: t('profile.rules.truemail'),
trigger: ['blur', 'change']
}
],
mobile: [
{ required: true, message: t('profile.rules.phone'), trigger: 'blur' },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: t('profile.rules.truephone'),
trigger: 'blur'
}
]
})
const schema = reactive<FormSchema[]>([
{
field: 'nickname',
label: t('profile.user.nickname'),
component: 'Input'
},
{
field: 'mobile',
label: t('profile.user.mobile'),
component: 'Input'
},
{
field: 'email',
label: t('profile.user.email'),
component: 'Input'
},
{
field: 'sex',
label: t('profile.user.sex'),
component: 'InputNumber',
value: 0
}
])
const formRef = ref<FormExpose>() // 表单 Ref
const submit = () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
const data = unref(formRef)?.formModel as UserProfileUpdateReqVO
await updateUserProfile(data)
message.success(t('common.updateSuccess'))
const profile = await init()
userStore.setUserNicknameAction(profile.nickname)
}
})
}
const init = async () => {
const res = await getUserProfile()
unref(formRef)?.setValues(res)
return res
}
onMounted(async () => {
await init()
})
</script>
密码设置子组件
ResetPwd 该 Vue 组件实现了用户修改密码的功能,包含表单验证和提交逻辑:
- 使用
el-form
构建表单,包含旧密码、新密码、确认密码三项和保存/重置按钮; - 通过 [rules](javascript:void(0)) 定义表单校验规则,确保密码长度及一致性(确认密码需与新密码一致);
- [submit](javascript:void(0)) 方法验证表单并调用接口更新密码;
- [reset](javascript:void(0)) 方法用于重置表单内容。
vue
<template>
<el-form ref="formRef" :model="password" :rules="rules" :label-width="200">
<el-form-item :label="t('profile.password.oldPassword')" prop="oldPassword">
<InputPassword v-model="password.oldPassword" />
</el-form-item>
<el-form-item :label="t('profile.password.newPassword')" prop="newPassword">
<InputPassword v-model="password.newPassword" strength />
</el-form-item>
<el-form-item :label="t('profile.password.confirmPassword')" prop="confirmPassword">
<InputPassword v-model="password.confirmPassword" strength />
</el-form-item>
<el-form-item>
<XButton :title="t('common.save')" type="primary" @click="submit(formRef)" />
<XButton :title="t('common.reset')" type="danger" @click="reset(formRef)" />
</el-form-item>
</el-form>
</template>