| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- <template>
- <div class="profile-container">
- <el-card class="profile-card">
- <template #header>
- <div class="card-header">
- <h2>个人资料</h2>
- </div>
- </template>
-
- <el-tabs v-model="activeTab" type="border-card">
- <!-- 基本信息 -->
- <el-tab-pane label="基本信息" name="basic">
- <el-form
- ref="profileFormRef"
- :model="profileForm"
- :rules="profileRules"
- label-width="120px"
- style="max-width: 600px"
- >
- <el-form-item label="头像">
- <div class="avatar-upload">
- <el-avatar
- :size="100"
- :src="profileForm.avatar || defaultAvatar"
- class="avatar-preview"
- >
- <el-icon><User /></el-icon>
- </el-avatar>
- <el-upload
- class="avatar-uploader"
- action="#"
- :show-file-list="false"
- :before-upload="beforeAvatarUpload"
- :http-request="handleAvatarUpload"
- >
- <el-button type="primary" size="small">上传头像</el-button>
- </el-upload>
- <div class="avatar-tip">支持 JPG、PNG 格式,大小不超过 2MB</div>
- </div>
- </el-form-item>
-
- <el-form-item label="用户名">
- <el-input v-model="profileForm.username" disabled />
- </el-form-item>
-
- <el-form-item label="真实姓名" prop="realName">
- <el-input v-model="profileForm.realName" placeholder="请输入真实姓名" />
- </el-form-item>
-
- <el-form-item label="手机号" prop="phone">
- <el-input v-model="profileForm.phone" placeholder="请输入手机号" />
- </el-form-item>
-
- <el-form-item label="邮箱" prop="email">
- <el-input v-model="profileForm.email" placeholder="请输入邮箱" />
- </el-form-item>
-
- <el-form-item>
- <el-button type="primary" @click="handleSaveProfile" :loading="saving">
- 保存
- </el-button>
- <el-button @click="handleReset">重置</el-button>
- </el-form-item>
- </el-form>
- </el-tab-pane>
-
- <!-- 修改密码 -->
- <el-tab-pane label="修改密码" name="password">
- <el-form
- ref="passwordFormRef"
- :model="passwordForm"
- :rules="passwordRules"
- label-width="120px"
- style="max-width: 600px"
- >
- <el-form-item label="原密码" prop="oldPassword">
- <el-input
- v-model="passwordForm.oldPassword"
- type="password"
- placeholder="请输入原密码"
- show-password
- />
- </el-form-item>
-
- <el-form-item label="新密码" prop="newPassword">
- <el-input
- v-model="passwordForm.newPassword"
- type="password"
- placeholder="请输入新密码(至少6位)"
- show-password
- />
- </el-form-item>
-
- <el-form-item label="确认新密码" prop="confirmPassword">
- <el-input
- v-model="passwordForm.confirmPassword"
- type="password"
- placeholder="请再次输入新密码"
- show-password
- />
- </el-form-item>
-
- <el-form-item>
- <el-button type="primary" @click="handleChangePassword" :loading="changingPassword">
- 修改密码
- </el-button>
- <el-button @click="handleResetPassword">重置</el-button>
- </el-form-item>
- </el-form>
- </el-tab-pane>
- </el-tabs>
- </el-card>
- </div>
- </template>
- <script setup>
- import { ref, reactive, onMounted } from 'vue'
- import { ElMessage } from 'element-plus'
- import { User } from '@element-plus/icons-vue'
- import request from '@/utils/request'
- import { API_ENDPOINTS } from '@/config/api'
- import { useUserStore } from '@/stores/user'
- const userStore = useUserStore()
- const activeTab = ref('basic')
- const saving = ref(false)
- const changingPassword = ref(false)
- const profileFormRef = ref(null)
- const passwordFormRef = ref(null)
- const defaultAvatar = 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
- const profileForm = reactive({
- id: null,
- username: '',
- realName: '',
- phone: '',
- email: '',
- avatar: ''
- })
- const passwordForm = reactive({
- oldPassword: '',
- newPassword: '',
- confirmPassword: ''
- })
- // 表单验证规则
- const profileRules = {
- realName: [
- { max: 50, message: '真实姓名长度不能超过50个字符', trigger: 'blur' }
- ],
- phone: [
- { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
- ],
- email: [
- { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
- ]
- }
- const passwordRules = {
- oldPassword: [
- { required: true, message: '请输入原密码', trigger: 'blur' }
- ],
- newPassword: [
- { required: true, message: '请输入新密码', trigger: 'blur' },
- { min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
- ],
- confirmPassword: [
- { required: true, message: '请确认新密码', trigger: 'blur' },
- {
- validator: (rule, value, callback) => {
- if (value !== passwordForm.newPassword) {
- callback(new Error('两次输入的密码不一致'))
- } else {
- callback()
- }
- },
- trigger: 'blur'
- }
- ]
- }
- // 加载个人资料
- const loadProfile = async () => {
- try {
- const response = await request.get(API_ENDPOINTS.ADMIN_USER_CURRENT_PROFILE)
- if (response.code === 200) {
- const data = response.data
- profileForm.id = data.id
- profileForm.username = data.username || ''
- profileForm.realName = data.realName || ''
- profileForm.phone = data.phone || ''
- profileForm.email = data.email || ''
- profileForm.avatar = data.avatar || ''
- }
- } catch (error) {
- console.error('加载个人资料失败:', error)
- ElMessage.error('加载个人资料失败')
- }
- }
- // 保存个人资料
- const handleSaveProfile = async () => {
- try {
- await profileFormRef.value.validate()
-
- saving.value = true
- const response = await request.put(API_ENDPOINTS.ADMIN_USER_UPDATE_CURRENT_PROFILE, {
- realName: profileForm.realName,
- phone: profileForm.phone,
- email: profileForm.email,
- avatar: profileForm.avatar
- })
-
- if (response.code === 200) {
- ElMessage.success('保存成功')
- // 更新用户信息
- await userStore.getUserInfo()
- } else {
- ElMessage.error(response.message || '保存失败')
- }
- } catch (error) {
- if (error !== false) { // validate 返回 false 时不显示错误
- console.error('保存个人资料失败:', error)
- ElMessage.error(error.message || '保存失败')
- }
- } finally {
- saving.value = false
- }
- }
- // 重置表单
- const handleReset = () => {
- loadProfile()
- }
- // 修改密码
- const handleChangePassword = async () => {
- try {
- await passwordFormRef.value.validate()
-
- changingPassword.value = true
- const response = await request.put(API_ENDPOINTS.ADMIN_USER_UPDATE_CURRENT_PASSWORD, {
- oldPassword: passwordForm.oldPassword,
- newPassword: passwordForm.newPassword
- })
-
- if (response.code === 200) {
- ElMessage.success('密码修改成功')
- handleResetPassword()
- } else {
- ElMessage.error(response.message || '密码修改失败')
- }
- } catch (error) {
- if (error !== false) { // validate 返回 false 时不显示错误
- console.error('修改密码失败:', error)
- ElMessage.error(error.message || '修改密码失败')
- }
- } finally {
- changingPassword.value = false
- }
- }
- // 重置密码表单
- const handleResetPassword = () => {
- passwordForm.oldPassword = ''
- passwordForm.newPassword = ''
- passwordForm.confirmPassword = ''
- passwordFormRef.value?.clearValidate()
- }
- // 头像上传前验证
- const beforeAvatarUpload = (file) => {
- const isImage = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg'
- const isLt2M = file.size / 1024 / 1024 < 2
- if (!isImage) {
- ElMessage.error('头像图片只能是 JPG/PNG 格式!')
- return false
- }
- if (!isLt2M) {
- ElMessage.error('头像图片大小不能超过 2MB!')
- return false
- }
- return true
- }
- // 头像上传
- const handleAvatarUpload = async (options) => {
- try {
- const formData = new FormData()
- formData.append('file', options.file)
-
- const response = await request.post(API_ENDPOINTS.UPLOAD_IMAGE, formData, {
- headers: {
- 'Content-Type': 'multipart/form-data'
- }
- })
-
- if (response.code === 200 && response.data) {
- profileForm.avatar = response.data.url || response.data
- ElMessage.success('头像上传成功')
- } else {
- ElMessage.error(response.message || '头像上传失败')
- }
- } catch (error) {
- console.error('头像上传失败:', error)
- ElMessage.error('头像上传失败')
- }
- }
- onMounted(() => {
- loadProfile()
- })
- </script>
- <style scoped>
- .profile-container {
- padding: 20px;
- }
- .profile-card {
- max-width: 900px;
- margin: 0 auto;
- }
- .card-header h2 {
- margin: 0;
- font-size: 20px;
- font-weight: 600;
- color: #303133;
- }
- .avatar-upload {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- gap: 12px;
- }
- .avatar-preview {
- border: 2px solid #dcdfe6;
- cursor: pointer;
- }
- .avatar-uploader {
- margin-top: 8px;
- }
- .avatar-tip {
- font-size: 12px;
- color: #909399;
- margin-top: -4px;
- }
- :deep(.el-tabs__content) {
- padding: 24px;
- }
- :deep(.el-form-item__label) {
- font-weight: 500;
- }
- :deep(.el-input__inner) {
- max-width: 400px;
- }
- </style>
|