blob: c4e0ec7c1cfb9fd33c790bdcc932e813f16e1ed1 [file] [log] [blame]
<template>
<div class="home-page">
<div class="home-container">
<!-- 用户信息和导航 -->
<header class="site-header">
<div class="header-content">
<div class="logo-section">
<h2 class="site-logo">🚀 PT Tracker</h2>
</div>
<div class="user-section">
<div class="user-stats">
<div class="stat-item">
<span class="stat-label">上传:</span>
<span class="stat-value">{{ userStats.uploaded }}</span>
</div>
<div class="stat-item">
<span class="stat-label">下载:</span>
<span class="stat-value">{{ userStats.downloaded }}</span>
</div>
<div class="stat-item">
<span class="stat-label">分享率:</span>
<span class="stat-value ratio" :class="getRatioClass(userStats.ratio)">
{{ userStats.ratio }}
</span>
</div>
</div>
<div class="user-info">
<el-avatar :size="40" :icon="UserFilled" />
<span class="username">{{ userInfo.username }}</span>
<el-dropdown @command="handleUserCommand">
<el-icon class="dropdown-icon"><ArrowDown /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile">个人资料</el-dropdown-item>
<el-dropdown-item command="settings">设置</el-dropdown-item>
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</div>
</header>
<!-- 主要内容区域 -->
<main class="main-content">
<!-- 统计概览 -->
<section class="stats-overview">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon">
<el-icon size="32" color="#67c23a"><Download /></el-icon>
</div>
<div class="stat-info">
<h3>{{ siteStats.totalTorrents }}</h3>
<p>种子总数</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<el-icon size="32" color="#409eff"><User /></el-icon>
</div>
<div class="stat-info">
<h3>{{ siteStats.totalUsers }}</h3>
<p>注册用户</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<el-icon size="32" color="#f56c6c"><Upload /></el-icon>
</div>
<div class="stat-info">
<h3>{{ siteStats.totalSize }}</h3>
<p>数据总量</p>
</div>
</div>
</div>
</section>
<!-- 快速操作 -->
<section class="quick-actions">
<h2 class="section-title">快速操作</h2>
<div class="action-grid">
<div class="action-card" @click="navigateTo('/torrents')">
<el-icon size="48" color="#409eff"><Search /></el-icon>
<h3>浏览种子</h3>
<p>搜索和浏览所有可用的种子资源</p>
</div>
<div class="action-card" @click="navigateTo('/upload')">
<el-icon size="48" color="#67c23a"><Upload /></el-icon>
<h3>上传资源</h3>
<p>分享你的资源,为社区做贡献</p>
</div>
<div class="action-card" @click="navigateTo('/forum')">
<el-icon size="48" color="#e6a23c"><ChatDotRound /></el-icon>
<h3>论坛交流</h3>
<p>与其他用户交流讨论</p>
</div>
<div class="action-card" @click="navigateTo('/rankings')">
<el-icon size="48" color="#f56c6c"><TrophyBase /></el-icon>
<h3>排行榜</h3>
<p>查看用户和资源排行</p>
</div>
</div>
</section>
<!-- 最新种子 -->
<section class="latest-torrents">
<div class="section-header">
<h2 class="section-title">最新种子</h2>
<el-button type="primary" text @click="navigateTo('/torrents')">
查看更多 <el-icon><ArrowRight /></el-icon>
</el-button>
</div>
<div class="torrents-list">
<div
v-for="torrent in latestTorrents"
:key="torrent.id"
class="torrent-item"
@click="navigateTo(`/torrent/${torrent.id}`)"
>
<div class="torrent-info">
<div class="torrent-category">
<el-tag :type="getCategoryType(torrent.category)" size="small">
{{ torrent.category }}
</el-tag>
</div>
<h4 class="torrent-title">{{ torrent.title }}</h4>
<div class="torrent-meta">
<span class="meta-item">
<el-icon><User /></el-icon>
{{ torrent.uploader }}
</span>
<span class="meta-item">
<el-icon><Clock /></el-icon>
{{ formatTime(torrent.uploadTime) }}
</span>
<span class="meta-item">
<el-icon><Coin /></el-icon>
{{ torrent.size }}
</span>
</div>
</div>
<div class="torrent-stats">
<div class="stat-group">
<span class="stat-number seeders">{{ torrent.seeders }}</span>
<span class="stat-label">做种</span>
</div>
<div class="stat-group">
<span class="stat-number leechers">{{ torrent.leechers }}</span>
<span class="stat-label">下载</span>
</div>
<div class="stat-group">
<span class="stat-number">{{ torrent.downloads }}</span>
<span class="stat-label">完成</span>
</div>
</div>
</div>
</div>
</section>
<!-- 个人活动 -->
<section class="user-activity">
<h2 class="section-title">我的活动</h2>
<div class="activity-grid">
<div class="activity-card">
<h3>我的种子</h3>
<div class="activity-stats">
<div class="activity-item">
<span class="activity-label">正在做种:</span>
<span class="activity-value">{{ userActivity.seeding }}</span>
</div>
<div class="activity-item">
<span class="activity-label">正在下载:</span>
<span class="activity-value">{{ userActivity.downloading }}</span>
</div>
<div class="activity-item">
<span class="activity-label">已上传:</span>
<span class="activity-value">{{ userActivity.uploaded }}</span>
</div>
</div>
<el-button type="primary" size="small" @click="navigateTo('/my-torrents')">
查看详情
</el-button>
</div>
<div class="activity-card">
<h3>邀请管理</h3>
<div class="activity-stats">
<div class="activity-item">
<span class="activity-label">可用邀请:</span>
<span class="activity-value">{{ userActivity.invitations }}</span>
</div>
<div class="activity-item">
<span class="activity-label">已邀请:</span>
<span class="activity-value">{{ userActivity.invited }}</span>
</div>
</div>
<el-button type="success" size="small" @click="navigateTo('/invitations')">
管理邀请
</el-button>
</div>
</div>
</section>
</main>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
UserFilled,
ArrowDown,
Download,
Upload,
ChatDotRound,
Search,
User,
Connection,
TrophyBase,
ArrowRight,
Clock,
Coin
} from '@element-plus/icons-vue'
export default {
name: 'HomeView',
components: {
UserFilled,
ArrowDown
},
setup() {
const router = useRouter()
const userInfo = ref({
username: '',
loginTime: ''
})
const userStats = ref({
uploaded: '128.5 GB',
downloaded: '45.2 GB',
ratio: '2.84'
})
const siteStats = ref({
totalTorrents: '12,458',
totalUsers: '8,924',
onlineUsers: '342',
totalSize: '45.2 TB'
})
const userActivity = ref({
seeding: 15,
downloading: 3,
uploaded: 8,
invitations: 5,
invited: 12
})
const latestTorrents = ref([
{
id: 1,
title: '[4K蓝光原盘] 阿凡达:水之道 Avatar: The Way of Water (2022)',
category: '电影',
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: '音乐',
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: '软件',
uploader: 'TechGuru',
uploadTime: '2025-06-03T08:45:00',
size: '12.8 GB',
seeders: 234,
leechers: 89,
downloads: 1205
}
])
onMounted(() => {
userInfo.value = {
username: localStorage.getItem('username') || '用户',
loginTime: localStorage.getItem('loginTime') || ''
}
// 模拟获取用户数据
fetchUserData()
})
const fetchUserData = () => {
// 这里应该是API调用,现在使用模拟数据
console.log('获取用户数据...')
}
const formatTime = (timeString) => {
if (!timeString) return ''
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 getRatioClass = (ratio) => {
const r = parseFloat(ratio)
if (r >= 2) return 'excellent'
if (r >= 1) return 'good'
return 'warning'
}
const getCategoryType = (category) => {
const types = {
'电影': 'primary',
'音乐': 'success',
'软件': 'warning',
'游戏': 'danger',
'电视剧': 'info'
}
return types[category] || 'default'
}
const navigateTo = (path) => {
router.push(path)
}
const handleUserCommand = async (command) => {
switch (command) {
case 'profile':
navigateTo('/profile')
break
case 'settings':
navigateTo('/settings')
break
case 'logout':
await handleLogout()
break
}
}
const handleLogout = async () => {
try {
await ElMessageBox.confirm(
'确定要退出登录吗?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
localStorage.removeItem('isLoggedIn')
localStorage.removeItem('username')
localStorage.removeItem('loginTime')
localStorage.removeItem('rememberLogin')
ElMessage.success('已安全退出')
router.push('/login')
} catch {
// 用户取消退出
}
}
return {
userInfo,
userStats,
siteStats,
userActivity,
latestTorrents,
formatTime,
getRatioClass,
getCategoryType,
navigateTo,
handleUserCommand,
handleLogout,
Download,
Upload,
ChatDotRound,
Search,
User,
Connection,
TrophyBase,
ArrowRight,
Clock,
Coin
}
}
}
</script>
<style lang="scss" scoped>
.home-page {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 0;
}
.home-container {
max-width: 1200px;
margin: 0 auto;
background: #fff;
min-height: 100vh;
}
// 网站头部
.site-header {
background: #fff;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
.logo-section {
.site-logo {
margin: 0;
font-size: 24px;
font-weight: bold;
color: #667eea;
}
}
.user-section {
display: flex;
align-items: center;
gap: 24px;
.user-stats {
display: flex;
gap: 16px;
.stat-item {
font-size: 14px;
.stat-label {
color: #909399;
margin-right: 4px;
}
.stat-value {
font-weight: 600;
color: #2c3e50;
&.ratio {
&.excellent { color: #67c23a; }
&.good { color: #e6a23c; }
&.warning { color: #f56c6c; }
}
}
}
}
.user-info {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
.username {
font-weight: 500;
color: #2c3e50;
}
.dropdown-icon {
color: #909399;
transition: transform 0.3s ease;
&:hover {
transform: rotate(180deg);
}
}
}
}
}
}
// 主要内容
.main-content {
padding: 24px;
}
.section-title {
font-size: 20px;
font-weight: 600;
color: #2c3e50;
margin-bottom: 16px;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
// 统计概览
.stats-overview {
margin-bottom: 32px;
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
.stat-card {
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
border: 1px solid #f0f0f0;
display: flex;
align-items: center;
gap: 16px;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
.stat-info {
h3 {
font-size: 24px;
font-weight: bold;
color: #2c3e50;
margin: 0 0 4px 0;
}
p {
font-size: 14px;
color: #909399;
margin: 0;
}
}
}
}
}
// 快速操作
.quick-actions {
margin-bottom: 32px;
.action-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 20px;
.action-card {
background: #fff;
border-radius: 12px;
padding: 32px 24px;
text-align: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
border: 1px solid #f0f0f0;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15);
}
h3 {
font-size: 18px;
font-weight: 600;
color: #2c3e50;
margin: 16px 0 8px 0;
}
p {
font-size: 14px;
color: #7f8c8d;
line-height: 1.5;
margin: 0;
}
}
}
}
// 最新种子
.latest-torrents {
margin-bottom: 32px;
.torrents-list {
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
border: 1px solid #f0f0f0;
overflow: hidden;
.torrent-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 24px;
border-bottom: 1px solid #f5f5f5;
cursor: pointer;
transition: background-color 0.3s ease;
&:hover {
background-color: #f8f9fa;
}
&:last-child {
border-bottom: none;
}
.torrent-info {
flex: 1;
.torrent-category {
margin-bottom: 8px;
}
.torrent-title {
font-size: 16px;
font-weight: 500;
color: #2c3e50;
margin: 0 0 8px 0;
line-height: 1.4;
}
.torrent-meta {
display: flex;
gap: 16px;
.meta-item {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: #909399;
.el-icon {
font-size: 12px;
}
}
}
}
.torrent-stats {
display: flex;
gap: 24px;
.stat-group {
text-align: center;
.stat-number {
display: block;
font-size: 16px;
font-weight: 600;
&.seeders { color: #67c23a; }
&.leechers { color: #f56c6c; }
}
.stat-label {
font-size: 12px;
color: #909399;
}
}
}
}
}
}
// 用户活动
.user-activity {
.activity-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
.activity-card {
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
border: 1px solid #f0f0f0;
h3 {
font-size: 18px;
font-weight: 600;
color: #2c3e50;
margin: 0 0 16px 0;
}
.activity-stats {
margin-bottom: 16px;
.activity-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
.activity-label {
font-size: 14px;
color: #7f8c8d;
}
.activity-value {
font-size: 14px;
font-weight: 600;
color: #2c3e50;
}
}
}
}
}
}
// 响应式设计
@media (max-width: 768px) {
.header-content {
flex-direction: column;
gap: 16px;
.user-stats {
flex-direction: column;
gap: 8px;
text-align: center;
}
}
.main-content {
padding: 16px;
}
.stats-grid,
.action-grid,
.activity-grid {
grid-template-columns: 1fr;
}
.torrent-item {
flex-direction: column;
align-items: flex-start;
gap: 16px;
.torrent-stats {
width: 100%;
justify-content: space-around;
}
}
}
</style>