blob: 1ae9f4b52ce078342885ede2118ce9f22a840c26 [file] [log] [blame]
Xing Jinwenff16b1e2025-06-05 00:29:26 +08001<template>
2 <div class="torrents-page">
3 <div class="page-header">
4 <h1>种子资源</h1>
5 <div class="header-actions">
6 <el-button type="primary" :icon="Upload" @click="$router.push('/upload')">
7 上传种子
8 </el-button>
9 </div>
10 </div>
11
12 <!-- 搜索和筛选 -->
13 <div class="search-section">
14 <div class="search-bar">
15 <el-input
16 v-model="searchQuery"
17 placeholder="搜索种子..."
18 :prefix-icon="Search"
19 size="large"
20 @keyup.enter="handleSearch"
21 clearable
22 />
23 <el-button type="primary" size="large" @click="handleSearch">
24 搜索
25 </el-button>
26 </div>
27
28 <div class="filters">
29 <el-select v-model="selectedCategory" placeholder="分类" @change="handleFilter">
30 <el-option label="全部" value="" />
31 <el-option label="电影" value="movie" />
32 <el-option label="电视剧" value="tv" />
33 <el-option label="音乐" value="music" />
34 <el-option label="软件" value="software" />
35 <el-option label="游戏" value="game" />
36 </el-select>
37
38 <el-select v-model="sortBy" placeholder="排序方式" @change="handleFilter">
39 <el-option label="上传时间" value="upload_time" />
40 <el-option label="文件大小" value="size" />
41 <el-option label="做种数" value="seeders" />
42 <el-option label="下载数" value="leechers" />
43 <el-option label="完成数" value="downloads" />
44 </el-select>
45
46 <el-radio-group v-model="sortOrder" @change="handleFilter">
47 <el-radio-button label="desc">降序</el-radio-button>
48 <el-radio-button label="asc">升序</el-radio-button>
49 </el-radio-group>
50 </div>
51 </div>
52
53 <!-- 种子列表 -->
54 <div class="torrents-list">
55 <div class="list-header">
56 <span class="results-count">共找到 {{ totalCount }} 个种子</span>
57 </div>
58
59 <el-table
60 :data="torrents"
61 v-loading="loading"
62 @row-click="handleRowClick"
63 stripe
64 class="torrents-table"
65 >
66 <el-table-column label="分类" width="80">
67 <template #default="{ row }">
68 <el-tag :type="getCategoryType(row.category)" size="small">
69 {{ getCategoryName(row.category) }}
70 </el-tag>
71 </template>
72 </el-table-column>
73
74 <el-table-column label="种子信息" min-width="400">
75 <template #default="{ row }">
76 <div class="torrent-info">
77 <h4 class="torrent-title">{{ row.title }}</h4>
78 <div class="torrent-meta">
79 <span class="uploader">
80 <el-icon><User /></el-icon>
81 {{ row.uploader }}
82 </span>
83 <span class="upload-time">
84 <el-icon><Clock /></el-icon>
85 {{ formatTime(row.uploadTime) }}
86 </span>
87 <span class="file-size">
88 <el-icon><Document /></el-icon>
89 {{ row.size }}
90 </span>
91 </div>
92 </div>
93 </template>
94 </el-table-column>
95
96 <el-table-column label="做种" width="80" align="center">
97 <template #default="{ row }">
98 <span class="seeders">{{ row.seeders }}</span>
99 </template>
100 </el-table-column>
101
102 <el-table-column label="下载" width="80" align="center">
103 <template #default="{ row }">
104 <span class="leechers">{{ row.leechers }}</span>
105 </template>
106 </el-table-column>
107
108 <el-table-column label="完成" width="80" align="center">
109 <template #default="{ row }">
110 <span>{{ row.downloads }}</span>
111 </template>
112 </el-table-column>
113
114 <el-table-column label="操作" width="120" align="center">
115 <template #default="{ row }">
116 <el-button
117 type="primary"
118 size="small"
119 :icon="Download"
120 @click.stop="handleDownload(row)"
121 >
122 下载
123 </el-button>
124 </template>
125 </el-table-column>
126 </el-table>
127
128 <!-- 分页 -->
129 <div class="pagination-wrapper">
130 <el-pagination
131 v-model:current-page="currentPage"
132 v-model:page-size="pageSize"
133 :page-sizes="[20, 50, 100]"
134 :total="totalCount"
135 layout="total, sizes, prev, pager, next, jumper"
136 @size-change="handleSizeChange"
137 @current-change="handleCurrentChange"
138 />
139 </div>
140 </div>
141 </div>
142</template>
143
144<script>
145import { ref, onMounted, watch } from 'vue'
146import { useRouter, useRoute } from 'vue-router'
147import { ElMessage } from 'element-plus'
148import {
149 Search,
150 Upload,
151 Download,
152 User,
153 Clock,
154 Document
155} from '@element-plus/icons-vue'
156
157export default {
158 name: 'TorrentsView',
159 setup() {
160 const router = useRouter()
161 const route = useRoute()
162
163 const loading = ref(false)
164 const searchQuery = ref('')
165 const selectedCategory = ref('')
166 const sortBy = ref('upload_time')
167 const sortOrder = ref('desc')
168 const currentPage = ref(1)
169 const pageSize = ref(20)
170 const totalCount = ref(0)
171
172 const torrents = ref([
173 {
174 id: 1,
175 title: '[4K蓝光原盘] 阿凡达:水之道 Avatar: The Way of Water (2022)',
176 category: 'movie',
177 uploader: 'MovieMaster',
178 uploadTime: '2025-06-03T10:30:00',
179 size: '85.6 GB',
180 seeders: 128,
181 leechers: 45,
182 downloads: 892
183 },
184 {
185 id: 2,
186 title: '[FLAC] Taylor Swift - Midnights (Deluxe Edition) [2022]',
187 category: 'music',
188 uploader: 'MusicLover',
189 uploadTime: '2025-06-03T09:15:00',
190 size: '1.2 GB',
191 seeders: 67,
192 leechers: 12,
193 downloads: 456
194 },
195 {
196 id: 3,
197 title: '[合集] Adobe Creative Suite 2025 完整版',
198 category: 'software',
199 uploader: 'TechGuru',
200 uploadTime: '2025-06-03T08:45:00',
201 size: '12.8 GB',
202 seeders: 234,
203 leechers: 89,
204 downloads: 1205
205 }
206 ])
207
208 onMounted(() => {
209 // 从URL参数初始化搜索条件
210 if (route.query.q) {
211 searchQuery.value = route.query.q
212 }
213 if (route.query.category) {
214 selectedCategory.value = route.query.category
215 }
216
217 fetchTorrents()
218 })
219
220 const fetchTorrents = async () => {
221 loading.value = true
222 try {
223 // 模拟API调用
224 await new Promise(resolve => setTimeout(resolve, 1000))
225 totalCount.value = 156
226 } catch (error) {
227 ElMessage.error('获取种子列表失败')
228 } finally {
229 loading.value = false
230 }
231 }
232
233 const handleSearch = () => {
234 currentPage.value = 1
235 updateURL()
236 fetchTorrents()
237 }
238
239 const handleFilter = () => {
240 currentPage.value = 1
241 updateURL()
242 fetchTorrents()
243 }
244
245 const updateURL = () => {
246 const query = {}
247 if (searchQuery.value) query.q = searchQuery.value
248 if (selectedCategory.value) query.category = selectedCategory.value
249 if (sortBy.value !== 'upload_time') query.sort = sortBy.value
250 if (sortOrder.value !== 'desc') query.order = sortOrder.value
251 if (currentPage.value > 1) query.page = currentPage.value
252
253 router.replace({ query })
254 }
255
256 const handleRowClick = (row) => {
257 router.push(`/torrent/${row.id}`)
258 }
259
260 const handleDownload = (row) => {
261 ElMessage.success(`开始下载: ${row.title}`)
262 // 这里实现下载逻辑
263 }
264
265 const handleSizeChange = (size) => {
266 pageSize.value = size
267 currentPage.value = 1
268 fetchTorrents()
269 }
270
271 const handleCurrentChange = (page) => {
272 currentPage.value = page
273 updateURL()
274 fetchTorrents()
275 }
276
277 const formatTime = (timeString) => {
278 const date = new Date(timeString)
279 const now = new Date()
280 const diff = now - date
281 const hours = Math.floor(diff / (1000 * 60 * 60))
282
283 if (hours < 1) return '刚刚'
284 if (hours < 24) return `${hours}小时前`
285 const days = Math.floor(hours / 24)
286 return `${days}天前`
287 }
288
289 const getCategoryType = (category) => {
290 const types = {
291 'movie': 'primary',
292 'tv': 'info',
293 'music': 'success',
294 'software': 'warning',
295 'game': 'danger'
296 }
297 return types[category] || 'default'
298 }
299
300 const getCategoryName = (category) => {
301 const names = {
302 'movie': '电影',
303 'tv': '电视剧',
304 'music': '音乐',
305 'software': '软件',
306 'game': '游戏'
307 }
308 return names[category] || category
309 }
310
311 return {
312 loading,
313 searchQuery,
314 selectedCategory,
315 sortBy,
316 sortOrder,
317 currentPage,
318 pageSize,
319 totalCount,
320 torrents,
321 handleSearch,
322 handleFilter,
323 handleRowClick,
324 handleDownload,
325 handleSizeChange,
326 handleCurrentChange,
327 formatTime,
328 getCategoryType,
329 getCategoryName,
330 Search,
331 Upload,
332 Download,
333 User,
334 Clock,
335 Document
336 }
337 }
338}
339</script>
340
341<style lang="scss" scoped>
342.torrents-page {
343 max-width: 1200px;
344 margin: 0 auto;
345 padding: 24px;
346}
347
348.page-header {
349 display: flex;
350 justify-content: space-between;
351 align-items: center;
352 margin-bottom: 24px;
353
354 h1 {
355 font-size: 28px;
356 font-weight: 600;
357 color: #2c3e50;
358 margin: 0;
359 }
360}
361
362.search-section {
363 background: #fff;
364 border-radius: 12px;
365 padding: 24px;
366 margin-bottom: 24px;
367 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
368
369 .search-bar {
370 display: flex;
371 gap: 12px;
372 margin-bottom: 16px;
373
374 .el-input {
375 flex: 1;
376 }
377 }
378
379 .filters {
380 display: flex;
381 gap: 16px;
382 flex-wrap: wrap;
383 align-items: center;
384
385 .el-select {
386 width: 120px;
387 }
388 }
389}
390
391.torrents-list {
392 background: #fff;
393 border-radius: 12px;
394 padding: 24px;
395 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
396
397 .list-header {
398 margin-bottom: 16px;
399
400 .results-count {
401 font-size: 14px;
402 color: #909399;
403 }
404 }
405
406 .torrents-table {
407 .torrent-info {
408 .torrent-title {
409 font-size: 16px;
410 font-weight: 500;
411 color: #2c3e50;
412 margin: 0 0 8px 0;
413 line-height: 1.4;
414 cursor: pointer;
415
416 &:hover {
417 color: #409eff;
418 }
419 }
420
421 .torrent-meta {
422 display: flex;
423 gap: 16px;
424 font-size: 12px;
425 color: #909399;
426
427 span {
428 display: flex;
429 align-items: center;
430 gap: 4px;
431 }
432 }
433 }
434
435 .seeders {
436 color: #67c23a;
437 font-weight: 600;
438 }
439
440 .leechers {
441 color: #f56c6c;
442 font-weight: 600;
443 }
444 }
445
446 .pagination-wrapper {
447 margin-top: 24px;
448 text-align: center;
449 }
450}
451
452@media (max-width: 768px) {
453 .torrents-page {
454 padding: 16px;
455 }
456
457 .page-header {
458 flex-direction: column;
459 gap: 16px;
460 align-items: flex-start;
461 }
462
463 .filters {
464 flex-direction: column;
465 align-items: flex-start;
466
467 .el-select {
468 width: 100%;
469 }
470 }
471
472 .torrents-table {
473 :deep(.el-table__header),
474 :deep(.el-table__body) {
475 font-size: 12px;
476 }
477 }
478}
xingjinwend652cc62025-06-04 19:52:19 +0800479</style>