个人中心全部,模糊乱序搜索,类型筛选

Change-Id: Id635654fccccaea80bfbf4d1480abd55f7d12046
diff --git a/src/components/Personal/Exchange.jsx b/src/components/Personal/Exchange.jsx
new file mode 100644
index 0000000..1e5b2e8
--- /dev/null
+++ b/src/components/Personal/Exchange.jsx
@@ -0,0 +1,175 @@
+import React, { useState, useEffect } from 'react';

+import { useNavigate, useLocation } from 'react-router-dom';

+import { generateInviteCode, getUserInviteCodes, exchangeUpload, getUserInfo } from '../../api/personal';

+import './personalSubpage.css';

+

+const Exchange = () => {

+  const navigate = useNavigate();

+  const location = useLocation();

+  const [inviteCodes, setInviteCodes] = useState([]);

+  const [userInfo, setUserInfo] = useState(null);

+  const [magicPoints, setMagicPoints] = useState('0'); 

+  const [loading, setLoading] = useState(false);

+  const [error, setError] = useState(null);

+

+  // 获取用户信息和邀请码列表

+  useEffect(() => {

+    const fetchData = async () => {

+      try {

+        setLoading(true);

+        const [userData, codes] = await Promise.all([

+          getUserInfo(),

+          getUserInviteCodes()

+        ]);

+        setUserInfo(userData);

+        setInviteCodes(codes);

+      } catch (err) {

+        setError(err.message);

+      } finally {

+        setLoading(false);

+      }

+    };

+    fetchData();

+  }, []);

+

+  // 生成邀请码

+  const handleGenerateInviteCode = async () => {

+    try {

+      setLoading(true);

+      const newCode = await generateInviteCode();

+      setInviteCodes([...inviteCodes, newCode]);

+      // 刷新用户信息

+      const updatedUser = await getUserInfo();

+      setUserInfo(updatedUser);

+    } catch (err) {

+      setError(err.message);

+    } finally {

+      setLoading(false);

+    }

+  };

+

+  const handleExchangeUpload = async () => {

+    const points = Number(magicPoints);

+    if (!points || points <= 0) {

+      setError('请输入有效的魔力值');

+      return;

+    }

+    try {

+      setLoading(true);

+      await exchangeUpload(points);

+      // 刷新用户信息

+      const updatedUser = await getUserInfo();

+      setUserInfo(updatedUser);

+      setMagicPoints('0');

+      setError(null);

+    } catch (err) {

+      setError(err.message);

+    } finally {

+      setLoading(false);

+    }

+  };

+

+  const handleBack = () => {

+    // 返回个人中心,并携带来源标记

+    navigate('/personal', { 

+      state: { 

+        fromSubpage: true,  // 标记来自子页面

+        dashboardTab: location.state?.dashboardTab // 保留Dashboard的标签页状态

+      },

+      replace: true  // 替换当前历史记录

+    });

+  };

+

+  if (loading) {

+    return <div className="subpage-container">加载中...</div>;

+  }

+

+  if (error) {

+    return (

+      <div className="subpage-container">

+        <button className="back-button" onClick={handleBack}>

+          ← 返回个人中心

+        </button>

+        <div className="error">错误: {error}</div>

+      </div>

+    );

+  }

+

+  return (

+    <div className="subpage-container">

+      <button className="back-button" onClick={handleBack}>

+        ← 返回个人中心

+      </button>

+

+      <h2 className="page-title">兑换区</h2>

+      

+      <div className="exchange-section">

+        <h3>当前魔力值: {userInfo?.magicPoints || 0}</h3>

+        

+        <div className="exchange-card">

+          <h4>兑换邀请码</h4>

+          <p>消耗10魔力值兑换一个邀请码</p>

+          <button 

+            className="exchange-btn"

+            onClick={handleGenerateInviteCode}

+            disabled={!userInfo || userInfo.magicPoints < 10}

+          >

+            兑换邀请码

+          </button>

+        </div>

+

+        <div className="exchange-card">

+          <h4>兑换上传量</h4>

+          <p>1魔力值 = 1GB上传量</p>

+          <div className="exchange-input-group">

+          <input

+            type="number"

+            value={magicPoints}

+            onChange={(e) => {

+              // 允许空字符串或有效数字

+              const value = e.target.value;

+              if (value === '' || !isNaN(value)) {

+                setMagicPoints(value);

+              }

+            }}

+            min="1"

+            max={userInfo?.magicPoints || 0}

+            placeholder="输入要兑换的魔力值"

+          />

+

+          <button 

+            className="exchange-btn"

+            onClick={handleExchangeUpload}

+            disabled={

+              !magicPoints || 

+              Number(magicPoints) <= 0 || 

+              !userInfo || 

+              Number(magicPoints) > userInfo.magicPoints

+            }

+          >

+            兑换上传量

+          </button>

+          </div>

+        </div>

+

+        {inviteCodes.length > 0 && (

+          <div className="invite-code-list">

+            <h4>我的邀请码</h4>

+            <ul>

+              {inviteCodes.map((code, index) => (

+                <li key={index}>

+                  <span className="code">{code.code}</span>

+                  <span className={`status ${code.isUsed ? 'used' : 'available'}`}>

+                    {code.isUsed ? '已使用' : '可用'}

+                  </span>

+                </li>

+              ))}

+            </ul>

+          </div>

+        )}

+      </div>

+    </div>

+  );

+};

+

+export default Exchange;
\ No newline at end of file