通知与推荐功能,css样式优化

Change-Id: I33d934bfdca88b7a8e6742be2a3c7323d28ffbcf
diff --git a/src/components/Personal/ActionCard.jsx b/src/components/Personal/ActionCard.jsx
index 7d3cd4f..0a62b1b 100644
--- a/src/components/Personal/ActionCard.jsx
+++ b/src/components/Personal/ActionCard.jsx
@@ -1,23 +1,23 @@
-import React from 'react';

-import PropTypes from 'prop-types';

+// import React from 'react';

+// import PropTypes from 'prop-types';

 

-const ActionCard = ({ title, subtitle, icon, onClick }) => {

-  return (

-    <div className="action-card" onClick={onClick}>

-      {icon && <div className="action-icon">{icon}</div>}

-      <div className="action-content">

-        <h3>{title}</h3>

-        <p>{subtitle}</p>

-      </div>

-    </div>

-  );

-};

+// const ActionCard = ({ title, subtitle, icon, onClick }) => {

+//   return (

+//     <div className="action-card" onClick={onClick}>

+//       {icon && <div className="action-icon">{icon}</div>}

+//       <div className="action-content">

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

+//         <p>{subtitle}</p>

+//       </div>

+//     </div>

+//   );

+// };

 

-ActionCard.propTypes = {

-  title: PropTypes.string.isRequired,

-  subtitle: PropTypes.string,

-  icon: PropTypes.node,

-  onClick: PropTypes.func

-};

+// ActionCard.propTypes = {

+//   title: PropTypes.string.isRequired,

+//   subtitle: PropTypes.string,

+//   icon: PropTypes.node,

+//   onClick: PropTypes.func

+// };

 

-export default ActionCard;
\ No newline at end of file
+// export default ActionCard;
\ No newline at end of file
diff --git a/src/components/Personal/Exchange.jsx b/src/components/Personal/Exchange.jsx
index 1e5b2e8..f6766ae 100644
--- a/src/components/Personal/Exchange.jsx
+++ b/src/components/Personal/Exchange.jsx
@@ -88,7 +88,7 @@
     return (

       <div className="subpage-container">

         <button className="back-button" onClick={handleBack}>

-          ← 返回个人中心

+      返回个人中心

         </button>

         <div className="error">错误: {error}</div>

       </div>

@@ -98,7 +98,7 @@
   return (

     <div className="subpage-container">

       <button className="back-button" onClick={handleBack}>

-        ← 返回个人中心

+      返回个人中心

       </button>

 

       <h2 className="page-title">兑换区</h2>

diff --git a/src/components/Personal/Exchange.test.jsx b/src/components/Personal/Exchange.test.jsx
index 20fe641..31abe48 100644
--- a/src/components/Personal/Exchange.test.jsx
+++ b/src/components/Personal/Exchange.test.jsx
@@ -125,7 +125,7 @@
     );

 

     await waitFor(() => {

-      const backButton = screen.getByText(/← 返回个人中心/);

+      const backButton = screen.getByText(/返回个人中心/);

       fireEvent.click(backButton);

       

       expect(mockNavigate).toHaveBeenCalledWith('/personal', {

diff --git a/src/components/Personal/Notice.jsx b/src/components/Personal/Notice.jsx
index 55bc955..05198f9 100644
--- a/src/components/Personal/Notice.jsx
+++ b/src/components/Personal/Notice.jsx
@@ -1,57 +1,106 @@
-import React from 'react';

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

+import React, { useEffect, useState } from 'react';

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

+import { notificationApi } from '../../api/notification';

 import './personalSubpage.css';

 

 const Notice = ({ onLogout }) => {

   const navigate = useNavigate();

   const location = useLocation();

-  // 模拟数据

-  const [notices] = React.useState([

-    { 

-      id: 1, 

-      title: '积分奖励到账', 

-      content: '您上传的资源《盗梦空间》获得100积分奖励',

-      date: '2023-10-20',

-      read: false

-    },

-    { 

-      id: 2, 

-      title: '系统通知', 

-      content: '服务器将于今晚2:00-4:00进行维护',

-      date: '2023-10-18',

-      read: true

+  const [notices, setNotices] = useState([]);

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

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

+

+  // 获取当前用户ID(根据你的实际应用获取方式)

+  const userId = localStorage.getItem('username') || 'default-user-id';

+

+  // 获取通知列表

+  const fetchNotifications = async () => {

+    try {

+      setLoading(true);

+      const response = await notificationApi.getNotifications(userId);

+      setNotices(response.data.notifications || []);

+    } catch (err) {

+      setError('获取通知失败,请稍后重试');

+      console.error(err);

+    } finally {

+      setLoading(false);

     }

-  ]);

+  };

+

+  useEffect(() => {

+    fetchNotifications();

+  }, [userId]);

 

   const handleBack = () => {

-    // 返回个人中心,并携带来源标记

     navigate('/personal', { 

       state: { 

-        fromSubpage: true,  // 标记来自子页面

-        dashboardTab: location.state?.dashboardTab // 保留Dashboard的标签页状态

+        fromSubpage: true,

+        dashboardTab: location.state?.dashboardTab

       },

-      replace: true  // 替换当前历史记录

+      replace: true

     });

   };

 

+  // 标记为已读处理

+  const handleMarkAsRead = async (id) => {

+    try {

+      const result = await notificationApi.markNotificationAsRead(id);

+      

+      if (result.success) {

+        // 使用后端返回的更新后通知替换本地状态

+        setNotices(prevNotices => 

+          prevNotices.map(notice => 

+            notice.id === id ? result.notification : notice

+          )

+        );

+      } else {

+        setError(result.message || '标记为已读失败');

+      }

+    } catch (err) {

+      console.error('标记为已读失败:', err);

+      setError('标记为已读失败,请稍后重试');

+    }

+  };

+

+  const handleItemClick = (notice) => {

+    if (!notice.isRead) {

+      handleMarkAsRead(notice.id);

+    }

+    // 这里可以添加其他点击逻辑,比如展开详情等

+  };

+

   return (

     <div className="subpage-container">

-      <button className="back-button" onClick={(handleBack)}>

-        ← 返回个人中心

+      <button className="back-button" onClick={handleBack}>

+      返回个人中心

       </button>

 

       <h2 className="page-title">消息通知</h2>

       

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

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

+      

       <div className="notice-list">

-        {notices.map(notice => (

-          <div key={notice.id} className={`list-item ${!notice.read ? 'unread' : ''}`}>

-            <div className="notice-header">

-              <h3>{notice.title}</h3>

-              <span className="notice-date">{notice.date}</span>

+        {notices.length === 0 && !loading ? (

+          <div className="empty-notice">暂无通知</div>

+        ) : (

+          notices.map(notice => (

+            <div 

+              key={notice.id} 

+              className={`list-item ${!notice.isRead ? 'unread' : ''}`}

+              onClick={() => handleItemClick(notice)}

+            >

+              <div className="notice-header">

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

+                <span className="notice-date">

+                  {new Date(notice.date).toLocaleDateString()}

+                  {!notice.isRead && <span className="unread-badge">未读</span>}

+                </span>

+              </div>

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

             </div>

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

-          </div>

-        ))}

+          ))

+        )}

       </div>

     </div>

   );

diff --git a/src/components/Personal/Personal.css b/src/components/Personal/Personal.css
index 28a1adb..69006d2 100644
--- a/src/components/Personal/Personal.css
+++ b/src/components/Personal/Personal.css
@@ -1,217 +1,95 @@
-/* Personal.css */

+/* Personal.css - 现代化设计 */

 .personal-container {

-    max-width: 800px;

-    margin: 0 auto;

-    padding: 20px;

-  }

-  

-  .back-button {

-    background: none;

-    border: none;

-    color: #1890ff;

-    cursor: pointer;

-    font-size: 16px;

-    margin-bottom: 20px;

-    padding: 5px 0;

-  }

-  

-  .profile-card {

-    background: #fff;

-    border-radius: 8px;

-    padding: 20px;

-    margin-bottom: 20px;

-    box-shadow: 0 1px 3px rgba(0,0,0,0.1);

-  }

-  

-  .profile-header {

-    display: flex;

-    align-items: center;

-    margin-bottom: 20px;

-  }

-  

-  .profile-avatar {

-    width: 80px;

-    height: 80px;

-    border-radius: 50%;

-    margin-right: 20px;

-    object-fit: cover;

-  }

-  

-  .profile-info {

-    flex-grow: 1;

-  }

-  

-  .username {

-    font-size: 24px;

-    margin: 0 0 5px;

-  }

-  

-  .user-meta {

-    display: flex;

-    gap: 15px;

-    color: #666;

-    font-size: 14px;

-  }

-  

-  .stats-grid {

-    display: grid;

-    grid-template-columns: repeat(4, 1fr);

-    gap: 15px;

-  }

-  

-  .stat-item {

-    background: #f5f5f5;

-    border-radius: 6px;

-    padding: 15px;

-    text-align: center;

-  }

-  

-  .stat-label {

-    font-size: 14px;

-    color: #666;

-    margin-bottom: 5px;

-  }

-  

-  .stat-value {

-    font-size: 18px;

-    font-weight: bold;

-  }

-  

-  .quota-card {

-    background: #fff;

-    border-radius: 8px;

-    padding: 20px;

-    margin-bottom: 20px;

-    box-shadow: 0 1px 3px rgba(0,0,0,0.1);

-  }

-  

-  .quota-card h3 {

-    margin-top: 0;

-    margin-bottom: 15px;

-  }

-  

-  .quota-info {

-    display: flex;

-    justify-content: space-between;

-    margin-bottom: 10px;

-  }

-  

-  .quota-used {

-    color: #1890ff;

-  }

-  

-  .quota-remaining {

-    color: #52c41a;

-  }

-  

-  .progress-bar {

-    height: 10px;

-    background: #f0f0f0;

-    border-radius: 5px;

-    margin-bottom: 10px;

-    overflow: hidden;

-  }

-  

-  .progress-fill {

-    height: 100%;

-    background: #1890ff;

-    border-radius: 5px;

-    transition: width 0.3s ease;

-  }

-  

-  .quota-total {

-    text-align: right;

-    color: #666;

-    font-size: 14px;

-  }

-  

-  .action-cards {

-    display: grid;

-    grid-template-columns: repeat(2, 1fr);

-    gap: 15px;

-  }

-  

-  .action-card {

-    background: #fff;

-    border-radius: 8px;

-    padding: 20px;

-    box-shadow: 0 1px 3px rgba(0,0,0,0.1);

-    cursor: pointer;

-    transition: transform 0.2s ease;

-  }

-  

-  .action-card:hover {

-    transform: translateY(-3px);

-    box-shadow: 0 4px 8px rgba(0,0,0,0.1);

-  }

-  

-  .action-card h3 {

-    margin-top: 0;

-    color: #1890ff;

-  }

-  

-  .action-card p {

-    color: #666;

-    margin-bottom: 0;

-  }

-

-  .subpage-container {

-    margin-top: 20px;

-    border-top: 1px solid #f0f0f0;

-    padding-top: 20px;

-  }

-

-

-  /* Personal.css */

-/* ... 其他已有样式 ... */

-

-/* 下载进度卡片样式 */

-.progress-card {

-  background: #fff;

-  border-radius: 8px;

-  padding: 20px;

-  margin-bottom: 20px;

-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

+  max-width: 1000px;

+  margin: 0 auto;

+  padding: 25px;

+  font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

+  animation: fadeIn 0.5s ease-out forwards;

 }

 

-.download-task {

-  margin-bottom: 15px;

+/* 返回按钮 - 渐变风格 */

+.back-button {

+  display: inline-flex;

+  align-items: center;

+  gap: 8px;

+  padding: 8px 16px;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

+  color: white;

+  border: none;

+  border-radius: 6px;

+  font-weight: 600;

+  cursor: pointer;

+  transition: all 0.3s;

+  margin-bottom: 30px;

+  box-shadow: 0 2px 8px rgba(30, 60, 114, 0.2);

 }

 

-.task-info {

-  display: flex;

-  justify-content: space-between;

-  margin-bottom: 5px;

+.back-button:hover {

+  transform: translateY(-2px);

+  box-shadow: 0 4px 12px rgba(30, 60, 114, 0.3);

 }

 

-.task-id {

-  font-size: 14px;

-  color: #666;

+.back-button::before {

+  content: "←";

 }

 

-.task-progress {

-  font-size: 14px;

-  font-weight: bold;

-  color: #1890ff;

-}

-

-.progress-bar {

-  height: 8px;

-  background: #f0f0f0;

-  border-radius: 4px;

+/* 用户资料卡片 - 3D效果 */

+.profile-card {

+  background: white;

+  border-radius: 12px;

+  padding: 25px;

+  margin-bottom: 25px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

+  transition: transform 0.3s, box-shadow 0.3s;

+  position: relative;

   overflow: hidden;

 }

 

-.progress-fill {

-  height: 100%;

-  background: #1890ff;

-  border-radius: 4px;

-  transition: width 0.3s ease;

+.profile-card:hover {

+  transform: translateY(-5px);

+  box-shadow: 0 12px 25px rgba(0, 0, 0, 0.12);

 }

 

+.profile-header {

+  display: flex;

+  align-items: center;

+  margin-bottom: 25px;

+}

+

+.profile-avatar {

+  width: 100px;

+  height: 100px;

+  border-radius: 50%;

+  margin-right: 25px;

+  object-fit: cover;

+  border: 4px solid rgba(30, 60, 114, 0.1);

+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);

+  transition: transform 0.3s;

+}

+

+.profile-avatar:hover {

+  transform: scale(1.05);

+}

+

+.username {

+  font-size: 28px;

+  margin: 0 0 10px;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

+  -webkit-background-clip: text;

+  -webkit-text-fill-color: transparent;

+  font-weight: 800;

+}

+

+.user-meta {

+  display: flex;

+  gap: 20px;

+}

 

 .user-meta span {

-  margin-right: 15px;

+  display: flex;

+  align-items: center;

+  gap: 5px;

+  font-size: 15px;

   color: #666;

 }

 

@@ -219,3 +97,221 @@
   color: #ff9800;

   font-weight: bold;

 }

+

+/* 统计数据网格 - 卡片式设计 */

+.stats-grid {

+  display: grid;

+  grid-template-columns: repeat(4, 1fr);

+  gap: 20px;

+}

+

+.stat-item {

+  background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);

+  border-radius: 10px;

+  padding: 20px;

+  text-align: center;

+  transition: transform 0.3s;

+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);

+}

+

+.stat-item:hover {

+  transform: translateY(-3px);

+  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);

+}

+

+.stat-label {

+  font-size: 15px;

+  color: #666;

+  margin-bottom: 10px;

+}

+

+.stat-value {

+  font-size: 22px;

+  font-weight: 700;

+  color: #1e3c72;

+}

+

+/* 下载额度卡片 - 渐变色 */

+.quota-card {

+  background: white;

+  border-radius: 12px;

+  padding: 25px;

+  margin-bottom: 25px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

+}

+

+.quota-card h3 {

+  margin-top: 0;

+  margin-bottom: 20px;

+  color: #1e3c72;

+  font-size: 20px;

+}

+

+.quota-info {

+  display: flex;

+  justify-content: space-between;

+  margin-bottom: 15px;

+  font-size: 15px;

+}

+

+.quota-used {

+  color: #ff4d4f;

+  font-weight: 600;

+}

+

+.quota-remaining {

+  color: #52c41a;

+  font-weight: 600;

+}

+

+.progress-bar {

+  height: 12px;

+  background: #f0f2f5;

+  border-radius: 6px;

+  margin-bottom: 15px;

+  overflow: hidden;

+}

+

+.progress-fill {

+  height: 100%;

+  border-radius: 6px;

+  transition: width 0.5s ease;

+}

+

+.quota-total {

+  text-align: right;

+  color: #666;

+  font-size: 14px;

+}

+

+/* 下载进度卡片 */

+.progress-card {

+  background: white;

+  border-radius: 12px;

+  padding: 25px;

+  margin-bottom: 25px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

+}

+

+.progress-card h3 {

+  margin-top: 0;

+  margin-bottom: 20px;

+  color: #1e3c72;

+  font-size: 20px;

+}

+

+.download-task {

+  margin-bottom: 20px;

+}

+

+.task-info {

+  display: flex;

+  justify-content: space-between;

+  margin-bottom: 8px;

+}

+

+.task-id {

+  font-size: 15px;

+  color: #666;

+}

+

+.task-progress {

+  font-size: 15px;

+  font-weight: 600;

+  color: #1890ff;

+}

+

+/* 功能卡片区 - 网格布局 */

+.action-cards {

+  display: grid;

+  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

+  gap: 20px;

+  margin-bottom: 30px;

+}

+

+.action-card {

+  background: white;

+  border-radius: 12px;

+  padding: 25px;

+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);

+  cursor: pointer;

+  transition: all 0.3s;

+  border: 1px solid rgba(30, 60, 114, 0.1);

+  text-align: center;

+}

+

+.action-card:hover {

+  transform: translateY(-5px);

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);

+  border-color: rgba(30, 60, 114, 0.2);

+}

+

+.action-card h3 {

+  margin-top: 0;

+  margin-bottom: 15px;

+  color: #1e3c72;

+  font-size: 20px;

+}

+

+.action-card p {

+  color: #666;

+  margin-bottom: 0;

+  font-size: 15px;

+}

+

+/* 子页面容器 */

+.subpage-container {

+  margin-top: 30px;

+  border-top: 2px solid #f0f2f5;

+  padding-top: 30px;

+}

+

+/* 加载和错误状态 */

+.loading, .error {

+  text-align: center;

+  padding: 50px;

+  font-size: 18px;

+  background: white;

+  border-radius: 12px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

+  margin: 20px 0;

+}

+

+.error {

+  color: #ff4d4f;

+}

+

+/* 动画效果 */

+@keyframes fadeIn {

+  from { opacity: 0; transform: translateY(10px); }

+  to { opacity: 1; transform: translateY(0); }

+}

+

+/* 响应式设计 */

+@media (max-width: 768px) {

+  .personal-container {

+    padding: 15px;

+  }

+  

+  .profile-header {

+    flex-direction: column;

+    text-align: center;

+  }

+  

+  .profile-avatar {

+    margin-right: 0;

+    margin-bottom: 15px;

+  }

+  

+  .user-meta {

+    justify-content: center;

+  }

+  

+  .stats-grid {

+    grid-template-columns: repeat(2, 1fr);

+  }

+  

+  .action-cards {

+    grid-template-columns: 1fr;

+  }

+}
\ No newline at end of file
diff --git a/src/components/Personal/Personal.jsx b/src/components/Personal/Personal.jsx
index 8c60baf..8199b4b 100644
--- a/src/components/Personal/Personal.jsx
+++ b/src/components/Personal/Personal.jsx
@@ -141,7 +141,7 @@
     <div className="personal-container">

       {/* 返回按钮 */}

       <button className="back-button" onClick={handleBack}>

-        &larr; 返回

+      返回

       </button>

       

       {/* 用户基本信息卡片 */}

diff --git a/src/components/Personal/Setting.jsx b/src/components/Personal/Setting.jsx
index 9ba07e8..5b6f730 100644
--- a/src/components/Personal/Setting.jsx
+++ b/src/components/Personal/Setting.jsx
@@ -87,7 +87,7 @@
   return (

     <div className="subpage-container">

       <button className="back-button" onClick={handleBack}>

-        ← 返回个人中心

+      返回个人中心

       </button>

 

       <h2 className="page-title">个人设置</h2>

diff --git a/src/components/Personal/Setting.test.jsx b/src/components/Personal/Setting.test.jsx
index e8b1cc0..02011be 100644
--- a/src/components/Personal/Setting.test.jsx
+++ b/src/components/Personal/Setting.test.jsx
@@ -149,7 +149,7 @@
       </MemoryRouter>

     );

 

-    const backButton = screen.getByText(/← 返回个人中心/);

+    const backButton = screen.getByText(/返回个人中心/);

     fireEvent.click(backButton);

     

     expect(mockNavigate).toHaveBeenCalledWith('/personal', {

diff --git a/src/components/Personal/Upload.jsx b/src/components/Personal/Upload.jsx
index 2d91b30..336f721 100644
--- a/src/components/Personal/Upload.jsx
+++ b/src/components/Personal/Upload.jsx
@@ -112,7 +112,7 @@
   return (

     <div className="subpage-container">

       <button className="back-button" onClick={handleBack}>

-        ← 返回个人中心

+      返回个人中心

       </button>

 

       <h2 className="page-title">上传记录</h2>

diff --git a/src/components/Personal/personalSubpage.css b/src/components/Personal/personalSubpage.css
index 2ba8687..ff587e2 100644
--- a/src/components/Personal/personalSubpage.css
+++ b/src/components/Personal/personalSubpage.css
@@ -1,336 +1,553 @@
+/* personalSubpage.css - 现代化设计 */

+

 /* 上传记录表格样式 */

 .uploads-table {

   width: 100%;

-  border-collapse: collapse;

-  margin-top: 20px;

+  border-collapse: separate;

+  border-spacing: 0;

+  margin-top: 25px;

+  background: white;

+  border-radius: 12px;

+  overflow: hidden;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

 }

 

 .uploads-table th, .uploads-table td {

-  padding: 12px 15px;

+  padding: 15px;

   text-align: left;

-  border-bottom: 1px solid #e0e0e0;

+  border-bottom: 1px solid #f0f2f5;

 }

 

 .uploads-table th {

-  background-color: #f5f5f5;

+  background-color: #1e3c72;

+  color: white;

   font-weight: 600;

+  text-transform: uppercase;

+  font-size: 14px;

 }

 

-.list-item:hover {

-  background-color: #f9f9f9;

+.uploads-table tr:last-child td {

+  border-bottom: none;

+}

+

+.uploads-table tr:hover td {

+  background-color: #f9fafc;

 }

 

 /* 操作按钮样式 */

 .action-btn {

-  padding: 6px 12px;

+  padding: 8px 16px;

   border: none;

-  border-radius: 4px;

+  border-radius: 6px;

   cursor: pointer;

   font-size: 14px;

-  transition: background-color 0.2s;

+  font-weight: 600;

+  transition: all 0.3s;

+  display: inline-flex;

+  align-items: center;

+  gap: 5px;

 }

 

 .delete-btn {

-  background-color: #ff4d4f;

+  background: linear-gradient(135deg, #ff4d4f 0%, #f5222d 100%);

   color: white;

 }

 

 .delete-btn:hover {

-  background-color: #ff7875;

+  transform: translateY(-2px);

+  box-shadow: 0 4px 12px rgba(255, 77, 79, 0.3);

 }

 

 /* 分页控件样式 */

 .pagination {

-  margin-top: 20px;

+  margin-top: 30px;

   display: flex;

   justify-content: center;

   align-items: center;

-  gap: 15px;

-}

-

-.pagination button {

-  padding: 6px 12px;

-  border: 1px solid #d9d9d9;

-  background-color: #fff;

-  border-radius: 4px;

-  cursor: pointer;

-}

-

-.pagination button:disabled {

-  color: #d9d9d9;

-  cursor: not-allowed;

-}

-

-.pagination button:not(:disabled):hover {

-  border-color: #1890ff;

-  color: #1890ff;

-}

-

-/* 分页控件样式 */

-.pagination {

-  margin-top: 20px;

-  display: flex;

-  justify-content: center;

-  align-items: center;

-  gap: 8px;

+  gap: 10px;

   flex-wrap: wrap;

 }

 

 .page-nav, .page-number {

-  padding: 6px 12px;

+  padding: 8px 16px;

   border: 1px solid #d9d9d9;

-  background-color: #fff;

-  border-radius: 4px;

+  background-color: white;

+  color:#333;

+  border-radius: 6px;

   cursor: pointer;

-  min-width: 32px;

+  min-width: 40px;

   text-align: center;

+  transition: all 0.3s;

+  font-weight: 600;

 }

 

 .page-nav:disabled, .page-number:disabled {

-  color: #d9d9d9;

+  color: #070202;

   cursor: not-allowed;

 }

 

 .page-nav:not(:disabled):hover, 

 .page-number:not(:disabled):hover {

-  border-color: #1890ff;

-  color: #1890ff;

+  border-color: #1e3c72;

+  color: #1e3c72;

+  transform: translateY(-2px);

 }

 

 .page-number.active {

-  background-color: #1890ff;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

   color: white;

-  border-color: #1890ff;

+  border-color: #1e3c72;

 }

 

 .ellipsis {

-  padding: 0 8px;

+  padding: 0 12px;

 }

 

 .page-info {

   display: flex;

   align-items: center;

-  gap: 8px;

-  margin-left: 15px;

+  gap: 10px;

+  margin-left: 20px;

 }

 

 .page-info input {

-  width: 50px;

-  padding: 4px;

+  width: 60px;

+  padding: 8px;

   border: 1px solid #d9d9d9;

-  border-radius: 4px;

+  border-radius: 6px;

   text-align: center;

+  font-weight: 600;

 }

 

 .page-info input:focus {

   outline: none;

-  border-color: #1890ff;

-}

-

-/* 调整表格列宽 */

-.uploads-table th:nth-child(1),

-.uploads-table td:nth-child(1) {

-  width: 30%;

-}

-

-.uploads-table th:nth-child(2),

-.uploads-table td:nth-child(2) {

-  width: 15%;

-}

-

-.uploads-table th:nth-child(3),

-.uploads-table td:nth-child(3) {

-  width: 20%;

-}

-

-.uploads-table th:nth-child(4),

-.uploads-table td:nth-child(4) {

-  width: 15%;

-  text-align: center;

-}

-

-.uploads-table th:nth-child(5),

-.uploads-table td:nth-child(5) {

-  width: 20%;

-  text-align: center;

+  border-color: #1e3c72;

+  box-shadow: 0 0 0 3px rgba(30, 60, 114, 0.2);

 }

 

 /* 兑换区样式 */

 .exchange-section {

-  margin-top: 20px;

-  padding: 20px;

-  background-color: #f9f9f9;

-  border-radius: 8px;

+  margin-top: 30px;

+  padding: 25px;

+  background: white;

+  border-radius: 12px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

 }

 

 .exchange-card {

-  margin-bottom: 20px;

-  padding: 15px;

-  background-color: white;

-  border-radius: 6px;

-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

+  margin-bottom: 25px;

+  padding: 20px;

+  background: #f9fafc;

+  border-radius: 10px;

+  border: 1px solid #f0f2f5;

+  transition: all 0.3s;

+}

+

+.exchange-card:hover {

+  transform: translateY(-3px);

+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);

 }

 

 .exchange-card h4 {

   margin-top: 0;

-  color: #333;

+  color: #1e3c72;

+  font-size: 18px;

 }

 

 .exchange-card p {

   color: #666;

-  margin-bottom: 15px;

+  margin-bottom: 20px;

+  font-size: 15px;

 }

 

 .exchange-btn {

-  padding: 8px 16px;

-  background-color: #1890ff;

+  padding: 10px 20px;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

   color: white;

   border: none;

-  border-radius: 4px;

+  border-radius: 6px;

   cursor: pointer;

-  transition: background-color 0.3s;

+  font-weight: 600;

+  transition: all 0.3s;

+  display: inline-flex;

+  align-items: center;

+  gap: 8px;

 }

 

 .exchange-btn:hover {

-  background-color: #40a9ff;

+  transform: translateY(-2px);

+  box-shadow: 0 4px 12px rgba(30, 60, 114, 0.3);

 }

 

 .exchange-btn:disabled {

-  background-color: #d9d9d9;

+  background: #d9d9d9;

   cursor: not-allowed;

+  transform: none;

+  box-shadow: none;

 }

 

 .exchange-input-group {

   display: flex;

-  gap: 10px;

-  margin-top: 10px;

+  gap: 15px;

+  margin-top: 15px;

 }

 

 .exchange-input-group input {

   flex: 1;

-  padding: 8px;

+  padding: 10px;

   border: 1px solid #d9d9d9;

-  border-radius: 4px;

+  border-radius: 6px;

+  font-size: 15px;

+}

+

+.exchange-input-group input:focus {

+  outline: none;

+  border-color: #1e3c72;

+  box-shadow: 0 0 0 3px rgba(30, 60, 114, 0.2);

 }

 

 .invite-code-list {

-  margin-top: 20px;

+  margin-top: 25px;

 }

 

 .invite-code-list ul {

   list-style: none;

   padding: 0;

+  margin: 0;

 }

 

 .invite-code-list li {

   display: flex;

   justify-content: space-between;

-  padding: 10px;

-  border-bottom: 1px solid #eee;

+  align-items: center;

+  padding: 15px;

+  border-bottom: 1px solid #f0f2f5;

+  transition: all 0.3s;

+}

+

+.invite-code-list li:hover {

+  background-color: #f9fafc;

 }

 

 .invite-code-list .code {

   font-family: monospace;

+  font-size: 16px;

+  color: #1e3c72;

 }

 

 .invite-code-list .status {

-  padding: 2px 6px;

-  border-radius: 3px;

-  font-size: 12px;

+  padding: 4px 12px;

+  border-radius: 20px;

+  font-size: 13px;

+  font-weight: 600;

 }

 

 .invite-code-list .status.available {

-  background-color: #f6ffed;

-  color: #52c41a;

-  border: 1px solid #b7eb8f;

+  background: linear-gradient(135deg, #52c41a 0%, #a0d911 100%);

+  color: white;

 }

 

 .invite-code-list .status.used {

+  background: linear-gradient(135deg, #ff4d4f 0%, #f5222d 100%);

+  color: white;

+}

+

+/* 设置页面样式 */

+.setting-section {

+  max-width: 800px;

+  margin: 0 auto;

+  padding: 25px;

+  background: white;

+  border-radius: 12px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

+}

+

+.user-info-card, .password-form-card {

+  background: #f9fafc;

+  border-radius: 10px;

+  padding: 25px;

+  margin-bottom: 25px;

+  border: 1px solid #f0f2f5;

+}

+

+.info-item {

+  display: flex;

+  margin-bottom: 15px;

+  align-items: center;

+}

+

+.info-item label {

+  font-weight: 600;

+  width: 150px;

+  color: #1e3c72;

+}

+

+.info-item span {

+  flex: 1;

+  color: #333;

+}

+

+.info-note {

+  color: #666;

+  font-size: 14px;

+  margin-top: 15px;

+  line-height: 1.6;

+}

+

+.form-group {

+  margin-bottom: 20px;

+}

+

+.form-group label {

+  display: block;

+  margin-bottom: 8px;

+  font-weight: 600;

+  color: #1e3c72;

+}

+

+.form-group input {

+  width: 100%;

+  padding: 12px;

+  border: 1px solid #d9d9d9;

+  border-radius: 6px;

+  box-sizing: border-box;

+  font-size: 15px;

+  transition: all 0.3s;

+}

+

+.form-group input:focus {

+  outline: none;

+  border-color: #1e3c72;

+  box-shadow: 0 0 0 3px rgba(30, 60, 114, 0.2);

+}

+

+.submit-button {

+  padding: 12px 24px;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

+  color: white;

+  border: none;

+  border-radius: 6px;

+  cursor: pointer;

+  font-size: 16px;

+  font-weight: 600;

+  transition: all 0.3s;

+}

+

+.submit-button:hover {

+  transform: translateY(-2px);

+  box-shadow: 0 4px 12px rgba(30, 60, 114, 0.3);

+}

+

+.submit-button:disabled {

+  background: #d9d9d9;

+  cursor: not-allowed;

+  transform: none;

+  box-shadow: none;

+}

+

+.error-message {

+  color: #ff4d4f;

+  margin-bottom: 20px;

+  padding: 10px;

+  background: #fff2f0;

+  border-radius: 6px;

+  border: 1px solid #ffccc7;

+}

+

+.success-message {

+  color: #52c41a;

+  margin-bottom: 20px;

+  padding: 10px;

+  background: #f6ffed;

+  border-radius: 6px;

+  border: 1px solid #b7eb8f;

+}

+

+.subpage-container {

+  max-width: 800px;

+  margin: 0 auto;

+  padding: 25px;

+  animation: fadeIn 0.5s ease-out forwards;

+}

+

+.back-button {

+  display: inline-flex;

+  align-items: center;

+  gap: 8px;

+  padding: 8px 16px;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

+  color: white;

+  border: none;

+  border-radius: 6px;

+  font-weight: 600;

+  cursor: pointer;

+  transition: all 0.3s;

+  margin-bottom: 30px;

+  box-shadow: 0 2px 8px rgba(30, 60, 114, 0.2);

+}

+

+.back-button:hover {

+  transform: translateY(-2px);

+  box-shadow: 0 4px 12px rgba(30, 60, 114, 0.3);

+}

+

+.back-button::before {

+  content: "←";

+}

+

+.page-title {

+  font-size: 24px;

+  margin: 0 0 25px;

+  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);

+  -webkit-background-clip: text;

+  -webkit-text-fill-color: transparent;

+  font-weight: 800;

+  padding-bottom: 10px;

+  border-bottom: 2px solid #f0f2f5;

+}

+

+.loading-message, .error-message {

+  padding: 15px;

+  border-radius: 8px;

+  margin-bottom: 20px;

+  text-align: center;

+}

+

+.loading-message {

+  background-color: #f5f5f5;

+  color: #666;

+}

+

+.error-message {

   background-color: #fff2f0;

   color: #ff4d4f;

   border: 1px solid #ffccc7;

 }

 

-

-/* personalSubpage.css 中添加以下样式 */

-

-.setting-section {

-  max-width: 600px;

-  margin: 0 auto;

-  padding: 20px;

+.notice-list {

+  background: white;

+  border-radius: 12px;

+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);

+  overflow: hidden;

 }

 

-.user-info-card, .password-form-card {

-  background: #fff;

-  border-radius: 8px;

-  padding: 20px;

-  margin-bottom: 20px;

-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

-}

-

-.info-item {

-  display: flex;

-  margin-bottom: 10px;

-}

-

-.info-item label {

-  font-weight: bold;

-  width: 100px;

-}

-

-.info-item span {

-  flex: 1;

-}

-

-.info-note {

+.empty-notice {

+  text-align: center;

+  padding: 50px 20px;

   color: #666;

-  font-size: 0.9em;

-  margin-top: 10px;

-}

-

-.form-group {

-  margin-bottom: 15px;

-}

-

-.form-group label {

-  display: block;

-  margin-bottom: 5px;

-  font-weight: bold;

-}

-

-.form-group input {

-  width: 100%;

-  padding: 8px;

-  border: 1px solid #ddd;

-  border-radius: 4px;

-  box-sizing: border-box;

-}

-

-.submit-button {

-  background-color: #4CAF50;

-  color: white;

-  padding: 10px 15px;

-  border: none;

-  border-radius: 4px;

-  cursor: pointer;

   font-size: 16px;

 }

 

-.submit-button:hover {

-  background-color: #45a049;

+.list-item {

+  padding: 20px;

+  border-bottom: 1px solid #f0f2f5;

+  transition: all 0.3s;

+  cursor: pointer;

 }

 

-.submit-button:disabled {

-  background-color: #cccccc;

-  cursor: not-allowed;

+.list-item:last-child {

+  border-bottom: none;

 }

 

-.error-message {

-  color: #f44336;

-  margin-bottom: 15px;

+.list-item:hover {

+  background-color: #f9fafc;

+  transform: translateX(5px);

 }

 

-.success-message {

-  color: #4CAF50;

-  margin-bottom: 15px;

+.list-item.unread {

+  background-color: #f0f7ff;

+}

+

+.notice-header {

+  display: flex;

+  justify-content: space-between;

+  align-items: center;

+  margin-bottom: 10px;

+}

+

+.notice-header h3 {

+  margin: 0;

+  font-size: 18px;

+  color: #1e3c72;

+  font-weight: 600;

+}

+

+.notice-date {

+  font-size: 14px;

+  color: #888;

+  display: flex;

+  align-items: center;

+  gap: 8px;

+}

+

+.unread-badge {

+  background: #ff4d4f;

+  color: white;

+  font-size: 12px;

+  padding: 2px 8px;

+  border-radius: 10px;

+  font-weight: 500;

+}

+

+.notice-content {

+  margin: 0;

+  color: #333;

+  line-height: 1.6;

+  font-size: 15px;

+}

+

+/* 动画效果 */

+@keyframes fadeIn {

+  from { opacity: 0; transform: translateY(10px); }

+  to { opacity: 1; transform: translateY(0); }

+}

+

+/* 响应式设计 */

+@media (max-width: 768px) {

+  

+}

+

+/* 响应式设计 */

+@media (max-width: 768px) {

+  .uploads-table {

+    display: block;

+    overflow-x: auto;

+  }

+  

+  .exchange-input-group {

+    flex-direction: column;

+  }

+  

+  .info-item {

+    flex-direction: column;

+    align-items: flex-start;

+  }

+  

+  .info-item label {

+    width: 100%;

+    margin-bottom: 5px;

+  }

+  

+  .pagination {

+    flex-direction: column;

+    align-items: center;

+  }

+  

+  .page-info {

+    margin-left: 0;

+    margin-top: 15px;

+  }

+  .subpage-container {

+    padding: 15px;

+  }

+  

+  .notice-header {

+    flex-direction: column;

+    align-items: flex-start;

+    gap: 5px;

+  }

+  

+  .list-item:hover {

+    transform: none;

+  }

 }
\ No newline at end of file