| // search.tsx |
| import React, { useState, useEffect } from 'react'; |
| import styles from './search.module.css'; |
| import { useLocation } from "react-router-dom"; |
| |
| interface PostItem { |
| postId: number; |
| userId: number; |
| postTitle: string; |
| postContent: string; |
| createdAt: number; |
| postType: string; |
| viewCount: number; |
| hotScore: number; |
| lastCalculated: number; |
| tags?: number[]; |
| } |
| |
| const tagMap: Record<number, string> = { |
| 1: "搞笑", |
| 2: "悬疑", |
| 3: "教育", |
| 4: "动作", |
| 5: "剧情" |
| }; |
| |
| const SearchPage: React.FC = () => { |
| const [posts, setPosts] = useState<PostItem[]>([]); |
| const [filteredPosts, setFilteredPosts] = useState<PostItem[]>([]); |
| const [selectedPostType, setSelectedPostType] = useState<string>('all'); |
| const [selectedRating, setSelectedRating] = useState<number | null>(null); |
| const [selectedTags, setSelectedTags] = useState<number[]>([]); |
| |
| const location = useLocation(); |
| const params = new URLSearchParams(location.search); |
| const keyword = params.get("keyword"); |
| |
| useEffect(() => { |
| fetch('/api/posts') |
| .then((res) => res.json()) |
| .then((data) => { |
| setPosts(data); |
| setFilteredPosts(data); |
| }); |
| }, []); |
| |
| const applyFilters = () => { |
| let filtered = posts; |
| |
| if (selectedPostType !== 'all') { |
| filtered = filtered.filter((post) => post.postType === selectedPostType); |
| } |
| |
| if (selectedRating !== null) { |
| filtered = filtered.filter((post) => post.hotScore >= selectedRating); |
| } |
| |
| if (selectedTags.length > 0) { |
| filtered = filtered.filter((post) => |
| post.tags?.some((tag) => selectedTags.includes(tag)) |
| ); |
| } |
| |
| setFilteredPosts(filtered); |
| }; |
| |
| return ( |
| <div className={styles.secondaryHeader}> |
| <div className={styles.leftSection}> |
| <select |
| value={selectedPostType} |
| onChange={(e) => setSelectedPostType(e.target.value)} |
| className={styles.selectBox} |
| > |
| <option value="all">所有分区</option> |
| <option value="影视">影视</option> |
| <option value="音乐">音乐</option> |
| <option value="游戏">游戏</option> |
| <option value="软件">软件</option> |
| </select> |
| |
| <select |
| value={selectedRating || ''} |
| onChange={(e) => |
| setSelectedRating(e.target.value ? Number(e.target.value) : null) |
| } |
| className={styles.selectBox} |
| > |
| <option value="">所有评分</option> |
| <option value="1">1星及以上</option> |
| <option value="2">2星及以上</option> |
| <option value="3">3星及以上</option> |
| <option value="4">4星及以上</option> |
| <option value="5">5星</option> |
| </select> |
| </div> |
| |
| <div className={styles.centerSection}> |
| <div className={styles.tagFilters}> |
| {Object.entries(tagMap).map(([tagId, tagName]) => ( |
| <label key={tagId}> |
| <input |
| type="checkbox" |
| value={tagId} |
| checked={selectedTags.includes(Number(tagId))} |
| onChange={(e) => { |
| const value = Number(e.target.value); |
| setSelectedTags((prev) => |
| prev.includes(value) |
| ? prev.filter((t) => t !== value) |
| : [...prev, value] |
| ); |
| }} |
| /> |
| {tagName} |
| </label> |
| ))} |
| </div> |
| </div> |
| |
| <div className={styles.rightSection}> |
| <button className={styles.filterButton} onClick={applyFilters}> |
| 筛选 |
| </button> |
| </div> |
| </div> |
| |
| ); |
| }; |
| |
| export default SearchPage; |