用户个人中心、兴趣小组

Change-Id: I0e2f3f4ad586f237505613238cbb7bebb6118b63
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;