| // index.tsx - 活动中心页面 |
| |
| import React, { useState, useEffect, useRef } from 'react'; |
| import { |
| Card, |
| Button, |
| Tag, |
| message, |
| Spin, |
| Empty, |
| List, |
| Space, |
| Typography, |
| Upload |
| } from 'antd'; |
| import { |
| GiftOutlined, |
| UploadOutlined, |
| DownloadOutlined, |
| FireOutlined, |
| CheckCircleOutlined, |
| ClockCircleOutlined |
| } from '@ant-design/icons'; |
| import { PageContainer } from '@ant-design/pro-components'; |
| import { getActivityList, participateActivity, formatDateTime } from './service'; |
| import { uploadTorrent, downloadTorrent } from '../Torrent/service'; |
| import type { SysActivity } from './data'; |
| |
| const { Title, Text } = Typography; |
| |
| const ActivityPage: React.FC = () => { |
| const [activities, setActivities] = useState<SysActivity[]>([]); |
| const [loading, setLoading] = useState(false); |
| const [participatingIds, setParticipatingIds] = useState<Set<number>>(new Set()); |
| const [uploading, setUploading] = useState(false); |
| const [downloading, setDownloading] = useState<number | null>(null); |
| const fileInputRef = useRef<HTMLInputElement>(null); |
| |
| // 获取活动列表 |
| const fetchActivities = async () => { |
| setLoading(true); |
| try { |
| const res = await getActivityList({ pageNum: 1, pageSize: 20 }); |
| console.log('活动列表响应:', res); |
| if (res.code === 0) { |
| // 修正:使用 res.data.list 而不是 res.rows |
| setActivities(res.data.list); |
| console.log('活动数据:', res.data.list); |
| console.log('第一个活动:', res.data.list[0]); |
| } else { |
| message.error(res.msg || '获取活动列表失败'); |
| } |
| } catch (error) { |
| console.error('获取活动列表异常:', error); |
| message.error('网络异常,请稍后重试'); |
| } finally { |
| setLoading(false); |
| } |
| }; |
| |
| // 获取排行榜 |
| // const fetchLeaderboard = async () => { |
| // try { |
| // const res = await getLeaderboard({ pageNum: 1, pageSize: 50 }); |
| // if (res.code === 0) { |
| // setLeaderboard(res.data.list); |
| // } else { |
| // message.error(res.msg || '获取排行榜失败'); |
| // } |
| // } catch (error) { |
| // console.error('获取排行榜失败', error); |
| // message.error('获取排行榜异常,请稍后重试'); |
| // } |
| // }; |
| |
| // 处理文件上传 |
| const handleUpload = async (file: File, activity: SysActivity) => { |
| setUploading(true); |
| try { |
| const res = await uploadTorrent(file); |
| if (res.code === 0) { |
| message.success('上传成功!'); |
| // 上传成功后自动参与活动 |
| await handleParticipate(activity.activityId); |
| } else { |
| message.error(res.msg || '上传失败'); |
| } |
| } catch (error) { |
| console.error('上传异常:', error); |
| message.error('上传异常,请稍后重试'); |
| } finally { |
| setUploading(false); |
| } |
| }; |
| |
| // 处理种子下载 |
| const handleDownload = async (activity: SysActivity) => { |
| setDownloading(activity.activityId); |
| try { |
| const torrentId = activity.conditionValue; // 种子ID存储在conditionValue中 |
| const blob = await downloadTorrent(Number(torrentId)); |
| |
| // 创建下载链接 |
| const url = window.URL.createObjectURL(blob); |
| const link = document.createElement('a'); |
| link.href = url; |
| link.download = `torrent_${torrentId}.torrent`; |
| document.body.appendChild(link); |
| link.click(); |
| document.body.removeChild(link); |
| window.URL.revokeObjectURL(url); |
| |
| message.success('下载成功'); |
| // 下载成功后自动参与活动 |
| await handleParticipate(activity.activityId); |
| } catch (error) { |
| console.error('下载异常:', error); |
| message.error('下载异常,请稍后重试'); |
| } finally { |
| setDownloading(null); |
| } |
| }; |
| |
| // 触发文件选择 |
| const triggerFileUpload = (activity: SysActivity) => { |
| const input = document.createElement('input'); |
| input.type = 'file'; |
| input.accept = '.torrent'; |
| input.onchange = (e) => { |
| const file = (e.target as HTMLInputElement).files?.[0]; |
| if (file) { |
| handleUpload(file, activity); |
| } |
| }; |
| input.click(); |
| }; |
| |
| // 参与活动 |
| const handleParticipate = async (activityId: number) => { |
| // 添加到参与中的活动ID集合 |
| setParticipatingIds(prev => new Set(prev).add(activityId)); |
| |
| try { |
| const res = await participateActivity(activityId); |
| if (res.code === 0) { |
| message.success('参与成功!'); |
| fetchActivities(); |
| // 已删除排行榜刷新 |
| } else { |
| message.error(res.msg || '参与失败'); |
| } |
| } catch (error) { |
| console.error('参与活动异常:', error); |
| message.error('网络异常,请稍后重试'); |
| } finally { |
| // 从参与中的活动ID集合中移除 |
| setParticipatingIds(prev => { |
| const newSet = new Set(prev); |
| newSet.delete(activityId); |
| return newSet; |
| }); |
| } |
| }; |
| |
| useEffect(() => { |
| fetchActivities(); |
| // 已删除排行榜获取 |
| }, []); |
| |
| // 渲染活动类型图标(可点击) |
| const renderActivityIcon = (activity: SysActivity) => { |
| if (activity.status === 0) { |
| // 活动已结束,图标不可点击 |
| return activity.activityType === 'UPLOAD' ? |
| <UploadOutlined style={{ fontSize: 20, color: '#d9d9d9' }} /> : |
| <DownloadOutlined style={{ fontSize: 20, color: '#d9d9d9' }} />; |
| } |
| |
| if (activity.activityType === 'UPLOAD') { |
| return ( |
| <UploadOutlined |
| style={{ |
| fontSize: 20, |
| color: '#1890ff', |
| cursor: 'pointer' |
| }} |
| title="点击上传种子文件" |
| onClick={() => triggerFileUpload(activity)} |
| /> |
| ); |
| } else { |
| return ( |
| <DownloadOutlined |
| style={{ |
| fontSize: 20, |
| color: '#52c41a', |
| cursor: 'pointer' |
| }} |
| title="点击下载种子" |
| onClick={() => handleDownload(activity)} |
| /> |
| ); |
| } |
| }; |
| |
| // 渲染状态标签 |
| const renderStatusTag = (status: number) => { |
| return status === 1 ? ( |
| <Tag icon={<FireOutlined />} color="success">进行中</Tag> |
| ) : ( |
| <Tag icon={<CheckCircleOutlined />} color="default">已结束</Tag> |
| ); |
| }; |
| |
| // 格式化条件显示 |
| const formatCondition = (activity: SysActivity) => { |
| if (activity.activityType === 'UPLOAD') { |
| return `上传 ${activity.conditionValue}`; |
| } |
| return '完成下载任务'; |
| }; |
| |
| // 格式化时间显示 |
| const formatTimeRange = (startTime: string, endTime: string) => { |
| try { |
| // 处理 ISO 8601 格式的时间 |
| const start = formatDateTime(startTime); |
| const end = formatDateTime(endTime); |
| |
| // 只显示日期部分 |
| const startDate = start.split(' ')[0]; |
| const endDate = end.split(' ')[0]; |
| |
| return `${startDate} ~ ${endDate}`; |
| } catch (error) { |
| console.error('时间格式化错误:', error); |
| // 降级处理:如果是老格式,直接使用 |
| return `${startTime.split(' ')[0]} ~ ${endTime.split(' ')[0]}`; |
| } |
| }; |
| |
| // 排行榜相关代码已删除 |
| |
| return ( |
| <PageContainer title="活动中心"> |
| <Spin spinning={loading}> |
| <List |
| grid={{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 3, xl: 3 }} |
| dataSource={activities} |
| locale={{ emptyText: <Empty description="暂无活动" /> }} |
| renderItem={(activity) => ( |
| <List.Item> |
| <Card |
| hoverable |
| actions={[ |
| <Button |
| key="participate" |
| type="primary" |
| disabled={activity.status === 0} |
| loading={ |
| participatingIds.has(activity.activityId) || |
| uploading || |
| downloading === activity.activityId |
| } |
| onClick={() => handleParticipate(activity.activityId)} |
| > |
| {activity.status === 1 ? '确认参与' : '已结束'} |
| </Button> |
| ]} |
| > |
| <Space direction="vertical" size={8} style={{ width: '100%' }}> |
| <Space style={{ width: '100%', justifyContent: 'space-between' }}> |
| {renderActivityIcon(activity)} |
| {renderStatusTag(activity.status)} |
| </Space> |
| |
| <Title level={5} style={{ margin: 0 }}> |
| {activity.activityName} |
| </Title> |
| |
| <Text type="secondary"> |
| {formatCondition(activity)} |
| </Text> |
| |
| <Space> |
| <GiftOutlined style={{ color: '#faad14' }} /> |
| <Text strong style={{ color: '#faad14' }}> |
| {activity.rewardBonus} 积分 |
| </Text> |
| </Space> |
| |
| <Space size={4} style={{ fontSize: 12 }}> |
| <ClockCircleOutlined /> |
| <Text type="secondary"> |
| {formatTimeRange(activity.startTime, activity.endTime)} |
| </Text> |
| </Space> |
| |
| {/* 操作提示 */} |
| {activity.status === 1 && ( |
| <Text type="secondary" style={{ fontSize: 12 }}> |
| {activity.activityType === 'UPLOAD' |
| ? '点击上传图标选择种子文件' |
| : '点击下载图标获取种子' |
| } |
| </Text> |
| )} |
| </Space> |
| </Card> |
| </List.Item> |
| )} |
| /> |
| </Spin> |
| </PageContainer> |
| ); |
| }; |
| |
| export default ActivityPage; |