种子列表优化、添加用户充值
Change-Id: I602e9eef78efe3527c320352d4522244d41ae807
diff --git a/src/pages/NewUserGuide/NewUserGuide.jsx b/src/pages/NewUserGuide/NewUserGuide.jsx
index 4c4d634..7a3dad1 100644
--- a/src/pages/NewUserGuide/NewUserGuide.jsx
+++ b/src/pages/NewUserGuide/NewUserGuide.jsx
@@ -1,6 +1,7 @@
-import Header from '../../components/Header';
import React, { useState } from 'react';
+import Header from '../../components/Header';
import './NewUserGuide.css';
+import NewbieTasks from './NewbieTasks.jsx';
const NewUserGuide = () => {
const [activeTab, setActiveTab] = useState('terms');
@@ -11,13 +12,15 @@
return (
<div className="guide-content">
<h2>名词解释</h2>
- <p>在本平台中,我们使用以下术语:</p>
+ <p>在echo Torrent中,我们使用以下术语:</p>
<ul>
- <li><strong>种子:</strong> 表示可下载的资源文件索引信息。</li>
+ <li><strong>Tracker:</strong> 监测用户流量的服务器。</li>
+ <li><strong>种子:</strong> 扩展名为.torrent的文件,主要包含文件信息、Tracker信息等。在本站发布的种子。每个用户下载都会下载包含特定信息的种子以便Tracker记录不同用户的流量情况。</li>
+ <li><strong>流量:</strong> 分为上传量(通过本站Tracker向其他用户上传的数据总量)和下载量(通过本站Tracker从其他用户下载的数据总量)。</li>
<li><strong>做种:</strong> 指上传资源供他人下载。</li>
- <li><strong>分享率:</strong> 上传流量与下载流量的比值。</li>
- <li><strong>魔力值:</strong> 用于奖励活跃用户的虚拟积分。</li>
- {/* 可继续添加名词 */}
+ <li><strong>分享率:</strong> 分享率=上传量/下载量</li>
+ <li><strong>经验值:</strong> 用于奖励活跃用户的虚拟积分。</li>
+ <li><strong>金币:</strong> 用于兑换虚拟物品的虚拟货币,可在个人中心充值。</li>
</ul>
</div>
);
@@ -30,21 +33,14 @@
<li>浏览并下载感兴趣的种子资源</li>
<li>做种、评论、评分获得积分</li>
<li>发布你的第一个种子</li>
- {/* 可继续扩展详细步骤 */}
</ol>
</div>
);
case 'tasks':
return (
<div className="guide-content">
- <h2>成长任务</h2>
- <p>完成以下任务可快速熟悉平台并获得奖励:</p>
- <ul>
- <li>🎯 浏览任意种子页面</li>
- <li>🗣️ 在论坛发一条评论</li>
- <li>📤 上传你的第一个资源</li>
- <li>🌟 连续登录 3 天</li>
- </ul>
+ <NewbieTasks />
+ {/* ✅ 使用真实组件替换静态任务列表 */}
</div>
);
default:
@@ -76,7 +72,9 @@
成长任务
</button>
</div>
- <div className="guide-main">{renderContent()}</div>
+ <div className="guide-main">
+ {renderContent()}
+ </div>
</div>
</div>
);
diff --git a/src/pages/NewUserGuide/NewbieTasks.css b/src/pages/NewUserGuide/NewbieTasks.css
new file mode 100644
index 0000000..4d64389
--- /dev/null
+++ b/src/pages/NewUserGuide/NewbieTasks.css
@@ -0,0 +1,64 @@
+.newbie-tasks {
+ font-size: 16px;
+ line-height: 1.6;
+}
+
+.task-list ul {
+ list-style: none;
+ padding: 0;
+}
+
+.task-card {
+ background-color: #f9f9f9;
+ border-radius: 12px;
+ padding: 15px;
+ margin-bottom: 15px;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.05);
+}
+
+.task-btn-group {
+ display: flex;
+ gap: 10px;
+ margin-top: 10px;
+}
+
+.task-btn-group button {
+ padding: 6px 12px;
+ border: none;
+ border-radius: 6px;
+ background-color: #0057ff;
+ color: white;
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+.task-btn-group button:hover {
+ background-color: #003fcc;
+}
+
+.status-completed {
+ color: green;
+}
+.status-pending {
+ color: orange;
+}
+.status-failed {
+ color: red;
+}
+.newbie-tasks {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
+}
+
+.task-card {
+ background-color: #f9f9f9;
+ border-radius: 12px;
+ padding: 15px;
+ margin-bottom: 20px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
+ border: 1px solid #eee;
+}
diff --git a/src/pages/NewUserGuide/NewbieTasks.jsx b/src/pages/NewUserGuide/NewbieTasks.jsx
new file mode 100644
index 0000000..5ff6a9c
--- /dev/null
+++ b/src/pages/NewUserGuide/NewbieTasks.jsx
@@ -0,0 +1,154 @@
+// export default NewbieTasks;
+import React, { useEffect, useState } from 'react';
+import axios from 'axios';
+
+const NewbieTasks = () => {
+ const [tasks, setTasks] = useState([]);
+ const [experience, setExperience] = useState({});
+ const [currentStep, setCurrentStep] = useState({});
+ const [loading, setLoading] = useState(true);
+
+ const baseURL = '/echo/task/tutorial';
+ const userId = 1;
+
+ const fetchTasks = async () => {
+ try {
+ const response = await axios.get(`${baseURL}/getAllTasks`, {
+ params: { user_id: userId },
+ });
+ setTasks(response.data.tasks || []);
+ } catch (error) {
+ console.error('获取任务失败:', error);
+ }
+ };
+
+ const fetchExperience = async () => {
+ try {
+ const response = await axios.get(`${baseURL}/getAllTasks`, {
+ params: { user_id: userId },
+ });
+ setExperience(response.data || {});
+ } catch (error) {
+ console.error('获取经验失败:', error);
+ }
+ };
+
+ const fetchCurrentStep = async () => {
+ try {
+ const response = await axios.get(`${baseURL}/getNewStep`, {
+ params: { user_id: userId },
+ });
+ setCurrentStep(response.data || {});
+ } catch (error) {
+ console.error('获取引导步骤失败:', error);
+ }
+ };
+
+ const updateStatus = async (taskId) => {
+ try {
+ await axios.post(`${baseURL}/updateStatus`, {
+ user_id: userId,
+ task_id: taskId,
+ });
+ await fetchTasks();
+ await fetchExperience();
+ } catch (error) {
+ console.error('更新状态失败:', error);
+ }
+ };
+
+ const updateProgress = async (taskId, progress) => {
+ try {
+ await axios.post(`${baseURL}/updateProgress`, {
+ user_id: userId,
+ task_id: taskId,
+ progress,
+ });
+ await fetchTasks();
+ } catch (error) {
+ console.error('更新进度失败:', error);
+ }
+ };
+
+ const claimReward = async (taskId) => {
+ try {
+ await axios.post(`${baseURL}/rewardClaim`, {
+ user_id: userId,
+ task_id: taskId,
+ });
+ await fetchTasks();
+ await fetchExperience();
+ } catch (error) {
+ console.error('领取奖励失败:', error);
+ }
+ };
+
+ const checkRewardStatus = async (taskId) => {
+ try {
+ const response = await axios.post(`${baseURL}/rewardReview`, {
+ user_id: userId,
+ task_id: taskId,
+ });
+ alert(response.data.message || '已完成');
+ } catch (error) {
+ console.error('查看失败:', error);
+ }
+ };
+
+ useEffect(() => {
+ const init = async () => {
+ await fetchTasks();
+ await fetchExperience();
+ await fetchCurrentStep();
+ setLoading(false);
+ };
+ init();
+ }, []);
+
+ if (loading) return <p className="loading">加载中...</p>;
+
+ return (
+ <div className="common-card right-content">
+ <div className="profile-header">
+ <h1>🎯 成长任务</h1>
+ </div>
+
+ <div className="profile-details">
+ <p><strong>当前经验:</strong>{experience.current_experience}</p>
+ <p><strong>等级:</strong>{experience.level}</p>
+ <p><strong>奖励经验:</strong>{experience.reward?.experience || 0}</p>
+ <p><strong>奖励积分:</strong>{experience.reward?.points || 0}</p>
+ </div>
+
+ <div className="profile-details">
+ <p><strong>🧭 当前引导步骤:</strong>{currentStep.current_step}</p>
+ <p>{currentStep.step_description}</p>
+ </div>
+
+ <div className="profile-details">
+ <h2>任务列表</h2>
+ <ul>
+ {tasks.map(task => (
+ <li key={task.task_id} style={{ marginBottom: '20px', borderBottom: '1px solid #eee', paddingBottom: '10px' }}>
+ <p><strong>任务:</strong>{task.title}</p>
+ <p><strong>描述:</strong>{task.description}</p>
+ <p><strong>进度:</strong>{task.progress}%</p>
+ <p><strong>状态:</strong>{task.status}</p>
+ <p><strong>奖励:</strong>经验 {task.reward.experience},积分 {task.reward.points}</p>
+
+ <div className="task-btn-group">
+ <button className="task-btn" onClick={() => updateStatus(task.task_id)}>更新状态</button>
+ <button className="task-btn" onClick={() => updateProgress(task.task_id, 100)}>提交进度</button>
+ <button className="task-btn" onClick={() => claimReward(task.task_id)}>领取奖励</button>
+ <button className="task-btn" onClick={() => checkRewardStatus(task.task_id)}>查看奖励状态</button>
+ </div>
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ );
+};
+
+export default NewbieTasks;
+
diff --git a/src/pages/Recharge/Recharge.css b/src/pages/Recharge/Recharge.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/pages/Recharge/Recharge.css
diff --git a/src/pages/Recharge/Recharge.jsx b/src/pages/Recharge/Recharge.jsx
new file mode 100644
index 0000000..0df1837
--- /dev/null
+++ b/src/pages/Recharge/Recharge.jsx
@@ -0,0 +1,192 @@
+// import React, { useState } from 'react';
+// import axios from 'axios';
+// import { useUser } from '../../context/UserContext';
+
+// const Recharge = () => {
+// const [amount, setAmount] = useState('');
+// const [loading, setLoading] = useState(false);
+// const [message, setMessage] = useState('');
+
+// // 从上下文获取当前登录用户
+// const { user } = useUser();
+// const userId = user?.userId;
+
+// const handleRecharge = async () => {
+// if (!userId) {
+// setMessage('未登录,无法充值');
+// return;
+// }
+// if (!amount || isNaN(amount) || Number(amount) <= 0) {
+// setMessage('请输入有效的充值金额');
+// return;
+// }
+// setLoading(true);
+// setMessage('');
+// try {
+// // 充值接口调用,注意后端用的是请求参数形式传递 userId 和 amount
+// const response = await axios.post('/echo/user/recharge', null, {
+// params: {
+// userId,
+// amount: Number(amount),
+// },
+// });
+// setMessage(response.data.message || '充值成功!');
+// setAmount('');
+// } catch (error) {
+// setMessage(error.response?.data?.message || '充值失败,请重试');
+// } finally {
+// setLoading(false);
+// }
+// };
+
+// return (
+// <div className="recharge-page">
+// <h2>充值服务</h2>
+// <div>
+// <label>
+// 充值金额:
+// <input
+// type="number"
+// min="1"
+// value={amount}
+// onChange={(e) => setAmount(e.target.value)}
+// disabled={loading}
+// />
+// </label>
+// </div>
+// <button onClick={handleRecharge} disabled={loading}>
+// {loading ? '处理中...' : '提交充值'}
+// </button>
+// {message && <p>{message}</p>}
+// </div>
+// );
+// };
+
+// export default Recharge;
+import React, { useState } from 'react';
+import axios from 'axios';
+import { useUser } from '../../context/UserContext';
+
+const Recharge = () => {
+ const [amount, setAmount] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [message, setMessage] = useState('');
+ const [showPayDialog, setShowPayDialog] = useState(false);
+ const [payProcessing, setPayProcessing] = useState(false);
+
+ const { user } = useUser();
+ const userId = user?.userId;
+
+ // 点击提交充值,打开模拟支付弹窗
+ const handleSubmit = () => {
+ if (!userId) {
+ setMessage('未登录,无法充值');
+ return;
+ }
+ if (!amount || isNaN(amount) || Number(amount) <= 0) {
+ setMessage('请输入有效的充值金额');
+ return;
+ }
+ setMessage('');
+ setShowPayDialog(true);
+ };
+
+ // 模拟支付弹窗点击“确认支付”
+ const handlePayConfirm = async () => {
+ setPayProcessing(true);
+ setMessage('');
+
+ // 模拟支付等待 2 秒
+ setTimeout(async () => {
+ try {
+ // 支付成功后调用后端充值接口
+ const response = await axios.post('/echo/user/recharge', null, {
+ params: {
+ userId,
+ amount: Number(amount),
+ },
+ });
+
+ setMessage(response.data.message || '充值成功!');
+ setAmount('');
+ } catch (error) {
+ setMessage(error.response?.data?.message || '充值失败,请重试');
+ } finally {
+ setPayProcessing(false);
+ setShowPayDialog(false);
+ }
+ }, 2000);
+ };
+
+ // 取消支付弹窗
+ const handlePayCancel = () => {
+ setShowPayDialog(false);
+ setMessage('支付已取消');
+ };
+
+ return (
+ <div className="recharge-page" style={{ maxWidth: 400, margin: 'auto', padding: 20 }}>
+ <h2>充值服务</h2>
+ <div style={{ marginBottom: 12 }}>
+ <label>
+ 充值金额:
+ <input
+ type="number"
+ min="1"
+ value={amount}
+ onChange={(e) => setAmount(e.target.value)}
+ disabled={loading || payProcessing}
+ style={{ marginLeft: 8, width: 120 }}
+ />
+ </label>
+ </div>
+ <button onClick={handleSubmit} disabled={loading || payProcessing}>
+ {loading || payProcessing ? '处理中...' : '提交充值'}
+ </button>
+
+ {message && <p style={{ marginTop: 12 }}>{message}</p>}
+
+ {/* 模拟支付弹窗 */}
+ {showPayDialog && (
+ <div
+ style={{
+ position: 'fixed',
+ top: 0, left: 0, right: 0, bottom: 0,
+ backgroundColor: 'rgba(0,0,0,0.5)',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ zIndex: 1000,
+ }}
+ >
+ <div
+ style={{
+ backgroundColor: '#fff',
+ padding: 20,
+ borderRadius: 8,
+ width: 300,
+ textAlign: 'center',
+ boxShadow: '0 0 10px rgba(0,0,0,0.25)',
+ }}
+ >
+ <h3>模拟支付</h3>
+ <p>支付金额:{amount} 元</p>
+
+ {payProcessing ? (
+ <p>支付处理中,请稍候...</p>
+ ) : (
+ <>
+ <button onClick={handlePayConfirm} style={{ marginRight: 10 }}>
+ 确认支付
+ </button>
+ <button onClick={handlePayCancel}>取消</button>
+ </>
+ )}
+ </div>
+ </div>
+ )}
+ </div>
+ );
+};
+
+export default Recharge;
diff --git a/src/pages/SeedList/SeedList.jsx b/src/pages/SeedList/SeedList.jsx
index adb2bb3..4f558fc 100644
--- a/src/pages/SeedList/SeedList.jsx
+++ b/src/pages/SeedList/SeedList.jsx
@@ -1,3 +1,4 @@
+// export default SeedList;
import React, { useState, useEffect } from 'react';
import { Link } from 'wouter';
import axios from 'axios';
@@ -18,28 +19,28 @@
const [errorMsg, setErrorMsg] = useState('');
const { user } = useUser();
-
const TAGS = ['猜你喜欢', '电影', '电视剧', '动漫', '音乐', '游戏', '综艺', '软件', '体育', '学习', '纪录片', '其他'];
- const CATEGORY_MAP = {
- '电影': '电影',
- '电视剧': '电视剧',
- '动漫': '动漫',
- '音乐': '音乐',
- '游戏': '游戏',
- '综艺': '综艺',
- '软件': '软件',
- '体育': '体育',
- '学习': '学习',
- '纪录片': '纪录片',
- '其他': '其他',
+const CATEGORY_MAP = {
+ '电影': 'movie',
+ '电视剧': 'tv',
+ '动漫': 'anime',
+ '音乐': 'music',
+ '游戏': 'game',
+ '综艺': 'variety',
+ '软件': 'software',
+ '体育': 'sports',
+ '学习': 'study',
+ '纪录片': 'documentary',
+ '其他': 'other',
'猜你喜欢': '',
'种子列表': '',
- };
+};
+
const buildQueryParams = () => {
const category = CATEGORY_MAP[activeTab] || '';
- const orderKey = sortOption === '最新' ? ['upload_time'] : (sortOption === '最热' ? ['downloads'] : ['upload_time']);
+ const orderKey = sortOption === '最新' ? 'upload_time' : (sortOption === '最热' ? 'downloads' : 'upload_time');
const params = {
page: 1,
size: 20,
@@ -72,8 +73,7 @@
setErrorMsg('');
try {
const params = buildQueryParams();
- const response = await axios.get('/seeds/list', params);
- // const response = await axios.get('/seeds/list', { params });
+ const response = await axios.get('/seeds/list', { params });
const data = response.data;
@@ -119,7 +119,6 @@
fetchSeeds();
}, [activeTab, sortOption, selectedFilters, tagMode, searchTerm]);
- // ✅ 修改后的下载函数
const handleDownload = async (seedId) => {
if (!user || !user.userId) {
alert('请先登录再下载种子文件');
@@ -254,7 +253,6 @@
</div>
<div className="seed-list-body">
{seeds.map((seed, index) => {
- // 处理 tags 字段,兼容字符串和数组
let tagsArray = [];
if (seed.tags) {
if (Array.isArray(seed.tags)) {
@@ -263,18 +261,15 @@
try {
tagsArray = JSON.parse(seed.tags);
if (!Array.isArray(tagsArray)) {
- // 解析后不是数组,按逗号分割
tagsArray = seed.tags.split(',').map(t => t.trim()).filter(t => t);
}
} catch {
- // 解析失败,按逗号分割
tagsArray = seed.tags.split(',').map(t => t.trim()).filter(t => t);
}
}
}
return (
-
<Link to={`/seed/${seed.id}`} key={index} className="seed-item-link">
<div className="seed-item">
{seed.imageUrl && (
@@ -300,7 +295,7 @@
<div className="seed-item-downloads">{seed.downloads ?? 0} 次下载</div>
<div
className="seed-item-actions"
- onClick={e => e.stopPropagation()} // 阻止事件冒泡,避免跳转
+ onClick={e => e.stopPropagation()}
>
<button
className="btn-primary"
@@ -313,35 +308,34 @@
下载
</button>
<button
- className="btn-outline"
- onClick={async (e) => {
- e.preventDefault();
- e.stopPropagation();
+ className="btn-outline"
+ onClick={async (e) => {
+ e.preventDefault();
+ e.stopPropagation();
- if (!user || !user.userId) {
- alert('请先登录再收藏');
- return;
- }
+ if (!user || !user.userId) {
+ alert('请先登录再收藏');
+ return;
+ }
- try {
- const res = await axios.post(`/seeds/${seed.id}/favorite-toggle`, null, {
- params: { user_id: user.userId },
- });
+ try {
+ const res = await axios.post(`/seeds/${seed.id}/favorite-toggle`, null, {
+ params: { user_id: user.userId },
+ });
- if (res.data.code === 0) {
- alert('操作成功'); // 你可以改成 toast 或 icon 状态提示
- } else {
- alert(res.data.msg || '操作失败');
- }
- } catch (err) {
- console.error('收藏失败:', err);
- alert('收藏失败,请稍后再试。');
- }
- }}
->
- 收藏
-</button>
-
+ if (res.data.code === 0) {
+ alert('操作成功');
+ } else {
+ alert(res.data.msg || '操作失败');
+ }
+ } catch (err) {
+ console.error('收藏失败:', err);
+ alert('收藏失败,请稍后再试。');
+ }
+ }}
+ >
+ 收藏
+ </button>
</div>
</div>
</Link>
diff --git a/src/pages/UserCenter/NewbieTasks.css b/src/pages/UserCenter/NewbieTasks.css
deleted file mode 100644
index 660cec3..0000000
--- a/src/pages/UserCenter/NewbieTasks.css
+++ /dev/null
@@ -1,20 +0,0 @@
-
-.task-btn {
- margin-right: 8px;
- padding: 6px 12px;
- border: none;
- border-radius: 6px;
- background-color: #4a90e2;
- color: white;
- cursor: pointer;
-}
-
-.task-btn:hover {
- background-color: #357abd;
-}
-
-.loading {
- text-align: center;
- font-size: 18px;
- color: #333;
-}
diff --git a/src/pages/UserCenter/NewbieTasks.jsx b/src/pages/UserCenter/NewbieTasks.jsx
deleted file mode 100644
index 768f95a..0000000
--- a/src/pages/UserCenter/NewbieTasks.jsx
+++ /dev/null
@@ -1,327 +0,0 @@
-// import React, { useEffect, useState } from 'react';
-// import axios from 'axios';
-// import Header from '../../components/Header';
-// import './UserProfile.css'; // 复用个人资料页面的样式
-// import UserNav from './UserNav';
-
-// const NewbieTasks = () => {
-// const [tasks, setTasks] = useState([]);
-// const [experience, setExperience] = useState({});
-// const [currentStep, setCurrentStep] = useState({});
-// const [loading, setLoading] = useState(true);
-
-// const baseURL = '/echo/task/tutorial';
-// const userId = 1;
-
-// // 获取所有任务
-// const fetchTasks = async () => {
-// try {
-// const response = await axios.get(`${baseURL}/getAllTasks`, {
-// params: { user_id: userId },
-// });
-// setTasks(response.data.tasks || []);
-// } catch (error) {
-// console.error('获取任务失败:', error);
-// }
-// };
-
-// // 获取经验与等级信息
-// const fetchExperience = async () => {
-// try {
-// const response = await axios.get(`${baseURL}/getAllTasks`, {
-// params: { user_id: userId },
-// });
-// setExperience(response.data || {});
-// } catch (error) {
-// console.error('获取经验失败:', error);
-// }
-// };
-
-// // 获取当前引导步骤
-// const fetchCurrentStep = async () => {
-// try {
-// const response = await axios.get(`${baseURL}/getNewStep`, {
-// params: { user_id: userId },
-// });
-// setCurrentStep(response.data || {});
-// } catch (error) {
-// console.error('获取引导步骤失败:', error);
-// }
-// };
-
-// // 更新任务状态
-// const updateStatus = async (taskId) => {
-// try {
-// await axios.post(`${baseURL}/updateStatus`, {
-// user_id: userId,
-// task_id: taskId,
-// });
-// await fetchTasks();
-// await fetchExperience();
-// } catch (error) {
-// console.error('更新状态失败:', error);
-// }
-// };
-
-// // 提交任务进度
-// const updateProgress = async (taskId, progress) => {
-// try {
-// await axios.post(`${baseURL}/updateProgress`, {
-// user_id: userId,
-// task_id: taskId,
-// progress,
-// });
-// await fetchTasks();
-// } catch (error) {
-// console.error('更新进度失败:', error);
-// }
-// };
-
-// // 领取奖励
-// const claimReward = async (taskId) => {
-// try {
-// await axios.post(`${baseURL}/rewardClaim`, {
-// user_id: userId,
-// task_id: taskId,
-// });
-// await fetchTasks();
-// await fetchExperience();
-// } catch (error) {
-// console.error('领取奖励失败:', error);
-// }
-// };
-
-// // 查看奖励是否已发放
-// const checkRewardStatus = async (taskId) => {
-// try {
-// const response = await axios.post(`${baseURL}/rewardReview`, {
-// user_id: userId,
-// task_id: taskId,
-// });
-// alert(response.data.message || '已完成');
-// } catch (error) {
-// console.error('查看失败:', error);
-// }
-// };
-
-// // 页面初始化
-// useEffect(() => {
-// const init = async () => {
-// await fetchTasks();
-// await fetchExperience();
-// await fetchCurrentStep();
-// setLoading(false);
-// };
-// init();
-// }, []);
-
-// if (loading) return <p className="loading">加载中...</p>;
-
-// return (
-// <div className="user-profile-container">
-// <Header />
-// <div className="user-center">
-// <div className="user-nav-container">
-// <UserNav activeKey="newbieTasks" onSelect={() => {}} />
-// </div>
-
-// <div className="common-card right-content">
-// <div className="profile-header">
-// <h1>🎯 新手考核</h1>
-// </div>
-
-// <div className="profile-details">
-// <p><strong>当前经验:</strong>{experience.current_experience}</p>
-// <p><strong>等级:</strong>{experience.level}</p>
-// <p><strong>奖励经验:</strong>{experience.reward?.experience || 0}</p>
-// <p><strong>奖励积分:</strong>{experience.reward?.points || 0}</p>
-// </div>
-
-// <div className="profile-details">
-// <p><strong>🧭 当前引导步骤:</strong>{currentStep.current_step}</p>
-// <p>{currentStep.step_description}</p>
-// </div>
-
-// <div className="profile-details">
-// <h2>任务列表</h2>
-// <ul>
-// {tasks.map(task => (
-// <li key={task.task_id} style={{ marginBottom: '20px' }}>
-// <p><strong>任务:</strong>{task.title}</p>
-// <p><strong>描述:</strong>{task.description}</p>
-// <p><strong>进度:</strong>{task.progress}%</p>
-// <p><strong>状态:</strong>{task.status}</p>
-// <p><strong>奖励:</strong>经验 {task.reward.experience},积分 {task.reward.points}</p>
-
-// <div style={{ marginTop: '10px' }}>
-// <button className="task-btn" onClick={() => updateStatus(task.task_id)}>更新状态</button>
-// <button className="task-btn" onClick={() => updateProgress(task.task_id, 100)}>提交进度</button>
-// <button className="task-btn" onClick={() => claimReward(task.task_id)}>领取奖励</button>
-// <button className="task-btn" onClick={() => checkRewardStatus(task.task_id)}>查看奖励是否已发放</button>
-// </div>
-// </li>
-// ))}
-// </ul>
-// </div>
-// </div>
-// </div>
-// </div>
-// );
-// };
-
-// export default NewbieTasks;
-
-import React, { useEffect, useState } from 'react';
-import axios from 'axios';
-import './UserProfile.css'; // 继续复用样式
-
-const NewbieTasks = () => {
- const [tasks, setTasks] = useState([]);
- const [experience, setExperience] = useState({});
- const [currentStep, setCurrentStep] = useState({});
- const [loading, setLoading] = useState(true);
-
- const baseURL = '/echo/task/tutorial';
- const userId = 1;
-
- const fetchTasks = async () => {
- try {
- const response = await axios.get(`${baseURL}/getAllTasks`, {
- params: { user_id: userId },
- });
- setTasks(response.data.tasks || []);
- } catch (error) {
- console.error('获取任务失败:', error);
- }
- };
-
- const fetchExperience = async () => {
- try {
- const response = await axios.get(`${baseURL}/getAllTasks`, {
- params: { user_id: userId },
- });
- setExperience(response.data || {});
- } catch (error) {
- console.error('获取经验失败:', error);
- }
- };
-
- const fetchCurrentStep = async () => {
- try {
- const response = await axios.get(`${baseURL}/getNewStep`, {
- params: { user_id: userId },
- });
- setCurrentStep(response.data || {});
- } catch (error) {
- console.error('获取引导步骤失败:', error);
- }
- };
-
- const updateStatus = async (taskId) => {
- try {
- await axios.post(`${baseURL}/updateStatus`, {
- user_id: userId,
- task_id: taskId,
- });
- await fetchTasks();
- await fetchExperience();
- } catch (error) {
- console.error('更新状态失败:', error);
- }
- };
-
- const updateProgress = async (taskId, progress) => {
- try {
- await axios.post(`${baseURL}/updateProgress`, {
- user_id: userId,
- task_id: taskId,
- progress,
- });
- await fetchTasks();
- } catch (error) {
- console.error('更新进度失败:', error);
- }
- };
-
- const claimReward = async (taskId) => {
- try {
- await axios.post(`${baseURL}/rewardClaim`, {
- user_id: userId,
- task_id: taskId,
- });
- await fetchTasks();
- await fetchExperience();
- } catch (error) {
- console.error('领取奖励失败:', error);
- }
- };
-
- const checkRewardStatus = async (taskId) => {
- try {
- const response = await axios.post(`${baseURL}/rewardReview`, {
- user_id: userId,
- task_id: taskId,
- });
- alert(response.data.message || '已完成');
- } catch (error) {
- console.error('查看失败:', error);
- }
- };
-
- useEffect(() => {
- const init = async () => {
- await fetchTasks();
- await fetchExperience();
- await fetchCurrentStep();
- setLoading(false);
- };
- init();
- }, []);
-
- if (loading) return <p className="loading">加载中...</p>;
-
- return (
- <div className="common-card right-content">
- <div className="profile-header">
- <h1>🎯 新手考核</h1>
- </div>
-
- <div className="profile-details">
- <p><strong>当前经验:</strong>{experience.current_experience}</p>
- <p><strong>等级:</strong>{experience.level}</p>
- <p><strong>奖励经验:</strong>{experience.reward?.experience || 0}</p>
- <p><strong>奖励积分:</strong>{experience.reward?.points || 0}</p>
- </div>
-
- <div className="profile-details">
- <p><strong>🧭 当前引导步骤:</strong>{currentStep.current_step}</p>
- <p>{currentStep.step_description}</p>
- </div>
-
- <div className="profile-details">
- <h2>任务列表</h2>
- <ul>
- {tasks.map(task => (
- <li key={task.task_id} style={{ marginBottom: '20px', borderBottom: '1px solid #eee', paddingBottom: '10px' }}>
- <p><strong>任务:</strong>{task.title}</p>
- <p><strong>描述:</strong>{task.description}</p>
- <p><strong>进度:</strong>{task.progress}%</p>
- <p><strong>状态:</strong>{task.status}</p>
- <p><strong>奖励:</strong>经验 {task.reward.experience},积分 {task.reward.points}</p>
-
- <div className="task-btn-group">
- <button className="task-btn" onClick={() => updateStatus(task.task_id)}>更新状态</button>
- <button className="task-btn" onClick={() => updateProgress(task.task_id, 100)}>提交进度</button>
- <button className="task-btn" onClick={() => claimReward(task.task_id)}>领取奖励</button>
- <button className="task-btn" onClick={() => checkRewardStatus(task.task_id)}>查看奖励状态</button>
- </div>
- </li>
- ))}
- </ul>
- </div>
- </div>
- );
-};
-
-export default NewbieTasks;
-
diff --git a/src/pages/UserCenter/UserNav.jsx b/src/pages/UserCenter/UserNav.jsx
index 3456195..c272424 100644
--- a/src/pages/UserCenter/UserNav.jsx
+++ b/src/pages/UserCenter/UserNav.jsx
@@ -14,6 +14,7 @@
{ to: '/user/collections', label: '我的收藏' },
// { to: '/user/newbie-tasks', label: '新手考核' },
{ to: '/user/invite', label: '邀请新用户' },
+ { to: '/user/recharge', label: '充值服务' },
];
// 判断路径是否是当前活动页面