前端

Change-Id: If55994fd11ad8d1f70a52e9c3bd53eded5f37544
diff --git a/src/api/request.js b/src/api/request.js
index 0e06f0a..01da8a3 100644
--- a/src/api/request.js
+++ b/src/api/request.js
@@ -5,7 +5,7 @@
 const request = axios.create({

   // 关键:不要设置baseURL,或者设置为空字符串

   // 这样请求会发送到当前域名(8080),然后被代理转发到8081

-  baseURL: process.env.VUE_APP_BASE_API || '/api',

+  baseURL: process.env.VUE_APP_BASE_API || '',

   timeout: 10000,

   headers: {

     // 'Content-Type': 'application/json'

@@ -15,15 +15,27 @@
 request.interceptors.request.use(

   config => {

     const token = localStorage.getItem('token')

-    console.log('📤 添加 token 到请求头:', token)

+    console.log('📤 Token长度:', token ? token.length : 0)

+    console.log('📤 Token前50字符:', token ? token.substring(0, 50) + '...' : 'null')

+    

     if (token) {

+      // 检查token是否过大

+      if (token.length > 8000) {

+        console.warn('⚠️ Token过大,长度:', token.length)

+        // 清除过大的token

+        localStorage.removeItem('token')

+        localStorage.removeItem('tokenInfo')

+        localStorage.removeItem('userInfo')

+        localStorage.removeItem('isLoggedIn')

+        ElMessage.error('登录信息过大,请重新登录')

+        router.push('/login')

+        return Promise.reject(new Error('Token过大'))

+      }

       config.headers.Authorization = `Bearer ${token}`

     }

     

     console.log('🚀 发送请求:', config.method?.toUpperCase(), config.url)

     console.log('📤 请求数据:', config.data)

-    console.log('🔍 VUE_APP_BASE_API:', process.env.VUE_APP_BASE_API)

-    console.log('🔍 VUE_APP_BACKEND:', process.env.VUE_APP_BACKEND)

     

     return config

   },

@@ -59,6 +71,15 @@
           ElMessage.error('API接口不存在')

           console.error('❌ 请求的URL:', error.config.url)

           break

+        case 431:

+          console.error('❌ 请求头太大 (431),可能是Token过大')

+          localStorage.removeItem('token')

+          localStorage.removeItem('tokenInfo')

+          localStorage.removeItem('userInfo')

+          localStorage.removeItem('isLoggedIn')

+          ElMessage.error('登录信息过大,请重新登录')

+          router.push('/login')

+          break

         case 500:

           ElMessage.error('服务器内部错误')

           break

diff --git a/src/api/torrent.js b/src/api/torrent.js
index 586e22c..e49887e 100644
--- a/src/api/torrent.js
+++ b/src/api/torrent.js
@@ -140,16 +140,4 @@
     url: `/torrent/download/${infoHash}`,

     method: 'get'

   })

-}

-

-/**

- * 获取种子下载数

- * @param {string} infoHash - 种子的info hash

- * @returns {Promise}

- */

-export function downloadTorrentNum(infoHash) {

-  return request({

-    url: `/torrent/${infoHash}/downloads`,

-    method: 'get'

-  })

 }
\ No newline at end of file
diff --git a/src/api/user.js b/src/api/user.js
index 2cfb40c..32073b1 100644
--- a/src/api/user.js
+++ b/src/api/user.js
@@ -7,7 +7,18 @@
    */

   getCurrentUser() {

     return request({

-      url: '/user/profile',

+      url: '/auth/status',

+      method: 'get'

+    })

+  },

+

+  /**

+   * 获取用户分享率和统计信息

+   * @returns {Promise<Object>} 分享率统计信息

+   */

+  getUserRatioInfo() {

+    return request({

+      url: '/torrent/ratio/info',

       method: 'get'

     })

   },

diff --git a/src/router/index.js b/src/router/index.js
index 7f60f9e..b2854a4 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -10,7 +10,6 @@
 import TopicView from '@/views/forum/TopicView.vue'

 import ChatRoom from '@/views/ChatRoom.vue'

 

-

 const routes = [

   {

     path: '/',

@@ -72,7 +71,7 @@
     }

   },

   {

-    path: '/torrent/:infoHash',

+    path: '/torrent/:id',

     name: 'TorrentDetail',

     component: () => import('@/views/torrent/TorrentDetailView.vue'),

     meta: {

diff --git a/src/views/ChatRoom.vue b/src/views/ChatRoom.vue
index 979dcc0..860505e 100644
--- a/src/views/ChatRoom.vue
+++ b/src/views/ChatRoom.vue
@@ -1,6 +1,6 @@
 <template>
-  <Navbar />
   <div class="chat-room">
+    <Navbar />
     <h2>聊天室</h2>
     <div class="chat-messages" ref="messagesRef">
       <div v-for="(msg, idx) in messages" :key="idx" class="chat-message">
@@ -20,9 +20,7 @@
 import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
 import { useStore } from 'vuex'
 import axios from 'axios'
-import Navbar from '@/components/Navbar.vue';
-
-
+import Navbar from "@/components/Navbar.vue";
 
 const store = useStore()
 const wsUrl = 'ws://localhost:8081/api/ws/chat'
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 3e1af4e..1828d28 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -1,640 +1,640 @@
-<template>

-  <div class="home-page">

-    <!-- 导航栏 -->

-    <Navbar />

-

-    <!-- 主内容区 -->

-    <div class="main-content">

-      <!-- 欢迎卡片 -->

-      <div class="welcome-card">

-        <div class="welcome-header">

-          <h1>欢迎回来,{{ username }}!</h1>

-          <p>当前时间:{{ currentTime }}</p>

-        </div>

-        

-        <!-- 用户统计概览 -->

-        <div class="stats-overview" v-if="userInfo">

-          <div class="stat-item">

-            <div class="stat-icon upload">

-              <el-icon size="24"><Upload /></el-icon>

-            </div>

-            <div class="stat-content">

-              <h3>{{ formatBytes(userInfo.user.uploaded) }}</h3>

-              <p>总上传</p>

-            </div>

-          </div>

-          

-          <div class="stat-item">

-            <div class="stat-icon download">

-              <el-icon size="24"><Download /></el-icon>

-            </div>

-            <div class="stat-content">

-              <h3>{{ formatBytes(userInfo.user.downloaded) }}</h3>

-              <p>总下载</p>

-            </div>

-          </div>

-          

-          <div class="stat-item">

-            <div class="stat-icon ratio">

-              <el-icon size="24"><TrendCharts /></el-icon>

-            </div>

-            <div class="stat-content">

-              <h3>{{ calculateRatio(userInfo.user.uploaded, userInfo.user.downloaded) }}</h3>

-              <p>分享率</p>

-            </div>

-          </div>

-          

-          <div class="stat-item">

-            <div class="stat-icon points">

-              <el-icon size="24"><Star /></el-icon>

-            </div>

-            <div class="stat-content">

-              <h3>{{ userInfo.user.karma || '0' }}</h3>

-              <p>积分</p>

-            </div>

-          </div>

-        </div>

-      </div>

-

-      <!-- 功能快捷入口 -->

-      <div class="quick-actions">

-        <h2>快捷操作</h2>

-        <div class="actions-grid">

-          <div class="action-card" @click="$router.push('/upload')">

-            <el-icon size="32" color="#67c23a"><Upload /></el-icon>

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

-            <p>分享你的资源</p>

-          </div>

-          

-          <div class="action-card" @click="$router.push('/torrents')">

-            <el-icon size="32" color="#409eff"><Search /></el-icon>

-            <h3>浏览种子</h3>

-            <p>发现新内容</p>

-          </div>

-          

-          <div class="action-card" @click="$router.push('/forum')">

-            <el-icon size="32" color="#e6a23c"><ChatDotRound /></el-icon>

-            <h3>社区论坛</h3>

-            <p>交流讨论</p>

-          </div>

-          

-          <div class="action-card" @click="$router.push('/profile')">

-            <el-icon size="32" color="#f56c6c"><User /></el-icon>

-            <h3>个人中心</h3>

-            <p>管理账户</p>

-          </div>

-          <div class="action-card" @click="$router.push('/chat')">

-            <el-icon size="32" color="#8e44ad"><ChatDotRound /></el-icon>

-            <h3>聊天室</h3>

-            <p>实时聊天互动</p>

-          </div>

-        </div>

-      </div>

-

-      <!-- API连接状态测试 -->

-      <div class="api-status-card">

-        <h2>API连接状态</h2>

-        <div class="status-items">

-          <div class="status-item">

-            <el-icon :color="loginStatusColor"><CircleCheck /></el-icon>

-            <span>登录状态:{{ loginStatusText }}</span>

-            <el-button size="small" @click="checkLoginStatus">检查状态</el-button>

-          </div>

-          

-          <div class="status-item">

-            <el-icon :color="userInfoStatusColor"><User /></el-icon>

-            <span>用户信息:{{ userInfoStatusText }}</span>

-            <el-button size="small" @click="refreshUserInfo">刷新信息</el-button>

-          </div>

-        </div>

-        

-        <!-- 用户详细信息展示 -->

-        <div class="user-details" v-if="userInfo">

-          <h3>用户详细信息</h3>

-          <div class="details-grid">

-            <div class="detail-item">

-              <label>用户ID:</label>

-              <span>{{ userInfo.user.id }}</span>

-            </div>

-            <div class="detail-item">

-              <label>用户名:</label>

-              <span>{{ userInfo.user.username }}</span>

-            </div>

-            <div class="detail-item">

-              <label>邮箱:</label>

-              <span>{{ userInfo.user.email }}</span>

-            </div>

-            <div class="detail-item">

-              <label>用户组:</label>

-              <span>{{ userInfo.user.group?.displayName || '未知' }}</span>

-            </div>

-            <div class="detail-item">

-              <label>注册时间:</label>

-              <span>{{ formatDate(userInfo.user.createdAt) }}</span>

-            </div>

-            <div class="detail-item">

-              <label>个性签名:</label>

-              <span>{{ userInfo.user.signature || '这个用户很懒,还没有个性签名' }}</span>

-            </div>

-          </div>

-        </div>

-      </div>

-    </div>

-  </div>

-</template>

-

-<script>

-import { ref, computed, onMounted, onUnmounted } from 'vue'

-import { useRouter } from 'vue-router'

-import { useStore } from 'vuex'

-import { ElMessage, ElMessageBox } from 'element-plus'

-import {

-  ArrowDown,

-  User,

-  Setting,

-  SwitchButton,

-  Upload,

-  Download,

-  TrendCharts,

-  Star,

-  Search,

-  ChatDotRound,

-  CircleCheck

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

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

-

-export default {

-  name: 'HomeView',

-  components: {

-    ArrowDown,

-    User,

-    Setting,

-    SwitchButton,

-    Upload,

-    Download,

-    TrendCharts,

-    Star,

-    Search,

-    ChatDotRound,

-    CircleCheck,

-    Navbar

-  },

-  setup() {

-    const router = useRouter()

-    const store = useStore()

-    

-    const currentTime = ref('')

-    const timeInterval = ref(null)

-    

-    // 从store获取用户信息

-    const userInfo = computed(() => store.getters['auth/userInfo'])

-    const username = computed(() => store.getters['auth/username'])

-    const userAvatar = computed(() => store.getters['auth/avatar'])

-    const isAuthenticated = computed(() => store.getters['auth/isAuthenticated'])

-    

-    // API状态

-    const loginStatusColor = computed(() => isAuthenticated.value ? '#67c23a' : '#f56c6c')

-    const loginStatusText = computed(() => isAuthenticated.value ? '已登录' : '未登录')

-    

-    const userInfoStatusColor = computed(() => userInfo.value ? '#67c23a' : '#f56c6c')

-    const userInfoStatusText = computed(() => userInfo.value ? '已获取' : '未获取')

-    

-    // 更新当前时间

-    const updateCurrentTime = () => {

-      currentTime.value = new Date().toLocaleString('zh-CN')

-    }

-    

-    // 格式化字节数

-    const formatBytes = (bytes) => {

-      if (!bytes || bytes === 0) return '0 B'

-      

-      const sizes = ['B', 'KB', 'MB', 'GB', 'TB']

-      const i = Math.floor(Math.log(bytes) / Math.log(1024))

-      const size = (bytes / Math.pow(1024, i)).toFixed(2)

-      

-      return `${size} ${sizes[i]}`

-    }

-    

-    // 计算分享率

-    const calculateRatio = (uploaded, downloaded) => {

-      if (!uploaded || !downloaded || downloaded === 0) {

-        return uploaded > 0 ? '∞' : '0.00'

-      }

-      return (uploaded / downloaded).toFixed(2)

-    }

-    

-    // 格式化日期

-    const formatDate = (timestamp) => {

-      if (!timestamp) return '未知'

-      return new Date(timestamp).toLocaleDateString('zh-CN')

-    }

-    

-    // 检查登录状态

-    const checkLoginStatus = async () => {

-      try {

-        await store.dispatch('auth/checkLoginStatus')

-        ElMessage.success('登录状态检查完成')

-      } catch (error) {

-        console.error('检查登录状态失败:', error)

-        ElMessage.error('检查登录状态失败')

-      }

-    }

-    

-    // 刷新用户信息

-    const refreshUserInfo = async () => {

-      try {

-        await store.dispatch('auth/checkLoginStatus')

-        ElMessage.success('用户信息刷新成功')

-      } catch (error) {

-        console.error('刷新用户信息失败:', error)

-        ElMessage.error('刷新用户信息失败')

-      }

-    }

-    

-    // 处理用户菜单命令

-    const handleUserCommand = async (command) => {

-      switch (command) {

-        case 'profile':

-          router.push('/profile')

-          break

-        case 'settings':

-          ElMessage.info('设置功能开发中...')

-          break

-        case 'logout':

-          try {

-            await ElMessageBox.confirm('确定要退出登录吗?', '提示', {

-              confirmButtonText: '确定',

-              cancelButtonText: '取消',

-              type: 'warning'

-            })

-            

-            await store.dispatch('auth/logout')

-            router.push('/login')

-          } catch (error) {

-            // 用户取消操作

-            if (error !== 'cancel') {

-              console.error('退出登录失败:', error)

-            }

-          }

-          break

-      }

-    }

-    

-    onMounted(() => {

-      // 开始时间更新

-      updateCurrentTime()

-      timeInterval.value = setInterval(updateCurrentTime, 1000)

-      

-      // 检查登录状态

-      if (!isAuthenticated.value) {

-        checkLoginStatus()

-      }

-    })

-    

-    onUnmounted(() => {

-      // 清理定时器

-      if (timeInterval.value) {

-        clearInterval(timeInterval.value)

-      }

-    })

-    

-    return {

-      currentTime,

-      userInfo,

-      username,

-      userAvatar,

-      isAuthenticated,

-      loginStatusColor,

-      loginStatusText,

-      userInfoStatusColor,

-      userInfoStatusText,

-      formatBytes,

-      calculateRatio,

-      formatDate,

-      checkLoginStatus,

-      refreshUserInfo,

-      handleUserCommand

-    }

-  }

-}

-</script>

-

-<style lang="scss" scoped>

-.home-page {

-  min-height: 100vh;

-  background: #f5f5f5;

-}

-

-.navbar {

-  background: #fff;

-  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);

-  height: 60px;

-  display: flex;

-  align-items: center;

-  justify-content: space-between;

-  padding: 0 24px;

-  position: sticky;

-  top: 0;

-  z-index: 1000;

-}

-

-.navbar-brand {

-  font-size: 20px;

-  font-weight: 700;

-  color: #409eff;

-  text-decoration: none;

-}

-

-.navbar-nav {

-  display: flex;

-  align-items: center;

-  gap: 24px;

-}

-

-.navbar-item {

-  color: #606266;

-  text-decoration: none;

-  font-weight: 500;

-  transition: color 0.3s;

-  

-  &:hover {

-    color: #409eff;

-  }

-}

-

-.navbar-user {

-  display: flex;

-  align-items: center;

-  gap: 8px;

-  cursor: pointer;

-  padding: 8px;

-  border-radius: 6px;

-  transition: background-color 0.3s;

-  

-  &:hover {

-    background-color: #f5f7fa;

-  }

-  

-  .username {

-    font-weight: 500;

-    color: #303133;

-  }

-}

-

-.main-content {

-  max-width: 1200px;

-  margin: 0 auto;

-  padding: 24px;

-}

-

-.welcome-card {

-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

-  color: white;

-  border-radius: 12px;

-  padding: 32px;

-  margin-bottom: 24px;

-  

-  .welcome-header {

-    text-align: center;

-    margin-bottom: 24px;

-    

-    h1 {

-      font-size: 28px;

-      margin-bottom: 8px;

-    }

-    

-    p {

-      opacity: 0.9;

-      font-size: 14px;

-    }

-  }

-  

-  .stats-overview {

-    display: grid;

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

-    gap: 16px;

-    

-    .stat-item {

-      background: rgba(255, 255, 255, 0.1);

-      backdrop-filter: blur(10px);

-      border-radius: 8px;

-      padding: 20px;

-      display: flex;

-      align-items: center;

-      gap: 16px;

-      

-      .stat-icon {

-        width: 48px;

-        height: 48px;

-        border-radius: 50%;

-        background: rgba(255, 255, 255, 0.2);

-        display: flex;

-        align-items: center;

-        justify-content: center;

-      }

-      

-      .stat-content {

-        h3 {

-          font-size: 20px;

-          font-weight: 600;

-          margin: 0 0 4px 0;

-        }

-        

-        p {

-          font-size: 14px;

-          opacity: 0.8;

-          margin: 0;

-        }

-      }

-    }

-  }

-}

-

-.quick-actions {

-  background: #fff;

-  border-radius: 12px;

-  padding: 24px;

-  margin-bottom: 24px;

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

-  

-  h2 {

-    font-size: 20px;

-    color: #303133;

-    margin: 0 0 20px 0;

-  }

-  

-  .actions-grid {

-    display: grid;

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

-    gap: 16px;

-    

-    .action-card {

-      background: #f8f9fa;

-      border-radius: 8px;

-      padding: 24px;

-      text-align: center;

-      cursor: pointer;

-      transition: all 0.3s;

-      border: 2px solid transparent;

-      

-      &:hover {

-        transform: translateY(-2px);

-        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);

-        border-color: #409eff;

-      }

-      

-      h3 {

-        font-size: 16px;

-        color: #303133;

-        margin: 12px 0 8px 0;

-      }

-      

-      p {

-        font-size: 14px;

-        color: #909399;

-        margin: 0;

-      }

-    }

-  }

-}

-

-.api-status-card {

-  background: #fff;

-  border-radius: 12px;

-  padding: 24px;

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

-  

-  h2 {

-    font-size: 20px;

-    color: #303133;

-    margin: 0 0 20px 0;

-  }

-  

-  .status-items {

-    margin-bottom: 24px;

-    

-    .status-item {

-      display: flex;

-      align-items: center;

-      gap: 12px;

-      padding: 12px 0;

-      border-bottom: 1px solid #ebeef5;

-      

-      &:last-child {

-        border-bottom: none;

-      }

-      

-      span {

-        flex: 1;

-        font-size: 14px;

-        color: #606266;

-      }

-    }

-  }

-  

-  .user-details {

-    border-top: 1px solid #ebeef5;

-    padding-top: 20px;

-    

-    h3 {

-      font-size: 16px;

-      color: #303133;

-      margin: 0 0 16px 0;

-    }

-    

-    .details-grid {

-      display: grid;

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

-      gap: 12px;

-      

-      .detail-item {

-        display: flex;

-        align-items: center;

-        padding: 8px 0;

-        

-        label {

-          font-weight: 500;

-          color: #909399;

-          min-width: 80px;

-          font-size: 14px;

-        }

-        

-        span {

-          color: #606266;

-          font-size: 14px;

-        }

-      }

-    }

-  }

-}

-

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

-  .navbar {

-    padding: 0 16px;

-    

-    .navbar-nav {

-      gap: 16px;

-    }

-    

-    .navbar-user .username {

-      display: none;

-    }

-  }

-  

-  .main-content {

-    padding: 16px;

-  }

-  

-  .welcome-card {

-    padding: 24px 16px;

-    

-    .welcome-header h1 {

-      font-size: 24px;

-    }

-    

-    .stats-overview {

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

-      gap: 12px;

-      

-      .stat-item {

-        padding: 16px;

-        

-        .stat-content h3 {

-          font-size: 16px;

-        }

-      }

-    }

-  }

-  

-  .actions-grid {

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

-    gap: 12px;

-    

-    .action-card {

-      padding: 16px;

-      

-      h3 {

-        font-size: 14px;

-      }

-      

-      p {

-        font-size: 12px;

-      }

-    }

-  }

-  

-  .details-grid {

-    grid-template-columns: 1fr;

-  }

-}

-

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

-  .stats-overview {

-    grid-template-columns: 1fr;

-  }

-  

-  .actions-grid {

-    grid-template-columns: 1fr;

-  }

-}

+<template>
+  <div class="home-page">
+    <!-- 导航栏 -->
+    <Navbar />
+
+    <!-- 主内容区 -->
+    <div class="main-content">
+      <!-- 欢迎卡片 -->
+      <div class="welcome-card">
+        <div class="welcome-header">
+          <h1>欢迎回来,{{ username }}!</h1>
+          <p>当前时间:{{ currentTime }}</p>
+        </div>
+        
+        <!-- 用户统计概览 -->
+        <div class="stats-overview" v-if="userInfo">
+          <div class="stat-item">
+            <div class="stat-icon upload">
+              <el-icon size="24"><Upload /></el-icon>
+            </div>
+            <div class="stat-content">
+              <h3>{{ formatBytes(userInfo.user.uploaded) }}</h3>
+              <p>总上传</p>
+            </div>
+          </div>
+          
+          <div class="stat-item">
+            <div class="stat-icon download">
+              <el-icon size="24"><Download /></el-icon>
+            </div>
+            <div class="stat-content">
+              <h3>{{ formatBytes(userInfo.user.downloaded) }}</h3>
+              <p>总下载</p>
+            </div>
+          </div>
+          
+          <div class="stat-item">
+            <div class="stat-icon ratio">
+              <el-icon size="24"><TrendCharts /></el-icon>
+            </div>
+            <div class="stat-content">
+              <h3>{{ calculateRatio(userInfo.user.uploaded, userInfo.user.downloaded) }}</h3>
+              <p>分享率</p>
+            </div>
+          </div>
+          
+          <div class="stat-item">
+            <div class="stat-icon points">
+              <el-icon size="24"><Star /></el-icon>
+            </div>
+            <div class="stat-content">
+              <h3>{{ userInfo.user.karma || '0' }}</h3>
+              <p>积分</p>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 功能快捷入口 -->
+      <div class="quick-actions">
+        <h2>快捷操作</h2>
+        <div class="actions-grid">
+          <div class="action-card" @click="$router.push('/upload')">
+            <el-icon size="32" color="#67c23a"><Upload /></el-icon>
+            <h3>上传种子</h3>
+            <p>分享你的资源</p>
+          </div>
+          
+          <div class="action-card" @click="$router.push('/torrents')">
+            <el-icon size="32" color="#409eff"><Search /></el-icon>
+            <h3>浏览种子</h3>
+            <p>发现新内容</p>
+          </div>
+          
+          <div class="action-card" @click="$router.push('/forum')">
+            <el-icon size="32" color="#e6a23c"><ChatDotRound /></el-icon>
+            <h3>社区论坛</h3>
+            <p>交流讨论</p>
+          </div>
+          
+          <div class="action-card" @click="$router.push('/profile')">
+            <el-icon size="32" color="#f56c6c"><User /></el-icon>
+            <h3>个人中心</h3>
+            <p>管理账户</p>
+          </div>
+          <div class="action-card" @click="$router.push('/chat')">
+            <el-icon size="32" color="#8e44ad"><ChatDotRound /></el-icon>
+            <h3>聊天室</h3>
+            <p>实时聊天互动</p>
+          </div>
+        </div>
+      </div>
+
+      <!-- API连接状态测试 -->
+      <div class="api-status-card">
+<!--        <h2>API连接状态</h2>-->
+<!--        <div class="status-items">-->
+<!--          <div class="status-item">-->
+<!--            <el-icon :color="loginStatusColor"><CircleCheck /></el-icon>-->
+<!--            <span>登录状态:{{ loginStatusText }}</span>-->
+<!--            <el-button size="small" @click="checkLoginStatus">检查状态</el-button>-->
+<!--          </div>-->
+<!--          -->
+<!--          <div class="status-item">-->
+<!--            <el-icon :color="userInfoStatusColor"><User /></el-icon>-->
+<!--            <span>用户信息:{{ userInfoStatusText }}</span>-->
+<!--            <el-button size="small" @click="refreshUserInfo">刷新信息</el-button>-->
+<!--          </div>-->
+<!--        </div>-->
+        
+        <!-- 用户详细信息展示 -->
+        <div class="user-details" v-if="userInfo">
+          <h3>用户详细信息</h3>
+          <div class="details-grid">
+            <div class="detail-item">
+              <label>用户ID:</label>
+              <span>{{ userInfo.user.id }}</span>
+            </div>
+            <div class="detail-item">
+              <label>用户名:</label>
+              <span>{{ userInfo.user.username }}</span>
+            </div>
+            <div class="detail-item">
+              <label>邮箱:</label>
+              <span>{{ userInfo.user.email }}</span>
+            </div>
+            <div class="detail-item">
+              <label>用户组:</label>
+              <span>{{ userInfo.user.group?.displayName || '未知' }}</span>
+            </div>
+            <div class="detail-item">
+              <label>注册时间:</label>
+              <span>{{ formatDate(userInfo.user.createdAt) }}</span>
+            </div>
+            <div class="detail-item">
+              <label>个性签名:</label>
+              <span>{{ userInfo.user.signature || '这个用户很懒,还没有个性签名' }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { ref, computed, onMounted, onUnmounted } from 'vue'
+import { useRouter } from 'vue-router'
+import { useStore } from 'vuex'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import {
+  ArrowDown,
+  User,
+  Setting,
+  SwitchButton,
+  Upload,
+  Download,
+  TrendCharts,
+  Star,
+  Search,
+  ChatDotRound,
+  CircleCheck
+} from '@element-plus/icons-vue'
+import Navbar from "@/components/Navbar.vue";
+
+export default {
+  name: 'HomeView',
+  components: {
+    ArrowDown,
+    User,
+    Setting,
+    SwitchButton,
+    Upload,
+    Download,
+    TrendCharts,
+    Star,
+    Search,
+    ChatDotRound,
+    CircleCheck,
+    Navbar
+  },
+  setup() {
+    const router = useRouter()
+    const store = useStore()
+    
+    const currentTime = ref('')
+    const timeInterval = ref(null)
+    
+    // 从store获取用户信息
+    const userInfo = computed(() => store.getters['auth/userInfo'])
+    const username = computed(() => store.getters['auth/username'])
+    const userAvatar = computed(() => store.getters['auth/avatar'])
+    const isAuthenticated = computed(() => store.getters['auth/isAuthenticated'])
+    
+    // API状态
+    const loginStatusColor = computed(() => isAuthenticated.value ? '#67c23a' : '#f56c6c')
+    const loginStatusText = computed(() => isAuthenticated.value ? '已登录' : '未登录')
+    
+    const userInfoStatusColor = computed(() => userInfo.value ? '#67c23a' : '#f56c6c')
+    const userInfoStatusText = computed(() => userInfo.value ? '已获取' : '未获取')
+    
+    // 更新当前时间
+    const updateCurrentTime = () => {
+      currentTime.value = new Date().toLocaleString('zh-CN')
+    }
+    
+    // 格式化字节数
+    const formatBytes = (bytes) => {
+      if (!bytes || bytes === 0) return '0 B'
+      
+      const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
+      const i = Math.floor(Math.log(bytes) / Math.log(1024))
+      const size = (bytes / Math.pow(1024, i)).toFixed(2)
+      
+      return `${size} ${sizes[i]}`
+    }
+    
+    // 计算分享率
+    const calculateRatio = (uploaded, downloaded) => {
+      if (!uploaded || !downloaded || downloaded === 0) {
+        return uploaded > 0 ? '∞' : '0.00'
+      }
+      return (uploaded / downloaded).toFixed(2)
+    }
+    
+    // 格式化日期
+    const formatDate = (timestamp) => {
+      if (!timestamp) return '未知'
+      return new Date(timestamp).toLocaleDateString('zh-CN')
+    }
+    
+    // 检查登录状态
+    const checkLoginStatus = async () => {
+      try {
+        await store.dispatch('auth/checkLoginStatus')
+        ElMessage.success('登录状态检查完成')
+      } catch (error) {
+        console.error('检查登录状态失败:', error)
+        ElMessage.error('检查登录状态失败')
+      }
+    }
+    
+    // 刷新用户信息
+    const refreshUserInfo = async () => {
+      try {
+        await store.dispatch('auth/checkLoginStatus')
+        ElMessage.success('用户信息刷新成功')
+      } catch (error) {
+        console.error('刷新用户信息失败:', error)
+        ElMessage.error('刷新用户信息失败')
+      }
+    }
+    
+    // 处理用户菜单命令
+    const handleUserCommand = async (command) => {
+      switch (command) {
+        case 'profile':
+          router.push('/profile')
+          break
+        case 'settings':
+          ElMessage.info('设置功能开发中...')
+          break
+        case 'logout':
+          try {
+            await ElMessageBox.confirm('确定要退出登录吗?', '提示', {
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+              type: 'warning'
+            })
+            
+            await store.dispatch('auth/logout')
+            router.push('/login')
+          } catch (error) {
+            // 用户取消操作
+            if (error !== 'cancel') {
+              console.error('退出登录失败:', error)
+            }
+          }
+          break
+      }
+    }
+    
+    onMounted(() => {
+      // 开始时间更新
+      updateCurrentTime()
+      timeInterval.value = setInterval(updateCurrentTime, 1000)
+      
+      // 检查登录状态
+      if (!isAuthenticated.value) {
+        checkLoginStatus()
+      }
+    })
+    
+    onUnmounted(() => {
+      // 清理定时器
+      if (timeInterval.value) {
+        clearInterval(timeInterval.value)
+      }
+    })
+    
+    return {
+      currentTime,
+      userInfo,
+      username,
+      userAvatar,
+      isAuthenticated,
+      loginStatusColor,
+      loginStatusText,
+      userInfoStatusColor,
+      userInfoStatusText,
+      formatBytes,
+      calculateRatio,
+      formatDate,
+      checkLoginStatus,
+      refreshUserInfo,
+      handleUserCommand
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.home-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.navbar {
+  background: #fff;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  height: 60px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 24px;
+  position: sticky;
+  top: 0;
+  z-index: 1000;
+}
+
+.navbar-brand {
+  font-size: 20px;
+  font-weight: 700;
+  color: #409eff;
+  text-decoration: none;
+}
+
+.navbar-nav {
+  display: flex;
+  align-items: center;
+  gap: 24px;
+}
+
+.navbar-item {
+  color: #606266;
+  text-decoration: none;
+  font-weight: 500;
+  transition: color 0.3s;
+  
+  &:hover {
+    color: #409eff;
+  }
+}
+
+.navbar-user {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  cursor: pointer;
+  padding: 8px;
+  border-radius: 6px;
+  transition: background-color 0.3s;
+  
+  &:hover {
+    background-color: #f5f7fa;
+  }
+  
+  .username {
+    font-weight: 500;
+    color: #303133;
+  }
+}
+
+.main-content {
+  max-width: 1200px;
+  margin: 0 auto;
+  padding: 24px;
+}
+
+.welcome-card {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  border-radius: 12px;
+  padding: 32px;
+  margin-bottom: 24px;
+  
+  .welcome-header {
+    text-align: center;
+    margin-bottom: 24px;
+    
+    h1 {
+      font-size: 28px;
+      margin-bottom: 8px;
+    }
+    
+    p {
+      opacity: 0.9;
+      font-size: 14px;
+    }
+  }
+  
+  .stats-overview {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+    gap: 16px;
+    
+    .stat-item {
+      background: rgba(255, 255, 255, 0.1);
+      backdrop-filter: blur(10px);
+      border-radius: 8px;
+      padding: 20px;
+      display: flex;
+      align-items: center;
+      gap: 16px;
+      
+      .stat-icon {
+        width: 48px;
+        height: 48px;
+        border-radius: 50%;
+        background: rgba(255, 255, 255, 0.2);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+      
+      .stat-content {
+        h3 {
+          font-size: 20px;
+          font-weight: 600;
+          margin: 0 0 4px 0;
+        }
+        
+        p {
+          font-size: 14px;
+          opacity: 0.8;
+          margin: 0;
+        }
+      }
+    }
+  }
+}
+
+.quick-actions {
+  background: #fff;
+  border-radius: 12px;
+  padding: 24px;
+  margin-bottom: 24px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+  
+  h2 {
+    font-size: 20px;
+    color: #303133;
+    margin: 0 0 20px 0;
+  }
+  
+  .actions-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+    gap: 16px;
+    
+    .action-card {
+      background: #f8f9fa;
+      border-radius: 8px;
+      padding: 24px;
+      text-align: center;
+      cursor: pointer;
+      transition: all 0.3s;
+      border: 2px solid transparent;
+      
+      &:hover {
+        transform: translateY(-2px);
+        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
+        border-color: #409eff;
+      }
+      
+      h3 {
+        font-size: 16px;
+        color: #303133;
+        margin: 12px 0 8px 0;
+      }
+      
+      p {
+        font-size: 14px;
+        color: #909399;
+        margin: 0;
+      }
+    }
+  }
+}
+
+.api-status-card {
+  background: #fff;
+  border-radius: 12px;
+  padding: 24px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+  
+  h2 {
+    font-size: 20px;
+    color: #303133;
+    margin: 0 0 20px 0;
+  }
+  
+  .status-items {
+    margin-bottom: 24px;
+    
+    .status-item {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      padding: 12px 0;
+      border-bottom: 1px solid #ebeef5;
+      
+      &:last-child {
+        border-bottom: none;
+      }
+      
+      span {
+        flex: 1;
+        font-size: 14px;
+        color: #606266;
+      }
+    }
+  }
+  
+  .user-details {
+    border-top: 1px solid #ebeef5;
+    padding-top: 20px;
+    
+    h3 {
+      font-size: 16px;
+      color: #303133;
+      margin: 0 0 16px 0;
+    }
+    
+    .details-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+      gap: 12px;
+      
+      .detail-item {
+        display: flex;
+        align-items: center;
+        padding: 8px 0;
+        
+        label {
+          font-weight: 500;
+          color: #909399;
+          min-width: 80px;
+          font-size: 14px;
+        }
+        
+        span {
+          color: #606266;
+          font-size: 14px;
+        }
+      }
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .navbar {
+    padding: 0 16px;
+    
+    .navbar-nav {
+      gap: 16px;
+    }
+    
+    .navbar-user .username {
+      display: none;
+    }
+  }
+  
+  .main-content {
+    padding: 16px;
+  }
+  
+  .welcome-card {
+    padding: 24px 16px;
+    
+    .welcome-header h1 {
+      font-size: 24px;
+    }
+    
+    .stats-overview {
+      grid-template-columns: repeat(2, 1fr);
+      gap: 12px;
+      
+      .stat-item {
+        padding: 16px;
+        
+        .stat-content h3 {
+          font-size: 16px;
+        }
+      }
+    }
+  }
+  
+  .actions-grid {
+    grid-template-columns: repeat(2, 1fr);
+    gap: 12px;
+    
+    .action-card {
+      padding: 16px;
+      
+      h3 {
+        font-size: 14px;
+      }
+      
+      p {
+        font-size: 12px;
+      }
+    }
+  }
+  
+  .details-grid {
+    grid-template-columns: 1fr;
+  }
+}
+
+@media (max-width: 480px) {
+  .stats-overview {
+    grid-template-columns: 1fr;
+  }
+  
+  .actions-grid {
+    grid-template-columns: 1fr;
+  }
+}
 </style>
\ No newline at end of file
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
diff --git a/src/views/forum/ForumSectionView.vue b/src/views/forum/ForumSectionView.vue
index 98c9780..3d55929 100644
--- a/src/views/forum/ForumSectionView.vue
+++ b/src/views/forum/ForumSectionView.vue
@@ -1,5 +1,4 @@
 <template>

-  <Navbar />

   <div class="section-page">

     <Navbar />

     <div class="page-container">

@@ -38,90 +37,90 @@
         </div>

       </div>

 

-      <!-- 筛选和搜索 -->

-      <div class="filter-section">

-        <div class="filter-left">

-          <el-input

-            v-model="searchQuery"

-            placeholder="搜索主题..."

-            :prefix-icon="Search"

-            @keyup.enter="handleSearch"

-            clearable

-            style="width: 300px;"

-          />

-          <el-button type="primary" @click="handleSearch">搜索</el-button>

-        </div>

-        

-        <div class="filter-right">

-          <el-select v-model="sortBy" placeholder="排序方式" @change="handleFilter">

-            <el-option label="最新回复" value="last_reply" />

-            <el-option label="发布时间" value="create_time" />

-            <el-option label="回复数量" value="replies" />

-            <el-option label="浏览次数" value="views" />

-          </el-select>

-          

-          <el-select v-model="filterType" placeholder="主题类型" @change="handleFilter">

-            <el-option label="全部主题" value="" />

-            <el-option label="置顶主题" value="pinned" />

-            <el-option label="热门主题" value="hot" />

-            <el-option label="精华主题" value="featured" />

-          </el-select>

-        </div>

-      </div>

+<!--      &lt;!&ndash; 筛选和搜索 &ndash;&gt;-->

+<!--      <div class="filter-section">-->

+<!--        <div class="filter-left">-->

+<!--          <el-input-->

+<!--            v-model="searchQuery"-->

+<!--            placeholder="搜索主题..."-->

+<!--            :prefix-icon="Search"-->

+<!--            @keyup.enter="handleSearch"-->

+<!--            clearable-->

+<!--            style="width: 300px;"-->

+<!--          />-->

+<!--          <el-button type="primary" @click="handleSearch">搜索</el-button>-->

+<!--        </div>-->

+<!--        -->

+<!--        <div class="filter-right">-->

+<!--          <el-select v-model="sortBy" placeholder="排序方式" @change="handleFilter">-->

+<!--            <el-option label="最新回复" value="last_reply" />-->

+<!--            <el-option label="发布时间" value="create_time" />-->

+<!--            <el-option label="回复数量" value="replies" />-->

+<!--            <el-option label="浏览次数" value="views" />-->

+<!--          </el-select>-->

+<!--          -->

+<!--          <el-select v-model="filterType" placeholder="主题类型" @change="handleFilter">-->

+<!--            <el-option label="全部主题" value="" />-->

+<!--            <el-option label="置顶主题" value="pinned" />-->

+<!--            <el-option label="热门主题" value="hot" />-->

+<!--            <el-option label="精华主题" value="featured" />-->

+<!--          </el-select>-->

+<!--        </div>-->

+<!--      </div>-->

 

       <!-- 置顶主题 -->

-      <div v-if="pinnedTopics.length > 0" class="pinned-topics">

-        <h3 class="section-title">置顶主题</h3>

-        <div class="topics-list">

-          <div

-            v-for="topic in pinnedTopics"

-            :key="topic.id"

-            class="topic-item pinned"

-            @click="navigateToTopic(topic.id)"

-          >

-            <div class="topic-status">

-              <el-icon class="pin-icon"><Top /></el-icon>

-            </div>

-            

-            <div class="topic-content">

-              <div class="topic-header">

-                <h4 class="topic-title">{{ topic.title }}</h4>

-                <div class="topic-tags">

-                  <el-tag type="warning" size="small">置顶</el-tag>

-                  <el-tag v-if="topic.hot" type="danger" size="small">热门</el-tag>

-                  <el-tag v-if="topic.featured" type="success" size="small">精华</el-tag>

-                </div>

-              </div>

-              

-              <div class="topic-meta">

-                <div class="author-info">

-                  <el-avatar :size="24">{{ topic.user?.username ? topic.user.username.charAt(0) : 'A' }}</el-avatar>

-                  <span class="author-name">{{ topic.user?.username || '匿名' }}</span>

-                  <span class="create-time">{{ formatTime(topic.createTime) }}</span>

-                </div>

-                

-                <div class="topic-stats">

-                  <span class="stat-item">

-                    <el-icon><View /></el-icon>

-                    {{ topic.views }}

-                  </span>

-                  <span class="stat-item">

-                    <el-icon><Comment /></el-icon>

-                    {{ topic.replies }}

-                  </span>

-                </div>

-              </div>

-            </div>

-            

-            <div class="last-reply">

-              <div v-if="topic.lastReply" class="reply-info">

-                <div class="reply-author">{{ topic.lastReply.author }}</div>

-                <div class="reply-time">{{ formatTime(topic.lastReply.time) }}</div>

-              </div>

-            </div>

-          </div>

-        </div>

-      </div>

+<!--      <div v-if="pinnedTopics.length > 0" class="pinned-topics">-->

+<!--        <h3 class="section-title">置顶主题</h3>-->

+<!--        <div class="topics-list">-->

+<!--          <div-->

+<!--            v-for="topic in pinnedTopics"-->

+<!--            :key="topic.id"-->

+<!--            class="topic-item pinned"-->

+<!--            @click="navigateToTopic(topic.id)"-->

+<!--          >-->

+<!--            <div class="topic-status">-->

+<!--              <el-icon class="pin-icon"><Top /></el-icon>-->

+<!--            </div>-->

+<!--            -->

+<!--            <div class="topic-content">-->

+<!--              <div class="topic-header">-->

+<!--                <h4 class="topic-title">{{ topic.title }}</h4>-->

+<!--                <div class="topic-tags">-->

+<!--                  <el-tag type="warning" size="small">置顶</el-tag>-->

+<!--                  <el-tag v-if="topic.hot" type="danger" size="small">热门</el-tag>-->

+<!--                  <el-tag v-if="topic.featured" type="success" size="small">精华</el-tag>-->

+<!--                </div>-->

+<!--              </div>-->

+<!--              -->

+<!--              <div class="topic-meta">-->

+<!--                <div class="author-info">-->

+<!--                  <el-avatar :size="24">{{ topic.user?.username ? topic.user.username.charAt(0) : 'A' }}</el-avatar>-->

+<!--                  <span class="author-name">{{ topic.user?.username || '匿名' }}</span>-->

+<!--                  <span class="create-time">{{ formatTime(topic.createTime) }}</span>-->

+<!--                </div>-->

+<!--                -->

+<!--                <div class="topic-stats">-->

+<!--                  <span class="stat-item">-->

+<!--                    <el-icon><View /></el-icon>-->

+<!--                    {{ topic.views }}-->

+<!--                  </span>-->

+<!--                  <span class="stat-item">-->

+<!--                    <el-icon><Comment /></el-icon>-->

+<!--                    {{ topic.replies }}-->

+<!--                  </span>-->

+<!--                </div>-->

+<!--              </div>-->

+<!--            </div>-->

+<!--            -->

+<!--            <div class="last-reply">-->

+<!--              <div v-if="topic.lastReply" class="reply-info">-->

+<!--                <div class="reply-author">{{ topic.lastReply.author }}</div>-->

+<!--                <div class="reply-time">{{ formatTime(topic.lastReply.time) }}</div>-->

+<!--              </div>-->

+<!--            </div>-->

+<!--          </div>-->

+<!--        </div>-->

+<!--      </div>-->

 

       <!-- 普通主题列表 -->

       <div class="normal-topics">

@@ -152,9 +151,10 @@
               <div class="topic-header">

                 <h4 class="topic-title">{{ topic.title }}</h4>

                 <div class="topic-tags">

-                  <el-tag v-if="topic.hot" type="danger" size="small">热门</el-tag>

+                  <el-tag v-if="topic.isPinned" type="warning" size="small">置顶</el-tag>

+                  <el-tag v-if="topic.views > 1000" type="danger" size="small">热门</el-tag>

                   <el-tag v-if="topic.featured" type="success" size="small">精华</el-tag>

-                  <el-tag v-if="topic.closed" type="info" size="small">已关闭</el-tag>

+                  <el-tag v-if="topic.isLocked" type="info" size="small">已关闭</el-tag>

                 </div>

               </div>

               

@@ -162,28 +162,27 @@
                 <div class="author-info">

                   <el-avatar :size="24">{{ topic.user?.username ? topic.user.username.charAt(0) : 'A' }}</el-avatar>

                   <span class="author-name">{{ topic.user?.username || '匿名' }}</span>

-                  <span class="create-time">{{ formatTime(topic.createTime) }}</span>

+<!--                  <span class="create-time">{{ formatTime(topic.createdAt) }}</span>-->

                 </div>

                 

-                <div class="topic-stats">

-                  <span class="stat-item">

-                    <el-icon><View /></el-icon>

-                    {{ topic.views }}

-                  </span>

-                  <span class="stat-item">

-                    <el-icon><Comment /></el-icon>

-                    {{ topic.replies }}

-                  </span>

-                </div>

+<!--                <div class="topic-stats">-->

+<!--                  <span class="stat-item">-->

+<!--                    <el-icon><View /></el-icon>-->

+<!--                    {{ topic.views || 0 }}-->

+<!--                  </span>-->

+<!--                  <span class="stat-item">-->

+<!--                    <el-icon><Comment /></el-icon>-->

+<!--                    {{ topic.replies || 0 }}-->

+<!--                  </span>-->

+<!--                </div>-->

               </div>

             </div>

             

             <div class="last-reply">

-              <div v-if="topic.lastReply" class="reply-info">

-                <div class="reply-author">{{ topic.lastReply.author }}</div>

-                <div class="reply-time">{{ formatTime(topic.lastReply.time) }}</div>

+              <div v-if="topic.updatedAt" class="reply-info">

+                <div class="reply-author">最后回复</div>

+                <div class="reply-time">{{ formatTime(topic.updatedAt) }}</div>

               </div>

-              <div v-else class="no-reply">暂无回复</div>

             </div>

           </div>

           

@@ -305,9 +304,11 @@
   Monitor,

   GamePad,

   Bell,

-  QuestionFilled

+  QuestionFilled,

+  Plus

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

 import { getTopicsByForum, createTopic } from '@/api/topic'

+import { getForumById } from '@/api/forum'

 import Navbar from "@/components/Navbar.vue";

 

 export default {

@@ -332,16 +333,7 @@
     const pageSize = ref(20)

     const totalTopics = ref(0)

     

-    const sectionInfo = ref({

-      id: 1,

-      name: '电影讨论',

-      description: '分享和讨论电影资源,交流观影心得',

-      icon: 'Film',

-      color: '#409eff',

-      topics: 3256,

-      replies: 18934,

-      members: 1234

-    })

+    const sectionInfo = ref({})

     

     const newTopic = reactive({

       title: '',

@@ -383,35 +375,31 @@
     onMounted(() => {

       const sectionId = route.params.id

       fetchSectionData(sectionId)

-      fetchTopics()

     })

     

     const fetchSectionData = async (id) => {

       loading.value = true

       try {

-        // 模拟API调用

-        console.log('获取版块数据:', id)

+        console.log('🏁 fetchSectionData 开始,id:', id)

+        const res = await getForumById(id)

+        console.log('📥 getForumById 响应:', res)

         

-        // 根据版块ID设置不同的版块信息

-        const sections = {

-          1: { name: '电影讨论', description: '分享和讨论电影资源,交流观影心得', icon: 'Film', color: '#409eff' },

-          2: { name: '音乐分享', description: '音乐资源分享,音乐制作技术交流', icon: 'Headphones', color: '#67c23a' },

-          3: { name: '软件技术', description: '软件资源分享,技术问题讨论', icon: 'Monitor', color: '#e6a23c' },

-          4: { name: '游戏天地', description: '游戏资源分享,游戏攻略讨论', icon: 'GamePad', color: '#f56c6c' },

-          5: { name: '站务公告', description: '网站公告,规则说明,意见建议', icon: 'Bell', color: '#909399' },

-          6: { name: '新手求助', description: '新手问题解答,使用教程分享', icon: 'QuestionFilled', color: '#606266' }

-        }

-        

-        const sectionData = sections[id] || sections[1]

         sectionInfo.value = {

-          id: parseInt(id),

-          ...sectionData,

-          topics: 0  // 初始化为0,会在fetchTopics中更新为真实数量

+          ...res,

+          icon: getForumIcon(res.name),

+          color: getForumColor(res.name),

+          topics: 0

         }

         

-        totalTopics.value = 156

+        console.log('📋 sectionInfo 设置完成:', sectionInfo.value)

+        console.log('🚀 准备调用 fetchTopics')

         

+        // sectionInfo有数据后再请求主题列表

+        fetchTopics()

+        

+        console.log('✅ fetchTopics 调用完成')

       } catch (error) {

+        console.error('❌ fetchSectionData 错误:', error)

         ElMessage.error('获取版块数据失败')

       } finally {

         loading.value = false

@@ -419,7 +407,31 @@
     }

     

     const formatTime = (timeString) => {

+      // 处理Java LocalDateTime数组格式: [年, 月, 日, 时, 分, 秒, 纳秒]

+      if (Array.isArray(timeString) && timeString.length >= 6) {

+        const [year, month, day, hour, minute, second] = timeString

+        const date = new Date(year, month - 1, day, hour, minute, second) // 月份需要减1

+        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', {

+          month: '2-digit',

+          day: '2-digit',

+          hour: '2-digit',

+          minute: '2-digit'

+        })

+      }

+      

+      // 处理普通字符串格式

       const date = new Date(timeString)

+      if (isNaN(date.getTime())) return '时间未知'

+      

       const now = new Date()

       const diff = now - date

       const hours = Math.floor(diff / (1000 * 60 * 60))

@@ -454,13 +466,29 @@
     const fetchTopics = async () => {

       loading.value = true

       try {

+        // 调试信息:确认方法被调用和参数值

+        console.log('🔍 fetchTopics 被调用,sectionInfo.value:', sectionInfo.value)

+        console.log('🔍 sectionInfo.value.id:', sectionInfo.value.id)

+        

+        if (!sectionInfo.value.id) {

+          console.error('❌ sectionInfo.value.id 为空,无法请求主题列表')

+          return

+        }

+        

         // 调用后端API获取主题列表

+        console.log('🚀 正在请求主题列表,forumId:', sectionInfo.value.id)

         const res = await getTopicsByForum(sectionInfo.value.id)

+        console.log('✅ 主题列表响应:', res)

+        

         topics.value = res.data || res // 兼容不同返回结构

         totalTopics.value = topics.value.length

         // 同时更新顶部显示的主题数量

         sectionInfo.value.topics = topics.value.length

+        

+        console.log('✅ topics.value:', topics.value)

+        console.log('✅ totalTopics.value:', totalTopics.value)

       } catch (error) {

+        console.error('❌ fetchTopics 错误:', error)

         ElMessage.error('获取主题列表失败')

       } finally {

         loading.value = false

@@ -567,6 +595,30 @@
       newTopic.options = []

     }

     

+    // icon和color映射函数,和首页保持一致

+    const getForumIcon = (name) => {

+      const iconMap = {

+        '电影讨论': 'Film',

+        '音乐分享': 'Headphones',

+        '软件技术': 'Monitor',

+        '游戏天地': 'GamePad',

+        '站务公告': 'Bell',

+        '新手求助': 'QuestionFilled'

+      }

+      return iconMap[name] || 'ChatLineRound'

+    }

+    const getForumColor = (name) => {

+      const colorMap = {

+        '电影讨论': '#409eff',

+        '音乐分享': '#67c23a',

+        '软件技术': '#e6a23c',

+        '游戏天地': '#f56c6c',

+        '站务公告': '#909399',

+        '新手求助': '#606266'

+      }

+      return colorMap[name] || '#409eff'

+    }

+    

     return {

       loading,

       showNewTopicDialog,

@@ -610,7 +662,8 @@
       Monitor,

       GamePad,

       Bell,

-      QuestionFilled

+      QuestionFilled,

+      Plus

     }

   }

 }

diff --git a/src/views/forum/ForumTopicView.vue b/src/views/forum/ForumTopicView.vue
index b3fe08b..170e313 100644
--- a/src/views/forum/ForumTopicView.vue
+++ b/src/views/forum/ForumTopicView.vue
@@ -1,5 +1,4 @@
 <template>

-  <Navbar />

   <div class="topic-detail-page">

     <Navbar />

     <div class="page-container">

diff --git a/src/views/forum/ForumView.vue b/src/views/forum/ForumView.vue
index cd7e7bf..2010ce7 100644
--- a/src/views/forum/ForumView.vue
+++ b/src/views/forum/ForumView.vue
@@ -1,18 +1,17 @@
 <template>

-  <Navbar />

   <div class="forum-page">

-    

+    <Navbar />

     <div class="page-container">

       <!-- 论坛头部 -->

       <div class="forum-header">

         <div class="header-content">

           <h1>社区论坛</h1>

           <p class="header-description">与其他用户交流讨论,分享经验心得</p>

-          <div class="header-actions">

-            <el-button type="primary" :icon="Edit" @click="showNewTopicDialog = true">

-              发布新帖

-            </el-button>

-          </div>

+<!--          <div class="header-actions">-->

+<!--            <el-button type="primary" :icon="Edit" @click="showNewTopicDialog = true">-->

+<!--              发布新帖-->

+<!--            </el-button>-->

+<!--          </div>-->

         </div>

       </div>

 

@@ -26,13 +25,13 @@
               <p>主题总数</p>

             </div>

           </div>

-          <div class="stat-item">

-            <el-icon size="32" color="#67c23a"><Comment /></el-icon>

-            <div class="stat-info">

-              <h3>{{ forumStats.totalReplies }}</h3>

-              <p>回复总数</p>

-            </div>

-          </div>

+<!--          <div class="stat-item">-->

+<!--            <el-icon size="32" color="#67c23a"><Comment /></el-icon>-->

+<!--            <div class="stat-info">-->

+<!--              <h3>{{ forumStats.totalReplies }}</h3>-->

+<!--              <p>回复总数</p>-->

+<!--            </div>-->

+<!--          </div>-->

           <div class="stat-item">

             <el-icon size="32" color="#e6a23c"><User /></el-icon>

             <div class="stat-info">

@@ -40,13 +39,13 @@
               <p>活跃用户</p>

             </div>

           </div>

-          <div class="stat-item">

-            <el-icon size="32" color="#f56c6c"><View /></el-icon>

-            <div class="stat-info">

-              <h3>{{ forumStats.todayPosts }}</h3>

-              <p>今日发帖</p>

-            </div>

-          </div>

+<!--          <div class="stat-item">-->

+<!--            <el-icon size="32" color="#f56c6c"><View /></el-icon>-->

+<!--            <div class="stat-info">-->

+<!--              <h3>{{ forumStats.todayPosts }}</h3>-->

+<!--              <p>今日发帖</p>-->

+<!--            </div>-->

+<!--          </div>-->

         </div>

       </div>

 

@@ -90,9 +89,9 @@
       <div class="hot-topics">

         <div class="section-header">

           <h2 class="section-title">热门主题</h2>

-          <el-button type="primary" text @click="$router.push('/forum/topics')">

-            查看全部 <el-icon><ArrowRight /></el-icon>

-          </el-button>

+<!--          <el-button type="primary" text @click="$router.push('/forum/topics')">-->

+<!--            查看全部 <el-icon><ArrowRight /></el-icon>-->

+<!--          </el-button>-->

         </div>

         <div class="topics-list">

           <div

@@ -120,17 +119,17 @@
                   <el-avatar :size="24">{{ topic.author.charAt(0) }}</el-avatar>

                   <span class="author-name">{{ topic.author }}</span>

                 </div>

-                <div class="topic-stats">

-                  <span class="stat-item">

-                    <el-icon><View /></el-icon>

-                    {{ topic.views }}

-                  </span>

-                  <span class="stat-item">

-                    <el-icon><Comment /></el-icon>

-                    {{ topic.replies }}

-                  </span>

-                  <span class="time">{{ formatTime(topic.lastReply) }}</span>

-                </div>

+<!--                <div class="topic-stats">-->

+<!--                  <span class="stat-item">-->

+<!--                    <el-icon><View /></el-icon>-->

+<!--                    {{ topic.views }}-->

+<!--                  </span>-->

+<!--                  <span class="stat-item">-->

+<!--                    <el-icon><Comment /></el-icon>-->

+<!--                    {{ topic.replies }}-->

+<!--                  </span>-->

+<!--&lt;!&ndash;                  <span class="time">{{ formatTime(topic.lastReply) }}</span>&ndash;&gt;-->

+<!--                </div>-->

               </div>

             </div>

             <div class="topic-status">

@@ -141,31 +140,31 @@
         </div>

       </div>

 

-      <!-- 最新回复 -->

-      <div class="recent-replies">

-        <h2 class="section-title">最新回复</h2>

-        <div class="replies-list">

-          <div

-            v-for="reply in recentReplies"

-            :key="reply.id"

-            class="reply-item"

-            @click="navigateToTopic(reply.topicId)"

-          >

-            <div class="reply-avatar">

-              <el-avatar :size="40">{{ reply.author.charAt(0) }}</el-avatar>

-            </div>

-            <div class="reply-content">

-              <div class="reply-header">

-                <span class="reply-author">{{ reply.author }}</span>

-                <span class="reply-action">回复了主题</span>

-                <span class="topic-title">{{ reply.topicTitle }}</span>

-              </div>

-              <div class="reply-text">{{ reply.content }}</div>

-              <div class="reply-time">{{ formatTime(reply.time) }}</div>

-            </div>

-          </div>

-        </div>

-      </div>

+<!--      &lt;!&ndash; 最新回复 &ndash;&gt;-->

+<!--      <div class="recent-replies">-->

+<!--        <h2 class="section-title">最新回复</h2>-->

+<!--        <div class="replies-list">-->

+<!--          <div-->

+<!--            v-for="reply in recentReplies"-->

+<!--            :key="reply.id"-->

+<!--            class="reply-item"-->

+<!--            @click="navigateToTopic(reply.topicId)"-->

+<!--          >-->

+<!--            <div class="reply-avatar">-->

+<!--              <el-avatar :size="40">{{ reply.author.charAt(0) }}</el-avatar>-->

+<!--            </div>-->

+<!--            <div class="reply-content">-->

+<!--              <div class="reply-header">-->

+<!--                <span class="reply-author">{{ reply.author }}</span>-->

+<!--                <span class="reply-action">回复了主题</span>-->

+<!--                <span class="topic-title">{{ reply.topicTitle }}</span>-->

+<!--              </div>-->

+<!--              <div class="reply-text">{{ reply.content }}</div>-->

+<!--              <div class="reply-time">{{ formatTime(reply.time) }}</div>-->

+<!--            </div>-->

+<!--          </div>-->

+<!--        </div>-->

+<!--      </div>-->

     </div>

 

     <!-- 发布新帖对话框 -->

@@ -256,7 +255,7 @@
 import { ref, reactive, onMounted, nextTick } from 'vue'

 import { useRouter } from 'vue-router'

 import { ElMessage, ElMessageBox } from 'element-plus'

-import { 

+import {

   Edit,

   ChatDotRound,

   Comment,

diff --git a/src/views/forum/TopicView.vue b/src/views/forum/TopicView.vue
index 0374dac..f88d0de 100644
--- a/src/views/forum/TopicView.vue
+++ b/src/views/forum/TopicView.vue
@@ -1,5 +1,4 @@
 <template>
-  <Navbar />
   <div class="topic-page">
     <Navbar />
     <div class="page-container">
@@ -13,43 +12,43 @@
                 <el-avatar :size="24">{{ topic.user?.username ? topic.user.username.charAt(0) : 'A' }}</el-avatar>
                 <span class="author-name">{{ topic.user?.username || '匿名' }}</span>
               </span>
-              <span class="time">{{ formatTime(topic.createTime) }}</span>
+<!--              <span class="time">{{ formatTime(topic.createTime) }}</span>-->
               <span class="views">
                 <el-icon><View /></el-icon>
                 {{ topic.views }}
               </span>
-              <el-button
-                :icon="isSubscribed ? StarFilled : Star"
-                :type="isSubscribed ? 'warning' : 'default'"
-                @click="handleSubscribe"
-              >
-                {{ isSubscribed ? '已订阅' : '订阅' }}
-              </el-button>
+<!--              <el-button-->
+<!--                :icon="isSubscribed ? StarFilled : Star"-->
+<!--                :type="isSubscribed ? 'warning' : 'default'"-->
+<!--                @click="handleSubscribe"-->
+<!--              >-->
+<!--                {{ isSubscribed ? '已订阅' : '订阅' }}-->
+<!--              </el-button>-->
             </div>
           </div>
-          <div class="topic-actions" v-if="isAuthor">
-            <el-button type="primary" @click="showEditDialog = true">编辑</el-button>
-            <el-button type="danger" @click="handleDelete">删除</el-button>
-          </div>
+<!--          <div class="topic-actions" v-if="isAuthor">-->
+<!--            <el-button type="primary" @click="showEditDialog = true">编辑</el-button>-->
+<!--            <el-button type="danger" @click="handleDelete">删除</el-button>-->
+<!--          </div>-->
         </div>
       </div>
 
-      <!-- 话题内容 -->
-      <div class="topic-content">
-        <div class="content-card">
-          <div class="content-body" v-html="topic.content"></div>
-          <div class="content-tags">
-            <el-tag
-              v-for="tag in topic.tags"
-              :key="tag.id"
-              :color="tag.color"
-              effect="light"
-            >
-              {{ tag.name }}
-            </el-tag>
-          </div>
-        </div>
-      </div>
+<!--      &lt;!&ndash; 话题内容 &ndash;&gt;-->
+<!--      <div class="topic-content">-->
+<!--        <div class="content-card">-->
+<!--          <div class="content-body" v-html="topic.content"></div>-->
+<!--          <div class="content-tags">-->
+<!--            <el-tag-->
+<!--              v-for="tag in topic.tags"-->
+<!--              :key="tag.id"-->
+<!--              :color="tag.color"-->
+<!--              effect="light"-->
+<!--            >-->
+<!--              {{ tag.name }}-->
+<!--            </el-tag>-->
+<!--          </div>-->
+<!--        </div>-->
+<!--      </div>-->
 
 
 
diff --git a/src/views/torrent/TorrentDetailView.vue b/src/views/torrent/TorrentDetailView.vue
index 8b1c8fd..046c00b 100644
--- a/src/views/torrent/TorrentDetailView.vue
+++ b/src/views/torrent/TorrentDetailView.vue
@@ -1,5 +1,4 @@
 <template>
-  <Navbar />
   <div class="torrent-detail-page">
     <div class="page-container">
       <!-- 加载状态 -->
@@ -95,17 +94,17 @@
               </div>
               
               <div class="torrent-stats">
-                <!-- <div class="stat-item seeders">
+                <div class="stat-item seeders">
                   <span class="stat-number">{{ peerStats.seeders }}</span>
                   <span class="stat-label">做种</span>
-                </div> -->
-                <!-- <div class="stat-item leechers">
+                </div>
+                <div class="stat-item leechers">
                   <span class="stat-number">{{ peerStats.leechers }}</span>
                   <span class="stat-label">下载</span>
-                </div> -->
+                </div>
                 <div class="stat-item downloads">
-                  <span class="stat-number">{{ peerStats.downloads }}</span>
-                  <span class="stat-label">总下载</span>
+                  <span class="stat-number">{{ torrentInfo.finishes }}</span>
+                  <span class="stat-label">完成</span>
                 </div>
               </div>
               
@@ -310,12 +309,10 @@
   Like
 } from '@element-plus/icons-vue'
 import axios from 'axios'
-import Navbar from '@/components/Navbar.vue'
 
 export default {
   name: 'TorrentDetailView',
   components: {
-    Navbar,
     ArrowLeft,
     Download,
     Star,
@@ -344,8 +341,7 @@
     const torrentFiles = ref([])
     const peerStats = ref({
       seeders: 0,
-      leechers: 0,
-      downloads: 0
+      leechers: 0
     })
     
     const seedersList = ref([])
@@ -400,9 +396,6 @@
           // 获取用户活动数据(如果有相关API)
           await fetchPeerStats(infoHash)
           
-          // 获取下载数
-          await fetchDownloadCount(infoHash)
-          
           // 获取评论(如果有相关API)
           await fetchComments(infoHash)
         } else {
@@ -468,18 +461,6 @@
       }
     }
     
-    const fetchDownloadCount = async (infoHash) => {
-      try {
-        const response = await axios.get(`/api/torrent/${infoHash}/downloads`)
-        if (response.status === 200) {
-          peerStats.value.downloads = response.data
-        }
-      } catch (error) {
-        console.error('获取下载数失败:', error)
-        peerStats.value.downloads = 0
-      }
-    }
-    
     const fetchComments = async (infoHash) => {
       try {
         // 这里应该调用获取评论的API
@@ -549,15 +530,6 @@
           }
         )
         
-        // 检查响应类型是否为JSON(表示发生了错误)
-        const contentType = response.headers['content-type'];
-        if (contentType && contentType.includes('application/json')) {
-          // 将blob转换为json以读取错误信息
-          const errorText = await response.data.text();
-          const errorData = JSON.parse(errorText);
-          throw new Error(errorData.message || '下载失败');
-        }
-
         // 从响应头中获取文件名,如果没有则使用默认格式
         let fileName = response.headers?.['content-disposition']?.split('filename=')[1]
         if (!fileName) {
@@ -581,41 +553,7 @@
         ElMessage.success('种子文件下载完成')
       } catch (error) {
         console.error('下载失败:', error)
-        // 根据错误类型显示不同的错误信息
-        let errorMessage = '下载失败,请稍后重试';
-        
-        if (error.response) {
-          const status = error.response.status;
-          const data = error.response.data;
-          
-          switch(status) {
-            case 401:
-              errorMessage = '认证失败,请检查登录状态或passkey是否正确';
-              break;
-            case 403:
-              if (data.message?.includes('share ratio')) {
-                errorMessage = '分享率不足,无法下载';
-              } else if (data.message?.includes('torrent:download_review')) {
-                errorMessage = '该种子正在审核中,您没有权限下载';
-              } else {
-                errorMessage = '您没有权限下载此种子';
-              }
-              break;
-            case 404:
-              if (data.message?.includes('torrent not registered')) {
-                errorMessage = '该种子未在服务器注册';
-              } else if (data.message?.includes('file are missing')) {
-                errorMessage = '种子文件丢失,请联系管理员';
-              } else {
-                errorMessage = '种子不存在';
-              }
-              break;
-            default:
-              errorMessage = data.message || '下载失败,请稍后重试';
-          }
-        }
-        
-        ElMessage.error(errorMessage)
+        ElMessage.error(error.response?.data?.message || '下载失败,请稍后重试')
       } finally {
         downloading.value = false
       }
diff --git a/src/views/torrent/TorrentsView.vue b/src/views/torrent/TorrentsView.vue
index 20d5dd0..34af25d 100644
--- a/src/views/torrent/TorrentsView.vue
+++ b/src/views/torrent/TorrentsView.vue
@@ -1,6 +1,6 @@
 <template>
-  <Navbar />
   <div class="torrents-page">
+    <Navbar />
     <div class="page-header">
       <h1>种子资源</h1>
       <div class="header-actions">
@@ -106,23 +106,23 @@
           </template>
         </el-table-column>
         
-        <!-- <el-table-column label="做种" width="80" align="center">
+        <el-table-column label="做种" width="80" align="center">
           <template #default="{ row }">
             <span class="seeders">{{ row.seeders || 0 }}</span>
           </template>
-        </el-table-column> -->
+        </el-table-column>
         
         <el-table-column label="下载" width="80" align="center">
           <template #default="{ row }">
-            <span class="downloads">{{ row.downloadCount || 0 }}</span>
+            <span class="leechers">{{ row.leechers || 0 }}</span>
           </template>
         </el-table-column>
         
-        <!-- <el-table-column label="完成" width="80" align="center">
+        <el-table-column label="完成" width="80" align="center">
           <template #default="{ row }">
             <span>{{ row.downloads || 0 }}</span>
           </template>
-        </el-table-column> -->
+        </el-table-column>
         
         <el-table-column label="操作" width="120" align="center">
           <template #default="{ row }">
@@ -168,7 +168,6 @@
 } from '@element-plus/icons-vue'
 import { searchTorrents, getCategories } from '@/api/torrent'
 import Navbar from '@/components/Navbar.vue'
-import axios from 'axios'
 
 export default {
   name: 'TorrentsView',
@@ -208,30 +207,20 @@
       fetchTorrents()
     })
     
-    const fetchDownloadCount = async (torrent) => {
-      try {
-        const response = await axios.get(`/api/torrent/${torrent.infoHash}/downloads`)
-        if (response.status === 200) {
-          torrent.downloadCount = response.data
-        }
-      } catch (error) {
-        console.error('获取下载数失败:', error)
-        torrent.downloadCount = 0
-      }
-    }
-    
     const fetchTorrents = async () => {
       loading.value = true
       try {
         if (selectedCategory.value) {
+          // 使用 GET 请求
           const response = await fetch(`/api/torrent/search?category=${selectedCategory.value}`)
-          .then(res => res.json())
+        .then(res => res.json())
 
           torrents.value = response.torrents || []
           totalCount.value = response.totalElements || 0
           totalPages.value = response.totalPages || 1
 
         } else {
+          // 使用 POST 请求(搜索)
           const searchParams = {
             keyword: searchQuery.value || '',
             page: currentPage.value - 1,
@@ -245,11 +234,6 @@
           totalPages.value = response.totalPages || 1
         }
 
-        // 为每个种子获取下载数
-        for (const torrent of torrents.value) {
-          await fetchDownloadCount(torrent)
-        }
-
       } catch (error) {
         console.error('获取种子列表失败:', error)
         ElMessage.error('获取种子列表失败')
@@ -303,87 +287,9 @@
       router.push(`/torrent/${row.infoHash}`)
     }
     
-    const handleDownload = async (row) => {
-      try {
-        const response = await axios.get(
-          `/api/torrent/download/${row.infoHash}`,
-          { 
-            responseType: 'blob',
-            // 如果需要传递passkey,可以在这里添加params
-            params: {
-              // passkey: userStore.passkey // 如果你有用户store存储passkey
-            }
-          }
-        )
-        
-        // 检查响应类型是否为JSON(表示发生了错误)
-        const contentType = response.headers['content-type'];
-        if (contentType && contentType.includes('application/json')) {
-          // 将blob转换为json以读取错误信息
-          const errorText = await response.data.text();
-          const errorData = JSON.parse(errorText);
-          throw new Error(errorData.message || '下载失败');
-        }
-
-        // 从响应头中获取文件名,如果没有则使用默认格式
-        let fileName = response.headers?.['content-disposition']?.split('filename=')[1]
-        if (!fileName) {
-          // 使用默认的文件名格式
-          fileName = `${row.title}.torrent`
-        } else {
-          // 解码文件名
-          fileName = decodeURIComponent(fileName)
-        }
-        
-        // 创建下载链接
-        const url = window.URL.createObjectURL(new Blob([response.data], { type: 'application/x-bittorrent' }))
-        const link = document.createElement('a')
-        link.href = url
-        link.download = fileName
-        document.body.appendChild(link)
-        link.click()
-        document.body.removeChild(link)
-        window.URL.revokeObjectURL(url)
-        
-        ElMessage.success('种子文件下载完成')
-      } catch (error) {
-        console.error('下载失败:', error)
-        // 根据错误类型显示不同的错误信息
-        let errorMessage = '下载失败,请稍后重试';
-        
-        if (error.response) {
-          const status = error.response.status;
-          const data = error.response.data;
-          
-          switch(status) {
-            case 401:
-              errorMessage = '认证失败,请检查登录状态或passkey是否正确';
-              break;
-            case 403:
-              if (data.message?.includes('share ratio')) {
-                errorMessage = '分享率不足,无法下载';
-              } else if (data.message?.includes('torrent:download_review')) {
-                errorMessage = '该种子正在审核中,您没有权限下载';
-              } else {
-                errorMessage = '您没有权限下载此种子';
-              }
-              break;
-            case 404:
-              if (data.message?.includes('torrent not registered')) {
-                errorMessage = '该种子未在服务器注册';
-              } else if (data.message?.includes('file are missing')) {
-                errorMessage = '种子文件丢失,请联系管理员';
-              } else {
-                errorMessage = '种子不存在';
-              }
-              break;
-            default:
-              errorMessage = data.message || '下载失败,请稍后重试';
-          }
-        }
-        
-        ElMessage.error(errorMessage)
-      }
+    const handleDownload = (row) => {
+      ElMessage.success(`开始下载: ${row.title || row.name}`)
+      // 这里实现下载逻辑
     }
     
     const handleSizeChange = (size) => {
diff --git a/src/views/torrent/UploadView.vue b/src/views/torrent/UploadView.vue
index 72b7638..9807cd1 100644
--- a/src/views/torrent/UploadView.vue
+++ b/src/views/torrent/UploadView.vue
@@ -1,5 +1,4 @@
 <template>

-  <Navbar />

   <div class="upload-page">

     <div class="upload-container">

       <h2>上传种子</h2>

@@ -103,12 +102,9 @@
 import { useRouter } from 'vue-router'

 import { ElMessage } from 'element-plus'

 import { uploadTorrent, getCategories, getTags } from '@/api/torrent'

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

+

 export default {

   name: 'UploadView',

-  components:{

-    Navbar

-  },

   setup() {

     const router = useRouter()

     const uploadFormRef = ref(null)