import React, { useState, useEffect } from "react"; | |
import AccountCircleIcon from "@mui/icons-material/AccountCircle"; | |
import { useNavigate } from "react-router-dom"; | |
import "./App.css"; | |
export default function UserProfile() { | |
const navigate = useNavigate(); | |
const [userInfo, setUserInfo] = useState({ | |
avatar_url: "", | |
username: "示例用户", | |
email: "user@example.com", | |
invite_left: "", | |
school: "", | |
account_status: "", | |
gender: "", | |
}); | |
const [tempUserInfo, setTempUserInfo] = useState({ ...userInfo }); | |
const [userSeeds, setUserSeeds] = useState([]); | |
const [userStats, setUserStats] = useState({ | |
magic: 0, | |
upload: 0, | |
download: 0, | |
ratio: 0, | |
}); | |
// 新增:根据userid从后端获取用户信息 | |
useEffect(() => { | |
const fetchUserInfo = async () => { | |
// 假设userid存储在localStorage或其他地方 | |
// const userid = localStorage.getItem("userid"); | |
const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid | |
if (!userid) return; | |
try { | |
const res = await fetch(`/api/user-profile?userid=${userid}`); | |
if (res.ok) { | |
const data = await res.json(); | |
setUserInfo(data); | |
setTempUserInfo(data); | |
} | |
} catch (err) { | |
// 可以根据需要处理错误 | |
console.error("获取用户信息失败", err); | |
} | |
}; | |
fetchUserInfo(); | |
}, []); | |
// 动态加载用户上传种子列表 | |
useEffect(() => { | |
const fetchUserSeeds = async () => { | |
// const userid = localStorage.getItem("userid"); | |
const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid | |
if (!userid) return; | |
try { | |
const res = await fetch(`/api/user-seeds?userid=${userid}`); | |
if (res.ok) { | |
const data = await res.json(); | |
setUserSeeds(data); | |
} | |
} catch (err) { | |
console.error("获取种子列表失败", err); | |
} | |
}; | |
fetchUserSeeds(); | |
}, []); | |
// 动态加载用户活跃度信息 | |
useEffect(() => { | |
const fetchUserStats = async () => { | |
// const userid = localStorage.getItem("userid"); | |
const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid | |
if (!userid) return; | |
try { | |
const res = await fetch(`/api/user-stats?userid=${userid}`); | |
if (res.ok) { | |
const data = await res.json(); | |
setUserStats(data); | |
} | |
} catch (err) { | |
console.error("获取活跃度信息失败", err); | |
} | |
}; | |
fetchUserStats(); | |
}, []); | |
const handleInputChange = (field, value) => { | |
setTempUserInfo({ ...tempUserInfo, [field]: value }); | |
}; | |
const handleSave = async () => { | |
setUserInfo({ ...tempUserInfo }); | |
// 获取userid | |
// const userid = localStorage.getItem("userid"); | |
const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid | |
try { | |
const res = await fetch('/api/change-profile', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ userid, ...tempUserInfo }), | |
}); | |
if (res.ok) { | |
alert("信息已保存!"); | |
} else { | |
alert("保存失败,请重试。"); | |
} | |
} catch (err) { | |
alert("保存失败,请检查网络连接。"); | |
console.error("保存用户信息失败", err); | |
} | |
}; | |
const handleAvatarClick = () => { | |
const avatarUrl = prompt("请输入头像的URL:"); | |
if (avatarUrl) { | |
setTempUserInfo({ ...tempUserInfo, avatar: avatarUrl }); | |
} | |
}; | |
return ( | |
<div className="container" style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #f0f4ff 0%, #e0e7ff 100%)', display: 'grid', gridTemplateColumns: '1fr 2fr', gridTemplateRows: 'auto 1fr', gap: '20px', padding: '40px' }}> | |
{/* 左侧:用户资料 */} | |
<div style={{ gridColumn: '1 / 2', gridRow: '1 / 3', display: 'flex', flexDirection: 'column', alignItems: 'center', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}> | |
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: 16 }}> | |
<div onClick={handleAvatarClick} style={{ cursor: 'pointer', position: 'relative' }}> | |
<AccountCircleIcon style={{ fontSize: 90, color: '#1a237e', marginBottom: 12 }} /> | |
{tempUserInfo.avatar && ( | |
<img | |
src={tempUserInfo.avatar_url} | |
alt="用户头像" | |
style={{ | |
position: 'absolute', | |
top: 0, | |
left: 0, | |
width: 90, | |
height: 90, | |
borderRadius: '50%', | |
objectFit: 'cover', | |
}} | |
/> | |
)} | |
</div> | |
<h2 style={{ color: '#1a237e', marginBottom: 0, fontSize: 24 }}>用户个人资料</h2> | |
</div> | |
<div className="card" style={{ padding: 28, width: '100%', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', flex: 1 }}> | |
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}> | |
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>用户名:</b> | |
<input | |
type="text" | |
value={tempUserInfo.username} | |
onChange={(e) => handleInputChange("username", e.target.value)} | |
style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }} | |
/> | |
</div> | |
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}> | |
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邮箱:</b> | |
<span | |
style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }} | |
> | |
{tempUserInfo.email} | |
</span> | |
</div> | |
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}> | |
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邀请剩余:</b> | |
<span | |
style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }} | |
> | |
{tempUserInfo.invite_left} | |
</span> | |
</div> | |
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}> | |
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>学校:</b> | |
<input | |
type="text" | |
value={tempUserInfo.school} | |
onChange={(e) => handleInputChange("school", e.target.value)} | |
style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }} | |
/> | |
</div> | |
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}> | |
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>账号状态:</b> | |
<span | |
style={{ flex: 1, display: 'flex', alignItems: 'center', padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }} | |
> | |
{tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? "封禁" : "正常"} | |
<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', | |
}} /> | |
</span> | |
</div> | |
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}> | |
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>性别:</b> | |
<div style={{ position: 'relative', flex: 1 }}> | |
<button | |
onClick={() => setTempUserInfo({ ...tempUserInfo, showGenderOptions: !tempUserInfo.showGenderOptions })} | |
style={{ | |
width: '100%', | |
padding: '6px 10px', | |
borderRadius: 7, | |
border: '1px solid #b2b2b2', | |
textAlign: 'left', | |
backgroundColor: '#fff', | |
fontSize: 15, | |
cursor: 'pointer', | |
}} | |
> | |
{tempUserInfo.gender || "性别"} | |
</button> | |
{tempUserInfo.showGenderOptions && ( | |
<ul | |
style={{ | |
position: 'absolute', | |
top: '100%', | |
left: 0, | |
right: 0, | |
backgroundColor: '#fff', | |
border: '1px solid #b2b2b2', | |
borderRadius: 7, | |
listStyle: 'none', | |
margin: 0, | |
padding: 0, | |
zIndex: 10, | |
}} | |
> | |
{["男", "女", "跨性别男", "跨性别女", "无性别"].map((option) => ( | |
<li | |
key={option} | |
onClick={() => { | |
setTempUserInfo({ ...tempUserInfo, gender: option, showGenderOptions: false }); | |
}} | |
style={{ | |
padding: '6px 10px', | |
cursor: 'pointer', | |
borderBottom: '1px solid #e0e0e0', | |
backgroundColor: option === tempUserInfo.gender ? '#f0f0f0' : '#fff', | |
}} | |
> | |
{option} | |
</li> | |
))} | |
</ul> | |
)} | |
</div> | |
</div> | |
<button | |
onClick={handleSave} | |
style={{ | |
marginTop: 20, | |
padding: '10px 20px', | |
backgroundColor: '#1a237e', | |
color: '#fff', | |
border: 'none', | |
borderRadius: 7, | |
cursor: 'pointer', | |
fontSize: 16, | |
alignSelf: 'center', // Center the button horizontally | |
}} | |
onMouseOver={(e) => (e.target.style.backgroundColor = '#0d1b5e')} | |
onMouseOut={(e) => (e.target.style.backgroundColor = '#1a237e')} | |
> | |
保存 | |
</button> | |
</div> | |
</div> | |
{/* 上传种子列表 */} | |
<div style={{ gridColumn: '2 / 3', gridRow: '1 / 2', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}> | |
<h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18 }}>个人上传种子列表</h3> | |
<div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, minHeight: 60, padding: 12 }}> | |
{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.seed_id || idx} | |
style={{ display: 'flex', alignItems: 'center', padding: '10px 0', borderBottom: '1px solid #e0e7ff', cursor: 'pointer' }} | |
onClick={e => { | |
// 阻止点击删除按钮时跳转 | |
if (e.target.classList.contains('delete-btn')) return; | |
navigate(`/torrent/${seed.seed_id}`); | |
}} | |
> | |
<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.popularity}</span> | |
<button | |
className="delete-btn" | |
style={{ marginLeft: 18, background: '#e53935', color: '#fff', border: 'none', borderRadius: 6, padding: '4px 14px', cursor: 'pointer', fontSize: 14 }} | |
onClick={async (e) => { | |
e.stopPropagation(); | |
// const userid = localStorage.getItem("userid"); | |
const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid | |
try { | |
const res = await fetch('/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> | |
</li> | |
))} | |
</ul> | |
)} | |
</div> | |
</div> | |
{/* 活跃度模块 */} | |
<div style={{ gridColumn: '2 / 3', gridRow: '2 / 3', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}> | |
<h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18 }}>活跃度</h3> | |
<div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, minHeight: 60, padding: 18, display: 'flex', flexDirection: 'column', gap: 12, fontSize: 18 }}> | |
<div>魔力值:<b style={{ color: '#1976d2' }}>{userStats.magic}</b></div> | |
<div>上传量:<b style={{ color: '#43a047' }}>{userStats.upload} GB</b></div> | |
<div>下载量:<b style={{ color: '#e53935' }}>{userStats.download} GB</b></div> | |
<div>上传/下载值:<b style={{ color: '#ff9800' }}>{userStats.ratio}</b></div> | |
</div> | |
</div> | |
</div> | |
); | |
} |