前端

Change-Id: If55994fd11ad8d1f70a52e9c3bd53eded5f37544
diff --git a/src/views/auth/ProfileView.vue b/src/views/auth/ProfileView.vue
index 73bdc57..b10ad9e 100644
--- a/src/views/auth/ProfileView.vue
+++ b/src/views/auth/ProfileView.vue
@@ -1,1347 +1,1225 @@
-<template>

-  <Navbar />

-  <div class="profile-page">

-    <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>

-                

-                <div class="form-section">

-                  <h3>个人介绍</h3>

-                  <el-form-item label="个人签名">

-                    <el-input

-                      v-model="editProfile.signature"

-                      type="textarea"

-                      :rows="3"

-                      maxlength="200"

-                      show-word-limit

-                      placeholder="介绍一下自己吧..."

-                    />

-                  </el-form-item>

-                  

-                  <el-form-item label="个人网站">

-                    <el-input v-model="editProfile.website" placeholder="https://" />

-                  </el-form-item>

-                  

-                  <el-form-item label="兴趣爱好">

-                    <div class="interests-input">

-                      <el-tag

-                        v-for="interest in editProfile.interests"

-                        :key="interest"

-                        closable

-                        @close="removeInterest(interest)"

-                        class="interest-tag"

-                      >

-                        {{ interest }}

-                      </el-tag>

-                      <el-input

-                        v-if="interestInputVisible"

-                        ref="interestInputRef"

-                        v-model="interestInputValue"

-                        size="small"

-                        @keyup.enter="addInterest"

-                        @blur="addInterest"

-                        style="width: 120px;"

-                      />

-                      <el-button

-                        v-else

-                        size="small"

-                        @click="showInterestInput"

-                      >

-                        + 添加兴趣

-                      </el-button>

-                    </div>

-                  </el-form-item>

-                </div>

-                

-                <div class="form-section">

-                  <h3>隐私设置</h3>

-                  <el-form-item label="邮箱公开">

-                    <el-switch v-model="editProfile.emailPublic" />

-                    <span class="setting-tip">是否在个人资料中显示邮箱</span>

-                  </el-form-item>

-                  

-                  <el-form-item label="统计公开">

-                    <el-switch v-model="editProfile.statsPublic" />

-                    <span class="setting-tip">是否公开上传下载统计</span>

-                  </el-form-item>

-                  

-                  <el-form-item label="活动记录">

-                    <el-switch v-model="editProfile.activityPublic" />

-                    <span class="setting-tip">是否公开活动记录</span>

-                  </el-form-item>

-                </div>

-                

-                <div class="form-actions">

-                  <el-button @click="resetProfile">重置</el-button>

-                  <el-button type="primary" @click="saveProfile" :loading="saving">

-                    保存修改

-                  </el-button>

-                </div>

-              </el-form>

-            </div>

-          </el-tab-pane>

-          

-          <!-- 数据统计 -->

-          <el-tab-pane label="数据统计" name="stats">

-            <div class="stats-section">

-              <div class="stats-overview">

-                <div class="overview-grid">

-                  <div class="overview-card">

-                    <h3>上传统计</h3>

-                    <div class="stat-details">

-                      <div class="detail-item">

-                        <span class="label">总上传量:</span>

-                        <span class="value">{{ userProfile.detailedStats.totalUploaded }}</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">上传种子:</span>

-                        <span class="value">{{ userProfile.detailedStats.uploadedTorrents }} 个</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">平均大小:</span>

-                        <span class="value">{{ userProfile.detailedStats.avgUploadSize }}</span>

-                      </div>

-                    </div>

-                  </div>

-                  

-                  <div class="overview-card">

-                    <h3>下载统计</h3>

-                    <div class="stat-details">

-                      <div class="detail-item">

-                        <span class="label">总下载量:</span>

-                        <span class="value">{{ userProfile.detailedStats.totalDownloaded }}</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">下载种子:</span>

-                        <span class="value">{{ userProfile.detailedStats.downloadedTorrents }} 个</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">完成种子:</span>

-                        <span class="value">{{ userProfile.detailedStats.completedTorrents }} 个</span>

-                      </div>

-                    </div>

-                  </div>

-                  

-                  <div class="overview-card">

-                    <h3>做种统计</h3>

-                    <div class="stat-details">

-                      <div class="detail-item">

-                        <span class="label">正在做种:</span>

-                        <span class="value">{{ userProfile.detailedStats.seeding }} 个</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">做种时间:</span>

-                        <span class="value">{{ userProfile.detailedStats.seedingTime }}</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">做种排名:</span>

-                        <span class="value">第 {{ userProfile.detailedStats.seedingRank }} 名</span>

-                      </div>

-                    </div>

-                  </div>

-                  

-                  <div class="overview-card">

-                    <h3>积分记录</h3>

-                    <div class="stat-details">

-                      <div class="detail-item">

-                        <span class="label">当前积分:</span>

-                        <span class="value">{{ userProfile.stats.points }}</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">累计获得:</span>

-                        <span class="value">{{ userProfile.detailedStats.totalEarnedPoints }}</span>

-                      </div>

-                      <div class="detail-item">

-                        <span class="label">累计消费:</span>

-                        <span class="value">{{ userProfile.detailedStats.totalSpentPoints }}</span>

-                      </div>

-                    </div>

-                  </div>

-                </div>

-              </div>

-              

-              <!-- 数据图表 -->

-              <div class="charts-section">

-                <div class="chart-card">

-                  <h3>上传下载趋势</h3>

-                  <div class="chart-placeholder">

-                    <el-icon size="48" color="#e4e7ed"><TrendCharts /></el-icon>

-                    <p>图表功能开发中...</p>

-                  </div>

-                </div>

-              </div>

-            </div>

-          </el-tab-pane>

-          

-          <!-- 我的种子 -->

-          <el-tab-pane label="我的种子" name="torrents">

-            <div class="torrents-section">

-              <div class="section-header">

-                <h3>我上传的种子</h3>

-                <el-button type="primary" :icon="Upload" @click="$router.push('/upload')">

-                  上传新种子

-                </el-button>

-              </div>

-              

-              <el-table :data="userTorrents" stripe>

-                <el-table-column label="种子名称" min-width="300">

-                  <template #default="{ row }">

-                    <div class="torrent-info">

-                      <el-tag :type="getCategoryType(row.category)" size="small">

-                        {{ getCategoryName(row.category) }}

-                      </el-tag>

-                      <span class="torrent-title">{{ row.title }}</span>

-                    </div>

-                  </template>

-                </el-table-column>

-                

-                <el-table-column label="大小" prop="size" width="100" />

-                <el-table-column label="做种" prop="seeders" width="80" align="center" />

-                <el-table-column label="下载" prop="leechers" width="80" align="center" />

-                <el-table-column label="完成" prop="downloads" width="80" align="center" />

-                <el-table-column label="上传时间" width="120">

-                  <template #default="{ row }">

-                    {{ formatDate(row.uploadTime) }}

-                  </template>

-                </el-table-column>

-                

-                <el-table-column label="操作" width="120" align="center">

-                  <template #default="{ row }">

-                    <el-button 

-                      type="primary" 

-                      size="small" 

-                      @click="$router.push(`/torrent/${row.id}`)"

-                    >

-                      查看

-                    </el-button>

-                  </template>

-                </el-table-column>

-              </el-table>

-              

-              <div class="pagination-wrapper">

-                <el-pagination

-                  v-model:current-page="torrentsPage"

-                  :page-size="10"

-                  :total="userTorrents.length"

-                  layout="prev, pager, next"

-                  small

-                />

-              </div>

-            </div>

-          </el-tab-pane>

-          

-          <!-- 活动记录 -->

-          <el-tab-pane label="活动记录" name="activity">

-            <div class="activity-section">

-              <div class="activity-filters">

-                <el-select v-model="activityFilter" placeholder="活动类型">

-                  <el-option label="全部活动" value="" />

-                  <el-option label="上传种子" value="upload" />

-                  <el-option label="下载种子" value="download" />

-                  <el-option label="论坛发帖" value="post" />

-                  <el-option label="积分变动" value="points" />

-                </el-select>

-              </div>

-              

-              <div class="activity-timeline">

-                <el-timeline>

-                  <el-timeline-item

-                    v-for="activity in filteredActivities"

-                    :key="activity.id"

-                    :timestamp="formatTime(activity.time)"

-                    :type="getActivityType(activity.type)"

-                  >

-                    <div class="activity-content">

-                      <div class="activity-header">

-                        <el-icon>

-                          <component :is="getActivityIcon(activity.type)" />

-                        </el-icon>

-                        <span class="activity-title">{{ activity.title }}</span>

-                      </div>

-                      <div class="activity-description">{{ activity.description }}</div>

-                    </div>

-                  </el-timeline-item>

-                </el-timeline>

-              </div>

-            </div>

-          </el-tab-pane>

-          

-          <!-- 安全设置 -->

-          <el-tab-pane label="安全设置" name="security">

-            <div class="security-section">

-              <div class="security-card">

-                <h3>修改密码</h3>

-                <el-form

-                  ref="passwordFormRef"

-                  :model="passwordForm"

-                  :rules="passwordRules"

-                  label-width="120px"

-                >

-                  <el-form-item label="当前密码" prop="currentPassword">

-                    <el-input

-                      v-model="passwordForm.currentPassword"

-                      type="password"

-                      show-password

-                      placeholder="请输入当前密码"

-                    />

-                  </el-form-item>

-                  

-                  <el-form-item label="新密码" prop="newPassword">

-                    <el-input

-                      v-model="passwordForm.newPassword"

-                      type="password"

-                      show-password

-                      placeholder="请输入新密码"

-                    />

-                  </el-form-item>

-                  

-                  <el-form-item label="确认密码" prop="confirmPassword">

-                    <el-input

-                      v-model="passwordForm.confirmPassword"

-                      type="password"

-                      show-password

-                      placeholder="请再次输入新密码"

-                    />

-                  </el-form-item>

-                  

-                  <el-form-item>

-                    <el-button type="primary" @click="changePassword" :loading="changingPassword">

-                      修改密码

-                    </el-button>

-                  </el-form-item>

-                </el-form>

-              </div>

-              

-              <div class="security-card">

-                <h3>登录记录</h3>

-                <el-table :data="loginHistory" stripe>

-                  <el-table-column label="登录时间" width="180">

-                    <template #default="{ row }">

-                      {{ formatDateTime(row.time) }}

-                    </template>

-                  </el-table-column>

-                  <el-table-column label="IP地址" prop="ip" width="150" />

-                  <el-table-column label="设备信息" prop="device" />

-                  <el-table-column label="登录结果" width="100">

-                    <template #default="{ row }">

-                      <el-tag :type="row.success ? 'success' : 'danger'" size="small">

-                        {{ row.success ? '成功' : '失败' }}

-                      </el-tag>

-                    </template>

-                  </el-table-column>

-                </el-table>

-              </div>

-            </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 { useRouter } from 'vue-router'

-import { ElMessage } from 'element-plus'

-import {

-  Calendar,

-  Clock,

-  Upload,

-  Download,

-  TrendCharts,

-  Star,

-  QuestionFilled,

-  Plus,

-  ChatDotRound,

-  Flag,

-  Coin

-} from '@element-plus/icons-vue'

-import Navbar from '@/components/Navbar.vue';

-export default {

-  name: 'ProfileView',

-  components:{

-    Navbar

-  },

-  setup() {

-    const router = useRouter()

-    const profileFormRef = ref(null)

-    const passwordFormRef = ref(null)

-    const avatarUploadRef = ref(null)

-    const interestInputRef = ref(null)

-    

-    const activeTab = ref('info')

-    const showAvatarDialog = ref(false)

-    const saving = ref(false)

-    const changingPassword = ref(false)

-    const uploadingAvatar = ref(false)

-    const interestInputVisible = ref(false)

-    const interestInputValue = ref('')

-    const activityFilter = ref('')

-    const torrentsPage = ref(1)

-    

-    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 passwordForm = reactive({

-      currentPassword: '',

-      newPassword: '',

-      confirmPassword: ''

-    })

-    

-    const profileRules = {

-      email: [

-        { required: true, message: '请输入邮箱地址', trigger: 'blur' },

-        { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }

-      ]

-    }

-    

-    const passwordRules = {

-      currentPassword: [

-        { 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 locationOptions = [

-      {

-        value: '北京市',

-        label: '北京市',

-        children: [

-          { value: '朝阳区', label: '朝阳区' },

-          { value: '海淀区', label: '海淀区' },

-          { value: '丰台区', label: '丰台区' }

-        ]

-      },

-      {

-        value: '上海市',

-        label: '上海市',

-        children: [

-          { value: '浦东新区', label: '浦东新区' },

-          { value: '黄浦区', label: '黄浦区' },

-          { value: '静安区', label: '静安区' }

-        ]

-      }

-    ]

-    

-    const userTorrents = ref([

-      {

-        id: 1,

-        title: '[4K蓝光原盘] 阿凡达:水之道',

-        category: 'movie',

-        size: '85.6 GB',

-        seeders: 45,

-        leechers: 12,

-        downloads: 234,

-        uploadTime: '2025-05-15T10:00:00'

-      },

-      {

-        id: 2,

-        title: '[FLAC] 古典音乐合集',

-        category: 'music',

-        size: '2.3 GB',

-        seeders: 23,

-        leechers: 5,

-        downloads: 89,

-        uploadTime: '2025-04-20T15:30:00'

-      }

-    ])

-    

-    const activities = ref([

-      {

-        id: 1,

-        type: 'upload',

-        title: '上传种子',

-        description: '上传了《阿凡达:水之道》4K蓝光原盘',

-        time: '2025-06-03T10:30:00'

-      },

-      {

-        id: 2,

-        type: 'download',

-        title: '下载种子',

-        description: '下载了《星际穿越》IMAX版本',

-        time: '2025-06-02T14:20:00'

-      },

-      {

-        id: 3,

-        type: 'post',

-        title: '发布主题',

-        description: '在电影讨论区发布了新主题',

-        time: '2025-06-01T16:45:00'

-      },

-      {

-        id: 4,

-        type: 'points',

-        title: '积分变动',

-        description: '做种奖励获得 +50 积分',

-        time: '2025-05-31T09:15:00'

-      }

-    ])

-    

-    const loginHistory = ref([

-      {

-        time: '2025-06-03T14:30:00',

-        ip: '192.168.1.100',

-        device: 'Windows 11 / Chrome 120',

-        success: true

-      },

-      {

-        time: '2025-06-02T09:15:00',

-        ip: '192.168.1.100',

-        device: 'Windows 11 / Chrome 120',

-        success: true

-      },

-      {

-        time: '2025-06-01T22:30:00',

-        ip: '192.168.1.100',

-        device: 'Android / Chrome Mobile',

-        success: true

-      }

-    ])

-    

-    const filteredActivities = computed(() => {

-      if (!activityFilter.value) return activities.value

-      return activities.value.filter(activity => activity.type === activityFilter.value)

-    })

-    

-    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 formatDateTime = (dateString) => {

-      const date = new Date(dateString)

-      return date.toLocaleString('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 getCategoryType = (category) => {

-      const types = {

-        'movie': 'primary',

-        'tv': 'info',

-        'music': 'success',

-        'software': 'warning',

-        'game': 'danger'

-      }

-      return types[category] || 'default'

-    }

-    

-    const getCategoryName = (category) => {

-      const names = {

-        'movie': '电影',

-        'tv': '电视剧',

-        'music': '音乐',

-        'software': '软件',

-        'game': '游戏'

-      }

-      return names[category] || category

-    }

-    

-    const getActivityType = (type) => {

-      const types = {

-        'upload': 'success',

-        'download': 'primary',

-        'post': 'warning',

-        'points': 'info'

-      }

-      return types[type] || 'primary'

-    }

-    

-    const getActivityIcon = (type) => {

-      const icons = {

-        'upload': 'Upload',

-        'download': 'Download',

-        'post': 'ChatDotRound',

-        'points': 'Coin'

-      }

-      return icons[type] || 'Star'

-    }

-    

-    const showInterestInput = () => {

-      interestInputVisible.value = true

-      nextTick(() => {

-        interestInputRef.value?.focus()

-      })

-    }

-    

-    const addInterest = () => {

-      const interest = interestInputValue.value.trim()

-      if (interest && !editProfile.interests.includes(interest)) {

-        editProfile.interests.push(interest)

-      }

-      interestInputVisible.value = false

-      interestInputValue.value = ''

-    }

-    

-    const removeInterest = (interest) => {

-      const index = editProfile.interests.indexOf(interest)

-      if (index > -1) {

-        editProfile.interests.splice(index, 1)

-      }

-    }

-    

-    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

-      }

-    }

-    

-    const resetProfile = () => {

-      loadUserProfile()

-      ElMessage.info('已重置为原始数据')

-    }

-    

-    const changePassword = async () => {

-      try {

-        await passwordFormRef.value?.validate()

-        

-        changingPassword.value = true

-        

-        // 模拟密码修改过程

-        await new Promise(resolve => setTimeout(resolve, 1500))

-        

-        // 重置表单

-        passwordFormRef.value?.resetFields()

-        Object.assign(passwordForm, {

-          currentPassword: '',

-          newPassword: '',

-          confirmPassword: ''

-        })

-        

-        ElMessage.success('密码修改成功')

-        

-      } catch (error) {

-        console.error('表单验证失败:', error)

-      } finally {

-        changingPassword.value = false

-      }

-    }

-    

-    const handleAvatarChange = (file) => {

-      const isImage = file.raw.type.startsWith('image/')

-      const isLt2M = file.raw.size / 1024 / 1024 < 2

-      

-      if (!isImage) {

-        ElMessage.error('只能上传图片文件!')

-        return false

-      }

-      if (!isLt2M) {

-        ElMessage.error('图片大小不能超过 2MB!')

-        return false

-      }

-      

-      return true

-    }

-    

-    const uploadAvatar = async () => {

-      const files = avatarUploadRef.value?.uploadFiles

-      if (!files || files.length === 0) {

-        ElMessage.warning('请选择头像文件')

-        return

-      }

-      

-      uploadingAvatar.value = true

-      try {

-        // 模拟上传过程

-        await new Promise(resolve => setTimeout(resolve, 2000))

-        

-        // 更新头像URL

-        userProfile.value.avatar = URL.createObjectURL(files[0].raw)

-        

-        ElMessage.success('头像上传成功')

-        showAvatarDialog.value = false

-        avatarUploadRef.value?.clearFiles()

-        

-      } catch (error) {

-        ElMessage.error('头像上传失败')

-      } finally {

-        uploadingAvatar.value = false

-      }

-    }

-    

-    return {

-      activeTab,

-      showAvatarDialog,

-      saving,

-      changingPassword,

-      uploadingAvatar,

-      interestInputVisible,

-      interestInputValue,

-      activityFilter,

-      torrentsPage,

-      userProfile,

-      editProfile,

-      passwordForm,

-      profileRules,

-      passwordRules,

-      locationOptions,

-      userTorrents,

-      filteredActivities,

-      loginHistory,

-      profileFormRef,

-      passwordFormRef,

-      avatarUploadRef,

-      interestInputRef,

-      formatDate,

-      formatTime,

-      formatDateTime,

-      getUserTitleType,

-      getRatioClass,

-      getCategoryType,

-      getCategoryName,

-      getActivityType,

-      getActivityIcon,

-      showInterestInput,

-      addInterest,

-      removeInterest,

-      saveProfile,

-      resetProfile,

-      changePassword,

-      handleAvatarChange,

-      uploadAvatar,

-      Calendar,

-      Clock,

-      Upload,

-      Download,

-      TrendCharts,

-      Star,

-      QuestionFilled,

-      Plus,

-      ChatDotRound,

-      Flag,

-      Coin

-    }

-  }

-}

-</script>

-

-<style lang="scss" scoped>

-.profile-page {

-  max-width: 1200px;

-  margin: 0 auto;

-  padding: 24px;

-  background: #f5f5f5;

-  min-height: 100vh;

-}

-

-.profile-header {

-  background: #fff;

-  border-radius: 12px;

-  padding: 32px;

-  margin-bottom: 24px;

-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);

-  

-  display: grid;

-  grid-template-columns: 1fr 1fr;

-  gap: 32px;

-  

-  .user-avatar-section {

-    display: flex;

-    gap: 24px;

-    

-    .avatar-container {

-      text-align: center;

-      

-      .change-avatar-btn {

-        margin-top: 12px;

-      }

-    }

-    

-    .user-basic-info {

-      flex: 1;

-      

-      .username {

-        font-size: 28px;

-        font-weight: 600;

-        color: #2c3e50;

-        margin: 0 0 12px 0;

-      }

-      

-      .user-title {

-        margin-bottom: 16px;

-      }

-      

-      .join-info, .last-login {

-        display: flex;

-        align-items: center;

-        gap: 8px;

-        font-size: 14px;

-        color: #7f8c8d;

-        margin-bottom: 8px;

-      }

-    }

-  }

-  

-  .user-stats-overview {

-    .stats-grid {

-      display: grid;

-      grid-template-columns: repeat(2, 1fr);

-      gap: 16px;

-      

-      .stat-card {

-        background: #f8f9fa;

-        border-radius: 8px;

-        padding: 20px;

-        display: flex;

-        align-items: center;

-        gap: 16px;

-        

-        .stat-icon {

-          width: 48px;

-          height: 48px;

-          border-radius: 50%;

-          display: flex;

-          align-items: center;

-          justify-content: center;

-          

-          &.upload { background: rgba(103, 194, 58, 0.1); color: #67c23a; }

-          &.download { background: rgba(64, 158, 255, 0.1); color: #409eff; }

-          &.ratio {

-            &.excellent { background: rgba(103, 194, 58, 0.1); color: #67c23a; }

-            &.good { background: rgba(230, 162, 60, 0.1); color: #e6a23c; }

-            &.warning { background: rgba(245, 108, 108, 0.1); color: #f56c6c; }

-          }

-          &.points { background: rgba(245, 108, 108, 0.1); color: #f56c6c; }

-        }

-        

-        .stat-info {

-          h3 {

-            font-size: 20px;

-            font-weight: 600;

-            color: #2c3e50;

-            margin: 0 0 4px 0;

-          }

-          

-          p {

-            font-size: 14px;

-            color: #7f8c8d;

-            margin: 0;

-          }

-        }

-      }

-    }

-  }

-}

-

-.profile-content {

-  background: #fff;

-  border-radius: 12px;

-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);

-  

-  :deep(.el-tabs__content) {

-    padding: 24px;

-  }

-}

-

-.info-section {

-  .form-section {

-    margin-bottom: 32px;

-    

-    h3 {

-      font-size: 18px;

-      font-weight: 600;

-      color: #2c3e50;

-      margin: 0 0 20px 0;

-      padding-bottom: 8px;

-      border-bottom: 2px solid #f0f0f0;

-    }

-  }

-  

-  .interests-input {

-    display: flex;

-    flex-wrap: wrap;

-    gap: 8px;

-    align-items: center;

-    

-    .interest-tag {

-      margin: 0;

-    }

-  }

-  

-  .setting-tip {

-    margin-left: 12px;

-    font-size: 12px;

-    color: #909399;

-  }

-  

-  .form-actions {

-    text-align: center;

-    margin-top: 32px;

-    

-    .el-button {

-      margin: 0 8px;

-      min-width: 100px;

-    }

-  }

-}

-

-.stats-section {

-  .stats-overview {

-    margin-bottom: 32px;

-    

-    .overview-grid {

-      display: grid;

-      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));

-      gap: 20px;

-      

-      .overview-card {

-        background: #f8f9fa;

-        border-radius: 8px;

-        padding: 24px;

-        

-        h3 {

-          font-size: 16px;

-          font-weight: 600;

-          color: #2c3e50;

-          margin: 0 0 16px 0;

-        }

-        

-        .stat-details {

-          .detail-item {

-            display: flex;

-            justify-content: space-between;

-            align-items: center;

-            margin-bottom: 12px;

-            

-            .label {

-              font-size: 14px;

-              color: #7f8c8d;

-            }

-            

-            .value {

-              font-size: 14px;

-              font-weight: 600;

-              color: #2c3e50;

-            }

-          }

-        }

-      }

-    }

-  }

-  

-  .charts-section {

-    .chart-card {

-      background: #f8f9fa;

-      border-radius: 8px;

-      padding: 24px;

-      

-      h3 {

-        font-size: 16px;

-        font-weight: 600;

-        color: #2c3e50;

-        margin: 0 0 20px 0;

-      }

-      

-      .chart-placeholder {

-        text-align: center;

-        padding: 60px 0;

-        color: #909399;

-        

-        p {

-          margin: 12px 0 0 0;

-        }

-      }

-    }

-  }

-}

-

-.torrents-section {

-  .section-header {

-    display: flex;

-    justify-content: space-between;

-    align-items: center;

-    margin-bottom: 20px;

-    

-    h3 {

-      font-size: 18px;

-      font-weight: 600;

-      color: #2c3e50;

-      margin: 0;

-    }

-  }

-  

-  .torrent-info {

-    display: flex;

-    align-items: center;

-    gap: 12px;

-    

-    .torrent-title {

-      font-weight: 500;

-    }

-  }

-  

-  .pagination-wrapper {

-    margin-top: 16px;

-    text-align: center;

-  }

-}

-

-.activity-section {

-  .activity-filters {

-    margin-bottom: 24px;

-    

-    .el-select {

-      width: 150px;

-    }

-  }

-  

-  .activity-timeline {

-    .activity-content {

-      .activity-header {

-        display: flex;

-        align-items: center;

-        gap: 8px;

-        margin-bottom: 8px;

-        

-        .activity-title {

-          font-weight: 600;

-          color: #2c3e50;

-        }

-      }

-      

-      .activity-description {

-        font-size: 14px;

-        color: #7f8c8d;

-        line-height: 1.5;

-      }

-    }

-  }

-}

-

-.security-section {

-  .security-card {

-    background: #f8f9fa;

-    border-radius: 8px;

-    padding: 24px;

-    margin-bottom: 24px;

-    

-    h3 {

-      font-size: 18px;

-      font-weight: 600;

-      color: #2c3e50;

-      margin: 0 0 20px 0;

-    }

-  }

-}

-

-.avatar-upload {

-  text-align: center;

-  

-  .avatar-uploader {

-    margin-bottom: 16px;

-  }

-  

-  .upload-tips {

-    font-size: 12px;

-    color: #909399;

-    

-    p {

-      margin: 4px 0;

-    }

-  }

-}

-

-@media (max-width: 768px) {

-  .profile-page {

-    padding: 16px;

-  }

-  

-  .profile-header {

-    grid-template-columns: 1fr;

-    gap: 24px;

-    

-    .user-avatar-section {

-      flex-direction: column;

-      text-align: center;

-    }

-    

-    .user-stats-overview .stats-grid {

-      grid-template-columns: 1fr;

-    }

-  }

-  

-  .stats-overview .overview-grid {

-    grid-template-columns: 1fr;

-  }

-  

-  .torrents-section .section-header {

-    flex-direction: column;

-    gap: 16px;

-    align-items: flex-start;

-  }

-}

+<template>
+  <div class="profile-page">
+    <Navbar />s
+    <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">{{ userBase.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>加入时间:{{ userBase.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>{{ 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>{{ stats.downloaded || '-' }}</h3>
+                <p>下载量</p>
+              </div>
+            </div>
+            
+            <div class="stat-card">
+              <div class="stat-icon ratio" :class="getRatioClass(calcRatio)">
+                <el-icon size="32"><TrendCharts /></el-icon>
+              </div>
+              <div class="stat-info">
+                <h3>{{ calcRatio }}</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>{{ 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="stats">
+            <div class="stats-section" v-if="stats">
+              <div class="stats-overview">
+                <div class="overview-grid">
+                  <div class="overview-card">
+                    <h3>上传统计</h3>
+                    <div class="stat-details">
+                      <div class="detail-item">
+                        <span class="label">总上传量:</span>
+                        <span class="value">{{ stats.uploaded || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">真实上传:</span>
+                        <span class="value">{{ stats.realUploaded || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">上传带宽:</span>
+                        <span class="value">{{ stats.uploadBandwidth || '-' }}</span>
+                      </div>
+                    </div>
+                  </div>
+                  
+                  <div class="overview-card">
+                    <h3>下载统计</h3>
+                    <div class="stat-details">
+                      <div class="detail-item">
+                        <span class="label">总下载量:</span>
+                        <span class="value">{{ stats.downloaded || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">真实下载:</span>
+                        <span class="value">{{ stats.realDownloaded || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">下载带宽:</span>
+                        <span class="value">{{ stats.downloadBandwidth || '-' }}</span>
+                      </div>
+                    </div>
+                  </div>
+                  
+                  <div class="overview-card">
+                    <h3>做种统计</h3>
+                    <div class="stat-details">
+                      <div class="detail-item">
+                        <span class="label">正在做种:</span>
+                        <span class="value">{{ stats.seeding || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">做种时间:</span>
+                        <span class="value">{{ stats.seedingTime || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">做种排名:</span>
+                        <span class="value">{{ stats.seedingRank || '-' }}</span>
+                      </div>
+                    </div>
+                  </div>
+
+                  <div class="overview-card">
+                    <h3>积分记录</h3>
+                    <div class="stat-details">
+                      <div class="detail-item">
+                        <span class="label">当前积分:</span>
+                        <span class="value">{{ stats.points || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">邀请名额:</span>
+                        <span class="value">{{ stats.inviteSlot || '-' }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="label">ISP:</span>
+                        <span class="value">{{ stats.isp || '-' }}</span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              
+              <!-- 数据图表 -->
+              <div class="charts-section">
+                <div class="chart-card">
+                  <h3>上传下载趋势</h3>
+                  <div class="chart-placeholder">
+                    <el-icon size="48" color="#e4e7ed"><TrendCharts /></el-icon>
+                    <p>图表功能开发中...</p>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+          
+          <!-- 我的种子 -->
+          <el-tab-pane label="我的种子" name="torrents">
+            <div class="torrents-section">
+              <div class="section-header">
+                <h3>我上传的种子</h3>
+                <el-button type="primary" :icon="Upload" @click="$router.push('/upload')">
+                  上传新种子
+                </el-button>
+              </div>
+              
+              <el-table :data="userTorrents" stripe>
+                <el-table-column label="种子名称" min-width="300">
+                  <template #default="{ row }">
+                    <div class="torrent-info">
+                      <el-tag :type="getCategoryType(row.category)" size="small">
+                        {{ getCategoryName(row.category) }}
+                      </el-tag>
+                      <span class="torrent-title">{{ row.title }}</span>
+                    </div>
+                  </template>
+                </el-table-column>
+                
+                <el-table-column label="大小" prop="size" width="100" />
+                <el-table-column label="做种" prop="seeders" width="80" align="center" />
+                <el-table-column label="下载" prop="leechers" width="80" align="center" />
+                <el-table-column label="完成" prop="downloads" width="80" align="center" />
+                <el-table-column label="上传时间" width="120">
+                  <template #default="{ row }">
+                    {{ formatDate(row.uploadTime) }}
+                  </template>
+                </el-table-column>
+                
+                <el-table-column label="操作" width="120" align="center">
+                  <template #default="{ row }">
+                    <el-button 
+                      type="primary" 
+                      size="small" 
+                      @click="$router.push(`/torrent/${row.id}`)"
+                    >
+                      查看
+                    </el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+              
+              <div class="pagination-wrapper">
+                <el-pagination
+                  :current-page="torrentsPage"
+                  :page-size="10"
+                  :total="userTorrents.length"
+                  layout="prev, pager, next"
+                  small
+                  @current-change="(page) => torrentsPage = page"
+                />
+              </div>
+            </div>
+          </el-tab-pane>
+          
+<!--          &lt;!&ndash; 活动记录 &ndash;&gt;-->
+<!--          <el-tab-pane label="活动记录" name="activity">-->
+<!--            <div class="activity-section">-->
+<!--              <div class="activity-filters">-->
+<!--                <el-select v-model="activityFilter" placeholder="活动类型">-->
+<!--                  <el-option label="全部活动" value="" />-->
+<!--                  <el-option label="上传种子" value="upload" />-->
+<!--                  <el-option label="下载种子" value="download" />-->
+<!--                  <el-option label="论坛发帖" value="post" />-->
+<!--                  <el-option label="积分变动" value="points" />-->
+<!--                </el-select>-->
+<!--              </div>-->
+<!--              -->
+<!--              <div class="activity-timeline">-->
+<!--                <el-timeline>-->
+<!--                  <el-timeline-item-->
+<!--                    v-for="activity in filteredActivities"-->
+<!--                    :key="activity.id"-->
+<!--                    :timestamp="formatTime(activity.time)"-->
+<!--                    :type="getActivityType(activity.type)"-->
+<!--                  >-->
+<!--                    <div class="activity-content">-->
+<!--                      <div class="activity-header">-->
+<!--                        <el-icon>-->
+<!--                          <component :is="getActivityIcon(activity.type)" />-->
+<!--                        </el-icon>-->
+<!--                        <span class="activity-title">{{ activity.title }}</span>-->
+<!--                      </div>-->
+<!--                      <div class="activity-description">{{ activity.description }}</div>-->
+<!--                    </div>-->
+<!--                  </el-timeline-item>-->
+<!--                </el-timeline>-->
+<!--              </div>-->
+<!--            </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 { useRouter } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import {
+  Calendar,
+  Clock,
+  Upload,
+  Download,
+  TrendCharts,
+  Star,
+  QuestionFilled,
+  Plus,
+  ChatDotRound,
+  Flag,
+  Coin
+} from '@element-plus/icons-vue'
+import { userApi } from '@/api/user'
+import Navbar from "@/components/Navbar.vue";
+
+export default {
+  name: 'ProfileView',
+  components: {Navbar},
+  setup() {
+    const router = useRouter()
+    const profileFormRef = ref(null)
+    const passwordFormRef = ref(null)
+    const avatarUploadRef = ref(null)
+    const interestInputRef = ref(null)
+    
+    const activeTab = ref('info')
+    const showAvatarDialog = ref(false)
+    const saving = ref(false)
+    const changingPassword = ref(false)
+    const uploadingAvatar = ref(false)
+    const interestInputVisible = ref(false)
+    const interestInputValue = ref('')
+    const activityFilter = ref('')
+    const torrentsPage = ref(1)
+    
+    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: '',
+      customTitle: '',
+      realName: '',
+      location: [],
+      signature: '',
+      website: '',
+      interests: [],
+      emailPublic: false,
+      statsPublic: true,
+      activityPublic: true
+    })
+    
+    const passwordForm = reactive({
+      currentPassword: '',
+      newPassword: '',
+      confirmPassword: ''
+    })
+    
+    const profileRules = {
+      email: [
+        { required: true, message: '请输入邮箱地址', trigger: 'blur' },
+        { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
+      ]
+    }
+    
+    const passwordRules = {
+      currentPassword: [
+        { 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 locationOptions = [
+      {
+        value: '北京市',
+        label: '北京市',
+        children: [
+          { value: '朝阳区', label: '朝阳区' },
+          { value: '海淀区', label: '海淀区' },
+          { value: '丰台区', label: '丰台区' }
+        ]
+      },
+      {
+        value: '上海市',
+        label: '上海市',
+        children: [
+          { value: '浦东新区', label: '浦东新区' },
+          { value: '黄浦区', label: '黄浦区' },
+          { value: '静安区', label: '静安区' }
+        ]
+      }
+    ]
+    
+    const userTorrents = ref([
+      {
+        id: 1,
+        title: '[4K蓝光原盘] 阿凡达:水之道',
+        category: 'movie',
+        size: '85.6 GB',
+        seeders: 45,
+        leechers: 12,
+        downloads: 234,
+        uploadTime: '2025-05-15T10:00:00'
+      },
+      {
+        id: 2,
+        title: '[FLAC] 古典音乐合集',
+        category: 'music',
+        size: '2.3 GB',
+        seeders: 23,
+        leechers: 5,
+        downloads: 89,
+        uploadTime: '2025-04-20T15:30:00'
+      }
+    ])
+    
+    const activities = ref([
+      {
+        id: 1,
+        type: 'upload',
+        title: '上传种子',
+        description: '上传了《阿凡达:水之道》4K蓝光原盘',
+        time: '2025-06-03T10:30:00'
+      },
+      {
+        id: 2,
+        type: 'download',
+        title: '下载种子',
+        description: '下载了《星际穿越》IMAX版本',
+        time: '2025-06-02T14:20:00'
+      },
+      {
+        id: 3,
+        type: 'post',
+        title: '发布主题',
+        description: '在电影讨论区发布了新主题',
+        time: '2025-06-01T16:45:00'
+      },
+      {
+        id: 4,
+        type: 'points',
+        title: '积分变动',
+        description: '做种奖励获得 +50 积分',
+        time: '2025-05-31T09:15:00'
+      }
+    ])
+    
+    const loginHistory = ref([
+      {
+        time: '2025-06-03T14:30:00',
+        ip: '192.168.1.100',
+        device: 'Windows 11 / Chrome 120',
+        success: true
+      },
+      {
+        time: '2025-06-02T09:15:00',
+        ip: '192.168.1.100',
+        device: 'Windows 11 / Chrome 120',
+        success: true
+      },
+      {
+        time: '2025-06-01T22:30:00',
+        ip: '192.168.1.100',
+        device: 'Android / Chrome Mobile',
+        success: true
+      }
+    ])
+    
+    const filteredActivities = computed(() => {
+      if (!activityFilter.value) return activities.value
+      return activities.value.filter(activity => activity.type === activityFilter.value)
+    })
+    
+    const stats = reactive({
+      uploaded: '-',
+      realUploaded: '-',
+      uploadBandwidth: '-',
+      downloaded: '-',
+      realDownloaded: '-',
+      downloadBandwidth: '-',
+      seeding: '-',
+      seedingTime: '-',
+      seedingRank: '-',
+      points: '-',
+      inviteSlot: '-',
+      isp: '-'
+    })
+    
+    const calcRatio = computed(() => {
+      if (!stats.uploaded || !stats.downloaded || stats.downloaded === '-' || stats.uploaded === '-') return '-'
+      const parseGB = (str) => {
+        if (typeof str !== 'string') return 0
+        if (str.endsWith('TB')) return parseFloat(str) * 1024
+        if (str.endsWith('GB')) return parseFloat(str)
+        if (str.endsWith('MB')) return parseFloat(str) / 1024
+        if (str.endsWith('KB')) return parseFloat(str) / 1024 / 1024
+        if (str.endsWith('B')) return parseFloat(str) / 1024 / 1024 / 1024
+        return parseFloat(str)
+      }
+      const up = parseGB(stats.uploaded)
+      const down = parseGB(stats.downloaded)
+      if (!down) return up > 0 ? '∞' : '0.00'
+      return (up / down).toFixed(2)
+    })
+    
+    const userBase = reactive({
+      username: '-',
+      joinDate: '-',
+    })
+    
+    onMounted(async () => {
+      try {
+        const res = await userApi.getCurrentUser()
+        if (res.user && res.user.user) {
+          const u = res.user.user
+          stats.uploaded = formatBytes(u.uploaded)
+          stats.realUploaded = formatBytes(u.realUploaded)
+          stats.uploadBandwidth = u.uploadBandwidth || '-'
+          stats.downloaded = formatBytes(u.downloaded)
+          stats.realDownloaded = formatBytes(u.realDownloaded)
+          stats.downloadBandwidth = u.downloadBandwidth || '-'
+          stats.seeding = u.seeding || '-'
+          stats.seedingTime = formatSeedingTime(u.seedingTime)
+          stats.seedingRank = u.seedingRank || '-'
+          stats.points = u.karma || '-'
+          stats.inviteSlot = u.inviteSlot || '-'
+          stats.isp = u.isp || '-'
+          userBase.username = u.username || '-'
+          userBase.joinDate = u.createdAt ? formatDate(u.createdAt) : '-'
+        }
+      } catch (e) {
+        ElMessage.error('获取数据失败')
+      }
+    })
+    
+    const getUserTitleByLevel = (level) => {
+      if (level == null) return '新手'
+      if (level >= 8) return '管理员'
+      if (level >= 6) return '资深会员'
+      if (level >= 4) return '正式会员'
+      if (level >= 2) return '初级会员'
+      return '新手'
+    }
+    
+    const formatBytes = (bytes) => {
+      if (!bytes || isNaN(bytes)) return '0 B'
+      const k = 1024
+      const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
+      const i = Math.floor(Math.log(bytes) / Math.log(k))
+      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
+    }
+    
+    const formatSeedingTime = (seconds) => {
+      if (!seconds || isNaN(seconds)) return '0 小时'
+      const hours = Math.floor(seconds / 3600)
+      const days = Math.floor(hours / 24)
+      if (days > 0) {
+        return `${days} 天 ${hours % 24} 小时`
+      } else {
+        return `${hours} 小时`
+      }
+    }
+    
+    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 formatDateTime = (dateString) => {
+      const date = new Date(dateString)
+      return date.toLocaleString('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 getCategoryType = (category) => {
+      const types = {
+        'movie': 'primary',
+        'tv': 'info',
+        'music': 'success',
+        'software': 'warning',
+        'game': 'danger'
+      }
+      return types[category] || 'default'
+    }
+    
+    const getCategoryName = (category) => {
+      const names = {
+        'movie': '电影',
+        'tv': '电视剧',
+        'music': '音乐',
+        'software': '软件',
+        'game': '游戏'
+      }
+      return names[category] || category
+    }
+
+    const getLanguageName = (language) => {
+      const languages = {
+        'zh-CN': '简体中文',
+        'zh-TW': '繁体中文',
+        'en-US': 'English',
+        'ja-JP': '日本語',
+        'ko-KR': '한국어'
+      }
+      return languages[language] || language
+    }
+    
+    const getActivityType = (type) => {
+      const types = {
+        'upload': 'success',
+        'download': 'primary',
+        'post': 'warning',
+        'points': 'info'
+      }
+      return types[type] || 'primary'
+    }
+    
+    const getActivityIcon = (type) => {
+      const icons = {
+        'upload': 'Upload',
+        'download': 'Download',
+        'post': 'ChatDotRound',
+        'points': 'Coin'
+      }
+      return icons[type] || 'Star'
+    }
+    
+    const showInterestInput = () => {
+      interestInputVisible.value = true
+      nextTick(() => {
+        interestInputRef.value?.focus()
+      })
+    }
+    
+    const addInterest = () => {
+      const interest = interestInputValue.value.trim()
+      if (interest && !editProfile.interests.includes(interest)) {
+        editProfile.interests.push(interest)
+      }
+      interestInputVisible.value = false
+      interestInputValue.value = ''
+    }
+    
+    const removeInterest = (interest) => {
+      const index = editProfile.interests.indexOf(interest)
+      if (index > -1) {
+        editProfile.interests.splice(index, 1)
+      }
+    }
+    
+    const saveProfile = async () => {
+      try {
+        const payload = {
+          username: editProfile.username,
+          email: editProfile.email
+        }
+        await userApi.updateProfile(payload)
+        ElMessage.success('保存成功')
+      } catch (error) {
+        ElMessage.error('保存失败')
+      }
+    }
+    
+    const resetProfile = () => {
+      loadUserProfile()
+      ElMessage.info('已重置为原始数据')
+    }
+    
+    const changePassword = async () => {
+      try {
+        await passwordFormRef.value?.validate()
+        
+        changingPassword.value = true
+        
+        // 模拟密码修改过程
+        await new Promise(resolve => setTimeout(resolve, 1500))
+        
+        // 重置表单
+        passwordFormRef.value?.resetFields()
+        Object.assign(passwordForm, {
+          currentPassword: '',
+          newPassword: '',
+          confirmPassword: ''
+        })
+        
+        ElMessage.success('密码修改成功')
+        
+      } catch (error) {
+        console.error('表单验证失败:', error)
+      } finally {
+        changingPassword.value = false
+      }
+    }
+    
+    const handleAvatarChange = (file) => {
+      const isImage = file.raw.type.startsWith('image/')
+      const isLt2M = file.raw.size / 1024 / 1024 < 2
+      
+      if (!isImage) {
+        ElMessage.error('只能上传图片文件!')
+        return false
+      }
+      if (!isLt2M) {
+        ElMessage.error('图片大小不能超过 2MB!')
+        return false
+      }
+      
+      return true
+    }
+    
+    const uploadAvatar = async () => {
+      const files = avatarUploadRef.value?.uploadFiles
+      if (!files || files.length === 0) {
+        ElMessage.warning('请选择头像文件')
+        return
+      }
+      
+      uploadingAvatar.value = true
+      try {
+        // 模拟上传过程
+        await new Promise(resolve => setTimeout(resolve, 2000))
+        
+        // 更新头像URL
+        userProfile.value.avatar = URL.createObjectURL(files[0].raw)
+        
+        ElMessage.success('头像上传成功')
+        showAvatarDialog.value = false
+        avatarUploadRef.value?.clearFiles()
+        
+      } catch (error) {
+        ElMessage.error('头像上传失败')
+      } finally {
+        uploadingAvatar.value = false
+      }
+    }
+    
+    return {
+      activeTab,
+      showAvatarDialog,
+      saving,
+      changingPassword,
+      uploadingAvatar,
+      interestInputVisible,
+      interestInputValue,
+      activityFilter,
+      torrentsPage,
+      userProfile,
+      editProfile,
+      passwordForm,
+      profileRules,
+      passwordRules,
+      locationOptions,
+      userTorrents,
+      filteredActivities,
+      loginHistory,
+      profileFormRef,
+      passwordFormRef,
+      avatarUploadRef,
+      interestInputRef,
+      formatDate,
+      formatTime,
+      formatDateTime,
+      getUserTitleType,
+      getRatioClass,
+      getCategoryType,
+      getCategoryName,
+      getActivityType,
+      getActivityIcon,
+      showInterestInput,
+      addInterest,
+      removeInterest,
+      saveProfile,
+      resetProfile,
+      changePassword,
+      handleAvatarChange,
+      uploadAvatar,
+      Calendar,
+      Clock,
+      Upload,
+      Download,
+      TrendCharts,
+      Star,
+      QuestionFilled,
+      Plus,
+      ChatDotRound,
+      Flag,
+      Coin,
+      stats,
+      calcRatio,
+      userBase
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.profile-page {
+  max-width: 1200px;
+  margin: 0 auto;
+  padding: 24px;
+  background: #f5f5f5;
+  min-height: 100vh;
+}
+
+.profile-header {
+  background: #fff;
+  border-radius: 12px;
+  padding: 32px;
+  margin-bottom: 24px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+  
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 32px;
+  
+  .user-avatar-section {
+    display: flex;
+    gap: 24px;
+    
+    .avatar-container {
+      text-align: center;
+      
+      .change-avatar-btn {
+        margin-top: 12px;
+      }
+    }
+    
+    .user-basic-info {
+      flex: 1;
+      
+      .username {
+        font-size: 28px;
+        font-weight: 600;
+        color: #2c3e50;
+        margin: 0 0 12px 0;
+      }
+      
+      .user-title {
+        margin-bottom: 16px;
+      }
+      
+      .join-info, .last-login {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        font-size: 14px;
+        color: #7f8c8d;
+        margin-bottom: 8px;
+      }
+    }
+  }
+  
+  .user-stats-overview {
+    .stats-grid {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      gap: 16px;
+      
+      .stat-card {
+        background: #f8f9fa;
+        border-radius: 8px;
+        padding: 20px;
+        display: flex;
+        align-items: center;
+        gap: 16px;
+        
+        .stat-icon {
+          width: 48px;
+          height: 48px;
+          border-radius: 50%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          
+          &.upload { background: rgba(103, 194, 58, 0.1); color: #67c23a; }
+          &.download { background: rgba(64, 158, 255, 0.1); color: #409eff; }
+          &.ratio {
+            &.excellent { background: rgba(103, 194, 58, 0.1); color: #67c23a; }
+            &.good { background: rgba(230, 162, 60, 0.1); color: #e6a23c; }
+            &.warning { background: rgba(245, 108, 108, 0.1); color: #f56c6c; }
+          }
+          &.points { background: rgba(245, 108, 108, 0.1); color: #f56c6c; }
+        }
+        
+        .stat-info {
+          h3 {
+            font-size: 20px;
+            font-weight: 600;
+            color: #2c3e50;
+            margin: 0 0 4px 0;
+          }
+          
+          p {
+            font-size: 14px;
+            color: #7f8c8d;
+            margin: 0;
+          }
+        }
+      }
+    }
+  }
+}
+
+.profile-content {
+  background: #fff;
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+  
+  :deep(.el-tabs__content) {
+    padding: 24px;
+  }
+}
+
+.info-section {
+  .form-section {
+    margin-bottom: 32px;
+    
+    h3 {
+      font-size: 18px;
+      font-weight: 600;
+      color: #2c3e50;
+      margin: 0 0 20px 0;
+      padding-bottom: 8px;
+      border-bottom: 2px solid #f0f0f0;
+    }
+  }
+  
+  .interests-input {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+    align-items: center;
+    
+    .interest-tag {
+      margin: 0;
+    }
+  }
+  
+  .setting-tip {
+    margin-left: 12px;
+    font-size: 12px;
+    color: #909399;
+  }
+  
+  .form-actions {
+    text-align: center;
+    margin-top: 32px;
+    
+    .el-button {
+      margin: 0 8px;
+      min-width: 100px;
+    }
+  }
+}
+
+.stats-section {
+  .stats-overview {
+    margin-bottom: 32px;
+    
+    .overview-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+      gap: 20px;
+      
+      .overview-card {
+        background: #f8f9fa;
+        border-radius: 8px;
+        padding: 24px;
+        
+        h3 {
+          font-size: 16px;
+          font-weight: 600;
+          color: #2c3e50;
+          margin: 0 0 16px 0;
+        }
+        
+        .stat-details {
+          .detail-item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 12px;
+            
+            .label {
+              font-size: 14px;
+              color: #7f8c8d;
+            }
+            
+            .value {
+              font-size: 14px;
+              font-weight: 600;
+              color: #2c3e50;
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  .charts-section {
+    .chart-card {
+      background: #f8f9fa;
+      border-radius: 8px;
+      padding: 24px;
+      
+      h3 {
+        font-size: 16px;
+        font-weight: 600;
+        color: #2c3e50;
+        margin: 0 0 20px 0;
+      }
+      
+      .chart-placeholder {
+        text-align: center;
+        padding: 60px 0;
+        color: #909399;
+        
+        p {
+          margin: 12px 0 0 0;
+        }
+      }
+    }
+  }
+}
+
+.torrents-section {
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+    
+    h3 {
+      font-size: 18px;
+      font-weight: 600;
+      color: #2c3e50;
+      margin: 0;
+    }
+  }
+  
+  .torrent-info {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    
+    .torrent-title {
+      font-weight: 500;
+    }
+  }
+  
+  .pagination-wrapper {
+    margin-top: 16px;
+    text-align: center;
+  }
+}
+
+.activity-section {
+  .activity-filters {
+    margin-bottom: 24px;
+    
+    .el-select {
+      width: 150px;
+    }
+  }
+  
+  .activity-timeline {
+    .activity-content {
+      .activity-header {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        margin-bottom: 8px;
+        
+        .activity-title {
+          font-weight: 600;
+          color: #2c3e50;
+        }
+      }
+      
+      .activity-description {
+        font-size: 14px;
+        color: #7f8c8d;
+        line-height: 1.5;
+      }
+    }
+  }
+}
+
+.avatar-upload {
+  text-align: center;
+  
+  .avatar-uploader {
+    margin-bottom: 16px;
+  }
+  
+  .upload-tips {
+    font-size: 12px;
+    color: #909399;
+    
+    p {
+      margin: 4px 0;
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .profile-page {
+    padding: 16px;
+  }
+  
+  .profile-header {
+    grid-template-columns: 1fr;
+    gap: 24px;
+    
+    .user-avatar-section {
+      flex-direction: column;
+      text-align: center;
+    }
+    
+    .user-stats-overview .stats-grid {
+      grid-template-columns: 1fr;
+    }
+  }
+  
+  .stats-overview .overview-grid {
+    grid-template-columns: 1fr;
+  }
+  
+  .torrents-section .section-header {
+    flex-direction: column;
+    gap: 16px;
+    align-items: flex-start;
+  }
+}
 </style>
\ No newline at end of file