blob: 60dcd551c8ab3da7a821a13d20c01984f8546be1 [file] [log] [blame]
Krishya73cd8822025-06-07 15:48:41 +08001// import React, { useState, useEffect } from 'react';
2// import axios from 'axios';
3
4// const UserLevelExperience = ({ userId }) => {
5// const [experienceInfo, setExperienceInfo] = useState(null);
6// const [error, setError] = useState(null);
7// const [isLoading, setIsLoading] = useState(false);
8// const [upgradeResult, setUpgradeResult] = useState(null);
9// const [hasCheckedIn, setHasCheckedIn] = useState(false);
10
11// useEffect(() => {
12// if (!userId) return;
13// fetchAllLevelData();
14// }, [userId]);
15
16// useEffect(() => {
17// // 自动触发升级判断
18// if (
19// experienceInfo &&
20// experienceInfo.current_experience >= experienceInfo.next_level_experience
21// ) {
22// checkUpgrade();
23// }
24// }, [experienceInfo]);
25
26// const fetchAllLevelData = async () => {
27// try {
28// setIsLoading(true);
29// setError(null);
30
31// const { data } = await axios.get('/echo/level/getExperience', {
32// params: { user_id: userId },
33// });
34
35// const normalizedData = {
36// ...data,
37// current_level: data.current_level || data.level,
38// };
39
40// setExperienceInfo(normalizedData);
41
42// const today = new Date().toDateString();
43// const lastCheckIn = localStorage.getItem('lastCheckIn');
44// setHasCheckedIn(lastCheckIn === today);
45// } catch (err) {
46// console.error('经验信息获取失败:', err);
47// setError('获取经验信息失败');
48// } finally {
49// setIsLoading(false);
50// }
51// };
52
53// const updateExperience = async (source, amount = 10) => {
54// try {
55// setIsLoading(true);
56// setError(null);
57
58// const { data } = await axios.post('/echo/level/updateExperience', {
59// user_id: userId,
60// experience: amount,
61// source: source,
62// });
63
64// setExperienceInfo((prev) => ({
65// ...prev,
66// current_experience: data.current_experience,
67// }));
68
69// alert(`获得${amount}点经验值!来源:${source}`);
70
71// if (source === 'check-in') {
72// localStorage.setItem('lastCheckIn', new Date().toDateString());
73// setHasCheckedIn(true);
74// }
75// } catch (err) {
76// console.error('更新经验失败:', err);
77// setError(err.response?.data?.message || '更新经验失败');
78// } finally {
79// setIsLoading(false);
80// }
81// };
82
83// const checkUpgrade = async () => {
84// try {
85// setIsLoading(true);
86// setError(null);
87
88// const { data } = await axios.get('/echo/level/upgrade-check', {
89// params: { user_id: userId },
90// });
91
92// if (data.can_upgrade) {
93// await performUpgrade(); // 自动触发
94// }
95// } catch (err) {
96// console.error('检查升级失败:', err);
97// setError(err.response?.data?.message || '检查升级失败');
98// } finally {
99// setIsLoading(false);
100// }
101// };
102
103
104// const performUpgrade = async () => {
105// try {
106// setIsLoading(true);
107// setError(null);
108
109// const { data } = await axios.post('/echo/level/upgrades', {
110// user_id: userId,
111// can_upgrade: true,
112// });
113
114// console.log('升级响应数据:', data); // 保留调试日志
115
116// setExperienceInfo((prev) => ({
117// ...prev,
118// current_level: data.new_level, // 修复:使用正确的字段名
119// current_experience: 0,
120// next_level_experience: prev.next_level_experience * 2,
121// }));
122
123// setUpgradeResult(data);
124// alert(`恭喜!您已升级到等级 ${data.new_level}!`); // 修复:使用正确的字段名
125// } catch (err) {
126// console.error('升级失败:', err);
127// setError(err.response?.data?.message || '升级失败');
128// } finally {
129// setIsLoading(false);
130// }
131// };
132
133
134// if (error) return <p className="error">{error}</p>;
135// if (isLoading) return <p>加载中...</p>;
136// if (!experienceInfo) return <p>加载经验信息中...</p>;
137
138// const { current_experience, next_level_experience, current_level } = experienceInfo;
139// const progressPercent = Math.min(
140// 100,
141// (current_experience / (next_level_experience || 1)) * 100
142// ).toFixed(2);
143
144// const expToNextLevel = Math.max(0, next_level_experience - current_experience); // 防止负数
145
146// return (
147// <div className="level-experience-section">
148// {/* <h3>等级与经验</h3> */}
149// <p><strong>当前等级:</strong>{current_level || '未知'}</p>
150// <p><strong>当前经验:</strong>{current_experience}</p>
151// <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
152
153// <div className="exp-bar-wrapper">
154// <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
155// </div>
156// <p className="exp-progress-text">{progressPercent}%</p>
157
158
159// {upgradeResult && (
160// <div className="upgrade-success">
161// {/* 使用与状态一致的字段名 */}
162// <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
163// </div>
164// )}
165
166
167// <div className="level-actions">
168// <button onClick={() => updateExperience('check-in', 15)} disabled={hasCheckedIn}>
169// {hasCheckedIn ? '今日已签到' : '每日签到 (+15经验)'}
170// </button>
171// <button onClick={() => updateExperience('task', 30)}>完成任务 (+30经验)</button>
172// <button onClick={() => updateExperience('upload', 50)}>上传种子 (+50经验)</button>
173// {/* <button onClick={checkUpgrade}>检查升级</button> */}
174// </div>
175// </div>
176// );
177// };
178
179// export default UserLevelExperience;
180
181import React, { useState, useEffect } from 'react';
182import axios from 'axios';
183
184const UserLevelExperience = ({ userId }) => {
185 const [experienceInfo, setExperienceInfo] = useState(null);
186 const [error, setError] = useState(null);
187 const [isLoading, setIsLoading] = useState(false);
188 const [upgradeResult, setUpgradeResult] = useState(null);
189 const [hasCheckedIn, setHasCheckedIn] = useState(false);
190
191 useEffect(() => {
192 if (!userId) return;
193 fetchAllLevelData();
194 }, [userId]);
195
196 useEffect(() => {
197 // 自动触发升级判断
198 if (
199 experienceInfo &&
200 experienceInfo.current_experience >= experienceInfo.next_level_experience
201 ) {
202 checkUpgrade();
203 }
204 }, [experienceInfo]);
205
206 const fetchAllLevelData = async () => {
207 try {
208 setIsLoading(true);
209 setError(null);
210
211 const { data } = await axios.get('/echo/level/getExperience', {
212 params: { user_id: userId },
213 });
214
215 const normalizedData = {
216 ...data,
217 current_level: data.current_level || data.level,
218 };
219
220 setExperienceInfo(normalizedData);
221
222 const today = new Date().toDateString();
223 const lastCheckIn = localStorage.getItem('lastCheckIn');
224 setHasCheckedIn(lastCheckIn === today);
225 } catch (err) {
226 console.error('经验信息获取失败:', err);
227 setError('获取经验信息失败');
228 } finally {
229 setIsLoading(false);
230 }
231 };
232
233 const updateExperience = async (source, amount = 10) => {
234 try {
235 setIsLoading(true);
236 setError(null);
237
238 const { data } = await axios.post('/echo/level/updateExperience', {
239 user_id: userId,
240 experience: amount,
241 source: source,
242 });
243
244 setExperienceInfo((prev) => ({
245 ...prev,
246 current_experience: data.current_experience,
247 }));
248
249 alert(`获得${amount}点经验值!来源:${source}`);
250
251 if (source === 'check-in') {
252 localStorage.setItem('lastCheckIn', new Date().toDateString());
253 setHasCheckedIn(true);
254 }
255 } catch (err) {
256 console.error('更新经验失败:', err);
257 setError(err.response?.data?.message || '更新经验失败');
258 } finally {
259 setIsLoading(false);
260 }
261 };
262
263 const checkUpgrade = async () => {
264 try {
265 setIsLoading(true);
266 setError(null);
267
268 const { data } = await axios.get('/echo/level/upgrade-check', {
269 params: { user_id: userId },
270 });
271
272 if (data.can_upgrade) {
273 if (window.confirm('您已满足升级条件,是否要升级?')) {
274 await performUpgrade();
275 }
276 } else {
277 // 区分是经验不足还是已达最高等级
278 if (data.is_max_level) {
279 alert('您已达到最高等级!');
280 } else {
281 alert(`还不能升级,还需要${data.next_level_experience - data.current_experience}点经验值`);
282 }
283 }
284 } catch (err) {
285 console.error('检查升级失败:', err);
286 setError(err.response?.data?.message || '检查升级失败');
287 } finally {
288 setIsLoading(false);
289 }
290 };
291
292 const performUpgrade = async () => {
293 try {
294 setIsLoading(true);
295 setError(null);
296
297 const { data } = await axios.post('/echo/level/upgrades', {
298 user_id: userId,
299 can_upgrade: true,
300 });
301
302 console.log('升级响应数据:', data);
303
304 // 正确处理升级结果
305 if (data.status === 'success') {
306 setExperienceInfo((prev) => ({
307 ...prev,
308 current_level: data.new_level,
309 current_experience: 0,
310 next_level_experience: prev.next_level_experience * 2,
311 }));
312
313 setUpgradeResult(data);
314 alert(`恭喜!您已升级到等级 ${data.new_level}!`);
315 } else {
316 throw new Error(data.message || '升级失败');
317 }
318 } catch (err) {
319 console.error('升级失败:', err);
320 setError(err.message || '升级失败');
321 alert(err.message || '升级失败,请稍后再试');
322 } finally {
323 setIsLoading(false);
324 }
325 };
326
327 if (error) return <p className="error">{error}</p>;
328 if (isLoading) return <p>加载中...</p>;
329 if (!experienceInfo) return <p>加载经验信息中...</p>;
330
331 const { current_experience, next_level_experience, current_level } = experienceInfo;
332 const progressPercent = Math.min(
333 100,
334 (current_experience / (next_level_experience || 1)) * 100
335 ).toFixed(2);
336
337 const expToNextLevel = Math.max(0, next_level_experience - current_experience);
338
339 return (
340 <div className="level-experience-section">
341 <h3>等级与经验</h3>
342 <p><strong>当前等级:</strong>{current_level || '未知'}</p>
343 <p><strong>当前经验:</strong>{current_experience}</p>
344 <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
345
346 <div className="exp-bar-wrapper">
347 <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
348 </div>
349 <p className="exp-progress-text">{progressPercent}%</p>
350
351 {upgradeResult && (
352 <div className="upgrade-success">
353 <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
354 </div>
355 )}
356
357 {error && (
358 <div className="upgrade-error">
359 <p>{error}</p>
360 </div>
361 )}
362
363 <div className="level-actions">
364 <button onClick={() => updateExperience('check-in', 15)} disabled={hasCheckedIn}>
365 {hasCheckedIn ? '今日已签到' : '每日签到 (+15经验)'}
366 </button>
367 <button onClick={() => updateExperience('task', 30)}>完成任务 (+30经验)</button>
368 <button onClick={() => updateExperience('upload', 50)}>上传种子 (+50经验)</button>
369 <button onClick={checkUpgrade}>检查升级</button>
370 </div>
371 </div>
372 );
373};
374
375export default UserLevelExperience;