add classification page

Change-Id: I5f661291cd32416b23e9b3f4483f200e885141c5
diff --git a/src/app/resource/classification/page.tsx b/src/app/resource/classification/page.tsx
new file mode 100644
index 0000000..88d6629
--- /dev/null
+++ b/src/app/resource/classification/page.tsx
@@ -0,0 +1,187 @@
+'use client';
+
+import React, { useEffect, useState, useRef } from "react";
+import { Card } from 'primereact/card';
+import { Image } from 'primereact/image';
+import { Button } from 'primereact/button';
+import { InputText } from 'primereact/inputtext';
+// 页面跳转
+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 { Sidebar } from 'primereact/sidebar';
+// 防抖函数
+import { debounce } from 'lodash';
+// 样式
+import './classification.scss';
+
+// 热门资源数据
+
+interface HotResource {
+  resourceId: number;
+  resourceName: string;
+  resourcePicture: string;
+  resourceSummary: string;
+  lastUpdateTime: string;
+  hot: number;
+  gamePlayList: { gameplayName: string }[];
+}
+
+interface HotResourceList {
+  total: number;
+  records: HotResource[];
+}
+// 主页
+export default function ClassificationResource() {
+  // 热门资源列表
+  const [hotResources, setHotResources] = useState<HotResource[]>([]);
+  const [totalHotResource, setTotalHotResource] = useState(0);
+  const [visibleRight, setVisibleRight] = useState<boolean>(false);
+
+  // 消息提醒
+  const toast = useRef<Toast>(null);
+  const router = useRouter();
+
+  // 当前选中的 classify
+  const [selectedClassify, setSelectedClassify] = useState<string>('模组');
+  const [selectedGameplay, setSelectedGameplay] = useState<string[]>([]);
+  const [selectedVersions, setSelectedVersions] = useState<string[]>([]);
+  const [searchValue, setSearchValue] = useState<string>('');
+  const debouncedSearch = useRef(
+    debounce((value: string) => {
+      setSearchValue(value);
+    }, 600)
+  ).current;
+  // 分页
+  const [first, setFirst] = useState(0);
+  const [rows, setRows] = useState(5);
+  const onPageChange = (event: PaginatorPageChangeEvent) => {
+    setFirst(event.first);
+    setRows(event.rows);
+  };
+  // 获取帖子列表
+  useEffect(() => {
+    handleSearch();
+  }, [first, rows,searchValue]);
+
+  const handleSearch = async () => {
+    try {
+      const pageNumber = first / rows + 1;
+      console.log(searchValue + " 当前页: " + pageNumber + "rows: " + rows + "selectedClassify: " + selectedClassify + "selectedGameplay: " + selectedGameplay + "selectedVersions: " + selectedVersions);
+      const response = await axios.get<HotResourceList>(process.env.PUBLIC_URL + `/resource/search`, {
+        params: {
+          userId: 22301145,
+          pageNumber,
+          rows,
+          classify: selectedClassify,
+          gameplayList: selectedGameplay.join(','),
+          versionList: selectedVersions.join(','),
+          searchValue
+        }
+      });
+      setHotResources(response.data.records);
+      setTotalHotResource(response.data.total);
+      setVisibleRight(false);
+    } catch (err) {
+      console.error('搜索资源失败', err);
+      toast.current?.show({ severity: 'error', summary: 'error', detail: '搜索资源失败' });
+    }
+  };
+
+  return (
+    <div className="HotResource">
+      <div className="header">
+        <div className="searchBar">
+          <i className="pi pi-search" />
+          <InputText type="search" className="search-helper" placeholder="搜索你感兴趣的帖子" onChange={(e) => { const target = e.target as HTMLInputElement; debouncedSearch(target.value); }} />
+        </div>
+        <Button label="查看分类" className="classificationButton" onClick={() => setVisibleRight(true)} />
+      </div>
+      {/* 全部社区 */}
+      <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={process.env.NEXT_PUBLIC_NGINX_URL + "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.gameplayName} />
+                  ))}
+                </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>
+      {totalHotResource > 5 && (<Paginator className="Paginator" first={first} rows={rows} totalRecords={totalHotResource} rowsPerPageOptions={[5, 10]} onPageChange={onPageChange} />)}
+      <Sidebar className="sidebar" visible={visibleRight} position="right" onHide={() => setVisibleRight(false)}>
+        <div className="sidebar-content">
+          <h3>分类</h3>
+          <div className="filter-section">
+            {['模组', '地图', '整合包', '材质包'].map((item) => (
+              <Button key={item} label={item} className={selectedClassify === item ? 'p-button-primary' : 'p-button-text'} onClick={() => setSelectedClassify(item)} />
+            ))}
+          </div>
+
+          <h3>主要玩法</h3>
+          <div className="filter-section">
+            {['不限', '科技', '魔法', '建筑', '风景', '竞技', '生存', '冒险', '跑酷', '艺术', '剧情', '社交', '策略', '极限'].map((gameplay) => (
+              <Button
+                key={gameplay}
+                label={gameplay}
+                className={selectedGameplay.includes(gameplay) ? 'p-button-primary' : 'p-button-text'}
+                onClick={() => {
+                  if (selectedGameplay.includes(gameplay)) {
+                    setSelectedGameplay(selectedGameplay.filter((g) => g !== gameplay));
+                  } else {
+                    setSelectedGameplay([...selectedGameplay, gameplay]);
+                  }
+                }}
+              />
+            ))}
+          </div>
+
+          <h3>游戏版本</h3>
+          <div className="filter-section">
+            {['不限', '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) => (
+              <Button
+                key={ver}
+                label={ver}
+                className={selectedVersions.includes(ver) ? 'p-button-primary' : 'p-button-text'}
+                onClick={() => {
+                  if (selectedVersions.includes(ver)) {
+                    setSelectedVersions(selectedVersions.filter((v) => v !== ver));
+                  } else {
+                    setSelectedVersions([...selectedVersions, ver]);
+                  }
+                }}
+              />
+            ))}
+          </div>
+          <div className="filter-confirm">
+            <Button label="确定" icon="pi pi-check" onClick={handleSearch} />
+          </div>
+        </div>
+      </Sidebar>
+    </div>
+  );
+}