final

Change-Id: Icf4ec3950a6bd1e066fa4a1976af36721af62a06
diff --git a/front/src/UserProfile.js b/front/src/UserProfile.js
index fb44b43..074d68c 100644
--- a/front/src/UserProfile.js
+++ b/front/src/UserProfile.js
@@ -1,5 +1,13 @@
 import React, { useState, useEffect } from "react";

 import AccountCircleIcon from "@mui/icons-material/AccountCircle";

+import PersonIcon from "@mui/icons-material/Person";

+import EmailIcon from "@mui/icons-material/Email";

+import SchoolIcon from "@mui/icons-material/School";

+import CloudUploadIcon from "@mui/icons-material/CloudUpload";

+import CloudDownloadIcon from "@mui/icons-material/CloudDownload";

+import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";

+import FavoriteIcon from "@mui/icons-material/Favorite";

+import EmptyIcon from "@mui/icons-material/Inbox";

 import Button from '@mui/material/Button';

 import TextField from '@mui/material/TextField';

 import MenuItem from '@mui/material/MenuItem';

@@ -9,7 +17,7 @@
 import DialogActions from '@mui/material/DialogActions';

 import { useNavigate } from "react-router-dom";

 import { API_BASE_URL } from "./config";

-import "./App.css";

+import "./UserProfile.css";

 

 export default function UserProfile() {

   const navigate = useNavigate();

@@ -386,442 +394,352 @@
       console.error('账号迁移失败', err);

       setMigrationStatus('迁移失败,请检查网络');

     }

-  };

+  };  return (

+    <div className="user-profile-container">

+      <div className="profile-grid">

+        {/* 用户基本信息卡片 */}

+        <div className="profile-card user-info-card">

+          <div className="user-avatar-section">

+            <div className="avatar-container" onClick={handleAvatarClick}>

+              {tempUserInfo.avatar_url ? (

+                <img

+                  src={tempUserInfo.avatar_url}

+                  alt="用户头像"

+                  className="user-avatar"

+                />

+              ) : (

+                <AccountCircleIcon style={{ fontSize: 120, color: '#1a237e' }} />

+              )}

+              <div className="avatar-overlay">

+                <span>点击更换头像</span>

+              </div>

+            </div>

+            <h2 className="user-title">用户个人资料</h2>

+          </div>

 

-  return (

-    <div

-      className="container"

-      style={{

-        minHeight: '100vh',

-        background: 'linear-gradient(135deg, #f0f4ff 0%, #e0e7ff 100%)',

-        display: 'grid',

-        gridTemplateColumns: '1.1fr 1.9fr',

-        gridTemplateRows: 'auto auto',

-        gap: '12px',

-        padding: '24px 3vw',

-        boxSizing: 'border-box'

-      }}

-    >

-      {/* 左上:用户资料 */}

-      <div style={{

-        gridColumn: '1 / 2',

-        gridRow: '1 / 2',

-        display: 'flex',

-        flexDirection: 'column',

-        alignItems: 'center',

-        background: '#fff',

-        borderRadius: 20,

-        boxShadow: '0 6px 32px #e0e7ff',

-        padding: '32px 28px',

-        minWidth: 320,

-        minHeight: 420,

-        transition: 'box-shadow 0.2s',

-      }}>

-        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: 18 }}>

-          <div onClick={handleAvatarClick} style={{ cursor: 'pointer', position: 'relative' }}>

-            <AccountCircleIcon style={{ fontSize: 96, color: '#1a237e', marginBottom: 12 }} />

-            {tempUserInfo.avatar_url && (

-              <img

-                src={tempUserInfo.avatar_url}

-                alt="用户头像"

-                style={{

-                  position: 'absolute',

-                  top: 0,

-                  left: 0,

-                  width: 96,

-                  height: 96,

-                  borderRadius: '50%',

-                  objectFit: 'cover',

-                  border: '2px solid #e0e7ff',

-                  boxShadow: '0 2px 8px #bfcfff'

-                }}

+          <div className="user-form">

+            <div className="form-group">

+              <label className="form-label">

+                <PersonIcon style={{ fontSize: 16, marginRight: 4 }} />

+                用户名

+              </label>

+              <input

+                className="form-input"

+                value={tempUserInfo.username}

+                onChange={(e) => handleInputChange("username", e.target.value)}

+                placeholder="请输入用户名"

               />

+            </div>

+

+            <div className="form-group">

+              <label className="form-label">

+                <EmailIcon style={{ fontSize: 16, marginRight: 4 }} />

+                邮箱

+              </label>

+              <input

+                className="form-input"

+                value={tempUserInfo.email}

+                readOnly

+                style={{ cursor: 'not-allowed' }}

+              />

+            </div>

+

+            <div className="form-group">

+              <label className="form-label">

+                <SchoolIcon style={{ fontSize: 16, marginRight: 4 }} />

+                学校

+              </label>

+              <input

+                className="form-input"

+                value={tempUserInfo.school}

+                onChange={(e) => handleInputChange("school", e.target.value)}

+                placeholder="请输入学校名称"

+              />

+            </div>

+

+            <div className="form-group">

+              <label className="form-label">账号状态</label>

+              <div className="status-indicator">

+                <input

+                  className="form-input"

+                  value={tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? "封禁" : "正常"}

+                  readOnly

+                />

+                <div className={`status-dot ${tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? 'banned' : 'active'}`}></div>

+              </div>

+            </div>

+

+            <div className="form-group">

+              <label className="form-label">性别</label>

+              <select

+                className="form-input"

+                value={tempUserInfo.gender}

+                onChange={(e) => handleInputChange("gender", e.target.value)}

+              >

+                <option value="">请选择性别</option>

+                <option value="m">男性</option>

+                <option value="f">女性</option>

+              </select>

+            </div>

+

+            {/* 邀请功能 */}

+            <div className="invite-section">

+              <label className="form-label">邀请功能</label>

+              <div className="invite-form">

+                <input

+                  className="form-input invite-input"

+                  type="email"

+                  placeholder="输入邀请邮箱"

+                  value={inviteEmail}

+                  onChange={e => setInviteEmail(e.target.value)}

+                  disabled={Number(tempUserInfo.invite_left) === 0}

+                />

+                <button

+                  className="btn btn-primary btn-small"

+                  onClick={handleInvite}

+                  disabled={Number(tempUserInfo.invite_left) === 0 || !inviteEmail}

+                >

+                  邀请

+                </button>

+              </div>

+              <div className="invite-counter">

+                剩余邀请次数:{tempUserInfo.invite_left || "0"}

+              </div>

+              {inviteStatus && (

+                <div className="invite-status">{inviteStatus}</div>

+              )}

+            </div>

+

+            <div className="btn-group">

+              <button className="btn btn-primary" onClick={handleSave}>

+                保存信息

+              </button>

+              <button className="btn btn-danger" onClick={() => setAppealOpen(true)}>

+                用户申诉

+              </button>

+              <button className="btn btn-warning" onClick={() => setMigrationOpen(true)}>

+                账号迁移

+              </button>            </div>

+          </div>

+        </div>

+

+        {/* 活跃度卡片 */}

+        <div className="profile-card activity-card">

+          <h3 className="activity-title">

+            <AutoAwesomeIcon style={{ fontSize: 24, marginRight: 8 }} />

+            活跃度统计

+          </h3>

+          

+          <div className="activity-content">

+            {/* 魔力值兑换 */}

+            <div className="magic-exchange">

+              <div className="stat-item">

+                <span className="stat-label">当前魔力值</span>

+                <span className="stat-value magic">{userStats.magic}</span>

+              </div>

+              

+              <div className="exchange-form">

+                <input

+                  className="form-input exchange-input"

+                  type="number"

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

+                  value={exchangeMagic}

+                  onChange={e => setExchangeMagic(e.target.value)}

+                />

+                <select

+                  className="form-input exchange-input"

+                  value={exchangeType}

+                  onChange={e => setExchangeType(e.target.value)}

+                >

+                  <option value="uploaded">上传量(增加)</option>

+                  <option value="downloaded">下载量(减少)</option>

+                  <option value="vip_downloads">VIP下载次数(增加)</option>

+                </select>

+                <button

+                  className="btn btn-primary btn-small"

+                  onClick={handleExchange}

+                  disabled={

+                    !exchangeMagic ||

+                    isNaN(exchangeMagic) ||

+                    Number(exchangeMagic) <= 0 ||

+                    Number(exchangeMagic) > userStats.magic ||

+                    !Number.isInteger(exchangeResult)

+                  }

+                >

+                  兑换

+                </button>

+              </div>

+              

+              {exchangeMagic && (

+                <div className="exchange-result">

+                  可兑换:{exchangeResult} {exchangeType === 'vip_downloads' ? '次' : 'MB'}

+                  {!Number.isInteger(exchangeResult) && exchangeResult > 0 && (

+                    <span style={{ color: '#e53935', marginLeft: 8 }}>

+                      (结果必须为整数)

+                    </span>

+                  )}

+                </div>

+              )}

+            </div>

+

+            {/* 统计数据 */}

+            <div className="stats-grid">

+              <div className="stat-item">

+                <span className="stat-label">

+                  <CloudUploadIcon style={{ fontSize: 16, marginRight: 4 }} />

+                  上传量

+                </span>

+                <span className="stat-value upload">

+                  {(userStats.upload / 1000000)?.toFixed(2)} MB

+                </span>

+              </div>

+              

+              <div className="stat-item">

+                <span className="stat-label">

+                  <CloudDownloadIcon style={{ fontSize: 16, marginRight: 4 }} />

+                  下载量

+                </span>

+                <span className="stat-value download">

+                  {(userStats.download / 1000000)?.toFixed(2)} MB

+                </span>

+              </div>

+              

+              <div className="stat-item">

+                <span className="stat-label">上传/下载比</span>

+                <span className="stat-value ratio">

+                  {userStats.download === 0 ? "∞" : (userStats.upload / userStats.download).toFixed(2)}

+                </span>

+              </div>

+              

+              <div className="stat-item">

+                <span className="stat-label">VIP下载次数</span>

+                <span className="stat-value vip">{userStats.viptime}</span>

+              </div>

+            </div>

+          </div>

+        </div>        {/* 个人上传种子列表 */}

+        <div className="profile-card seeds-card">

+          <h3 className="list-title">

+            <CloudUploadIcon style={{ fontSize: 24, marginRight: 8 }} />

+            个人上传种子列表

+          </h3>

+          

+          <div className="list-container">

+            {userSeeds.length === 0 ? (

+              <div className="empty-state">

+                <EmptyIcon className="empty-icon" />

+                <span>暂无上传种子</span>

+              </div>

+            ) : (

+              <ul className="seeds-list">

+                {userSeeds.map((seed, idx) => (

+                  <li

+                    key={seed.seedid || idx}

+                    className="seed-item"

+                    onClick={e => {

+                      if (e.target.classList.contains('delete-btn')) return;

+                      navigate(`/torrent/${seed.seed_id}`);

+                    }}

+                  >

+                    <span className="seed-title">{seed.title}</span>

+                    <span className="seed-tags">{seed.tags}</span>

+                    <span className="seed-stats">人气: {seed.downloadtimes}</span>

+                    <div className="seed-actions">

+                      <button

+                        className="btn btn-danger btn-small delete-btn"

+                        onClick={async e => {

+                          e.stopPropagation();

+                          const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');

+                          const userid = match ? match[2] : null;

+                          if (!userid) {

+                            alert('未获取到用户ID');

+                            return;

+                          }

+                          try {

+                            const res = await fetch(`${API_BASE_URL}/api/delete-seed`, {

+                              method: 'POST',

+                              headers: { 'Content-Type': 'application/json' },

+                              body: JSON.stringify({ seed_id: seed.seed_id, userid }),

+                            });

+                            if (res.ok) {

+                              setUserSeeds(userSeeds.filter((s, i) => (s.seed_id || i) !== (seed.seed_id || idx)));

+                            } else {

+                              alert('删除失败,请重试');

+                            }

+                          } catch (err) {

+                            alert('删除失败,请检查网络');

+                          }

+                        }}

+                      >

+                        删除

+                      </button>

+                    </div>

+                  </li>

+                ))}

+              </ul>

             )}

           </div>

-          <h2 style={{ color: '#1a237e', marginBottom: 0, fontSize: 26, letterSpacing: 1 }}>用户个人资料</h2>

         </div>

-        <div className="card" style={{

-          padding: 32,

-          width: '100%',

-          background: '#fff',

-          borderRadius: 18,

-          boxShadow: '0 2px 12px #e0e7ff',

-          flex: 1,

-          minWidth: 0

-        }}>

-          <div style={{ marginBottom: 20, display: 'flex', alignItems: 'center' }}>

-            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>用户名:</b>

-            <TextField

-              variant="outlined"

-              size="small"

-              value={tempUserInfo.username}

-              onChange={(e) => handleInputChange("username", e.target.value)}

-              sx={{ flex: 1, minWidth: 0 }}

-            />

-          </div>

-          <div style={{ marginBottom: 20, display: 'flex', alignItems: 'center' }}>

-            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邮箱:</b>

-            <TextField

-              variant="outlined"

-              size="small"

-              value={tempUserInfo.email}

-              InputProps={{ readOnly: true }}

-              sx={{ flex: 1, minWidth: 0, background: '#f5f5f5' }}

-            />

-          </div>

-          {/* 邀请功能 */}

-          <div style={{ marginBottom: 20, display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>

-            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邀请剩余:</b>

-            <TextField

-              type="email"

-              size="small"

-              placeholder="被邀请邮箱"

-              value={inviteEmail}

-              onChange={e => setInviteEmail(e.target.value)}

-              sx={{ flex: 2, marginRight: 1, minWidth: 120 }}

-              disabled={Number(tempUserInfo.invite_left) === 0}

-            />

-            <Button

-              variant="contained"

-              color="primary"

-              onClick={handleInvite}

-              disabled={Number(tempUserInfo.invite_left) === 0 || !inviteEmail}

-              sx={{ marginRight: 1, minWidth: 80 }}

-            >邀请</Button>

-            <span style={{ color: '#888', fontSize: 15 }}>剩余:{tempUserInfo.invite_left || "0"}</span>

-          </div>

-          {inviteStatus && <div style={{ color: '#e53935', fontSize: 14, marginBottom: 8 }}>{inviteStatus}</div>}

-          <div style={{ marginBottom: 20, display: 'flex', alignItems: 'center' }}>

-            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>学校:</b>

-            <TextField

-              variant="outlined"

-              size="small"

-              value={tempUserInfo.school}

-              onChange={(e) => handleInputChange("school", e.target.value)}

-              sx={{ flex: 1, minWidth: 0 }}

-            />

-          </div>

-          <div style={{ marginBottom: 20, display: 'flex', alignItems: 'center' }}>

-            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>账号状态:</b>

-            <TextField

-              variant="outlined"

-              size="small"

-              value={tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? "封禁" : "正常"}

-              InputProps={{ readOnly: true }}

-              sx={{ flex: 1, minWidth: 0, background: '#f5f5f5' }}

-            />

-            <span style={{

-              display: 'inline-block',

-              width: 12,

-              height: 12,

-              borderRadius: '50%',

-              backgroundColor: tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? '#e53935' : '#43a047',

-              marginLeft: 10,

-              border: '1px solid #b2b2b2',

-            }} />

-          </div>

-          <div style={{ marginBottom: 20, display: 'flex', alignItems: 'center' }}>

-            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>性别:</b>

-            <TextField

-              select

-              variant="outlined"

-              size="small"

-              value={tempUserInfo.gender}

-              onChange={e => handleInputChange("gender", e.target.value)}

-              sx={{ flex: 1, minWidth: 0 }}

-            >

-              <MenuItem value="m">男性</MenuItem>

-              <MenuItem value="f">女性</MenuItem>

-            </TextField>

-          </div>          <div style={{ display: 'flex', gap: 16, marginTop: 24, justifyContent: 'flex-end' }}>

-            <Button

-              variant="contained"

-              color="primary"

-              onClick={handleSave}

-              sx={{ fontSize: 16, borderRadius: 2, padding: '6px 12px' }}

-            >保存</Button>

-            <Button

-              variant="contained"

-              color="error"

-              onClick={() => setAppealOpen(true)}

-              sx={{ fontSize: 16, borderRadius: 2, padding: '6px 12px' }}

-            >用户申诉</Button>

-            <Button

-              variant="contained"

-              color="warning"

-              onClick={() => setMigrationOpen(true)}

-              sx={{ fontSize: 16, borderRadius: 2, padding: '6px 12px' }}

-            >账号迁移</Button>

-          </div>

-        </div>

-      </div>

-      {/* 左下:活跃度模块 */}

-      <div style={{

-        gridColumn: '1 / 2',

-        gridRow: '2 / 3',

-        background: '#fff',

-        borderRadius: 20,

-        boxShadow: '0 6px 32px #e0e7ff',

-        padding: '32px 28px',

-        minWidth: 320,

-        minHeight: 320,

-        display: 'flex',

-        flexDirection: 'column',

-        justifyContent: 'center'

-      }}>

-        <h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18, letterSpacing: 1 }}>活跃度</h3>

-        <div style={{

-          border: '1.5px dashed #b2b2b2',

-          borderRadius: 14,

-          minHeight: 80,

-          padding: 22,

-          display: 'flex',

-          flexDirection: 'column',

-          gap: 14,

-          fontSize: 18,

-          background: '#f8faff'

-        }}>

-          <div style={{ display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>

-            <span>魔力值:<b style={{ color: '#1976d2' }}>{userStats.magic}</b></span>

-            <TextField

-              type="number"

-              size="small"

-              placeholder="输入兑换魔力值"

-              value={exchangeMagic}

-              onChange={e => setExchangeMagic(e.target.value)}

-              sx={{ width: 100, marginLeft: 2, marginRight: 1 }}

-            />

-            <TextField

-              select

-              size="small"

-              value={exchangeType}

-              onChange={e => setExchangeType(e.target.value)}

-              sx={{ minWidth: 120 }}

-            >

-              <MenuItem value="uploaded">上传量(增加)</MenuItem>

-              <MenuItem value="downloaded">下载量(减少)</MenuItem>

-              <MenuItem value="vip_downloads">VIP下载次数(增加)</MenuItem>

-            </TextField>            <span style={{ marginLeft: 8, color: '#43a047' }}>

-              可兑换:<b>{exchangeResult}</b> {exchangeType === 'vip_downloads' ? '次' : 'MB'}

-              {!Number.isInteger(exchangeResult) && exchangeResult > 0 && (

-                <span style={{ color: '#e53935', fontSize: '12px', marginLeft: 8 }}>

-                  (结果必须为整数)

-                </span>

-              )}

-            </span><Button

-              variant="contained"

-              color="primary"

-              onClick={handleExchange}

-              disabled={

-                !exchangeMagic ||

-                isNaN(exchangeMagic) ||

-                Number(exchangeMagic) <= 0 ||

-                Number(exchangeMagic) > userStats.magic ||

-                !Number.isInteger(exchangeResult)

-              }

-              sx={{

-                marginLeft: 2,

-                minWidth: 80,

-                background: (!exchangeMagic || isNaN(exchangeMagic) || Number(exchangeMagic) <= 0 || Number(exchangeMagic) > userStats.magic || !Number.isInteger(exchangeResult)) ? '#ccc' : undefined

-              }}

-            >兑换</Button>

-          </div>          <div>上传量:<b style={{ color: '#43a047' }}>{(userStats.upload / 1000000)?.toFixed(2)} MB</b></div>

-          <div>下载量:<b style={{ color: '#e53935' }}>{(userStats.download / 1000000)?.toFixed(2)} MB</b></div>

-          <div>上传/下载值:<b style={{ color: '#ff9800' }}>{userStats.download === 0 ? "∞" : (userStats.upload / userStats.download).toFixed(2)}</b></div>

-          <div>VIP下载次数:<b style={{ color: '#1976d2' }}>{userStats.viptime}</b></div>

-        </div>

-      </div>

-      {/* 右上:个人上传种子列表 */}

-      <div style={{

-        gridColumn: '2 / 3',

-        gridRow: '1 / 2',

-        background: '#fff',

-        borderRadius: 20,

-        boxShadow: '0 6px 32px #e0e7ff',

-        padding: '32px 36px',

-        minHeight: 420,

-        display: 'flex',

-        flexDirection: 'column'

-      }}>

-        <h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18, letterSpacing: 1 }}>个人上传种子列表</h3>

-        <div style={{

-          border: '1.5px dashed #b2b2b2',

-          borderRadius: 14,

-          minHeight: 80,

-          padding: 16,

-          background: '#f8faff'

-        }}>

-          {userSeeds.length === 0 ? (

-            <div style={{ color: '#b2b2b2', fontSize: 18, textAlign: 'center' }}>(暂无上传种子)</div>

-          ) : (

-            <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>

-              {userSeeds.map((seed, idx) => (

-                <li

-                  key={seed.seedid || idx}

-                  style={{

-                    display: 'flex',

-                    alignItems: 'center',

-                    padding: '12px 0',

-                    borderBottom: idx === userSeeds.length - 1 ? 'none' : '1px solid #e0e7ff',

-                    cursor: 'pointer',

-                    transition: 'background 0.15s'

-                  }}

-                  onClick={e => {

-                    if (e.target.classList.contains('delete-btn')) return;

-                    navigate(`/torrent/${seed.seed_id}`);

-                  }}

-                  onMouseOver={e => e.currentTarget.style.background = '#f3f6ff'}

-                  onMouseOut={e => e.currentTarget.style.background = ''}

-                >

-                  <span style={{ flex: 2, fontWeight: 500, color: '#1a237e', textDecoration: 'underline' }}>{seed.title}</span>

-                  <span style={{ flex: 1, color: '#5c6bc0' }}>{seed.tags}</span>

-                  <span style={{ flex: 1, color: '#ff9800', textAlign: 'right' }}>人气: {seed.downloadtimes}</span>

-                  <Button

-                    className="delete-btn"

-                    variant="contained"

-                    color="error"

-                    size="small"

-                    sx={{ marginLeft: 2, borderRadius: 1, minWidth: 60 }} onClick={async e => {

-                      e.stopPropagation();

-                      const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');

-                      const userid = match ? match[2] : null;

-                      if (!userid) {

-                        alert('未获取到用户ID');

-                        return;

-                      }

-                      try {

-                        const res = await fetch(`${API_BASE_URL}/api/delete-seed`, {

-                          method: 'POST',

-                          headers: { 'Content-Type': 'application/json' },

-                          body: JSON.stringify({ seed_id: seed.seed_id, userid }),

-                        });

-                        if (res.ok) {

-                          setUserSeeds(userSeeds.filter((s, i) => (s.seed_id || i) !== (seed.seed_id || idx)));

-                        } else {

-                          alert('删除失败,请重试');

-                        }

-                      } catch (err) {

-                        alert('删除失败,请检查网络');

-                      }

+

+        {/* 个人收藏种子列表 */}

+        <div className="profile-card favorites-card">

+          <h3 className="list-title">

+            <FavoriteIcon style={{ fontSize: 24, marginRight: 8 }} />

+            个人收藏种子列表

+          </h3>

+          

+          <div className="list-container">

+            {userFavorites.length === 0 ? (

+              <div className="empty-state">

+                <FavoriteIcon className="empty-icon" />

+                <span>暂无收藏种子</span>

+              </div>

+            ) : (

+              <ul className="seeds-list">

+                {userFavorites.map((seed, idx) => (

+                  <li

+                    key={seed.seedid || idx}

+                    className="seed-item"

+                    onClick={e => {

+                      if (e.target.classList.contains('remove-favorite-btn')) return;

+                      navigate(`/torrent/${seed.seedid || seed.seed_id}`);

                     }}

-                  >删除</Button>

-                </li>

-              ))}

-            </ul>

-          )}

+                  >

+                    <span className="seed-title">{seed.seed.title}</span>

+                    <span className="seed-tags">{seed.seed.tags}</span>

+                    <span className="seed-stats">人气: {seed.seed.downloadtimes}</span>

+                    <div className="seed-actions">

+                      <button

+                        className="btn btn-warning btn-small remove-favorite-btn"

+                        onClick={e => {

+                          e.stopPropagation();

+                          handleRemoveFavorite(seed.seedid || seed.seed_id);

+                        }}

+                      >

+                        取消收藏

+                      </button>

+                    </div>

+                  </li>

+                ))}

+              </ul>

+            )}

+          </div>

         </div>

-      </div>

-      {/* 右下:个人收藏种子列表 */}

-      <div style={{

-        gridColumn: '2 / 3',

-        gridRow: '2 / 3',

-        background: '#fff',

-        borderRadius: 20,

-        boxShadow: '0 6px 32px #e0e7ff',

-        padding: '32px 36px',

-        minHeight: 320,

-        display: 'flex',

-        flexDirection: 'column'

-      }}>

-        <h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18, letterSpacing: 1 }}>个人收藏种子列表</h3>

-        <div style={{

-          border: '1.5px dashed #b2b2b2',

-          borderRadius: 14,

-          minHeight: 80,

-          padding: 16,

-          background: '#f8faff'

-        }}>

-          {userFavorites.length === 0 ? (

-            <div style={{ color: '#b2b2b2', fontSize: 18, textAlign: 'center' }}>(暂无收藏种子)</div>

-          ) : (<ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>

-            {userFavorites.map((seed, idx) => (

-              <li

-                key={seed.seedid || idx}

-                style={{

-                  display: 'flex',

-                  alignItems: 'center',

-                  padding: '12px 0',

-                  borderBottom: idx === userFavorites.length - 1 ? 'none' : '1px solid #e0e7ff',

-                  cursor: 'pointer',

-                  transition: 'background 0.15s'

-                }} onClick={e => {

-                  if (e.target.classList.contains('remove-favorite-btn')) return;

-                  navigate(`/torrent/${seed.seedid || seed.seed_id}`);

-                }}

-                onMouseOver={e => e.currentTarget.style.background = '#f3f6ff'}

-                onMouseOut={e => e.currentTarget.style.background = ''}

-              >

-                <span style={{ flex: 2, fontWeight: 500, color: '#1a237e', textDecoration: 'underline', cursor: 'pointer' }}>{seed.seed.title}</span>

-                <span style={{ flex: 1, color: '#5c6bc0' }}>{seed.seed.tags}</span>

-                <span style={{ flex: 1, color: '#ff9800', textAlign: 'right' }}>人气: {seed.seed.downloadtimes}</span>

-                <Button

-                  className="remove-favorite-btn"

-                  variant="contained"

-                  color="warning"

-                  size="small"

-                  sx={{ marginLeft: 2, borderRadius: 1, minWidth: 80 }} onClick={e => {

-                    e.stopPropagation();

-                    handleRemoveFavorite(seed.seedid || seed.seed_id);

-                  }}

-                >取消收藏</Button>

-              </li>

-            ))}

-          </ul>

-          )}

-        </div>

-      </div>

+      </div>      

       {/* 申诉弹窗 */}

-      <Dialog open={appealOpen} onClose={() => setAppealOpen(false)}>

-        <DialogTitle>提交申诉</DialogTitle>

-        <DialogContent>

-          <div style={{ marginBottom: 16 }}>

+      <Dialog open={appealOpen} onClose={() => setAppealOpen(false)} maxWidth="sm" fullWidth>

+        <DialogTitle style={{ background: '#f8faff', color: '#1a237e', fontWeight: 600 }}>

+          提交申诉

+        </DialogTitle>

+        <DialogContent style={{ padding: '24px', background: '#ffffff' }}>

+          <div style={{ marginBottom: 20 }}>

             <TextField

               label="申诉主题"

               fullWidth

               value={appealTitle}

               onChange={e => setAppealTitle(e.target.value)}

-              size="small"

-            />

-          </div>          <div>

-            <input

-              type="file"

-              accept=".pdf"

-              onChange={e => {

-                const file = e.target.files[0];

-                if (file && file.type !== 'application/pdf') {

-                  alert('请选择PDF文件');

-                  e.target.value = '';

-                  setAppealFile(null);

-                } else {

-                  setAppealFile(file);

-                }

-              }}

-              style={{ marginTop: 8 }}

-            />

-            <div style={{ fontSize: 12, color: '#666', marginTop: 4 }}>

-              请选择PDF文件(最大100MB)

-            </div>

-          </div>

-        </DialogContent>

-        <DialogActions>

-          <Button onClick={handleAppealSubmit} variant="contained" color="primary" disabled={!appealTitle || !appealFile}>提交</Button>

-          <Button onClick={() => setAppealOpen(false)} variant="outlined">取消</Button>

-        </DialogActions>

-      </Dialog>

-      {/* 账号迁移弹窗 */}

-      <Dialog open={migrationOpen} onClose={() => setMigrationOpen(false)}>

-        <DialogTitle>账号迁移</DialogTitle>

-        <DialogContent>

-          <div style={{ marginBottom: 16 }}>

-            <TextField

-              label="待发放上传量"

-              type="number"

-              fullWidth

-              value={migrationUpload}

-              onChange={e => setMigrationUpload(e.target.value)}

-              size="small"

-              inputProps={{ min: 1 }}

-              style={{ marginBottom: 18 }}

+              variant="outlined"

+              style={{ marginBottom: 16 }}

             />

           </div>

           <div>

@@ -838,21 +756,135 @@
                   setAppealFile(file);

                 }

               }}

-              style={{ marginTop: 8 }}

+              style={{ 

+                marginTop: 8,

+                padding: '12px',

+                border: '2px dashed #e0e7ff',

+                borderRadius: '8px',

+                width: '100%',

+                background: '#f8faff'

+              }}

             />

-            <div style={{ fontSize: 12, color: '#666', marginTop: 4 }}>

+            <div style={{ 

+              fontSize: 12, 

+              color: '#666', 

+              marginTop: 8,

+              padding: '8px 12px',

+              background: '#f0f4ff',

+              borderRadius: '6px'

+            }}>

+              请选择PDF文件(最大100MB)

+            </div>

+          </div>

+        </DialogContent>

+        <DialogActions style={{ padding: '16px 24px', background: '#f8faff' }}>

+          <Button 

+            onClick={handleAppealSubmit} 

+            variant="contained" 

+            disabled={!appealTitle || !appealFile}

+            style={{

+              background: (!appealTitle || !appealFile) ? '#ccc' : 'linear-gradient(135deg, #1a237e 0%, #3f51b5 100%)',

+              color: 'white',

+              fontWeight: 600

+            }}

+          >

+            提交申诉

+          </Button>

+          <Button 

+            onClick={() => setAppealOpen(false)} 

+            variant="outlined"

+            style={{ color: '#1a237e', borderColor: '#1a237e' }}

+          >

+            取消

+          </Button>

+        </DialogActions>

+      </Dialog>

+

+      {/* 账号迁移弹窗 */}

+      <Dialog open={migrationOpen} onClose={() => setMigrationOpen(false)} maxWidth="sm" fullWidth>

+        <DialogTitle style={{ background: '#f8faff', color: '#1a237e', fontWeight: 600 }}>

+          账号迁移

+        </DialogTitle>

+        <DialogContent style={{ padding: '24px', background: '#ffffff' }}>

+          <div style={{ marginBottom: 20 }}>

+            <TextField

+              label="待发放上传量"

+              type="number"

+              fullWidth

+              value={migrationUpload}

+              onChange={e => setMigrationUpload(e.target.value)}

+              variant="outlined"

+              inputProps={{ min: 1 }}

+              style={{ marginBottom: 16 }}

+            />

+          </div>

+          <div>

+            <input

+              type="file"

+              accept=".pdf"

+              onChange={e => {

+                const file = e.target.files[0];

+                if (file && file.type !== 'application/pdf') {

+                  alert('请选择PDF文件');

+                  e.target.value = '';

+                  setAppealFile(null);

+                } else {

+                  setAppealFile(file);

+                }

+              }}

+              style={{ 

+                marginTop: 8,

+                padding: '12px',

+                border: '2px dashed #e0e7ff',

+                borderRadius: '8px',

+                width: '100%',

+                background: '#f8faff'

+              }}

+            />

+            <div style={{ 

+              fontSize: 12, 

+              color: '#666', 

+              marginTop: 8,

+              padding: '8px 12px',

+              background: '#f0f4ff',

+              borderRadius: '6px'

+            }}>

               请选择PDF文件(最大10MB)

             </div>

           </div>

           {migrationStatus && (

-            <div style={{ color: migrationStatus.includes('成功') ? '#43a047' : '#e53935', fontSize: 14, marginTop: 8 }}>

+            <div style={{ 

+              color: migrationStatus.includes('成功') ? '#43a047' : '#e53935', 

+              fontSize: 14, 

+              marginTop: 16,

+              padding: '12px',

+              borderRadius: '8px',

+              background: migrationStatus.includes('成功') ? 'rgba(67, 160, 71, 0.1)' : 'rgba(229, 57, 53, 0.1)',

+              border: `1px solid ${migrationStatus.includes('成功') ? 'rgba(67, 160, 71, 0.3)' : 'rgba(229, 57, 53, 0.3)'}`

+            }}>

               {migrationStatus}

             </div>

           )}

         </DialogContent>

-        <DialogActions>

-          <Button onClick={handleMigrationSubmit} variant="contained" color="primary">提交迁移</Button>

-          <Button onClick={() => setMigrationOpen(false)} variant="outlined">取消</Button>

+        <DialogActions style={{ padding: '16px 24px', background: '#f8faff' }}>

+          <Button 

+            onClick={handleMigrationSubmit} 

+            variant="contained"

+            style={{

+              background: 'linear-gradient(135deg, #ff9800 0%, #ffa726 100%)',

+              color: 'white',

+              fontWeight: 600

+            }}

+          >

+            提交迁移

+          </Button>

+          <Button 

+            onClick={() => setMigrationOpen(false)} 

+            variant="outlined"

+            style={{ color: '#1a237e', borderColor: '#1a237e' }}

+          >

+            取消

+          </Button>

         </DialogActions>

       </Dialog>

     </div>