blob: 57f1b26920e7c3b3a4b057f4f1738a81945482c8 [file] [log] [blame]
'use client';
import React, { useEffect, useState, useRef } from "react";
import { Card } from 'primereact/card';
import { Image } from 'primereact/image';
import { Carousel } from 'primereact/carousel';
// 页面跳转
import { useRouter } from 'next/navigation';
// 消息提醒
import { Toast } from 'primereact/toast';
// 分页
import { Paginator, type PaginatorPageChangeEvent } from 'primereact/paginator';
// 评分图标
import { Fire } from '@icon-park/react';
// 接口传输
import axios from 'axios';
// 标签
import { Tag } from 'primereact/tag';
import { Chart } from 'primereact/chart';
import { TabView, TabPanel } from 'primereact/tabview';
// 样式
import './hot-resource.scss';
// 热门资源数据
interface HotResourceSlide {
resourceId: number;
resourceName: string;
resourcePicture: string;
}
interface HotResourceSlideList {
records: HotResourceSlide[];
}
interface HotResource {
resourceId: number;
resourceName: string;
resourcePicture: string;
resourceSummary: string;
lastUpdateTime: string;
hot: number;
gameplayList: string[];
}
interface HotEntry {
hot: number;
}
interface HotInfo {
classify: string;
hotInfoList: HotEntry[];
}
interface HotInfoResponse {
records: HotInfo[];
}
interface HotResourceList {
total: number;
records: HotResource[];
}
// 主页
export default function HotResource() {
// 热门资源列表
const [hotResources, setHotResources] = useState<HotResource[]>([]);
const [totalHotResource, setTotalHotResource] = useState(0);
const [hotResourceSlide, setHotResourceSlide] = useState<HotResourceSlide[]>([]);
// 图表数据
const [chartData, setChartData] = useState({});
const [chartOptions, setChartOptions] = useState({});
// 消息提醒
const toast = useRef<Toast>(null);
const router = useRouter();
const [activeTabIndex, setActiveTabIndex] = useState(0);
const resourceTabs = [
{ title: '模组' },
{ title: '地图' },
{ title: '整合包' },
{ title: '材质包' }
];
// 当前选中的 classify
const [classify, setClassify] = useState<string>(resourceTabs[0].title);
// 分页
const [first, setFirst] = useState(0);
const [rows, setRows] = useState(6);
const onPageChange = (event: PaginatorPageChangeEvent) => {
setFirst(event.first);
setRows(event.rows);
};
// 获取帖子列表
useEffect(() => {
fetchHotResources(classify);
}, [first, rows, classify]);
useEffect(() => {
fetchHotInfo();
// 组件加载时获取热门资源幻灯片
fetchHotResourcesSlide();
}, []);
const generateColor = (index: number): string => {
const colors = [
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0',
'#9966FF', '#FF9F40', '#C9CBCF', '#009688'
];
return colors[index % colors.length];
};
const fetchHotInfo = async () => {
try {
const response = await axios.get<HotInfoResponse>(process.env.PUBLIC_URL + `/resource/hot-trend`);
console.log(response.data.records)
const records = response.data.records;
// 获取最近七天的日期标签(格式:MM-DD)
const labels = Array.from({ length: 7 }, (_, i) => {
const date = new Date();
date.setDate(date.getDate() - (6 - i)); // 向前推6~0天,按时间顺序排列
return `${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
});
const datasets = records.map((info, idx) => ({
label: info.classify,
data: info.hotInfoList.map(h => h.hot),
fill: false,
tension: 0.4,
borderColor: generateColor(idx),
backgroundColor: generateColor(idx)
}));
setChartData({
labels,
datasets
});
setChartOptions({
responsive: true,
plugins: {
legend: {
position: 'right'
},
title: {
display: true,
text: '资源热度变化趋势图'
}
},
scales: {
x: {
title: {
display: true,
text: '日期'
}
},
y: {
title: {
display: true,
text: '热度'
},
beginAtZero: true,
min: 4,
max: 10,
ticks: {
stepSize: 2,
font: {
size: 12
}
}
}
}
});
} catch (err) {
console.error('获取资源热度信息失败', err);
toast.current?.show({ severity: 'error', summary: 'error', detail: '获取热度信息失败' });
}
};
// 获取热门资源幻灯片
const fetchHotResourcesSlide = async () => {
try {
const response = await axios.get<HotResourceSlideList>(process.env.PUBLIC_URL + `/resource/hot/slide`);
console.log('获取热门社区幻灯片:', response.data.records);
setHotResourceSlide(response.data.records);
} catch (err) {
console.error('获取Mod失败', err);
toast.current?.show({ severity: 'error', summary: 'error', detail: '获取Mod失败' });
}
};
// 获取热门资源
const fetchHotResources = async (classify: string) => {
try {
const pageNumber = first / rows + 1;
console.log("当前页" + pageNumber + "size" + rows + "分类" + classify);
const response = await axios.get<HotResourceList>(process.env.PUBLIC_URL + `/resource/hot`, {
params: { pageNumber, rows, classify }
});
console.log('获取热门社区:', response.data.records);
setHotResources(response.data.records);
setTotalHotResource(response.data.total);
} catch (err) {
console.error('获取Mod失败', err);
toast.current?.show({ severity: 'error', summary: 'error', detail: '获取Mod失败' });
}
};
return (
<div className="HotResource">
{/* 轮播图部分 */}
<div className="main-header">
<div className="carousel-wrapper">
<Carousel
value={hotResourceSlide}
numVisible={1}
numScroll={1}
showIndicators={false}
showNavigators={true}
className="custom-carousel"
itemTemplate={(hotResource) => (
<div className="carousel-item" onClick={() => router.push(`/resource/resource-detail/${hotResource.resourceId}`)}>
<Image alt="slide" src={ hotResource.resourcePicture} className="carousel-avatar" width="480" height="350" />
<h3>{hotResource.resourceName}</h3>
</div>
)}
/>
</div>
<div className="chart-wrapper">
<Chart type="line" data={chartData} options={chartOptions} />
</div>
</div>
{/* 全部社区 */}
<TabView scrollable className="all-resources" activeIndex={activeTabIndex} onTabChange={(e) => {
setActiveTabIndex(e.index);
const newClassify = resourceTabs[e.index].title;
setClassify(newClassify);
}}>
{resourceTabs.map((tab) => {
return (
<TabPanel key={tab.title} header={tab.title}>
<div className="all-resources-list">
{hotResources.map((hotResource) => (
<Card key={hotResource.resourceId} className="all-resources-card" onClick={() => router.push(`/resource/resource-detail/${hotResource.resourceId}`)}>
<Image alt="avatar" src={ "hotResource/" + hotResource.resourcePicture} className="resource-avatar" width="250" height="140" />
<div className="resource-header">
<div className="resource-content">
<h3>{hotResource.resourceName}</h3>
<div className="tags">
{hotResource.gameplayList.map((tag, index) => (
<Tag key={index} value={tag} />
))}
</div>
</div>
<div className="resources-states">
<div className="state-item">
<Fire theme="outline" size="16" fill="#FF8D1A" />
<span>热度: {hotResource.hot}</span>
</div>
<div className="state-item">
<span>最新更新时间: {hotResource.lastUpdateTime}</span>
</div>
</div>
</div>
</Card>
))}
</div>
</TabPanel>
);
})}
{totalHotResource > 6 && (<Paginator className="Paginator" first={first} rows={rows} totalRecords={totalHotResource} rowsPerPageOptions={[6, 12]} onPageChange={onPageChange} />)}
</TabView>
</div>
);
}