修改密码、管理员删帖、促销、退出登录

Change-Id: I2cc0e211ac5a04f9e89d0736fadd25541a5fccb9
diff --git a/src/pages/Forum/posts-main/components/PostList.jsx b/src/pages/Forum/posts-main/components/PostList.jsx
index 5d14fdd..533e726 100644
--- a/src/pages/Forum/posts-main/components/PostList.jsx
+++ b/src/pages/Forum/posts-main/components/PostList.jsx
@@ -4,9 +4,9 @@
 import { GoodTwo, Star, Delete } from '@icon-park/react';
 import { likePost } from '../../posts-detail/api';
 import { formatAvatarUrl } from '../../../../components/utils/avatar';
+import { useUser } from '../../../../context/UserContext';  // 路径根据实际调整
 import './PostList.css';
 
-// 修改后的封面图 URL 拼接函数
 const formatImageUrl = (url) => {
   if (!url) return '';
   const filename = url.split('/').pop(); // 提取文件名部分
@@ -14,6 +14,7 @@
 };
 
 const PostList = ({ search }) => {
+  const { user } = useUser();  // 获取当前登录用户
   const [posts, setPosts] = useState([]);
   const [page, setPage] = useState(1);
   const [total, setTotal] = useState(0);
@@ -116,7 +117,17 @@
     }
   };
 
-  const handleDeletePost = async (postNo) => {
+  const handleDeletePost = async (postNo, postUserId) => {
+    // 权限判断:管理员或者帖子发布者本人
+    if (!user) {
+      alert('请先登录');
+      return;
+    }
+    if (user.role !== 'admin' && user.userId !== postUserId) {
+      alert('您没有权限删除此帖子');
+      return;
+    }
+
     if (window.confirm('确定要删除这篇帖子吗?')) {
       try {
         await axios.delete(`/echo/forum/posts/${postNo}/deletePost`);
@@ -144,17 +155,10 @@
                 coverImage = imgs.length > 0 ? formatImageUrl(imgs[0]) : null;
               }
 
+              const canDelete = user && (user.role === 'admin' || user.userId === post.user_id);
+
               return (
                 <div key={post.postNo} className="post-card" style={{ backgroundColor: '#e9ded2' }}>
-                  {/* <div className="user-info">
-                    <img
-                      className="avatar"
-                      src={post.avatarUrl}
-                      alt="头像"
-                    />
-                    <span className="nickname" style={{ color: '#755e50' }}>{post.username}</span>
-                  </div> */}
-
                   <div className="user-info">
                     <Link href={`/information/${post.user_id}`}>
                       <img
@@ -167,7 +171,6 @@
                     <span className="nickname" style={{ color: '#755e50' }}>{post.username}</span>
                   </div>
 
-
                   {coverImage && <img className="cover-image" src={coverImage} alt="封面" />}
 
                   <h3 style={{ color: '#000000' }}>{post.title || '无标题'}</h3>
@@ -182,9 +185,12 @@
                         <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
                         <span>{post.collectCount}</span>
                       </button>
-                      <button className="icon-btn" onClick={() => handleDeletePost(post.postNo)}>
-                        <Delete theme="outline" size="24" fill="#333" />
-                      </button>
+
+                      {canDelete && (
+                        <button className="icon-btn" onClick={() => handleDeletePost(post.postNo, post.user_id)}>
+                          <Delete theme="outline" size="24" fill="#333" />
+                        </button>
+                      )}
                     </div>
                   </div>
                   <div className="detail-button-wrapper">
@@ -205,3 +211,4 @@
 };
 
 export default PostList;
+
diff --git a/src/pages/Forum/promotion-part/Promotion.css b/src/pages/Forum/promotion-part/Promotion.css
index 2232ba5..46e7a0d 100644
--- a/src/pages/Forum/promotion-part/Promotion.css
+++ b/src/pages/Forum/promotion-part/Promotion.css
@@ -108,3 +108,49 @@
   font-size: 16px;
   text-align: center;
 }
+
+.dialog-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0,0,0,0.4);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 999;
+}
+.dialog {
+  background: #fff;
+  padding: 20px;
+  border-radius: 6px;
+  width: 400px;
+  max-width: 90%;
+  box-shadow: 0 0 10px rgba(0,0,0,0.25);
+}
+.form-item {
+  margin-bottom: 12px;
+  display: flex;
+  flex-direction: column;
+}
+.form-item label {
+  font-weight: bold;
+  margin-bottom: 4px;
+}
+.form-item input, .form-item textarea {
+  padding: 6px 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+.dialog-buttons {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+.dialog-buttons button {
+  padding: 6px 16px;
+  cursor: pointer;
+}
+
diff --git a/src/pages/Forum/promotion-part/Promotion.jsx b/src/pages/Forum/promotion-part/Promotion.jsx
index 28fd7ac..8ca4067 100644
--- a/src/pages/Forum/promotion-part/Promotion.jsx
+++ b/src/pages/Forum/promotion-part/Promotion.jsx
@@ -1,17 +1,32 @@
-// export default Promotion;
-
 import React, { useEffect, useState, useRef } from 'react';
 import './Promotion.css';
+import { useUser } from '../../../context/UserContext';
 
 const Promotion = () => {
+  const { user } = useUser();
   const [promotions, setPromotions] = useState([]);
+  const [torrents, setTorrents] = useState([]);
   const [loading, setLoading] = useState(true);
-
   const [promoIndex, setPromoIndex] = useState(0);
   const promoTimerRef = useRef(null);
 
+  // 新增:控制创建对话框显示
+  const [showCreateDialog, setShowCreateDialog] = useState(false);
+
+  // 创建促销活动表单状态
+  const [formData, setFormData] = useState({
+    name: '',
+    startTime: '',
+    endTime: '',
+    discountPercentage: '',
+    uploadCoeff: '',
+    downloadCoeff: '',
+    description: ''
+  });
+
   useEffect(() => {
     fetchData();
+    fetchTorrentList();
   }, []);
 
   useEffect(() => {
@@ -25,11 +40,9 @@
 
   const fetchData = async () => {
     try {
-      // ✅ 获取促销活动列表(新接口)
-      const promoResponse = await fetch(`/seeds/promotions`);
-      const promoJson = await promoResponse.json();
-      console.log('接口返回数据:', promoJson);
-      const promoData = Array.isArray(promoJson?.result) ? promoJson.result : [];
+      const response = await fetch('/seeds/promotions');
+      const json = await response.json();
+      const promoData = Array.isArray(json?.data) ? json.data : [];
       setPromotions(promoData);
     } catch (error) {
       console.error('获取促销活动失败:', error);
@@ -38,19 +51,140 @@
     }
   };
 
+  const fetchTorrentList = async () => {
+    try {
+      const response = await fetch('/seeds/list');
+      const json = await response.json();
+      const torrentList = Array.isArray(json?.data) ? json.data : [];
+      setTorrents(torrentList);
+    } catch (error) {
+      console.error('获取种子列表失败:', error);
+    }
+  };
+
+  // 打开创建促销活动弹窗
+  const openCreateDialog = () => {
+    // 重置表单数据
+    setFormData({
+      name: '',
+      startTime: '',
+      endTime: '',
+      discountPercentage: '',
+      uploadCoeff: '',
+      downloadCoeff: '',
+      description: ''
+    });
+    setShowCreateDialog(true);
+  };
+
+  // 关闭弹窗
+  const closeCreateDialog = () => {
+    setShowCreateDialog(false);
+  };
+
+  // 处理表单输入变化
+  const handleInputChange = (e) => {
+    const { name, value } = e.target;
+    setFormData(prev => ({
+      ...prev,
+      [name]: value
+    }));
+  };
+
+  // 提交创建促销活动
+  const handleCreatePromotion = async () => {
+    if (torrents.length === 0) {
+      alert('没有可用的种子,请先上传种子');
+      return;
+    }
+    if (!formData.name.trim()) {
+      alert('促销名称不能为空');
+      return;
+    }
+    if (!formData.startTime || !formData.endTime) {
+      alert('促销开始时间和结束时间不能为空');
+      return;
+    }
+    if (new Date(formData.startTime) >= new Date(formData.endTime)) {
+      alert('促销结束时间必须晚于开始时间');
+      return;
+    }
+    if (!formData.discountPercentage || isNaN(formData.discountPercentage)) {
+      alert('折扣百分比必须是数字');
+      return;
+    }
+
+    const applicableTorrentIds = torrents.map(t => t.id);
+
+    const newPromo = {
+      name: formData.name,
+      startTime: new Date(formData.startTime).toISOString(),
+      endTime: new Date(formData.endTime).toISOString(),
+      discountPercentage: Number(formData.discountPercentage),
+      uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
+      downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
+      applicableTorrentIds: JSON.stringify(applicableTorrentIds), // ✅ 关键修改
+      description: formData.description
+    };
+
+
+    try {
+      const res = await fetch('/seeds/promotions', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify(newPromo)
+      });
+      const json = await res.json();
+      if (json.code === 200) {
+        alert('促销活动创建成功');
+        fetchData();
+        setShowCreateDialog(false);
+      } else {
+        alert('创建失败: ' + (json.msg || '未知错误'));
+      }
+    } catch (err) {
+      console.error('创建促销失败:', err);
+      alert('创建促销失败');
+    }
+  };
+
+  const handleDeletePromotion = async (promotionId) => {
+    if (!window.confirm('确认删除该促销活动吗?')) return;
+
+    try {
+      const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
+      const json = await res.json();
+      if (json.success) {
+        alert('删除成功');
+        fetchData();
+      } else {
+        alert('删除失败: ' + json.message);
+      }
+    } catch (err) {
+      console.error('删除失败:', err);
+    }
+  };
+
+  const isAdmin = user?.role === 'admin';
+  const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
+    const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
+  const currentPromo = promotions[promoIndex];
+
   if (loading) {
     return <div className="promotion-container">加载中...</div>;
   }
 
-  const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
-  const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
-  const currentPromo = promotions[promoIndex];
-
   return (
     <div className="promotion-container carousel-container">
-      {/* 促销活动轮播 */}
       <section className="carousel-section">
         <h2>当前促销活动</h2>
+
+        {isAdmin && (
+          <button className="create-btn" onClick={openCreateDialog}>
+            创建促销活动
+          </button>
+        )}
+
         {promotions.length === 0 || !currentPromo ? (
           <div className="empty-state">暂无促销活动</div>
         ) : (
@@ -76,14 +210,616 @@
               {currentPromo?.description && (
                 <div><strong>描述:</strong>{currentPromo.description}</div>
               )}
+              {isAdmin && (
+                <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
+                  删除该活动
+                </button>
+              )}
             </div>
             <button className="arrow right" onClick={nextPromo}>&gt;</button>
           </div>
         )}
       </section>
+
+      {/* 创建促销活动弹窗 */}
+      {showCreateDialog && (
+        <div className="dialog-overlay">
+          <div className="dialog">
+            <h3>创建促销活动</h3>
+            <div className="form-item">
+              <label>促销名称:</label>
+              <input
+                type="text"
+                name="name"
+                value={formData.name}
+                onChange={handleInputChange}
+                placeholder="请输入促销名称"
+              />
+            </div>
+            <div className="form-item">
+              <label>开始时间:</label>
+              <input
+                type="datetime-local"
+                name="startTime"
+                value={formData.startTime}
+                onChange={handleInputChange}
+              />
+            </div>
+            <div className="form-item">
+              <label>结束时间:</label>
+              <input
+                type="datetime-local"
+                name="endTime"
+                value={formData.endTime}
+                onChange={handleInputChange}
+              />
+            </div>
+            <div className="form-item">
+              <label>折扣百分比(数字):</label>
+              <input
+                type="number"
+                name="discountPercentage"
+                value={formData.discountPercentage}
+                onChange={handleInputChange}
+                placeholder="例如:20 表示 20% 折扣"
+                min="0"
+                max="100"
+              />
+            </div>
+            <div className="form-item">
+              <label>上传奖励系数(可选):</label>
+              <input
+                type="number"
+                name="uploadCoeff"
+                value={formData.uploadCoeff}
+                onChange={handleInputChange}
+                placeholder="例如:1.5"
+                step="0.1"
+              />
+            </div>
+            <div className="form-item">
+              <label>下载折扣系数(可选):</label>
+              <input
+                type="number"
+                name="downloadCoeff"
+                value={formData.downloadCoeff}
+                onChange={handleInputChange}
+                placeholder="例如:0.8"
+                step="0.1"
+              />
+            </div>
+            <div className="form-item">
+              <label>描述(可选):</label>
+              <textarea
+                name="description"
+                value={formData.description}
+                onChange={handleInputChange}
+                placeholder="促销活动描述"
+                rows={3}
+              />
+            </div>
+            <div className="dialog-buttons">
+              <button onClick={handleCreatePromotion}>确定</button>
+              <button onClick={closeCreateDialog}>取消</button>
+            </div>
+          </div>
+        </div>
+      )}
     </div>
   );
 };
 
 export default Promotion;
 
+
+// import React, { useEffect, useState, useRef } from 'react';
+// import './Promotion.css';
+// import { useUser } from '../../../context/UserContext';
+
+// const Promotion = () => {
+//   const { user } = useUser();
+//   const [promotions, setPromotions] = useState([]);
+//   const [torrents, setTorrents] = useState([]);
+//   const [loading, setLoading] = useState(true);
+//   const [promoIndex, setPromoIndex] = useState(0);
+//   const promoTimerRef = useRef(null);
+
+//   // 新增:控制模态框显示与表单状态
+//   const [showCreateModal, setShowCreateModal] = useState(false);
+//   const [formData, setFormData] = useState({
+//     name: '',
+//     description: '',
+//     discountPercentage: 0,
+//     startTime: '',
+//     endTime: '',
+//     applicableTorrentIds: [],
+//   });
+
+//   useEffect(() => {
+//     fetchData();
+//     fetchTorrentList();
+//   }, []);
+
+//   useEffect(() => {
+//     if (promotions.length === 0) return;
+//     clearInterval(promoTimerRef.current);
+//     promoTimerRef.current = setInterval(() => {
+//       setPromoIndex(prev => (prev + 1) % promotions.length);
+//     }, 5000);
+//     return () => clearInterval(promoTimerRef.current);
+//   }, [promotions]);
+
+//   const fetchData = async () => {
+//     try {
+//       const response = await fetch('/seeds/promotions');
+//       const json = await response.json();
+//       const promoData = Array.isArray(json?.data) ? json.data : [];
+//       setPromotions(promoData);
+//     } catch (error) {
+//       console.error('获取促销活动失败:', error);
+//     } finally {
+//       setLoading(false);
+//     }
+//   };
+
+//   const fetchTorrentList = async () => {
+//     try {
+//       const response = await fetch('/seeds/list');
+//       const json = await response.json();
+//       const torrentList = Array.isArray(json?.data) ? json.data : [];
+//       setTorrents(torrentList);
+//     } catch (error) {
+//       console.error('获取种子列表失败:', error);
+//     }
+//   };
+
+//   // 打开模态框时,重置表单数据,默认设置时间并填入所有种子ID
+//   const openCreateModal = () => {
+//     if (torrents.length === 0) {
+//       alert('没有可用的种子,请先上传种子');
+//       return;
+//     }
+//     setFormData({
+//       name: '',
+//       description: '',
+//       discountPercentage: 20,
+//       startTime: new Date().toISOString().slice(0, 16), // 用于datetime-local输入框,格式 YYYY-MM-DDTHH:mm
+//       endTime: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 16),
+//       applicableTorrentIds: torrents.map(t => t.id),
+//     });
+//     setShowCreateModal(true);
+//   };
+
+//   // 表单输入处理
+//   const handleInputChange = (e) => {
+//     const { name, value } = e.target;
+//     setFormData(prev => ({
+//       ...prev,
+//       [name]: name === 'discountPercentage' ? Number(value) : value,
+//     }));
+//   };
+
+//   // 点击确定提交创建
+//   const handleCreateConfirm = async () => {
+//     if (!formData.name) {
+//       alert('促销名称不能为空');
+//       return;
+//     }
+//     if (!formData.startTime || !formData.endTime) {
+//       alert('请选择开始时间和结束时间');
+//       return;
+//     }
+//     if (formData.discountPercentage <= 0 || formData.discountPercentage >= 100) {
+//       alert('折扣百分比应在1-99之间');
+//       return;
+//     }
+//     if (!formData.applicableTorrentIds.length) {
+//       alert('请选择适用的种子');
+//       return;
+//     }
+
+//     // 准备发送数据,适配后端字段名
+//     const newPromo = {
+//       name: formData.name,
+//       description: formData.description,
+//       discountPercentage: formData.discountPercentage,
+//       startTime: new Date(formData.startTime).toISOString(),
+//       endTime: new Date(formData.endTime).toISOString(),
+//       applicableTorrentIds: formData.applicableTorrentIds,
+//     };
+
+//     try {
+//       const res = await fetch('/seeds/promotions', {
+//         method: 'POST',
+//         headers: { 'Content-Type': 'application/json' },
+//         body: JSON.stringify(newPromo),
+//       });
+//       const json = await res.json();
+//       if (json.code === 200) {
+//         alert('促销活动创建成功');
+//         setShowCreateModal(false);
+//         fetchData();
+//       } else {
+//         alert('创建失败: ' + (json.msg || '未知错误'));
+//       }
+//     } catch (err) {
+//       console.error('创建促销失败:', err);
+//       alert('创建促销失败');
+//     }
+//   };
+
+//   const handleCancel = () => {
+//     setShowCreateModal(false);
+//   };
+
+//   const handleDeletePromotion = async (promotionId) => {
+//     if (!window.confirm('确认删除该促销活动吗?')) return;
+
+//     try {
+//       const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
+//       const json = await res.json();
+//       if (json.success) {
+//         alert('删除成功');
+//         fetchData();
+//       } else {
+//         alert('删除失败: ' + json.message);
+//       }
+//     } catch (err) {
+//       console.error('删除失败:', err);
+//     }
+//   };
+
+//   const isAdmin = user?.role === 'admin';
+//   const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
+//   const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
+//   const currentPromo = promotions[promoIndex];
+
+//   if (loading) {
+//     return <div className="promotion-container">加载中...</div>;
+//   }
+
+//   return (
+//     <div className="promotion-container carousel-container">
+//       <section className="carousel-section">
+//         <h2>当前促销活动</h2>
+
+//         {isAdmin && (
+//           <button className="create-btn" onClick={openCreateModal}>
+//             创建促销活动
+//           </button>
+//         )}
+
+//         {promotions.length === 0 || !currentPromo ? (
+//           <div className="empty-state">暂无促销活动</div>
+//         ) : (
+//           <div
+//             className="carousel"
+//             onMouseEnter={() => clearInterval(promoTimerRef.current)}
+//             onMouseLeave={() => {
+//               promoTimerRef.current = setInterval(() => {
+//                 setPromoIndex(prev => (prev + 1) % promotions.length);
+//               }, 3000);
+//             }}
+//           >
+//             <button className="arrow left" onClick={prevPromo}>&lt;</button>
+//             <div className="slide">
+//               <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
+//               <div><strong>促销时间:</strong>
+//                 {currentPromo?.startTime && currentPromo?.endTime
+//                   ? `${new Date(currentPromo.startTime).toLocaleString()} ~ ${new Date(currentPromo.endTime).toLocaleString()}`
+//                   : '未知'}
+//               </div>
+//               <div><strong>折扣百分比:</strong>{currentPromo?.discountPercentage ?? '无'}</div>
+//               {currentPromo?.description && (
+//                 <div><strong>描述:</strong>{currentPromo.description}</div>
+//               )}
+//               {isAdmin && (
+//                 <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
+//                   删除该活动
+//                 </button>
+//               )}
+//             </div>
+//             <button className="arrow right" onClick={nextPromo}>&gt;</button>
+//           </div>
+//         )}
+//       </section>
+
+//       {/* 创建促销模态框 */}
+//       {showCreateModal && (
+//         <div className="modal-overlay">
+//           <div className="modal-content">
+//             <h3>创建促销活动</h3>
+//             <label>
+//               促销名称:
+//               <input
+//                 type="text"
+//                 name="name"
+//                 value={formData.name}
+//                 onChange={handleInputChange}
+//               />
+//             </label>
+//             <label>
+//               描述:
+//               <textarea
+//                 name="description"
+//                 value={formData.description}
+//                 onChange={handleInputChange}
+//                 rows={3}
+//               />
+//             </label>
+//             <label>
+//               折扣百分比:
+//               <input
+//                 type="number"
+//                 name="discountPercentage"
+//                 value={formData.discountPercentage}
+//                 min={1}
+//                 max={99}
+//                 onChange={handleInputChange}
+//               />
+//             </label>
+//             <label>
+//               开始时间:
+//               <input
+//                 type="datetime-local"
+//                 name="startTime"
+//                 value={formData.startTime}
+//                 onChange={handleInputChange}
+//               />
+//             </label>
+//             <label>
+//               结束时间:
+//               <input
+//                 type="datetime-local"
+//                 name="endTime"
+//                 value={formData.endTime}
+//                 onChange={handleInputChange}
+//               />
+//             </label>
+//             <label>
+//               适用种子ID(逗号分隔,可留空默认所有):
+//               <input
+//                 type="text"
+//                 name="applicableTorrentIds"
+//                 value={formData.applicableTorrentIds.join(',')}
+//                 onChange={(e) => {
+//                   const ids = e.target.value
+//                     .split(',')
+//                     .map(id => id.trim())
+//                     .filter(id => id !== '')
+//                     .map(id => Number(id))
+//                     .filter(id => !isNaN(id));
+//                   setFormData(prev => ({ ...prev, applicableTorrentIds: ids }));
+//                 }}
+//               />
+//             </label>
+
+//             <div className="modal-buttons">
+//               <button onClick={handleCreateConfirm}>确定</button>
+//               <button onClick={handleCancel}>取消</button>
+//             </div>
+//           </div>
+//         </div>
+//       )}
+
+//       {/* 模态框简单样式 */}
+//       <style>{`
+//         .modal-overlay {
+//           position: fixed;
+//           top: 0; left: 0; right: 0; bottom: 0;
+//           background: rgba(0,0,0,0.4);
+//           display: flex;
+//           justify-content: center;
+//           align-items: center;
+//           z-index: 999;
+//         }
+//         .modal-content {
+//           background: white;
+//           padding: 20px;
+//           border-radius: 6px;
+//           width: 320px;
+//           max-width: 90%;
+//         }
+//         .modal-content label {
+//           display: block;
+//           margin-bottom: 10px;
+//           font-size: 14px;
+//         }
+//         .modal-content input[type="text"],
+//         .modal-content input[type="number"],
+//         .modal-content input[type="datetime-local"],
+//         .modal-content textarea {
+//           width: 100%;
+//           box-sizing: border-box;
+//           padding: 5px;
+//           font-size: 14px;
+//           margin-top: 4px;
+//         }
+//         .modal-buttons {
+//           margin-top: 15px;
+//           text-align: right;
+//         }
+//         .modal-buttons button {
+//           margin-left: 10px;
+//           padding: 6px 12px;
+//           font-size: 14px;
+//         }
+//       `}</style>
+//     </div>
+//   );
+// };
+
+// export default Promotion;
+
+
+// import React, { useEffect, useState, useRef } from 'react';
+// import './Promotion.css';
+// import { useUser } from '../../../context/UserContext';
+
+// const Promotion = () => {
+//   const { user } = useUser();
+//   const [promotions, setPromotions] = useState([]);
+//   const [torrents, setTorrents] = useState([]); // 新增,存放种子列表
+//   const [loading, setLoading] = useState(true);
+//   const [promoIndex, setPromoIndex] = useState(0);
+//   const promoTimerRef = useRef(null);
+
+//   useEffect(() => {
+//     fetchData();
+//     fetchTorrentList();  // 新增,获取种子列表
+//   }, []);
+
+//   useEffect(() => {
+//     if (promotions.length === 0) return;
+//     clearInterval(promoTimerRef.current);
+//     promoTimerRef.current = setInterval(() => {
+//       setPromoIndex(prev => (prev + 1) % promotions.length);
+//     }, 5000);
+//     return () => clearInterval(promoTimerRef.current);
+//   }, [promotions]);
+
+//   // 获取促销数据
+//   const fetchData = async () => {
+//     try {
+//       const response = await fetch('/seeds/promotions');
+//       const json = await response.json();
+//       const promoData = Array.isArray(json?.data) ? json.data : [];
+//       setPromotions(promoData);
+//     } catch (error) {
+//       console.error('获取促销活动失败:', error);
+//     } finally {
+//       setLoading(false);
+//     }
+//   };
+
+//   // 获取种子列表,赋值给torrents
+//   const fetchTorrentList = async () => {
+//     try {
+//       const response = await fetch('/seeds/list');
+//       const json = await response.json();
+//       const torrentList = Array.isArray(json?.data) ? json.data : [];
+//       setTorrents(torrentList);
+//     } catch (error) {
+//       console.error('获取种子列表失败:', error);
+//     }
+//   };
+
+//   // 创建促销时,自动使用当前种子的id列表,而不是写死
+//   const handleCreatePromotion = async () => {
+//     if (torrents.length === 0) {
+//       alert('没有可用的种子,请先上传种子');
+//       return;
+//     }
+
+//     const applicableTorrentIds = torrents.map(t => t.id); // 获取所有种子id数组
+
+//     const newPromo = {
+//       name: '测试促销活动',
+//       startTime: new Date().toISOString(),
+//       endTime: new Date(Date.now() + 7 * 86400000).toISOString(),
+//       discountPercentage: 20,
+//       applicableTorrentIds: applicableTorrentIds, // 动态传入种子ID数组
+//       description: '这是一个测试促销活动'
+//     };
+
+//     try {
+//       const res = await fetch('/seeds/promotions', {
+//         method: 'POST',
+//         headers: {
+//           'Content-Type': 'application/json'
+//         },
+//         body: JSON.stringify(newPromo)
+//       });
+//       const json = await res.json();
+//       if (json.code === 200) {
+//         alert('促销活动创建成功');
+//         fetchData();
+//       } else {
+//         alert('创建失败: ' + (json.msg || '未知错误'));
+//       }
+//     } catch (err) {
+//       console.error('创建促销失败:', err);
+//       alert('创建促销失败');
+//     }
+//   };
+
+//   const handleDeletePromotion = async (promotionId) => {
+//     if (!window.confirm('确认删除该促销活动吗?')) return;
+
+//     try {
+//       const res = await fetch(`/seeds/promotions/${promotionId}`, {
+//         method: 'DELETE'
+//       });
+//       const json = await res.json();
+//       if (json.success) {
+//         alert('删除成功');
+//         fetchData();
+//       } else {
+//         alert('删除失败: ' + json.message);
+//       }
+//     } catch (err) {
+//       console.error('删除失败:', err);
+//     }
+//   };
+
+//   const isAdmin = user?.role === 'admin';
+//   const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
+//   const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
+//   const currentPromo = promotions[promoIndex];
+
+//   if (loading) {
+//     return <div className="promotion-container">加载中...</div>;
+//   }
+
+//   return (
+//     <div className="promotion-container carousel-container">
+//       <section className="carousel-section">
+//         <h2>当前促销活动</h2>
+
+//         {isAdmin && (
+//           <button className="create-btn" onClick={handleCreatePromotion}>
+//             创建促销活动
+//           </button>
+//         )}
+
+//         {promotions.length === 0 || !currentPromo ? (
+//           <div className="empty-state">暂无促销活动</div>
+//         ) : (
+//           <div
+//             className="carousel"
+//             onMouseEnter={() => clearInterval(promoTimerRef.current)}
+//             onMouseLeave={() => {
+//               promoTimerRef.current = setInterval(() => {
+//                 setPromoIndex(prev => (prev + 1) % promotions.length);
+//               }, 3000);
+//             }}
+//           >
+//             <button className="arrow left" onClick={prevPromo}>&lt;</button>
+//             <div className="slide">
+//               <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
+//               <div><strong>促销时间:</strong>
+//                 {currentPromo?.pStartTime && currentPromo?.pEndTime
+//                   ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
+//                   : '未知'}
+//               </div>
+//               <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
+//               <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
+//               {currentPromo?.description && (
+//                 <div><strong>描述:</strong>{currentPromo.description}</div>
+//               )}
+//               {isAdmin && (
+//                 <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
+//                   删除该活动
+//                 </button>
+//               )}
+//             </div>
+//             <button className="arrow right" onClick={nextPromo}>&gt;</button>
+//           </div>
+//         )}
+//       </section>
+//     </div>
+//   );
+// };
+
+// export default Promotion;
+