Merge changes I53afd377,I95718173,Iebe50bff,Ieeaa92b5

* changes:
  索要资源相关的前端以及管理员
  帖子的相关用户前端与管理员后端
  好友的相关前端
  举报的管理员前端
diff --git a/src/components/AvatarWithFrame.css b/src/components/AvatarWithFrame.css
new file mode 100644
index 0000000..ffea91b
--- /dev/null
+++ b/src/components/AvatarWithFrame.css
@@ -0,0 +1,25 @@
+.avatar-container {
+  position: relative;
+  display: inline-block;
+  width: 100px;
+  height: 100px;
+}
+
+.user-avatar {
+  position: absolute;
+  width: 80px;
+  height: 80px;
+  top: 10px;
+  left: 10px;
+  z-index: 1;
+}
+
+.avatar-frame-image {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  z-index: 2;
+  pointer-events: none;
+}
\ No newline at end of file
diff --git a/src/components/AvatarWithFrame.jsx b/src/components/AvatarWithFrame.jsx
new file mode 100644
index 0000000..15be459
--- /dev/null
+++ b/src/components/AvatarWithFrame.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { Avatar } from 'antd';
+import frameImage from './avatar-frame.png'; // 头像框图片素材
+import './AvatarWithFrame.css';
+
+const AvatarWithFrame = () => {
+  // 从localStorage获取用户数据
+  const userData = JSON.parse(localStorage.getItem('user')) || {};
+  const { image, decoration = '' } = userData;
+
+  // 检查是否包含头像框
+  const hasFrame = decoration.includes('头像框');
+
+  return (
+    <div className="avatar-container">
+      {/* 头像 */}
+      <Avatar 
+        src={image} 
+        size={80}
+        className={`user-avatar ${hasFrame ? 'with-frame' : ''}`}
+      />
+      
+      {/* 头像框图片 - 根据decoration显示 */}
+      {hasFrame && (
+        <img 
+          src={frameImage} 
+          alt="头像框" 
+          className="avatar-frame-image"
+        />
+      )}
+    </div>
+  );
+};
+
+export default AvatarWithFrame;
\ No newline at end of file
diff --git a/src/components/avatar-frame.png b/src/components/avatar-frame.png
new file mode 100644
index 0000000..16ad8f0
--- /dev/null
+++ b/src/components/avatar-frame.png
Binary files differ
diff --git a/src/introGuide.js b/src/introGuide.js
new file mode 100644
index 0000000..bcfe58e
--- /dev/null
+++ b/src/introGuide.js
@@ -0,0 +1,43 @@
+import introJs from 'intro.js';
+
+export const startIntroGuide = () => {
+  introJs().setOptions({
+    steps: [
+      {
+        intro: '欢迎加入我们,这是一个优质的种子资源分享社区。让我们快速了解一下主要功能,帮助您更好地使用我们的平台。'
+      },
+     {
+        element: document.querySelector('#torrent-activity'),
+        intro: '这里是首页,包括近期活动速递,资源推荐,您可以浏览最新活动,参加领取奖励,提升您的等级!'
+      },
+      {
+        element: document.querySelector('#community-posts'),
+        intro: '这里是社区交流中心,您可以发布帖子、评论互动、发布需求贴悬赏求助,还能查看我的帖子!'
+      },
+      {
+        element: document.querySelector('#torrent-list'),
+        intro: '这里是全站种子列表,您可以按分类浏览、搜索特定资源、查看详细信息和下载种子文件。所有优质资源都在这里!'
+      },
+      {
+        element: document.querySelector('#torrent-upload'),
+        intro: '这是快速上传种子入口,操作简单易上手,快来上传你的第一个资源!'
+      },
+      {
+        element: document.querySelector('#community-friends'),
+        intro: '这里是好友聊天区,您可以添加和管理好友、畅聊分享!'
+      },
+      {
+        element: document.querySelector('#torrent-shop'),
+        intro: '用您的积分兑换个人装饰、上传量和邀请码,提升使用体验,邀请更多好友。'
+      },
+      {
+        element: document.querySelector('#help-button'),
+        intro: '小贴士:您可以随时点击右上角的帮助按钮重新查看引导和查看文档。祝您使用愉快!'
+      }
+    ],
+    nextLabel: '下一步',
+    prevLabel: '上一步',
+    skipLabel: '跳过',
+    doneLabel: '完成'
+  }).start();
+};
diff --git a/src/pages/AuthStyle.css b/src/pages/AuthStyle.css
new file mode 100644
index 0000000..820c596
--- /dev/null
+++ b/src/pages/AuthStyle.css
@@ -0,0 +1,240 @@
+/* AuthStyle.css - 仅针对auth页面的样式,不影响其他页面 */
+
+/* 限定在.auth-wrapper内的样式才会生效 */
+.auth-wrapper {
+  /* 基础样式 */
+  --primary-color: #f9952f;
+  --primary-hover: #e08527;
+  --white: #ffffff;
+  --light-gray: #f5f5f5;
+  --dark-gray: #333333;
+  --error-color: #ff4d4f;
+
+  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+  
+  /* 页面背景(仅影响.auth-wrapper内部) */
+  background-color: var(--light-gray);
+  background-image: linear-gradient(135deg, var(--primary-color) 0%, #f9c22f 100%);
+  background-size: 400% 400%;
+  min-height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 2rem;
+  animation: gradientBG 15s ease infinite;
+}
+
+@keyframes gradientBG {
+  0% { background-position: 0% 50%; }
+  50% { background-position: 100% 50%; }
+  100% { background-position: 0% 50%; }
+}
+
+/* 容器样式 */
+.auth-wrapper .auth-container {
+  width: 100%;
+  max-width: 500px;
+  animation: fadeIn 0.5s ease;
+}
+
+@keyframes fadeIn {
+  from { opacity: 0; transform: translateY(20px); }
+  to { opacity: 1; transform: translateY(0); }
+}
+
+.auth-wrapper .auth-header {
+  text-align: center;
+  margin-bottom: 2rem;
+  color: var(--white);
+}
+
+.auth-wrapper .auth-header h1 {
+  font-size: 2.5rem;
+  margin-bottom: 0.5rem;
+  text-shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+
+.auth-wrapper .auth-header p {
+  font-size: 1rem;
+  opacity: 0.9;
+}
+
+/* 卡片样式 */
+.auth-wrapper .auth-card {
+  background-color: var(--white);
+  border-radius: 10px;
+  box-shadow: 0 10px 30px rgba(0,0,0,0.1);
+  padding: 2rem;
+  transition: all 0.3s ease;
+}
+
+.auth-wrapper .auth-card:hover {
+  box-shadow: 0 15px 35px rgba(0,0,0,0.15);
+}
+
+/* 标签页样式 */
+.auth-wrapper .tabs {
+  display: flex;
+  position: relative;
+  margin-bottom: 2rem;
+  border-bottom: 1px solid #eee;
+}
+
+.auth-wrapper .tab-btn {
+  flex: 1;
+  padding: 0.75rem;
+  text-align: center;
+  background: none;
+  border: none;
+  font-size: 1rem;
+  font-weight: 600;
+  color: var(--dark-gray);
+  cursor: pointer;
+  transition: all 0.3s ease;
+  position: relative;
+}
+
+.auth-wrapper .tab-btn.active {
+  color: var(--primary-color);
+}
+
+.auth-wrapper .tab-indicator {
+  position: absolute;
+  bottom: -1px;
+  left: 0;
+  height: 3px;
+  width: 50%;
+  background-color: var(--primary-color);
+  transition: all 0.3s ease;
+}
+
+/* 表单样式 */
+.auth-wrapper .auth-form {
+  display: flex;
+  flex-direction: column;
+  gap: 1.5rem;
+}
+
+.auth-wrapper .form-group {
+  position: relative;
+}
+
+.auth-wrapper .form-group input {
+  width: 100%;
+  padding: 1rem;
+  border: 1px solid #ddd;
+  border-radius: 5px;
+  font-size: 1rem;
+  transition: all 0.3s ease;
+}
+
+.auth-wrapper .form-group input:focus {
+  border-color: var(--primary-color);
+  box-shadow: 0 0 0 2px rgba(249, 149, 47, 0.2);
+  outline: none;
+}
+
+.auth-wrapper .form-group.with-button {
+  display: flex;
+  gap: 0.5rem;
+}
+
+.auth-wrapper .form-group.with-button input {
+  flex: 1;
+}
+
+/* 按钮样式 */
+.auth-wrapper .submit-btn {
+  background-color: var(--primary-color);
+  color: white;
+  border: none;
+  padding: 1rem;
+  border-radius: 5px;
+  font-size: 1rem;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  height: 50px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.auth-wrapper .submit-btn:hover {
+  background-color: var(--primary-hover);
+  transform: translateY(-2px);
+}
+
+.auth-wrapper .submit-btn:active {
+  transform: translateY(0);
+}
+
+.auth-wrapper .code-btn {
+  background-color: var(--light-gray);
+  color: var(--dark-gray);
+  border: none;
+  padding: 0 1rem;
+  border-radius: 5px;
+  font-size: 0.9rem;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  white-space: nowrap;
+}
+
+.auth-wrapper .code-btn:hover:not(:disabled) {
+  background-color: #e0e0e0;
+}
+
+.auth-wrapper .code-btn:disabled {
+  cursor: not-allowed;
+  opacity: 0.7;
+}
+
+/* 消息样式 */
+.auth-wrapper .message {
+  padding: 0.75rem 1rem;
+  border-radius: 5px;
+  margin-bottom: 1.5rem;
+  text-align: center;
+  transition: all 0.3s ease;
+}
+
+.auth-wrapper .message.error {
+  background-color: #fff2f0;
+  border: 1px solid var(--error-color);
+  color: var(--error-color);
+}
+
+/* 加载动画 */
+.auth-wrapper .spinner {
+  width: 20px;
+  height: 20px;
+  border: 3px solid rgba(255,255,255,0.3);
+  border-radius: 50%;
+  border-top-color: var(--white);
+  animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+  to { transform: rotate(360deg); }
+}
+
+/* 页脚样式 */
+.auth-wrapper .auth-footer {
+  text-align: center;
+  margin-top: 2rem;
+  color: var(--white);
+  font-size: 0.9rem;
+  opacity: 0.8;
+}
+
+/* 响应式设计 */
+@media (max-width: 600px) {
+  .auth-wrapper {
+    padding: 1rem;
+  }
+  
+  .auth-wrapper .auth-card {
+    padding: 1.5rem;
+  }
+}
\ No newline at end of file
diff --git a/src/pages/HelpPage.css b/src/pages/HelpPage.css
new file mode 100644
index 0000000..6809108
--- /dev/null
+++ b/src/pages/HelpPage.css
@@ -0,0 +1,78 @@
+.help-page-wrapper {
+  min-height: 100vh;
+  background-color: #fff7e6; /* 淡橙色背景 */
+  padding: 3rem 1rem; /* 上下3rem,左右1rem */
+  box-sizing: border-box;
+}
+
+.help-container {
+  max-width: 960px; /* 大约是4xl宽度 */
+  margin: 0 auto;
+  background: white;
+  border: 4px solid black;
+  border-radius: 0.5rem;
+  box-shadow: 0 0 10px rgb(0 0 0 / 0.1);
+  padding: 2rem;
+  box-sizing: border-box;
+}
+
+.help-title {
+  font-size: 2rem;
+  font-weight: 700;
+  text-align: center;
+  margin-bottom: 1.5rem;
+  border-bottom: 2px solid black;
+  padding-bottom: 1rem;
+}
+
+.help-content {
+  max-width: none; /* 让内容最大宽度不限制 */
+  margin: 0 auto;
+  padding: 0 2rem; /* 左右边距2rem */
+  box-sizing: border-box;
+}
+
+/* markdown 内容排版,配合 rehype-highlight 样式 */
+.help-content p {
+  margin: 1rem 0;
+  line-height: 1.6;
+}
+
+.help-content h1 {
+  font-size: 1.5rem;
+  margin: 2rem 0 1rem;
+  font-weight: 700;
+  border-bottom: 1px solid #ccc;
+  padding-bottom: 0.5rem;
+}
+
+.help-content h2 {
+  font-size: 1.25rem;
+  margin: 1.5rem 0 1rem;
+  font-weight: 600;
+}
+
+.help-content code {
+  background-color: #f3f4f6;
+  padding: 0.2rem 0.4rem;
+  border-radius: 0.25rem;
+  font-family: monospace;
+  font-size: 0.9rem;
+}
+
+.help-content pre {
+  background-color: #f3f4f6;
+  padding: 1rem;
+  border-radius: 0.5rem;
+  overflow-x: auto;
+  margin: 1rem 0;
+  border: 1px solid #d1d5db;
+}
+
+.help-content blockquote {
+  border-left: 4px solid #9ca3af;
+  padding-left: 1rem;
+  font-style: italic;
+  color: #6b7280;
+  margin: 1rem 0;
+}
diff --git a/src/pages/HelpPage.jsx b/src/pages/HelpPage.jsx
new file mode 100644
index 0000000..ec5161b
--- /dev/null
+++ b/src/pages/HelpPage.jsx
@@ -0,0 +1,47 @@
+import React, { useEffect, useState } from 'react';
+import ReactMarkdown from 'react-markdown';
+import remarkGfm from 'remark-gfm';
+import rehypeHighlight from 'rehype-highlight';
+import './HelpPage.css'; // 引入样式
+import Navbar from '../components/Navbar'; // 导航栏组件
+
+export default function HelpPage() {
+  const [markdown, setMarkdown] = useState('');
+
+  useEffect(() => {
+    fetch('/help.md')
+      .then(res => {
+        if (!res.ok) throw new Error('Markdown 文件加载失败');
+        return res.text();
+      })
+      .then(text => setMarkdown(text))
+      .catch(() => setMarkdown('# 帮助文档加载失败,请稍后再试。'));
+  }, []);
+
+   return (
+     <div>
+      <Navbar />
+      <div className="help-page-wrapper">
+        <div className="help-container">
+          <h1 className="help-title">📚 帮助文档</h1>
+          <div className="help-content">
+            <ReactMarkdown
+              remarkPlugins={[remarkGfm]}
+              rehypePlugins={[rehypeHighlight]}
+              components={{
+                h1: ({ node, ...props }) => <h1 {...props} />,
+                h2: ({ node, ...props }) => <h2 {...props} />,
+                p: ({ node, ...props }) => <p {...props} />,
+                code: ({ node, ...props }) => <code {...props} />,
+                pre: ({ node, ...props }) => <pre {...props} />,
+                blockquote: ({ node, ...props }) => <blockquote {...props} />,
+              }}
+            >
+              {markdown}
+            </ReactMarkdown>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
diff --git a/src/pages/ShopPage.jsx b/src/pages/ShopPage.jsx
new file mode 100644
index 0000000..bb7d989
--- /dev/null
+++ b/src/pages/ShopPage.jsx
@@ -0,0 +1,187 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+import { message, Button } from 'antd';
+import { ArrowLeftOutlined } from '@ant-design/icons';
+import { useNavigate } from 'react-router-dom';
+
+const ShopPage = () => {
+  const navigate = useNavigate();
+  const [user, setUser] = useState(null);
+  const [loading, setLoading] = useState(false);
+  const [shopItems, setShopItems] = useState([
+    {
+      id: 1,
+      type: 'decoration',
+      name: '头像框',
+      description: '好看的头像框可以让别人更好地记住你',
+      price: 100,
+      image: 'https://img.icons8.com/?size=100&id=11730&format=png&color=000000'
+    },
+    {
+      id: 2,
+      type: 'decoration',
+      name: '对话框',
+      description: '闪亮的对话框,让您的消息更醒目',
+      price: 150,
+      image: 'https://img.icons8.com/?size=100&id=143&format=png&color=000000'
+    },
+    {
+      id: 3,
+      type: 'upload',
+      name: '上传量+100MB',
+      description: '增加100MB的上传量',
+      price: 50,
+      image: 'https://img.icons8.com/?size=100&id=368&format=png&color=000000'
+    },
+    {
+      id: 4,
+      type: 'invite',
+      name: '邀请码',
+      description: '一个邀请码,用于邀请好友加入',
+      price: 200,
+      image: 'https://img.icons8.com/?size=100&id=5465&format=png&color=000000'
+    }
+  ]);
+
+  useEffect(() => {
+    // 从localStorage获取用户信息
+    const userData = localStorage.getItem('user');
+    if (userData) {
+      setUser(JSON.parse(userData));
+    }
+  }, []);
+
+  const handlePurchase = async (item) => {
+    if (!user) {
+      message.error('请先登录');
+      return;
+    }
+
+    setLoading(true);
+    try {
+      let response;
+      const username = user.username;
+
+      switch (item.type) {
+        case 'decoration':
+          response = await axios.post('http://localhost:8080/shop/soldDecoration', null, {
+            params: {
+              buyername: username,
+              decoration: item.name,
+              price: item.price
+            }
+          });
+          break;
+        case 'upload':
+          response = await axios.post('http://localhost:8080/shop/soldUpload', null, {
+            params: {
+              buyername: username,
+              price: item.price,
+              upload: 100 // 假设每次购买增加100MB
+            }
+          });
+          break;
+        case 'invite':
+          response = await axios.post('http://localhost:8080/shop/soldInvite', null, {
+            params: {
+              buyername: username,
+              price: item.price
+            }
+          });
+          break;
+        default:
+          throw new Error('未知的商品类型');
+      }
+
+      if (response.data && response.data.success) {
+        message.success('购买成功!');
+        // 更新用户信息
+        user.credit -= item.price;
+        if(item.type=='decoration'){
+            user.decoration= user.decoration+" "+item.name;
+        }
+        localStorage.setItem('user', JSON.stringify(user));
+        setUser(user);
+      } else {
+        message.error(response.data.message || '购买失败');
+      }
+    } catch (error) {
+      console.error('购买出错:', error);
+      message.error(error.response?.data?.message || '购买过程中出错');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  if (!user) {
+    return (
+      <div style={{ padding: '20px', textAlign: 'center' }}>
+        <h2>请先登录后再访问商城</h2>
+      </div>
+    );
+  }
+
+  return (
+    <div className="shop-container" style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
+      {/* 添加返回按钮 */}
+      <Button 
+        type="text" 
+        icon={<ArrowLeftOutlined />} 
+        onClick={() => navigate(-1)}
+        style={{ marginBottom: '20px', paddingLeft: 0 }}
+      >
+        返回
+      </Button>
+
+      <h1 style={{ textAlign: 'center', marginBottom: '30px' }}>商城</h1>
+      <div style={{ marginBottom: '20px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+        <div>
+          <h3>当前用户: {user.username}</h3>
+          <p>余额: {user.credit || 0} 积分</p>
+        </div>
+      </div>
+
+      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: '20px' }}>
+        {shopItems.map((item) => (
+          <div key={item.id} style={{
+            border: '1px solid #ddd',
+            borderRadius: '8px',
+            padding: '15px',
+            display: 'flex',
+            flexDirection: 'column',
+            boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
+          }}>
+            <div style={{ height: '150px', backgroundColor: '#f5f5f5', display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '15px' }}>
+              {item.image ? (
+                <img src={item.image} alt={item.name} style={{ maxWidth: '100%', maxHeight: '100%' }} />
+              ) : (
+                <span>商品图片</span>
+              )}
+            </div>
+            <h3 style={{ margin: '0 0 10px 0' }}>{item.name}</h3>
+            <p style={{ color: '#666', flexGrow: 1 }}>{item.description}</p>
+            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: '15px' }}>
+              <span style={{ fontSize: '18px', fontWeight: 'bold', color: '#f56c6c' }}>{item.price} 积分</span>
+              <button
+                onClick={() => handlePurchase(item)}
+                disabled={loading || (user.credit < item.price)}
+                style={{
+                  padding: '8px 16px',
+                  backgroundColor: user.credit >= item.price ? '#1890ff' : '#ccc',
+                  color: 'white',
+                  border: 'none',
+                  borderRadius: '4px',
+                  cursor: user.credit >= item.price ? 'pointer' : 'not-allowed'
+                }}
+              >
+                {loading ? '处理中...' : '购买'}
+              </button>
+            </div>
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export default ShopPage;
\ No newline at end of file
diff --git a/src/pages/UserAuth.jsx b/src/pages/UserAuth.jsx
new file mode 100644
index 0000000..2982270
--- /dev/null
+++ b/src/pages/UserAuth.jsx
@@ -0,0 +1,274 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+import './AuthStyle.css'; // 引入样式文件
+
+const UserAuth = () => {
+  // 状态管理
+  const [registerData, setRegisterData] = useState({
+    username: '',
+    password: '',
+    code: '',
+    email: '',
+    emailcode: ''
+  });
+  const [loginData, setLoginData] = useState({
+    username: '',
+    password: ''
+  });
+  const [activeTab, setActiveTab] = useState('login');
+  const [message, setMessage] = useState('');
+  const [error, setError] = useState('');
+  const [countdown, setCountdown] = useState(0);
+  const [isLoading, setIsLoading] = useState(false);
+
+  // 倒计时效果
+  useEffect(() => {
+    if (countdown > 0) {
+      const timer = setTimeout(() => setCountdown(countdown - 1), 1000);
+      return () => clearTimeout(timer);
+    }
+  }, [countdown]);
+
+  // 输入处理
+  const handleChange = (e, formType) => {
+    const { name, value } = e.target;
+    formType === 'register' 
+      ? setRegisterData(prev => ({ ...prev, [name]: value }))
+      : setLoginData(prev => ({ ...prev, [name]: value }));
+  };
+
+  // 发送验证码
+  const handleSendCode = async () => {
+    if (!registerData.email) {
+      setError('请输入邮箱地址');
+      return;
+    }
+    
+    try {
+      setIsLoading(true);
+      const response = await axios.post('http://localhost:8080/user/sendCode', null, {
+        params: { email: registerData.email }
+      });
+      
+      if (response.data?.success) {
+        setMessage('验证码已发送');
+        setError('');
+        setCountdown(60);
+      } else {
+        setError(response.data?.message || '发送失败');
+      }
+    } catch (err) {
+      setError(err.response?.data?.message || '发送出错');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  // 注册提交
+  const handleRegister = async (e) => {
+    e.preventDefault();
+    if (Object.values(registerData).some(v => !v)) {
+      setError('请填写所有字段');
+      return;
+    }
+    
+    try {
+      setIsLoading(true);
+      const response = await axios.post('http://localhost:8080/user/register', {
+        username: registerData.username,
+        password: registerData.password,
+        email: registerData.email
+      }, {
+        params: {
+          code: registerData.code,
+          emailcode: registerData.emailcode
+        }
+      });
+      
+      if (response.data?.success) {
+        setMessage('注册成功');
+        setActiveTab('login');
+        setRegisterData({
+          username: '',
+          password: '',
+          code: '',
+          email: '',
+          emailcode: ''
+        });
+      } else {
+        setError(response.data?.message || '注册失败');
+      }
+    } catch (err) {
+      setError(err.response?.data?.message || '注册出错');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  // 登录提交
+  const handleLogin = async (e) => {
+    e.preventDefault();
+    if (!loginData.username || !loginData.password) {
+      setError('请输入用户名和密码');
+      return;
+    }
+    
+    try {
+      setIsLoading(true);
+      const response = await axios.post('http://localhost:8080/user/login', null, {
+        params: {
+          username: loginData.username,
+          password: loginData.password
+        }
+      });
+      
+      if (response.data?.success) {
+        localStorage.setItem('user', JSON.stringify(response.data.user));
+        if(response.data.user.permission==0)
+        window.location.href = '/';
+        else
+        window.location.href = '/';
+      } else {
+        setError(response.data?.message || '登录失败');
+      }
+    } catch (err) {
+      setError(err.response?.data?.message || '登录出错');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <div className="auth-wrapper">
+    <div className="auth-container">
+      <div className="auth-header">
+        <h1>PT Share</h1>
+        <p>专业资源分享平台</p>
+      </div>
+      
+      <div className="auth-card">
+        <div className="tabs">
+          <button 
+            className={`tab-btn ${activeTab === 'login' ? 'active' : ''}`}
+            onClick={() => setActiveTab('login')}
+          >
+            登录
+          </button>
+          <button 
+            className={`tab-btn ${activeTab === 'register' ? 'active' : ''}`}
+            onClick={() => setActiveTab('register')}
+          >
+            注册
+          </button>
+          <div 
+            className="tab-indicator" 
+            style={{ left: activeTab === 'login' ? '0' : '50%' }}
+          />
+        </div>
+        
+        <div className={`message ${error ? 'error' : ''}`}>
+          {error || message}
+        </div>
+        
+        {activeTab === 'login' ? (
+          <form onSubmit={handleLogin} className="auth-form">
+            <div className="form-group">
+              <input
+                type="text"
+                name="username"
+                value={loginData.username}
+                onChange={(e) => handleChange(e, 'login')}
+                placeholder="用户名"
+                required
+              />
+            </div>
+            <div className="form-group">
+              <input
+                type="password"
+                name="password"
+                value={loginData.password}
+                onChange={(e) => handleChange(e, 'login')}
+                placeholder="密码"
+                required
+              />
+            </div>
+            <button type="submit" className="submit-btn" disabled={isLoading}>
+              {isLoading ? <div className="spinner"></div> : '登 录'}
+            </button>
+          </form>
+        ) : (
+          <form onSubmit={handleRegister} className="auth-form">
+            <div className="form-group">
+              <input
+                type="text"
+                name="username"
+                value={registerData.username}
+                onChange={(e) => handleChange(e, 'register')}
+                placeholder="用户名"
+                required
+              />
+            </div>
+            <div className="form-group">
+              <input
+                type="password"
+                name="password"
+                value={registerData.password}
+                onChange={(e) => handleChange(e, 'register')}
+                placeholder="密码"
+                required
+              />
+            </div>
+            <div className="form-group">
+              <input
+                type="text"
+                name="code"
+                value={registerData.code}
+                onChange={(e) => handleChange(e, 'register')}
+                placeholder="邀请码"
+                required
+              />
+            </div>
+            <div className="form-group">
+              <input
+                type="email"
+                name="email"
+                value={registerData.email}
+                onChange={(e) => handleChange(e, 'register')}
+                placeholder="邮箱"
+                required
+              />
+            </div>
+            <div className="form-group with-button">
+              <input
+                type="text"
+                name="emailcode"
+                value={registerData.emailcode}
+                onChange={(e) => handleChange(e, 'register')}
+                placeholder="验证码"
+                required
+              />
+              <button 
+                type="button" 
+                onClick={handleSendCode}
+                disabled={countdown > 0 || isLoading}
+                className="code-btn"
+              >
+                {countdown > 0 ? `${countdown}s` : '获取验证码'}
+              </button>
+            </div>
+            <button type="submit" className="submit-btn" disabled={isLoading}>
+              {isLoading ? <div className="spinner"></div> : '注 册'}
+            </button>
+          </form>
+        )}
+      </div>
+      
+      <div className="auth-footer">
+        <p>© {new Date().getFullYear()} PT Share - 专业资源分享平台</p>
+      </div>
+    </div>
+    </div>
+  );
+};
+
+export default UserAuth;
\ No newline at end of file
diff --git a/src/pages/UserCenter.jsx b/src/pages/UserCenter.jsx
new file mode 100644
index 0000000..2b71e65
--- /dev/null
+++ b/src/pages/UserCenter.jsx
@@ -0,0 +1,599 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+import { message, Button, Form, Input, Radio, Upload, Avatar, Modal, Card, Statistic, Row, Col } from 'antd';
+import { UserOutlined, LockOutlined, LogoutOutlined, UploadOutlined, DownloadOutlined, StarOutlined, MoneyCollectOutlined, ArrowLeftOutlined } from '@ant-design/icons';
+import { useNavigate } from 'react-router-dom';
+import AvatarWithFrame from '../components/AvatarWithFrame.jsx';
+
+const UserCenter = () => {
+  const [user, setUser] = useState(null);
+  const [form] = Form.useForm();
+  const [avatarForm] = Form.useForm();
+  const [passwordForm] = Form.useForm();
+  const [loading, setLoading] = useState(false);
+  const [avatarLoading, setAvatarLoading] = useState(false);
+  const [passwordLoading, setPasswordLoading] = useState(false);
+  const [isModalVisible, setIsModalVisible] = useState(false);
+  const [fadeAnimation, setFadeAnimation] = useState(false);
+  const navigate = useNavigate();
+
+  // Add fade-in animation when component mounts
+  useEffect(() => {
+    setFadeAnimation(true);
+  }, []);
+
+  useEffect(() => {
+    const userData = localStorage.getItem('user');
+    if (userData) {
+      const parsedUser = JSON.parse(userData);
+      setUser(parsedUser);
+      form.setFieldsValue({ sex: parsedUser.sex || '男' });
+    } else {
+      message.error('请先登录');
+      navigate('/login');
+    }
+  }, [form, navigate]);
+
+  const handleGoBack = () => {
+    navigate(-1); // 返回上一页
+  };
+
+  const handleSexChange = async () => {
+    try {
+      const values = await form.validateFields();
+      setLoading(true);
+      const response = await axios.post('http://localhost:8080/user/changesex', null, {
+        params: {
+          username: user.username,
+          sex: values.sex
+        }
+      });
+
+      if (response.data && response.data.success) {
+        message.success('性别修改成功');
+        const updatedUser = { ...user, sex: values.sex };
+        localStorage.setItem('user', JSON.stringify(updatedUser));
+        setUser(updatedUser);
+
+        // Add a subtle success animation effect
+        message.config({
+          duration: 2,
+          maxCount: 1,
+        });
+      } else {
+        message.error(response.data.message || '性别修改失败');
+      }
+    } catch (error) {
+      console.error('修改性别出错:', error);
+      message.error(error.response?.data?.message || '修改性别过程中出错');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleAvatarChange = async (info) => {
+    if (info.file.status === 'uploading') {
+      setAvatarLoading(true);
+      return;
+    }
+
+    if (info.file.status === 'done') {
+      try {
+        const uploadRes = info.file.response;
+        if (!uploadRes?.success) {
+          throw new Error(uploadRes?.message || '上传失败');
+        }
+
+        const updateRes = await axios.post('http://localhost:8080/user/changeimage', null, {
+          params: {
+            username: user.username,
+            image: uploadRes.url
+          }
+        });
+
+        if (updateRes.data?.success) {
+          message.success('头像更新成功');
+          const updatedUser = {
+            ...user,
+            image: uploadRes.url,
+            ...updateRes.data.user
+          };
+          localStorage.setItem('user', JSON.stringify(updatedUser));
+          setUser(updatedUser);
+
+          // Add a subtle animation when avatar updates
+          message.config({
+            duration: 2,
+            maxCount: 1,
+          });
+        } else {
+          throw new Error(updateRes.data?.message || '更新失败');
+        }
+      } catch (err) {
+        message.error(err.message);
+      } finally {
+        setAvatarLoading(false);
+      }
+    }
+
+    if (info.file.status === 'error') {
+      message.error(info.file.response?.message || '上传出错');
+      setAvatarLoading(false);
+    }
+  };
+
+  const handlePasswordChange = async () => {
+    try {
+      const values = await passwordForm.validateFields();
+      setPasswordLoading(true);
+      const response = await axios.post('http://localhost:8080/user/changePassword', null, {
+        params: {
+          username: user.username,
+          oldpassword: values.oldPassword,
+          newpassword: values.newPassword
+        }
+      });
+
+      if (response.data && response.data.success) {
+        message.success('密码修改成功');
+        passwordForm.resetFields();
+        setIsModalVisible(false);
+
+        // Add a subtle success animation effect
+        message.config({
+          duration: 2,
+          maxCount: 1,
+        });
+      } else {
+        message.error(response.data.message || '密码修改失败');
+      }
+    } catch (error) {
+      console.error('修改密码出错:', error);
+      message.error(error.response?.data?.message || '修改密码过程中出错');
+    } finally {
+      setPasswordLoading(false);
+    }
+  };
+
+  const handleLogout = () => {
+    localStorage.removeItem('user');
+    message.success('已退出登录');
+    navigate('/'); // 退出后跳转到登录页
+  };
+
+  const uploadProps = {
+    name: 'avatar',
+    action: 'http://localhost:8080/user/uploadimage',
+    showUploadList: false,
+    onChange: handleAvatarChange,
+    beforeUpload: (file) => {
+      const isImage = ['image/jpeg', 'image/png', 'image/gif'].includes(file.type);
+      if (!isImage) {
+        message.error('只能上传JPG/PNG/GIF图片!');
+        return false;
+      }
+      const isLt10M = file.size / 1024 / 1024 < 10;
+      if (!isLt10M) {
+        message.error('图片必须小于10MB!');
+        return false;
+      }
+      return true;
+    },
+    transformResponse: (data) => {
+      try {
+        return JSON.parse(data);
+      } catch {
+        return { success: false, message: '解析响应失败' };
+      }
+    }
+  };
+
+  if (!user) {
+    return <div style={{ padding: '20px', textAlign: 'center' }}>加载中...</div>;
+  }
+
+  const calculateRatio = () => {
+    if (user.user_download === 0) return '∞';
+    return (user.user_upload / user.user_download).toFixed(2);
+  };
+
+  // Dynamic styles with the primary color #ffbd19
+  const primaryColor = '#ffbd19';
+  const secondaryColor = '#ffffff'; // White for contrast
+  const cardBackgroundColor = '#ffffff';
+  const cardShadow = '0 4px 12px rgba(255, 189, 25, 0.1)';
+  const textColor = '#333333';
+  const borderColor = '#ffbd19';
+
+  return (
+    <div style={{
+      maxWidth: '1000px',
+      margin: '0 auto',
+      padding: '20px',
+      animation: fadeAnimation ? 'fadeIn 0.5s ease-in' : 'none'
+    }}>
+      {/* CSS animations */}
+      <style>{`
+        @keyframes fadeIn {
+          from { opacity: 0; transform: translateY(10px); }
+          to { opacity: 1; transform: translateY(0); }
+        }
+        
+        .stat-card:hover {
+          transform: translateY(-5px);
+          transition: transform 0.3s ease;
+          box-shadow: 0 6px 16px rgba(255, 189, 25, 0.2);
+        }
+        
+        .section-title {
+          position: relative;
+          padding-bottom: 10px;
+          margin-bottom: 20px;
+        }
+        
+        .section-title::after {
+          content: '';
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          width: 50px;
+          height: 3px;
+          background-color: ${primaryColor};
+          border-radius: 3px;
+        }
+        
+        .avatar-upload-hint {
+          transition: all 0.3s ease;
+        }
+        
+        .avatar-upload-hint:hover {
+          background-color: rgba(255, 189, 25, 0.2);
+        }
+      `}</style>
+
+      {/* 添加返回按钮 */}
+      <Button
+        type="text"
+        icon={<ArrowLeftOutlined />}
+        onClick={handleGoBack}
+        style={{
+          marginBottom: '20px',
+          color: textColor,
+          transition: 'all 0.3s'
+        }}
+        onMouseOver={(e) => e.currentTarget.style.color = primaryColor}
+        onMouseOut={(e) => e.currentTarget.style.color = textColor}
+      >
+        返回
+      </Button>
+
+      <h1 style={{
+        textAlign: 'center',
+        marginBottom: '30px',
+        color: textColor,
+        fontWeight: 'bold'
+      }}>
+        用户中心
+      </h1>
+
+      <div style={{
+        display: 'flex',
+        flexDirection: 'column',
+        gap: '30px'
+      }}>
+        {/* 基本信息展示 */}
+        <div style={{
+          backgroundColor: cardBackgroundColor,
+          padding: '20px',
+          borderRadius: '8px',
+          boxShadow: cardShadow
+        }}>
+          <div style={{
+            display: 'flex',
+            alignItems: 'center',
+            marginBottom: '20px'
+          }}>
+            <Upload {...uploadProps}>
+              <div style={{ position: 'relative', cursor: 'pointer' }}>
+                <AvatarWithFrame user={user} />
+                <div style={{
+                  position: 'absolute',
+                  bottom: -25,
+                  right: 20,
+                  backgroundColor: 'rgba(0,0,0,0.5)',
+                  color: 'white',
+                  padding: '2px 8px',
+                  borderRadius: '4px',
+                  fontSize: '12px'
+                }}>
+                  <UploadOutlined /> 修改
+                </div>
+              </div>
+            </Upload>
+            <div style={{
+              marginLeft: '20px', // Adjusted position
+              flex: 1
+            }}>
+              <h2 style={{ margin: '0', color: textColor }}>{user.username}</h2>
+              <p style={{ margin: '5px 0 0', color: '#666' }}>用户等级: Lv {user.grade_id}</p>
+            </div>
+          </div>
+        </div>
+
+        {/* 数据统计展示区 */}
+        <Card
+          title={
+            <div className="section-title">
+              数据统计
+            </div>
+          }
+          bordered={false}
+          style={{
+            borderRadius: '8px',
+            boxShadow: cardShadow
+          }}
+        >
+          <Row gutter={16}>
+            <Col span={6}>
+              <Card
+                className="stat-card"
+                hoverable
+                style={{
+                  borderRadius: '8px',
+                  textAlign: 'center',
+                  transition: 'all 0.3s'
+                }}
+              >
+                <Statistic
+                  title="积分"
+                  value={user.credit || 0}
+                  prefix={<MoneyCollectOutlined style={{ color: primaryColor }} />}
+                  valueStyle={{ color: '#3f8600' }}
+                />
+              </Card>
+            </Col>
+            <Col span={6}>
+              <Card
+                className="stat-card"
+                hoverable
+                style={{
+                  borderRadius: '8px',
+                  textAlign: 'center',
+                  transition: 'all 0.3s'
+                }}
+              >
+                <Statistic
+                  title="上传量 (MB)"
+                  value={(user.user_upload / (1024 * 1024)).toFixed(2) || 0}
+                  prefix={<UploadOutlined style={{ color: primaryColor }} />}
+                  valueStyle={{ color: '#1890ff' }}
+                />
+              </Card>
+            </Col>
+            <Col span={6}>
+              <Card
+                className="stat-card"
+                hoverable
+                style={{
+                  borderRadius: '8px',
+                  textAlign: 'center',
+                  transition: 'all 0.3s'
+                }}
+              >
+                <Statistic
+                  title="下载量 (MB)"
+                  value={(user.user_download / (1024 * 1024)).toFixed(2) || 0}
+                  prefix={<DownloadOutlined style={{ color: primaryColor }} />}
+                  valueStyle={{ color: '#722ed1' }}
+                />
+              </Card>
+            </Col>
+            <Col span={6}>
+              <Card
+                className="stat-card"
+                hoverable
+                style={{
+                  borderRadius: '8px',
+                  textAlign: 'center',
+                  transition: 'all 0.3s'
+                }}
+              >
+                <Statistic
+                  title="分享率"
+                  value={calculateRatio()}
+                  prefix={<StarOutlined style={{ color: primaryColor }} />}
+                  valueStyle={{ color: '#faad14' }}
+                />
+              </Card>
+            </Col>
+          </Row>
+        </Card>
+
+        {/* 性别设置 */}
+        <div style={{
+          backgroundColor: cardBackgroundColor,
+          padding: '20px',
+          borderRadius: '8px',
+          boxShadow: cardShadow
+        }}>
+          <h3 className="section-title">性别设置</h3>
+          <Form form={form} layout="inline">
+            <Form.Item name="sex">
+              <Radio.Group>
+                <Radio value="男">男</Radio>
+                <Radio value="女">女</Radio>
+                <Radio value="保密">保密</Radio>
+              </Radio.Group>
+            </Form.Item>
+            <Form.Item>
+              <Button
+                type="primary"
+                onClick={handleSexChange}
+                loading={loading}
+                style={{
+                  backgroundColor: primaryColor,
+                  borderColor: primaryColor,
+                  transition: 'all 0.3s'
+                }}
+                onMouseOver={(e) => {
+                  e.currentTarget.style.backgroundColor = '#ffc940';
+                  e.currentTarget.style.borderColor = '#ffc940';
+                }}
+                onMouseOut={(e) => {
+                  e.currentTarget.style.backgroundColor = primaryColor;
+                  e.currentTarget.style.borderColor = primaryColor;
+                }}
+              >
+                确认修改
+              </Button>
+            </Form.Item>
+          </Form>
+        </div>
+
+        {/* 修改密码 */}
+        <div style={{
+          backgroundColor: cardBackgroundColor,
+          padding: '20px',
+          borderRadius: '8px',
+          boxShadow: cardShadow
+        }}>
+          <h3 className="section-title">修改密码</h3>
+          <Button
+            type="primary"
+            onClick={() => setIsModalVisible(true)}
+            icon={<LockOutlined />}
+            style={{
+              backgroundColor: primaryColor,
+              borderColor: primaryColor,
+              transition: 'all 0.3s'
+            }}
+            onMouseOver={(e) => {
+              e.currentTarget.style.backgroundColor = '#ffc940';
+              e.currentTarget.style.borderColor = '#ffc940';
+            }}
+            onMouseOut={(e) => {
+              e.currentTarget.style.backgroundColor = primaryColor;
+              e.currentTarget.style.borderColor = primaryColor;
+            }}
+          >
+            修改密码
+          </Button>
+        </div>
+
+        {/* 退出登录 */}
+        <div style={{ textAlign: 'center' }}>
+          <Button
+            danger
+            onClick={handleLogout}
+            icon={<LogoutOutlined />}
+            style={{
+              transition: 'all 0.3s'
+            }}
+            onMouseOver={(e) => e.currentTarget.style.opacity = '0.8'}
+            onMouseOut={(e) => e.currentTarget.style.opacity = '1'}
+          >
+            退出登录
+          </Button>
+        </div>
+      </div>
+
+      {/* 修改密码模态框 */}
+      <Modal
+        title={
+          <div style={{
+            color: primaryColor,
+            fontWeight: 'bold'
+          }}>
+            修改密码
+          </div>
+        }
+        open={isModalVisible}
+        onCancel={() => setIsModalVisible(false)}
+        footer={null}
+        centered
+        width={400}
+        className="modal-content"
+        style={{
+          borderRadius: '8px',
+          boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
+        }}
+      >
+        <Form
+          form={passwordForm}
+          layout="vertical"
+          onFinish={handlePasswordChange}
+        >
+          <Form.Item
+            name="oldPassword"
+            label="旧密码"
+            rules={[{ required: true, message: '请输入旧密码' }]}
+          >
+            <Input.Password
+              placeholder="请输入当前密码"
+              style={{ borderRadius: '4px' }}
+            />
+          </Form.Item>
+          <Form.Item
+            name="newPassword"
+            label="新密码"
+            rules={[
+              { required: true, message: '请输入新密码' },
+              { min: 3, message: '密码长度不能少于3位' }
+            ]}
+          >
+            <Input.Password
+              placeholder="请输入新密码"
+              style={{ borderRadius: '4px' }}
+            />
+          </Form.Item>
+          <Form.Item
+            name="confirmPassword"
+            label="确认新密码"
+            dependencies={['newPassword']}
+            rules={[
+              { required: true, message: '请确认新密码' },
+              ({ getFieldValue }) => ({
+                validator(_, value) {
+                  if (!value || getFieldValue('newPassword') === value) {
+                    return Promise.resolve();
+                  }
+                  return Promise.reject(new Error('两次输入的密码不一致!'));
+                },
+              }),
+            ]}
+          >
+            <Input.Password
+              placeholder="请再次输入新密码"
+              style={{ borderRadius: '4px' }}
+            />
+          </Form.Item>
+          <Form.Item>
+            <Button
+              type="primary"
+              htmlType="submit"
+              loading={passwordLoading}
+              style={{
+                width: '100%',
+                backgroundColor: primaryColor,
+                borderColor: primaryColor,
+                transition: 'all 0.3s'
+              }}
+              onMouseOver={(e) => {
+                e.currentTarget.style.backgroundColor = '#ffc940';
+                e.currentTarget.style.borderColor = '#ffc940';
+              }}
+              onMouseOut={(e) => {
+                e.currentTarget.style.backgroundColor = primaryColor;
+                e.currentTarget.style.borderColor = primaryColor;
+              }}
+            >
+              确认修改
+            </Button>
+          </Form.Item>
+        </Form>
+      </Modal>
+    </div>
+  );
+};
+
+export default UserCenter;
\ No newline at end of file