blob: 88d662932f97ea0f6a3f7f925003c089ff96e8b6 [file] [log] [blame]
LaoeGaocia8f7d6c2025-06-04 15:39:49 +08001'use client';
2
3import React, { useEffect, useState, useRef } from "react";
4import { Card } from 'primereact/card';
5import { Image } from 'primereact/image';
6import { Button } from 'primereact/button';
7import { InputText } from 'primereact/inputtext';
8// 页面跳转
9import { useRouter } from 'next/navigation';
10// 消息提醒
11import { Toast } from 'primereact/toast';
12// 分页
13import { Paginator, type PaginatorPageChangeEvent } from 'primereact/paginator';
14// 评分图标
15import { Fire } from '@icon-park/react';
16// 接口传输
17import axios from 'axios';
18// 标签
19import { Tag } from 'primereact/tag';
20import { Sidebar } from 'primereact/sidebar';
21// 防抖函数
22import { debounce } from 'lodash';
23// 样式
24import './classification.scss';
25
26// 热门资源数据
27
28interface HotResource {
29 resourceId: number;
30 resourceName: string;
31 resourcePicture: string;
32 resourceSummary: string;
33 lastUpdateTime: string;
34 hot: number;
35 gamePlayList: { gameplayName: string }[];
36}
37
38interface HotResourceList {
39 total: number;
40 records: HotResource[];
41}
42// 主页
43export default function ClassificationResource() {
44 // 热门资源列表
45 const [hotResources, setHotResources] = useState<HotResource[]>([]);
46 const [totalHotResource, setTotalHotResource] = useState(0);
47 const [visibleRight, setVisibleRight] = useState<boolean>(false);
48
49 // 消息提醒
50 const toast = useRef<Toast>(null);
51 const router = useRouter();
52
53 // 当前选中的 classify
54 const [selectedClassify, setSelectedClassify] = useState<string>('模组');
55 const [selectedGameplay, setSelectedGameplay] = useState<string[]>([]);
56 const [selectedVersions, setSelectedVersions] = useState<string[]>([]);
57 const [searchValue, setSearchValue] = useState<string>('');
58 const debouncedSearch = useRef(
59 debounce((value: string) => {
60 setSearchValue(value);
61 }, 600)
62 ).current;
63 // 分页
64 const [first, setFirst] = useState(0);
65 const [rows, setRows] = useState(5);
66 const onPageChange = (event: PaginatorPageChangeEvent) => {
67 setFirst(event.first);
68 setRows(event.rows);
69 };
70 // 获取帖子列表
71 useEffect(() => {
72 handleSearch();
73 }, [first, rows,searchValue]);
74
75 const handleSearch = async () => {
76 try {
77 const pageNumber = first / rows + 1;
78 console.log(searchValue + " 当前页: " + pageNumber + "rows: " + rows + "selectedClassify: " + selectedClassify + "selectedGameplay: " + selectedGameplay + "selectedVersions: " + selectedVersions);
79 const response = await axios.get<HotResourceList>(process.env.PUBLIC_URL + `/resource/search`, {
80 params: {
81 userId: 22301145,
82 pageNumber,
83 rows,
84 classify: selectedClassify,
85 gameplayList: selectedGameplay.join(','),
86 versionList: selectedVersions.join(','),
87 searchValue
88 }
89 });
90 setHotResources(response.data.records);
91 setTotalHotResource(response.data.total);
92 setVisibleRight(false);
93 } catch (err) {
94 console.error('搜索资源失败', err);
95 toast.current?.show({ severity: 'error', summary: 'error', detail: '搜索资源失败' });
96 }
97 };
98
99 return (
100 <div className="HotResource">
101 <div className="header">
102 <div className="searchBar">
103 <i className="pi pi-search" />
104 <InputText type="search" className="search-helper" placeholder="搜索你感兴趣的帖子" onChange={(e) => { const target = e.target as HTMLInputElement; debouncedSearch(target.value); }} />
105 </div>
106 <Button label="查看分类" className="classificationButton" onClick={() => setVisibleRight(true)} />
107 </div>
108 {/* 全部社区 */}
109 <div className="all-resources-list">
110 {hotResources.map((hotResource) => (
111 <Card key={hotResource.resourceId} className="all-resources-card" onClick={() => router.push(`/resource/resource-detail/${hotResource.resourceId}`)}>
112 <Image alt="avatar" src={process.env.NEXT_PUBLIC_NGINX_URL + "hotResource/" + hotResource.resourcePicture} className="resource-avatar" width="250" height="140" />
113 <div className="resource-header">
114 <div className="resource-content">
115 <h3>{hotResource.resourceName}</h3>
116 <div className="tags">
117 {hotResource.gamePlayList.map((tag, index) => (
118 <Tag key={index} value={tag.gameplayName} />
119 ))}
120 </div>
121 </div>
122 <div className="resources-states">
123 <div className="state-item">
124 <Fire theme="outline" size="16" fill="#FF8D1A" />
125 <span>热度: {hotResource.hot}</span>
126 </div>
127 <div className="state-item">
128 <span>最新更新时间: {hotResource.lastUpdateTime}</span>
129 </div>
130 </div>
131 </div>
132 </Card>
133 ))}
134 </div>
135 {totalHotResource > 5 && (<Paginator className="Paginator" first={first} rows={rows} totalRecords={totalHotResource} rowsPerPageOptions={[5, 10]} onPageChange={onPageChange} />)}
136 <Sidebar className="sidebar" visible={visibleRight} position="right" onHide={() => setVisibleRight(false)}>
137 <div className="sidebar-content">
138 <h3>分类</h3>
139 <div className="filter-section">
140 {['模组', '地图', '整合包', '材质包'].map((item) => (
141 <Button key={item} label={item} className={selectedClassify === item ? 'p-button-primary' : 'p-button-text'} onClick={() => setSelectedClassify(item)} />
142 ))}
143 </div>
144
145 <h3>主要玩法</h3>
146 <div className="filter-section">
147 {['不限', '科技', '魔法', '建筑', '风景', '竞技', '生存', '冒险', '跑酷', '艺术', '剧情', '社交', '策略', '极限'].map((gameplay) => (
148 <Button
149 key={gameplay}
150 label={gameplay}
151 className={selectedGameplay.includes(gameplay) ? 'p-button-primary' : 'p-button-text'}
152 onClick={() => {
153 if (selectedGameplay.includes(gameplay)) {
154 setSelectedGameplay(selectedGameplay.filter((g) => g !== gameplay));
155 } else {
156 setSelectedGameplay([...selectedGameplay, gameplay]);
157 }
158 }}
159 />
160 ))}
161 </div>
162
163 <h3>游戏版本</h3>
164 <div className="filter-section">
165 {['不限', '1.20.1', '1.20.4', '1.7.3', '1.12.1', '1.19.2', '1.18.3', '1.20.3', '1.19.1', '1.18.6'].map((ver) => (
166 <Button
167 key={ver}
168 label={ver}
169 className={selectedVersions.includes(ver) ? 'p-button-primary' : 'p-button-text'}
170 onClick={() => {
171 if (selectedVersions.includes(ver)) {
172 setSelectedVersions(selectedVersions.filter((v) => v !== ver));
173 } else {
174 setSelectedVersions([...selectedVersions, ver]);
175 }
176 }}
177 />
178 ))}
179 </div>
180 <div className="filter-confirm">
181 <Button label="确定" icon="pi pi-check" onClick={handleSearch} />
182 </div>
183 </div>
184 </Sidebar>
185 </div>
186 );
187}