用户资料接口添加
Change-Id: Id55e7fef307ec1663bb7a05cfbf7f81e097ac767
diff --git a/front/src/UserProfile.js b/front/src/UserProfile.js
index 0269723..4737033 100644
--- a/front/src/UserProfile.js
+++ b/front/src/UserProfile.js
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import { useNavigate } from "react-router-dom";
import "./App.css";
@@ -6,21 +6,109 @@
export default function UserProfile() {
const navigate = useNavigate();
const [userInfo, setUserInfo] = useState({
+ avatar_url: "",
username: "示例用户",
email: "user@example.com",
- company: "",
+ invite_left: "",
school: "",
- birthday: "",
+ 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 = () => {
+ const handleSave = async () => {
setUserInfo({ ...tempUserInfo });
- alert("信息已保存!");
+ // 获取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 = () => {
@@ -39,7 +127,7 @@
<AccountCircleIcon style={{ fontSize: 90, color: '#1a237e', marginBottom: 12 }} />
{tempUserInfo.avatar && (
<img
- src={tempUserInfo.avatar}
+ src={tempUserInfo.avatar_url}
alt="用户头像"
style={{
position: 'absolute',
@@ -67,21 +155,19 @@
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邮箱:</b>
- <input
- type="email"
- value={tempUserInfo.email}
- onChange={(e) => handleInputChange("email", e.target.value)}
- style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
- />
+ <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>
- <input
- type="text"
- value={tempUserInfo.company}
- onChange={(e) => handleInputChange("company", e.target.value)}
- style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
- />
+ <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>
@@ -93,22 +179,21 @@
/>
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
- <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>生日:</b>
- <input
- type="date"
- value={tempUserInfo.birthday}
- onChange={(e) => handleInputChange("birthday", 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>
- <input
- type="password"
- value={tempUserInfo.password || ""}
- onChange={(e) => handleInputChange("password", e.target.value)}
- style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
- />
+ <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>
@@ -187,15 +272,61 @@
{/* 上传种子列表 */}
<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, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b2b2b2', fontSize: 18 }}>
- (此处显示上传种子列表)
+ <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, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b2b2b2', fontSize: 18 }}>
- (此处显示活跃度信息)
+ <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>