用户个人中心、兴趣小组
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;