add classification page
Change-Id: I5f661291cd32416b23e9b3f4483f200e885141c5
diff --git a/src/app/globals.scss b/src/app/globals.scss
index a2f8cf4..d549826 100644
--- a/src/app/globals.scss
+++ b/src/app/globals.scss
@@ -117,19 +117,19 @@
//TabView组件样式
.p-tabview {
- background-color: #F0F4F7;
+ background-color: $background-color;
}
.p-tabview-panels {
- background-color: #F0F4F7;
+ background-color: $background-color;
}
.p-tabview-nav {
- background-color: #F0F4F7;
+ background-color: $background-color;
}
.p-tabview-nav-link {
- background-color: #F0F4F7;
+ background-color: $background-color;
}
//分页样式
@@ -137,7 +137,7 @@
display: flex;
justify-content: center;
align-items: center;
- background-color: #F0F4F7;
+ background-color: $background-color;
// 高亮状态的分页按钮
.p-highlight {
@@ -301,4 +301,101 @@
gap: 3rem;
padding: 1rem;
}
+}
+
+// 资源卡片列表
+.all-resources {
+ width: 100%;
+ padding: 1rem;
+
+ &-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ &-card {
+ height: 140px;
+ padding: 1.5rem;
+ margin-bottom: 1rem;
+ border-radius: 0.5rem;
+ transition: transform 0.3s ease;
+ box-shadow: none !important; // 取消阴影
+ cursor: pointer;
+
+ //填充卡片
+ &.p-card.p-component {
+ padding: 0;
+ }
+
+ .p-card-body {
+ padding: 0;
+ }
+
+ &:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ }
+
+ .p-card-content {
+ height: 140px;
+ display: flex;
+ justify-content: space-between;
+ padding: 0;
+ }
+
+ img {
+ border-radius: 0.5rem 0 0 0.5rem;
+ object-fit: cover;
+ }
+
+ .resource-header {
+ display: flex;
+ flex: 1;
+ max-width: 850px;
+ padding-left: 20px;
+ padding-right: 20px;
+ margin-bottom: 20px;
+ }
+
+ .resource-content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ h3 {
+ font-size: 1.5rem;
+ font-weight: bold;
+ color: #2c3e50;
+ }
+
+ .tags {
+ display: flex;
+ gap: 0.5rem;
+ }
+
+ .resource-introduction {
+ color: #666;
+ font-size: 1rem;
+ margin-bottom: 0;
+ }
+ }
+
+ .resources-states {
+ min-width: 120px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: flex-end;
+ gap: 0.5rem;
+
+ .state-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: #666;
+ font-size: 1rem;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git "a/src/app/resource/classification/\133resourceId\135/page.tsx" "b/src/app/resource/classification/\133resourceId\135/page.tsx"
deleted file mode 100644
index c48b626..0000000
--- "a/src/app/resource/classification/\133resourceId\135/page.tsx"
+++ /dev/null
@@ -1,12 +0,0 @@
-'use client';
-import React from 'react';
-
-const EmptyPage: React.FC = () => {
- return (
- <div className="p-d-flex p-jc-center p-ai-center" style={{ height: '100vh' }}>
- {"一个空页面"}
- </div>
- );
-};
-
-export default EmptyPage;
diff --git a/src/app/resource/classification/classification.scss b/src/app/resource/classification/classification.scss
new file mode 100644
index 0000000..f1cc964
--- /dev/null
+++ b/src/app/resource/classification/classification.scss
@@ -0,0 +1,59 @@
+.HotResource {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 2rem;
+}
+
+.searchBar {
+ max-width: 1000px;
+ padding: 0;
+ width: 85%;
+ height: 50px;
+
+ .search-helper {
+ height: 50px;
+ padding-left: 2.5rem;
+ border-radius: 10px 0px 0px 10px;
+ font-size: 1.1rem;
+ border: 1px solid #ddd;
+ }
+}
+
+.classificationButton {
+ height: 50px;
+ width: 15%;
+ border-radius: 0 10px 10px 0;
+}
+
+.header {
+ display: flex;
+ align-items: center;
+
+ flex-direction: row;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+}
+
+.sidebar {
+ width: 400px;
+}
+
+.sidebar-content {
+ width: 100%;
+}
+
+.filter-section {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-bottom: 1rem;
+}
+
+.filter-confirm {
+ margin-top: 10rem;
+ text-align: center;
+}
+
+.Paginator{
+ margin-bottom: 1rem;
+}
\ No newline at end of file
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>
+ );
+}
diff --git a/src/app/resource/hot-resource/hot-resource.scss b/src/app/resource/hot-resource/hot-resource.scss
index 587eb15..681a246 100644
--- a/src/app/resource/hot-resource/hot-resource.scss
+++ b/src/app/resource/hot-resource/hot-resource.scss
@@ -91,102 +91,4 @@
right: 0.6rem;
}
}
-}
-
-
-// 全部社区样式
-.all-resources {
- width: 100%;
- padding: 1rem;
-
- &-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
-
- &-card {
- height: 140px;
- padding: 1.5rem;
- margin-bottom: 1rem;
- border-radius: 0.5rem;
- transition: transform 0.3s ease;
- box-shadow: none !important; // 取消阴影
- cursor: pointer;
-
- //填充卡片
- &.p-card.p-component {
- padding: 0;
- }
-
- .p-card-body {
- padding: 0;
- }
-
- &:hover {
- transform: translateY(-3px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
- }
-
- .p-card-content {
- height: 140px;
- display: flex;
- justify-content: space-between;
- padding: 0;
- }
-
- img {
- border-radius: 0.5rem 0 0 0.5rem;
- object-fit: cover;
- }
-
- .resource-header {
- display: flex;
- flex: 1;
- max-width: 850px;
- padding-left: 20px;
- padding-right: 20px;
- margin-bottom: 20px;
- }
-
- .resource-content {
- flex: 1;
- display: flex;
- flex-direction: column;
-
- h3 {
- font-size: 1.5rem;
- font-weight: bold;
- color: #2c3e50;
- }
-
- .tags {
- display: flex;
- gap: 0.5rem;
- }
-
- .resource-introduction {
- color: #666;
- font-size: 1rem;
- margin-bottom: 0;
- }
- }
-
- .resources-states {
- min-width: 120px;
- display: flex;
- flex-direction: column;
- justify-content: flex-end;
- align-items: flex-end;
- gap: 0.5rem;
-
- .state-item {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- color: #666;
- font-size: 1rem;
- }
- }
- }
}
\ No newline at end of file
diff --git a/src/app/resource/hot-resource/page.tsx b/src/app/resource/hot-resource/page.tsx
index 022ebe3..3204d6a 100644
--- a/src/app/resource/hot-resource/page.tsx
+++ b/src/app/resource/hot-resource/page.tsx
@@ -160,7 +160,7 @@
min: 4,
max: 10,
ticks: {
- stepSize: 2, // ← 每 1 个单位显示一个刻度
+ stepSize: 2,
font: {
size: 12
}