203 lines
4.7 KiB
Vue
203 lines
4.7 KiB
Vue
<template>
|
||
<div class="ucenter">
|
||
<a-card>
|
||
<a-row :gutter="24">
|
||
<a-col :span="6">
|
||
<ProfileInfo :user-info="userInfo" @avatar-click="showAvatarModal = true" />
|
||
<a-menu v-model:selectedKeys="selectedKeys" mode="inline" class="menu">
|
||
<a-menu-item key="basic">
|
||
<UserOutlined />
|
||
基本信息
|
||
</a-menu-item>
|
||
<a-menu-item key="password">
|
||
<LockOutlined />
|
||
修改密码
|
||
</a-menu-item>
|
||
<a-menu-item key="security">
|
||
<SafetyOutlined />
|
||
账号安全
|
||
</a-menu-item>
|
||
</a-menu>
|
||
</a-col>
|
||
<a-col :span="18">
|
||
<div class="content-wrapper">
|
||
<BasicInfo v-if="selectedKeys[0] === 'basic'" :user-info="userInfo"
|
||
@update="handleUpdateUserInfo" />
|
||
<Password v-else-if="selectedKeys[0] === 'password'" @success="handlePasswordSuccess" />
|
||
<Security v-else-if="selectedKeys[0] === 'security'" @change-password="handleChangePassword" />
|
||
</div>
|
||
</a-col>
|
||
</a-row>
|
||
</a-card>
|
||
|
||
<!-- 头像上传弹窗 -->
|
||
<a-modal v-model:open="showAvatarModal" title="更换头像" :confirm-loading="loading" @ok="handleAvatarUpload"
|
||
@cancel="showAvatarModal = false">
|
||
<div class="avatar-upload">
|
||
<a-upload list-type="picture-card" :max-count="1" :before-upload="beforeUpload"
|
||
@change="handleAvatarChange" :file-list="avatarFileList">
|
||
<div v-if="avatarFileList.length === 0">
|
||
<PlusOutlined />
|
||
<div class="ant-upload-text">上传头像</div>
|
||
</div>
|
||
</a-upload>
|
||
<div class="upload-tip">
|
||
<a-typography-text type="secondary"> 支持 JPG、PNG 格式,文件大小不超过 2MB </a-typography-text>
|
||
</div>
|
||
</div>
|
||
</a-modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue'
|
||
import { message } from 'ant-design-vue'
|
||
import { PlusOutlined, UserOutlined, LockOutlined, SafetyOutlined } from '@ant-design/icons-vue'
|
||
import dayjs from 'dayjs'
|
||
import ProfileInfo from './components/ProfileInfo.vue'
|
||
import BasicInfo from './components/BasicInfo.vue'
|
||
import Password from './components/Password.vue'
|
||
import Security from './components/Security.vue'
|
||
|
||
// 用户信息
|
||
const userInfo = ref({
|
||
username: '',
|
||
nickname: '',
|
||
phone: '',
|
||
email: '',
|
||
avatar: '',
|
||
status: 1,
|
||
gender: 0,
|
||
birthday: null,
|
||
bio: '',
|
||
})
|
||
|
||
// 选中的菜单
|
||
const selectedKeys = ref(['basic'])
|
||
|
||
// 头像上传
|
||
const showAvatarModal = ref(false)
|
||
const avatarFileList = ref([])
|
||
const loading = ref(false)
|
||
|
||
// 初始化用户信息
|
||
const initUserInfo = () => {
|
||
// 模拟用户数据
|
||
const mockUserInfo = {
|
||
username: 'admin',
|
||
nickname: '管理员',
|
||
phone: '13800138000',
|
||
email: 'admin@example.com',
|
||
avatar: '',
|
||
status: 1,
|
||
gender: 1,
|
||
birthday: dayjs('1990-01-01'),
|
||
bio: '热爱编程,专注于前端开发技术。',
|
||
}
|
||
userInfo.value = { ...mockUserInfo }
|
||
}
|
||
|
||
// 更新用户信息
|
||
const handleUpdateUserInfo = (data) => {
|
||
Object.assign(userInfo.value, data)
|
||
}
|
||
|
||
// 密码修改成功
|
||
const handlePasswordSuccess = () => {
|
||
// 密码修改成功后的处理
|
||
}
|
||
|
||
// 切换到密码修改页面
|
||
const handleChangePassword = () => {
|
||
selectedKeys.value = ['password']
|
||
}
|
||
|
||
// 头像上传前校验
|
||
const beforeUpload = (file) => {
|
||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
|
||
if (!isJpgOrPng) {
|
||
message.error('只能上传 JPG/PNG 格式的文件!')
|
||
return false
|
||
}
|
||
const isLt2M = file.size / 1024 / 1024 < 2
|
||
if (!isLt2M) {
|
||
message.error('图片大小不能超过 2MB!')
|
||
return false
|
||
}
|
||
return false // 阻止自动上传
|
||
}
|
||
|
||
// 头像文件变化
|
||
const handleAvatarChange = ({ fileList }) => {
|
||
avatarFileList.value = fileList
|
||
}
|
||
|
||
// 上传头像
|
||
const handleAvatarUpload = () => {
|
||
if (avatarFileList.value.length === 0) {
|
||
message.warning('请先选择头像')
|
||
return
|
||
}
|
||
loading.value = true
|
||
// 模拟上传
|
||
setTimeout(() => {
|
||
const file = avatarFileList.value[0]
|
||
userInfo.value.avatar = URL.createObjectURL(file.originFileObj)
|
||
message.success('头像更新成功')
|
||
showAvatarModal.value = false
|
||
avatarFileList.value = []
|
||
loading.value = false
|
||
}, 1000)
|
||
}
|
||
|
||
onMounted(() => {
|
||
initUserInfo()
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.ucenter {
|
||
.content-wrapper {
|
||
padding: 24px;
|
||
background: #fafafa;
|
||
border-radius: 8px;
|
||
min-height: 400px;
|
||
}
|
||
|
||
.menu {
|
||
margin-top: 16px;
|
||
background: transparent;
|
||
border: none;
|
||
|
||
.ant-menu-item {
|
||
border-radius: 6px;
|
||
margin: 4px 0;
|
||
|
||
&:hover {
|
||
background: rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
&.ant-menu-item-selected {
|
||
background: rgba(255, 255, 255, 0.4);
|
||
|
||
&::after {
|
||
border-right-width: 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.avatar-upload {
|
||
.upload-tip {
|
||
margin-top: 16px;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
:deep(.ant-card-head-title) {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
</style>
|