前段

Change-Id: I718d4d07ea03c6d2b6bcbd4d426c5d1af2201bf4
diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx
new file mode 100644
index 0000000..941210c
--- /dev/null
+++ b/src/components/Dashboard.jsx
@@ -0,0 +1,940 @@
+import React, { useEffect, useState } from 'react';

+import { useNavigate, useLocation,useParams } from 'react-router-dom';

+// import { getUserInfo } from '../api';  // 保留import但注释掉

+import { createTorrent, getTorrents} from '../api/torrent'; 

+import './Dashboard.css';

+import { createPost, getPosts } from '../api/helpPost';

+

+

+const Dashboard = ({ onLogout }) => {

+  const location = useLocation();

+  const [userInfo, setUserInfo] = useState(null);

+  const [loading, setLoading] = useState(false);

+  const [error, setError] = useState('');

+  const [currentSlide, setCurrentSlide] = useState(0);

+  const navigate = useNavigate();

+  const {tab} = useParams();

+  const [showUploadModal, setShowUploadModal] = useState(false);

+  const [isUploading, setIsUploading] = useState(false);

+  const [uploadData, setUploadData] = useState({

+    name: '',

+    type: '',

+    region: '',

+    subtitle: '',

+    resolution: '', // 新增分辨率字段

+    file: null,

+    description: ''

+  });

+  const [showPostModal, setShowPostModal] = useState(false);

+  const [postTitle, setPostTitle] = useState('');

+  const [postContent, setPostContent] = useState('');

+  const [selectedImage, setSelectedImage] = useState(null);

+  const [helpPosts, setHelpPosts] = useState([]);

+  const [helpLoading, setHelpLoading] = useState(false);

+  const [helpError, setHelpError] = useState(null);

+  const [currentPage, setCurrentPage] = useState(1);

+  const [totalPages, setTotalPages] = useState(1);

+

+    // 添加状态

+  const [torrentPosts, setTorrentPosts] = useState([]);

+  const [torrentLoading, setTorrentLoading] = useState(false);

+  const [torrentError, setTorrentError] = useState(null);

+  

+  const [filteredResources, setFilteredResources] = useState(torrentPosts);

+  

+  const activeTab = tab || 'announcement'; // 如果没有tab参数,则默认为announcement

+  // 从location.state中初始化状态

+  

+  

+  const handleTabChange = (tabName) => {

+    navigate(`/dashboard/${tabName}`, { 

+      state: { 

+        savedFilters: selectedFilters, // 使用新的筛选状态 // 保留现有状态

+        activeTab: tabName // 可选,如果其他组件依赖这个 state

+      } 

+    });

+  };

+  

+  //公告区

+  const [announcements] = useState([

+    {

+      id: 1,

+      title: '系统维护与更新',

+      content: '2023-10-15 02:00-06:00将进行系统维护升级,期间网站将无法访问。本次更新包含:\n1. 数据库服务器迁移\n2. 安全补丁更新\n3. CDN节点优化\n\n请提前做好下载安排。',

+      author: '系统管理员',

+      date: '2023-10-10',

+      excerpt: '2023-10-15 02:00-06:00将进行系统维护,期间无法访问',

+      category: '系统'

+    },

+    {

+      id: 2,

+      title: '资源上新',

+      content: '最新热门电影《奥本海默》4K REMUX资源已上线,包含:\n- 4K HDR版本 (56.8GB)\n- 1080P标准版 (12.3GB)\n- 中英双语字幕\n\n欢迎下载保种!',

+      author: '资源组',

+      date: '2023-10-08',

+      excerpt: '最新热门电影《奥本海默》4K资源已上线',

+      category: '资源'

+    },

+    {

+      id: 3,

+      title: '积分规则调整',

+      content: '自11月1日起,上传资源积分奖励提升20%,具体规则如下:\n- 上传电影资源:每GB 10积分\n- 上传电视剧资源:每GB 8积分\n- 上传动漫资源:每GB 6积分\n\n感谢大家的支持与贡献!',

+      author: '管理员',

+      date: '2023-10-05',

+      excerpt: '自11月1日起,上传资源积分奖励提升20%',

+      category: '公告'

+    },

+    {

+      id: 4,

+      title: '违规处理公告',

+      content: '用户user123因发布虚假资源已被封禁,相关资源已删除。请大家遵守社区规则,维护良好的分享环境。',

+      author: '管理员',

+      date: '2023-10-03',

+      excerpt: '用户user123因发布虚假资源已被封禁',

+      category: '违规'

+    },

+    {

+      id: 5,

+      title: '节日活动',

+      content: '国庆期间所有资源下载积分减半,活动时间:2023年10月1日至2023年10月7日。',

+      author: '活动组',

+      date: '2023-09-30',

+      excerpt: '国庆期间所有资源下载积分减半',

+      category: '活动'

+    },

+    {

+      id: 6,

+      title: '客户端更新',

+      content: 'PT客户端v2.5.0已发布,修复多个BUG,新增资源搜索功能。请尽快更新到最新版本以获得更好的使用体验。',

+      author: '开发组',

+      date: '2023-09-28',

+      excerpt: 'PT客户端v2.5.0已发布,修复多个BUG',

+      category: '更新'

+    },

+    // 其他公告...

+  ]);

+

+  

+  const handleAnnouncementClick = (announcement,e) => {

+    if (!e.target.closest('.exclude-click')) {

+      navigate(`/announcement/${announcement.id}`, {

+        state: {

+          announcement,

+          returnPath: `/dashboard/${activeTab}`,

+          scrollPosition: window.scrollY,

+          activeTab

+        }

+      });

+    }

+  };

+

+

+  //资源区

+ 

+

+  const handleFileChange = (e) => {

+    setUploadData({...uploadData, file: e.target.files[0]});

+  };

+

+  const handleUploadSubmit = async (e) => {

+    e.preventDefault();

+    

+    try {

+      setIsUploading(true);

+      const username = localStorage.getItem('username');

+      

+      // 创建种子数据

+      const torrentData = {

+        torrentName: uploadData.name,

+        category: uploadData.type,

+        regin: uploadData.region,

+        resolution: uploadData.resolution,

+        subtitle: uploadData.subtitle,

+        description: uploadData.description,

+        username: username,

+        filePath: "D:\\大学\\大三_下\\实训BT服务器下载\\G2-ptPlatform-backend\\torrents\\[电影天堂www.dytt89.com]两杆大烟枪BD中英双字.mp4.torrent" // 默认路径

+      };

+  

+      // 调用API创建种子

+      await createTorrent(

+        torrentData.torrentName,

+        torrentData.description,

+        torrentData.username,

+        torrentData.category,

+        torrentData.regin,

+        torrentData.resolution,

+        torrentData.subtitle,

+        torrentData.filePath

+      );

+      

+      // 上传成功处理

+      setShowUploadModal(false);

+      setUploadData({ 

+        name: '', 

+        type: '', 

+        region: '', 

+        subtitle: '', 

+        resolution: '', 

+        file: null, 

+        description: '' 

+      });

+      alert('种子创建成功!');

+      

+      // 刷新列表

+      fetchTorrentPosts(currentPage);

+      

+    } catch (error) {

+      console.error('创建失败:', error);

+      alert('创建失败: ' + (error.response?.data?.message || error.message));

+    } finally {

+      setIsUploading(false);

+    }

+  };

+

+  const handlePostSubmit = async (e) => {

+    e.preventDefault();

+    try {

+      const username = localStorage.getItem('username');

+      const response = await createPost(

+        postTitle,

+        postContent,

+        username

+      );

+      

+      if (response.data.code === 200) {

+        // 刷新帖子列表

+        await fetchHelpPosts();

+        // 重置表单

+        setShowPostModal(false);

+        setPostTitle('');

+        setPostContent('');

+        setSelectedImage(null);

+      } else {

+        setHelpError(response.data.message || '发帖失败');

+      }

+    } catch (err) {

+      setHelpError(err.message || '发帖失败');

+    }

+  };

+

+    // 获取Torrent帖子列表

+  const fetchTorrentPosts = async (page = 1) => {

+  setTorrentLoading(true);

+  try {

+    const response = await getTorrents(page);

+    setTorrentPosts(response.data.data.records);

+    setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条

+    setCurrentPage(page);

+  } catch (err) {

+    setTorrentError(err.message);

+  } finally {

+    setTorrentLoading(false);

+  }

+};

+

+  // 在useEffect中调用

+  useEffect(() => {

+    if (activeTab === 'share') {

+      fetchTorrentPosts();

+    }

+  }, [activeTab]);

+

+  const handleImageUpload = (e) => {

+    setSelectedImage(e.target.files[0]);

+  };

+

+

+

+

+  const fetchHelpPosts = async (page = 1) => {

+    setHelpLoading(true);

+    try {

+      const response = await getPosts(page);

+      if (response.data.code === 200) {

+        setHelpPosts(response.data.data.records);

+        setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条

+        setCurrentPage(page);

+      } else {

+        setHelpError(response.data.message || '获取求助帖失败');

+      }

+    } catch (err) {

+      setHelpError(err.message || '获取求助帖失败');

+    } finally {

+      setHelpLoading(false);

+    }

+  };

+  useEffect(() => {

+    if (activeTab === 'help') {

+      fetchHelpPosts(currentPage);

+    }

+  }, [activeTab, currentPage]); // 添加 currentPage 作为依赖

+

+

+  

+

+  // 分类维度配置

+  const filterCategories = {

+    type: {

+      label: '类型',

+      options: {

+        'all': '全部',

+        '电影': '电影',

+        '电视剧': '电视剧',

+        '动漫': '动漫',

+        '综艺': '综艺'

+      }

+    },

+    subtitle: {

+      label: '字幕',

+      options: {

+        'all': '全部',

+        'yes': '有字幕',

+        'no': '无字幕'

+      }

+    },

+    region: {

+      label: '地区',

+      options: {

+        'all': '全部',

+        'cn': '大陆',

+        'us': '欧美',

+        'jp': '日本'

+      }

+    }

+  };

+  

+  const [selectedFilters, setSelectedFilters] = useState(

+    location.state?.savedFilters || 

+    Object.keys(filterCategories).reduce((acc, category) => {

+      acc[category] = 'all';

+      return acc;

+    }, {})

+  );

+

+

+

+// 处理筛选条件变更

+const handleFilterSelect = (category, value) => {

+  setSelectedFilters(prev => ({

+    ...prev,

+    [category]: prev[category] === value ? null : value // 点击已选中的则取消

+  }));

+};

+

+//应用筛选条件

+const applyFilters = () => {

+  const result = torrentPosts.filter(resource => {

+    return Object.entries(selectedFilters).every(([category, selectedValue]) => {

+      if (selectedValue === 'all') return true;

+      if (category === 'subtitle') {

+        return resource.subtitle === (selectedValue === 'yes');

+      }

+      return resource[category] === selectedValue;

+    });

+  });

+  setFilteredResources(result);

+};

+

+

+  // 恢复滚动位置

+  useEffect(() => {

+    if (location.state?.scrollPosition) {

+      window.scrollTo(0, location.state.scrollPosition);

+    }

+  }, [location.state]);

+

+

+  useEffect(() => {

+    const token = localStorage.getItem('token');

+    if (!token) {

+      navigate('/login');

+      return;

+    }

+

+    /* 保留但注释掉实际的用户信息获取

+    const fetchUserInfo = async () => {

+      try {

+        const response = await getUserInfo(token);

+        if (response.data.code === 200) {

+          setUserInfo(response.data.data);

+        } else {

+          setError('获取用户信息失败');

+        }

+      } catch (err) {

+        setError('获取用户信息失败');

+      } finally {

+        setLoading(false);

+      }

+    };

+

+    fetchUserInfo();

+    */

+    

+    // 模拟用户信息

+    setUserInfo({ 

+      name: localStorage.getItem('username') || '演示用户', // 确保这里读取的是最新值

+    avatar: 'https://via.placeholder.com/40'

+    });

+    setLoading(false);

+  }, [navigate]);

+

+  // 轮播图自动切换效果

+  useEffect(() => {

+    if (activeTab === 'announcement') {

+      const timer = setInterval(() => {

+        setCurrentSlide(prev => (prev + 1) % 3); // 3张轮播图循环

+      }, 3000);

+      return () => clearInterval(timer);

+    }

+  }, [activeTab]);

+

+  useEffect(() => {

+    if (activeTab === 'help') {

+      fetchHelpPosts();

+    }

+  }, [activeTab]);

+

+  const renderContent = () => {

+    switch(activeTab) {

+      case 'announcement':

+        return (

+          <div className="content-area" data-testid="announcement-section"> 

+            {/* 轮播图区域 */}

+            <div className="carousel-container">

+              <div className={`carousel-slide ${currentSlide === 0 ? 'active' : ''}`}>

+                <div className="carousel-image gray-bg">促销活动1</div>

+              </div>

+              <div className={`carousel-slide ${currentSlide === 1 ? 'active' : ''}`}>

+                <div className="carousel-image gray-bg">促销活动2</div>

+              </div>

+              <div className={`carousel-slide ${currentSlide === 2 ? 'active' : ''}`}>

+                <div className="carousel-image gray-bg">促销活动3</div>

+              </div>

+              <div className="carousel-dots">

+                <span className={`dot ${currentSlide === 0 ? 'active' : ''}`}></span>

+                <span className={`dot ${currentSlide === 1 ? 'active' : ''}`}></span>

+                <span className={`dot ${currentSlide === 2 ? 'active' : ''}`}></span>

+              </div>

+            </div>

+

+            {/* 公告区块区域 */}

+            <div className="announcement-grid">

+              {announcements.map(announcement => (

+                <div 

+                  key={announcement.id}

+                  className="announcement-card"

+                  onClick={(e) => handleAnnouncementClick(announcement, e)}

+                >

+                  <h3>{announcement.title}</h3>

+                  <p>{announcement.excerpt}</p>

+                  <div className="announcement-footer exclude-click">

+                    <span>{announcement.author}</span>

+                    <span>{announcement.date}</span>

+                  </div>

+                </div>

+              ))}

+            </div>

+          </div>

+        );

+        case 'share':

+          return (

+            <div className="content-area" data-testid="share-section">

+              {/* 上传按钮 - 添加在筛选区上方 */}

+              <div className="upload-header">

+                <button 

+                  className="upload-btn"

+                  onClick={() => setShowUploadModal(true)}

+                >

+                  + 上传种子

+                </button>

+              </div>

+              {/* 分类筛选区 */}

+              <div className="filter-section">

+                {Object.entries(filterCategories).map(([category, config]) => (

+                  <div key={category} className="filter-group">

+                    <h4>{config.label}:</h4>

+                    <div className="filter-options">

+                      {Object.entries(config.options).map(([value, label]) => (

+                        <button

+                          key={value}

+                          className={`filter-btn ${

+                            selectedFilters[category] === value ? 'active' : ''

+                          }`}

+                          onClick={() => handleFilterSelect(category, value)}

+                        >

+                          {label}

+                        </button>

+                      ))}

+                    </div>

+                  </div>

+                ))}

+        

+                <button 

+                  className="confirm-btn"

+                  onClick={applyFilters}

+                >

+                  确认筛选

+                </button>

+              </div>

+        

+              {/* 上传弹窗 */}

+              {showUploadModal && (

+                <div className="modal-overlay">

+                  <div className="upload-modal">

+                    <h3>上传新种子</h3>

+                    <button 

+                      className="close-btn"

+                      onClick={() => setShowUploadModal(false)}

+                    >

+                      ×

+                    </button>

+                    

+                    <form onSubmit={handleUploadSubmit}>

+                      <div className="form-group">

+                        <label>种子名称</label>

+                        <input

+                          type="text"

+                          value={uploadData.name}

+                          onChange={(e) => setUploadData({...uploadData, name: e.target.value})}

+                          required

+                        />

+                      </div>

+        

+                      <div className="form-group">

+                        <label>资源类型</label>

+                        <select

+                          value={uploadData.type}

+                          onChange={(e) => setUploadData({...uploadData, type: e.target.value})}

+                          required

+                        >

+                          <option value="">请选择</option>

+                          <option value="电影">电影</option>

+                          <option value="电视剧">电视剧</option>

+                          <option value="动漫">动漫</option>

+                          <option value="综艺">综艺</option>

+                          <option value="音乐">音乐</option>

+                        </select>

+                      </div>

+        

+                      {/* 新增地区输入框 */}

+                      <div className="form-group">

+                        <label>地区</label>

+                        <input

+                          type="text"

+                          value={uploadData.region || ''}

+                          onChange={(e) => setUploadData({...uploadData, region: e.target.value})}

+                          placeholder="例如: 美国, 中国, 日本等"

+                          required

+                        />

+                      </div>

+

+                      {/* 添加分辨率下拉框 */}

+                      <div className="form-group">

+                        <label>分辨率</label>

+                        <select

+                          value={uploadData.resolution || ''}

+                          onChange={(e) => setUploadData({...uploadData, resolution: e.target.value})}

+                          required

+                        >

+                          <option value="">请选择</option>

+                          <option value="4K">4K</option>

+                          <option value="2K">2K</option>

+                          <option value="1080P">1080P</option>

+                          <option value="720P">720P</option>

+                          <option value="SD">SD</option>

+                          <option value="无损音源">无损音源</option>

+                          <option value="杜比全景声">杜比全景声</option>

+                          <option value="其他">其他</option>

+                        </select>

+                      </div>

+

+                    

+        

+                      {/* 新增字幕语言下拉框 */}

+                      <div className="form-group">

+                        <label>字幕语言</label>

+                        <select

+                          value={uploadData.subtitle || ''}

+                          onChange={(e) => setUploadData({...uploadData, subtitle: e.target.value})}

+                          required

+                        >

+                          <option value="">请选择</option>

+                          <option value="无需字幕">无需字幕</option>

+                          <option value="暂无字幕">暂无字幕</option>

+                          <option value="自带中文字幕">自带中文字幕</option>

+                          <option value="自带双语字幕(含中文)">自带双语字幕(含中文)</option>

+                          <option value="附件中文字幕">附件中文字幕</option>

+                          <option value="附件双语字幕">附件双语字幕</option>

+                        </select>

+                      </div>

+        

+                      <div className="form-group">

+                        <label>种子文件</label>

+                        <input

+                          type="file"

+                          accept=".torrent"

+                          onChange={handleFileChange}

+

+                        />

+                      </div>

+        

+                      <div className="form-group">

+                        <label>简介</label>

+                        <textarea

+                          value={uploadData.description}

+                          onChange={(e) => setUploadData({...uploadData, description: e.target.value})}

+                        />

+                      </div>

+        

+                      <div className="form-actions">

+                        <button 

+                          type="button"

+                          className="cancel-btn"

+                          onClick={() => setShowUploadModal(false)}

+                        >

+                          取消

+                        </button>

+                        <button 

+                          type="submit" 

+                          className="confirm-btn"

+                          disabled={isUploading}

+                        >

+                          {isUploading ? '上传中...' : '确认上传'}

+                        </button>

+                      </div>

+                    </form>

+                  </div>

+                </div>

+              )}

+              

+              <div className="resource-list">

+                {torrentPosts.map(torrent => (

+                  <div 

+                    key={torrent.id}

+                    className="resource-item"

+                    onClick={() => navigate(`/torrent/${torrent.id}`)}

+                  >

+                    <div className="resource-poster">

+                      <div className="poster-image gray-bg">{torrent.torrentName.charAt(0)}</div>

+                    </div>

+                    <div className="resource-info">

+                      <h3 className="resource-title">{torrent.torrentName}</h3>

+                      <p className="resource-meta">

+                        {torrent.resolution} | {torrent.region} | {torrent.category}

+                      </p>

+                      <p className="resource-subtitle">字幕: {torrent.subtitle}</p>

+                    </div>

+                    <div className="resource-stats">

+                      <span className="stat">{torrent.size}</span>

+                      <span className="stat">发布者: {torrent.username}</span>

+                    </div>

+                    <button 

+                      className="download-btn"

+                      onClick={(e) => {

+                        e.stopPropagation();

+                        // 下载逻辑

+                      }}

+                    >

+                      立即下载

+                    </button>

+                  </div>

+                ))}

+              </div>

+

+              {/* 分页控件 */}

+              <div className="pagination">

+                <button 

+                  onClick={() => fetchTorrentPosts(currentPage - 1)} 

+                  disabled={currentPage === 1}

+                >

+                  上一页

+                </button>

+                

+                {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (

+                  <button

+                    key={page}

+                    onClick={() => fetchTorrentPosts(page)}

+                    className={currentPage === page ? 'active' : ''}

+                  >

+                    {page}

+                  </button>

+                ))}

+                

+                <button 

+                  onClick={() => fetchTorrentPosts(currentPage + 1)} 

+                  disabled={currentPage === totalPages}

+                >

+                  下一页

+                </button>

+              </div>

+            </div>

+          );

+      // 在Dashboard.jsx的renderContent函数中修改case 'request'部分

+      case 'request':

+        return (

+          <div className="content-area" data-testid="request-section">

+            {/* 求种区帖子列表 */}

+            <div className="request-list">

+              {[

+                {

+                  id: 1,

+                  title: '求《药屋少女的呢喃》第二季全集',

+                  content: '求1080P带中文字幕版本,最好是内嵌字幕不是外挂的',

+                  author: '动漫爱好者',

+                  authorAvatar: 'https://via.placeholder.com/40',

+                  date: '2023-10-15',

+                  likeCount: 24,

+                  commentCount: 8

+                },

+                {

+                  id: 2,

+                  title: '求《奥本海默》IMAX版',

+                  content: '最好是原盘或者高码率的版本,谢谢各位大佬',

+                  author: '电影收藏家',

+                  authorAvatar: 'https://via.placeholder.com/40',

+                  date: '2023-10-14',

+                  likeCount: 15,

+                  commentCount: 5

+                }

+              ].map(post => (

+                <div 

+                  key={post.id} 

+                  className="request-post"

+                  onClick={() => navigate(`/request/${post.id}`)}

+                >

+                  <div className="post-header">

+                    <img src={post.authorAvatar} alt={post.author} className="post-avatar" />

+                    <div className="post-author">{post.author}</div>

+                    <div className="post-date">{post.date}</div>

+                  </div>

+                  <h3 className="post-title">{post.title}</h3>

+                  <p className="post-content">{post.content}</p>

+                  <div className="post-stats">

+                    <span className="post-likes">👍 {post.likeCount}</span>

+                    <span className="post-comments">💬 {post.commentCount}</span>

+                  </div>

+                </div>

+              ))}

+            </div>

+          </div>

+        );

+      // 在Dashboard.jsx的renderContent函数中修改case 'help'部分

+      case 'help':

+        return (

+          <div className="content-area" data-testid="help-section">

+            {/* 新增发帖按钮 */}

+            <div className="post-header">

+              <button 

+                className="create-post-btn"

+                onClick={() => setShowPostModal(true)}

+              >

+                + 发帖求助

+              </button>

+            </div>

+

+            {/* 加载状态和错误提示 */}

+            {helpLoading && <div className="loading">加载中...</div>}

+            {helpError && <div className="error">{helpError}</div>}

+

+            {/* 求助区帖子列表 */}

+            <div className="help-list">

+              {helpPosts.map(post => (

+                <div 

+                  key={post.id} 

+                  className={`help-post ${post.isSolved ? 'solved' : ''}`}

+                  onClick={() => navigate(`/help/${post.id}`)}

+                >

+                  <div className="post-header">

+                    <img 

+                      src={post.authorAvatar || 'https://via.placeholder.com/40'} 

+                      alt={post.authorId} 

+                      className="post-avatar" 

+                    />

+                    <div className="post-author">{post.authorId}</div>

+                    <div className="post-date">

+                      {new Date(post.createTime).toLocaleDateString()}

+                    </div>

+                    {post.isSolved && <span className="solved-badge">已解决</span>}

+                  </div>

+                  <h3 className="post-title">{post.title}</h3>

+                  <p className="post-content">{post.content}</p>

+                  <div className="post-stats">

+                    <span className="post-likes">👍 {post.likeCount || 0}</span>

+                    <span className="post-comments">💬 {post.replyCount || 0}</span>

+                  </div>

+                </div>

+              ))}

+            </div>

+

+            {/* 在帖子列表后添加分页控件 */}

+            <div className="pagination">

+              <button 

+                onClick={() => fetchHelpPosts(currentPage - 1)} 

+                disabled={currentPage === 1}

+              >

+                上一页

+              </button>

+              

+              {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (

+                <button

+                  key={page}

+                  onClick={() => fetchHelpPosts(page)}

+                  className={currentPage === page ? 'active' : ''}

+                >

+                  {page}

+                </button>

+              ))}

+              

+              <button 

+                onClick={() => fetchHelpPosts(currentPage + 1)} 

+                disabled={currentPage === totalPages}

+              >

+                下一页

+              </button>

+            </div>

+        

+            {/* 新增发帖弹窗 */}

+            {showPostModal && (

+              <div className="post-modal-overlay">

+                <div className="post-modal">

+                  <h3>发布求助帖</h3>

+                  <button 

+                    className="modal-close-btn"

+                    onClick={() => setShowPostModal(false)}

+                  >

+                    ×

+                  </button>

+                  

+                  <form onSubmit={handlePostSubmit}>

+                    <div className="form-group">

+                      <label>帖子标题</label>

+                      <input

+                        type="text"

+                        value={postTitle}

+                        onChange={(e) => setPostTitle(e.target.value)}

+                        placeholder="请输入标题"

+                        required

+                      />

+                    </div>

+        

+                    <div className="form-group">

+                      <label>帖子内容</label>

+                      <textarea

+                        value={postContent}

+                        onChange={(e) => setPostContent(e.target.value)}

+                        placeholder="详细描述你的问题"

+                        required

+                      />

+                    </div>

+        

+                    <div className="form-group">

+                      <label>上传图片</label>

+                      <div className="upload-image-btn">

+                        <input

+                          type="file"

+                          id="image-upload"

+                          accept="image/*"

+                          onChange={handleImageUpload}

+                          style={{ display: 'none' }}

+                        />

+                        <label htmlFor="image-upload">

+                          {selectedImage ? '已选择图片' : '选择图片'}

+                        </label>

+                        {selectedImage && (

+                          <span className="image-name">{selectedImage.name}</span>

+                        )}

+                      </div>

+                    </div>

+        

+                    <div className="form-actions">

+                      <button 

+                        type="button"

+                        className="cancel-btn"

+                        onClick={() => setShowPostModal(false)}

+                      >

+                        取消

+                      </button>

+                      <button 

+                        type="submit" 

+                        className="submit-btn"

+                      >

+                        确认发帖

+                      </button>

+                    </div>

+                  </form>

+                </div>

+              </div>

+            )}

+          </div>

+        );

+      default:

+        return <div className="content-area" data-testid="default-section">公告区内容</div>;

+    }

+  };

+

+  if (loading) return <div className="loading">加载中...</div>;

+  if (error) return <div className="error">{error}</div>;

+

+  return (

+    <div className="dashboard-container" data-testid="dashboard-container">

+      {/* 顶部栏 */}

+      <div className="top-bar" data-testid="top-bar">

+        {/* 搜索框 */}

+        <div className="search-container">

+          <input 

+            type="text" 

+            placeholder="搜索种子、用户..." 

+            className="search-input"

+          />

+          <button className="search-button">搜索</button>

+        </div>

+        

+        <div className="user-info" data-testid="user-info">

+          <img 

+            src={userInfo?.avatar || 'https://via.placeholder.com/40'} 

+            alt="用户头像" 

+            className="user-avatar"

+            onClick={() => navigate('/personal')}  // 添加点击跳转

+            style={{ cursor: 'pointer' }}  // 添加手型指针

+          />

+          <span className="username">{userInfo?.name || '用户'}</span>

+          <button onClick={onLogout} className="logout-button">退出</button>

+        </div>

+      </div>

+      

+      {/* 导航栏 */}

+      {/* handleTabchange函数替换了原本的setactivetab函数 */}

+      <div className="nav-tabs">

+        <button 

+          className={`tab-button ${activeTab === 'announcement' ? 'active' : ''}`}

+          onClick={() => handleTabChange('announcement')}

+        >

+          公告区

+        </button>

+        <button 

+          className={`tab-button ${activeTab === 'share' ? 'active' : ''}`}

+          onClick={() => handleTabChange('share')}

+        >

+          分享区

+        </button>

+        <button 

+          className={`tab-button ${activeTab === 'request' ? 'active' : ''}`}

+          onClick={() => handleTabChange('request')}

+        >

+          求种区

+        </button>

+        <button 

+          className={`tab-button ${activeTab === 'help' ? 'active' : ''}`}

+          onClick={() => handleTabChange('help')}

+        >

+          求助区

+        </button>

+      </div>

+      

+      {/* 内容区 */}

+      {renderContent()}

+    </div>

+  );

+};

+

+export default Dashboard;
\ No newline at end of file