用户个人中心、兴趣小组

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;
-
diff --git a/src/pages/InterestGroup/GroupFilters.jsx b/src/pages/InterestGroup/GroupFilters.jsx
index c93b495..c6c3a52 100644
--- a/src/pages/InterestGroup/GroupFilters.jsx
+++ b/src/pages/InterestGroup/GroupFilters.jsx
@@ -1,58 +1,58 @@
-import React from 'react';
-import { useGroupStore } from '../../context/useGroupStore';
+// import React from 'react';
+// import { useGroupStore } from '../../context/useGroupStore';
 
-const GroupFilters = () => {
-  const { 
-    category, setCategory, 
-    name, setName, 
-    sortBy, setSortBy,
-    handleSearch
-  } = useGroupStore();
+// const GroupFilters = () => {
+//   const { 
+//     category, setCategory, 
+//     name, setName, 
+//     sortBy, setSortBy,
+//     handleSearch
+//   } = useGroupStore();
 
-  const handleSortChange = (e) => {
-    const sortValueMap = {
-      'member_count': 'member_count',
-      'name': 'groupName',
-      'category': 'category'
-    };
-    const backendValue = sortValueMap[e.target.value] || 'member_count';
-    setSortBy(backendValue);
-  };
+//   const handleSortChange = (e) => {
+//     const sortValueMap = {
+//       'member_count': 'member_count',
+//       'name': 'groupName',
+//       'category': 'category'
+//     };
+//     const backendValue = sortValueMap[e.target.value] || 'member_count';
+//     setSortBy(backendValue);
+//   };
 
-  return (
-    <div className="filter-search-sort-container">
-      <div className="filter">
-        <label>分类:</label>
-        <select onChange={(e) => setCategory(e.target.value)} value={category}>
-          <option value="">全部</option>
-          <option value="影视">影视</option>
-          <option value="游戏">游戏</option>
-          <option value="学习">学习</option>
-          <option value="体育">体育</option>
-          <option value="其他">其他</option>
-        </select>
-      </div>
+//   return (
+//     <div className="filter-search-sort-container">
+//       <div className="filter">
+//         <label>分类:</label>
+//         <select onChange={(e) => setCategory(e.target.value)} value={category}>
+//           <option value="">全部</option>
+//           <option value="影视">影视</option>
+//           <option value="游戏">游戏</option>
+//           <option value="学习">学习</option>
+//           <option value="体育">体育</option>
+//           <option value="其他">其他</option>
+//         </select>
+//       </div>
 
-      <div className="sort">
-        <label>排序:</label>
-        <select onChange={handleSortChange} value={sortBy}>
-          <option value="member_count">按成员数排序</option>
-          <option value="name">按名称排序</option>
-          <option value="category">按分类排序</option>
-        </select>
-      </div>
+//       <div className="sort">
+//         <label>排序:</label>
+//         <select onChange={handleSortChange} value={sortBy}>
+//           <option value="member_count">按成员数排序</option>
+//           <option value="name">按名称排序</option>
+//           <option value="category">按分类排序</option>
+//         </select>
+//       </div>
 
-      <div className="search">
-        <input
-          type="text"
-          value={name}
-          onChange={(e) => setName(e.target.value)}
-          placeholder="输入小组名称搜索"
-        />
-        <button onClick={handleSearch}>搜索</button>
-      </div>
-    </div>
-  );
-};
+//       <div className="search">
+//         <input
+//           type="text"
+//           value={name}
+//           onChange={(e) => setName(e.target.value)}
+//           placeholder="输入小组名称搜索"
+//         />
+//         <button onClick={handleSearch}>搜索</button>
+//       </div>
+//     </div>
+//   );
+// };
 
-export default GroupFilters;
\ No newline at end of file
+// export default GroupFilters;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/GroupItem.jsx b/src/pages/InterestGroup/GroupItem.jsx
index 736f88d..ea2253f 100644
--- a/src/pages/InterestGroup/GroupItem.jsx
+++ b/src/pages/InterestGroup/GroupItem.jsx
@@ -1,97 +1,3 @@
-// import React, { useState, useEffect } from 'react';
-// import { useGroupStore } from '../../context/useGroupStore';
-// import { useUser } from '../../context/UserContext';
-// import CreatePostForm from './CreatePostForm';
-// import axios from 'axios'; // 新增
-
-// const GroupItem = ({ group }) => {
-//   const { handleJoinGroup, joinStatus, setJoinStatus } = useGroupStore(); // 假设你有 setJoinStatus 方法
-//   const { user } = useUser();
-
-//   const userId = user?.userId;
-//   const groupId = group.groupId;
-
-//   const [isMember, setIsMember] = useState(false);
-
-//   useEffect(() => {
-//     setIsMember(joinStatus[groupId] === '加入成功');
-//   }, [joinStatus, groupId]);
-
-//   const [showCreatePost, setShowCreatePost] = useState(false);
-
-//   // 退出小组函数(新增)
-//   const handleLeaveGroup = async () => {
-//     try {
-//       const res = await axios.post(`/echo/groups/${groupId}/leave`, {
-//         user_id: userId,
-//       });
-//       if (res.data.status === 'success') {
-//         setJoinStatus(groupId, '未加入'); // 更新全局状态(需确保 useGroupStore 中有此方法)
-//         setIsMember(false); // 本地状态也更新
-//       } else {
-//         alert(res.data.message || '退出失败');
-//       }
-//     } catch (error) {
-//       console.error('退出小组失败:', error);
-//       alert('退出小组失败');
-//     }
-//   };
-
-//   return (
-//     <div className="group-item">
-//       <div className="group-content">
-//         <img
-//           style={{ width: '40%', height: '40%' }}
-//           src={group.coverImage || 'https://picsum.photos/200/200'}
-//           alt={group.groupName}
-//           className="group-cover"
-//         />
-//         <div className="group-info-right">
-//           <h3>{group.groupName}</h3>
-//           <p style={{ color: '#BA929A' }}>{group.memberCount || 0}人加入了小组</p>
-
-//           {/* 加入/退出按钮逻辑 */}
-//           {userId && (
-//             <button
-//               onClick={() => {
-//                 if (isMember) {
-//                   handleLeaveGroup(); // 已加入 -> 退出
-//                 } else {
-//                   handleJoinGroup(groupId, userId); // 未加入 -> 加入
-//                 }
-//               }}
-//             >
-//               {isMember ? '退出小组' : '+加入小组'}
-//             </button>
-//           )}
-//           {!userId && <button disabled>请登录</button>}
-
-//           {/* 发布帖子按钮 */}
-//           {userId && isMember && (
-//             <button onClick={() => setShowCreatePost(!showCreatePost)}>
-//               +发布帖子
-//             </button>
-//           )}
-//         </div>
-//       </div>
-
-//       <div className="group-description">
-//         <p>{group.description}</p>
-//       </div>
-//       <p>分类:{group.category}</p>
-
-//       {showCreatePost && (
-//         <CreatePostForm 
-//           groupId={groupId}
-//           onClose={() => setShowCreatePost(false)}
-//         />
-//       )}
-//     </div>
-//   );
-// };
-
-// export default GroupItem;
-
 import React, { useState, useEffect } from 'react';
 import { useGroupStore } from '../../context/useGroupStore';
 import { useUser } from '../../context/UserContext';
@@ -99,7 +5,7 @@
 import axios from 'axios';
 
 const GroupItem = ({ group }) => {
-  const { handleJoinGroup, joinStatus, setJoinStatus } = useGroupStore();
+  const { handleJoinGroup, joinStatus, setJoinStatus,fetchGroupList } = useGroupStore();
   const { user } = useUser();
 
   const userId = user?.userId;
@@ -126,7 +32,8 @@
     try {
       const res = await axios.get(`/echo/groups/${groupId}/members`);
       const isMember = res.data.members.some(member => member.user_id === userId);
-      setJoinStatus(groupId, isMember ? '加入成功' : '未加入');
+      setIsMember(isMember);
+      // setJoinStatus(groupId, isMember ? '加入成功' : '未加入');
     } catch (error) {
       console.error('检查成员状态失败:', error);
     }
@@ -141,7 +48,8 @@
         user_id: userId,
       });
       if (res.data.status === 'success') {
-        setJoinStatus(groupId, '未加入');
+          fetchGroupList(); // 刷新小组列表
+        // setJoinStatus(groupId, '未加入');
         setIsMember(false);
         // 可选:刷新小组成员计数
         group.memberCount = (group.memberCount || 0) - 1;
diff --git a/src/pages/InterestGroup/InterestGroup.css b/src/pages/InterestGroup/InterestGroup.css
index 91b21da..f819038 100644
--- a/src/pages/InterestGroup/InterestGroup.css
+++ b/src/pages/InterestGroup/InterestGroup.css
@@ -204,4 +204,82 @@
   margin-top: 40px;
   /* padding: 24px 32px; */
   padding: 3% 3%
-}    
\ No newline at end of file
+}    
+
+.create-group-btn {
+  background-color: #f2d0c9; /* 浅粉色 */
+  color: #4e342e; /* 深棕色 */
+  border: none;
+  padding: 10px 20px;
+  margin: 20px 0;
+  border-radius: 8px;
+  font-size: 16px;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+}
+
+.create-group-btn:hover {
+  background-color: #e4b5ae;
+}
+
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(50, 30, 20, 0.5); /* 米棕半透明 */
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  background-color: #fffaf5; /* 淡米色 */
+  padding: 30px;
+  border-radius: 12px;
+  width: 400px;
+  box-shadow: 0 5px 15px rgba(0,0,0,0.2);
+}
+
+.modal-content h2 {
+  margin-bottom: 15px;
+  color: #4e342e;
+}
+
+.modal-content input,
+.modal-content textarea {
+  width: 100%;
+  padding: 10px;
+  margin: 8px 0;
+  border: 1px solid #d3c0b0;
+  border-radius: 6px;
+  font-size: 14px;
+}
+
+.modal-buttons {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  margin-top: 15px;
+}
+
+.modal-buttons button {
+  padding: 8px 16px;
+  border: none;
+  border-radius: 6px;
+  font-weight: bold;
+  cursor: pointer;
+  font-size: 14px;
+}
+
+.modal-buttons button:first-child {
+  background-color: #d7a29e; /* 粉棕 */
+  color: white;
+}
+
+.modal-buttons button:last-child {
+  background-color: #c5b8af; /* 米色灰棕 */
+  color: white;
+}
diff --git a/src/pages/InterestGroup/InterestGroup.jsx b/src/pages/InterestGroup/InterestGroup.jsx
index b89cf57..0b5b002 100644
--- a/src/pages/InterestGroup/InterestGroup.jsx
+++ b/src/pages/InterestGroup/InterestGroup.jsx
@@ -1,23 +1,217 @@
-import React, { useEffect } from 'react';
+// // import React, { useEffect } from 'react';
+// // import Header from '../../components/Header';
+// // import { useGroupStore } from '../../context/useGroupStore';
+// // // import GroupFilters from './GroupFilters';
+// // import GroupList from './GroupList';
+// // import GroupPagination from './GroupPagination';
+// // import './InterestGroup.css';
+// // const InterestGroup = () => {
+// //   const { fetchGroupList, setPage, handleSearch } = useGroupStore();
+
+// //   // 初始化加载
+// //   useEffect(() => {
+// //     fetchGroupList();
+// //   }, [fetchGroupList]);
+
+// //   return (
+// //     <div className="interest-group-container">
+// //       <Header />
+// //       <div className="interest-group-card">
+// //         {/* <GroupFilters /> */}
+// //         <GroupList />
+// //         <GroupPagination />
+// //       </div>
+// //     </div>
+// //   );
+// // };
+
+// // export default InterestGroup;
+
+// import React, { useEffect, useState } from 'react';
+// import Header from '../../components/Header';
+// import { useGroupStore } from '../../context/useGroupStore';
+// import GroupList from './GroupList';
+// import GroupPagination from './GroupPagination';
+// import './InterestGroup.css';
+// import axios from 'axios';
+
+// const InterestGroup = () => {
+//   const { fetchGroupList } = useGroupStore();
+
+//   const [showModal, setShowModal] = useState(false);
+//   const [groupName, setGroupName] = useState('');
+//   const [groupDescription, setGroupDescription] = useState('');
+
+//   useEffect(() => {
+//     fetchGroupList();
+//   }, [fetchGroupList]);
+
+//   const handleCreateGroup = async () => {
+//   try {
+//     const res = await axios.post('http://localhost:3011/echo/groups/createGroup', {
+//       user_id: 1,
+//       group_name: groupName,               // ✅ 改为 snake_case
+//       description: groupDescription,
+//       time: new Date().toISOString(),
+//       category: '默认分类',
+//       cover_image: 'https://picsum.photos/300/200',
+//     });
+
+//     if (res.status === 200 && res.data.status === 'success') {
+//       alert('小组创建成功');
+//       setShowModal(false);
+//       setGroupName('');
+//       setGroupDescription('');
+//       fetchGroupList();
+//     } else {
+//       alert('创建失败: ' + res.data.message);
+//     }
+//   } catch (error) {
+//     alert('创建失败,请检查网络或输入');
+//     console.error(error);
+//   }
+// };
+
+
+//   // const handleCreateGroup = async () => {
+//   //   try {
+//   //     const res = await axios.post('/createGroup', {
+//   //       groupName,
+//   //       description: groupDescription,
+//   //     });
+//   //     if (res.status === 200) {
+//   //       alert('小组创建成功');
+//   //       setShowModal(false);
+//   //       setGroupName('');
+//   //       setGroupDescription('');
+//   //       fetchGroupList(); // 刷新列表
+//   //     }
+//   //   } catch (error) {
+//   //     alert('创建失败,请重试');
+//   //   }
+//   // };
+
+//   return (
+//     <div className="interest-group-container">
+//       <Header />
+//       <div className="interest-group-card">
+//         <button className="create-group-btn" onClick={() => setShowModal(true)}>
+//           创建小组
+//         </button>
+
+//         {showModal && (
+//           <div className="modal-overlay">
+//             <div className="modal-content">
+//               <h2>创建新小组</h2>
+//               <input
+//                 type="text"
+//                 placeholder="小组名称"
+//                 value={groupName}
+//                 onChange={(e) => setGroupName(e.target.value)}
+//               />
+//               <textarea
+//                 placeholder="小组简介"
+//                 value={groupDescription}
+//                 onChange={(e) => setGroupDescription(e.target.value)}
+//               />
+//               <div className="modal-buttons">
+//                 <button onClick={handleCreateGroup}>确定</button>
+//                 <button onClick={() => setShowModal(false)}>取消</button>
+//               </div>
+//             </div>
+//           </div>
+//         )}
+
+//         <GroupList />
+//         <GroupPagination />
+//       </div>
+//     </div>
+//   );
+// };
+
+// export default InterestGroup;
+
+
+import React, { useEffect, useState } from 'react';
 import Header from '../../components/Header';
 import { useGroupStore } from '../../context/useGroupStore';
-import GroupFilters from './GroupFilters';
 import GroupList from './GroupList';
 import GroupPagination from './GroupPagination';
 import './InterestGroup.css';
-const InterestGroup = () => {
-  const { fetchGroupList, setPage, handleSearch } = useGroupStore();
+import axios from 'axios';
 
-  // 初始化加载
+const InterestGroup = () => {
+  const { fetchGroupList } = useGroupStore();
+
+  const [showModal, setShowModal] = useState(false);
+  const [groupName, setGroupName] = useState('');
+  const [groupDescription, setGroupDescription] = useState('');
+
   useEffect(() => {
     fetchGroupList();
   }, [fetchGroupList]);
 
+  const handleCreateGroup = async () => {
+    try {
+      // ✅ 修改请求体字段名,使用驼峰命名法
+      const res = await axios.post('http://localhost:3011/echo/groups/createGroup', {
+        userId: 1,                 // 改为驼峰命名 userId
+        groupName: groupName,      // 改为驼峰命名 groupName
+        description: groupDescription,
+        // 移除time字段,使用后端生成的时间
+        memberCount: 1,            // 添加初始成员数
+        category: '默认分类',
+        coverImage: 'https://picsum.photos/300/200',  // 改为驼峰命名 coverImage
+      });
+
+      if (res.status === 200 && res.data.status === 'success') {
+        alert('小组创建成功');
+        setShowModal(false);
+        setGroupName('');
+        setGroupDescription('');
+        fetchGroupList(); // 刷新列表
+      } else {
+        // 显示后端返回的详细错误信息
+        alert('创建失败: ' + res.data.message);
+      }
+    } catch (error) {
+      // 处理网络错误或其他异常
+      alert('创建失败,请检查网络连接或输入内容');
+      console.error('创建小组错误:', error);
+    }
+  };
+
   return (
     <div className="interest-group-container">
       <Header />
       <div className="interest-group-card">
-        <GroupFilters />
+        <button className="create-group-btn" onClick={() => setShowModal(true)}>
+          创建小组
+        </button>
+
+        {showModal && (
+          <div className="modal-overlay">
+            <div className="modal-content">
+              <h2>创建新小组</h2>
+              <input
+                type="text"
+                placeholder="小组名称"
+                value={groupName}
+                onChange={(e) => setGroupName(e.target.value)}
+              />
+              <textarea
+                placeholder="小组简介"
+                value={groupDescription}
+                onChange={(e) => setGroupDescription(e.target.value)}
+              />
+              <div className="modal-buttons">
+                <button onClick={handleCreateGroup}>确定</button>
+                <button onClick={() => setShowModal(false)}>取消</button>
+              </div>
+            </div>
+          </div>
+        )}
+
         <GroupList />
         <GroupPagination />
       </div>
diff --git a/src/pages/LevelPage/LevelPage.jsx b/src/pages/LevelPage/LevelPage.jsx
index 55ce6b6..a7b8ea3 100644
--- a/src/pages/LevelPage/LevelPage.jsx
+++ b/src/pages/LevelPage/LevelPage.jsx
@@ -1,100 +1,100 @@
-import React, { useEffect, useState } from 'react';
-import { getExperience, updateExperience, checkUpgrade, upgradeUserLevel } from '../../api/level';
-import LevelCard from '../../components/LevelCard';
+// import React, { useEffect, useState } from 'react';
+// import { getExperience, updateExperience, checkUpgrade, upgradeUserLevel } from '../../api/level';
+// import LevelCard from '../../components/LevelCard';
 
-const user_id = 1; // 实际项目中请从用户上下文获取
+// const user_id = 1; // 实际项目中请从用户上下文获取
 
-const LevelPage = () => {
-  const [levelInfo, setLevelInfo] = useState(null);
-  const [upgradeStatus, setUpgradeStatus] = useState(null);
-  const [message, setMessage] = useState('');
+// const LevelPage = () => {
+//   const [levelInfo, setLevelInfo] = useState(null);
+//   const [upgradeStatus, setUpgradeStatus] = useState(null);
+//   const [message, setMessage] = useState('');
 
-  const fetchExperience = async () => {
-    try {
-      const res = await getExperience(user_id);
-      setLevelInfo(res.data);
-    } catch (error) {
-      console.error(error);
-    }
-  };
+//   const fetchExperience = async () => {
+//     try {
+//       const res = await getExperience(user_id);
+//       setLevelInfo(res.data);
+//     } catch (error) {
+//       console.error(error);
+//     }
+//   };
 
-  const handleUpdate = async () => {
-    try {
-      const res = await updateExperience({ user_id, experience: 50, source: '签到' });
-      setMessage(res.data.message || '经验更新成功');
-      fetchExperience();
-    } catch (error) {
-      console.error(error);
-    }
-  };
+//   const handleUpdate = async () => {
+//     try {
+//       const res = await updateExperience({ user_id, experience: 50, source: '签到' });
+//       setMessage(res.data.message || '经验更新成功');
+//       fetchExperience();
+//     } catch (error) {
+//       console.error(error);
+//     }
+//   };
 
-  const handleCheckUpgrade = async () => {
-    try {
-      const res = await checkUpgrade(user_id);
-      setUpgradeStatus(res.data);
-    } catch (error) {
-      console.error(error);
-    }
-  };
+//   const handleCheckUpgrade = async () => {
+//     try {
+//       const res = await checkUpgrade(user_id);
+//       setUpgradeStatus(res.data);
+//     } catch (error) {
+//       console.error(error);
+//     }
+//   };
 
-  const handleUpgrade = async () => {
-    try {
-      const res = await upgradeUserLevel({ user_id, can_upgrade: true });
-      setMessage(res.data.message || '升级成功');
-      fetchExperience();
-    } catch (error) {
-      setMessage(error.response?.data?.message || '升级失败');
-    }
-  };
+//   const handleUpgrade = async () => {
+//     try {
+//       const res = await upgradeUserLevel({ user_id, can_upgrade: true });
+//       setMessage(res.data.message || '升级成功');
+//       fetchExperience();
+//     } catch (error) {
+//       setMessage(error.response?.data?.message || '升级失败');
+//     }
+//   };
 
-  useEffect(() => {
-    fetchExperience();
-  }, []);
+//   useEffect(() => {
+//     fetchExperience();
+//   }, []);
 
-  return (
-    <div className="max-w-xl mx-auto p-4">
-      <h1 className="text-2xl font-bold mb-4">我的等级</h1>
-      {levelInfo && (
-        <LevelCard
-          level={levelInfo.level}
-          current={levelInfo.current_experience}
-          next={levelInfo.next_level_experience}
-        />
-      )}
+//   return (
+//     <div className="max-w-xl mx-auto p-4">
+//       <h1 className="text-2xl font-bold mb-4">我的等级</h1>
+//       {levelInfo && (
+//         <LevelCard
+//           level={levelInfo.level}
+//           current={levelInfo.current_experience}
+//           next={levelInfo.next_level_experience}
+//         />
+//       )}
 
-      <div className="space-x-2 mb-4">
-        <button
-          onClick={handleUpdate}
-          className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
-        >
-          模拟签到加经验
-        </button>
-        <button
-          onClick={handleCheckUpgrade}
-          className="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
-        >
-          检查是否可升级
-        </button>
-      </div>
+//       <div className="space-x-2 mb-4">
+//         <button
+//           onClick={handleUpdate}
+//           className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
+//         >
+//           模拟签到加经验
+//         </button>
+//         <button
+//           onClick={handleCheckUpgrade}
+//           className="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
+//         >
+//           检查是否可升级
+//         </button>
+//       </div>
 
-      {upgradeStatus && (
-        <div className="mb-4">
-          {upgradeStatus.can_upgrade ? (
-            <button
-              onClick={handleUpgrade}
-              className="px-4 py-2 bg-purple-600 text-white rounded hover:bg-purple-700"
-            >
-              升级到下一级
-            </button>
-          ) : (
-            <p className="text-gray-700">当前还不能升级。</p>
-          )}
-        </div>
-      )}
+//       {upgradeStatus && (
+//         <div className="mb-4">
+//           {upgradeStatus.can_upgrade ? (
+//             <button
+//               onClick={handleUpgrade}
+//               className="px-4 py-2 bg-purple-600 text-white rounded hover:bg-purple-700"
+//             >
+//               升级到下一级
+//             </button>
+//           ) : (
+//             <p className="text-gray-700">当前还不能升级。</p>
+//           )}
+//         </div>
+//       )}
 
-      {message && <div className="text-sm text-green-700 mt-2">{message}</div>}
-    </div>
-  );
-};
+//       {message && <div className="text-sm text-green-700 mt-2">{message}</div>}
+//     </div>
+//   );
+// };
 
-export default LevelPage;
+// export default LevelPage;
diff --git a/src/pages/PromotionsPage/PromotionsPage.css b/src/pages/PromotionsPage/PromotionsPage.css
index 6752c69..bc5bf8c 100644
--- a/src/pages/PromotionsPage/PromotionsPage.css
+++ b/src/pages/PromotionsPage/PromotionsPage.css
@@ -1,4 +1,4 @@
-.promotions-page {
+/* .promotions-page {
     padding: 20px;
     font-family: Arial, sans-serif;
 }
@@ -203,4 +203,4 @@
 
 .pagination span {
     font-size: 14px;
-}
\ No newline at end of file
+} */
\ No newline at end of file
diff --git a/src/pages/UserCenter/UserCollect.css b/src/pages/UserCenter/UserCollect.css
index fe7b3bd..79caaf6 100644
--- a/src/pages/UserCenter/UserCollect.css
+++ b/src/pages/UserCenter/UserCollect.css
@@ -1,11 +1,11 @@
-.user-center {
+/* .user-center {
   max-width: 100%;
   padding: 3%;
   font-family: Arial, sans-serif;
   display: flex;
   gap: 10%;
   background: #333;
-}
+} */
 
 .post-item {
   margin-bottom: 20px;
diff --git a/src/pages/UserCenter/UserDynamics.css b/src/pages/UserCenter/UserDynamics.css
index 40a11b4..5380c57 100644
--- a/src/pages/UserCenter/UserDynamics.css
+++ b/src/pages/UserCenter/UserDynamics.css
@@ -17,12 +17,13 @@
 }
 
 .dynamic-card {
-  background: #fff;
-  border: 1px solid #eee;
+  background: #E4D8C9;
+  /* border: 1px solid #eee; */
   border-radius: 12px;
   padding: 20px;
   margin-bottom: 20px;
   box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
+  width: 100%;
 }
 
 .dynamic-header {
diff --git a/src/pages/UserCenter/UserDynamics.jsx b/src/pages/UserCenter/UserDynamics.jsx
index 05d9046..d494c52 100644
--- a/src/pages/UserCenter/UserDynamics.jsx
+++ b/src/pages/UserCenter/UserDynamics.jsx
@@ -29,7 +29,7 @@
 
   return (
     <div className="user-dynamics-container">
-      <h2 className="user-dynamics-title">我的动态</h2>
+      {/* <h2 className="user-dynamics-title">我的动态</h2> */}
       {dynamics.length === 0 ? (
         <div className="user-dynamics-empty">暂无动态</div>
       ) : (
@@ -49,13 +49,6 @@
             <div className="dynamic-content">
               {item.title && <h4 className="dynamic-title">{item.title}</h4>}
               <p>{item.content}</p>
-              {/* {item.images && (
-                <div className="dynamic-images">
-                  {JSON.parse(item.images).map((img, index) => (
-                    <img key={index} src={img} alt={`图${index + 1}`} />
-                  ))}
-                </div>
-              )} */}
               {item.images && (
                 <div className="dynamic-images">
                     {(() => {
diff --git a/src/pages/UserCenter/UserFriends.css b/src/pages/UserCenter/UserFriends.css
index 2533959..37f6c9b 100644
--- a/src/pages/UserCenter/UserFriends.css
+++ b/src/pages/UserCenter/UserFriends.css
@@ -19,6 +19,8 @@
 
 .friend-info {
   flex: 1;
+  /* 字体大小 */
+  font-size: 1.3em;
 }
 
 .friend-info h4 {
diff --git a/src/pages/UserCenter/UserFriends.jsx b/src/pages/UserCenter/UserFriends.jsx
index 5540911..491c19c 100644
--- a/src/pages/UserCenter/UserFriends.jsx
+++ b/src/pages/UserCenter/UserFriends.jsx
@@ -335,13 +335,25 @@
 
   return (
     <div className="user-subpage-card">
-      <h2>我的好友</h2>
-      <div>
-        <input type="text" value={email} placeholder="请输入好友邮箱" onChange={e => setEmail(e.target.value)} />
+
+      <div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginLeft: '-12%' }}>
+        <div className="search">
+          <input
+            type="text"
+            value={email}
+            onChange={(e) => setEmail(e.target.value)}
+            placeholder="搜索邮箱添加好友"
+          />
+        </div>
+
         <button className="btn submit" onClick={handleSubmit}>
           添加
         </button>
       </div>
+
+      {/* 增加间距 */}
+      <div style={{ marginBottom: '30px' }}></div>
+
       <div className="friends-list">
         {friends.length === 0 && <p>暂无好友</p>}
         {friends.map((friend) => (
@@ -350,7 +362,7 @@
             <div className="friend-info">
               <p><strong>{friend.nickname}</strong></p>
               <p>{friend.email}</p>
-              <button className="send-message-btn" onClick={() => openChat(friend)}>
+              <button style={{ padding: '6px 12px', fontSize: '15px', float: 'right' }} onClick={() => openChat(friend)}>
                 发送私信
               </button>
             </div>
diff --git a/src/pages/UserCenter/UserLevelExperience.jsx b/src/pages/UserCenter/UserLevelExperience.jsx
new file mode 100644
index 0000000..60dcd55
--- /dev/null
+++ b/src/pages/UserCenter/UserLevelExperience.jsx
@@ -0,0 +1,375 @@
+// import React, { useState, useEffect } from 'react';
+// import axios from 'axios';
+
+// const UserLevelExperience = ({ userId }) => {
+//   const [experienceInfo, setExperienceInfo] = useState(null);
+//   const [error, setError] = useState(null);
+//   const [isLoading, setIsLoading] = useState(false);
+//   const [upgradeResult, setUpgradeResult] = useState(null);
+//   const [hasCheckedIn, setHasCheckedIn] = useState(false);
+
+//   useEffect(() => {
+//     if (!userId) return;
+//     fetchAllLevelData();
+//   }, [userId]);
+
+//   useEffect(() => {
+//     // 自动触发升级判断
+//     if (
+//       experienceInfo &&
+//       experienceInfo.current_experience >= experienceInfo.next_level_experience
+//     ) {
+//       checkUpgrade();
+//     }
+//   }, [experienceInfo]);
+
+//   const fetchAllLevelData = async () => {
+//     try {
+//       setIsLoading(true);
+//       setError(null);
+
+//       const { data } = await axios.get('/echo/level/getExperience', {
+//         params: { user_id: userId },
+//       });
+
+//       const normalizedData = {
+//         ...data,
+//         current_level: data.current_level || data.level,
+//       };
+
+//       setExperienceInfo(normalizedData);
+
+//       const today = new Date().toDateString();
+//       const lastCheckIn = localStorage.getItem('lastCheckIn');
+//       setHasCheckedIn(lastCheckIn === today);
+//     } catch (err) {
+//       console.error('经验信息获取失败:', err);
+//       setError('获取经验信息失败');
+//     } finally {
+//       setIsLoading(false);
+//     }
+//   };
+
+//   const updateExperience = async (source, amount = 10) => {
+//     try {
+//       setIsLoading(true);
+//       setError(null);
+
+//       const { data } = await axios.post('/echo/level/updateExperience', {
+//         user_id: userId,
+//         experience: amount,
+//         source: source,
+//       });
+
+//       setExperienceInfo((prev) => ({
+//         ...prev,
+//         current_experience: data.current_experience,
+//       }));
+
+//       alert(`获得${amount}点经验值!来源:${source}`);
+
+//       if (source === 'check-in') {
+//         localStorage.setItem('lastCheckIn', new Date().toDateString());
+//         setHasCheckedIn(true);
+//       }
+//     } catch (err) {
+//       console.error('更新经验失败:', err);
+//       setError(err.response?.data?.message || '更新经验失败');
+//     } finally {
+//       setIsLoading(false);
+//     }
+//   };
+
+//   const checkUpgrade = async () => {
+//     try {
+//       setIsLoading(true);
+//       setError(null);
+
+//       const { data } = await axios.get('/echo/level/upgrade-check', {
+//         params: { user_id: userId },
+//       });
+
+//       if (data.can_upgrade) {
+//         await performUpgrade(); // 自动触发
+//       }
+//     } catch (err) {
+//       console.error('检查升级失败:', err);
+//       setError(err.response?.data?.message || '检查升级失败');
+//     } finally {
+//       setIsLoading(false);
+//     }
+//   };
+
+
+// const performUpgrade = async () => {
+//   try {
+//     setIsLoading(true);
+//     setError(null);
+
+//     const { data } = await axios.post('/echo/level/upgrades', {
+//       user_id: userId,
+//       can_upgrade: true,
+//     });
+
+//     console.log('升级响应数据:', data); // 保留调试日志
+
+//     setExperienceInfo((prev) => ({
+//       ...prev,
+//       current_level: data.new_level, // 修复:使用正确的字段名
+//       current_experience: 0,
+//       next_level_experience: prev.next_level_experience * 2,
+//     }));
+
+//     setUpgradeResult(data);
+//     alert(`恭喜!您已升级到等级 ${data.new_level}!`); // 修复:使用正确的字段名
+//   } catch (err) {
+//     console.error('升级失败:', err);
+//     setError(err.response?.data?.message || '升级失败');
+//   } finally {
+//     setIsLoading(false);
+//   }
+// };
+
+
+//   if (error) return <p className="error">{error}</p>;
+//   if (isLoading) return <p>加载中...</p>;
+//   if (!experienceInfo) return <p>加载经验信息中...</p>;
+
+//   const { current_experience, next_level_experience, current_level } = experienceInfo;
+//   const progressPercent = Math.min(
+//     100,
+//     (current_experience / (next_level_experience || 1)) * 100
+//   ).toFixed(2);
+
+//   const expToNextLevel = Math.max(0, next_level_experience - current_experience); // 防止负数
+
+//   return (
+//     <div className="level-experience-section">
+//       {/* <h3>等级与经验</h3> */}
+//       <p><strong>当前等级:</strong>{current_level || '未知'}</p>
+//       <p><strong>当前经验:</strong>{current_experience}</p>
+//       <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
+
+//       <div className="exp-bar-wrapper">
+//         <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
+//       </div>
+//       <p className="exp-progress-text">{progressPercent}%</p>
+
+
+//       {upgradeResult && (
+//         <div className="upgrade-success">
+//             {/* 使用与状态一致的字段名 */}
+//             <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
+//         </div>
+//         )}
+      
+
+//       <div className="level-actions">
+//         <button onClick={() => updateExperience('check-in', 15)} disabled={hasCheckedIn}>
+//           {hasCheckedIn ? '今日已签到' : '每日签到 (+15经验)'}
+//         </button>
+//         <button onClick={() => updateExperience('task', 30)}>完成任务 (+30经验)</button>
+//         <button onClick={() => updateExperience('upload', 50)}>上传种子 (+50经验)</button>
+//         {/* <button onClick={checkUpgrade}>检查升级</button> */}
+//       </div>
+//     </div>
+//   );
+// };
+
+// export default UserLevelExperience;
+
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+
+const UserLevelExperience = ({ userId }) => {
+  const [experienceInfo, setExperienceInfo] = useState(null);
+  const [error, setError] = useState(null);
+  const [isLoading, setIsLoading] = useState(false);
+  const [upgradeResult, setUpgradeResult] = useState(null);
+  const [hasCheckedIn, setHasCheckedIn] = useState(false);
+
+  useEffect(() => {
+    if (!userId) return;
+    fetchAllLevelData();
+  }, [userId]);
+
+  useEffect(() => {
+    // 自动触发升级判断
+    if (
+      experienceInfo &&
+      experienceInfo.current_experience >= experienceInfo.next_level_experience
+    ) {
+      checkUpgrade();
+    }
+  }, [experienceInfo]);
+
+  const fetchAllLevelData = async () => {
+    try {
+      setIsLoading(true);
+      setError(null);
+
+      const { data } = await axios.get('/echo/level/getExperience', {
+        params: { user_id: userId },
+      });
+
+      const normalizedData = {
+        ...data,
+        current_level: data.current_level || data.level,
+      };
+
+      setExperienceInfo(normalizedData);
+
+      const today = new Date().toDateString();
+      const lastCheckIn = localStorage.getItem('lastCheckIn');
+      setHasCheckedIn(lastCheckIn === today);
+    } catch (err) {
+      console.error('经验信息获取失败:', err);
+      setError('获取经验信息失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  const updateExperience = async (source, amount = 10) => {
+    try {
+      setIsLoading(true);
+      setError(null);
+
+      const { data } = await axios.post('/echo/level/updateExperience', {
+        user_id: userId,
+        experience: amount,
+        source: source,
+      });
+
+      setExperienceInfo((prev) => ({
+        ...prev,
+        current_experience: data.current_experience,
+      }));
+
+      alert(`获得${amount}点经验值!来源:${source}`);
+
+      if (source === 'check-in') {
+        localStorage.setItem('lastCheckIn', new Date().toDateString());
+        setHasCheckedIn(true);
+      }
+    } catch (err) {
+      console.error('更新经验失败:', err);
+      setError(err.response?.data?.message || '更新经验失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  const checkUpgrade = async () => {
+    try {
+      setIsLoading(true);
+      setError(null);
+
+      const { data } = await axios.get('/echo/level/upgrade-check', {
+        params: { user_id: userId },
+      });
+
+      if (data.can_upgrade) {
+        if (window.confirm('您已满足升级条件,是否要升级?')) {
+          await performUpgrade();
+        }
+      } else {
+        // 区分是经验不足还是已达最高等级
+        if (data.is_max_level) {
+          alert('您已达到最高等级!');
+        } else {
+          alert(`还不能升级,还需要${data.next_level_experience - data.current_experience}点经验值`);
+        }
+      }
+    } catch (err) {
+      console.error('检查升级失败:', err);
+      setError(err.response?.data?.message || '检查升级失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  const performUpgrade = async () => {
+    try {
+      setIsLoading(true);
+      setError(null);
+
+      const { data } = await axios.post('/echo/level/upgrades', {
+        user_id: userId,
+        can_upgrade: true,
+      });
+
+      console.log('升级响应数据:', data);
+
+      // 正确处理升级结果
+      if (data.status === 'success') {
+        setExperienceInfo((prev) => ({
+          ...prev,
+          current_level: data.new_level,
+          current_experience: 0,
+          next_level_experience: prev.next_level_experience * 2,
+        }));
+
+        setUpgradeResult(data);
+        alert(`恭喜!您已升级到等级 ${data.new_level}!`);
+      } else {
+        throw new Error(data.message || '升级失败');
+      }
+    } catch (err) {
+      console.error('升级失败:', err);
+      setError(err.message || '升级失败');
+      alert(err.message || '升级失败,请稍后再试');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  if (error) return <p className="error">{error}</p>;
+  if (isLoading) return <p>加载中...</p>;
+  if (!experienceInfo) return <p>加载经验信息中...</p>;
+
+  const { current_experience, next_level_experience, current_level } = experienceInfo;
+  const progressPercent = Math.min(
+    100,
+    (current_experience / (next_level_experience || 1)) * 100
+  ).toFixed(2);
+
+  const expToNextLevel = Math.max(0, next_level_experience - current_experience);
+
+  return (
+    <div className="level-experience-section">
+      <h3>等级与经验</h3>
+      <p><strong>当前等级:</strong>{current_level || '未知'}</p>
+      <p><strong>当前经验:</strong>{current_experience}</p>
+      <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
+
+      <div className="exp-bar-wrapper">
+        <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
+      </div>
+      <p className="exp-progress-text">{progressPercent}%</p>
+
+      {upgradeResult && (
+        <div className="upgrade-success">
+          <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
+        </div>
+      )}
+
+      {error && (
+        <div className="upgrade-error">
+          <p>{error}</p>
+        </div>
+      )}
+
+      <div className="level-actions">
+        <button onClick={() => updateExperience('check-in', 15)} disabled={hasCheckedIn}>
+          {hasCheckedIn ? '今日已签到' : '每日签到 (+15经验)'}
+        </button>
+        <button onClick={() => updateExperience('task', 30)}>完成任务 (+30经验)</button>
+        <button onClick={() => updateExperience('upload', 50)}>上传种子 (+50经验)</button>
+        <button onClick={checkUpgrade}>检查升级</button>
+      </div>
+    </div>
+  );
+};
+
+export default UserLevelExperience;  
diff --git a/src/pages/UserCenter/UserProfile.css b/src/pages/UserCenter/UserProfile.css
index b230c1e..cb71be7 100644
--- a/src/pages/UserCenter/UserProfile.css
+++ b/src/pages/UserCenter/UserProfile.css
@@ -54,10 +54,25 @@
   margin-top: 40px;
   width: 80%;
   padding-top: 10%;
-  padding-right: 15%;
+  padding-right: 10%;
   padding-bottom: 10%;
   padding-left: 10%;
+  margin-left: 3%;
+  margin-right: 5%;
+  
+  /* padding: 10% 20%; */
 }  
+
+/* .common-card {
+  background-color: #e9ded2;
+  border-radius: 16px;
+  margin: 0 auto;
+  margin-top: 40px;
+  padding: 10% 20%;
+  margin-left: 5%;
+  margin-right: 5%;
+} */
+   
 .avatar-wrapper {
   position: relative;
   display: inline-block;
@@ -119,15 +134,7 @@
   text-align: center;
 }
 
-.common-card {
-  background-color: #e9ded2;
-  border-radius: 16px;
-  margin: 0 auto;
-  margin-top: 40px;
-  padding: 10% 20%;
-  margin-left: 5%;
-  margin-right: 5%;
-}
+
 
 .avatar-wrapper {
   position: relative;
diff --git a/src/pages/UserCenter/UserProfile.jsx b/src/pages/UserCenter/UserProfile.jsx
index c6e80e0..bd87c99 100644
--- a/src/pages/UserCenter/UserProfile.jsx
+++ b/src/pages/UserCenter/UserProfile.jsx
@@ -1,263 +1,283 @@
-import React, { useEffect, useState } from 'react';
-import axios from 'axios';
-import './UserProfile.css';
-import { useUser } from '../../context/UserContext';
-import { useLocation } from 'wouter';
+// import React, { useEffect, useState } from 'react';
+// import axios from 'axios';
+// import './UserProfile.css';
+// import { useUser } from '../../context/UserContext';
+// import { useLocation } from 'wouter';
 
-const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
+// const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
+
+// const UserProfile = () => {
+//   const { user, loading, logout } = useUser();
+//   const [userProfile, setUserProfile] = useState(null);
+//   const [experienceInfo, setExperienceInfo] = useState(null);
+//   const [error, setError] = useState(null);
+
+//   // 修改密码状态
+//   const [showPwdModal, setShowPwdModal] = useState(false);
+//   const [oldPassword, setOldPassword] = useState('');
+//   const [newPassword, setNewPassword] = useState('');
+//   const [confirmPassword, setConfirmPassword] = useState('');
+
+//   // 退出登录
+//   const [, setLocation] = useLocation();
+
+//   useEffect(() => {
+//     if (loading) return;
+//     if (!user || !user.userId) {
+//       setError('未登录或用户信息缺失');
+//       setUserProfile(null);
+//       return;
+//     }
+
+//     const fetchUserProfile = async () => {
+//       try {
+//         setError(null);
+//         const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
+//         if (!raw) {
+//           setError('用户数据为空');
+//           setUserProfile(null);
+//           return;
+//         }
+
+//         const profile = {
+//           avatarUrl: raw.avatarUrl
+//             ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
+//             : DEFAULT_AVATAR_URL,
+//           nickname: raw.username || '未知用户',
+//           email: raw.email || '未填写',
+//           gender: raw.gender || '保密',
+//           bio: raw.description || '无',
+//           interests: raw.hobbies ? raw.hobbies.split(',') : [],
+//           level: raw.level || '未知',
+//           experience: raw.experience ?? 0,
+//           uploadAmount: raw.uploadCount ?? 0,
+//           downloadAmount: raw.downloadCount ?? 0,
+//           shareRate: raw.shareRate ?? 0,
+//           joinedDate: raw.registrationTime,
+//         };
+
+//         setUserProfile(profile);
+//       } catch (err) {
+//         setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
+//         setUserProfile(null);
+//       }
+//     };
+
+//     const fetchExperienceInfo = async () => {
+//       try {
+//         const { data } = await axios.get('/echo/level/getExperience', {
+//           params: { user_id: user.userId },
+//         });
+//         setExperienceInfo(data);
+//       } catch (err) {
+//         console.error('经验信息获取失败:', err);
+//       }
+//     };
+
+//     fetchUserProfile();
+//     fetchExperienceInfo();
+//   }, [user, loading]);
+
+//   const handleAvatarUpload = async (e) => {
+//     const file = e.target.files[0];
+//     if (!file) return;
+
+//     const formData = new FormData();
+//     formData.append('file', file);
+
+//     try {
+//       const { data } = await axios.post(
+//         `/echo/user/${user.userId}/uploadAvatar`,
+//         formData,
+//         { headers: { 'Content-Type': 'multipart/form-data' } }
+//       );
+
+//       if (data?.avatarUrl) {
+//         setUserProfile((prev) => ({
+//           ...prev,
+//           avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
+//         }));
+//         alert('头像上传成功');
+//       } else {
+//         alert('头像上传成功,但未返回新头像地址');
+//       }
+//     } catch (err) {
+//       console.error('上传失败:', err);
+//       alert('头像上传失败,请重试');
+//     }
+//   };
+
+//   const handleLogout = () => {
+//     logout();
+//     setLocation('/auth'); // 退出后跳转登录页
+//     // window.location.reload(); // 或跳转登录页
+//   };
+
+//   const handleChangePassword = async () => {
+//     if (!oldPassword || !newPassword || !confirmPassword) {
+//       alert('请填写所有字段');
+//       return;
+//     }
+//     if (newPassword !== confirmPassword) {
+//       alert('两次输入的新密码不一致');
+//       return;
+//     }
+
+//     try {
+//       // await axios.post('/echo/user/password', {
+//       //   user_id: user.userId,
+//       //   oldPassword,
+//       //   newPassword,
+//       // });
+//       await axios.post('/echo/user/password', {
+//         user_id: user.userId,
+//         old_password: oldPassword,
+//         new_password: newPassword,
+//         confirm_password: confirmPassword,
+//       });
+//       alert('密码修改成功,请重新登录');
+//       logout();
+//       window.location.reload();
+//     } catch (err) {
+//       alert(err.response?.data?.message || '密码修改失败,请检查原密码是否正确');
+//     }
+//   };
+
+//   if (loading) return <p>正在加载用户信息...</p>;
+//   if (error) return <p className="error">{error}</p>;
+//   if (!userProfile) return null;
+
+//   const {
+//     avatarUrl,
+//     nickname,
+//     email,
+//     gender,
+//     bio,
+//     interests,
+//     level,
+//     experience,
+//     uploadAmount,
+//     downloadAmount,
+//     shareRate,
+//     joinedDate,
+//   } = userProfile;
+
+//   const progressPercent = experienceInfo
+//     ? Math.min(
+//         100,
+//         ((experienceInfo.current_experience || 0) /
+//           (experienceInfo.next_level_experience || 1)) *
+//           100
+//       ).toFixed(2)
+//     : 0;
+
+//   const expToNextLevel = experienceInfo
+//     ? (experienceInfo.next_level_experience - experienceInfo.current_experience)
+//     : null;
+
+//   return (
+//     <div className="common-card">
+//       <div className="right-content">
+//         <div className="profile-header">
+//           <div className="avatar-wrapper">
+//             <img src={avatarUrl} alt={nickname} className="avatar" />
+//             <label htmlFor="avatar-upload" className="avatar-upload-label">
+//               上传头像
+//             </label>
+//             <input
+//               type="file"
+//               id="avatar-upload"
+//               accept="image/*"
+//               style={{ display: 'none' }}
+//               onChange={handleAvatarUpload}
+//             />
+//           </div>
+//           <h1>{nickname}</h1>
+//         </div>
+
+//         <div className="profile-details">
+//           <p><strong>邮箱:</strong>{email}</p>
+//           <p><strong>性别:</strong>{gender}</p>
+//           <p><strong>个人简介:</strong>{bio}</p>
+//           <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
+//           <p><strong>等级:</strong>{level}</p>
+//           <p><strong>经验:</strong>{experience}</p>
+//           <p><strong>上传量:</strong>{uploadAmount}</p>
+//           <p><strong>下载量:</strong>{downloadAmount}</p>
+//           <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
+//           <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
+
+//           {experienceInfo && (
+//             <>
+//               <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
+//               <div className="exp-bar-wrapper">
+//                 <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
+//               </div>
+//               <p className="exp-progress-text">{progressPercent}%</p>
+//             </>
+//           )}
+
+//           {/* 修改密码与退出登录按钮 */}
+//           <div className="profile-actions">
+//             <button onClick={() => setShowPwdModal(true)}>修改密码</button>
+//             <button onClick={handleLogout}>退出登录</button>
+//           </div>
+
+//           {/* 修改密码弹窗 */}
+//           {showPwdModal && (
+//             <div className="modal">
+//               <div className="modal-content">
+//                 <h3>修改密码</h3>
+//                 <input
+//                   type="password"
+//                   placeholder="原密码"
+//                   value={oldPassword}
+//                   onChange={(e) => setOldPassword(e.target.value)}
+//                 />
+//                 <input
+//                   type="password"
+//                   placeholder="新密码"
+//                   value={newPassword}
+//                   onChange={(e) => setNewPassword(e.target.value)}
+//                 />
+//                 <input
+//                   type="password"
+//                   placeholder="确认新密码"
+//                   value={confirmPassword}
+//                   onChange={(e) => setConfirmPassword(e.target.value)}
+//                 />
+//                 <div className="modal-buttons">
+//                   <button onClick={handleChangePassword}>确认修改</button>
+//                   <button onClick={() => setShowPwdModal(false)}>取消</button>
+//                 </div>
+//               </div>
+//             </div>
+//           )}
+//         </div>
+//       </div>
+//     </div>
+//   );
+// };
+
+// export default UserProfile;
+
+import React from 'react';
+import UserProfileBase from './UserProfileBase';
+import UserLevelExperience from './UserLevelExperience';
 
 const UserProfile = () => {
-  const { user, loading, logout } = useUser();
-  const [userProfile, setUserProfile] = useState(null);
-  const [experienceInfo, setExperienceInfo] = useState(null);
-  const [error, setError] = useState(null);
+  const [userId, setUserId] = React.useState(null);
 
-  // 修改密码状态
-  const [showPwdModal, setShowPwdModal] = useState(false);
-  const [oldPassword, setOldPassword] = useState('');
-  const [newPassword, setNewPassword] = useState('');
-  const [confirmPassword, setConfirmPassword] = useState('');
-
-  // 退出登录
-  const [, setLocation] = useLocation();
-
-  useEffect(() => {
-    if (loading) return;
-    if (!user || !user.userId) {
-      setError('未登录或用户信息缺失');
-      setUserProfile(null);
-      return;
-    }
-
-    const fetchUserProfile = async () => {
-      try {
-        setError(null);
-        const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
-        if (!raw) {
-          setError('用户数据为空');
-          setUserProfile(null);
-          return;
-        }
-
-        const profile = {
-          avatarUrl: raw.avatarUrl
-            ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
-            : DEFAULT_AVATAR_URL,
-          nickname: raw.username || '未知用户',
-          email: raw.email || '未填写',
-          gender: raw.gender || '保密',
-          bio: raw.description || '无',
-          interests: raw.hobbies ? raw.hobbies.split(',') : [],
-          level: raw.level || '未知',
-          experience: raw.experience ?? 0,
-          uploadAmount: raw.uploadCount ?? 0,
-          downloadAmount: raw.downloadCount ?? 0,
-          shareRate: raw.shareRate ?? 0,
-          joinedDate: raw.registrationTime,
-        };
-
-        setUserProfile(profile);
-      } catch (err) {
-        setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
-        setUserProfile(null);
-      }
-    };
-
-    const fetchExperienceInfo = async () => {
-      try {
-        const { data } = await axios.get('/echo/level/getExperience', {
-          params: { user_id: user.userId },
-        });
-        setExperienceInfo(data);
-      } catch (err) {
-        console.error('经验信息获取失败:', err);
-      }
-    };
-
-    fetchUserProfile();
-    fetchExperienceInfo();
-  }, [user, loading]);
-
-  const handleAvatarUpload = async (e) => {
-    const file = e.target.files[0];
-    if (!file) return;
-
-    const formData = new FormData();
-    formData.append('file', file);
-
-    try {
-      const { data } = await axios.post(
-        `/echo/user/${user.userId}/uploadAvatar`,
-        formData,
-        { headers: { 'Content-Type': 'multipart/form-data' } }
-      );
-
-      if (data?.avatarUrl) {
-        setUserProfile((prev) => ({
-          ...prev,
-          avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
-        }));
-        alert('头像上传成功');
-      } else {
-        alert('头像上传成功,但未返回新头像地址');
-      }
-    } catch (err) {
-      console.error('上传失败:', err);
-      alert('头像上传失败,请重试');
-    }
+  const loadExperienceInfo = (id) => {
+    setUserId(id);
   };
 
-  const handleLogout = () => {
-    logout();
-    setLocation('/auth'); // 退出后跳转登录页
-    // window.location.reload(); // 或跳转登录页
-  };
-
-  const handleChangePassword = async () => {
-    if (!oldPassword || !newPassword || !confirmPassword) {
-      alert('请填写所有字段');
-      return;
-    }
-    if (newPassword !== confirmPassword) {
-      alert('两次输入的新密码不一致');
-      return;
-    }
-
-    try {
-      // await axios.post('/echo/user/password', {
-      //   user_id: user.userId,
-      //   oldPassword,
-      //   newPassword,
-      // });
-      await axios.post('/echo/user/password', {
-        user_id: user.userId,
-        old_password: oldPassword,
-        new_password: newPassword,
-        confirm_password: confirmPassword,
-      });
-      alert('密码修改成功,请重新登录');
-      logout();
-      window.location.reload();
-    } catch (err) {
-      alert(err.response?.data?.message || '密码修改失败,请检查原密码是否正确');
-    }
-  };
-
-  if (loading) return <p>正在加载用户信息...</p>;
-  if (error) return <p className="error">{error}</p>;
-  if (!userProfile) return null;
-
-  const {
-    avatarUrl,
-    nickname,
-    email,
-    gender,
-    bio,
-    interests,
-    level,
-    experience,
-    uploadAmount,
-    downloadAmount,
-    shareRate,
-    joinedDate,
-  } = userProfile;
-
-  const progressPercent = experienceInfo
-    ? Math.min(
-        100,
-        ((experienceInfo.current_experience || 0) /
-          (experienceInfo.next_level_experience || 1)) *
-          100
-      ).toFixed(2)
-    : 0;
-
-  const expToNextLevel = experienceInfo
-    ? (experienceInfo.next_level_experience - experienceInfo.current_experience)
-    : null;
-
   return (
-    <div className="common-card">
-      <div className="right-content">
-        <div className="profile-header">
-          <div className="avatar-wrapper">
-            <img src={avatarUrl} alt={nickname} className="avatar" />
-            <label htmlFor="avatar-upload" className="avatar-upload-label">
-              上传头像
-            </label>
-            <input
-              type="file"
-              id="avatar-upload"
-              accept="image/*"
-              style={{ display: 'none' }}
-              onChange={handleAvatarUpload}
-            />
-          </div>
-          <h1>{nickname}</h1>
-        </div>
-
-        <div className="profile-details">
-          <p><strong>邮箱:</strong>{email}</p>
-          <p><strong>性别:</strong>{gender}</p>
-          <p><strong>个人简介:</strong>{bio}</p>
-          <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
-          <p><strong>等级:</strong>{level}</p>
-          <p><strong>经验:</strong>{experience}</p>
-          <p><strong>上传量:</strong>{uploadAmount}</p>
-          <p><strong>下载量:</strong>{downloadAmount}</p>
-          <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
-          <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
-
-          {experienceInfo && (
-            <>
-              <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
-              <div className="exp-bar-wrapper">
-                <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
-              </div>
-              <p className="exp-progress-text">{progressPercent}%</p>
-            </>
-          )}
-
-          {/* 修改密码与退出登录按钮 */}
-          <div className="profile-actions">
-            <button onClick={() => setShowPwdModal(true)}>修改密码</button>
-            <button onClick={handleLogout}>退出登录</button>
-          </div>
-
-          {/* 修改密码弹窗 */}
-          {showPwdModal && (
-            <div className="modal">
-              <div className="modal-content">
-                <h3>修改密码</h3>
-                <input
-                  type="password"
-                  placeholder="原密码"
-                  value={oldPassword}
-                  onChange={(e) => setOldPassword(e.target.value)}
-                />
-                <input
-                  type="password"
-                  placeholder="新密码"
-                  value={newPassword}
-                  onChange={(e) => setNewPassword(e.target.value)}
-                />
-                <input
-                  type="password"
-                  placeholder="确认新密码"
-                  value={confirmPassword}
-                  onChange={(e) => setConfirmPassword(e.target.value)}
-                />
-                <div className="modal-buttons">
-                  <button onClick={handleChangePassword}>确认修改</button>
-                  <button onClick={() => setShowPwdModal(false)}>取消</button>
-                </div>
-              </div>
-            </div>
-          )}
-        </div>
-      </div>
+    <div>
+      <UserProfileBase onLoadExperienceInfo={loadExperienceInfo} />
+      {userId && <UserLevelExperience userId={userId} />}
     </div>
   );
 };
 
-export default UserProfile;
-
+export default UserProfile;  
\ No newline at end of file
diff --git a/src/pages/UserCenter/UserProfileBase.jsx b/src/pages/UserCenter/UserProfileBase.jsx
new file mode 100644
index 0000000..7a1f726
--- /dev/null
+++ b/src/pages/UserCenter/UserProfileBase.jsx
@@ -0,0 +1,221 @@
+import React, { useEffect, useState } from 'react';
+import axios from 'axios';
+import { useUser } from '../../context/UserContext';
+import { useLocation } from 'wouter';
+
+const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
+
+const UserProfileBase = ({ onLoadExperienceInfo }) => {
+  const { user, loading, logout } = useUser();
+  const [userProfile, setUserProfile] = useState(null);
+  const [error, setError] = useState(null);
+
+  // 修改密码状态
+  const [showPwdModal, setShowPwdModal] = useState(false);
+  const [oldPassword, setOldPassword] = useState('');
+  const [newPassword, setNewPassword] = useState('');
+  const [confirmPassword, setConfirmPassword] = useState('');
+
+  // 退出登录
+  const [, setLocation] = useLocation();
+
+  useEffect(() => {
+    if (loading) return;
+    if (!user || !user.userId) {
+      setError('未登录或用户信息缺失');
+      setUserProfile(null);
+      return;
+    }
+
+    const fetchUserProfile = async () => {
+      try {
+        setError(null);
+        const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
+        if (!raw) {
+          setError('用户数据为空');
+          setUserProfile(null);
+          return;
+        }
+
+        const profile = {
+          avatarUrl: raw.avatarUrl
+            ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
+            : DEFAULT_AVATAR_URL,
+          nickname: raw.username || '未知用户',
+          email: raw.email || '未填写',
+          gender: raw.gender || '保密',
+          bio: raw.description || '无',
+          interests: raw.hobbies ? raw.hobbies.split(',') : [],
+          level: raw.level || '未知',
+          experience: raw.experience ?? 0,
+          uploadAmount: raw.uploadCount ?? 0,
+          downloadAmount: raw.downloadCount ?? 0,
+          shareRate: raw.shareRate ?? 0,
+          joinedDate: raw.registrationTime,
+        };
+
+        setUserProfile(profile);
+        // 加载经验信息
+        if (onLoadExperienceInfo) onLoadExperienceInfo(user.userId);
+      } catch (err) {
+        setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
+        setUserProfile(null);
+      }
+    };
+
+    fetchUserProfile();
+  }, [user, loading, onLoadExperienceInfo]);
+
+  const handleAvatarUpload = async (e) => {
+    const file = e.target.files[0];
+    if (!file) return;
+
+    const formData = new FormData();
+    formData.append('file', file);
+
+    try {
+      const { data } = await axios.post(
+        `/echo/user/${user.userId}/uploadAvatar`,
+        formData,
+        { headers: { 'Content-Type': 'multipart/form-data' } }
+      );
+
+      if (data?.avatarUrl) {
+        setUserProfile((prev) => ({
+          ...prev,
+          avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
+        }));
+        alert('头像上传成功');
+      } else {
+        alert('头像上传成功,但未返回新头像地址');
+      }
+    } catch (err) {
+      console.error('上传失败:', err);
+      alert('头像上传失败,请重试');
+    }
+  };
+
+  const handleLogout = () => {
+    logout();
+    setLocation('/auth'); // 退出后跳转登录页
+  };
+
+  const handleChangePassword = async () => {
+    if (!oldPassword || !newPassword || !confirmPassword) {
+      alert('请填写所有字段');
+      return;
+    }
+    if (newPassword !== confirmPassword) {
+      alert('两次输入的新密码不一致');
+      return;
+    }
+
+    try {
+      await axios.post('/echo/user/password', {
+        user_id: user.userId,
+        old_password: oldPassword,
+        new_password: newPassword,
+        confirm_password: confirmPassword,
+      });
+      alert('密码修改成功,请重新登录');
+      logout();
+      window.location.reload();
+    } catch (err) {
+      alert(err.response?.data?.message || '密码修改失败,请检查原密码是否正确');
+    }
+  };
+
+  if (loading) return <p>正在加载用户信息...</p>;
+  if (error) return <p className="error">{error}</p>;
+  if (!userProfile) return null;
+
+  const {
+    avatarUrl,
+    nickname,
+    email,
+    gender,
+    bio,
+    interests,
+    level,
+    experience,
+    uploadAmount,
+    downloadAmount,
+    shareRate,
+    joinedDate,
+  } = userProfile;
+
+  return (
+    <div className="common-card">
+      <div className="right-content">
+        <div className="profile-header">
+          <div className="avatar-wrapper">
+            <img src={avatarUrl} alt={nickname} className="avatar" />
+            <label htmlFor="avatar-upload" className="avatar-upload-label">
+              上传头像
+            </label>
+            <input
+              type="file"
+              id="avatar-upload"
+              accept="image/*"
+              style={{ display: 'none' }}
+              onChange={handleAvatarUpload}
+            />
+          </div>
+          <h1>{nickname}</h1>
+        </div>
+
+        <div className="profile-details">
+          <p><strong>邮箱:</strong>{email}</p>
+          <p><strong>性别:</strong>{gender}</p>
+          <p><strong>个人简介:</strong>{bio}</p>
+          <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
+          {/* <p><strong>等级:</strong>{level}</p>
+          <p><strong>经验:</strong>{experience}</p> */}
+          <p><strong>上传量:</strong>{uploadAmount}</p>
+          <p><strong>下载量:</strong>{downloadAmount}</p>
+          <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
+          <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
+
+          {/* 修改密码与退出登录按钮 */}
+          <div className="profile-actions">
+            <button onClick={() => setShowPwdModal(true)}>修改密码</button>
+            <button onClick={handleLogout}>退出登录</button>
+          </div>
+
+          {/* 修改密码弹窗 */}
+          {showPwdModal && (
+            <div className="modal">
+              <div className="modal-content">
+                <h3>修改密码</h3>
+                <input
+                  type="password"
+                  placeholder="原密码"
+                  value={oldPassword}
+                  onChange={(e) => setOldPassword(e.target.value)}
+                />
+                <input
+                  type="password"
+                  placeholder="新密码"
+                  value={newPassword}
+                  onChange={(e) => setNewPassword(e.target.value)}
+                />
+                <input
+                  type="password"
+                  placeholder="确认新密码"
+                  value={confirmPassword}
+                  onChange={(e) => setConfirmPassword(e.target.value)}
+                />
+                <div className="modal-buttons">
+                  <button onClick={handleChangePassword}>确认修改</button>
+                  <button onClick={() => setShowPwdModal(false)}>取消</button>
+                </div>
+              </div>
+            </div>
+          )}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default UserProfileBase;  
\ No newline at end of file