添加了postsPanel作为通用帖子显示板,增加了对jest测试的配置,添加了论坛主页,设定了论坛全局框架,设定了论坛基础主题色及主题切换、字号切换逻辑

Change-Id: I9fad0cf577088adb00c9850d405ccd23e6072413
diff --git a/src/views/forum/index.module.css b/src/views/forum/index.module.css
index 53cf91c..5cd586a 100644
--- a/src/views/forum/index.module.css
+++ b/src/views/forum/index.module.css
@@ -1,12 +1,80 @@
-.selfStatus{
-    width:25%;
-    height:45%;
-    position: absolute;
-    right:0%;
-    top:0%;
-    
+/* index.module.css */
+.container {
+    width: 100%;
+    height: 100%;
+    position: relative; /* 新增 */
 }
-.container{
+.up{
+    width: 100%;
+    height: 50%;
+    position: relative; /* 新增 */
+    top: 0%;
+    display: flex;
+    flex-direction: row;
+    border-radius: 8px;
+}
+
+.down{
+    height:48%;
+    width:100%;
+    bottom:0%;
+    display:flex;
+    flex-direction:row;
+}
+
+
+.upright{
+    width:25%;
+}
+.upleft{
+    height:100%;
+    width:75%;
+    margin:5px;
+    display:flex;
+    flex-direction:column;
+}
+
+.upcontent{
+    display:flex;
+    flex-direction: row;
     width:100%;
     height:100%;
+}
+
+.advertisements {
+    width:40%;
+    margin: 5px;
+    border-radius: 8px;
+    overflow: hidden;
+}
+
+.adImage {
+    width: 100%;
+    height: 99%;
+    object-fit: fill;
+    border-radius: 8px;
+}
+
+
+.hotPosts{
+    width:60%;
+    margin:5px;
+}
+
+
+.selfStatus {
+    width: 100%;
+    height: 100%;
+    position: relative; /* 改为绝对定位 */
+    
+    border-radius: 8px;
+}
+
+.newPost,
+.likePost,
+.forsalePost {
+
+    flex:1;
+    margin:5px;
+    border-radius: 8px;
 }
\ No newline at end of file
diff --git a/src/views/forum/index.tsx b/src/views/forum/index.tsx
index dbceffd..345f880 100644
--- a/src/views/forum/index.tsx
+++ b/src/views/forum/index.tsx
@@ -3,14 +3,65 @@
 import SelfStatus from "@/components/selfStatus/selfStatus";
 
 import style from "./index.module.css";
+import Navbar from "@/components/navbar/navbar";
+import PostsPanel from "@/components/postsPanel/postsPanel";
+import { hotPosts } from "@/api/post";
+import { Carousel } from 'antd';
+import ad1 from '&/assets/ad1.png'
+import ad2 from '&/assets/ad2.png'
+import { useEffect } from "react";
 
 export default function Forum() {
+    useEffect(() => {
+        // 禁止滚动
+        document.body.style.overflow = 'hidden';
 
-
+        // 组件卸载时恢复滚动
+        return () => {
+            document.body.style.overflow = 'auto';
+        };
+    }, []);
+    
+    
     return (
         <div className={style.container}>
-            <div className={style.selfStatus}>
-                <SelfStatus />
+            <div className={style.up}>
+               <div className={style.upleft}>
+                <div className={style.navbar}>
+                    <Navbar/>
+                </div>
+                <div className={style.upcontent}>
+                    <div className={style.advertisements}>
+                        <Carousel arrows infinite={false}>
+                            <div>
+                                <img src={ad1} alt="广告1" className={style.adImage} />
+                            </div>
+                            <div>
+                                <img src={ad2} alt="广告2" className={style.adImage} />
+                            </div>
+                        </Carousel>
+                    </div>
+                    <div className={style.hotPosts}>
+                        <PostsPanel name='热门种子' url={hotPosts} limit={5}/>
+                    </div>
+                </div>
+               </div>
+                <div className={style.upright}>
+                    <div className={style.selfStatus}>
+                        <SelfStatus />
+                    </div>
+                </div> 
+            </div>
+            <div className={style.down}>
+                <div className={style.newPost}>
+                    <PostsPanel name='最新发布' url={hotPosts} limit={5}/>
+                </div>
+                <div className={style.likePost}>
+                    <PostsPanel name='猜你喜欢' url={hotPosts} limit={5}/>
+                </div>
+                <div className={style.forsalePost}>
+                    <PostsPanel name='促销种子' url={hotPosts} limit={5}/>
+                </div>
             </div>
         </div>
     );
diff --git a/src/views/frame/frame.module.css b/src/views/frame/frame.module.css
new file mode 100644
index 0000000..91967f8
--- /dev/null
+++ b/src/views/frame/frame.module.css
@@ -0,0 +1,63 @@
+
+
+.header{
+    display:flex;
+    justify-content: space-between;
+    align-items: center;
+    height:8%;
+    background-color: var(--bg-color);
+    width: 100%;
+    overflow:hidden;
+}
+
+.header .logo{
+    width: 100px; /* Set a fixed width for the logo */
+    height: auto; /* Maintain aspect ratio */
+    left:0;
+    margin:10px;
+}
+
+.header .searchInput{
+    border:1px solid rgb(197, 193, 194);
+    width: 60%;
+    height:50%;
+    padding: 5px 10px;
+    border-radius: 5px;
+    font-size: 1rem;
+    color: var(--text-color);
+    background-color: var(--bg-color);
+    transition: all 0.1s ease-in-out;
+}
+
+.header .toollist{
+    align-content: center;
+    right:0;
+    gap:10px;
+    margin-right:10px;
+}
+
+.header .toollist > *{
+    padding: 5px 10px;
+    width:auto;
+    font-size:150%;
+    user-select: none;
+    color: var(--text-color);
+}
+
+.header .toollist > *:hover{
+    background-color: rgb(197, 193, 194);
+    border-radius: 5px;
+    cursor: pointer;
+    font-size:160%;
+    transition: all 0.1s ease-in-out;
+    color: var(--text-color);
+}
+
+.container{
+    height:92vh;
+    background-color:var(--bg-color);
+    display:flex;
+    flex-direction:column;
+    overflow: auto;
+    width:100%;
+}
\ No newline at end of file
diff --git a/src/views/frame/frame.tsx b/src/views/frame/frame.tsx
new file mode 100644
index 0000000..c0c2e0e
--- /dev/null
+++ b/src/views/frame/frame.tsx
@@ -0,0 +1,55 @@
+import React from "react";
+import { Outlet } from "react-router";
+import { useEffect, useState } from "react";
+import { 
+    SearchOutlined, 
+    FontSizeOutlined, 
+    MessageOutlined, 
+    SunOutlined, 
+    MoonOutlined
+ } from "@ant-design/icons";
+import style from "./frame.module.css";
+import logo from "&/assets/logo.png";
+import { useAppDispatch } from "@/hooks/store";
+import { useSelector } from "react-redux";
+const Frame:React.FC = () => {
+
+    const dispatch = useAppDispatch();
+
+    const showSearch = useSelector((state: any) => state.setting.showSearch); 
+    const theme= useSelector((state: any) => state.setting.theme);
+    const toggleSearch = () => {
+        dispatch({ type: "setting/toggleSearch" });
+    }
+
+    const toggleFontSize = () => {
+        dispatch({ type: "setting/toggleFontSize" });
+    };
+
+    const toggleTheme = () => {
+        dispatch({ type: "setting/toggleTheme" });
+    };
+
+
+    return (
+        <div style={{ display: 'block', height: '100vh' }}>
+            <header className={style.header}>
+                <img className={style.logo} src={logo} alt="website logo"></img>
+                {showSearch && (<input className={style.searchInput} placeholder="输入关键词进行搜索"/>)}
+                <div className={style.toollist}>
+                    <SearchOutlined onClick={toggleSearch}/>
+                    <FontSizeOutlined onClick={toggleFontSize}/>
+                    <MessageOutlined />
+                    {theme === 'dark' ? <MoonOutlined onClick={toggleTheme}/> : <SunOutlined onClick={toggleTheme}/>}
+                </div>
+            </header>
+            <div className={style.container}>
+                <Outlet/>
+            </div>
+            
+            
+        </div>
+    );
+}
+
+export default Frame;
\ No newline at end of file
diff --git a/src/views/login/login.tsx b/src/views/login/login.tsx
index 26b7842..bd429c7 100644
--- a/src/views/login/login.tsx
+++ b/src/views/login/login.tsx
@@ -8,21 +8,21 @@
 import { useState } from 'react';
 import { useSelector } from 'react-redux';
 import { useNavigate } from 'react-router';
-import logo from '&/asserts/logo.png';
+import logo from '&/assets/logo.png';
 import { getUserInfo } from '@/api/user';
-
+import debounce from 'lodash/debounce';
 
 const Login: React.FC = () => {
     const [email, setEmail] = useState('');
     const [password, setPassword] = useState('');
     const dispatch = useAppDispatch();
     const { refresh: postUserLoginRefresh } = useApi(() => request.post(postUserLogin, {}), false);
-    const { refresh: getUserInfoRefresh } = useApi(async () => await request.get(getUserInfo), false);
+    const { refresh: getUserInfoRefresh } = useApi(() => request.get(getUserInfo), false);
 
     const nav = useNavigate();
-    const handleLogin = async () => {
+    const handleLogin = debounce(async () => {
         try {
-            const res = await postUserLoginRefresh();
+            const res =await postUserLoginRefresh();
             if (res==null ||(res as any).error) {
                 alert('Login failed. Please check your credentials.');
                 return;
@@ -44,14 +44,17 @@
               console.error('Unknown error occurred');
             }
         }
-    };
+    }, 1000) as () => void;
 
+    const handleLogoClick = () => {
+        nav('/');
+    }
     return (
         <div className={style.form}>
-            <img className={style.logo} src={logo} alt="logo"></img>
+            <img className={style.logo} src={logo} alt="logo" onClick={handleLogoClick}></img>
             <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} className={style.email} placeholder="Enter your email" />
             <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} className={style.password} placeholder="Enter your password" />
-            <button className={style.submit} onClick={handleLogin}>登录</button>
+            <button className={style.submit} onClick={() => handleLogin()}>登录</button>
             <button className={style.register}>注册</button>
             <button className={style.forget}> 忘记密码</button>
         </div>