<template> | |
<div class="torrents-page"> | |
<div class="page-header"> | |
<h1>种子资源</h1> | |
<div class="header-actions"> | |
<el-button type="primary" :icon="Upload" @click="$router.push('/upload')"> | |
上传种子 | |
</el-button> | |
</div> | |
</div> | |
<!-- 搜索和筛选 --> | |
<div class="search-section"> | |
<div class="search-bar"> | |
<el-input | |
v-model="searchQuery" | |
placeholder="搜索种子..." | |
:prefix-icon="Search" | |
size="large" | |
@keyup.enter="handleSearch" | |
clearable | |
/> | |
<el-button type="primary" size="large" @click="handleSearch"> | |
搜索 | |
</el-button> | |
</div> | |
<div class="filters"> | |
<el-select v-model="selectedCategory" placeholder="分类" @change="handleFilter"> | |
<el-option label="全部" value="" /> | |
<el-option label="电影" value="movie" /> | |
<el-option label="电视剧" value="tv" /> | |
<el-option label="音乐" value="music" /> | |
<el-option label="软件" value="software" /> | |
<el-option label="游戏" value="game" /> | |
</el-select> | |
<el-select v-model="sortBy" placeholder="排序方式" @change="handleFilter"> | |
<el-option label="上传时间" value="upload_time" /> | |
<el-option label="文件大小" value="size" /> | |
<el-option label="做种数" value="seeders" /> | |
<el-option label="下载数" value="leechers" /> | |
<el-option label="完成数" value="downloads" /> | |
</el-select> | |
<el-radio-group v-model="sortOrder" @change="handleFilter"> | |
<el-radio-button label="desc">降序</el-radio-button> | |
<el-radio-button label="asc">升序</el-radio-button> | |
</el-radio-group> | |
</div> | |
</div> | |
<!-- 种子列表 --> | |
<div class="torrents-list"> | |
<div class="list-header"> | |
<span class="results-count">共找到 {{ totalCount }} 个种子</span> | |
</div> | |
<el-table | |
:data="torrents" | |
v-loading="loading" | |
@row-click="handleRowClick" | |
stripe | |
class="torrents-table" | |
> | |
<el-table-column label="分类" width="80"> | |
<template #default="{ row }"> | |
<el-tag :type="getCategoryType(row.category)" size="small"> | |
{{ getCategoryName(row.category) }} | |
</el-tag> | |
</template> | |
</el-table-column> | |
<el-table-column label="种子信息" min-width="400"> | |
<template #default="{ row }"> | |
<div class="torrent-info"> | |
<h4 class="torrent-title">{{ row.title }}</h4> | |
<div class="torrent-meta"> | |
<span class="uploader"> | |
<el-icon><User /></el-icon> | |
{{ row.uploader }} | |
</span> | |
<span class="upload-time"> | |
<el-icon><Clock /></el-icon> | |
{{ formatTime(row.uploadTime) }} | |
</span> | |
<span class="file-size"> | |
<el-icon><Document /></el-icon> | |
{{ row.size }} | |
</span> | |
</div> | |
</div> | |
</template> | |
</el-table-column> | |
<el-table-column label="做种" width="80" align="center"> | |
<template #default="{ row }"> | |
<span class="seeders">{{ row.seeders }}</span> | |
</template> | |
</el-table-column> | |
<el-table-column label="下载" width="80" align="center"> | |
<template #default="{ row }"> | |
<span class="leechers">{{ row.leechers }}</span> | |
</template> | |
</el-table-column> | |
<el-table-column label="完成" width="80" align="center"> | |
<template #default="{ row }"> | |
<span>{{ row.downloads }}</span> | |
</template> | |
</el-table-column> | |
<el-table-column label="操作" width="120" align="center"> | |
<template #default="{ row }"> | |
<el-button | |
type="primary" | |
size="small" | |
:icon="Download" | |
@click.stop="handleDownload(row)" | |
> | |
下载 | |
</el-button> | |
</template> | |
</el-table-column> | |
</el-table> | |
<!-- 分页 --> | |
<div class="pagination-wrapper"> | |
<el-pagination | |
v-model:current-page="currentPage" | |
v-model:page-size="pageSize" | |
:page-sizes="[20, 50, 100]" | |
:total="totalCount" | |
layout="total, sizes, prev, pager, next, jumper" | |
@size-change="handleSizeChange" | |
@current-change="handleCurrentChange" | |
/> | |
</div> | |
</div> | |
</div> | |
</template> | |
<script> | |
import { ref, onMounted, watch } from 'vue' | |
import { useRouter, useRoute } from 'vue-router' | |
import { ElMessage } from 'element-plus' | |
import { | |
Search, | |
Upload, | |
Download, | |
User, | |
Clock, | |
Document | |
} from '@element-plus/icons-vue' | |
export default { | |
name: 'TorrentsView', | |
setup() { | |
const router = useRouter() | |
const route = useRoute() | |
const loading = ref(false) | |
const searchQuery = ref('') | |
const selectedCategory = ref('') | |
const sortBy = ref('upload_time') | |
const sortOrder = ref('desc') | |
const currentPage = ref(1) | |
const pageSize = ref(20) | |
const totalCount = ref(0) | |
const torrents = ref([ | |
{ | |
id: 1, | |
title: '[4K蓝光原盘] 阿凡达:水之道 Avatar: The Way of Water (2022)', | |
category: 'movie', | |
uploader: 'MovieMaster', | |
uploadTime: '2025-06-03T10:30:00', | |
size: '85.6 GB', | |
seeders: 128, | |
leechers: 45, | |
downloads: 892 | |
}, | |
{ | |
id: 2, | |
title: '[FLAC] Taylor Swift - Midnights (Deluxe Edition) [2022]', | |
category: 'music', | |
uploader: 'MusicLover', | |
uploadTime: '2025-06-03T09:15:00', | |
size: '1.2 GB', | |
seeders: 67, | |
leechers: 12, | |
downloads: 456 | |
}, | |
{ | |
id: 3, | |
title: '[合集] Adobe Creative Suite 2025 完整版', | |
category: 'software', | |
uploader: 'TechGuru', | |
uploadTime: '2025-06-03T08:45:00', | |
size: '12.8 GB', | |
seeders: 234, | |
leechers: 89, | |
downloads: 1205 | |
} | |
]) | |
onMounted(() => { | |
// 从URL参数初始化搜索条件 | |
if (route.query.q) { | |
searchQuery.value = route.query.q | |
} | |
if (route.query.category) { | |
selectedCategory.value = route.query.category | |
} | |
fetchTorrents() | |
}) | |
const fetchTorrents = async () => { | |
loading.value = true | |
try { | |
// 模拟API调用 | |
await new Promise(resolve => setTimeout(resolve, 1000)) | |
totalCount.value = 156 | |
} catch (error) { | |
ElMessage.error('获取种子列表失败') | |
} finally { | |
loading.value = false | |
} | |
} | |
const handleSearch = () => { | |
currentPage.value = 1 | |
updateURL() | |
fetchTorrents() | |
} | |
const handleFilter = () => { | |
currentPage.value = 1 | |
updateURL() | |
fetchTorrents() | |
} | |
const updateURL = () => { | |
const query = {} | |
if (searchQuery.value) query.q = searchQuery.value | |
if (selectedCategory.value) query.category = selectedCategory.value | |
if (sortBy.value !== 'upload_time') query.sort = sortBy.value | |
if (sortOrder.value !== 'desc') query.order = sortOrder.value | |
if (currentPage.value > 1) query.page = currentPage.value | |
router.replace({ query }) | |
} | |
const handleRowClick = (row) => { | |
router.push(`/torrent/${row.id}`) | |
} | |
const handleDownload = (row) => { | |
ElMessage.success(`开始下载: ${row.title}`) | |
// 这里实现下载逻辑 | |
} | |
const handleSizeChange = (size) => { | |
pageSize.value = size | |
currentPage.value = 1 | |
fetchTorrents() | |
} | |
const handleCurrentChange = (page) => { | |
currentPage.value = page | |
updateURL() | |
fetchTorrents() | |
} | |
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) | |
return `${days}天前` | |
} | |
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 | |
} | |
return { | |
loading, | |
searchQuery, | |
selectedCategory, | |
sortBy, | |
sortOrder, | |
currentPage, | |
pageSize, | |
totalCount, | |
torrents, | |
handleSearch, | |
handleFilter, | |
handleRowClick, | |
handleDownload, | |
handleSizeChange, | |
handleCurrentChange, | |
formatTime, | |
getCategoryType, | |
getCategoryName, | |
Search, | |
Upload, | |
Download, | |
User, | |
Clock, | |
Document | |
} | |
} | |
} | |
</script> | |
<style lang="scss" scoped> | |
.torrents-page { | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 24px; | |
} | |
.page-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 24px; | |
h1 { | |
font-size: 28px; | |
font-weight: 600; | |
color: #2c3e50; | |
margin: 0; | |
} | |
} | |
.search-section { | |
background: #fff; | |
border-radius: 12px; | |
padding: 24px; | |
margin-bottom: 24px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); | |
.search-bar { | |
display: flex; | |
gap: 12px; | |
margin-bottom: 16px; | |
.el-input { | |
flex: 1; | |
} | |
} | |
.filters { | |
display: flex; | |
gap: 16px; | |
flex-wrap: wrap; | |
align-items: center; | |
.el-select { | |
width: 120px; | |
} | |
} | |
} | |
.torrents-list { | |
background: #fff; | |
border-radius: 12px; | |
padding: 24px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); | |
.list-header { | |
margin-bottom: 16px; | |
.results-count { | |
font-size: 14px; | |
color: #909399; | |
} | |
} | |
.torrents-table { | |
.torrent-info { | |
.torrent-title { | |
font-size: 16px; | |
font-weight: 500; | |
color: #2c3e50; | |
margin: 0 0 8px 0; | |
line-height: 1.4; | |
cursor: pointer; | |
&:hover { | |
color: #409eff; | |
} | |
} | |
.torrent-meta { | |
display: flex; | |
gap: 16px; | |
font-size: 12px; | |
color: #909399; | |
span { | |
display: flex; | |
align-items: center; | |
gap: 4px; | |
} | |
} | |
} | |
.seeders { | |
color: #67c23a; | |
font-weight: 600; | |
} | |
.leechers { | |
color: #f56c6c; | |
font-weight: 600; | |
} | |
} | |
.pagination-wrapper { | |
margin-top: 24px; | |
text-align: center; | |
} | |
} | |
@media (max-width: 768px) { | |
.torrents-page { | |
padding: 16px; | |
} | |
.page-header { | |
flex-direction: column; | |
gap: 16px; | |
align-items: flex-start; | |
} | |
.filters { | |
flex-direction: column; | |
align-items: flex-start; | |
.el-select { | |
width: 100%; | |
} | |
} | |
.torrents-table { | |
:deep(.el-table__header), | |
:deep(.el-table__body) { | |
font-size: 12px; | |
} | |
} | |
} | |
</style> |