用户个人中心、兴趣小组

Change-Id: I0e2f3f4ad586f237505613238cbb7bebb6118b63
diff --git a/src/pages/Forum/promotion-part/Promotion.jsx b/src/pages/Forum/promotion-part/Promotion.jsx
index 8ca4067..953a37f 100644
--- a/src/pages/Forum/promotion-part/Promotion.jsx
+++ b/src/pages/Forum/promotion-part/Promotion.jsx
@@ -1,3 +1,829 @@
+// 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(() => {
+//     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);
+//     }
+//   };
+
+//   // 打开创建促销活动弹窗
+//   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>;
+//   }
+
+//   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>
+//         ) : (
+//           <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>
+
+//       {/* 创建促销活动弹窗 */}
+//       {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;
+
+
 import React, { useEffect, useState, useRef } from 'react';
 import './Promotion.css';
 import { useUser } from '../../../context/UserContext';
@@ -123,7 +949,7 @@
       discountPercentage: Number(formData.discountPercentage),
       uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
       downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
-      applicableTorrentIds: JSON.stringify(applicableTorrentIds), // ✅ 关键修改
+      applicableTorrentIds: applicableTorrentIds,
       description: formData.description
     };
 
@@ -135,7 +961,7 @@
         body: JSON.stringify(newPromo)
       });
       const json = await res.json();
-      if (json.code === 200) {
+      if (json.code === 200 || json.code === 0) {
         alert('促销活动创建成功');
         fetchData();
         setShowCreateDialog(false);
@@ -154,11 +980,11 @@
     try {
       const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
       const json = await res.json();
-      if (json.success) {
+      if (json.code === 0 || json.code === 200) {
         alert('删除成功');
         fetchData();
       } else {
-        alert('删除失败: ' + json.message);
+        alert('删除失败: ' + (json.msg || '未知错误'));
       }
     } catch (err) {
       console.error('删除失败:', err);
@@ -310,516 +1136,3 @@
 };
 
 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;
-