下载数

Change-Id: Id3c07b7d57de7f92e2f550306cf339a0c892fc6d
diff --git a/src/api/torrent.js b/src/api/torrent.js
index e49887e..586e22c 100644
--- a/src/api/torrent.js
+++ b/src/api/torrent.js
@@ -140,4 +140,16 @@
     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/views/forum/TopicView.vue b/src/views/forum/TopicView.vue
index c79bfa8..0374dac 100644
--- a/src/views/forum/TopicView.vue
+++ b/src/views/forum/TopicView.vue
@@ -1,4 +1,5 @@
 <template>
+  <Navbar />
   <div class="topic-page">
     <Navbar />
     <div class="page-container">
diff --git a/src/views/torrent/TorrentDetailView.vue b/src/views/torrent/TorrentDetailView.vue
index 28af1f6..8b1c8fd 100644
--- a/src/views/torrent/TorrentDetailView.vue
+++ b/src/views/torrent/TorrentDetailView.vue
@@ -95,17 +95,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">{{ torrentInfo.finishes }}</span>
-                  <span class="stat-label">完成</span>
+                  <span class="stat-number">{{ peerStats.downloads }}</span>
+                  <span class="stat-label">总下载</span>
                 </div>
               </div>
               
@@ -344,7 +344,8 @@
     const torrentFiles = ref([])
     const peerStats = ref({
       seeders: 0,
-      leechers: 0
+      leechers: 0,
+      downloads: 0
     })
     
     const seedersList = ref([])
@@ -399,6 +400,9 @@
           // 获取用户活动数据(如果有相关API)
           await fetchPeerStats(infoHash)
           
+          // 获取下载数
+          await fetchDownloadCount(infoHash)
+          
           // 获取评论(如果有相关API)
           await fetchComments(infoHash)
         } else {
@@ -464,6 +468,18 @@
       }
     }
     
+    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
@@ -533,6 +549,15 @@
           }
         )
         
+        // 检查响应类型是否为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) {
@@ -556,7 +581,41 @@
         ElMessage.success('种子文件下载完成')
       } catch (error) {
         console.error('下载失败:', error)
-        ElMessage.error(error.response?.data?.message || '下载失败,请稍后重试')
+        // 根据错误类型显示不同的错误信息
+        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)
       } finally {
         downloading.value = false
       }
diff --git a/src/views/torrent/TorrentsView.vue b/src/views/torrent/TorrentsView.vue
index 596ca22..20d5dd0 100644
--- a/src/views/torrent/TorrentsView.vue
+++ b/src/views/torrent/TorrentsView.vue
@@ -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="leechers">{{ row.leechers || 0 }}</span>
+            <span class="downloads">{{ row.downloadCount || 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,6 +168,7 @@
 } 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',
@@ -207,20 +208,30 @@
       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,
@@ -234,6 +245,11 @@
           totalPages.value = response.totalPages || 1
         }
 
+        // 为每个种子获取下载数
+        for (const torrent of torrents.value) {
+          await fetchDownloadCount(torrent)
+        }
+
       } catch (error) {
         console.error('获取种子列表失败:', error)
         ElMessage.error('获取种子列表失败')
@@ -287,9 +303,87 @@
       router.push(`/torrent/${row.infoHash}`)
     }
     
-    const handleDownload = (row) => {
-      ElMessage.success(`开始下载: ${row.title || row.name}`)
-      // 这里实现下载逻辑
+    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 handleSizeChange = (size) => {