blob: 8e37d76b542f95273cccc18d344c94429f062478 [file] [log] [blame]
<template>
<div class="profile-page">
<Navbar />
<div class="page-container">
<!-- 个人信息卡片 -->
<div class="profile-header">
<div class="user-avatar-section">
<div class="avatar-container">
<el-avatar :size="120" :src="userProfile.avatar">
{{ userProfile.username.charAt(0).toUpperCase() }}
</el-avatar>
<el-button
type="primary"
size="small"
class="change-avatar-btn"
@click="showAvatarDialog = true"
>
更换头像
</el-button>
</div>
<div class="user-basic-info">
<h1 class="username">{{ userProfile.username }}</h1>
<div class="user-title">
<el-tag :type="getUserTitleType(userProfile.userLevel)" size="large">
{{ userProfile.userTitle }}
</el-tag>
</div>
<div class="join-info">
<el-icon><Calendar /></el-icon>
<span>加入时间:{{ formatDate(userProfile.joinDate) }}</span>
</div>
<div class="last-login">
<el-icon><Clock /></el-icon>
<span>最后登录:{{ formatTime(userProfile.lastLogin) }}</span>
</div>
</div>
</div>
<div class="user-stats-overview">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon upload">
<el-icon size="32"><Upload /></el-icon>
</div>
<div class="stat-info">
<h3>{{ userProfile.stats.uploaded }}</h3>
<p>上传量</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon download">
<el-icon size="32"><Download /></el-icon>
</div>
<div class="stat-info">
<h3>{{ userProfile.stats.downloaded }}</h3>
<p>下载量</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon ratio" :class="getRatioClass(userProfile.stats.ratio)">
<el-icon size="32"><TrendCharts /></el-icon>
</div>
<div class="stat-info">
<h3>{{ userProfile.stats.ratio }}</h3>
<p>分享率</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon points">
<el-icon size="32"><Star /></el-icon>
</div>
<div class="stat-info">
<h3>{{ userProfile.stats.points }}</h3>
<p>积分</p>
</div>
</div>
</div>
</div>
</div>
<!-- 详细信息选项卡 -->
<div class="profile-content">
<el-tabs v-model="activeTab" type="border-card">
<!-- 个人信息 -->
<el-tab-pane label="个人信息" name="info">
<div class="info-section">
<el-form
ref="profileFormRef"
:model="editProfile"
:rules="profileRules"
label-width="120px"
size="large"
>
<div class="form-section">
<h3>基本信息</h3>
<el-form-item label="用户名">
<el-input v-model="editProfile.username" disabled>
<template #suffix>
<el-tooltip content="用户名不可修改">
<el-icon><QuestionFilled /></el-icon>
</el-tooltip>
</template>
</el-input>
</el-form-item>
<el-form-item label="邮箱地址" prop="email">
<el-input v-model="editProfile.email" type="email" />
</el-form-item>
<el-form-item label="真实姓名" prop="realName">
<el-input v-model="editProfile.realName" placeholder="可选填写" />
</el-form-item>
<el-form-item label="所在地区">
<el-cascader
v-model="editProfile.location"
:options="locationOptions"
placeholder="请选择地区"
clearable
/>
</el-form-item>
</div>
</el-form>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
<!-- 更换头像对话框 -->
<el-dialog v-model="showAvatarDialog" title="更换头像" width="400px">
<div class="avatar-upload">
<el-upload
ref="avatarUploadRef"
:auto-upload="false"
:limit="1"
accept="image/*"
:on-change="handleAvatarChange"
list-type="picture-card"
class="avatar-uploader"
>
<el-icon><Plus /></el-icon>
</el-upload>
<div class="upload-tips">
<p>支持 JPG、PNG 格式</p>
<p>建议尺寸 200x200 像素</p>
<p>文件大小不超过 2MB</p>
</div>
</div>
<template #footer>
<el-button @click="showAvatarDialog = false">取消</el-button>
<el-button type="primary" @click="uploadAvatar" :loading="uploadingAvatar">
上传头像
</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import {
Calendar,
Clock,
Upload,
Download,
TrendCharts,
Star,
QuestionFilled,
Plus
} from '@element-plus/icons-vue'
import Navbar from '@/components/Navbar.vue'
export default {
name: 'ProfileView',
components: {
Navbar
},
setup() {
const activeTab = ref('info')
const showAvatarDialog = ref(false)
const saving = ref(false)
const uploadingAvatar = ref(false)
const userProfile = ref({
username: 'MovieExpert',
email: 'movieexpert@example.com',
realName: '',
avatar: '',
userLevel: 5,
userTitle: '资深会员',
joinDate: '2023-01-15T10:00:00',
lastLogin: '2025-06-03T14:30:00',
location: ['北京市', '朝阳区'],
signature: '热爱电影,分享快乐!',
website: 'https://movieblog.com',
interests: ['电影', '音乐', '科技', '摄影'],
emailPublic: false,
statsPublic: true,
activityPublic: true,
stats: {
uploaded: '256.8 GB',
downloaded: '89.6 GB',
ratio: '2.87',
points: '15,680'
},
detailedStats: {
totalUploaded: '256.8 GB',
uploadedTorrents: 45,
avgUploadSize: '5.7 GB',
totalDownloaded: '89.6 GB',
downloadedTorrents: 123,
completedTorrents: 118,
seeding: 32,
seedingTime: '1,245 小时',
seedingRank: 86,
totalEarnedPoints: '28,940',
totalSpentPoints: '13,260'
}
})
const editProfile = reactive({
username: '',
email: '',
realName: '',
location: [],
signature: '',
website: '',
interests: [],
emailPublic: false,
statsPublic: true,
activityPublic: true
})
const profileRules = {
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
]
}
const locationOptions = [
{
value: '北京市',
label: '北京市',
children: [
{ value: '朝阳区', label: '朝阳区' },
{ value: '海淀区', label: '海淀区' },
{ value: '丰台区', label: '丰台区' }
]
},
{
value: '上海市',
label: '上海市',
children: [
{ value: '浦东新区', label: '浦东新区' },
{ value: '黄浦区', label: '黄浦区' },
{ value: '静安区', label: '静安区' }
]
}
]
onMounted(() => {
loadUserProfile()
})
const loadUserProfile = () => {
// 加载用户资料到编辑表单
Object.assign(editProfile, {
username: userProfile.value.username,
email: userProfile.value.email,
realName: userProfile.value.realName,
location: userProfile.value.location,
signature: userProfile.value.signature,
website: userProfile.value.website,
interests: [...userProfile.value.interests],
emailPublic: userProfile.value.emailPublic,
statsPublic: userProfile.value.statsPublic,
activityPublic: userProfile.value.activityPublic
})
}
const formatDate = (dateString) => {
const date = new Date(dateString)
return date.toLocaleDateString('zh-CN')
}
const formatTime = (timeString) => {
const date = new Date(timeString)
const now = new Date()
const diff = now - date
const hours = Math.floor(diff / (1000 * 60 * 60))
if (hours < 1) return '刚刚'
if (hours < 24) return `${hours}小时前`
const days = Math.floor(hours / 24)
if (days < 7) return `${days}天前`
return date.toLocaleDateString('zh-CN')
}
const getUserTitleType = (level) => {
if (level >= 8) return 'danger' // 管理员
if (level >= 6) return 'warning' // 资深会员
if (level >= 4) return 'success' // 正式会员
if (level >= 2) return 'info' // 初级会员
return 'default' // 新手
}
const getRatioClass = (ratio) => {
const r = parseFloat(ratio)
if (r >= 2) return 'excellent'
if (r >= 1) return 'good'
return 'warning'
}
const saveProfile = async () => {
try {
await profileFormRef.value?.validate()
saving.value = true
// 模拟保存过程
await new Promise(resolve => setTimeout(resolve, 1500))
// 更新用户资料
Object.assign(userProfile.value, editProfile)
ElMessage.success('个人资料保存成功')
} catch (error) {
console.error('表单验证失败:', error)
} finally {
saving.value = false
}
}
return {
activeTab,
showAvatarDialog,
saving,
userProfile,
editProfile,
profileRules,
locationOptions,
formatDate,
formatTime,
getUserTitleType,
getRatioClass,
saveProfile
}
}
}
</script>
<style scoped>
/* 添加相关样式 */
</style>