Merge "修改前端页面样式,工作进度:80%"
diff --git a/front/src/AnimePage.js b/front/src/AnimePage.js
index 03ad8b2..47ae5e2 100644
--- a/front/src/AnimePage.js
+++ b/front/src/AnimePage.js
@@ -1,38 +1,40 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
+import "./SharedStyles.css";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 动漫地区标签
const areaTabs = [
- { label: "国创", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "日漫", icon: <EmailIcon fontSize="small" /> },
- { label: "欧美动漫", icon: <PersonIcon fontSize="small" /> },
- { label: "韩漫", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "国创动漫", value: "chinese" },
+ { label: "日系动漫", value: "japanese" },
+ { label: "欧美动漫", value: "western" },
+ { label: "韩系动漫", value: "korean" },
+ { label: "其他动漫", value: "others" }
];
export default function AnimePage() {
@@ -60,18 +62,8 @@
})
.catch(err => console.error('Fetching user profile failed', err));
}, []);
-
- // 每个tab对应的动漫类型
- const animeTypesList = [
- ["华语动漫(大陆)", "欧美动漫", "日韩动漫", "港台动漫", "其他"], // 国创
- ["日漫热血", "日漫搞笑", "日漫其他"], // 日漫
- ["欧美冒险", "欧美科幻", "欧美其他"], // 欧美动漫
- ["韩漫爱情", "韩漫奇幻", "韩漫其他"], // 韩漫
- ["其他类型1", "其他类型2"] // 其他
- ];
- const animeTypes = animeTypesList[activeTab] || [];
-
useEffect(() => {
+ // 根据选中的标签获取动漫列表
const area = areaTabs[activeTab].label;
fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
.then(res => res.json())
@@ -85,128 +77,221 @@
fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
.then(res => res.json())
.then(data => {
+ console.log('搜索返回数据:', data);
setAnimeList(data);
})
.catch(() => setAnimeList([]));
};
+ const animeTypesList = [
+ ["华语动漫", "国产3D", "国产2D", "华语其他"], // 国创动漫
+ ["日漫热血", "日漫治愈", "日漫搞笑", "日漫其他"], // 日系动漫
+ ["欧美冒险", "欧美科幻", "欧美喜剧", "欧美其他"], // 欧美动漫
+ ["韩漫爱情", "韩漫奇幻", "韩漫其他"], // 韩系动漫
+ ["独立动画", "短篇动画", "其他类型"] // 其他动漫
+ ];
+ const animeTypes = animeTypesList[activeTab] || [];
return (
- <div className="container">
- {/* 顶部空白与动漫界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与动漫界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "动漫" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
</div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="anime-table">
- <thead>
- <tr>
- <th>动漫类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {animeList.length > 0 ? (
- animeList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
) : (
- animeTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
)}
- </tbody>
- </table>
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "动漫" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 动漫内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">🎌 动漫资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux动漫频道,这里有最新最热门的动漫资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索动漫资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div>
+
+ {/* 地区分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 动漫列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>动漫类型</th>
+ <th>标题</th>
+ <th>发布者</th>
+ <th>大小</th>
+ <th>热度</th>
+ <th>折扣倍率</th>
+ </tr>
+ </thead>
+ <tbody>
+ {animeList.length > 0 ? (
+ animeList.map((item, index) => (
+ <tr key={item.id || index}>
+ <td>{item.seedtag}</td>
+ <td>
+ <a href={`/torrent/${item.seedid}`}>
+ {item.title}
+ </a>
+ </td>
+ <td>{item.username}</td>
+ <td>{item.seedsize}</td>
+ <td>{item.downloadtimes}</td>
+ <td>{item.discount == null ? 1 : item.discount}</td>
+ </tr>
+ ))
+ ) : (
+ animeTypes.map((type, index) => (
+ <tr key={type}>
+ <td>{type}</td>
+ <td>
+ <a href={`/torrent/${type}`}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ <td>--</td>
+ <td>--</td>
+ <td>1</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div>
- <div style={{ height: 32 }} />
- <Pagination />
</div>
);
}
+// Pagination组件暂时不使用
function Pagination() {
const [page, setPage] = React.useState(3);
const total = 5;
diff --git a/front/src/ForumPage.js b/front/src/ForumPage.js
index 7939da1..bf75671 100644
--- a/front/src/ForumPage.js
+++ b/front/src/ForumPage.js
@@ -1,43 +1,69 @@
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
+import HomeIcon from "@mui/icons-material/Home";
+import MovieIcon from "@mui/icons-material/Movie";
+import TvIcon from "@mui/icons-material/Tv";
+import MusicNoteIcon from "@mui/icons-material/MusicNote";
+import AnimationIcon from "@mui/icons-material/Animation";
+import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
+import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
+import PersonIcon from "@mui/icons-material/Person";
+import AccountCircleIcon from "@mui/icons-material/AccountCircle";
+import ForumIcon from "@mui/icons-material/Forum";
+import HelpIcon from "@mui/icons-material/Help";
+import SearchIcon from "@mui/icons-material/Search";
+import PostAddIcon from "@mui/icons-material/PostAdd";
+import "./SharedStyles.css";
-// 示例数据
-const posts = [
- {
- post_id: "1",
- title: "欢迎来到G10论坛",
- content: "这里是G10 PT站的官方论坛,欢迎大家发帖交流!",
- author_id: "u1",
- author_name: "Alice",
- created_at: "2024-06-01 12:00",
- reply_count: 3,
- view_count: 120,
- },
- {
- post_id: "2",
- title: "经典电影合集",
- content: "90年代经典电影大家有什么推荐吗?",
- author_id: "u2",
- author_name: "Bob",
- created_at: "2024-06-02 09:30",
- reply_count: 1,
- view_count: 45,
- },
+const navItems = [
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
+];
+
+// 论坛文字雨内容
+const forumTexts = [
+ "讨论", "交流", "分享", "观点", "话题", "回复", "发帖", "社区",
+ "对话", "互动", "评论", "建议", "意见", "经验", "心得", "推荐",
+ "新手", "老鸟", "攻略", "指南", "教程", "资源", "福利", "活动"
];
export default function ForumPage() {
const navigate = useNavigate();
const [posts, setPosts] = useState([]);
const [searchQuery, setSearchQuery] = useState('');
+ const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
+ const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
useEffect(() => {
- // get userId from cookie
+ // 获取用户信息
const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
const userId = match ? match[2] : null;
- console.log("User ID from cookie:", userId);
- // if (!userId) return;
- console.log("Fetching forum posts...");
+ if (userId) {
+ fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
+ .then(res => res.json())
+ .then(data => {
+ setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
+ setUserPT({
+ magic: data.magic_value || data.magic || 0,
+ ratio: data.share_ratio || data.share || 0,
+ upload: data.upload_amount || data.upload || 0,
+ download: data.download_amount || data.download || 0,
+ });
+ })
+ .catch(err => console.error('Fetching user profile failed', err));
+ }
+
+ // 获取论坛帖子
fetch(`${API_BASE_URL}/api/forum`)
.then(res => {
// console.log("fetch raw response:", res);
@@ -81,68 +107,157 @@
};
return (
- <div style={{ maxWidth: 700, margin: "40px auto" }}>
- <div style={{ display: "flex", alignItems: "center", marginBottom: 24 }}>
- <h2 style={{ color: "#1a237e", margin: 0, marginRight: 24 }}>G10 论坛</h2>
- <input
- type="text"
- placeholder="搜索帖子内容"
- value={searchQuery}
- onChange={e => setSearchQuery(e.target.value)}
- style={{
- flex: 1,
- fontSize: 16,
- padding: "8px 14px",
- border: "1px solid #bfcfff",
- borderRadius: 8,
- outline: "none",
- minWidth: 0,
- }}
- />
- <button
- style={{
- marginLeft: 8,
- fontSize: 16,
- padding: "8px 18px",
- border: "1px solid #bfcfff",
- background: "#e0e7ff",
- borderRadius: 8,
- cursor: "pointer",
- }}
- onClick={handleSearch}
- >
- 🔍
- </button>
+ <div className="emerald-home-container">
+ {/* 文字雨背景效果 */}
+ <div className="forum-text-rain">
+ {forumTexts.map((text, index) => (
+ <div key={index} className="text-drop" style={{
+ left: `${(index * 3.5) % 100}%`,
+ animationDelay: `${(index * 0.8) % 10}s`,
+ animationDuration: `${8 + (index % 5)}s`
+ }}>
+ {text}
+ </div>
+ ))}
</div>
- {posts.map(post => (
- <div
- key={post.post_id}
- style={{
- background: "#fff",
- borderRadius: 12,
- boxShadow: "0 2px 8px #e0e7ff",
- padding: 24,
- marginBottom: 24,
- cursor: "pointer",
- transition: "box-shadow 0.2s",
- }}
- onClick={() => navigate(`/forum/${post.post_id}`)}
- >
- <div style={{ fontSize: 15, color: "#1976d2", marginBottom: 6 }}>
- {post.author_name} · {post.created_at}
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">💬</div>
+ <div className="garden-element">📝</div>
+ <div className="garden-element">🗨️</div>
+ <div className="garden-element">✍️</div>
+ </div>
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
+ ) : (
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
+ )}
</div>
- <div style={{ fontWeight: 600, fontSize: 20, marginBottom: 8, color: "#222" }}>
- {post.title}
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
</div>
- <div style={{ fontSize: 16, color: "#444", marginBottom: 18 }}>
- {post.content}
- </div>
- <div style={{ display: "flex", justifyContent: "flex-start", gap: 32, fontSize: 14, color: "#888" }}>
- <span>回复数: {post.reply_count}</span>
- <span>观看数: {post.view_count}</span>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
</div>
</div>
- ))}
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "论坛" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 论坛内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">💬 NeuraFlux论坛</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux社区论坛,这里是知识与思想的碰撞之地
+ </p>
+
+ {/* 论坛工具栏 */}
+ <div className="forum-toolbar">
+ <div className="search-section">
+ <div className="search-input-container">
+ <SearchIcon className="search-icon" />
+ <input
+ type="text"
+ placeholder="搜索论坛话题..."
+ value={searchQuery}
+ onChange={(e) => setSearchQuery(e.target.value)}
+ className="forum-search-input"
+ />
+ </div>
+ <button onClick={handleSearch} className="forum-search-btn">
+ 搜索
+ </button>
+ </div>
+ <button className="new-post-btn" onClick={() => navigate('/publish')}>
+ <PostAddIcon style={{ marginRight: '8px' }} />
+ 发布新话题
+ </button>
+ </div>
+
+ {/* 帖子列表 */}
+ <div className="forum-posts-container">
+ {posts.length > 0 ? (
+ posts.map((post) => (
+ <div
+ key={post.post_id}
+ className="forum-post-card"
+ onClick={() => navigate(`/forum/${post.post_id}`)}
+ >
+ <div className="post-header">
+ <div className="post-author-info">
+ <div className="author-avatar">
+ <AccountCircleIcon style={{ fontSize: 28, color: '#2d5016' }} />
+ </div>
+ <div className="author-details">
+ <span className="author-name">{post.author_name}</span>
+ <span className="post-time">{post.created_at}</span>
+ </div>
+ </div>
+ <div className="post-stats">
+ <span className="stat-item">👁 {post.view_count}</span>
+ <span className="stat-item">💬 {post.reply_count}</span>
+ </div>
+ </div>
+
+ <div className="post-content">
+ <h3 className="post-title">{post.title}</h3>
+ <p className="post-preview">{post.content}</p>
+ </div>
+
+ <div className="post-footer">
+ <div className="post-tags">
+ <span className="post-tag">讨论</span>
+ </div>
+ <div className="post-actions">
+ <span className="action-btn">查看详情 →</span>
+ </div>
+ </div>
+ </div>
+ ))
+ ) : (
+ <div className="empty-state">
+ <ForumIcon style={{ fontSize: 64, color: '#90ee90', marginBottom: '16px' }} />
+ <h3 style={{ color: '#2d5016', marginBottom: '8px' }}>暂无帖子</h3>
+ <p style={{ color: '#666', marginBottom: '20px' }}>快来发布第一个话题吧!</p>
+ <button className="new-post-btn" onClick={() => navigate('/publish')}>
+ <PostAddIcon style={{ marginRight: '8px' }} />
+ 发布话题
+ </button>
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
</div>
);
}
\ No newline at end of file
diff --git a/front/src/GamePage.js b/front/src/GamePage.js
index cae28cd..4a12636 100644
--- a/front/src/GamePage.js
+++ b/front/src/GamePage.js
@@ -1,51 +1,41 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
+import "./SharedStyles.css";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 游戏平台标签
const areaTabs = [
- { label: "PC", icon: <MovieIcon fontSize="small" /> },
- { label: "主机", icon: <EmailIcon fontSize="small" /> },
- { label: "移动", icon: <PersonIcon fontSize="small" /> },
- { label: "掌机", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "视频", icon: <PersonIcon fontSize="small" /> },
+ { label: "PC游戏", value: "pc" },
+ { label: "主机游戏", value: "console" },
+ { label: "移动游戏", value: "mobile" },
+ { label: "掌机游戏", value: "handheld" },
+ { label: "游戏视频", value: "video" }
];
-
-// 每个tab对应的游戏类型
-const gameTypesList = [
- ["PC单机", "PC网络", "PC独立", "PC其他"], // PC
- ["主机动作", "主机RPG", "主机其他"], // 主机
- ["移动休闲", "移动竞技", "移动其他"], // 移动
- ["掌机冒险", "掌机其他"], // 掌机
- ["游戏视频", "赛事视频", "其他视频"], // 视频
- ["其他类型1", "其他类型2"] // 其他
-];
-
export default function GamePage() {
const navigate = useNavigate();
const [searchText, setSearchText] = useState('');
@@ -72,9 +62,8 @@
.catch(err => console.error('Fetching user profile failed', err));
}, []);
- const gameTypes = gameTypesList[activeTab] || [];
-
useEffect(() => {
+ // 根据选中的标签获取游戏列表
const area = areaTabs[activeTab].label;
fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
.then(res => res.json())
@@ -88,128 +77,221 @@
fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
.then(res => res.json())
.then(data => {
+ console.log('搜索返回数据:', data);
setGameList(data);
})
.catch(() => setGameList([]));
};
+ const gameTypesList = [
+ ["PC单机", "PC网络", "PC独立", "PC其他"], // PC游戏
+ ["主机动作", "主机RPG", "主机竞速", "主机其他"], // 主机游戏
+ ["移动休闲", "移动竞技", "移动策略", "移动其他"], // 移动游戏
+ ["掌机冒险", "掌机RPG", "掌机其他"], // 掌机游戏
+ ["游戏实况", "赛事视频", "攻略教学", "其他视频"] // 游戏视频
+ ];
+ const gameTypes = gameTypesList[activeTab] || [];
return (
- <div className="container">
- {/* 顶部空白与游戏界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与游戏界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "游戏" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
</div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="game-table">
- <thead>
- <tr>
- <th>游戏类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {gameList.length > 0 ? (
- gameList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
) : (
- gameTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
)}
- </tbody>
- </table>
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "游戏" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 游戏内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">🎮 游戏资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux游戏频道,这里有最新最热门的游戏资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索游戏资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div>
+
+ {/* 平台分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 游戏列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>游戏类型</th>
+ <th>标题</th>
+ <th>发布者</th>
+ <th>大小</th>
+ <th>热度</th>
+ <th>折扣倍率</th>
+ </tr>
+ </thead>
+ <tbody>
+ {gameList.length > 0 ? (
+ gameList.map((item, index) => (
+ <tr key={item.id || index}>
+ <td>{item.seedtag}</td>
+ <td>
+ <a href={`/torrent/${item.seedid}`}>
+ {item.title}
+ </a>
+ </td>
+ <td>{item.username}</td>
+ <td>{item.seedsize}</td>
+ <td>{item.downloadtimes}</td>
+ <td>{item.discount == null ? 1 : item.discount}</td>
+ </tr>
+ ))
+ ) : (
+ gameTypes.map((type, index) => (
+ <tr key={type}>
+ <td>{type}</td>
+ <td>
+ <a href={`/torrent/${type}`}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ <td>--</td>
+ <td>--</td>
+ <td>1</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div>
- <div style={{ height: 32 }} />
- <Pagination />
</div>
);
}
+// Pagination组件暂时不使用
function Pagination() {
const [page, setPage] = React.useState(3);
const total = 5;
diff --git a/front/src/HomePage.css b/front/src/HomePage.css
new file mode 100644
index 0000000..4423000
--- /dev/null
+++ b/front/src/HomePage.css
@@ -0,0 +1,133 @@
+/* HomePage 特定样式 */
+@import './SharedStyles.css';
+
+/* 表格区域样式 */
+.emerald-table-section {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border-radius: 25px;
+ padding: 30px;
+ margin: 30px auto;
+ box-shadow:
+ 0 20px 60px rgba(45, 80, 22, 0.12),
+ 0 8px 25px rgba(144, 238, 144, 0.08),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ position: relative;
+ overflow: hidden;
+}
+
+.emerald-table-section::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 27px;
+ z-index: -1;
+ animation: borderGlow 4s ease-in-out infinite;
+}
+
+/* 表格样式 */
+.emerald-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-family: 'Lora', serif;
+ background: transparent;
+}
+
+.emerald-table thead {
+ background: linear-gradient(135deg, #2d5016 0%, #4a7c59 100%);
+}
+
+.emerald-table th {
+ padding: 16px 20px;
+ text-align: left;
+ color: white;
+ font-weight: 600;
+ font-size: 16px;
+ letter-spacing: 1px;
+ border-bottom: 3px solid #90ee90;
+ position: relative;
+}
+
+.emerald-table th:first-child {
+ border-radius: 15px 0 0 0;
+}
+
+.emerald-table th:last-child {
+ border-radius: 0 15px 0 0;
+}
+
+.emerald-table tbody tr {
+ transition: all 0.3s ease;
+ border-bottom: 1px solid rgba(144, 238, 144, 0.2);
+}
+
+.emerald-table tbody tr:hover {
+ background: rgba(144, 238, 144, 0.1);
+ transform: translateX(5px);
+ box-shadow: 0 4px 15px rgba(144, 238, 144, 0.15);
+}
+
+.emerald-table td {
+ padding: 14px 20px;
+ color: #2d5016;
+ font-size: 15px;
+ vertical-align: middle;
+ transition: all 0.3s ease;
+}
+
+.emerald-table tbody tr:hover td {
+ color: #1a5c1a;
+}
+
+/* 表格链接样式 */
+.emerald-table a {
+ color: #2d5016;
+ text-decoration: none;
+ font-weight: 500;
+ transition: all 0.3s ease;
+ padding: 4px 8px;
+ border-radius: 8px;
+ display: inline-block;
+}
+
+.emerald-table a:hover {
+ color: #1a5c1a;
+ background: rgba(144, 238, 144, 0.2);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(144, 238, 144, 0.3);
+}
+
+/* 响应式表格设计 */
+@media (max-width: 768px) {
+ .emerald-table-section {
+ margin: 20px 10px;
+ padding: 20px 15px;
+ }
+
+ .emerald-table {
+ font-size: 14px;
+ }
+
+ .emerald-table th,
+ .emerald-table td {
+ padding: 12px 15px;
+ }
+}
+
+@media (max-width: 480px) {
+ .emerald-table th,
+ .emerald-table td {
+ padding: 10px 12px;
+ font-size: 13px;
+ }
+}
diff --git a/front/src/HomePage.js b/front/src/HomePage.js
index a657a72..026f122 100644
--- a/front/src/HomePage.js
+++ b/front/src/HomePage.js
@@ -1,9 +1,9 @@
import React from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
@@ -11,21 +11,21 @@
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
import { useNavigate } from "react-router-dom";
-import "./App.css";
+import "./HomePage.css";
// 导航栏
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
// 示例种子数据
@@ -64,63 +64,98 @@
const navigate = useNavigate();
return (
- <div className="container">
- {/* 顶部空白与电影界面一致 */}
- <div style={{ height: 80 }} />
- {/* 用户栏 */}
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>用户栏</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>12345</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>2.56</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>100GB</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>50GB</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与电影界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "首页" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
+ </div>
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
</div>
- ))}
- </nav>
- <div className="table-section card">
- <table className="movie-table">
- <thead>
- <tr>
- <th>标签</th>
- <th>标题</th>
- <th>热度</th>
- <th>发布者</th>
- </tr>
- </thead>
- <tbody>
- {exampleSeeds.map((seed) => (
- <tr key={seed.id}>
- <td>{seed.tags}</td>
- <td>
- <a href={`/torrent/${seed.id}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {seed.title}
- </a>
- </td>
- <td>{seed.popularity}</td>
- <td>{seed.user.username}</td>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">12,345</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">2.56</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">100GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">50GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "首页" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* NeuraFlux种子列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>分类标签</th>
+ <th>资源标题</th>
+ <th>热门指数</th>
+ <th>发布者</th>
</tr>
- ))}
- </tbody>
- </table>
+ </thead>
+ <tbody>
+ {exampleSeeds.map((seed) => (
+ <tr key={seed.id}>
+ <td>{seed.tags}</td>
+ <td>
+ <a href={`/torrent/${seed.id}`}>
+ {seed.title}
+ </a>
+ </td>
+ <td>{seed.popularity}</td>
+ <td>{seed.user.username}</td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
</div>
- <div style={{ height: 32 }} />
</div>
);
}
\ No newline at end of file
diff --git a/front/src/InfoPage.js b/front/src/InfoPage.js
index cec0b4d..1164816 100644
--- a/front/src/InfoPage.js
+++ b/front/src/InfoPage.js
@@ -1,39 +1,40 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
+import "./SharedStyles.css";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 资料地区标签
const areaTabs = [
- { label: "出版物", icon: <MovieIcon fontSize="small" /> },
- { label: "学习教程", icon: <EmailIcon fontSize="small" /> },
- { label: "素材模板", icon: <PersonIcon fontSize="small" /> },
- { label: "演讲交流", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "日常娱乐", icon: <PersonIcon fontSize="small" /> },
+ { label: "出版物", value: "publication" },
+ { label: "学习教程", value: "tutorial" },
+ { label: "素材模板", value: "template" },
+ { label: "演讲交流", value: "speech" },
+ { label: "日常娱乐", value: "entertainment" }
];
export default function InfoPage() {
@@ -93,126 +94,209 @@
})
.catch(() => setInfoList([]));
};
-
return (
- <div className="container">
- {/* 顶部空白与资料界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与资料界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "资料" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
</div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="info-table">
- <thead>
- <tr>
- <th>资料类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {infoList.length > 0 ? (
- infoList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
) : (
- infoTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
)}
- </tbody>
- </table>
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "资料" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 资料内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">📚 资料资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux资料频道,这里有最新最热门的学习和资料资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索资料资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div>
+
+ {/* 地区分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 资料列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>资料类型</th>
+ <th>标题</th>
+ <th>发布者</th>
+ <th>大小</th>
+ <th>热度</th>
+ <th>折扣倍率</th>
+ </tr>
+ </thead>
+ <tbody>
+ {infoList.length > 0 ? (
+ infoList.map((item, index) => (
+ <tr key={item.id || index}>
+ <td>{item.seedtag}</td>
+ <td>
+ <a href={`/torrent/${item.seedid}`}>
+ {item.title}
+ </a>
+ </td>
+ <td>{item.username}</td>
+ <td>{item.seedsize}</td>
+ <td>{item.downloadtimes}</td>
+ <td>{item.discount == null ? 1 : item.discount}</td>
+ </tr>
+ ))
+ ) : (
+ infoTypes.map((type, index) => (
+ <tr key={type}>
+ <td>{type}</td>
+ <td>
+ <a href={`/torrent/${type}`}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ <td>--</td>
+ <td>--</td>
+ <td>1</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div>
- <div style={{ height: 32 }} />
- <Pagination />
</div>
);
}
+// Pagination组件暂时不使用
function Pagination() {
- const [page, setPage] = React.useState(3);
+ const [page, setPage] = useState(3);
const total = 5;
return (
<div className="pagination">
diff --git a/front/src/LoginPage.css b/front/src/LoginPage.css
new file mode 100644
index 0000000..ced4dae
--- /dev/null
+++ b/front/src/LoginPage.css
@@ -0,0 +1,467 @@
+/* 翡翠庄园 - 欧式园林风格登录页面样式 */
+
+/* 引入Google字体 */
+@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Lora:wght@400;500;600&display=swap');
+
+/* 页面基础样式 */
+.garden-login-page {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #2d5016 0%, #4a7c59 20%, #8fbc8f 40%, #98fb98 60%, #f0fff0 100%);
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+ font-family: 'Lora', serif;
+}
+
+/* 背景装饰元素 */
+.garden-login-page::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background:
+ radial-gradient(circle at 20% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
+ radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.08) 0%, transparent 50%),
+ radial-gradient(circle at 40% 40%, rgba(144, 238, 144, 0.1) 0%, transparent 50%);
+ animation: backgroundShift 20s ease-in-out infinite;
+}
+
+/* 浮动花瓣动画 */
+.floating-petals {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ overflow: hidden;
+}
+
+.petal {
+ position: absolute;
+ font-size: 20px;
+ animation: fall linear infinite;
+ opacity: 0.7;
+}
+
+.petal:nth-child(1) { left: 10%; animation-duration: 8s; animation-delay: 0s; }
+.petal:nth-child(2) { left: 20%; animation-duration: 12s; animation-delay: 2s; }
+.petal:nth-child(3) { left: 30%; animation-duration: 10s; animation-delay: 4s; }
+.petal:nth-child(4) { left: 40%; animation-duration: 14s; animation-delay: 1s; }
+.petal:nth-child(5) { left: 50%; animation-duration: 9s; animation-delay: 3s; }
+.petal:nth-child(6) { left: 60%; animation-duration: 11s; animation-delay: 5s; }
+.petal:nth-child(7) { left: 70%; animation-duration: 13s; animation-delay: 0.5s; }
+.petal:nth-child(8) { left: 80%; animation-duration: 15s; animation-delay: 2.5s; }
+
+/* 登录表单容器 */
+.garden-login-container {
+ width: 420px;
+ padding: 50px 40px 60px;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border-radius: 25px;
+ box-shadow:
+ 0 20px 60px rgba(0, 0, 0, 0.15),
+ 0 8px 25px rgba(45, 80, 22, 0.1),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+ position: relative;
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ animation: containerFloat 6s ease-in-out infinite;
+}
+
+/* 装饰边框 */
+.garden-login-container::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 27px;
+ z-index: -1;
+ animation: borderGlow 4s ease-in-out infinite;
+}
+
+/* 顶部装饰图标 */
+.garden-icon {
+ text-align: center;
+ margin-bottom: 30px;
+ font-size: 48px;
+ animation: iconPulse 3s ease-in-out infinite;
+}
+
+/* 标题样式 */
+.garden-title {
+ text-align: center;
+ margin-bottom: 40px;
+ color: #2d5016;
+ font-family: 'Playfair Display', serif;
+ font-weight: 700;
+ font-size: 36px;
+ letter-spacing: 3px;
+ text-shadow: 0 2px 4px rgba(45, 80, 22, 0.1);
+ position: relative;
+}
+
+.garden-title::after {
+ content: '';
+ position: absolute;
+ bottom: -10px;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 80px;
+ height: 3px;
+ background: linear-gradient(90deg, #90ee90, #2d5016, #90ee90);
+ border-radius: 2px;
+}
+
+/* 表单组样式 */
+.garden-form-group {
+ margin-bottom: 28px;
+ position: relative;
+}
+
+.garden-label {
+ display: block;
+ margin-bottom: 10px;
+ color: #2d5016;
+ font-weight: 600;
+ font-size: 16px;
+ letter-spacing: 1px;
+ transition: color 0.3s ease;
+}
+
+.garden-input {
+ width: 100%;
+ padding: 16px 20px;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ border-radius: 15px;
+ font-size: 16px;
+ font-family: 'Lora', serif;
+ background: rgba(240, 255, 240, 0.5);
+ transition: all 0.3s ease;
+ outline: none;
+ box-sizing: border-box;
+}
+
+.garden-input:focus {
+ border-color: #90ee90;
+ background: rgba(240, 255, 240, 0.8);
+ box-shadow:
+ 0 0 0 4px rgba(144, 238, 144, 0.1),
+ 0 8px 25px rgba(144, 238, 144, 0.15);
+ transform: translateY(-2px);
+}
+
+.garden-input::placeholder {
+ color: #8fbc8f;
+ font-style: italic;
+}
+
+/* 输入框图标 */
+.garden-input-icon {
+ position: absolute;
+ right: 15px;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 18px;
+ color: #8fbc8f;
+ transition: all 0.3s ease;
+}
+
+.garden-form-group:focus-within .garden-input-icon {
+ color: #2d5016;
+ animation: iconBounce 0.5s ease;
+}
+
+/* 错误信息样式 */
+.garden-error {
+ color: #dc3545;
+ text-align: center;
+ margin-bottom: 20px;
+ font-weight: 500;
+ font-size: 14px;
+ padding: 10px;
+ background: rgba(220, 53, 69, 0.1);
+ border-radius: 10px;
+ border-left: 4px solid #dc3545;
+ animation: errorShake 0.5s ease;
+}
+
+/* 按钮容器 */
+.garden-button-group {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ margin-top: 35px;
+ align-items: center;
+}
+
+/* 按钮基础样式 */
+.garden-button {
+ width: 160px;
+ padding: 14px 0;
+ border: none;
+ border-radius: 25px;
+ font-family: 'Lora', serif;
+ font-weight: 600;
+ font-size: 16px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+ letter-spacing: 1px;
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
+}
+
+.garden-button::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
+ transition: left 0.6s ease;
+}
+
+.garden-button:hover::before {
+ left: 100%;
+}
+
+/* 登录按钮 */
+.garden-login-btn {
+ background: linear-gradient(135deg, #2d5016 0%, #4a7c59 50%, #90ee90 100%);
+ color: white;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
+}
+
+.garden-login-btn:hover {
+ transform: translateY(-3px);
+ box-shadow:
+ 0 10px 30px rgba(45, 80, 22, 0.3),
+ 0 4px 15px rgba(144, 238, 144, 0.2);
+}
+
+.garden-login-btn:active {
+ transform: translateY(-1px);
+}
+
+/* 注册按钮 */
+.garden-register-btn {
+ background: linear-gradient(135deg, #f0fff0 0%, #98fb98 50%, #90ee90 100%);
+ color: #2d5016;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+}
+
+.garden-register-btn:hover {
+ transform: translateY(-3px);
+ background: linear-gradient(135deg, #98fb98 0%, #90ee90 50%, #2d5016 100%);
+ color: white;
+ box-shadow:
+ 0 10px 30px rgba(144, 238, 144, 0.3),
+ 0 4px 15px rgba(45, 80, 22, 0.2);
+}
+
+/* 装饰性元素 */
+.garden-decoration {
+ position: absolute;
+ font-size: 24px;
+ opacity: 0.3;
+ animation: decorationFloat 4s ease-in-out infinite;
+}
+
+.garden-decoration.top-left {
+ top: 20px;
+ left: 20px;
+ animation-delay: 0s;
+}
+
+.garden-decoration.top-right {
+ top: 20px;
+ right: 20px;
+ animation-delay: 1s;
+}
+
+.garden-decoration.bottom-left {
+ bottom: 20px;
+ left: 20px;
+ animation-delay: 2s;
+}
+
+.garden-decoration.bottom-right {
+ bottom: 20px;
+ right: 20px;
+ animation-delay: 3s;
+}
+
+/* 动画定义 */
+@keyframes backgroundShift {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.8; }
+}
+
+@keyframes fall {
+ 0% {
+ transform: translateY(-100vh) rotate(0deg);
+ opacity: 0;
+ }
+ 10% {
+ opacity: 0.7;
+ }
+ 90% {
+ opacity: 0.7;
+ }
+ 100% {
+ transform: translateY(100vh) rotate(360deg);
+ opacity: 0;
+ }
+}
+
+@keyframes containerFloat {
+ 0%, 100% {
+ transform: translateY(0px);
+ }
+ 50% {
+ transform: translateY(-10px);
+ }
+}
+
+@keyframes borderGlow {
+ 0%, 100% {
+ opacity: 0.6;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes iconPulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.1);
+ }
+}
+
+@keyframes iconBounce {
+ 0%, 100% {
+ transform: translateY(-50%) scale(1);
+ }
+ 50% {
+ transform: translateY(-50%) scale(1.2);
+ }
+}
+
+@keyframes errorShake {
+ 0%, 100% { transform: translateX(0); }
+ 25% { transform: translateX(-5px); }
+ 75% { transform: translateX(5px); }
+}
+
+@keyframes decorationFloat {
+ 0%, 100% {
+ transform: translateY(0px) rotate(0deg);
+ }
+ 33% {
+ transform: translateY(-10px) rotate(120deg);
+ }
+ 66% {
+ transform: translateY(-5px) rotate(240deg);
+ }
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+ .garden-login-container {
+ width: 90%;
+ max-width: 380px;
+ padding: 40px 30px 50px;
+ }
+
+ .garden-title {
+ font-size: 28px;
+ letter-spacing: 2px;
+ }
+
+ .petal {
+ font-size: 16px;
+ }
+}
+
+@media (max-width: 480px) {
+ .garden-login-container {
+ padding: 30px 20px 40px;
+ }
+
+ .garden-title {
+ font-size: 24px;
+ letter-spacing: 1px;
+ }
+
+ .garden-button {
+ width: 140px;
+ padding: 12px 0;
+ font-size: 14px;
+ }
+}
+
+/* 加载动画 */
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.garden-login-container {
+ animation: fadeInUp 0.8s ease-out;
+}
+
+/* 键盘导航优化 */
+.garden-button:focus,
+.garden-input:focus {
+ outline: 3px solid rgba(144, 238, 144, 0.5);
+ outline-offset: 2px;
+}
+
+/* 深色模式支持 */
+@media (prefers-color-scheme: dark) {
+ .garden-login-page {
+ background: linear-gradient(135deg, #1a2f0a 0%, #2d5016 20%, #4a7c59 40%, #5a8a5a 60%, #6b9b6b 100%);
+ }
+
+ .garden-login-container {
+ background: rgba(30, 40, 20, 0.95);
+ color: #e0e7ff;
+ }
+
+ .garden-title {
+ color: #90ee90;
+ }
+
+ .garden-label {
+ color: #98fb98;
+ }
+
+ .garden-input {
+ background: rgba(45, 80, 22, 0.3);
+ color: #f0fff0;
+ border-color: rgba(144, 238, 144, 0.4);
+ }
+}
diff --git a/front/src/LoginPage.js b/front/src/LoginPage.js
index 31718d1..b6bdcf3 100644
--- a/front/src/LoginPage.js
+++ b/front/src/LoginPage.js
@@ -1,7 +1,6 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
-import { Input } from 'antd';
-import './App.css';
+import './LoginPage.css';
import { API_BASE_URL } from './config';
const LoginPage = () => {
@@ -75,56 +74,78 @@
} catch { }
}
}, []);
-
return (
- <div className="login-page" style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #e0e7ff 0%, #f0f8ff 100%)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
- <div className="login-form-container" style={{ width: 360, padding: '40px 32px 80px 32px', borderRadius: 18, boxShadow: '0 8px 32px rgba(60, 80, 180, 0.10)', background: '#fff', position: 'relative' }}>
- <h1 style={{ textAlign: 'center', marginBottom: 32, color: '#222', fontWeight: 700, fontSize: 32, letterSpacing: 2 }}>欢迎登录</h1>
- <form className="login-form">
- <div className="form-row" style={{ marginBottom: 24 }}>
- <label htmlFor="username" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>邮箱</label>
- <Input
- placeholder="请输入邮箱"
+ <div className="garden-login-page">
+ {/* 浮动花瓣装饰 */}
+ <div className="floating-petals">
+ <div className="petal">🌸</div>
+ <div className="petal">🌺</div>
+ <div className="petal">🌼</div>
+ <div className="petal">🌷</div>
+ <div className="petal">🌹</div>
+ <div className="petal">🌻</div>
+ <div className="petal">🌸</div>
+ <div className="petal">🌺</div>
+ </div>
+
+ <div className="garden-login-container">
+ {/* 装饰性元素 */}
+ <div className="garden-decoration top-left">🌿</div>
+ <div className="garden-decoration top-right">🦋</div>
+ <div className="garden-decoration bottom-left">🌱</div>
+ <div className="garden-decoration bottom-right">🌳</div> {/* 顶部图标 */}
+ <div className="garden-icon">⚡</div>
+
+ <h1 className="garden-title">NeuraFlux</h1>
+
+ <form className="garden-form">
+ <div className="garden-form-group">
+ <label htmlFor="username" className="garden-label">邮箱地址</label>
+ <input
+ type="email"
+ className="garden-input"
+ placeholder="请输入您的邮箱地址"
id="username"
name="username"
value={formData.username}
onChange={handleChange}
required
- style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
/>
+ <div className="garden-input-icon">📧</div>
</div>
- <div className="form-row" style={{ marginBottom: 24 }}>
- <label htmlFor="password" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>密码</label>
- <div style={{ display: 'flex', alignItems: 'center' }}>
- <Input
- placeholder="请输入密码"
- type="password"
- id="password"
- name="password"
- value={formData.password}
- onChange={handleChange}
- required
- style={{ flex: 1, padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
- />
+
+ <div className="garden-form-group">
+ <label htmlFor="password" className="garden-label">密码</label>
+ <input
+ type="password"
+ className="garden-input"
+ placeholder="请输入您的密码"
+ id="password"
+ name="password"
+ value={formData.password}
+ onChange={handleChange}
+ required
+ />
+ <div className="garden-input-icon">🔒</div>
+ </div>
+
+ {errorMessage && (
+ <div className="garden-error">
+ {errorMessage}
</div>
- </div>
- {errorMessage && <p style={{ color: '#e53935', textAlign: 'center', marginBottom: 18, fontWeight: 500 }}>{errorMessage}</p>}
- <div className="form-row button-row" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 32, position: 'static', gap: 16 }}>
- <button
+ )}
+
+ <div className="garden-button-group"> <button
type="button"
- className="login-button"
- onClick={handleLogin}
- style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #34c759 0%, #5be584 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2eac2', marginBottom: 12 }}
- >
- 登录
+ className="garden-button garden-login-btn"
+ onClick={handleLogin} >
+ 接入神经网络
</button>
<button
type="button"
- className="register-button"
- onClick={handleRegister}
- style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #4f8cff 0%, #6ad1ff 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2d8ea' }}
- >
- 注册
+ className="garden-button garden-register-btn"
+ onClick={handleRegister} >
+ 注册神经节点
</button>
</div>
</form>
diff --git a/front/src/MoviePage.js b/front/src/MoviePage.js
index 79f2c8b..421e0dd 100644
--- a/front/src/MoviePage.js
+++ b/front/src/MoviePage.js
@@ -1,223 +1,173 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
import { useNavigate } from "react-router-dom";
+import "./SharedStyles.css";
import { API_BASE_URL } from "./config";
+// 导航栏
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 电影地区标签
const areaTabs = [
- { label: "大陆", icon: <MovieIcon fontSize="small" /> },
- { label: "港台", icon: <EmailIcon fontSize="small" /> },
- { label: "欧美", icon: <PersonIcon fontSize="small" /> },
- { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "华语电影", value: "chinese" },
+ { label: "港台电影", value: "hk_tw" },
+ { label: "欧美电影", value: "western" },
+ { label: "日韩电影", value: "jp_kr" },
+ { label: "其他电影", value: "others" }
];
export default function MoviePage() {
- const navigate = useNavigate();
- const [searchText, setSearchText] = React.useState('');
- const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
- const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
- const [activeTab, setActiveTab] = React.useState(0);
- const [movieList, setMovieList] = React.useState([]);
+ const navigate = useNavigate();
+ const [searchText, setSearchText] = React.useState('');
+ const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
+ const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
+ const [activeTab, setActiveTab] = React.useState(0);
+ const [movieList, setMovieList] = React.useState([]);
- useEffect(() => {
- const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
- const userId = match ? match[2] : null;
- if (!userId) return;
- fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
- .then(res => res.json())
- .then(data => {
- setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
- setUserPT({
- magic: data.magic_value || data.magic || 0,
- ratio: data.share_ratio || data.share || 0,
- upload: data.upload_amount || data.upload || 0,
- download: data.download_amount || data.download || 0,
- });
- })
- .catch(err => console.error('Fetching user profile failed', err));
- }, []);
+ useEffect(() => {
+ const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
+ const userId = match ? match[2] : null;
+ if (!userId) return;
+ fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
+ .then(res => res.json())
+ .then(data => {
+ setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
+ setUserPT({
+ magic: data.magic_value || data.magic || 0,
+ ratio: data.share_ratio || data.share || 0,
+ upload: data.upload_amount || data.upload || 0,
+ download: data.download_amount || data.download || 0,
+ });
+ })
+ .catch(err => console.error('Fetching user profile failed', err));
+ }, []);
- // 每个tab对应的电影类型
- const movieTypesList = [
- ["华语电影(大陆)", "欧美电影", "日韩电影", "港台电影", "其他"], // 大陆
- ["港台动作", "港台爱情", "港台喜剧", "港台其他"], // 港台
- ["欧美动作", "欧美科幻", "欧美剧情", "欧美其他"], // 欧美
- ["日韩动画", "日韩爱情", "日韩其他"], // 日韩
- ["其他类型1", "其他类型2"] // 其他
- ];
- const movieTypes = movieTypesList[activeTab] || [];
+ // 每个tab对应的电影类型
+ const movieTypesList = [
+ ["华语电影(大陆)", "欧美电影", "日韩电影", "港台电影", "其他"], // 大陆
+ ["港台动作", "港台爱情", "港台喜剧", "港台其他"], // 港台
+ ["欧美动作", "欧美科幻", "欧美剧情", "欧美其他"], // 欧美
+ ["日韩动画", "日韩爱情", "日韩其他"], // 日韩
+ ["其他类型1", "其他类型2"] // 其他
+ ];
+ const movieTypes = movieTypesList[activeTab] || [];
- React.useEffect(() => {
- const area = areaTabs[activeTab].label;
- fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => {
- setMovieList(data);
- })
- .catch(() => setMovieList([]));
- }, [activeTab]);
+ React.useEffect(() => {
+ const area = areaTabs[activeTab].label;
+ fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
+ .then(res => res.json())
+ .then(data => {
+ setMovieList(data);
+ })
+ .catch(() => setMovieList([]));
+ }, [activeTab]);
- // 搜索按钮处理
- const handleSearch = () => {
- const area = areaTabs[activeTab].label;
- fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
- .then(res => res.json())
- .then(data => {
- setMovieList(data);
- })
- .catch(() => setMovieList([]));
- };
+ // 搜索按钮处理
+ const handleSearch = () => {
+ const area = areaTabs[activeTab].label;
+ fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
+ .then(res => res.json())
+ .then(data => {
+ setMovieList(data);
+ })
+ .catch(() => setMovieList([]));
+ };
- return (
- <div className="container">
- {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
+ return (
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ </div>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
+ </div>
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">12,345</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">2.56</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">100GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">50GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "电影" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 电影内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">🎬 电影资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px' }}>
+ 欢迎来到NeuraFlux电影频道,这里有最新最热门的电影资源
+ </p>
+ </div>
+ </div>
</div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
- </div>
- {/* 下方内容整体下移,留出与音乐界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "电影" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
- </div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="movie-table">
- <thead>
- <tr>
- <th>电影类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {movieList.length > 0 ? (
- movieList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
- ) : (
- movieTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
- )}
- </tbody>
- </table>
- </div>
- <div style={{ height: 32 }} />
- <Pagination />
- </div>
- );
-}
-
-function Pagination() {
- const [page, setPage] = React.useState(3);
- const total = 5;
- return (
- <div className="pagination">
- <button onClick={() => setPage(p => Math.max(1, p - 1))} disabled={page === 1}>上一页</button>
- <span className="page-num">{page}/{total}</span>
- <button onClick={() => setPage(p => Math.min(total, p + 1))} disabled={page === total}>下一页</button>
- <span className="page-info">第 <b>{page}</b> 页</span>
- </div>
- );
+ );
}
diff --git a/front/src/MusicPage.js b/front/src/MusicPage.js
index 097cf3c..13a6ba5 100644
--- a/front/src/MusicPage.js
+++ b/front/src/MusicPage.js
@@ -1,48 +1,49 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
+import "./SharedStyles.css";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 音乐地区标签
const areaTabs = [
- { label: "古典音乐", icon: <MovieIcon fontSize="small" /> },
- { label: "流行音乐", icon: <EmailIcon fontSize="small" /> },
- { label: "摇滚", icon: <PersonIcon fontSize="small" /> },
- { label: "电子音乐", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "说唱", icon: <PersonIcon fontSize="small" /> },
+ { label: "华语音乐", value: "chinese" },
+ { label: "港台音乐", value: "hk_tw" },
+ { label: "欧美音乐", value: "western" },
+ { label: "日韩音乐", value: "jp_kr" },
+ { label: "其他音乐", value: "others" }
];
export default function MusicPage() {
const navigate = useNavigate();
- const [searchText, setSearchText] = useState('');
+ const [searchText, setSearchText] = React.useState('');
const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
- const [activeTab, setActiveTab] = useState(0);
- const [musicList, setMusicList] = useState([]);
+ const [activeTab, setActiveTab] = React.useState(0);
+ const [musicList, setMusicList] = React.useState([]);
useEffect(() => {
const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
@@ -62,17 +63,8 @@
.catch(err => console.error('Fetching user profile failed', err));
}, []);
- // 每个tab对应的音乐类型
- const musicTypesList = [
- ["华语音乐(大陆)", "欧美音乐", "日韩音乐", "港台音乐", "其他"], // 古典音乐
- ["港台流行", "港台摇滚", "港台其他"], // 流行音乐
- ["欧美流行", "欧美摇滚", "欧美其他"], // 摇滚
- ["日韩流行", "日韩其他"], // 电子音乐
- ["其他类型1", "其他类型2"] // 说唱
- ];
- const musicTypes = musicTypesList[activeTab] || [];
-
- useEffect(() => {
+ React.useEffect(() => {
+ // 根据选中的标签获取音乐列表
const area = areaTabs[activeTab].label;
fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
.then(res => res.json())
@@ -86,128 +78,221 @@
fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
.then(res => res.json())
.then(data => {
+ console.log('搜索返回数据:', data);
setMusicList(data);
})
.catch(() => setMusicList([]));
};
+ const musicTypesList = [
+ ["华语流行", "华语摇滚", "华语民谣", "华语其他"], // 华语音乐
+ ["港台流行", "港台摇滚", "港台怀旧", "港台其他"], // 港台音乐
+ ["欧美流行", "欧美摇滚", "欧美电子", "欧美其他"], // 欧美音乐
+ ["日韩流行", "日韩摇滚", "日韩其他"], // 日韩音乐
+ ["古典音乐", "世界音乐", "其他类型"] // 其他音乐
+ ];
+ const musicTypes = musicTypesList[activeTab] || [];
return (
- <div className="container">
- {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与音乐界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "音乐" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
</div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="music-table">
- <thead>
- <tr>
- <th>音乐类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {musicList.length > 0 ? (
- musicList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
) : (
- musicTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
)}
- </tbody>
- </table>
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "音乐" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 音乐内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">🎵 音乐资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux音乐频道,这里有最新最热门的音乐资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索音乐资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div>
+
+ {/* 地区分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 音乐列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>音乐类型</th>
+ <th>标题</th>
+ <th>发布者</th>
+ <th>大小</th>
+ <th>热度</th>
+ <th>折扣倍率</th>
+ </tr>
+ </thead>
+ <tbody>
+ {musicList.length > 0 ? (
+ musicList.map((item, index) => (
+ <tr key={item.id || index}>
+ <td>{item.seedtag}</td>
+ <td>
+ <a href={`/torrent/${item.seedid}`}>
+ {item.title}
+ </a>
+ </td>
+ <td>{item.username}</td>
+ <td>{item.seedsize}</td>
+ <td>{item.downloadtimes}</td>
+ <td>{item.discount == null ? 1 : item.discount}</td>
+ </tr>
+ ))
+ ) : (
+ musicTypes.map((type, index) => (
+ <tr key={type}>
+ <td>{type}</td>
+ <td>
+ <a href={`/torrent/${type}`}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ <td>--</td>
+ <td>--</td>
+ <td>1</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div>
- <div style={{ height: 32 }} />
- <Pagination />
</div>
);
}
+// Pagination组件暂时不使用
function Pagination() {
const [page, setPage] = React.useState(3);
const total = 5;
diff --git a/front/src/PostDetailPage.js b/front/src/PostDetailPage.js
index fceaef8..aae1874 100644
--- a/front/src/PostDetailPage.js
+++ b/front/src/PostDetailPage.js
@@ -1,12 +1,70 @@
import React, { useState, useEffect } from "react";
-import { useParams } from "react-router-dom";
+import { useParams, useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
+import HomeIcon from "@mui/icons-material/Home";
+import MovieIcon from "@mui/icons-material/Movie";
+import TvIcon from "@mui/icons-material/Tv";
+import MusicNoteIcon from "@mui/icons-material/MusicNote";
+import AnimationIcon from "@mui/icons-material/Animation";
+import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
+import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
+import PersonIcon from "@mui/icons-material/Person";
+import AccountCircleIcon from "@mui/icons-material/AccountCircle";
+import ForumIcon from "@mui/icons-material/Forum";
+import HelpIcon from "@mui/icons-material/Help";
+import ArrowBackIcon from "@mui/icons-material/ArrowBack";
+import ReplyIcon from "@mui/icons-material/Reply";
+import VisibilityIcon from "@mui/icons-material/Visibility";
+import "./SharedStyles.css";
+
+const navItems = [
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
+];
+
+// 论坛详情页文字雨内容
+const forumDetailTexts = [
+ "讨论", "回复", "交流", "观点", "见解", "思考", "分享", "互动",
+ "对话", "评论", "深度", "专业", "洞察", "分析", "探讨", "解答"
+];
export default function PostDetailPage() {
const { postId } = useParams();
+ const navigate = useNavigate();
const [post, setPost] = useState(null);
const [replies, setReplies] = useState([]);
const [newReply, setNewReply] = useState('');
+ const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
+ const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
+
+ useEffect(() => {
+ // 获取用户信息
+ const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
+ const userId = match ? match[2] : null;
+ if (userId) {
+ fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
+ .then(res => res.json())
+ .then(data => {
+ setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
+ setUserPT({
+ magic: data.magic_value || data.magic || 0,
+ ratio: data.share_ratio || data.share || 0,
+ upload: data.upload_amount || data.upload || 0,
+ download: data.download_amount || data.download || 0,
+ });
+ })
+ .catch(err => console.error('Fetching user profile failed', err));
+ }
+ }, []);
// function to load post details and its replies
const fetchDetail = () => {
@@ -64,82 +122,190 @@
.catch(err => console.error(err));
};
- if (!post) return <div>加载中...</div>;
- return (
- <div style={{ maxWidth: 700, margin: "40px auto" }}>
- {/* 原帖 */}
- <div style={{
- background: "#fff",
- borderRadius: 12,
- boxShadow: "0 2px 8px #e0e7ff",
- padding: 24,
- marginBottom: 32,
- }}>
- <div style={{ fontSize: 15, color: "#1976d2", marginBottom: 6 }}>
- {post.author_name} · {post.created_at}
- </div>
- <div style={{ fontWeight: 600, fontSize: 20, marginBottom: 8, color: "#222" }}>
- {post.title}
- </div>
- <div style={{ fontSize: 16, color: "#444", marginBottom: 18 }}>
- {post.content}
- </div>
- <div style={{ display: "flex", justifyContent: "flex-start", gap: 32, fontSize: 14, color: "#888" }}>
- <span>回复数: {post.reply_count}</span>
- <span>观看数: {post.view_count}</span>
+ if (!post) return (
+ <div className="emerald-home-container">
+ <div className="emerald-content">
+ <div style={{
+ textAlign: 'center',
+ padding: '100px 20px',
+ color: '#2d5016',
+ fontSize: '18px',
+ background: 'rgba(255, 255, 255, 0.95)',
+ borderRadius: '25px',
+ margin: '50px auto',
+ maxWidth: '600px'
+ }}>
+ <ForumIcon style={{ fontSize: 64, marginBottom: '20px', color: '#90ee90' }} />
+ <div>加载帖子详情中...</div>
</div>
</div>
- {/* 评论区 */}
- <div>
- {replies.map(reply => (
- <div key={reply.reply_id} style={{
- display: "flex",
- alignItems: "center",
- background: "#f8faff",
- borderRadius: 8,
- padding: "12px 18px",
- marginBottom: 16,
- fontSize: 15,
+ </div>
+ );
+
+ return (
+ <div className="emerald-home-container">
+ {/* 文字雨背景效果 */}
+ <div className="forum-text-rain">
+ {forumDetailTexts.map((text, index) => (
+ <div key={index} className="text-drop" style={{
+ left: `${(index * 3.5) % 100}%`,
+ animationDelay: `${(index * 0.8) % 10}s`,
+ animationDuration: `${8 + (index % 5)}s`
}}>
- <span style={{ color: "#1976d2", fontWeight: 500, minWidth: 80 }}>{reply.author_name}</span>
- <span style={{ flex: 1, marginLeft: 18 }}>{reply.content}</span>
- <span style={{ color: "#888", fontSize: 13, marginLeft: 18 }}>{reply.created_at}</span>
+ {text}
</div>
))}
</div>
- {/* 回复框 */}
- <div style={{
- marginTop: 32,
- background: "#fff",
- borderRadius: 8,
- boxShadow: "0 2px 8px #e0e7ff",
- padding: 18,
- display: "flex",
- gap: 12,
- alignItems: "center"
- }}>
- <input
- type="text"
- placeholder="写下你的回复..."
- value={newReply}
- onChange={e => setNewReply(e.target.value)}
- style={{
- flex: 1,
- border: "1px solid #bfcfff",
- borderRadius: 6,
- padding: "8px 12px",
- fontSize: 15,
- }}
- />
- <button onClick={handleReply} style={{
- background: "#1976d2",
- color: "#fff",
- border: "none",
- borderRadius: 6,
- padding: "8px 24px",
- fontSize: 15,
- cursor: "pointer"
- }}>回复</button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">💭</div>
+ <div className="garden-element">📖</div>
+ <div className="garden-element">💡</div>
+ <div className="garden-element">✨</div>
+ </div>
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
+ ) : (
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
+ )}
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "论坛" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 返回按钮 */}
+ <div className="post-detail-header">
+ <button className="back-to-forum-btn" onClick={() => navigate('/forum')}>
+ <ArrowBackIcon style={{ marginRight: '8px', fontSize: '20px' }} />
+ 返回论坛
+ </button>
+ </div>
+
+ {/* 帖子详情内容区域 */}
+ <div className="emerald-content-section">
+ {/* 原帖内容 */}
+ <div className="post-detail-main">
+ <div className="post-detail-header-info">
+ <div className="post-author-section">
+ <div className="post-author-avatar">
+ <AccountCircleIcon style={{ fontSize: 48, color: '#2d5016' }} />
+ </div>
+ <div className="post-author-details">
+ <h2 className="post-author-name">{post.author_name}</h2>
+ <span className="post-publish-time">{post.created_at}</span>
+ </div>
+ </div>
+ <div className="post-stats-section">
+ <div className="stat-badge">
+ <VisibilityIcon style={{ fontSize: '18px', marginRight: '4px' }} />
+ <span>{post.view_count} 浏览</span>
+ </div>
+ <div className="stat-badge">
+ <ReplyIcon style={{ fontSize: '18px', marginRight: '4px' }} />
+ <span>{post.reply_count} 回复</span>
+ </div>
+ </div>
+ </div>
+
+ <div className="post-content-section">
+ <h1 className="post-detail-title">{post.title}</h1>
+ <div className="post-detail-content">
+ {post.content}
+ </div>
+ </div>
+ </div>
+
+ {/* 回复列表 */}
+ <div className="replies-section">
+ <h3 className="replies-title">
+ <ReplyIcon style={{ marginRight: '8px', color: '#2d5016' }} />
+ 全部回复 ({replies.length})
+ </h3>
+
+ {replies.length > 0 ? (
+ <div className="replies-list">
+ {replies.map((reply, index) => (
+ <div key={reply.reply_id} className="reply-card">
+ <div className="reply-index">#{index + 1}</div>
+ <div className="reply-content-wrapper">
+ <div className="reply-author-info">
+ <AccountCircleIcon style={{ fontSize: 24, color: '#2d5016', marginRight: '8px' }} />
+ <span className="reply-author-name">{reply.author_name}</span>
+ <span className="reply-time">{reply.created_at}</span>
+ </div>
+ <div className="reply-content">{reply.content}</div>
+ </div>
+ </div>
+ ))}
+ </div>
+ ) : (
+ <div className="no-replies">
+ <ForumIcon style={{ fontSize: 48, color: '#90ee90', marginBottom: '16px' }} />
+ <p>还没有人回复,快来抢沙发吧!</p>
+ </div>
+ )}
+ </div>
+
+ {/* 回复输入框 */}
+ <div className="reply-input-section">
+ <h3 className="reply-input-title">发表回复</h3>
+ <div className="reply-input-wrapper">
+ <textarea
+ placeholder="写下你的想法和观点..."
+ value={newReply}
+ onChange={e => setNewReply(e.target.value)}
+ className="reply-textarea"
+ rows="4"
+ />
+ <div className="reply-actions">
+ <div className="reply-tips">
+ 💡 支持理性讨论,拒绝恶意灌水
+ </div>
+ <button onClick={handleReply} className="submit-reply-btn">
+ <ReplyIcon style={{ marginRight: '6px', fontSize: '18px' }} />
+ 发布回复
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
</div>
</div>
);
diff --git a/front/src/SharedStyles.css b/front/src/SharedStyles.css
new file mode 100644
index 0000000..730a76e
--- /dev/null
+++ b/front/src/SharedStyles.css
@@ -0,0 +1,1419 @@
+/* NeuraFlux - 共享欧式园林风格样式 */
+
+/* 引入Google字体 */
+@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Lora:wght@400;500;600&display=swap');
+
+/* 页面基础样式 */
+.emerald-home-container {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #2d5016 0%, #4a7c59 20%, #8fbc8f 40%, #98fb98 60%, #f0fff0 100%);
+ position: relative;
+ font-family: 'Lora', serif;
+ overflow-x: hidden;
+}
+
+/* 背景装饰元素 */
+.emerald-home-container::before {
+ content: '';
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background:
+ radial-gradient(circle at 20% 80%, rgba(255, 255, 255, 0.08) 0%, transparent 50%),
+ radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.06) 0%, transparent 50%),
+ radial-gradient(circle at 40% 40%, rgba(144, 238, 144, 0.08) 0%, transparent 50%);
+ animation: backgroundShift 25s ease-in-out infinite;
+ pointer-events: none;
+ z-index: 0;
+}
+
+/* 流星雨效果 */
+.meteor-shower {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ overflow: hidden;
+ z-index: 1;
+}
+
+.meteor {
+ position: absolute;
+ font-size: 18px;
+ animation: meteorFall linear infinite;
+ opacity: 0.8;
+ filter: drop-shadow(0 0 6px rgba(144, 238, 144, 0.6));
+}
+
+.meteor:nth-child(1) { left: 5%; animation-duration: 12s; animation-delay: 0s; }
+.meteor:nth-child(2) { left: 15%; animation-duration: 8s; animation-delay: 3s; }
+.meteor:nth-child(3) { left: 25%; animation-duration: 15s; animation-delay: 1s; }
+.meteor:nth-child(4) { left: 35%; animation-duration: 10s; animation-delay: 5s; }
+.meteor:nth-child(5) { left: 45%; animation-duration: 13s; animation-delay: 2s; }
+.meteor:nth-child(6) { left: 55%; animation-duration: 9s; animation-delay: 6s; }
+.meteor:nth-child(7) { left: 65%; animation-duration: 14s; animation-delay: 0.5s; }
+.meteor:nth-child(8) { left: 75%; animation-duration: 11s; animation-delay: 4s; }
+.meteor:nth-child(9) { left: 85%; animation-duration: 16s; animation-delay: 1.5s; }
+.meteor:nth-child(10) { left: 95%; animation-duration: 7s; animation-delay: 3.5s; }
+
+/* 浮动装饰元素 */
+.floating-garden-elements {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.garden-element {
+ position: absolute;
+ font-size: 24px;
+ opacity: 0.4;
+ animation: gardenFloat 6s ease-in-out infinite;
+}
+
+.garden-element:nth-child(1) { top: 10%; left: 10%; animation-delay: 0s; }
+.garden-element:nth-child(2) { top: 20%; right: 15%; animation-delay: 2s; }
+.garden-element:nth-child(3) { bottom: 30%; left: 20%; animation-delay: 4s; }
+.garden-element:nth-child(4) { bottom: 15%; right: 25%; animation-delay: 1s; }
+
+/* 内容容器 */
+.emerald-content {
+ position: relative;
+ z-index: 10;
+ padding: 20px;
+ max-width: 1400px;
+ margin: 0 auto;
+}
+
+/* 用户栏样式 */
+.emerald-user-bar {
+ position: fixed;
+ top: 18px;
+ right: 42px;
+ z-index: 100;
+ display: flex;
+ align-items: center;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(15px);
+ border-radius: 20px;
+ padding: 8px 24px;
+ box-shadow:
+ 0 8px 32px rgba(45, 80, 22, 0.15),
+ 0 4px 16px rgba(144, 238, 144, 0.1),
+ inset 0 1px 0 rgba(255, 255, 255, 0.7);
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ min-width: 320px;
+ min-height: 48px;
+ width: 520px;
+ animation: userBarFloat 4s ease-in-out infinite;
+}
+
+.emerald-user-bar::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 22px;
+ z-index: -1;
+ animation: borderGlow 3s ease-in-out infinite;
+}
+
+.emerald-user-avatar {
+ cursor: pointer;
+ margin-right: 16px;
+ transition: all 0.3s ease;
+ border-radius: 50%;
+ padding: 4px;
+ background: linear-gradient(135deg, #90ee90, #2d5016);
+}
+
+.emerald-user-avatar:hover {
+ transform: scale(1.1) rotate(5deg);
+ box-shadow: 0 4px 15px rgba(144, 238, 144, 0.4);
+}
+
+/* 品牌区域样式 */
+.emerald-brand-section {
+ display: flex;
+ align-items: center;
+ margin-right: 24px;
+}
+
+.emerald-brand-icon {
+ font-size: 24px;
+ margin-right: 8px;
+ animation: iconPulse 3s ease-in-out infinite;
+}
+
+.emerald-user-label {
+ color: #2d5016;
+ font-weight: 600;
+ font-family: 'Playfair Display', serif;
+ letter-spacing: 1px;
+}
+
+.emerald-user-stats {
+ display: flex;
+ gap: 24px;
+ flex: 1;
+ justify-content: flex-end;
+ align-items: center;
+}
+
+.emerald-stat-item {
+ color: #2d5016;
+ font-weight: 500;
+ font-size: 14px;
+ transition: all 0.3s ease;
+ padding: 4px 8px;
+ border-radius: 8px;
+}
+
+.emerald-stat-item:hover {
+ background: rgba(144, 238, 144, 0.2);
+ transform: translateY(-2px);
+}
+
+.emerald-stat-value {
+ font-weight: 700;
+ color: #1a5c1a;
+}
+
+/* 导航栏样式 */
+.emerald-nav-bar {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border-radius: 25px;
+ padding: 20px 30px;
+ margin: 120px auto 30px;
+ box-shadow:
+ 0 15px 45px rgba(45, 80, 22, 0.12),
+ 0 6px 20px rgba(144, 238, 144, 0.08),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
+ gap: 10px;
+ justify-items: center;
+ position: relative;
+ overflow: hidden;
+}
+
+.emerald-nav-bar::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 27px;
+ z-index: -1;
+ animation: borderGlow 5s ease-in-out infinite;
+}
+
+/* 导航项目样式 */
+.emerald-nav-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 20px;
+ border-radius: 18px;
+ cursor: pointer;
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+ background: rgba(240, 255, 240, 0.3);
+ border: 2px solid transparent;
+ position: relative;
+ overflow: hidden;
+ min-width: 90px;
+ font-family: 'Lora', serif;
+}
+
+.emerald-nav-item::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(144, 238, 144, 0.3), transparent);
+ transition: left 0.6s ease;
+}
+
+.emerald-nav-item:hover::before {
+ left: 100%;
+}
+
+.emerald-nav-item:hover {
+ transform: translateY(-8px) scale(1.05);
+ background: rgba(144, 238, 144, 0.2);
+ border-color: rgba(144, 238, 144, 0.4);
+ box-shadow:
+ 0 12px 35px rgba(45, 80, 22, 0.2),
+ 0 6px 20px rgba(144, 238, 144, 0.15);
+}
+
+.emerald-nav-item.active {
+ background: linear-gradient(135deg, #90ee90 0%, #2d5016 100%);
+ color: white;
+ border-color: #2d5016;
+ transform: translateY(-4px);
+ box-shadow:
+ 0 8px 25px rgba(45, 80, 22, 0.3),
+ 0 4px 15px rgba(144, 238, 144, 0.2);
+}
+
+/* 导航图标动画 */
+.emerald-nav-icon {
+ font-size: 28px !important;
+ margin-bottom: 8px;
+ transition: all 0.4s ease;
+ position: relative;
+}
+
+.emerald-nav-item:hover .emerald-nav-icon {
+ animation: iconDance 0.6s ease-in-out;
+ transform: scale(1.2);
+}
+
+.emerald-nav-item.active .emerald-nav-icon {
+ color: white;
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
+}
+
+/* 导航标签 */
+.emerald-nav-label {
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.5px;
+ color: #2d5016;
+ transition: all 0.3s ease;
+}
+
+.emerald-nav-item:hover .emerald-nav-label {
+ color: #1a5c1a;
+ transform: scale(1.05);
+}
+
+.emerald-nav-item.active .emerald-nav-label {
+ color: white;
+ font-weight: 700;
+}
+
+/* 内容区域样式 */
+.emerald-content-section {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border-radius: 25px;
+ padding: 30px;
+ margin: 30px auto;
+ box-shadow:
+ 0 20px 60px rgba(45, 80, 22, 0.12),
+ 0 8px 25px rgba(144, 238, 144, 0.08),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ position: relative;
+ overflow: hidden;
+}
+
+.emerald-content-section::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 27px;
+ z-index: -1;
+ animation: borderGlow 4s ease-in-out infinite;
+}
+
+.emerald-page-title {
+ text-align: center;
+ color: #2d5016;
+ font-family: 'Playfair Display', serif;
+ font-weight: 700;
+ font-size: 32px;
+ margin-bottom: 30px;
+ letter-spacing: 2px;
+}
+
+/* 表格区域样式 */
+.emerald-table-section {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border-radius: 25px;
+ padding: 30px;
+ margin: 30px auto;
+ box-shadow:
+ 0 20px 60px rgba(45, 80, 22, 0.12),
+ 0 8px 25px rgba(144, 238, 144, 0.08),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ position: relative;
+ overflow: hidden;
+}
+
+.emerald-table-section::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 27px;
+ z-index: -1;
+ animation: borderGlow 4s ease-in-out infinite;
+}
+
+/* 表格样式 */
+.emerald-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-family: 'Lora', serif;
+ background: transparent;
+}
+
+.emerald-table thead {
+ background: linear-gradient(135deg, #2d5016 0%, #4a7c59 100%);
+}
+
+.emerald-table th {
+ padding: 16px 20px;
+ text-align: left;
+ color: white;
+ font-weight: 600;
+ font-size: 16px;
+ letter-spacing: 1px;
+ border-bottom: 3px solid #90ee90;
+ position: relative;
+}
+
+.emerald-table th:first-child {
+ border-radius: 15px 0 0 0;
+}
+
+.emerald-table th:last-child {
+ border-radius: 0 15px 0 0;
+}
+
+.emerald-table tbody tr {
+ transition: all 0.3s ease;
+ border-bottom: 1px solid rgba(144, 238, 144, 0.2);
+}
+
+.emerald-table tbody tr:hover {
+ background: rgba(144, 238, 144, 0.1);
+ transform: translateX(5px);
+ box-shadow: 0 4px 15px rgba(144, 238, 144, 0.15);
+}
+
+.emerald-table td {
+ padding: 14px 20px;
+ color: #2d5016;
+ font-size: 15px;
+ vertical-align: middle;
+ transition: all 0.3s ease;
+}
+
+.emerald-table tbody tr:hover td {
+ color: #1a5c1a;
+}
+
+/* 表格链接样式 */
+.emerald-table a {
+ color: #2d5016;
+ text-decoration: none;
+ font-weight: 500;
+ transition: all 0.3s ease;
+ padding: 4px 8px;
+ border-radius: 8px;
+ display: inline-block;
+}
+
+.emerald-table a:hover {
+ color: #1a5c1a;
+ background: rgba(144, 238, 144, 0.2);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(144, 238, 144, 0.3);
+}
+
+/* 论坛页面专用样式 */
+
+/* 文字雨背景效果 */
+.forum-text-rain {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ overflow: hidden;
+ z-index: 1;
+}
+
+.text-drop {
+ position: absolute;
+ top: -50px;
+ font-size: 14px;
+ color: rgba(45, 80, 22, 0.6);
+ font-family: 'Lora', serif;
+ font-weight: 500;
+ animation: textFall linear infinite;
+ filter: drop-shadow(0 0 4px rgba(144, 238, 144, 0.3));
+}
+
+@keyframes textFall {
+ 0% {
+ top: -50px;
+ opacity: 0;
+ transform: translateX(0);
+ }
+ 10% {
+ opacity: 1;
+ }
+ 90% {
+ opacity: 1;
+ }
+ 100% {
+ top: 100vh;
+ opacity: 0;
+ transform: translateX(20px);
+ }
+}
+
+/* 论坛工具栏样式 */
+.forum-toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30px;
+ padding: 20px 30px;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(15px);
+ border-radius: 20px;
+ box-shadow:
+ 0 8px 32px rgba(45, 80, 22, 0.12),
+ 0 4px 16px rgba(144, 238, 144, 0.08);
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ gap: 20px;
+}
+
+.search-section {
+ display: flex;
+ align-items: center;
+ gap: 0;
+ flex: 1;
+ max-width: 500px;
+}
+
+.search-input-container {
+ position: relative;
+ flex: 1;
+ display: flex;
+ align-items: center;
+}
+
+.search-icon {
+ position: absolute;
+ left: 15px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: rgba(45, 80, 22, 0.6);
+ font-size: 20px !important;
+}
+
+.forum-search-input {
+ width: 100%;
+ padding: 12px 20px 12px 50px;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ border-radius: 25px 0 0 25px;
+ background: rgba(240, 255, 240, 0.5);
+ font-size: 16px;
+ font-family: 'Lora', serif;
+ outline: none;
+ transition: all 0.3s ease;
+ border-right: none;
+}
+
+.forum-search-input:focus {
+ border-color: rgba(144, 238, 144, 0.6);
+ background: rgba(240, 255, 240, 0.8);
+ box-shadow: 0 0 15px rgba(144, 238, 144, 0.2);
+}
+
+.forum-search-btn {
+ padding: 14px 20px;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ border-left: none;
+ border-radius: 0 25px 25px 0;
+ background: linear-gradient(135deg, #2d5016 0%, #90ee90 100%);
+ color: white;
+ font-size: 16px;
+ font-family: 'Lora', serif;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 4px 15px rgba(45, 80, 22, 0.2);
+ white-space: nowrap;
+}
+
+.forum-search-btn:hover {
+ background: linear-gradient(135deg, #1a3d0e 0%, #7ddc7d 100%);
+ transform: translateY(-1px);
+ box-shadow: 0 6px 20px rgba(45, 80, 22, 0.3);
+}
+
+.forum-search-input:focus + .forum-search-btn {
+ border-color: rgba(144, 238, 144, 0.6);
+}
+
+.new-post-btn {
+ display: flex;
+ align-items: center;
+ padding: 12px 20px;
+ border: none;
+ border-radius: 20px;
+ background: linear-gradient(135deg, #90ee90 0%, #2d5016 100%);
+ color: white;
+ font-size: 16px;
+ font-family: 'Lora', serif;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 4px 15px rgba(144, 238, 144, 0.2);
+}
+
+.new-post-btn:hover {
+ transform: translateY(-2px) scale(1.02);
+ box-shadow: 0 6px 20px rgba(144, 238, 144, 0.3);
+}
+
+/* 论坛帖子容器 */
+.forum-posts-container {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+/* 论坛帖子卡片样式 */
+.forum-post-card {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(15px);
+ border-radius: 20px;
+ padding: 25px 30px;
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ cursor: pointer;
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+ position: relative;
+ overflow: hidden;
+ box-shadow: 0 8px 25px rgba(45, 80, 22, 0.1);
+}
+
+.forum-post-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(144, 238, 144, 0.1), transparent);
+ transition: left 0.6s ease;
+}
+
+.forum-post-card:hover::before {
+ left: 100%;
+}
+
+.forum-post-card:hover {
+ transform: translateY(-8px) scale(1.02);
+ border-color: rgba(144, 238, 144, 0.4);
+ box-shadow:
+ 0 15px 40px rgba(45, 80, 22, 0.15),
+ 0 8px 25px rgba(144, 238, 144, 0.1);
+}
+
+/* 帖子头部信息 */
+.post-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+}
+
+.post-author-info {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.author-avatar {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #90ee90, #2d5016);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 2px 10px rgba(45, 80, 22, 0.2);
+}
+
+.author-details {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+
+.author-name {
+ font-weight: 600;
+ color: #2d5016;
+ font-size: 16px;
+ font-family: 'Lora', serif;
+}
+
+.post-time {
+ font-size: 12px;
+ color: rgba(45, 80, 22, 0.7);
+}
+
+.post-stats {
+ display: flex;
+ gap: 15px;
+}
+
+.stat-item {
+ background: rgba(144, 238, 144, 0.2);
+ padding: 4px 10px;
+ border-radius: 12px;
+ font-size: 12px;
+ color: #2d5016;
+ font-weight: 500;
+}
+
+/* 帖子内容区域 */
+.post-content {
+ margin: 15px 0;
+}
+
+.post-title {
+ font-family: 'Playfair Display', serif;
+ font-size: 20px;
+ font-weight: 700;
+ color: #2d5016;
+ margin-bottom: 10px;
+ line-height: 1.3;
+}
+
+.post-preview {
+ font-size: 15px;
+ color: rgba(45, 80, 22, 0.8);
+ line-height: 1.5;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+/* 帖子底部 */
+.post-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 15px;
+ padding-top: 15px;
+ border-top: 1px solid rgba(144, 238, 144, 0.2);
+}
+
+.post-tags {
+ display: flex;
+ gap: 8px;
+}
+
+.post-tag {
+ background: linear-gradient(135deg, #90ee90, #2d5016);
+ color: white;
+ padding: 4px 12px;
+ border-radius: 15px;
+ font-size: 12px;
+ font-weight: 500;
+}
+
+.post-actions {
+ display: flex;
+ gap: 10px;
+}
+
+.action-btn {
+ color: #2d5016;
+ font-size: 14px;
+ font-weight: 500;
+ transition: all 0.3s ease;
+}
+
+.action-btn:hover {
+ color: #90ee90;
+ transform: translateX(3px);
+}
+
+/* 帖子详情页面样式 */
+.post-detail-header {
+ margin: 20px 0;
+ display: flex;
+ justify-content: flex-start;
+}
+
+.back-to-forum-btn {
+ background: rgba(144, 238, 144, 0.2);
+ border: 2px solid rgba(144, 238, 144, 0.4);
+ border-radius: 20px;
+ padding: 12px 24px;
+ color: #2d5016;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ display: flex;
+ align-items: center;
+ font-family: 'Lora', serif;
+ backdrop-filter: blur(10px);
+}
+
+.back-to-forum-btn:hover {
+ background: rgba(144, 238, 144, 0.3);
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(45, 80, 22, 0.15);
+}
+
+.post-detail-main {
+ background: rgba(255, 255, 255, 0.98);
+ border-radius: 20px;
+ padding: 30px;
+ margin-bottom: 30px;
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ box-shadow: 0 15px 40px rgba(45, 80, 22, 0.08);
+ position: relative;
+ overflow: hidden;
+}
+
+.post-detail-main::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 22px;
+ z-index: -1;
+ animation: borderGlow 6s ease-in-out infinite;
+}
+
+.post-detail-header-info {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 25px;
+ padding-bottom: 20px;
+ border-bottom: 2px solid rgba(144, 238, 144, 0.2);
+}
+
+.post-author-section {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+.post-author-avatar {
+ padding: 8px;
+ background: linear-gradient(135deg, rgba(144, 238, 144, 0.2), rgba(240, 255, 240, 0.6));
+ border-radius: 50%;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+}
+
+.post-author-details h2.post-author-name {
+ margin: 0;
+ font-size: 22px;
+ color: #2d5016;
+ font-weight: 700;
+ font-family: 'Playfair Display', serif;
+}
+
+.post-publish-time {
+ color: #666;
+ font-size: 14px;
+ font-style: italic;
+}
+
+.post-stats-section {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+}
+
+.stat-badge {
+ display: flex;
+ align-items: center;
+ background: rgba(144, 238, 144, 0.15);
+ padding: 8px 16px;
+ border-radius: 20px;
+ border: 1px solid rgba(144, 238, 144, 0.3);
+ color: #2d5016;
+ font-weight: 500;
+ font-size: 14px;
+ transition: all 0.3s ease;
+}
+
+.stat-badge:hover {
+ background: rgba(144, 238, 144, 0.25);
+ transform: translateY(-2px);
+}
+
+.post-content-section {
+ margin-top: 20px;
+}
+
+.post-detail-title {
+ font-size: 28px;
+ color: #2d5016;
+ font-weight: 700;
+ margin-bottom: 20px;
+ font-family: 'Playfair Display', serif;
+ line-height: 1.3;
+}
+
+.post-detail-content {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #444;
+ background: rgba(240, 255, 240, 0.3);
+ padding: 25px;
+ border-radius: 15px;
+ border-left: 4px solid #90ee90;
+ font-family: 'Lora', serif;
+}
+
+/* 回复区域样式 */
+.replies-section {
+ margin-top: 30px;
+}
+
+.replies-title {
+ display: flex;
+ align-items: center;
+ font-size: 22px;
+ color: #2d5016;
+ font-weight: 600;
+ margin-bottom: 25px;
+ font-family: 'Playfair Display', serif;
+}
+
+.replies-list {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.reply-card {
+ display: flex;
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 15px;
+ padding: 20px;
+ border: 1px solid rgba(144, 238, 144, 0.2);
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.reply-card::before {
+ content: '';
+ position: absolute;
+ top: -1px;
+ left: -1px;
+ right: -1px;
+ bottom: -1px;
+ background: linear-gradient(45deg,
+ transparent 0%,
+ rgba(144, 238, 144, 0.1) 50%,
+ transparent 100%);
+ border-radius: 16px;
+ z-index: -1;
+ opacity: 0;
+ transition: opacity 0.3s ease;
+}
+
+.reply-card:hover::before {
+ opacity: 1;
+}
+
+.reply-card:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 10px 25px rgba(45, 80, 22, 0.1);
+}
+
+.reply-index {
+ background: linear-gradient(135deg, #90ee90, #2d5016);
+ color: white;
+ width: 35px;
+ height: 35px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 700;
+ font-size: 14px;
+ margin-right: 20px;
+ flex-shrink: 0;
+ box-shadow: 0 4px 12px rgba(45, 80, 22, 0.2);
+}
+
+.reply-content-wrapper {
+ flex: 1;
+}
+
+.reply-author-info {
+ display: flex;
+ align-items: center;
+ margin-bottom: 12px;
+ gap: 8px;
+}
+
+.reply-author-name {
+ font-weight: 600;
+ color: #2d5016;
+ font-size: 16px;
+}
+
+.reply-time {
+ color: #888;
+ font-size: 13px;
+ font-style: italic;
+}
+
+.reply-content {
+ color: #444;
+ font-size: 15px;
+ line-height: 1.6;
+ font-family: 'Lora', serif;
+}
+
+.no-replies {
+ text-align: center;
+ padding: 60px 20px;
+ color: #666;
+ background: rgba(240, 255, 240, 0.3);
+ border-radius: 20px;
+ border: 2px dashed rgba(144, 238, 144, 0.3);
+}
+
+.no-replies p {
+ margin: 0;
+ font-size: 16px;
+ font-style: italic;
+}
+
+/* 回复输入区域样式 */
+.reply-input-section {
+ margin-top: 40px;
+ background: rgba(255, 255, 255, 0.98);
+ border-radius: 20px;
+ padding: 30px;
+ border: 2px solid rgba(144, 238, 144, 0.2);
+ position: relative;
+ overflow: hidden;
+}
+
+.reply-input-section::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg,
+ #90ee90 0%,
+ #98fb98 25%,
+ #f0fff0 50%,
+ #98fb98 75%,
+ #90ee90 100%);
+ border-radius: 22px;
+ z-index: -1;
+ animation: borderGlow 5s ease-in-out infinite;
+}
+
+.reply-input-title {
+ color: #2d5016;
+ font-size: 20px;
+ font-weight: 600;
+ margin-bottom: 20px;
+ font-family: 'Playfair Display', serif;
+}
+
+.reply-input-wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+}
+
+.reply-textarea {
+ width: 100%;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ border-radius: 15px;
+ padding: 20px;
+ font-size: 15px;
+ font-family: 'Lora', serif;
+ line-height: 1.6;
+ background: rgba(240, 255, 240, 0.2);
+ resize: vertical;
+ min-height: 120px;
+ transition: all 0.3s ease;
+ box-sizing: border-box;
+}
+
+.reply-textarea:focus {
+ outline: none;
+ border-color: #90ee90;
+ background: rgba(240, 255, 240, 0.4);
+ box-shadow: 0 0 0 3px rgba(144, 238, 144, 0.2);
+}
+
+.reply-textarea::placeholder {
+ color: #999;
+ font-style: italic;
+}
+
+.reply-actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.reply-tips {
+ color: #666;
+ font-size: 14px;
+ font-style: italic;
+}
+
+.submit-reply-btn {
+ background: linear-gradient(135deg, #90ee90, #2d5016);
+ color: white;
+ border: none;
+ border-radius: 20px;
+ padding: 12px 30px;
+ font-size: 16px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ display: flex;
+ align-items: center;
+ font-family: 'Lora', serif;
+ box-shadow: 0 6px 20px rgba(45, 80, 22, 0.2);
+}
+
+.submit-reply-btn:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 10px 30px rgba(45, 80, 22, 0.3);
+ background: linear-gradient(135deg, #7dd87d, #1a4a1a);
+}
+
+.submit-reply-btn:active {
+ transform: translateY(-1px);
+}
+
+/* 动画定义 */
+@keyframes backgroundShift {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.7; }
+}
+
+@keyframes meteorFall {
+ 0% {
+ transform: translateY(-100vh) translateX(-50px) rotate(0deg);
+ opacity: 0;
+ }
+ 10% {
+ opacity: 0.8;
+ }
+ 90% {
+ opacity: 0.8;
+ }
+ 100% {
+ transform: translateY(100vh) translateX(50px) rotate(360deg);
+ opacity: 0;
+ }
+}
+
+@keyframes gardenFloat {
+ 0%, 100% {
+ transform: translateY(0px) rotate(0deg);
+ opacity: 0.4;
+ }
+ 50% {
+ transform: translateY(-15px) rotate(180deg);
+ opacity: 0.6;
+ }
+}
+
+@keyframes userBarFloat {
+ 0%, 100% {
+ transform: translateY(0px);
+ }
+ 50% {
+ transform: translateY(-3px);
+ }
+}
+
+@keyframes borderGlow {
+ 0%, 100% {
+ opacity: 0.6;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes iconDance {
+ 0%, 100% {
+ transform: scale(1) rotate(0deg);
+ }
+ 25% {
+ transform: scale(1.1) rotate(5deg);
+ }
+ 50% {
+ transform: scale(1.2) rotate(0deg);
+ }
+ 75% {
+ transform: scale(1.1) rotate(-5deg);
+ }
+}
+
+@keyframes iconPulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.1);
+ }
+}
+
+/* 响应式设计 */
+@media (max-width: 1200px) {
+ .emerald-user-bar {
+ width: 440px;
+ right: 20px;
+ }
+
+ .emerald-nav-bar {
+ margin: 100px 20px 20px;
+ padding: 16px 20px;
+ grid-template-columns: repeat(6, 1fr);
+ }
+
+ .emerald-nav-item {
+ min-width: 80px;
+ padding: 12px 16px;
+ }
+}
+
+@media (max-width: 768px) {
+ .emerald-user-bar {
+ position: relative;
+ top: 0;
+ right: 0;
+ width: 100%;
+ margin: 20px 0;
+ flex-direction: column;
+ gap: 16px;
+ }
+
+ .emerald-brand-section {
+ margin-right: 0;
+ justify-content: center;
+ }
+
+ .emerald-user-stats {
+ flex-direction: column;
+ gap: 8px;
+ width: 100%;
+ }
+
+ .emerald-nav-bar {
+ margin: 20px 10px;
+ padding: 16px;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 12px;
+ }
+
+ .emerald-nav-item {
+ min-width: 70px;
+ padding: 10px 12px;
+ }
+
+ .emerald-nav-icon {
+ font-size: 24px !important;
+ }
+
+ .emerald-nav-label {
+ font-size: 12px;
+ }
+
+ .emerald-content-section {
+ margin: 20px 10px;
+ padding: 20px 15px;
+ }
+
+ .meteor {
+ font-size: 14px;
+ }
+
+ .garden-element {
+ font-size: 20px;
+ }
+
+ .forum-toolbar {
+ flex-direction: column;
+ gap: 15px;
+ padding: 15px 20px;
+ }
+
+ .search-section {
+ width: 100%;
+ max-width: none;
+ }
+
+ .search-input-container {
+ max-width: none;
+ }
+
+ .forum-search-input {
+ border-radius: 25px 0 0 25px;
+ }
+
+ .forum-search-btn {
+ border-radius: 0 25px 25px 0;
+ padding: 14px 16px;
+ }
+
+ .forum-post-card {
+ padding: 20px;
+ }
+
+ .post-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ }
+
+ .post-footer {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ }
+}
+
+@media (max-width: 480px) {
+ .emerald-nav-bar {
+ grid-template-columns: repeat(3, 1fr);
+ gap: 8px;
+ padding: 12px;
+ }
+
+ .emerald-nav-item {
+ min-width: 60px;
+ padding: 8px 10px;
+ }
+
+ .emerald-nav-icon {
+ font-size: 20px !important;
+ }
+
+ .emerald-nav-label {
+ font-size: 11px;
+ }
+
+ .emerald-table-section {
+ margin: 20px 10px;
+ padding: 20px 15px;
+ }
+
+ .emerald-table th,
+ .emerald-table td {
+ padding: 10px 12px;
+ font-size: 13px;
+ }
+
+ .forum-toolbar {
+ padding: 12px 15px;
+ }
+
+ .search-section {
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ .forum-search-input {
+ border-radius: 20px;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ border-bottom: none;
+ }
+
+ .forum-search-btn {
+ border-radius: 20px;
+ border: 2px solid rgba(144, 238, 144, 0.3);
+ border-top: none;
+ width: 100%;
+ }
+
+ .post-detail-title {
+ font-size: 24px;
+ }
+
+ .post-detail-content {
+ font-size: 14px;
+ }
+
+ .reply-textarea {
+ padding: 15px;
+ }
+
+ .submit-reply-btn {
+ padding: 10px 20px;
+ font-size: 14px;
+ }
+}
diff --git a/front/src/SportPage.js b/front/src/SportPage.js
index 2874495..6fed422 100644
--- a/front/src/SportPage.js
+++ b/front/src/SportPage.js
@@ -1,39 +1,40 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
+import "./SharedStyles.css";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 体育地区标签
const areaTabs = [
- { label: "篮球", icon: <MovieIcon fontSize="small" /> },
- { label: "足球", icon: <EmailIcon fontSize="small" /> },
- { label: "羽毛球", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "排球", icon: <PersonIcon fontSize="small" /> },
- { label: "电竞", icon: <PersonIcon fontSize="small" /> },
+ { label: "篮球", value: "basketball" },
+ { label: "足球", value: "football" },
+ { label: "羽毛球", value: "badminton" },
+ { label: "排球", value: "volleyball" },
+ { label: "电竞", value: "esports" }
];
export default function SportPage() {
@@ -72,8 +73,8 @@
["其他类型1", "其他类型2"] // 其他
];
const sportTypes = sportTypesList[activeTab] || [];
-
useEffect(() => {
+ // 根据选中的标签获取体育列表
const area = areaTabs[activeTab].label;
fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
.then(res => res.json())
@@ -87,128 +88,212 @@
fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
.then(res => res.json())
.then(data => {
+ console.log('搜索返回数据:', data);
setSportList(data);
})
.catch(() => setSportList([]));
};
-
return (
- <div className="container">
- {/* 顶部空白与体育界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与体育界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "体育" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
</div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="sport-table">
- <thead>
- <tr>
- <th>体育类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {sportList.length > 0 ? (
- sportList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
) : (
- sportTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
)}
- </tbody>
- </table>
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "体育" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 体育内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">⚽ 体育资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux体育频道,这里有最新最热门的体育资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索体育资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div>
+
+ {/* 地区分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 体育列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>体育类型</th>
+ <th>标题</th>
+ <th>发布者</th>
+ <th>大小</th>
+ <th>热度</th>
+ <th>折扣倍率</th>
+ </tr>
+ </thead>
+ <tbody>
+ {sportList.length > 0 ? (
+ sportList.map((item, index) => (
+ <tr key={item.id || index}>
+ <td>{item.seedtag}</td>
+ <td>
+ <a href={`/torrent/${item.seedid}`}>
+ {item.title}
+ </a>
+ </td>
+ <td>{item.username}</td>
+ <td>{item.seedsize}</td>
+ <td>{item.downloadtimes}</td>
+ <td>{item.discount == null ? 1 : item.discount}</td>
+ </tr>
+ ))
+ ) : (
+ sportTypes.map((type, index) => (
+ <tr key={type}>
+ <td>{type}</td>
+ <td>
+ <a href={`/torrent/${type}`}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ <td>--</td>
+ <td>--</td>
+ <td>1</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div>
- <div style={{ height: 32 }} />
- <Pagination />
</div>
);
}
+// Pagination组件暂时不使用
function Pagination() {
const [page, setPage] = React.useState(3);
const total = 5;
diff --git a/front/src/TVPage.js b/front/src/TVPage.js
index d75a172..2d6a3a5 100644
--- a/front/src/TVPage.js
+++ b/front/src/TVPage.js
@@ -1,38 +1,40 @@
import React, { useState, useEffect } from "react";
import HomeIcon from "@mui/icons-material/Home";
import MovieIcon from "@mui/icons-material/Movie";
-import EmailIcon from "@mui/icons-material/Email";
+import TvIcon from "@mui/icons-material/Tv";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
-import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import AnimationIcon from "@mui/icons-material/Animation";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
import PersonIcon from "@mui/icons-material/Person";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import ForumIcon from "@mui/icons-material/Forum";
import HelpIcon from "@mui/icons-material/Help";
-import "./App.css";
+import "./SharedStyles.css";
import { useNavigate } from "react-router-dom";
import { API_BASE_URL } from "./config";
const navItems = [
- { label: "首页", icon: <HomeIcon />, path: "/home" },
- { label: "电影", icon: <MovieIcon />, path: "/movie" },
- { label: "剧集", icon: <EmailIcon />, path: "/tv" },
- { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
- { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
- { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
- { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
- { label: "资料", icon: <PersonIcon />, path: "/info" },
- { label: "论坛", icon: <ForumIcon />, path: "/forum" },
- { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
- { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
];
+// 剧集地区标签
const areaTabs = [
- { label: "国产电视剧", icon: <MovieIcon fontSize="small" /> },
- { label: "港剧", icon: <EmailIcon fontSize="small" /> },
- { label: "欧美剧", icon: <PersonIcon fontSize="small" /> },
- { label: "日韩剧", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "华语剧集", value: "chinese" },
+ { label: "港台剧集", value: "hk_tw" },
+ { label: "欧美剧集", value: "western" },
+ { label: "日韩剧集", value: "jp_kr" },
+ { label: "其他剧集", value: "others" }
];
export default function TVPage() {
@@ -90,124 +92,203 @@
["其他类型1", "其他类型2"] // 其他
];
const tvTypes = tvTypesList[activeTab] || [];
-
return (
- <div className="container">
- {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
- <div style={{ height: 80 }} />
- <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
- <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
- ) : (
- <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
- )}
- </div>
- <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>{userInfo.username || '用户栏'}</div>
- <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>{userPT.magic}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>{userPT.ratio}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>{userPT.upload}</b></span>
- <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>{userPT.download}</b></span>
- </div>
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
</div>
- {/* 下方内容整体下移,留出与音乐界面一致的间距 */}
- <div style={{ height: 32 }} />
- <nav className="nav-bar card">
- {navItems.map((item) => (
- <div
- key={item.label}
- className={item.label === "剧集" ? "nav-item active" : "nav-item"}
- onClick={() => navigate(item.path)}
- >
- {item.icon}
- <span>{item.label}</span>
- </div>
- ))}
- </nav>
- <div className="search-section card">
- <input
- className="search-input"
- placeholder="输入搜索关键词"
- value={searchText}
- onChange={e => setSearchText(e.target.value)}
- />
- <button className="search-btn" onClick={handleSearch}>
- <span role="img" aria-label="search">🔍</span>
- </button>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
</div>
- <div className="area-tabs" style={{ display: 'flex', justifyContent: 'center', gap: 24, margin: '18px 0' }}>
- {areaTabs.map((tab, idx) => (
- <div
- key={tab.label}
- className={activeTab === idx ? "area-tab active" : "area-tab"}
- onClick={() => setActiveTab(idx)}
- >
- {tab.icon} <span>{tab.label}</span>
- </div>
- ))}
- </div>
- <div className="table-section">
- <table className="movie-table">
- <thead>
- <tr>
- <th>剧集类型</th>
- <th>标题</th>
- <th>发布者</th>
- <th>大小</th>
- <th>热度</th>
- <th>折扣倍率</th>
- </tr>
- </thead>
- <tbody>
- {tvList.length > 0 ? (
- tvList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.username}</td>
- <td>{item.seedsize}</td>
- <td>{item.downloadtimes}</td>
- <td>{item.discount == null ? 1 : item.discount}</td>
- </tr>
- ))
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ {userInfo.avatar_url ? (
+ <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
) : (
- tvTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- <td>--</td>
- <td>--</td>
- <td>1</td>
- </tr>
- ))
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
)}
- </tbody>
- </table>
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div> {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "剧集" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 剧集内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">📺 剧集资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux剧集频道,这里有最新最热门的电视剧、综艺、纪录片资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索剧集资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div> {/* 地区分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 剧集列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>剧集类型</th>
+ <th>标题</th>
+ <th>发布者</th>
+ <th>大小</th>
+ <th>热度</th>
+ <th>折扣倍率</th>
+ </tr>
+ </thead>
+ <tbody>
+ {tvList.length > 0 ? (
+ tvList.map((item, index) => (
+ <tr key={item.id || index}>
+ <td>{item.seedtag}</td>
+ <td>
+ <a href={`/torrent/${item.seedid}`}>
+ {item.title}
+ </a>
+ </td>
+ <td>{item.username}</td>
+ <td>{item.seedsize}</td>
+ <td>{item.downloadtimes}</td>
+ <td>{item.discount == null ? 1 : item.discount}</td>
+ </tr>
+ ))
+ ) : (
+ tvTypes.map((type, index) => (
+ <tr key={type}>
+ <td>{type}</td>
+ <td>
+ <a href={`/torrent/${type}`}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ <td>--</td>
+ <td>--</td>
+ <td>1</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div>
- <div style={{ height: 32 }} />
- <Pagination />
</div>
);
}
+// Pagination组件暂时不使用
function Pagination() {
const [page, setPage] = React.useState(3);
const total = 5;
diff --git a/front/src/TvPage.js b/front/src/TvPage.js
new file mode 100644
index 0000000..5bac9f3
--- /dev/null
+++ b/front/src/TvPage.js
@@ -0,0 +1,284 @@
+import React, { useState, useEffect } from "react";
+import HomeIcon from "@mui/icons-material/Home";
+import MovieIcon from "@mui/icons-material/Movie";
+import TvIcon from "@mui/icons-material/Tv";
+import MusicNoteIcon from "@mui/icons-material/MusicNote";
+import AnimationIcon from "@mui/icons-material/Animation";
+import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
+import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
+import PersonIcon from "@mui/icons-material/Person";
+import AccountCircleIcon from "@mui/icons-material/AccountCircle";
+import ForumIcon from "@mui/icons-material/Forum";
+import HelpIcon from "@mui/icons-material/Help";
+import { useNavigate } from "react-router-dom";
+import "./SharedStyles.css";
+import { API_BASE_URL } from "./config";
+
+// 导航栏
+const navItems = [
+ { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
+ { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
+ { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
+ { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
+ { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
+ { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
+ { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
+ { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
+ { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
+ { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
+ { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
+];
+
+// 剧集地区标签
+const areaTabs = [
+ { label: "华语剧集", value: "chinese" },
+ { label: "港台剧集", value: "hk_tw" },
+ { label: "欧美剧集", value: "western" },
+ { label: "日韩剧集", value: "jp_kr" },
+ { label: "其他剧集", value: "others" }
+];
+
+export default function TvPage() {
+ const navigate = useNavigate();
+ const [searchText, setSearchText] = React.useState('');
+ const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
+ const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
+ const [activeTab, setActiveTab] = React.useState(0);
+ const [tvList, setTvList] = React.useState([]);
+
+ useEffect(() => {
+ const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
+ const userId = match ? match[2] : null;
+ if (!userId) return;
+ fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
+ .then(res => res.json())
+ .then(data => {
+ setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
+ setUserPT({
+ magic: data.magic_value || data.magic || 0,
+ ratio: data.share_ratio || data.share || 0,
+ upload: data.upload_amount || data.upload || 0,
+ download: data.download_amount || data.download || 0,
+ });
+ })
+ .catch(err => console.error('Fetching user profile failed', err));
+ }, []);
+
+ // 每个tab对应的剧集类型
+ const tvTypesList = [
+ ["华语电视剧", "华语综艺", "华语纪录片", "华语其他"], // 华语
+ ["港台电视剧", "港台综艺", "港台其他"], // 港台
+ ["欧美电视剧", "欧美综艺", "欧美纪录片", "欧美其他"], // 欧美
+ ["日韩电视剧", "日韩综艺", "日韩其他"], // 日韩
+ ["其他类型1", "其他类型2"] // 其他
+ ];
+ const tvTypes = tvTypesList[activeTab] || [];
+
+ React.useEffect(() => {
+ const area = areaTabs[activeTab].label;
+ fetch(`${API_BASE_URL}/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
+ .then(res => res.json())
+ .then(data => {
+ setTvList(data);
+ })
+ .catch(() => setTvList([]));
+ }, [activeTab]);
+
+ // 搜索按钮处理
+ const handleSearch = () => {
+ const area = areaTabs[activeTab].label;
+ fetch(`${API_BASE_URL}/api/search-seeds?tag=${encodeURIComponent(area)}&keyword=${encodeURIComponent(searchText)}`)
+ .then(res => res.json())
+ .then(data => {
+ setTvList(data);
+ })
+ .catch(() => setTvList([]));
+ };
+
+ return (
+ <div className="emerald-home-container">
+ {/* 流星雨背景效果 */}
+ <div className="meteor-shower">
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ <div className="meteor">✨</div>
+ <div className="meteor">🌟</div>
+ <div className="meteor">💫</div>
+ <div className="meteor">⭐</div>
+ </div>
+
+ {/* 浮动园林装饰元素 */}
+ <div className="floating-garden-elements">
+ <div className="garden-element">🌿</div>
+ <div className="garden-element">🦋</div>
+ <div className="garden-element">🌺</div>
+ <div className="garden-element">🌸</div>
+ </div>
+
+ <div className="emerald-content">
+ {/* NeuraFlux用户栏 */}
+ <div className="emerald-user-bar">
+ <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
+ <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
+ </div>
+ <div className="emerald-brand-section">
+ <div className="emerald-brand-icon">⚡</div>
+ <div className="emerald-user-label">NeuraFlux</div>
+ </div>
+ <div className="emerald-user-stats">
+ <span className="emerald-stat-item">
+ 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
+ </span>
+ <span className="emerald-stat-item">
+ 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
+ </span>
+ <span className="emerald-stat-item">
+ 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
+ </span>
+ </div>
+ </div>
+
+ {/* NeuraFlux导航栏 */}
+ <nav className="emerald-nav-bar">
+ {navItems.map((item) => (
+ <div
+ key={item.label}
+ className={`emerald-nav-item ${item.label === "剧集" ? "active" : ""}`}
+ data-type={item.type}
+ onClick={() => navigate(item.path)}
+ >
+ {item.icon}
+ <span className="emerald-nav-label">{item.label}</span>
+ </div>
+ ))}
+ </nav>
+
+ {/* 剧集内容区域 */}
+ <div className="emerald-content-section">
+ <h1 className="emerald-page-title">📺 剧集资源</h1>
+ <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
+ 欢迎来到NeuraFlux剧集频道,这里有最新最热门的电视剧、综艺、纪录片资源
+ </p>
+
+ {/* 搜索栏 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px'
+ }}>
+ <input
+ type="text"
+ placeholder="搜索剧集资源..."
+ value={searchText}
+ onChange={(e) => setSearchText(e.target.value)}
+ style={{
+ padding: '12px 20px',
+ borderRadius: '20px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: 'rgba(240, 255, 240, 0.5)',
+ fontSize: '16px',
+ width: '300px',
+ fontFamily: 'Lora, serif'
+ }}
+ />
+ <button
+ onClick={handleSearch}
+ style={{
+ padding: '12px 24px',
+ borderRadius: '20px',
+ border: 'none',
+ background: 'linear-gradient(135deg, #2d5016 0%, #90ee90 100%)',
+ color: 'white',
+ fontSize: '16px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif'
+ }}
+ >
+ 搜索
+ </button>
+ </div>
+
+ {/* 地区分类标签 */}
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ marginBottom: '30px',
+ gap: '15px',
+ flexWrap: 'wrap'
+ }}>
+ {areaTabs.map((tab, index) => (
+ <button
+ key={tab.value}
+ onClick={() => setActiveTab(index)}
+ style={{
+ padding: '10px 20px',
+ borderRadius: '15px',
+ border: '2px solid rgba(144, 238, 144, 0.3)',
+ background: activeTab === index
+ ? 'linear-gradient(135deg, #90ee90 0%, #2d5016 100%)'
+ : 'rgba(240, 255, 240, 0.3)',
+ color: activeTab === index ? 'white' : '#2d5016',
+ fontSize: '14px',
+ cursor: 'pointer',
+ fontFamily: 'Lora, serif',
+ transition: 'all 0.3s ease'
+ }}
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+
+ {/* 剧集列表 */}
+ <div className="emerald-table-section">
+ <table className="emerald-table">
+ <thead>
+ <tr>
+ <th>分类标签</th>
+ <th>剧集标题</th>
+ <th>热门指数</th>
+ <th>发布者</th>
+ </tr>
+ </thead>
+ <tbody>
+ {tvList.length > 0 ? (
+ tvList.map((tv, index) => (
+ <tr key={tv.id || index}>
+ <td>{tv.tags || areaTabs[activeTab].label}</td>
+ <td>
+ <a href={`/torrent/${tv.id || index}`}>
+ {tv.title || `剧集资源 ${index + 1}`}
+ </a>
+ </td>
+ <td>{tv.popularity || Math.floor(Math.random() * 100) + 1}</td>
+ <td>{tv.user?.username || '匿名用户'}</td>
+ </tr>
+ ))
+ ) : (
+ <tr>
+ <td colspan="4" style={{
+ textAlign: 'center',
+ color: '#666',
+ fontStyle: 'italic',
+ padding: '40px 20px'
+ }}>
+ 暂无{areaTabs[activeTab].label}资源,请稍后再试
+ </td>
+ </tr>
+ )}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+}