重新提交

Change-Id: I41d894c30f6945402022f7309d52d9dfc0ff4c79
diff --git a/nginx.conf b/nginx.conf
index d96b07b..76a4aae 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -1,17 +1,15 @@
 server {
     listen 80; # 代理默认端口,可改
-    server_name localhost;
+    server_name team2.10813352.xyz;
  
     root /var/www/html;
     index index.html;
  
-    location / {
-        try_files $uri $uri/ /index.html;
-    }
+    
  
     # 代理 /api/v1/ 到后端服务
     location /api/v1/ {
-        proxy_pass http://team2.10813352.xyz:8088; # 你的后端暴露位置
+        proxy_pass http://localhost:8088; # 你的后端暴露位置
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection 'upgrade';
@@ -19,8 +17,8 @@
         proxy_cache_bypass $http_upgrade;
     }
  
-    location = /favicon.ico { log_not_found off; access_log off; }
-    location = /robots.txt { log_not_found off; access_log off; allow all; }
+    location = /favicon.ico { log_not_found off}; access_log off; }
+    location = /robots.txt { log_not_found off}; access_log off; allow all; }
     location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
         expires max;
         log_not_found off;
diff --git a/src/api/administer.js b/src/api/administer.js
index 5f28e45..d90bffa 100644
--- a/src/api/administer.js
+++ b/src/api/administer.js
@@ -1,10 +1,10 @@
 import axios from 'axios';
 
-const API_BASE_URL = 'http://localhost:8088'; // 替换为你的后端API基础URL
+// const API_BASE_URL = 'http://team2.10813352.xyz:8088'; // 替换为你的后端API基础URL
 
 export const getAllUsers = async () => {
   try {
-    const response = await axios.get(`${API_BASE_URL}/user/allUser`, {
+    const response = await axios.get(`/user/allUser`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -27,7 +27,7 @@
 
 export const searchUsers = async (key) => {
   try {
-    const response = await axios.get(`${API_BASE_URL}/user/searchUser`, {
+    const response = await axios.get(`/user/searchUser`, {
       params: { key },
       headers: {
         Authorization: localStorage.getItem('token')
@@ -50,7 +50,7 @@
 // 修改用户权限
 export const updateUserAuthority = async (username, authority) => {
   try {
-    const response = await axios.put(`${API_BASE_URL}/user/changeAuthority`, 
+    const response = await axios.put(`/user/changeAuthority`, 
       { 
         changeUsername: username, 
         authority: authority 
@@ -113,7 +113,7 @@
 // 修改 getAllDiscounts 和 getCurrentDiscount 方法
 export const getAllDiscounts = async () => {
   try {
-    const response = await axios.get(`${API_BASE_URL}/discount/all`, {
+    const response = await axios.get(`/discount/all`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -133,7 +133,7 @@
 
 export const getCurrentDiscount = async () => {
   try {
-    const response = await axios.get(`${API_BASE_URL}/discount/current`, {
+    const response = await axios.get(`/discount/current`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -156,7 +156,7 @@
 // 添加折扣
 export const addDiscount = async (discountData) => {
   try {
-    const response = await axios.post(`${API_BASE_URL}/discount/add`, discountData, {
+    const response = await axios.post(`/discount/add`, discountData, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -176,7 +176,7 @@
 // 删除折扣
 export const deleteDiscount = async (id) => {
   try {
-    const response = await axios.delete(`${API_BASE_URL}/discount/delete/${id}`, {
+    const response = await axios.delete(`/discount/delete/${id}`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
diff --git a/src/api/administer.test.js b/src/api/administer.test.js
index beb1e11..e5e785e 100644
--- a/src/api/administer.test.js
+++ b/src/api/administer.test.js
@@ -37,7 +37,7 @@
       }
     ];
 
-    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+    mock.onGet('/user/allUser').reply(200, {
       code: 200,
       data: { data: mockUsers }
     });
@@ -47,7 +47,7 @@
   });
 
   it('should return empty array when no users', async () => {
-    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+    mock.onGet('/user/allUser').reply(200, {
       code: 200,
       data: { data: [] }
     });
@@ -57,7 +57,7 @@
   });
 
   it('should handle error when fetching users', async () => {
-    mock.onGet('http://localhost:8088/user/allUser').reply(500, {
+    mock.onGet('/user/allUser').reply(500, {
       message: 'Request failed with status code 500'
     });
 
@@ -74,7 +74,7 @@
         }
       ];
 
-      mock.onGet('http://localhost:8088/user/searchUser', { params: { key: 'user' } })
+      mock.onGet('/user/searchUser', { params: { key: 'user' } })
         .reply(200, {
           code: 200,
           data: { data: mockUsers }
@@ -92,7 +92,7 @@
         }
       ];
 
-      mock.onGet('http://localhost:8088/user/searchUser', { params: { key: '' } })
+      mock.onGet('/user/searchUser', { params: { key: '' } })
         .reply(200, {
           code: 200,
           data: { data: mockUsers }
@@ -108,7 +108,7 @@
       const username = 'user1';
       const authority = 'ADMIN';
 
-      mock.onPut('http://localhost:8088/user/changeAuthority', {
+      mock.onPut('/user/changeAuthority', {
         changeUsername: username,
         authority: authority
       }).reply(200, {
@@ -133,7 +133,7 @@
         }
       ];
 
-      mock.onGet('http://localhost:8088/discount/all').reply(200, {
+      mock.onGet('/discount/all').reply(200, {
         code: 200,
         data: { data: mockDiscounts }
       });
@@ -153,7 +153,7 @@
       endTime: '2023-05-07T23:59:59'
     };
 
-    mock.onGet('http://localhost:8088/discount/current').reply(200, {
+    mock.onGet('/discount/current').reply(200, {
       code: 200,
       data: { data: mockDiscount }
     });
@@ -163,7 +163,7 @@
   });
 
   it('should return null when no current discount', async () => {
-    mock.onGet('http://localhost:8088/discount/current').reply(200, {
+    mock.onGet('/discount/current').reply(200, {
       code: 200,
       message: '目前没有进行中的折扣',
       data: null
@@ -174,7 +174,7 @@
   });
 
   it('should handle error when fetching current discount', async () => {
-    mock.onGet('http://localhost:8088/discount/current').reply(500);
+    mock.onGet('/discount/current').reply(500);
 
     await expect(getCurrentDiscount()).rejects.toThrow();
   });
@@ -189,7 +189,7 @@
         endTime: '2023-06-07T23:59:59'
       };
 
-      mock.onPost('http://localhost:8088/discount/add', newDiscount).reply(200, {
+      mock.onPost('/discount/add', newDiscount).reply(200, {
         code: 200,
         data: { data: { id: 2, ...newDiscount } }
       });
@@ -203,7 +203,7 @@
     it('should delete discount successfully', async () => {
       const discountId = 1;
 
-      mock.onDelete(`http://localhost:8088/discount/delete/${discountId}`).reply(200, {
+      mock.onDelete(`/discount/delete/${discountId}`).reply(200, {
         code: 200,
         message: '删除成功'
       });
diff --git a/src/api/auth.js b/src/api/auth.js
index c094a44..a779af2 100644
--- a/src/api/auth.js
+++ b/src/api/auth.js
@@ -3,7 +3,7 @@
 

 // 创建并导出 axios 实例

 export const api = axios.create({

-  baseURL: 'http://localhost:8088',

+  baseURL: 'http://team2.10813352.xyz:8088',

   timeout: 5000,

 });

 

diff --git a/src/api/recommend.js b/src/api/recommend.js
new file mode 100644
index 0000000..13c9f94
--- /dev/null
+++ b/src/api/recommend.js
@@ -0,0 +1,30 @@
+// src/api/recommend.js
+import { api } from './auth';
+
+export const getRecommendations = async (limit = 5) => {
+  try {
+    const response = await api.get('/recommend/for-user', {
+      params: { limit }
+    });
+    return response.data;
+  } catch (error) {
+    console.error('获取推荐失败:', error);
+    throw error;
+  }
+};
+
+export const markRecommendationShown = async (torrentId) => {
+  try {
+    await api.post(`/recommend/mark-shown/${torrentId}`);
+  } catch (error) {
+    console.error('标记推荐为已显示失败:', error);
+  }
+};
+
+export const markRecommendationClicked = async (torrentId) => {
+  try {
+    await api.post(`/recommend/mark-clicked/${torrentId}`);
+  } catch (error) {
+    console.error('标记推荐为已点击失败:', error);
+  }
+};
\ No newline at end of file
diff --git a/src/components/Administer.test.jsx b/src/components/Administer.test.jsx
index 7f446ed..598ed4e 100644
--- a/src/components/Administer.test.jsx
+++ b/src/components/Administer.test.jsx
@@ -23,7 +23,7 @@
   });
 
   test('renders user management tab by default', async () => {
-    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+    mock.onGet('/user/allUser').reply(200, {
       code: 200,
       data: { data: [] }
     });
@@ -53,7 +53,7 @@
       }
     ];
 
-    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+    mock.onGet('/user/allUser').reply(200, {
       code: 200,
       data: { data: mockUsers }
     });
@@ -77,7 +77,7 @@
       }
     ];
 
-    mock.onGet('http://localhost:8088/user/searchUser').reply(200, {
+    mock.onGet('/user/searchUser').reply(200, {
       code: 200,
       data: { data: mockUsers }
     });
@@ -99,12 +99,12 @@
   });
 
   test('switches between tabs', async () => {
-    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+    mock.onGet('/user/allUser').reply(200, {
       code: 200,
       data: { data: [] }
     });
 
-    mock.onGet('http://localhost:8088/discount/all').reply(200, {
+    mock.onGet('/discount/all').reply(200, {
       code: 200,
       data: { data: [] }
     });
diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx
index 40bd19d..61111f3 100644
--- a/src/components/Dashboard.jsx
+++ b/src/components/Dashboard.jsx
@@ -7,8 +7,10 @@
 import { message } from 'antd'; // 用于显示提示消息

 import { getAnnouncements,getLatestAnnouncements,getAnnouncementDetail } from '../api/announcement'; 

 import { getAllDiscounts } from '../api/administer'; 

-   import { getUserInfo, isAdmin } from '../api/auth';

+import { getUserInfo, isAdmin } from '../api/auth';

 import { api } from '../api/auth'; 

+import { getRecommendations, markRecommendationShown, markRecommendationClicked } from '../api/recommend';

+

 

 

 const Dashboard = ({onLogout}) => {

@@ -67,6 +69,10 @@
     const [shareSearch, setShareSearch] = useState('');

     const [requestSearch, setRequestSearch] = useState('');

     const [helpSearch, setHelpSearch] = useState('');

+    const [recommendations, setRecommendations] = useState([]);

+    const [recommendLoading, setRecommendLoading] = useState(false);

+    const [recommendError, setRecommendError] = useState(null);

+

 

 

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

@@ -99,6 +105,7 @@
         if (activeTab === 'announcement') {

             fetchAnnouncements();

             fetchDiscountsForCarousel();

+            fetchRecommendations();

         }

     }, [activeTab]);

 

@@ -143,6 +150,23 @@
         }

     };

 

+    const handleRecommendClick = async (torrent) => {

+        try {

+            // 标记为已点击

+            await markRecommendationClicked(torrent.id);

+            

+            // 导航到种子详情页

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

+            state: {

+                fromTab: 'announcement',

+                scrollPosition: window.scrollY

+            }

+            });

+        } catch (error) {

+            console.error('标记推荐点击失败:', error);

+        }

+    };

+

     

    // 公告区搜索处理

     const handleSearchAnnouncement = (e) => {

@@ -515,7 +539,7 @@
         

         const response = (shareSearch && !isReset) 

             ? await searchTorrents(shareSearch, page)

-            : await api.get('http://localhost:8088/torrent', { params });

+            : await api.get('/torrent', { params });

             

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

             setTorrentPosts(response.data.data.records);

@@ -614,7 +638,26 @@
         } finally {

           setHelpLoading(false);

         }

-      };

+    };

+

+    const fetchRecommendations = async () => {

+        try {

+            setRecommendLoading(true);

+            const response = await getRecommendations(5);

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

+            setRecommendations(response.data || []);

+            

+            // 标记这些推荐为已显示

+            response.data.forEach(torrent => {

+                markRecommendationShown(torrent.id);

+            });

+            }

+        } catch (error) {

+            setRecommendError(error.message || '获取推荐失败');

+        } finally {

+            setRecommendLoading(false);

+        }

+    };

 

 

     useEffect(() => {

@@ -719,7 +762,7 @@
             }

             

             // 调用API获取筛选结果

-            const response = await api.get('http://localhost:8088/torrent', { params });

+            const response = await api.get('/torrent', { params });

             

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

                 setTorrentPosts(response.data.data.records);

@@ -857,6 +900,45 @@
                                 </div>

                             ))}

                         </div>

+                        {/* 新增的为你推荐区域 */}

+                        <div className="recommend-section">

+                            <h2 className="section-title">为你推荐</h2>

+                            

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

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

+                            

+                            <div className="recommend-grid">

+                            {recommendations.map(torrent => (

+                                <div 

+                                key={torrent.id}

+                                className="recommend-card"

+                                onClick={() => handleRecommendClick(torrent)}

+                                >

+                                <div className="card-poster">

+                                    <div className="poster-image gray-bg">

+                                    {torrent.torrentName.charAt(0)}

+                                    </div>

+                                </div>

+                                <div className="card-info">

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

+                                    <p className="card-meta">

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

+                                    </p>

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

+                                </div>

+                                <div className="card-stats">

+                                    <span className="stat">👍 {torrent.likeCount || 0}</span>

+                                </div>

+                                </div>

+                            ))}

+                            

+                            {!recommendLoading && recommendations.length === 0 && (

+                                <div className="no-recommendations">

+                                暂无推荐,请先下载一些资源以获取个性化推荐

+                                </div>

+                            )}

+                            </div>

+                        </div>

                     </div>

                 );

             case 'share':

diff --git a/src/config/config.js b/src/config/config.js
index 365cc9e..1da40df 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -2,6 +2,6 @@
 

     //serverIP后端服务器地址

 

-    serverIP:'http://team2.10813352.xyz:8088'

+    serverIP:'http://team2.10813352.xyz:8088',

   

   }
\ No newline at end of file
diff --git "a/\345\255\230\345\234\250\347\232\204\351\227\256\351\242\230.txt" "b/\345\255\230\345\234\250\347\232\204\351\227\256\351\242\230.txt"
index 335c27b..4a0acb5 100644
--- "a/\345\255\230\345\234\250\347\232\204\351\227\256\351\242\230.txt"
+++ "b/\345\255\230\345\234\250\347\232\204\351\227\256\351\242\230.txt"
@@ -4,10 +4,9 @@
 4.个人中心添加一个下载进度展示的条,可能每十秒请求一次数据ok

 5.公告区前后端ok

 6.个人中心新增的魔力值兑换量之类的接口都接好ok

-7.求种区,前后端

-8.下载进度条合上之后才能测试

+7.求种区,前后端,完成

+8.下载进度条合上之后才能测试(未完成)

 9。管理员区里的发布公告,新开一个公告管理,完成

 10.轮播图实现折扣展示ok

 11.图片展示固定比例,(暂时解决,未找到其他bug,已修复主评论不能上传图片bug)

 12.看不到其他人上传的图片(需要云服务器),暂且搁置

-a
\ No newline at end of file