Merge "管理员端用户管理"
diff --git a/src/App.css b/src/App.css
new file mode 100644
index 0000000..1766c19
--- /dev/null
+++ b/src/App.css
@@ -0,0 +1,2891 @@
+#root {
+  max-width: 100%;
+  margin: 0;
+  padding: 0;
+}
+
+/* 覆盖默认样式,适配Mantine组件 */
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.mantine-Image-root {
+  border-radius: 8px;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
+
+.mantine-Card-root {
+  margin-bottom: 1rem;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
diff --git a/src/App.jsx b/src/App.jsx
new file mode 100644
index 0000000..b04728a
--- /dev/null
+++ b/src/App.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
+import Home from './pages/Home';
+import AdminPage from './pages/AdminPage';
+import TorrentDetail from './components/torrentdetail';
+import TorrentDetailhelp from './components/torrentdetailhelp';
+import TorrentDetailcomplain from './components/torrentdetailcomplain';
+import TorrentList from './components/torrentlist';
+import UploadTorrent from './components/upload';
+import Navbar from './components/Navbar';
+import TorrentDetailmanage from './pages/managetorrentdetail';
+import RecommendAll from './components/RecommendAll';
+import UserAuth from './pages/UserAuth';
+import 'antd/dist/reset.css'; // Ant Design 默认样式
+import './App.css';
+import MainPage from './pages/MainPage';
+import Friend from './pages/Friend';
+import Community from './pages/Community';
+import UserCenter from './pages/UserCenter111';
+import UploadTorrentFull from './components/upload-full';
+import ShopPage from './pages/ShopPage';
+
+// 定义橙色主题(使用 Ant Design 的 orange-6 色值)
+const orangeTheme = {
+  token: {
+    colorPrimary: '#fa8c16', // orange-6
+    borderRadius: 4,         // 可选:圆角大小
+  },
+};
+
+function App() {
+  return (
+    <div className="App">
+      {/* <div className="container mx-auto p-4"> */}
+        <Routes>
+          {/* <Route path="/" element={<Home />} /> */}
+          <Route path="/home" element={<MainPage />} />
+          <Route path="/admin" element={<AdminPage />} />
+          <Route path="/admin/:id" element={<TorrentDetailmanage />} />
+          <Route path="/process/:id" element={<TorrentDetailhelp />} />
+          <Route path="/complain-process/:id" element={<TorrentDetailcomplain />} />
+          <Route path="/torrents" element={<TorrentList />} />
+          <Route path="/upload" element={<UploadTorrent />} />
+          <Route path="/torrent/:id" element={<TorrentDetail />} />
+          <Route path="/recommend" element={<RecommendAll />} />
+          <Route path="/" element={<UserAuth />} />
+          <Route path="/Community" element={<Community />} />
+          <Route path="/friend" element={<Friend />} />
+          <Route path="/usercenter" element={<UserCenter />} />
+          <Route path="/uploadfull/:requestid" element={<UploadTorrentFull/>}/>
+          <Route path="/shop" element={<ShopPage />} />
+        </Routes>
+      {/* </div> */}
+    </div>
+  );
+}
+
+export default App;
\ No newline at end of file
diff --git a/src/Modal.css b/src/Modal.css
new file mode 100644
index 0000000..c37a106
--- /dev/null
+++ b/src/Modal.css
@@ -0,0 +1,118 @@
+/* 模态框遮罩层 */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5); /* 半透明黑色背景 */
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000; /* 确保在最上层 */
+}
+
+/* 模态框内容 */
+.modal-content {
+  background-color: white;
+  border-radius: 12px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+  width: 90%;
+  max-width: 500px; /* 最大宽度 */
+  overflow: hidden;
+  animation: fadeInUp 0.3s ease-out; /* 淡入动画 */
+}
+
+/* 模态框头部 */
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 16px 20px;
+  background-color: #e6f0ff; /* 浅蓝色背景 */
+  border-bottom: 1px solid #d0e3ff;
+}
+
+.modal-header h3 {
+  margin: 0;
+  font-size: 18px;
+  font-weight: 600;
+  color: #0066cc; /* 蓝色标题 */
+}
+
+.close-btn {
+  background: none;
+  border: none;
+  font-size: 24px;
+  cursor: pointer;
+  color: #666;
+}
+
+.close-btn:hover {
+  color: #000;
+}
+
+/* 模态框主体 */
+.modal-body {
+  padding: 20px;
+}
+
+.modal-body p {
+  margin: 0;
+  font-size: 16px;
+  color: #333;
+}
+
+.highlight {
+  font-weight: 600;
+  color: #0066cc; /* 蓝色高亮 */
+}
+
+/* 模态框底部 */
+.modal-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  padding: 16px 20px;
+  background-color: #f5f5f5;
+}
+
+/* 按钮样式 */
+.btn-cancel {
+  padding: 8px 16px;
+  border: 1px solid #ccc;
+  background: white;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+.btn-cancel:hover {
+  background: #f0f0f0;
+}
+
+.btn-confirm {
+  padding: 8px 16px;
+  background-color: #0066cc; /* 蓝色按钮 */
+  color: white;
+  border: none;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+.btn-confirm:hover {
+  background-color: #0052a3; /* 深蓝色 */
+}
+
+/* 动画 */
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(10px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
\ No newline at end of file
diff --git a/src/TorrentDetail.css b/src/TorrentDetail.css
new file mode 100644
index 0000000..d854a7c
--- /dev/null
+++ b/src/TorrentDetail.css
@@ -0,0 +1,48 @@
+.page-wrapper {
+  padding: 0px 24px 24px 24px;
+  background-color: #ffffff;
+  min-height: 100vh;
+}
+
+.custom-card {
+  background-color: #fafae7;
+  border: 1px solid #ffd591 !important;
+  border-radius: 12px !important;
+  box-shadow: 0 4px 12px rgba(255, 153, 0, 0.1);
+}
+
+.custom-table .ant-table-thead > tr > th {
+  background-color: #fff1b8 !important;
+  color: #a15c00;
+  font-weight: bold;
+}
+
+.info-card {
+  background-color: #fffefc;
+  border: 1px solid #ffe58f;
+  border-radius: 16px !important;
+  box-shadow: 0 6px 16px rgba(255, 140, 0, 0.15);
+  padding: 24px;
+  transition: box-shadow 0.3s ease;
+}
+
+.info-card:hover {
+  box-shadow: 0 10px 24px rgba(255, 140, 0, 0.25);
+}
+
+.info-title {
+  color: #d46b08;
+  font-weight: 700;
+  margin-bottom: 24px;
+}
+
+.custom-descriptions .ant-descriptions-item-label {
+  background-color: #fff7e6 !important;
+  color: #a15c00 !important;
+  font-size: 16px;
+}
+
+.custom-descriptions .ant-descriptions-item-content {
+  font-size: 15px;
+  color: #595959;
+}
diff --git a/src/__mocks__/axios.js b/src/__mocks__/axios.js
new file mode 100644
index 0000000..1e2caac
--- /dev/null
+++ b/src/__mocks__/axios.js
@@ -0,0 +1,4 @@
+// __mocks__/axios.js
+const axios = jest.createMockFromModule('axios');
+
+export default axios;
\ No newline at end of file
diff --git a/src/api/__tests__/chat.test.js b/src/api/__tests__/chat.test.js
new file mode 100644
index 0000000..8571fbc
--- /dev/null
+++ b/src/api/__tests__/chat.test.js
@@ -0,0 +1,84 @@
+// src/api/__tests__/chat.test.js
+const axios = require('axios');
+const MockAdapter = require('axios-mock-adapter');
+const {
+    createChat,
+    deleteChat,
+    getChatsByUser,
+    getChatsBetweenUsers
+} = require('../chat');
+
+jest.mock('axios');
+
+describe('Chat API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    test('createChat should post chat data', async () => {
+        const mockData = {
+            senderId: 1,
+            receiverId: 2,
+            content: 'Hello!',
+            talkTime: '2025-06-09T10:00:00'
+        };
+        const mockResponse = { data: { ...mockData, informationid: 101 } };
+        axios.post.mockResolvedValue(mockResponse);
+
+        const response = await createChat(mockData);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/chat/create',
+            mockData
+        );
+        expect(response.data).toEqual(mockResponse.data);
+    });
+
+    test('deleteChat should send delete request', async () => {
+        axios.delete.mockResolvedValue({ data: '删除成功' });
+
+        const response = await deleteChat(101);
+
+        expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/chat/delete/101');
+        expect(response.data).toBe('删除成功');
+    });
+
+    test('getChatsByUser should fetch all chats for a user', async () => {
+        const userId = 1;
+        const mockData = { data: [{ senderId: 1, receiverId: 2, content: 'Hi' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const result = await getChatsByUser(userId);
+
+        expect(axios.get).toHaveBeenCalledWith(`http://localhost:8080/chat/user/${userId}`);
+        expect(result).toEqual(mockData.data);
+    });
+
+    test('getChatsBetweenUsers should fetch chats between two users', async () => {
+        const user1 = 1;
+        const user2 = 2;
+        const mockData = {
+            data: [{ senderId: 1, receiverId: 2, content: 'Hi there!' }]
+        };
+        axios.get.mockResolvedValue(mockData);
+
+        const result = await getChatsBetweenUsers(user1, user2);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/chat/between', {
+            params: { user1, user2 }
+        });
+        expect(result).toEqual(mockData.data);
+    });
+
+    test('getChatsByUser should return [] on error', async () => {
+        axios.get.mockRejectedValue(new Error('Failed'));
+        const result = await getChatsByUser(1);
+        expect(result).toEqual([]);
+    });
+
+    test('getChatsBetweenUsers should return [] on error', async () => {
+        axios.get.mockRejectedValue(new Error('Failed'));
+        const result = await getChatsBetweenUsers(1, 2);
+        expect(result).toEqual([]);
+    });
+});
diff --git a/src/api/__tests__/comment.test.js b/src/api/__tests__/comment.test.js
new file mode 100644
index 0000000..a55dba7
--- /dev/null
+++ b/src/api/__tests__/comment.test.js
@@ -0,0 +1,83 @@
+// src/api/__tests__/comment.test.js
+const axios = require('axios');
+jest.mock('axios');
+
+const {
+    createComment,
+    deleteComment,
+    updateComment,
+    getCommentsByPostId,
+    likeComment,
+    unlikeComment
+} = require('../comment');
+
+describe('Comment API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    test('createComment should send POST request', async () => {
+        const mockData = { userid: 1, postid: 2, postCommentcontent: 'Test comment' };
+        axios.post.mockResolvedValue({ data: mockData });
+
+        const response = await createComment(mockData);
+
+        expect(axios.post).toHaveBeenCalledWith('http://localhost:8080/comment/create', mockData);
+        expect(response.data).toEqual(mockData);
+    });
+
+    test('deleteComment should send DELETE request', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await deleteComment(123);
+
+        expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/comment/delete/123');
+        expect(response.data).toBe(true);
+    });
+
+    test('updateComment should send PUT request', async () => {
+        const updatedData = { commentid: 1, postCommentcontent: 'Updated comment' };
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await updateComment(updatedData);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/comment/update', updatedData);
+        expect(response.data).toBe(true);
+    });
+
+    test('getCommentsByPostId should fetch comments by post ID', async () => {
+        const mockResponse = { data: [{ commentid: 1, postCommentcontent: 'Nice!' }] };
+        axios.get.mockResolvedValue(mockResponse);
+
+        const response = await getCommentsByPostId(5);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/comment/post/5');
+        expect(response).toEqual(mockResponse.data);
+    });
+
+    test('getCommentsByPostId should return empty array on error', async () => {
+        axios.get.mockRejectedValue(new Error('Network Error'));
+
+        const response = await getCommentsByPostId(99);
+
+        expect(response).toEqual([]);
+    });
+
+    test('likeComment should send POST request', async () => {
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await likeComment(10);
+
+        expect(axios.post).toHaveBeenCalledWith('http://localhost:8080/comment/like/10');
+        expect(response.data).toBe(true);
+    });
+
+    test('unlikeComment should send POST request', async () => {
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await unlikeComment(10);
+
+        expect(axios.post).toHaveBeenCalledWith('http://localhost:8080/comment/unlike/10');
+        expect(response.data).toBe(true);
+    });
+});
diff --git a/src/api/__tests__/complain.test.js b/src/api/__tests__/complain.test.js
new file mode 100644
index 0000000..94a06c6
--- /dev/null
+++ b/src/api/__tests__/complain.test.js
@@ -0,0 +1,96 @@
+const axios = require('axios');
+jest.mock('axios');
+
+const {
+    createComplain,
+    deleteComplain,
+    updateComplain,
+    getComplainsByTargetUser,
+    getComplainsByPostingUser,
+    getAllComplains,
+    getComplainDetailById
+} = require('../complain');
+
+describe('Complain API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    test('createComplain should post complain data', async () => {
+        const mockData = { data: { complainid: 1 } };
+        const complainPayload = { puse: 1, duser: 2, content: 'test', torrentid: 99 };
+        axios.post.mockResolvedValue(mockData);
+
+        const response = await createComplain(complainPayload);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/complain/create',
+            complainPayload
+        );
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('deleteComplain should send delete request', async () => {
+        const mockData = { data: true };
+        axios.delete.mockResolvedValue(mockData);
+
+        const response = await deleteComplain(1);
+
+        expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/complain/delete/1');
+        expect(response).toBe(true);
+    });
+
+    test('updateComplain should put complain data', async () => {
+        const complainPayload = { complainid: 1, content: 'updated' };
+        const mockData = { data: true };
+        axios.put.mockResolvedValue(mockData);
+
+        const response = await updateComplain(complainPayload);
+
+        expect(axios.put).toHaveBeenCalledWith(
+            'http://localhost:8080/complain/update',
+            complainPayload
+        );
+        expect(response).toBe(true);
+    });
+
+    test('getComplainsByTargetUser should fetch complains by duser', async () => {
+        const mockData = { data: [{ complainid: 1, duser: 2 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getComplainsByTargetUser(2);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/target/2');
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('getComplainsByPostingUser should fetch complains by puse', async () => {
+        const mockData = { data: [{ complainid: 1, puse: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getComplainsByPostingUser(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/from/1');
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('getAllComplains should fetch all complains', async () => {
+        const mockData = { data: [{ complainid: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getAllComplains();
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/all');
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('getComplainDetailById should fetch detailed complain info', async () => {
+        const mockData = { data: { complainid: 1, puse: 1, duser: 2 } };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getComplainDetailById(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/detail/1');
+        expect(response).toEqual(mockData.data);
+    });
+});
diff --git a/src/api/__tests__/friends.test.js b/src/api/__tests__/friends.test.js
new file mode 100644
index 0000000..2358e04
--- /dev/null
+++ b/src/api/__tests__/friends.test.js
@@ -0,0 +1,90 @@
+const axios = require('axios');
+jest.mock('axios'); // mock axios
+
+const {
+    addFriend,
+    acceptFriend,
+    rejectFriend,
+    deleteFriend,
+    getFriendsByUserId,
+    getPendingRequests
+} = require('../friends'); // 引入你的 API 方法
+
+describe('Friends API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks(); // 每个测试前清除 mock 状态
+    });
+
+    test('addFriend should post friend request data', async () => {
+        const mockFriendData = {
+            friend1: 1,
+            friend2: 2
+        };
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await addFriend(mockFriendData);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/add',
+            mockFriendData
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('acceptFriend should send accept request with params', async () => {
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await acceptFriend(1, 2);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/accept',
+            null,
+            { params: { friend1: 1, friend2: 2 } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('rejectFriend should delete pending friend request', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await rejectFriend(1, 2);
+
+        expect(axios.delete).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/delete',
+            { params: { friend1: 1, friend2: 2 } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('deleteFriend should delete a friend relationship', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await deleteFriend(3, 4);
+
+        expect(axios.delete).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/delete',
+            { params: { friend1: 3, friend2: 4 } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('getFriendsByUserId should get all accepted friends for user', async () => {
+        const mockData = { data: [{ relationid: 1, friend1: 1, friend2: 2, status: 'accepted' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getFriendsByUserId(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/friends/list/1');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('getPendingRequests should fetch pending friend requests', async () => {
+        const mockData = { data: [{ relationid: 2, friend1: 3, friend2: 1, status: 'pending' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getPendingRequests(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/friends/pending/1');
+        expect(response.data).toEqual(mockData.data);
+    });
+});
diff --git a/src/api/__tests__/post.test.js b/src/api/__tests__/post.test.js
new file mode 100644
index 0000000..89fe48f
--- /dev/null
+++ b/src/api/__tests__/post.test.js
@@ -0,0 +1,160 @@
+const axios = require('axios');
+const MockAdapter = require('axios-mock-adapter');
+
+const {
+    createPost,
+    togglePinPost,
+    deletePost,
+    updatePost,
+    searchPosts,
+    likePost,
+    unlikePost,
+    pinPost,
+    unpinPost,
+    findPostsByUserId,
+    findPinnedPosts,
+    getAllPostsSorted,
+    getPostById
+} = require('../post'); // 注意根据你的实际路径修改
+
+jest.mock('axios');
+
+describe('Post API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    test('createPost should post form data', async () => {
+        const formData = new FormData();
+        formData.append('userid', '1');
+        formData.append('post_title', 'Test');
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await createPost(formData);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/post/create',
+            formData,
+            { headers: { 'Content-Type': 'multipart/form-data' } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('togglePinPost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await togglePinPost(123);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/togglePin/123');
+        expect(response.data).toBe(true);
+    });
+
+    test('deletePost should send DELETE request', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await deletePost(123);
+
+        expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/post/delete/123');
+        expect(response.data).toBe(true);
+    });
+
+    test('updatePost should send PUT request with JSON', async () => {
+        const post = { postid: 1, post_title: 'Updated Title' };
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await updatePost(post);
+
+        expect(axios.put).toHaveBeenCalledWith(
+            'http://localhost:8080/post/update',
+            JSON.stringify(post),
+            { headers: { 'Content-Type': 'application/json' } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('searchPosts should send GET request with keyword', async () => {
+        const mockData = { data: [{ post_title: 'Keyword Match' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await searchPosts('test');
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/search?keyword=test');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('likePost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await likePost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/like/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('unlikePost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await unlikePost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/unlike/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('pinPost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await pinPost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/pin/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('unpinPost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await unpinPost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/unpin/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('findPostsByUserId should fetch user posts', async () => {
+        const mockData = { data: [{ postid: 1, userid: 2 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await findPostsByUserId(2);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/findByUserid?userid=2');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('findPinnedPosts should fetch pinned posts', async () => {
+        const mockData = { data: [{ postid: 1, is_pinned: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await findPinnedPosts();
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/findPinned');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('getAllPostsSorted should fetch all posts sorted', async () => {
+        const mockData = { data: [{ postid: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getAllPostsSorted();
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/all');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('getPostById should fetch post by ID', async () => {
+        const mockData = { data: { postid: 1 } };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getPostById(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/get/1');
+        expect(response.data).toEqual(mockData.data);
+    });
+});
diff --git a/src/api/activity.js b/src/api/activity.js
new file mode 100644
index 0000000..8d9b24f
--- /dev/null
+++ b/src/api/activity.js
@@ -0,0 +1,48 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/activity';
+
+// 获取所有 is_show == 0 的活动预览(只含标题和图片)
+export const getActivityPreviews = () => {
+    return axios.get(`${BASE_URL}/preview`);
+};
+
+// 获取所有 is_show == 0 的完整活动信息
+export const getFullActivities = () => {
+    return axios.get(`${BASE_URL}/full`);
+};
+
+// 创建新的活动公告(使用 FormData 传递)
+export const createActivity = (formData) => {
+    return axios.post(`${BASE_URL}/create`, formData, {
+        headers: {
+            'Content-Type': 'multipart/form-data',
+        },
+    });
+};
+
+// 删除活动公告(通过 ID)
+export const deleteActivity = (id) => {
+    return axios.delete(`${BASE_URL}/delete/${id}`);
+};
+
+// 获取所有活动(无论展示状态)
+export const getAllActivities = () => {
+    return axios.get(`${BASE_URL}/all`);
+};
+
+// 修改活动公告(使用 FormData 传递)
+export const updateActivity = (formData) => {
+    return axios.put(`${BASE_URL}/update`, formData, {
+        headers: {
+            'Content-Type': 'multipart/form-data',
+        },
+    });
+};
+
+// 根据标题搜索活动
+export const searchActivitiesByTitle = (title) => {
+    return axios.get(`${BASE_URL}/search`, {
+        params: { title },
+    });
+};
diff --git a/src/api/chat.js b/src/api/chat.js
new file mode 100644
index 0000000..ab2d38d
--- /dev/null
+++ b/src/api/chat.js
@@ -0,0 +1,40 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/chat';
+
+// 创建聊天记录
+export const createChat = (chatData) => {
+    return axios.post(`${BASE_URL}/create`, chatData);
+};
+
+// 删除聊天记录
+export const deleteChat = (chatId) => {
+    return axios.delete(`${BASE_URL}/delete/${chatId}`);
+};
+
+// 获取某个用户的所有聊天记录(与所有人的)
+export async function getChatsByUser(userId) {
+    try {
+        const response = await axios.get(`${BASE_URL}/user/${userId}`);
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('获取用户聊天记录失败', error);
+        return [];
+    }
+}
+
+// 获取两个用户之间的聊天记录(请求参数形式)
+export async function getChatsBetweenUsers(user1Id, user2Id) {
+    try {
+        const response = await axios.get(`${BASE_URL}/between`, {
+            params: {
+                user1: user1Id,
+                user2: user2Id
+            }
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('获取两人聊天记录失败', error);
+        return [];
+    }
+}
diff --git a/src/api/comment.js b/src/api/comment.js
new file mode 100644
index 0000000..28b2b4e
--- /dev/null
+++ b/src/api/comment.js
@@ -0,0 +1,40 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/comment';
+
+// 创建评论
+export const createComment = (commentData) => {
+    return axios.post(`${BASE_URL}/create`, commentData);
+};
+
+// 删除评论
+export const deleteComment = (commentId) => {
+    return axios.delete(`${BASE_URL}/delete/${commentId}`);
+};
+
+// 更新评论
+export const updateComment = (commentData) => {
+    return axios.put(`${BASE_URL}/update`, commentData);
+};
+
+// 获取某个帖子的所有评论
+// comment.js
+export async function getCommentsByPostId(postid) {
+    try {
+        const response = await axios.get(`${BASE_URL}/post/${postid}`);
+        return Array.isArray(response.data) ? response.data : []; // 确保返回数据是数组
+    } catch (error) {
+        console.error('获取评论失败', error);
+        return [];
+    }
+}
+
+// 点赞评论
+export const likeComment = (commentId) => {
+    return axios.post(`${BASE_URL}/like/${commentId}`);
+};
+
+// 取消点赞评论
+export const unlikeComment = (commentId) => {
+    return axios.post(`${BASE_URL}/unlike/${commentId}`);
+};
diff --git a/src/api/complain.js b/src/api/complain.js
new file mode 100644
index 0000000..8ac3e03
--- /dev/null
+++ b/src/api/complain.js
@@ -0,0 +1,80 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/complain';
+
+// 创建投诉
+export const createComplain = async (complainData) => {
+    try {
+        const response = await axios.post(`${BASE_URL}/create`, complainData);
+        return response.data;
+    } catch (error) {
+        console.error('创建投诉失败:', error);
+        throw error;
+    }
+};
+
+// 删除投诉(根据 complainid)
+export const deleteComplain = async (complainid) => {
+    try {
+        const response = await axios.delete(`${BASE_URL}/delete/${complainid}`);
+        return response.data;
+    } catch (error) {
+        console.error('删除投诉失败:', error);
+        throw error;
+    }
+};
+
+// 更新投诉
+export const updateComplain = async (complainData) => {
+    try {
+        const response = await axios.put(`${BASE_URL}/update`, complainData);
+        return response.data;
+    } catch (error) {
+        console.error('更新投诉失败:', error);
+        throw error;
+    }
+};
+
+// 获取某个被投诉用户的所有投诉记录(根据 duser)
+export const getComplainsByTargetUser = async (duser) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/target/${duser}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取被投诉用户的投诉记录失败:', error);
+        throw error;
+    }
+};
+
+// 获取某个投诉发起者的所有投诉记录(根据 puse)
+export const getComplainsByPostingUser = async (puse) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/from/${puse}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取用户提交的投诉记录失败:', error);
+        throw error;
+    }
+};
+
+// ✅ 获取所有投诉记录
+export const getAllComplains = async () => {
+    try {
+        const response = await axios.get(`${BASE_URL}/all`);
+        return response.data;
+    } catch (error) {
+        console.error('获取所有投诉记录失败:', error);
+        throw error;
+    }
+};
+
+// ✅ 根据投诉 ID 获取详情(包含投诉用户、被投诉用户、种子号等)
+export const getComplainDetailById = async (complainid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/detail/${complainid}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取投诉详情失败:', error);
+        throw error;
+    }
+};
diff --git a/src/api/friends.js b/src/api/friends.js
new file mode 100644
index 0000000..794e061
--- /dev/null
+++ b/src/api/friends.js
@@ -0,0 +1,39 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/friends';
+
+// 添加好友(发起好友请求)
+export const addFriend = (friendData) => {
+    return axios.post(`${BASE_URL}/add`, friendData);
+};
+
+// 同意好友申请
+export const acceptFriend = (friend1, friend2) => {
+    return axios.post(`${BASE_URL}/accept`, null, {
+        params: { friend1, friend2 }
+    });
+};
+
+// 拒绝好友申请(删除 pending 状态的好友关系)
+export const rejectFriend = (friend1, friend2) => {
+    return axios.delete(`${BASE_URL}/delete`, {
+        params: { friend1, friend2 }
+    });
+};
+
+// 删除好友
+export const deleteFriend = (friend1, friend2) => {
+    return axios.delete(`${BASE_URL}/delete`, {
+        params: { friend1, friend2 }
+    });
+};
+
+// 查询某用户所有已通过好友
+export const getFriendsByUserId = (userid) => {
+    return axios.get(`${BASE_URL}/list/${userid}`);
+};
+
+// 查询某用户收到的好友申请(pending 状态)
+export const getPendingRequests = (userid) => {
+    return axios.get(`${BASE_URL}/pending/${userid}`);
+};
diff --git a/src/api/post.js b/src/api/post.js
new file mode 100644
index 0000000..5891f99
--- /dev/null
+++ b/src/api/post.js
@@ -0,0 +1,128 @@
+const BASE_URL = 'http://localhost:8080/post';
+
+/**
+ * 创建帖子(带图片)
+ * @param {FormData} formData 包含 userid、post_title、post_content、tags、rannge、is_pinned、photo
+ */
+export const createPost = (formData) => {
+    return fetch(`${BASE_URL}/create`, {
+        method: 'POST',
+        body: formData,
+    }).then(res => res.json());
+};
+
+/**
+ * 切换置顶状态
+ * @param {number} postid 帖子 ID
+ */
+export const togglePinPost = (postid) => {
+    return fetch(`${BASE_URL}/togglePin/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 删除帖子
+ * @param {number} postid 帖子 ID
+ */
+export const deletePost = (postid) => {
+    return fetch(`${BASE_URL}/delete/${postid}`, {
+        method: 'DELETE',
+    }).then(res => res.json());
+};
+
+/**
+ * 更新帖子(JSON 格式)
+ * @param {Object} post 帖子对象
+ */
+export const updatePost = (post) => {
+    return fetch(`${BASE_URL}/update`, {
+        method: 'PUT',
+        headers: {
+            'Content-Type': 'application/json',
+        },
+        body: JSON.stringify(post),
+    }).then(res => res.json());
+};
+
+/**
+ * 关键词搜索帖子
+ * @param {string} keyword 搜索关键词
+ */
+export const searchPosts = (keyword) => {
+    return fetch(`${BASE_URL}/search?keyword=${encodeURIComponent(keyword)}`)
+        .then(res => res.json());
+};
+
+/**
+ * 点赞帖子
+ * @param {number} postid 帖子 ID
+ */
+export const likePost = (postid) => {
+    return fetch(`${BASE_URL}/like/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 取消点赞帖子
+ * @param {number} postid 帖子 ID
+ */
+export const unlikePost = (postid) => {
+    return fetch(`${BASE_URL}/unlike/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 置顶帖子
+ * @param {number} postid 帖子 ID
+ */
+export const pinPost = (postid) => {
+    return fetch(`${BASE_URL}/pin/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 取消置顶帖子
+ * @param {number} postid 帖子 ID
+ */
+export const unpinPost = (postid) => {
+    return fetch(`${BASE_URL}/unpin/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 获取某用户所有帖子
+ * @param {number} userid 用户 ID
+ */
+export const findPostsByUserId = (userid) => {
+    return fetch(`${BASE_URL}/findByUserid?userid=${userid}`)
+        .then(res => res.json());
+};
+
+/**
+ * 获取所有置顶帖子
+ */
+export const findPinnedPosts = () => {
+    return fetch(`${BASE_URL}/findPinned`)
+        .then(res => res.json());
+};
+
+/**
+ * 获取所有帖子(排序后)
+ */
+export const getAllPostsSorted = () => {
+    return fetch(`${BASE_URL}/all`)
+        .then(res => res.json());
+};
+
+/**
+ * 根据 postid 获取帖子详情(若你后期需要)
+ */
+export const getPostById = (postid) => {
+    return fetch(`${BASE_URL}/get/${postid}`)
+        .then(res => res.json());
+};
diff --git a/src/api/request.js b/src/api/request.js
new file mode 100644
index 0000000..26d57b9
--- /dev/null
+++ b/src/api/request.js
@@ -0,0 +1,123 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/request';
+
+// 创建求助帖(支持上传图片)
+export const createRequest = (formData) => {
+    return axios.post(`${BASE_URL}/create`, formData, {
+        headers: {
+            'Content-Type': 'multipart/form-data',
+        },
+    });
+};
+
+// 修改求助帖金额
+export const updateMoney = (requestid, money) => {
+    return axios.put(`${BASE_URL}/updateMoney/${requestid}`, null, {
+        params: { money },
+    });
+};
+
+// 根据名称批量更新被协助用户 ID
+export const updateLoaduserByName = (name, loaduser) => {
+    return axios.post(`${BASE_URL}/updateLoaduserByName`, null, {
+        params: { name, loaduser },
+    });
+};
+
+// ✅ 新增:根据 requestid 更新 torrentid
+export const updateTorrentid = (requestid, torrentid) => {
+    return axios.put(`${BASE_URL}/updateTorrentid/${requestid}`, null, {
+        params: { torrentid },
+    });
+};
+
+// ✅ 新增:根据 requestid 获取 torrentid
+export const getTorrentid = async (requestid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/getTorrentid/${requestid}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取 torrentid 失败', error);
+        return null;
+    }
+};
+
+// 删除求助帖
+export const deleteRequest = (requestid) => {
+    return axios.delete(`${BASE_URL}/delete/${requestid}`);
+};
+
+// 根据名称查找求助帖
+export const findByName = async (name) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/findByName`, {
+            params: { name },
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('按名称查找求助帖失败', error);
+        return [];
+    }
+};
+
+// 根据发帖用户 ID 查找求助帖
+export const findByUserid = async (userid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/findByUserid`, {
+            params: { userid },
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('按用户ID查找求助帖失败', error);
+        return [];
+    }
+};
+
+// 根据被协助用户 ID 查找求助帖
+export const findByLoaduser = async (loaduser) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/findByLoaduser`, {
+            params: { loaduser },
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('按被协助用户ID查找求助帖失败', error);
+        return [];
+    }
+};
+
+// 获取某名称的总金额
+export const getTotalMoneyByName = async (name) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/totalMoneyByName`, {
+            params: { name },
+        });
+        return typeof response.data === 'number' ? response.data : 0;
+    } catch (error) {
+        console.error('获取总金额失败', error);
+        return 0;
+    }
+};
+
+// 获取所有求助帖
+export const getAllRequests = async () => {
+    try {
+        const response = await axios.get(`${BASE_URL}/all`);
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('获取全部求助帖失败', error);
+        return [];
+    }
+};
+
+// ✅ 新增:根据 requestid 获取求助帖的部分信息(torrentid、money、loaduser)
+export const getInfoByRequestId = async (requestid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/info/${requestid}`);
+        return response.data || {};
+    } catch (error) {
+        console.error('获取求助帖信息失败', error);
+        return {};
+    }
+};
diff --git a/src/components/ActivityAdminPanel.jsx b/src/components/ActivityAdminPanel.jsx
new file mode 100644
index 0000000..5c0ce26
--- /dev/null
+++ b/src/components/ActivityAdminPanel.jsx
@@ -0,0 +1,269 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table, Button, Modal, Image, message, Tag,
+    Space, Input, Tooltip, Form, Upload
+} from 'antd';
+import {
+    ExclamationCircleOutlined, SearchOutlined, UploadOutlined
+} from '@ant-design/icons';
+import {
+    getAllActivities,
+    searchActivitiesByTitle,
+    deleteActivity,
+    createActivity,
+    updateActivity
+} from '../api/activity';
+
+const { confirm } = Modal;
+
+const ActivityAdminPanel = () => {
+    const [activities, setActivities] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const [keyword, setKeyword] = useState('');
+    const [modalVisible, setModalVisible] = useState(false);
+    const [editMode, setEditMode] = useState(false);
+    const [currentActivity, setCurrentActivity] = useState(null);
+    const [form] = Form.useForm();
+
+    const fetchActivities = async () => {
+        setLoading(true);
+        try {
+            const data = keyword.trim()
+                ? await searchActivitiesByTitle(keyword.trim())
+                : await getAllActivities();
+            setActivities(data.data || []);
+        } catch (error) {
+            message.error('获取公告失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchActivities();
+    }, []);
+
+    const handleSearch = () => {
+        fetchActivities();
+    };
+
+    const handleDelete = (activityid) => {
+        confirm({
+            title: '确认删除该公告吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk: async () => {
+                try {
+                    const res = await deleteActivity(activityid);
+                    if (res.data === true) {
+                        message.success('删除成功');
+                        fetchActivities();
+                    } else {
+                        message.error('删除失败');
+                    }
+                } catch {
+                    message.error('删除请求失败');
+                }
+            },
+        });
+    };
+
+    const openEditModal = (record) => {
+        setEditMode(true);
+        setCurrentActivity(record);
+        form.setFieldsValue({
+            activityid: record.activityid,
+            title: record.title,
+            content: record.content,
+            isShow: record.is_show,
+        });
+        setModalVisible(true);
+    };
+
+    const openCreateModal = () => {
+        setEditMode(false);
+        form.resetFields();
+        setModalVisible(true);
+    };
+
+    const handleModalOk = async () => {
+        try {
+            const values = await form.validateFields();
+            const formData = new FormData();
+            Object.keys(values).forEach(key => {
+                if (key !== 'photo' && values[key] !== undefined) {
+                    formData.append(key, values[key]);
+                }
+            });
+            if (values.photo && values.photo.file) {
+                formData.append('photo', values.photo.file);
+            }
+
+            const res = editMode
+                ? await updateActivity(formData)
+                : await createActivity(formData);
+
+            if (res.data === true) {
+                message.success(editMode ? '修改成功' : '创建成功');
+                setModalVisible(false);
+                fetchActivities();
+            } else {
+                message.error('提交失败');
+            }
+        } catch (error) {
+            message.error('提交失败,请检查表单');
+        }
+    };
+
+    const columns = [
+        {
+            title: 'ID',
+            dataIndex: 'activityid',
+            key: 'activityid',
+            width: 80,
+        },
+        {
+            title: '标题',
+            dataIndex: 'title',
+            key: 'title',
+            width: 200,
+            ellipsis: true,
+        },
+        {
+            title: '内容',
+            dataIndex: 'content',
+            key: 'content',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '图片',
+            dataIndex: 'photo',
+            key: 'photo',
+            width: 100,
+            render: (url) =>
+                url ? (
+                    <Image
+                        src={`http://localhost:8080${url}`}
+                        width={80}
+                        height={80}
+                        style={{ objectFit: 'cover' }}
+                    />
+                ) : (
+                    <Tag color="default">无</Tag>
+                ),
+        },
+        {
+            title: '展示状态',
+            dataIndex: 'is_show',
+            key: 'is_show',
+            width: 100,
+            render: (val) =>
+                val === 0 ? <Tag color="green">展示</Tag> : <Tag color="red">隐藏</Tag>,
+        },
+        {
+            title: '发布时间',
+            dataIndex: 'time',
+            key: 'time',
+            width: 180,
+            render: (time) =>
+                time ? new Date(time).toLocaleString() : <Tag color="default">暂无</Tag>,
+        },
+        {
+            title: '操作',
+            key: 'action',
+            width: 180,
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button type="primary" onClick={() => openEditModal(record)}>
+                        修改
+                    </Button>
+                    <Button danger onClick={() => handleDelete(record.activityid)}>
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>公告管理面板</h2>
+            <Space style={{ marginBottom: 16 }}>
+                <Input
+                    placeholder="请输入标题关键词"
+                    value={keyword}
+                    onChange={(e) => setKeyword(e.target.value)}
+                    style={{ width: 300 }}
+                />
+                <Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
+                    搜索
+                </Button>
+                <Button onClick={() => { setKeyword(''); fetchActivities(); }}>
+                    重置
+                </Button>
+                <Button type="primary" onClick={openCreateModal}>
+                    新建公告
+                </Button>
+            </Space>
+            <Table
+                rowKey="activityid"
+                columns={columns}
+                dataSource={activities}
+                loading={loading}
+                scroll={{ x: 1200 }}
+                pagination={{ pageSize: 8 }}
+                bordered
+                size="middle"
+            />
+
+            <Modal
+                title={editMode ? '修改公告' : '新建公告'}
+                open={modalVisible}
+                onOk={handleModalOk}
+                onCancel={() => setModalVisible(false)}
+                okText="提交"
+                cancelText="取消"
+                destroyOnClose
+            >
+                <Form form={form} layout="vertical" preserve={false}>
+                    {editMode && (
+                        <Form.Item name="activityid" hidden>
+                            <Input />
+                        </Form.Item>
+                    )}
+                    <Form.Item
+                        name="title"
+                        label="标题"
+                        rules={[{ required: true, message: '请输入标题' }]}
+                    >
+                        <Input />
+                    </Form.Item>
+                    <Form.Item
+                        name="content"
+                        label="内容"
+                        rules={[{ required: true, message: '请输入内容' }]}
+                    >
+                        <Input.TextArea rows={4} />
+                    </Form.Item>
+                    <Form.Item name="isShow" label="是否展示">
+                        <Input placeholder="0 表示展示,1 表示隐藏" />
+                    </Form.Item>
+                    <Form.Item name="photo" label="上传图片">
+                        <Upload beforeUpload={() => false} maxCount={1}>
+                            <Button icon={<UploadOutlined />}>选择文件</Button>
+                        </Upload>
+                    </Form.Item>
+                </Form>
+            </Modal>
+        </div>
+    );
+};
+
+export default ActivityAdminPanel;
diff --git a/src/components/ActivityBoard.css b/src/components/ActivityBoard.css
new file mode 100644
index 0000000..7cb11d7
--- /dev/null
+++ b/src/components/ActivityBoard.css
@@ -0,0 +1,38 @@
+/* src/components/ActivityBoard.css */
+
+.activity-card {
+    border-radius: 12px;
+    overflow: hidden;
+    transition: all 0.3s ease;
+}
+
+.activity-card:hover {
+    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
+    transform: translateY(-4px);
+}
+
+.activity-photo {
+    height: 180px;
+    width: 100%;
+    object-fit: cover;
+    border-radius: 8px 8px 0 0;
+    transition: transform 0.2s ease;
+    cursor: pointer;
+}
+
+.activity-photo:hover {
+    transform: scale(1.03);
+}
+
+.activity-title {
+    font-weight: 600;
+    font-size: 16px;
+    margin: 8px 0;
+    color: #1a1a1a;
+}
+
+.loading-container {
+    display: flex;
+    justify-content: center;
+    padding: 50px 0;
+}
\ No newline at end of file
diff --git a/src/components/ActivityBoard.jsx b/src/components/ActivityBoard.jsx
new file mode 100644
index 0000000..4cbfb52
--- /dev/null
+++ b/src/components/ActivityBoard.jsx
@@ -0,0 +1,98 @@
+// src/components/ActivityBoard.jsx
+import React, { useEffect, useState } from 'react';
+import { Card, Row, Col, Typography, Spin, message, Modal } from 'antd';
+import { getFullActivities } from '../api/activity';
+import './ActivityBoard.css';
+
+const { Paragraph, Text } = Typography;
+
+const ActivityBoard = () => {
+    const [activities, setActivities] = useState([]);
+    const [loading, setLoading] = useState(true);
+    const [modalVisible, setModalVisible] = useState(false);
+    const [selectedActivity, setSelectedActivity] = useState(null);
+
+    useEffect(() => {
+        getFullActivities()
+            .then((res) => {
+                setActivities(res.data);
+                setLoading(false);
+            })
+            .catch(() => {
+                message.error('获取公告失败');
+                setLoading(false);
+            });
+    }, []);
+
+    const showModal = (activity) => {
+        setSelectedActivity(activity);
+        setModalVisible(true);
+    };
+
+    const handleClose = () => {
+        setModalVisible(false);
+        setSelectedActivity(null);
+    };
+
+    return (
+        <>
+            {loading ? (
+                <div className="loading-container">
+                    <Spin size="large" />
+                </div>
+            ) : (
+                <Row gutter={[24, 24]}>
+                    {activities.map((activity) => (
+                        <Col xs={24} sm={12} md={8} lg={6} key={activity.activityid}>
+                            <Card
+                                hoverable
+                                className="activity-card"
+                                cover={
+                                    <img
+                                        alt="活动图片"
+                                        src={`http://localhost:8080${activity.photo}`}
+                                        className="activity-photo"
+                                        onClick={() => showModal(activity)}
+                                    />
+                                }
+                            >
+                                <Card.Meta
+                                    title={<div className="activity-title">{activity.title}</div>}
+                                />
+                            </Card>
+                        </Col>
+                    ))}
+                </Row>
+            )}
+
+            {/* 弹窗展示公告详情 */}
+            <Modal
+                open={modalVisible}
+                title={selectedActivity?.title}
+                footer={null}
+                onCancel={handleClose}
+                centered
+                width={700}
+                bodyStyle={{ padding: '24px', maxHeight: '80vh', overflowY: 'auto' }}
+            >
+                {selectedActivity && (
+                    <div>
+                        {selectedActivity.photo && (
+                            <img
+                                src={`http://localhost:8080${selectedActivity.photo}`}
+                                alt="公告图片"
+                                style={{ width: '100%', maxHeight: 400, objectFit: 'cover', borderRadius: 8, marginBottom: 20 }}
+                            />
+                        )}
+                        <Paragraph style={{ fontSize: 16 }}>{selectedActivity.content}</Paragraph>
+                        <Text type="secondary">
+                            发布时间:{new Date(selectedActivity.time).toLocaleString()}
+                        </Text>
+                    </div>
+                )}
+            </Modal>
+        </>
+    );
+};
+
+export default ActivityBoard;
diff --git a/src/components/ChatBox.jsx b/src/components/ChatBox.jsx
new file mode 100644
index 0000000..2efbfc8
--- /dev/null
+++ b/src/components/ChatBox.jsx
@@ -0,0 +1,202 @@
+import React, { useEffect, useState, useRef } from 'react';
+import { Input, Button, Avatar, Typography, List, Popover, message as antdMessage } from 'antd';
+import { SendOutlined, SmileOutlined } from '@ant-design/icons';
+import { getChatsBetweenUsers, createChat } from '../api/chat';
+import axios from 'axios';
+import './chat.css';
+
+const { Text } = Typography;
+const { TextArea } = Input;
+
+// 完整表情数组
+const emojis = [
+  "😀", "😃", "😄", "😁", "😆", "😅", "😂", "🤣", "😊", "😇",
+  "🙂", "🙃", "😉", "😌", "😍", "🥰", "😘", "😗", "😙", "😚",
+  "😋", "😛", "😝", "😜", "🤪", "🤨", "🧐", "🤓", "😎", "🤩",
+  "🥳", "😏", "😒", "😞", "😔", "😟", "😕", "🙁", "☹️", "😣",
+  "😖", "😫", "😩", "🥺", "😢", "😭", "😤", "😠", "😡", "🤬",
+  "🤯", "😳", "🥵", "🥶", "😱", "😨", "😰", "😥", "😓", "🤗",
+  "🤔", "🤭", "🤫", "🤥", "😶", "😐", "😑", "😬", "🙄", "😯",
+  "😦", "😧", "😮", "😲", "🥱", "😴", "🤤", "😪", "😵", "🤐",
+  "🥴", "🤢", "🤮", "🤧", "😷", "🤒", "🤕", "🤑", "🤠", "😈",
+  "👿", "👹", "👺", "🤡", "💩", "👻", "💀", "☠️", "👽", "👾",
+  "🤖", "🎃", "😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿",
+  "😾", "👋", "🤚", "🖐", "✋", "🖖", "👌", "🤏", "✌️", "🤞",
+  "🤟", "🤘", "🤙", "👈", "👉", "👆", "🖕", "👇", "☝️", "👍",
+  "👎", "✊", "👊", "🤛", "🤜", "👏", "🙌", "👐", "🤲", "🤝",
+  "🙏", "✍️", "💅", "🤳", "💪", "🦾", "🦵", "🦿", "🦶", "👂",
+  "🦻", "👃", "🧠", "🦷", "🦴", "👀", "👁", "👅", "👄", "💋",
+  "🩸", "💘", "💝", "💖", "💗", "💓", "💞", "💕", "💟", "❣️",
+  "💔", "❤️", "🧡", "💛", "💚", "💙", "💜", "🤎", "🖤", "🤍",
+  "💯", "💢", "💥", "💫", "💦", "💨", "🕳", "💣", "💬", "👁️‍🗨️",
+  "🗨", "🗯", "💭", "💤", "👋", "🤚", "🖐", "✋", "🖖", "👌"
+];
+
+const ChatBox = ({ senderId, receiverId }) => {
+  const [messages, setMessages] = useState([]);
+  const [input, setInput] = useState('');
+  const [showEmojis, setShowEmojis] = useState(false);
+  const messagesEndRef = useRef(null);
+  const inputRef = useRef(null);
+  const [loading, setLoading] = useState(false);
+  const [cursorPosition, setCursorPosition] = useState(0);
+  const [users, setUsers] = useState({}); // {id: {username, avatar}}
+
+  const formatTime = timeStr => new Date(timeStr).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+
+  const fetchUserInfo = async (id) => {
+    if (!id || users[id]) return;
+    try {
+      const res = await axios.get(`http://localhost:8080/user/getDecoration?userid=${id}`);
+      const info = res.data.data;
+      setUsers(u => ({ ...u, [id]: { username: info.username, avatar: info.image } }));
+    } catch (e) {
+      console.error('获取用户信息失败', e);
+      setUsers(u => ({ ...u, [id]: { username: `用户${id}`, avatar: null } }));
+    }
+  };
+
+  const fetchMessages = async () => {
+    if (!senderId || !receiverId) return;
+    try {
+      await fetchUserInfo(senderId);
+      await fetchUserInfo(receiverId);
+      const data = await getChatsBetweenUsers(senderId, receiverId);
+      setMessages(data.sort((a, b) => new Date(a.talkTime) - new Date(b.talkTime)));
+    } catch {
+      antdMessage.error('加载聊天记录失败');
+    }
+  };
+
+  useEffect(fetchMessages, [senderId, receiverId]);
+
+  useEffect(() => {
+    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
+  }, [messages]);
+
+  const handleSend = async () => {
+    const trimmed = input.trim();
+    if (!trimmed) return;
+    setLoading(true);
+    const newChat = { senderId, receiverId, content: trimmed, talkTime: new Date().toISOString() };
+    try {
+      await createChat(newChat);
+      setInput('');
+      fetchMessages();
+    } catch {
+      antdMessage.error('发送失败,请重试');
+    }
+    setLoading(false);
+  };
+
+  const handleKeyDown = e => {
+    if (e.key === 'Enter' && !e.shiftKey) {
+      e.preventDefault();
+      handleSend();
+    }
+  };
+
+  const handleEmojiInsert = emoji => {
+    const start = input.slice(0, cursorPosition);
+    const end = input.slice(cursorPosition);
+    const newText = start + emoji + end;
+    setInput(newText);
+    setShowEmojis(false);
+    setTimeout(() => {
+      const pos = start.length + emoji.length;
+      inputRef.current.focus();
+      inputRef.current.setSelectionRange(pos, pos);
+      setCursorPosition(pos);
+    }, 0);
+  };
+
+  const handleInputSelection = () => inputRef.current && setCursorPosition(inputRef.current.selectionStart);
+
+  const renderEmojiPicker = () => (
+    <div className="emoji-picker">
+      {emojis.map((e, i) => (
+        <span key={i} className="emoji-item" onClick={() => handleEmojiInsert(e)}>
+          {e}
+        </span>
+      ))}
+    </div>
+  );
+
+  return (
+    <div className="chatbox-container">
+      <div className="chatbox-header">
+        <Text strong style={{ fontSize: 20 }}>
+          🟢 Chat with {users[receiverId]?.username || receiverId}
+        </Text>
+      </div>
+
+      <div className="chatbox-content">
+        {messages.length === 0 ? (
+          <div className="no-messages">暂无聊天记录</div>
+        ) : (
+          <List
+            dataSource={messages}
+            renderItem={msg => {
+              const isSender = msg.senderId === senderId;
+              const otherId = isSender ? senderId : receiverId;
+              const user = users[otherId] || {};
+              const avatarContent = user.avatar ? (
+                <Avatar src={user.avatar} className="avatar" />
+              ) : (
+                <Avatar className="avatar">{String(otherId).slice(-2)}</Avatar>
+              );
+              return (
+                <List.Item key={msg.informationid} className={`chat-message ${isSender ? 'sender' : 'receiver'}`}>
+                  {!isSender && avatarContent}
+                  <div className="message-bubble-wrapper">
+                    <div className="message-bubble">
+                      <Text>{msg.content}</Text>
+                      <div className="message-time">{formatTime(msg.talkTime)}</div>
+                    </div>
+                  </div>
+                  {isSender && avatarContent}
+                </List.Item>
+              );
+            }}
+          />
+        )}
+        <div ref={messagesEndRef} />
+      </div>
+
+      <div className="chatbox-footer">
+        <Popover
+          content={renderEmojiPicker()}
+          title="选择表情"
+          trigger="click"
+          open={showEmojis}
+          onOpenChange={setShowEmojis}
+          placement="topLeft"
+          overlayClassName="emoji-popover"
+          arrow={false}
+        >
+          <Button icon={<SmileOutlined />} type="text" className="emoji-btn" />
+        </Popover>
+        <TextArea
+          ref={inputRef}
+          value={input}
+          onChange={e => { setInput(e.target.value); setCursorPosition(e.target.selectionStart); }}
+          onClick={handleInputSelection}
+          onSelect={handleInputSelection}
+          onKeyUp={handleInputSelection}
+          onKeyDown={handleKeyDown}
+          placeholder="输入消息,Enter发送,Shift+Enter换行"
+          autoSize={{ minRows: 2, maxRows: 6 }}
+          disabled={loading}
+          maxLength={500}
+          showCount
+          className="chat-input"
+        />
+        <Button type="primary" icon={<SendOutlined />} onClick={handleSend} loading={loading} disabled={!input.trim()} className="send-btn">
+          发送
+        </Button>
+      </div>
+    </div>
+  );
+};
+
+export default ChatBox;
\ No newline at end of file
diff --git a/src/components/Comment.css b/src/components/Comment.css
new file mode 100644
index 0000000..e5529d3
--- /dev/null
+++ b/src/components/Comment.css
@@ -0,0 +1,128 @@
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
+
+.comment-card {
+    max-width: 700px;
+    margin: 20px auto;
+    border-radius: 8px;
+    box-shadow: 0 4px 12px rgb(0 0 0 / 0.1);
+    background: #fff;
+    padding: 16px;
+}
+
+.comment-textarea {
+    border-radius: 6px;
+    resize: none;
+    font-size: 16px;
+}
+
+.text-right {
+    text-align: right;
+}
+
+.mt-2 {
+    margin-top: 0.5rem;
+}
+
+.mt-6 {
+    margin-top: 1.5rem;
+}
+
+.comment-time {
+    font-size: 12px;
+    color: #888;
+    margin-left: 8px;
+    white-space: nowrap;
+}
+
+.comment-username {
+    font-weight: 600;
+    color: #1890ff;
+    user-select: none;
+}
+
+.comment-content {
+    font-size: 14px;
+    line-height: 1.5;
+    color: #333;
+    white-space: pre-wrap;
+}
+
+/* 头像带蓝色边框 */
+.avatar-with-border {
+    border: 2px solid #1890ff !important;
+    border-radius: 50% !important;
+}
+
+
+
+body {
+    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+    background-color: #fffaf5;
+}
+
+/* 全局动画效果 */
+.transition {
+    transition: all 0.3s ease;
+}
+
+/* 卡片阴影效果 */
+.shadow-lg {
+    box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
+}
+
+.shadow-md {
+    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+}
+
+/* 圆角 */
+.rounded-xl {
+    border-radius: 1rem;
+}
+
+.rounded-lg {
+    border-radius: 0.75rem;
+}
+
+/* 渐变背景 */
+.bg-gradient-to-r {
+    background-size: 200% auto;
+    transition: background-position 0.5s ease;
+}
+
+.bg-gradient-to-r:hover {
+    background-position: right center;
+}
+
+/* 表单输入框动画 */
+input:focus,
+textarea:focus {
+    transform: translateY(-1px);
+}
+
+/* 卡片悬停效果 */
+.bg-white:hover {
+    transform: translateY(-3px);
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+    .text-xl {
+        font-size: 1.25rem;
+    }
+
+    .text-2xl {
+        font-size: 1.5rem;
+    }
+
+    .p-6 {
+        padding: 1.25rem;
+    }
+
+    .p-12 {
+        padding: 2rem;
+    }
+
+    .grid-cols-2 {
+        grid-template-columns: 1fr;
+    }
+}
\ No newline at end of file
diff --git a/src/components/Comment.jsx b/src/components/Comment.jsx
new file mode 100644
index 0000000..704636e
--- /dev/null
+++ b/src/components/Comment.jsx
@@ -0,0 +1,290 @@
+import React, { useState, useEffect } from 'react';
+import {
+    getCommentsByPostId,
+    createComment,
+    deleteComment,
+    likeComment,
+    unlikeComment,
+} from '../api/comment';
+
+import {
+    Card,
+    Button,
+    Input,
+    List,
+    Avatar,
+    Popconfirm,
+    message,
+    Space,
+    Tooltip
+} from 'antd';
+
+import {
+    LikeOutlined,
+    LikeFilled,
+    DeleteOutlined
+} from '@ant-design/icons';
+
+import axios from 'axios';
+import './Comment.css';
+
+const { TextArea } = Input;
+
+const Comment = ({ postId, currentUser }) => {
+    const [comments, setComments] = useState([]);
+    const [newContent, setNewContent] = useState('');
+    const [loading, setLoading] = useState(false);
+    const [userInfoMap, setUserInfoMap] = useState({});
+    const [isCommenting, setIsCommenting] = useState(false);
+
+    useEffect(() => {
+        loadComments();
+    }, [postId, currentUser]);
+
+    const loadComments = async () => {
+        try {
+            if (!postId) return;
+
+            const commentList = await getCommentsByPostId(postId);
+            setComments(commentList);
+
+            // 修复1: 统一使用 userid 而不是 id
+            const userIds = [
+                ...new Set(commentList.map(c => c.userid))
+            ];
+
+            // 如果当前用户存在,添加其 userid
+            if (currentUser && currentUser.userid) {
+                userIds.push(currentUser.userid);
+            }
+
+            // 批量获取用户信息
+            const userInfoPromises = userIds.map(async (id) => {
+                try {
+                    const res = await axios.get(`http://localhost:8080/user/getDecoration?userid=${id}`);
+                    if (res.data?.success) {
+                        return { id, data: res.data.data };
+                    }
+                    return { id, data: { username: `用户${id}`, image: '' } };
+                } catch (error) {
+                    return { id, data: { username: `用户${id}`, image: '' } };
+                }
+            });
+
+            const userInfoResults = await Promise.all(userInfoPromises);
+
+            // 构建用户信息映射
+            const newUserInfoMap = {};
+            userInfoResults.forEach(({ id, data }) => {
+                newUserInfoMap[id] = data;
+            });
+
+            setUserInfoMap(newUserInfoMap);
+
+        } catch (error) {
+            console.error('加载评论失败:', error);
+            message.error('加载评论失败');
+        }
+    };
+
+    const handleCreate = async () => {
+        // 检查用户是否登录
+        if (!currentUser) {
+            message.error('请先登录后再评论');
+            return;
+        }
+
+        // 修复2: 确保当前用户有 userid 属性
+        if (!currentUser.userid) {
+            message.error('用户信息异常,请重新登录');
+            return;
+        }
+
+        if (!newContent.trim()) {
+            message.warning('评论内容不能为空');
+            return;
+        }
+
+        setIsCommenting(true);
+        setLoading(true);
+
+        // 修复3: 使用 currentUser.userid 而非 currentUser.id
+        const commentData = {
+            postid: postId,
+            userid: Number(currentUser.userid),
+            postCommentcontent: newContent,
+            commenttime: new Date().toISOString()
+        };
+
+        try {
+            await createComment(commentData);
+            setNewContent('');
+            await loadComments(); // 重新加载评论,确保新评论显示
+            message.success('评论发布成功');
+        } catch (error) {
+            console.error('发布评论失败:', error);
+            message.error('发布评论失败');
+        } finally {
+            setLoading(false);
+            setIsCommenting(false);
+        }
+    };
+
+    const handleDelete = async (commentid) => {
+        try {
+            await deleteComment(commentid);
+            message.success('删除成功');
+            loadComments();
+        } catch (error) {
+            console.error('删除评论失败:', error);
+            message.error('删除失败');
+        }
+    };
+
+    const handleLike = async (commentid) => {
+        try {
+            await likeComment(commentid);
+            loadComments();
+        } catch (error) {
+            console.error('点赞失败:', error);
+            message.error('操作失败');
+        }
+    };
+
+    const handleUnlike = async (commentid) => {
+        try {
+            await unlikeComment(commentid);
+            loadComments();
+        } catch (error) {
+            console.error('取消点赞失败:', error);
+            message.error('操作失败');
+        }
+    };
+
+    // 获取用户信息(包括当前登录用户)
+    const getUserInfo = (userId) => {
+        // 修复4: 使用 currentUser.userid 而非 currentUser.id
+        if (currentUser && currentUser.userid && userId === currentUser.userid) {
+            return {
+                username: currentUser.username || `用户${userId}`,
+                image: currentUser.image || '',
+                decoration: currentUser.decoration || ''
+            };
+        }
+
+        // 对于其他用户,从userInfoMap中获取
+        return userInfoMap[userId] || {
+            username: `用户${userId}`,
+            image: '',
+            decoration: ''
+        };
+    };
+
+    return (
+        <Card title="评论区" bordered={false} className="comment-card">
+            {/* 评论输入框 - 根据用户登录状态调整 */}
+            {currentUser ? (
+                <>
+                    <TextArea
+                        rows={3}
+                        placeholder={`${currentUser.username},留下你的评论...`}
+                        value={newContent}
+                        onChange={(e) => setNewContent(e.target.value)}
+                        className="comment-textarea"
+                        disabled={loading}
+                    />
+                    <div className="text-right mt-2">
+                        <Button
+                            type="primary"
+                            onClick={handleCreate}
+                            loading={loading || isCommenting}
+                            disabled={isCommenting}
+                        >
+                            {isCommenting ? '发布中...' : '发布评论'}
+                        </Button>
+                    </div>
+                </>
+            ) : (
+                <div className="login-prompt">
+                    请<a href="/login" className="login-link">登录</a>后发表评论
+                </div>
+            )}
+
+            {/* 评论列表 */}
+            <List
+                itemLayout="vertical"
+                dataSource={comments}
+                locale={{ emptyText: '暂无评论' }}
+                className="mt-6"
+                renderItem={(item) => {
+                    const user = getUserInfo(item.userid);
+                    // 修复5: 使用 userid 而非 id 比较当前用户
+                    const isCurrentUser = currentUser && currentUser.userid === item.userid;
+
+                    return (
+                        <List.Item
+                            key={item.commentid}
+                            className={isCurrentUser ? "current-user-comment" : ""}
+                            actions={[
+                                <Tooltip title="点赞" key="like">
+                                    <Space>
+                                        <Button
+                                            icon={<LikeOutlined />}
+                                            size="small"
+                                            onClick={() => handleLike(item.commentid)}
+                                        />
+                                        {item.likes}
+                                    </Space>
+                                </Tooltip>,
+                                <Tooltip title="取消点赞" key="unlike">
+                                    <Button
+                                        icon={<LikeFilled style={{ color: '#fadb14' }} />}
+                                        size="small"
+                                        onClick={() => handleUnlike(item.commentid)}
+                                    />
+                                </Tooltip>,
+                                isCurrentUser && (
+                                    <Popconfirm
+                                        title="确定要删除这条评论吗?"
+                                        onConfirm={() => handleDelete(item.commentid)}
+                                        okText="删除"
+                                        cancelText="取消"
+                                        key="delete"
+                                    >
+                                        <Button icon={<DeleteOutlined />} size="small" danger />
+                                    </Popconfirm>
+                                )
+                            ]}
+                            extra={
+                                <div className="comment-time">
+                                    {new Date(item.commenttime).toLocaleString()}
+                                </div>
+                            }
+                        >
+                            <List.Item.Meta
+                                avatar={
+                                    <Avatar
+                                        src={user.image || undefined}
+                                        alt={user.username}
+                                        className="comment-avatar"
+                                    >
+                                        {!user.image && user.username ? user.username.charAt(0).toUpperCase() : ''}
+                                    </Avatar>
+                                }
+                                title={
+                                    <span className="comment-username">
+                                        {user.username || `用户${item.userid}`}
+                                        {isCurrentUser && <span className="current-user-tag">(我)</span>}
+                                    </span>
+                                }
+                                description={<div className="comment-content">{item.postCommentcontent}</div>}
+                            />
+                        </List.Item>
+                    );
+                }}
+            />
+        </Card>
+    );
+};
+
+export default Comment;
\ No newline at end of file
diff --git a/src/components/ComplainAdminPanel.jsx b/src/components/ComplainAdminPanel.jsx
new file mode 100644
index 0000000..a7985be
--- /dev/null
+++ b/src/components/ComplainAdminPanel.jsx
@@ -0,0 +1,149 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table,
+    Button,
+    Modal,
+    message,
+    Tag,
+    Space,
+    Tooltip,
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import {
+    getAllComplains,
+    deleteComplain,
+    // 预留:你后续可以新增处理投诉的API
+} from '../api/complain';
+import { useNavigate } from 'react-router-dom';
+
+const { confirm } = Modal;
+
+const ComplainAdminPanel = () => {
+    const [complains, setComplains] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const navigate = useNavigate();
+
+    const fetchComplains = async () => {
+        setLoading(true);
+        try {
+            const data = await getAllComplains();
+            setComplains(data);
+        } catch (error) {
+            message.error('获取投诉记录失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchComplains();
+    }, []);
+
+    const showDeleteConfirm = (complainid) => {
+        confirm({
+            title: '确认删除该投诉记录吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk() {
+                handleDelete(complainid);
+            },
+        });
+    };
+
+    const handleDelete = async (complainid) => {
+        try {
+            const success = await deleteComplain(complainid);
+            if (success) {
+                message.success('删除成功');
+                fetchComplains();
+            } else {
+                message.error('删除失败');
+            }
+        } catch {
+            message.error('删除请求失败');
+        }
+    };
+
+    const handleProcess = (complain) => {
+        const { complainid, duser, torrentid } = complain;
+        navigate(`/complain-process/${complainid}`, {
+            state: { complainid, duser, torrentid },
+        });
+    };
+
+    const columns = [
+        {
+            title: '投诉ID',
+            dataIndex: 'complainid',
+            key: 'complainid',
+            width: 80,
+            fixed: 'left',
+        },
+        {
+            title: '投诉人ID',
+            dataIndex: 'puse',
+            key: 'puse',
+            width: 120,
+        },
+        {
+            title: '被投诉人ID',
+            dataIndex: 'duser',
+            key: 'duser',
+            width: 120,
+        },
+        {
+            title: '投诉内容',
+            dataIndex: 'content',
+            key: 'content',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '相关种子ID',
+            dataIndex: 'torrentid',
+            key: 'torrentid',
+            width: 120,
+            render: (val) => val ?? <Tag color="default">无</Tag>,
+        },
+        {
+            title: '操作',
+            key: 'action',
+            fixed: 'right',
+            width: 150,
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button type="primary" onClick={() => handleProcess(record)}>
+                        处理
+                    </Button>
+                    <Button danger onClick={() => showDeleteConfirm(record.complainid)}>
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>投诉管理面板</h2>
+            <Table
+                rowKey="complainid"
+                columns={columns}
+                dataSource={complains}
+                loading={loading}
+                scroll={{ x: 1000 }}
+                pagination={{ pageSize: 10 }}
+                bordered
+                size="middle"
+            />
+        </div>
+    );
+};
+
+export default ComplainAdminPanel;
diff --git a/src/components/FriendManager.css b/src/components/FriendManager.css
new file mode 100644
index 0000000..97cf2a9
--- /dev/null
+++ b/src/components/FriendManager.css
@@ -0,0 +1,155 @@
+/* FriendManager.css */
+
+.friend-manager-container {
+    max-width: 800px;
+    margin: 20px auto;
+    padding: 0 15px;
+}
+
+.friend-card {
+    border-radius: 10px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+}
+
+.friend-header {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+}
+
+.header-icon {
+    font-size: 24px;
+    color: #1890ff;
+    margin-right: 12px;
+}
+
+.header-title {
+    margin: 0 !important;
+}
+
+.search-section {
+    display: flex;
+    margin-bottom: 24px;
+    gap: 12px;
+}
+
+.search-input {
+    flex: 1;
+    border-radius: 20px;
+    padding: 10px 16px;
+}
+
+.search-button {
+    border-radius: 20px;
+    padding: 0 24px;
+    height: 40px;
+}
+
+.search-results-container {
+    margin-bottom: 24px;
+    background: #fafafa;
+    border-radius: 8px;
+    padding: 16px;
+    border: 1px solid #f0f0f0;
+}
+
+.results-title {
+    margin-bottom: 16px !important;
+    color: #333;
+}
+
+.user-item {
+    padding: 12px;
+    border-radius: 8px;
+    transition: all 0.3s;
+    cursor: pointer;
+}
+
+.user-item:hover {
+    background-color: #f5f7fa;
+}
+
+.user-avatar {
+    background-color: #1890ff;
+}
+
+.add-friend-button {
+    border-radius: 16px;
+}
+
+.section-title {
+    margin-bottom: 16px !important;
+    color: #333;
+    position: relative;
+    padding-left: 10px;
+}
+
+.section-title::before {
+    content: '';
+    position: absolute;
+    left: 0;
+    top: 5px;
+    height: 20px;
+    width: 4px;
+    background-color: #1890ff;
+    border-radius: 2px;
+}
+
+.request-item,
+.friend-item {
+    padding: 12px 16px;
+    border-radius: 8px;
+    margin-bottom: 8px;
+    border: 1px solid #f0f0f0;
+    transition: all 0.3s;
+}
+
+.request-item:hover,
+.friend-item:hover {
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transform: translateY(-2px);
+    border-color: #d0e0ff;
+}
+
+.accept-button {
+    background-color: #52c41a;
+    border-color: #52c41a;
+}
+
+.reject-button {
+    background-color: #f5222d;
+    border-color: #f5222d;
+    color: white;
+}
+
+.delete-button {
+    border-radius: 16px;
+}
+
+.friend-list-section {
+    margin-top: 24px;
+}
+
+.friend-list-header {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 16px;
+}
+
+.refresh-button {
+    color: #1890ff;
+}
+
+@media (max-width: 768px) {
+    .search-section {
+        flex-direction: column;
+    }
+
+    .search-button {
+        width: 100%;
+    }
+
+    .friend-card {
+        padding: 16px;
+    }
+}
\ No newline at end of file
diff --git a/src/components/FriendManager.jsx b/src/components/FriendManager.jsx
new file mode 100644
index 0000000..374ac83
--- /dev/null
+++ b/src/components/FriendManager.jsx
@@ -0,0 +1,359 @@
+import React, { useState, useEffect } from 'react';
+import {
+    Input,
+    Button,
+    List,
+    Typography,
+    Space,
+    Spin,
+    Popconfirm,
+    message,
+    Divider,
+    Avatar,
+} from 'antd';
+import {
+    UserAddOutlined,
+    DeleteOutlined,
+    ReloadOutlined,
+    CheckOutlined,
+    CloseOutlined,
+} from '@ant-design/icons';
+import {
+    addFriend,
+    deleteFriend,
+    getFriendsByUserId,
+    getPendingRequests,
+    acceptFriend,
+    rejectFriend,
+} from '../api/friends';
+import axios from 'axios';
+
+const { Title, Text } = Typography;
+
+const FriendManager = ({ currentUser, onSelectRelation }) => {
+    const currentUserId = currentUser?.userid;
+
+    const [friendName, setFriendName] = useState('');
+    const [friends, setFriends] = useState([]);
+    const [pendingRequests, setPendingRequests] = useState([]);
+    const [userInfoMap, setUserInfoMap] = useState({});
+    const [loading, setLoading] = useState(false);
+    const [refreshing, setRefreshing] = useState(false);
+    const [pendingLoading, setPendingLoading] = useState(false);
+
+    useEffect(() => {
+        if (currentUserId) {
+            refreshData();
+        }
+    }, [currentUserId]);
+
+    const refreshData = () => {
+        loadFriends(currentUserId);
+        loadPendingRequests(currentUserId);
+    };
+
+    const fetchUserInfo = async (userId) => {
+        if (userInfoMap[userId]) return;
+        try {
+            const res = await axios.get(`http://localhost:8080/user/getDecoration?userid=${userId}`);
+            const info = res.data?.data;
+            if (info) {
+                setUserInfoMap((prev) => ({
+                    ...prev,
+                    [userId]: {
+                        username: info.username,
+                        avatar: info.image,
+                    },
+                }));
+            }
+        } catch {
+            setUserInfoMap((prev) => ({
+                ...prev,
+                [userId]: {
+                    username: `用户${userId}`,
+                    avatar: null,
+                },
+            }));
+        }
+    };
+
+    const loadFriends = async (userId) => {
+        setRefreshing(true);
+        try {
+            const res = await getFriendsByUserId(userId);
+            const list = res.data || [];
+            setFriends(list);
+            list.forEach(f => fetchUserInfo(getFriendUserId(f)));
+        } catch {
+            message.error('加载好友失败,请稍后重试');
+        }
+        setRefreshing(false);
+    };
+
+    const loadPendingRequests = async (userId) => {
+        setPendingLoading(true);
+        try {
+            const res = await getPendingRequests(userId);
+            const list = res.data || [];
+            setPendingRequests(list);
+            list.forEach(req => {
+                const otherId = req.friend1 === currentUserId ? req.friend2 : req.friend1;
+                fetchUserInfo(otherId);
+            });
+        } catch {
+            message.error('加载好友申请失败');
+        }
+        setPendingLoading(false);
+    };
+
+    const handleAddFriend = async () => {
+        if (!friendName.trim()) return message.warning('请输入好友用户名');
+
+        setLoading(true);
+        try {
+            const res = await axios.get(`http://localhost:8080/user/getUserid?username=${friendName.trim()}`);
+            const newFriendId = res.data?.data;
+            if (!newFriendId) {
+                message.error('未找到该用户名对应的用户');
+                setLoading(false);
+                return;
+            }
+
+            if (newFriendId === currentUserId) {
+                message.warning('不能添加自己为好友');
+                setLoading(false);
+                return;
+            }
+
+            const isAlreadyFriend = friends.some(f =>
+                (f.friend1 === currentUserId && f.friend2 === newFriendId) ||
+                (f.friend1 === newFriendId && f.friend2 === currentUserId)
+            );
+            if (isAlreadyFriend) {
+                message.warning('该用户已是您的好友');
+                setLoading(false);
+                return;
+            }
+
+            const result = await addFriend({ friend1: currentUserId, friend2: newFriendId });
+            if (result.data) {
+                message.success('好友请求已发送');
+                setFriendName('');
+                loadPendingRequests(currentUserId);
+            } else {
+                message.error('添加失败');
+            }
+        } catch {
+            message.error('添加好友失败,请稍后重试');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    const handleDelete = async (friend1, friend2) => {
+        setLoading(true);
+        try {
+            const res = await deleteFriend(friend1, friend2);
+            if (res.data) {
+                message.success('删除成功');
+                loadFriends(currentUserId);
+            } else {
+                message.error('删除失败');
+            }
+        } catch {
+            message.error('删除好友失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    const handleAccept = async (friend1, friend2) => {
+        setPendingLoading(true);
+        try {
+            const res = await acceptFriend(friend1, friend2);
+            if (res.data) {
+                message.success('已同意好友请求');
+                refreshData();
+            } else {
+                message.error('操作失败');
+            }
+        } catch {
+            message.error('同意失败');
+        } finally {
+            setPendingLoading(false);
+        }
+    };
+
+    const handleReject = async (friend1, friend2) => {
+        setPendingLoading(true);
+        try {
+            const res = await rejectFriend(friend1, friend2);
+            if (res.data) {
+                message.info('已拒绝好友请求');
+                loadPendingRequests(currentUserId);
+            } else {
+                message.error('操作失败');
+            }
+        } catch {
+            message.error('拒绝失败');
+        } finally {
+            setPendingLoading(false);
+        }
+    };
+
+    const getFriendUserId = (f) => f.friend1 === currentUserId ? f.friend2 : f.friend1;
+
+    const renderUserMeta = (userId, timeLabel) => {
+        const user = userInfoMap[userId] || {};
+        return {
+            avatar: <Avatar src={user.avatar} />,
+            title: user.username ? `${user.username}(ID: ${userId})` : `用户ID:${userId}`,
+            description: timeLabel,
+        };
+    };
+
+    return (
+        <div style={{ maxWidth: 700, margin: 'auto', padding: 24 }}>
+            <Title level={3} style={{ textAlign: 'center', marginBottom: 24 }}>
+                好友管理
+            </Title>
+
+            <Space style={{ marginBottom: 24 }} align="start">
+                <Input
+                    placeholder="输入好友用户名"
+                    value={friendName}
+                    onChange={(e) => setFriendName(e.target.value)}
+                    style={{ width: 220 }}
+                    allowClear
+                    prefix={<UserAddOutlined />}
+                />
+                <Button
+                    type="primary"
+                    loading={loading}
+                    onClick={handleAddFriend}
+                    disabled={!friendName.trim()}
+                >
+                    添加好友
+                </Button>
+            </Space>
+
+            <Divider />
+
+            <Title level={4}>好友申请</Title>
+            <Spin spinning={pendingLoading}>
+                {pendingRequests.length === 0 ? (
+                    <Text type="secondary">暂无好友申请</Text>
+                ) : (
+                    <List
+                        itemLayout="horizontal"
+                        dataSource={pendingRequests}
+                        renderItem={(item) => {
+                            const otherId = item.friend1 === currentUserId ? item.friend2 : item.friend1;
+                            return (
+                                <List.Item
+                                    actions={[
+                                        <Button
+                                            key="accept"
+                                            type="primary"
+                                            icon={<CheckOutlined />}
+                                            onClick={() => handleAccept(item.friend1, item.friend2)}
+                                            loading={pendingLoading}
+                                            size="small"
+                                        >
+                                            同意
+                                        </Button>,
+                                        <Popconfirm
+                                            key="reject"
+                                            title="确定拒绝该好友请求?"
+                                            onConfirm={() => handleReject(item.friend1, item.friend2)}
+                                            okText="确认"
+                                            cancelText="取消"
+                                        >
+                                            <Button
+                                                danger
+                                                icon={<CloseOutlined />}
+                                                loading={pendingLoading}
+                                                size="small"
+                                            >
+                                                拒绝
+                                            </Button>
+                                        </Popconfirm>,
+                                    ]}
+                                >
+                                    <List.Item.Meta {...renderUserMeta(otherId, `申请时间:${new Date(item.requestTime).toLocaleString()}`)} />
+                                </List.Item>
+                            );
+                        }}
+                    />
+                )}
+            </Spin>
+
+            <Divider />
+
+            <Space align="center" style={{ marginBottom: 12, justifyContent: 'space-between', width: '100%' }}>
+                <Title level={4} style={{ margin: 0 }}>
+                    我的好友列表
+                </Title>
+                <Button
+                    icon={<ReloadOutlined />}
+                    onClick={() => refreshData()}
+                    loading={refreshing || pendingLoading}
+                    type="link"
+                >
+                    刷新
+                </Button>
+            </Space>
+            <Spin spinning={refreshing}>
+                {friends.length === 0 ? (
+                    <Text type="secondary">暂无好友</Text>
+                ) : (
+                    <List
+                        itemLayout="horizontal"
+                        dataSource={friends}
+                        renderItem={(f) => {
+                            const friendUserId = getFriendUserId(f);
+                            return (
+                                <List.Item
+                                    onClick={() =>
+                                        onSelectRelation({
+                                            relationid: f.relationid,
+                                            friendId: friendUserId,
+                                        })
+                                    }
+                                    style={{ cursor: 'pointer' }}
+                                    actions={[
+                                        <Popconfirm
+                                            title="确定删除该好友?"
+                                            onConfirm={(e) => {
+                                                e.stopPropagation();
+                                                handleDelete(f.friend1, f.friend2);
+                                            }}
+                                            okText="确认"
+                                            cancelText="取消"
+                                            key="delete"
+                                        >
+                                            <Button
+                                                danger
+                                                icon={<DeleteOutlined />}
+                                                loading={loading}
+                                                size="small"
+                                            >
+                                                删除
+                                            </Button>
+                                        </Popconfirm>,
+                                    ]}
+                                >
+                                    <List.Item.Meta
+                                        {...renderUserMeta(friendUserId, `添加时间:${new Date(f.requestTime).toLocaleString()}`)}
+                                    />
+                                </List.Item>
+                            );
+                        }}
+                    />
+                )}
+            </Spin>
+        </div>
+    );
+};
+
+export default FriendManager;
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
new file mode 100644
index 0000000..a381989
--- /dev/null
+++ b/src/components/Navbar.jsx
@@ -0,0 +1,98 @@
+import React from 'react';
+import { Link, useNavigate, useLocation } from 'react-router-dom';
+import { Layout, Menu, Avatar } from 'antd';
+import {
+  HomeOutlined,
+  CloudUploadOutlined,
+  ThunderboltOutlined,
+  UsergroupAddOutlined
+} from '@ant-design/icons';
+
+const { Header } = Layout;
+
+const Navbar = () => {
+  const navigate = useNavigate();
+  const location = useLocation();
+
+  // 从localStorage获取用户数据
+  const userData = JSON.parse(localStorage.getItem('user')) || {};
+  const { username, image } = userData;
+
+  // 点击头像或用户名跳转到首页
+  const handleUserClick = () => {
+    navigate('/usercenter');
+  };
+
+  return (
+    <Header
+      style={{
+        backgroundColor: '#f5be42',
+        boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
+        padding: '0 40px',
+         width: '100%', // 确保宽度扩展到100%
+        display: 'flex',
+        alignItems: 'center',
+        justifyContent: 'space-between'
+      }}
+    >
+      {/* Logo */}
+      <div style={{ color: '#fff', fontSize: '20px', fontWeight: 'bold' }}>
+        <Link to="/" style={{ color: '#fff', textDecoration: 'none' }}>
+          社交互动平台
+        </Link>
+      </div>
+
+      {/* Menu */}
+      <Menu
+        mode="horizontal"
+        theme="dark"
+        selectedKeys={[location.pathname]}
+        style={{
+          backgroundColor: 'transparent',
+          flex: 1,
+          justifyContent: 'center',
+          borderBottom: 'none'
+        }}
+      >
+        <Menu.Item key="/mainpage" icon={<HomeOutlined />}>
+          <Link to="/home" style={{ color: '#fff' }}>首页</Link>
+        </Menu.Item>
+        <Menu.Item key="/" icon={<HomeOutlined />}>
+          <Link to="/community" style={{ color: '#fff' }}>社区</Link>
+        </Menu.Item>
+        <Menu.Item key="/torrents" icon={<ThunderboltOutlined />}>
+          <Link to="/torrents" style={{ color: '#fff' }}>种子</Link>
+        </Menu.Item>
+        <Menu.Item key="/upload" icon={<CloudUploadOutlined />}>
+          <Link to="/upload" style={{ color: '#fff' }}>上传种子</Link>
+        </Menu.Item>
+        <Menu.Item key="/friend" icon={<UsergroupAddOutlined />}>
+          <Link to="/friend" style={{ color: '#fff' }}>好友</Link>
+        </Menu.Item>
+        <Menu.Item key="/shop" icon={<UsergroupAddOutlined />}>
+          <Link to="/shop" style={{ color: '#fff' }}>商城</Link>
+        </Menu.Item>
+      </Menu>
+
+      {/* 用户名和头像 - 添加点击事件 */}
+      <div
+        style={{
+          display: 'flex',
+          alignItems: 'center',
+          gap: '8px',
+          cursor: 'pointer'  // 添加指针样式表示可点击
+        }}
+        onClick={handleUserClick}
+      >
+        <Avatar
+          src={image}
+          size="default"
+          style={{ backgroundColor: '#f56a00' }}
+        />
+        <span style={{ color: '#fff' }}>{username}</span>
+      </div>
+    </Header>
+  );
+};
+
+export default Navbar;
\ No newline at end of file
diff --git a/src/components/Post.css b/src/components/Post.css
new file mode 100644
index 0000000..40d787e
--- /dev/null
+++ b/src/components/Post.css
@@ -0,0 +1,483 @@
+.post-container {
+  padding: 2rem;
+  background: #f8f9fa;
+  min-height: 100vh;
+  max-width: 900px;
+  margin: auto;
+}
+
+.post-form-card {
+  background: white;
+  border-radius: 12px;
+  padding: 2rem;
+  box-shadow: 0 8px 20px rgba(255, 102, 0, 0.15);
+  margin-bottom: 2rem;
+  animation: fadeInUp 0.5s ease-in-out;
+}
+
+.post-form-title {
+  font-size: 1.5rem;
+  font-weight: bold;
+  margin-bottom: 1rem;
+  color: #ff6600;
+}
+
+.post-input,
+.post-textarea {
+  width: 100%;
+  padding: 12px 14px;
+  border-radius: 8px;
+  border: 1px solid #ffbf80;
+  margin-bottom: 1rem;
+  font-size: 1rem;
+  transition: border-color 0.3s ease;
+}
+
+.post-input:focus,
+.post-textarea:focus {
+  outline: none;
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+}
+
+.post-textarea {
+  height: 100px;
+  resize: vertical;
+}
+
+.post-file {
+  margin-bottom: 1rem;
+}
+
+.post-button {
+  padding: 10px 20px;
+  border: none;
+  border-radius: 8px;
+  font-size: 1rem;
+  font-weight: 600;
+  margin-right: 0.5rem;
+  transition: all 0.3s ease;
+  cursor: pointer;
+  box-shadow: 0 4px 6px rgba(255, 102, 0, 0.3);
+}
+
+/* 浅橙色实底按钮 */
+.primary {
+  background: linear-gradient(45deg, #FFB366, #FFC299);
+  color: white;
+  box-shadow: 0 6px 10px rgba(255, 179, 102, 0.5);
+}
+
+.primary:hover {
+  background: linear-gradient(45deg, #FFAA33, #FFBF66);
+  box-shadow: 0 8px 14px rgba(255, 170, 51, 0.7);
+}
+
+/* 橙色边框按钮 */
+.primary-outline {
+  background: transparent;
+  border: 2px solid #ff6600;
+  color: #ff6600;
+  box-shadow: none;
+}
+
+.primary-outline:hover {
+  background: #ff6600;
+  color: white;
+  box-shadow: 0 6px 10px rgba(255, 102, 0, 0.4);
+}
+
+.post-list {
+  display: flex;
+  flex-direction: column;
+  gap: 1.5rem;
+}
+
+.post-card {
+  background: white;
+  border-radius: 12px;
+  padding: 1.5rem;
+  box-shadow: 0 4px 15px rgba(255, 102, 0, 0.12);
+  animation: fadeInUp 0.3s ease-out;
+  transition: box-shadow 0.3s ease;
+}
+
+.post-card:hover {
+  box-shadow: 0 8px 30px rgba(255, 102, 0, 0.25);
+}
+
+.post-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 1rem;
+}
+
+.post-info {
+  flex: 1;
+}
+
+.post-title {
+  font-size: 1.5rem;
+  font-weight: 700;
+  color: #cc5200;
+  margin-bottom: 0.75rem;
+  padding-left: 12px;
+  border-left: 4px solid #ff6600;
+  transition: color 0.3s ease;
+}
+
+.post-title:hover {
+  color: #ff6600;
+}
+
+.post-content {
+  color: #444;
+  margin-bottom: 0.75rem;
+}
+
+.post-image {
+  width: 160px;
+  height: 120px;
+  object-fit: cover;
+  border-radius: 6px;
+  box-shadow: 0 4px 8px rgba(255, 102, 0, 0.3);
+  flex-shrink: 0;
+  cursor: pointer;
+  transition: transform 0.3s ease;
+}
+
+.post-image:hover {
+  transform: scale(1.05);
+}
+
+.post-meta {
+  font-size: 0.9rem;
+  color: #777;
+  margin-top: 0.5rem;
+}
+
+.post-actions-inline {
+  margin-top: 0.75rem;
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+  font-size: 0.95rem;
+}
+
+.post-link {
+  cursor: pointer;
+  text-decoration: underline;
+  transition: color 0.3s ease;
+}
+
+.post-link.like {
+  color: #ff6600;
+}
+
+.post-link.like:hover {
+  color: #ff8533;
+}
+
+.post-link.unlike {
+  color: #cc3300;
+}
+
+.post-link.unlike:hover {
+  color: #ff3300;
+}
+
+.post-comment {
+  margin-top: 1rem;
+  border-top: 1px solid #ffe6cc;
+  padding-top: 1rem;
+}
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 图片模态框 */
+.image-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  background: rgba(0, 0, 0, 0.75);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 9999;
+}
+
+.image-modal-content {
+  position: relative;
+  max-width: 90%;
+  max-height: 90%;
+}
+
+.image-modal-img {
+  width: 100%;
+  max-height: 80vh;
+  border-radius: 12px;
+  box-shadow: 0 0 20px rgba(255, 102, 0, 0.8);
+}
+
+.image-modal-close {
+  position: absolute;
+  top: -20px;
+  right: -20px;
+  background: white;
+  border: none;
+  border-radius: 50%;
+  width: 36px;
+  height: 36px;
+  font-size: 24px;
+  line-height: 36px;
+  text-align: center;
+  cursor: pointer;
+  box-shadow: 0 2px 10px rgba(255, 102, 0, 0.7);
+}
+
+.action-group {
+  display: flex;
+  gap: 0.5rem;
+  margin-bottom: 0.5rem;
+}
+
+.post-empty-state {
+  text-align: center;
+  padding: 2rem;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 4px 15px rgba(255, 102, 0, 0.12);
+}
+
+.post-empty-message {
+  font-size: 1.2rem;
+  color: #cc5200;
+  margin-bottom: 1rem;
+}
+
+/* RequestBoard组件样式保持一致 */
+.request-board-container {
+  background: white;
+  border-radius: 12px;
+  padding: 1.5rem;
+  box-shadow: 0 4px 15px rgba(255, 102, 0, 0.12);
+  margin-top: 1rem;
+}
+
+.request-board-section {
+  margin-bottom: 1.5rem;
+}
+
+.request-board-form {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 1rem;
+  margin-bottom: 1.5rem;
+}
+
+.request-board-input {
+  padding: 10px 12px;
+  border-radius: 8px;
+  border: 1px solid #ffbf80;
+  font-size: 0.95rem;
+}
+
+.request-board-input:focus {
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+  outline: none;
+}
+
+.request-board-textarea {
+  grid-column: span 2;
+  padding: 10px 12px;
+  border-radius: 8px;
+  border: 1px solid #ffbf80;
+  resize: vertical;
+  min-height: 100px;
+}
+
+.request-board-textarea:focus {
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+  outline: none;
+}
+
+.request-board-file {
+  grid-column: span 2;
+}
+
+.request-board-list {
+  display: grid;
+  grid-template-columns: 1fr;
+  gap: 1rem;
+}
+
+.request-board-item {
+  background: white;
+  border-radius: 10px;
+  padding: 1.25rem;
+  box-shadow: 0 2px 8px rgba(255, 102, 0, 0.08);
+}
+
+.request-board-item-title {
+  font-size: 1.3rem;
+  font-weight: 700;
+  margin-bottom: 0.75rem;
+  color: hsl(24, 67%, 55%);
+  border-bottom: 2px solid #ffe0b3;
+  padding-bottom: 0.5rem;
+}
+
+.request-board-item-content {
+  color: #555;
+  margin-bottom: 1rem;
+}
+
+.request-board-item-meta {
+  display: flex;
+  gap: 1rem;
+  margin-bottom: 1rem;
+  color: #777;
+  font-size: 0.9rem;
+}
+
+.request-board-item-image {
+  max-width: 200px;
+  max-height: 150px;
+  border-radius: 6px;
+  margin-bottom: 1rem;
+}
+
+.request-board-item-actions {
+  display: flex;
+  gap: 0.75rem;
+  flex-wrap: wrap;
+}
+
+.request-board-small-input {
+  padding: 8px 10px;
+  border-radius: 6px;
+  border: 1px solid #ffbf80;
+  flex: 1;
+}
+
+.request-board-small-input:focus {
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+  outline: none;
+}
+
+/* 新增的用户信息显示样式 */
+.post-form-user-info {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20px;
+  padding: 10px;
+  background-color: #f8f9fa;
+  border-radius: 8px;
+  border: 1px solid #e9ecef;
+}
+
+.post-form-user-avatar {
+  width: 50px;
+  height: 50px;
+  border-radius: 50%;
+  object-fit: cover;
+  margin-right: 15px;
+  border: 2px solid #40a9ff;
+}
+
+.post-form-user-avatar-placeholder {
+  width: 50px;
+  height: 50px;
+  border-radius: 50%;
+  background-color: #e9ecef;
+  margin-right: 15px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 2px solid #40a9ff;
+}
+
+.avatar-initial {
+  font-size: 24px;
+  font-weight: bold;
+  color: #495057;
+}
+
+.post-form-username {
+  font-weight: 600;
+  font-size: 18px;
+  color: #212529;
+}
+
+.post-form-user-label {
+  margin-left: auto;
+  padding: 5px 10px;
+  background-color: #e6f7ff;
+  color: #1890ff;
+  border-radius: 4px;
+  font-size: 14px;
+}
+
+/* 帖子作者信息样式 */
+.post-author-info {
+  display: flex;
+  align-items: center;
+  padding: 10px 15px;
+  border-bottom: 1px solid #f0f0f0;
+  margin-bottom: 15px;
+}
+
+.post-author-avatar {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  object-fit: cover;
+  margin-right: 12px;
+  border: 1px solid #e8e8e8;
+}
+
+.post-author-avatar-placeholder {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  background-color: #f5f5f5;
+  margin-right: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid #e8e8e8;
+}
+
+.post-author-details {
+  display: flex;
+  flex-direction: column;
+}
+
+.post-author-name {
+  font-weight: 600;
+  font-size: 16px;
+  margin-bottom: 3px;
+  color: #333;
+}
+
+.post-meta {
+  font-size: 12px;
+  color: #888;
+  margin: 2px 0;
+}
\ No newline at end of file
diff --git a/src/components/Post.jsx b/src/components/Post.jsx
new file mode 100644
index 0000000..c6b2e69
--- /dev/null
+++ b/src/components/Post.jsx
@@ -0,0 +1,294 @@
+import React, { useState, useEffect } from 'react';
+import {
+    createPost,
+    findPinnedPosts,
+    likePost,
+    unlikePost,
+    searchPosts,
+    getAllPostsSorted,
+    findPostsByUserId,
+} from '../api/post';
+import Comment from './Comment';
+import RequestBoard from './RequestBoard';
+import './Post.css';
+
+const Post = () => {
+    const [title, setTitle] = useState('');
+    const [content, setContent] = useState('');
+    const [tags, setTags] = useState('');
+    const [photo, setPhoto] = useState(null);
+    const [posts, setPosts] = useState([]);
+    const [searchKeyword, setSearchKeyword] = useState('');
+    const [imagePreview, setImagePreview] = useState(null);
+    const [showCreateForm, setShowCreateForm] = useState(false);
+    const [currentView, setCurrentView] = useState('posts');
+    const [currentUser, setCurrentUser] = useState(null);
+    const [userDecorations, setUserDecorations] = useState({});
+
+    useEffect(() => {
+        const storedUser = JSON.parse(localStorage.getItem('user'));
+        if (storedUser) setCurrentUser(storedUser);
+    }, []);
+
+    useEffect(() => {
+        loadPinnedPosts();
+    }, []);
+
+    useEffect(() => {
+        if (posts.length > 0) {
+            fetchUserDecorations(posts);
+        }
+    }, [posts]);
+
+    const fetchUserDecorations = async (posts) => {
+        const decorations = {};
+        await Promise.all(
+            posts.map(async (post) => {
+                if (!decorations[post.userid]) {
+                    try {
+                        const res = await fetch(`http://localhost:8080/user/getDecoration?userid=${post.userid}`);
+                        const json = await res.json();
+                        if (json.success) {
+                            decorations[post.userid] = json.data;
+                        }
+                    } catch (error) {
+                        console.error(`获取用户 ${post.userid} 的装饰信息失败`, error);
+                    }
+                }
+            })
+        );
+        setUserDecorations(decorations);
+    };
+
+    const loadPinnedPosts = async () => {
+        const data = await findPinnedPosts();
+        setPosts(data);
+        setCurrentView('posts');
+    };
+
+    const loadAllPosts = async () => {
+        const data = await getAllPostsSorted();
+        setPosts(data);
+        setCurrentView('posts');
+    };
+
+    const loadMyPosts = async () => {
+        if (!currentUser) return;
+        const data = await findPostsByUserId(currentUser.userid);
+        setPosts(data);
+        setCurrentView('posts');
+    };
+
+    const handleCreate = async () => {
+        if (!currentUser) {
+            alert('请先登录再发帖');
+            return;
+        }
+
+        const formData = new FormData();
+        formData.append('userid', currentUser.userid);
+        formData.append('post_title', title);
+        formData.append('post_content', content);
+        formData.append('tags', tags);
+        formData.append('rannge', 'public');
+        if (photo) formData.append('photo', photo);
+
+        const success = await createPost(formData);
+        if (success) {
+            alert('帖子创建成功');
+            loadPinnedPosts();
+            setTitle('');
+            setContent('');
+            setTags('');
+            setPhoto(null);
+            setShowCreateForm(false);
+        } else {
+            alert('创建失败');
+        }
+    };
+
+    const handleLike = async (postid) => {
+        await likePost(postid);
+        loadPinnedPosts();
+    };
+
+    const handleUnlike = async (postid) => {
+        await unlikePost(postid);
+        loadPinnedPosts();
+    };
+
+    const handleSearch = async () => {
+        const result = await searchPosts(searchKeyword);
+        setPosts(result);
+        setCurrentView('posts');
+    };
+
+    const showRequestBoard = () => {
+        setCurrentView('requests');
+    };
+
+    return (
+        <div className="post-container">
+            <div className="post-actions">
+                <div className="action-group">
+                    {currentUser && (
+                        <button
+                            className="post-button primary"
+                            onClick={() => setShowCreateForm(!showCreateForm)}
+                        >
+                            {showCreateForm ? '收起发布表单' : '创建新帖子'}
+                        </button>
+                    )}
+                    <input
+                        type="text"
+                        placeholder="搜索关键词"
+                        value={searchKeyword}
+                        onChange={(e) => setSearchKeyword(e.target.value)}
+                        className="post-input"
+                    />
+                    <button className="post-button primary-outline" onClick={handleSearch}>搜索</button>
+                </div>
+
+                <div className="action-group">
+                    <button className="post-button primary-outline" onClick={loadPinnedPosts}>置顶帖子</button>
+                    <button className="post-button primary-outline" onClick={loadAllPosts}>所有帖子</button>
+                    {currentUser && (
+                        <button className="post-button primary-outline" onClick={loadMyPosts}>我的帖子</button>
+                    )}
+                    <button className="post-button primary-outline" onClick={showRequestBoard}>需求帖子</button>
+                </div>
+            </div>
+
+            {showCreateForm && currentUser && currentView !== 'requests' && (
+                <div className="post-form-card">
+                    <div className="post-form-user-info">
+                        {currentUser.image ? (
+                            <img
+                                src={currentUser.image}
+                                alt="头像"
+                                className="post-form-user-avatar"
+                            />
+                        ) : (
+                            <div className="post-form-user-avatar-placeholder">
+                                <div className="avatar-initial">
+                                    {currentUser.username?.charAt(0) || 'U'}
+                                </div>
+                            </div>
+                        )}
+                        <div className="post-form-username">{currentUser.username}</div>
+                        <div className="post-form-user-label">发布者</div>
+                    </div>
+
+                    <h2 className="post-form-title">发布新帖子</h2>
+                    <input
+                        type="text"
+                        placeholder="标题"
+                        value={title}
+                        onChange={(e) => setTitle(e.target.value)}
+                        className="post-input"
+                    />
+                    <textarea
+                        placeholder="内容"
+                        value={content}
+                        onChange={(e) => setContent(e.target.value)}
+                        className="post-textarea"
+                    />
+                    <input
+                        type="text"
+                        placeholder="标签(逗号分隔)"
+                        value={tags}
+                        onChange={(e) => setTags(e.target.value)}
+                        className="post-input"
+                    />
+                    <input
+                        type="file"
+                        onChange={(e) => setPhoto(e.target.files[0])}
+                        className="post-file"
+                    />
+                    <button className="post-button primary" onClick={handleCreate}>
+                        发布
+                    </button>
+                </div>
+            )}
+
+            {currentView === 'requests' ? (
+                <RequestBoard
+                    currentUserId={currentUser?.userid}
+                    onBack={() => setCurrentView('posts')}
+                />
+            ) : (
+                posts.length > 0 ? (
+                    <div className="post-list">
+                        {posts.map((post) => {
+                            const decoration = userDecorations[post.userid] || {};
+                            const avatar = decoration.image || '';
+                            const username = decoration.username || '匿名用户';
+
+                            return (
+                                <div className="post-card" key={post.postid}>
+                                    <div className="post-author-info">
+                                        {avatar ? (
+                                            <img
+                                                src={avatar}
+                                                alt="头像"
+                                                className="post-author-avatar"
+                                            />
+                                        ) : (
+                                            <div className="post-author-avatar-placeholder">
+                                                <div className="avatar-initial">{username.charAt(0)}</div>
+                                            </div>
+                                        )}
+                                        <div className="post-author-details">
+                                            <div className="post-author-name">{username}</div>
+                                            <div className="post-meta">发布时间: {post.postCreatedTime}</div>
+                                        </div>
+                                    </div>
+
+                                    <div className="post-header">
+                                        <div className="post-info">
+                                            <h3 className="post-title">{post.postTitle}</h3>
+                                            <p className="post-content">{post.postContent}</p>
+                                            <div className="post-meta">标签: {post.tags || '无标签'}</div>
+                                            <div className="post-actions-inline">
+                                                <span>👍 {post.likes}</span>
+                                                <button className="post-link like" onClick={() => handleLike(post.postid)}>点赞</button>
+                                                <button className="post-link unlike" onClick={() => handleUnlike(post.postid)}>取消点赞</button>
+                                            </div>
+                                        </div>
+                                        {post.photo && (
+                                            <img
+                                                src={`http://localhost:8080${post.photo}`}
+                                                alt="post"
+                                                className="post-image"
+                                                onClick={() => setImagePreview(`http://localhost:8080${post.photo}`)}
+                                            />
+                                        )}
+                                    </div>
+
+                                    <div className="post-comment">
+                                        <Comment postId={post.postid} currentUser={currentUser} />
+                                    </div>
+                                </div>
+                            );
+                        })}
+                    </div>
+                ) : (
+                    <div className="post-empty-state">
+                        <p className="post-empty-message">暂无内容</p>
+                    </div>
+                )
+            )}
+
+            {imagePreview && (
+                <div className="image-modal" onClick={() => setImagePreview(null)}>
+                    <div className="image-modal-content" onClick={(e) => e.stopPropagation()}>
+                        <img src={imagePreview} alt="preview" className="image-modal-img" />
+                        <button className="image-modal-close" onClick={() => setImagePreview(null)}>×</button>
+                    </div>
+                </div>
+            )}
+        </div>
+    );
+};
+
+export default Post;
diff --git a/src/components/PostAdminPanel.jsx b/src/components/PostAdminPanel.jsx
new file mode 100644
index 0000000..a01df08
--- /dev/null
+++ b/src/components/PostAdminPanel.jsx
@@ -0,0 +1,232 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table,
+    Button,
+    Modal,
+    Image,
+    message,
+    Tag,
+    Space,
+    Input,
+    Tooltip,
+} from 'antd';
+import { ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
+import {
+    getAllPostsSorted,
+    searchPosts,
+    deletePost,
+    togglePinPost,
+} from '../api/post';
+
+const { confirm } = Modal;
+
+const PostAdminPanel = () => {
+    const [posts, setPosts] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const [keyword, setKeyword] = useState('');
+
+    const fetchPosts = async () => {
+        setLoading(true);
+        try {
+            const data = keyword.trim()
+                ? await searchPosts(keyword.trim())
+                : await getAllPostsSorted();
+            setPosts(data);
+        } catch (error) {
+            message.error('获取帖子失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchPosts();
+    }, []);
+
+    const handleSearch = () => {
+        fetchPosts();
+    };
+
+    const handleDelete = (postid) => {
+        confirm({
+            title: '确认删除该帖子吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk: async () => {
+                try {
+                    const res = await deletePost(postid);
+                    if (res) {
+                        message.success('删除成功');
+                        fetchPosts();
+                    } else {
+                        message.error('删除失败');
+                    }
+                } catch {
+                    message.error('删除请求失败');
+                }
+            },
+        });
+    };
+
+    const handlePinToggle = async (postid) => {
+        try {
+            const res = await togglePinPost(postid);
+            if (res === true || res === false) {
+                // ✅ 用后端返回的状态更新 UI
+                const newPosts = posts.map(post => {
+                    if (post.postid === postid) {
+                        return {
+                            ...post,
+                            is_pinned: res ? 1 : 0,
+                        };
+                    }
+                    return post;
+                });
+                setPosts(newPosts);
+                message.success(`帖子${res ? '已置顶' : '已取消置顶'}`);
+            } else {
+                message.error('更新失败');
+            }
+        } catch {
+            message.error('更新置顶状态失败');
+        }
+    };
+
+
+
+
+    const columns = [
+        {
+            title: 'ID',
+            dataIndex: 'postid',
+            key: 'postid',
+            width: 80,
+            fixed: 'left',
+        },
+        {
+            title: '用户ID',
+            dataIndex: 'userid',
+            key: 'userid',
+            width: 100,
+        },
+        {
+            title: '标题',
+            dataIndex: 'postTitle',
+            key: 'postTitle',
+            width: 200,
+            ellipsis: true,
+        },
+        {
+            title: '内容',
+            dataIndex: 'postContent',
+            key: 'postContent',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '标签',
+            dataIndex: 'tags',
+            key: 'tags',
+            render: (tags) =>
+                tags ? tags.split(',').map((tag) => <Tag key={tag}>{tag}</Tag>) : <Tag color="default">无</Tag>,
+        },
+        {
+            title: '图片',
+            dataIndex: 'photo',
+            key: 'photo',
+            width: 100,
+            render: (url) =>
+                url ? (
+                    <Image
+                        src={`http://localhost:8080${url}`}
+                        width={80}
+                        height={80}
+                        style={{ objectFit: 'cover' }}
+                    />
+                ) : (
+                    <Tag color="default">无</Tag>
+                ),
+        },
+        {
+            title: '点赞数',
+            dataIndex: 'likes',
+            key: 'likes',
+            width: 100,
+            render: (likes) => <Tag color="blue">{likes}</Tag>,
+        },
+        {
+            title: '置顶状态',
+            dataIndex: 'is_pinned',
+            key: 'is_pinned',
+            width: 100,
+            render: (val) =>
+                val ? <Tag color="green">已置顶</Tag> : <Tag color="default">未置顶</Tag>,
+        },
+        {
+            title: '发布时间',
+            dataIndex: 'postCreatedTime',
+            key: 'postCreatedTime',
+            width: 180,
+            render: (time) =>
+                time ? new Date(time).toLocaleString() : <Tag color="default">暂无</Tag>,
+        },
+        {
+            title: '操作',
+            key: 'action',
+            width: 180,
+            fixed: 'right',
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button
+                        type="primary"
+                        onClick={() => handlePinToggle(record.postid, record.is_pinned)}
+                    >
+                        {Boolean(record.is_pinned) ? '取消置顶' : '置顶'}
+                    </Button>
+
+                    <Button danger onClick={() => handleDelete(record.postid)}>
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>帖子管理面板</h2>
+            <Space style={{ marginBottom: 16 }}>
+                <Input
+                    placeholder="请输入关键词"
+                    value={keyword}
+                    onChange={(e) => setKeyword(e.target.value)}
+                    style={{ width: 300 }}
+                />
+                <Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
+                    搜索
+                </Button>
+                <Button onClick={() => { setKeyword(''); fetchPosts(); }}>
+                    重置
+                </Button>
+            </Space>
+            <Table
+                rowKey="postid"
+                columns={columns}
+                dataSource={posts}
+                loading={loading}
+                scroll={{ x: 1600 }}
+                pagination={{ pageSize: 10 }}
+                bordered
+                size="middle"
+            />
+        </div>
+    );
+};
+
+export default PostAdminPanel;
diff --git a/src/components/PostCard.jsx b/src/components/PostCard.jsx
new file mode 100644
index 0000000..5051cec
--- /dev/null
+++ b/src/components/PostCard.jsx
@@ -0,0 +1,103 @@
+import React, { useState, useEffect } from 'react';
+import {
+    likePost,
+    unlikePost,
+    togglePinPost,
+    deletePost,
+} from '../api/post';
+
+const PostCard = ({ post, onDeleted, onUpdated }) => {
+    const [likes, setLikes] = useState(post.likes);
+    const [isLiked, setIsLiked] = useState(false); // 默认未点赞
+    const [isPinned, setIsPinned] = useState(post.is_pinned || false);
+    const [loading, setLoading] = useState(false);
+
+    useEffect(() => {
+        setIsPinned(post.is_pinned || false);
+    }, [post.is_pinned]);
+
+    const handleLike = async () => {
+        setLoading(true);
+        try {
+            if (!isLiked) {
+                const res = await likePost(post.postid);
+                if (res) {
+                    setLikes(likes + 1);
+                    setIsLiked(true);
+                }
+            } else {
+                const res = await unlikePost(post.postid);
+                if (res) {
+                    setLikes(likes - 1);
+                    setIsLiked(false);
+                }
+            }
+        } catch (error) {
+            console.error('点赞操作失败', error);
+        }
+        setLoading(false);
+    };
+
+    const handlePin = async () => {
+        setLoading(true);
+        try {
+            const res = await togglePinPost(post.postid);
+            if (res) {
+                onUpdated && onUpdated(); // 通知父组件刷新数据
+            }
+        } catch (error) {
+            console.error('置顶切换失败', error);
+        }
+        setLoading(false);
+    };
+
+    const handleDelete = async () => {
+        if (!window.confirm('确认删除该帖子吗?')) return;
+        setLoading(true);
+        try {
+            const res = await deletePost(post.postid);
+            if (res) {
+                onDeleted && onDeleted(post.postid);
+            }
+        } catch (error) {
+            console.error('删除失败', error);
+        }
+        setLoading(false);
+    };
+
+    return (
+        <div className="post-card" style={{ border: '1px solid #ddd', padding: 16, marginBottom: 12 }}>
+            <h3>{post.postTitle}</h3>
+            <p>{post.postContent}</p>
+            {post.photo && (
+                <img
+                    src={`http://localhost:8080${post.photo}`}
+                    alt="帖子图片"
+                    style={{ maxWidth: '100%', maxHeight: 200 }}
+                />
+            )}
+            <p>
+                <strong>标签:</strong> {post.tags || '无'}
+            </p>
+            <p>
+                <strong>作者ID:</strong> {post.userid} | <strong>点赞数:</strong> {likes}
+            </p>
+            <p>
+                <strong>发布时间:</strong> {new Date(post.postCreatedTime).toLocaleString()}
+            </p>
+            <p>
+                <button onClick={handleLike} disabled={loading}>
+                    {isLiked ? '取消点赞' : '点赞'}
+                </button>{' '}
+                <button onClick={handlePin} disabled={loading}>
+                    {isPinned ? '取消置顶' : '置顶'}
+                </button>{' '}
+                <button onClick={handleDelete} disabled={loading}>
+                    删除
+                </button>
+            </p>
+        </div>
+    );
+};
+
+export default PostCard;
diff --git a/src/components/RecommendAll.jsx b/src/components/RecommendAll.jsx
new file mode 100644
index 0000000..330c433
--- /dev/null
+++ b/src/components/RecommendAll.jsx
@@ -0,0 +1,83 @@
+import React, { useEffect, useState } from 'react';
+import '../torrentlist.css';
+
+const RecommendAll = () => {
+  const [torrents, setTorrents] = useState([]);
+  const storedUser = localStorage.getItem('user');
+    //let currentUserId = null; // 初始化为 null
+    let currentUserId = null; // 初始化为 null
+
+    if (storedUser) {
+        try {
+            const parsedUser = JSON.parse(storedUser);
+            currentUserId = parsedUser.userid; // 直接赋值
+        } catch (error) {
+            console.error('解析用户数据失败:', error);
+            // 可以在这里处理 JSON 解析错误(如数据损坏)
+        }
+    } else {
+        console.log('用户未登录');
+    }
+
+    // 现在 currentUserId 可以在后续逻辑中使用
+    console.log('当前用户ID:', currentUserId);
+
+
+  useEffect(() => {
+    const fetchAll = async () => {
+   const res = await fetch(`http://localhost:8080/recommend/list?userId=${currentUserId}`);
+    //const res = await fetch('http://localhost:8080/torrent/list');
+      const data = await res.json();
+      setTorrents(data);
+    };
+    fetchAll();
+  }, []);
+
+  const formatFileSize = (bytes) => {
+    if (!bytes) return '0 Bytes';
+    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(1024));
+    return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
+  };
+
+  return (
+    <div className="torrents-container">
+      <h2 style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 16 }}>全部推荐种子</h2>
+      <div className="torrents1-grid">
+        {torrents.map(torrent => (
+          <div key={torrent.torrentid} className="torrent-card">
+            <div className="cover">
+              {torrent.coverImagePath ? (
+                <img src={torrent.coverImagePath} alt="封面" className="cover-image" />
+              ) : (
+                <div className="no-cover">无封面</div>
+              )}
+            </div>
+
+            <div className="info">
+              <h3 className="title" title={torrent.filename}>
+                {torrent.torrentTitle || torrent.filename}
+              </h3>
+              <p className="description" title={torrent.description}>
+                {torrent.description || '暂无描述'}
+              </p>
+
+              <div className="details">
+                <span>大小: {formatFileSize(torrent.torrentSize)}</span>
+                <span>上传时间: {new Date(torrent.uploadTime).toLocaleDateString()}</span>
+                <span>下载次数: {torrent.downloadCount}</span>
+              </div>
+
+              <div className="actions">
+                <button className="btn btn-download">下载</button>
+                <a href={`/torrent/${torrent.torrentid}`} className="btn btn-detail">详情</a>
+              </div>
+            </div>
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export default RecommendAll;
diff --git a/src/components/RecommendPreview.jsx b/src/components/RecommendPreview.jsx
new file mode 100644
index 0000000..5eb45d3
--- /dev/null
+++ b/src/components/RecommendPreview.jsx
@@ -0,0 +1,92 @@
+import React, { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import '../RecommendPreview.css';
+
+const RecommendPreview = () => {
+  
+  const [recommendList, setRecommendList] = useState([]);
+  const navigate = useNavigate();
+
+  const storedUser = localStorage.getItem('user');
+    //let currentUserId = null; // 初始化为 null
+    let currentUserId = null; // 初始化为 null
+
+    if (storedUser) {
+        try {
+            const parsedUser = JSON.parse(storedUser);
+            currentUserId = parsedUser.userid; // 直接赋值
+        } catch (error) {
+            console.error('解析用户数据失败:', error);
+            // 可以在这里处理 JSON 解析错误(如数据损坏)
+        }
+    } else {
+        console.log('用户未登录');
+    }
+
+    // 现在 currentUserId 可以在后续逻辑中使用
+    console.log('当前用户ID:', currentUserId);
+
+  useEffect(() => {
+    const fetchRecommendList = async () => {
+      try {
+        const res = await fetch(`http://localhost:8080/recommend/list?userId=${currentUserId}`);
+        //const res = await fetch('http://localhost:8080/torrent/list');
+        const data = await res.json();
+        console.log('推荐列表数据:', data);
+        setRecommendList(data.slice(0, 8)); // 只展示前8个
+      } catch (err) {
+        console.error('推荐获取失败:', err);
+      }
+    };
+    fetchRecommendList();
+  }, []);
+
+  const formatFileSize = (bytes) => {
+    if (!bytes) return '0 Bytes';
+    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(1024));
+    return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
+  };
+
+  const formatDate = (dateString) => {
+    const date = new Date(dateString);
+    return date.toLocaleDateString();
+  };
+
+  return (
+    <div className="recommend-horizontal-container">
+      <div className="recommend-header">
+        <h2>为你推荐</h2>
+        <button className="more-btn" onClick={() => navigate('/recommend')}>
+          更多
+        </button>
+      </div>
+
+      <div className="recommend-horizontal-grid">
+        {recommendList.map((torrent) => (
+          <div key={torrent.torrentid} className="horizontal-card">
+            {torrent.coverImagePath ? (
+              <img src={torrent.coverImagePath} alt="封面" className="card-cover" />
+            ) : (
+              <div className="card-no-cover">无封面</div>
+            )}
+            <div className="card-info">
+              <div className="card-title" title={torrent.torrentTitle || torrent.filename}>
+                {torrent.torrentTitle || torrent.filename}
+              </div>
+              <div className="card-description">
+                {torrent.description || '暂无描述'}
+              </div>
+              <div className="card-meta">
+                <span>{formatDate(torrent.uploadTime)}</span>
+                <span>{formatFileSize(torrent.torrentSize)}</span>
+              </div>
+            </div>
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export default RecommendPreview;
diff --git a/src/components/RequestAdminPanel.jsx b/src/components/RequestAdminPanel.jsx
new file mode 100644
index 0000000..ecf4ee1
--- /dev/null
+++ b/src/components/RequestAdminPanel.jsx
@@ -0,0 +1,228 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table,
+    Button,
+    Modal,
+    Image,
+    message,
+    Tag,
+    Space,
+    Spin,
+    Tooltip,
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import {
+    getAllRequests,
+    deleteRequest,
+} from '../api/request';
+import { useNavigate } from 'react-router-dom';
+
+const { confirm } = Modal;
+
+const RequestAdminPanel = () => {
+    const [requests, setRequests] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const navigate = useNavigate();
+
+    // 获取所有求助帖
+    const fetchRequests = async () => {
+        setLoading(true);
+        try {
+            const data = await getAllRequests();
+            setRequests(data);
+        } catch (error) {
+            message.error('获取求助帖失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchRequests();
+    }, []);
+
+    // 删除确认弹窗
+    const showDeleteConfirm = (requestid) => {
+        confirm({
+            title: '确认删除该求助帖吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk() {
+                handleDelete(requestid);
+            },
+        });
+    };
+
+    // 删除求助帖
+    const handleDelete = async (requestid) => {
+        try {
+            const success = await deleteRequest(requestid);
+            if (success) {
+                message.success('删除成功');
+                fetchRequests();
+            } else {
+                message.error('删除失败');
+            }
+        } catch {
+            message.error('删除请求失败');
+        }
+    };
+
+    // 处理按钮示例
+    const handleProcess = (request) => {
+        navigate(`/process/${request.requestid}`, {
+            state: {
+                requestid: request.requestid,
+                helpedid: request.userid,
+                loaduser: request.loaduser,
+                money: request.money,
+                torrentid: request.torrentid
+            },
+        });
+    };
+
+    console.log('请求数据:', requests);
+
+    // 表格列定义
+    const columns = [
+        {
+            title: 'ID',
+            dataIndex: 'requestid',
+            key: 'requestid',
+            width: 60,
+            fixed: 'left',
+        },
+        {
+            title: '发帖ID',
+            dataIndex: 'userid',
+            key: 'userid',
+            width: 100,
+        },
+        {
+            title: '上传者ID',
+            dataIndex: 'loaduser',
+            key: 'loaduser',
+            width: 100,
+            render: (val) => val ?? <Tag color="default">目前没有</Tag>,
+        },
+        {
+            title: '资源名字',
+            dataIndex: 'name',
+            key: 'name',
+            width: 120,
+            ellipsis: true,
+        },
+        {
+            title: '内容描述',
+            dataIndex: 'plot',
+            key: 'plot',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '悬赏金额',
+            dataIndex: 'money',
+            key: 'money',
+            width: 80,
+            render: (money) => <Tag color="volcano">{money}元</Tag>,
+        },
+        {
+            title: '照片',
+            dataIndex: 'photo',
+            key: 'photo',
+            width: 100,
+            render: (url) =>
+                url ? (
+                    <Image
+                        src={`http://localhost:8080${url}`}
+                        width={80}
+                        height={80}
+                        style={{ objectFit: 'cover' }}
+                        placeholder={<Spin />}
+                    />
+                ) : (
+                    <Tag color="default">无</Tag>
+                ),
+        },
+        {
+            title: '年份',
+            dataIndex: 'year',
+            key: 'year',
+            width: 80,
+        },
+        {
+            title: '国家',
+            dataIndex: 'country',
+            key: 'country',
+            width: 100,
+        },
+        {
+            title: '种子号',
+            dataIndex: 'torrentid',
+            key: 'torrentid',
+            width: 120,
+            render: (val) =>
+                val !== null && val !== undefined ? (
+                    <Tag color="green">{val}</Tag>
+                ) : (
+                    <Tag color="default">暂无</Tag>
+                ),
+        },
+        {
+            title: '发布时间',
+            dataIndex: 'requesttime',
+            key: 'requesttime',
+            width: 180,
+            render: (text) => {
+                if (!text) return <Tag color="default">暂无</Tag>;
+                return new Date(text).toLocaleString();
+            },
+        },
+        {
+            title: '操作',
+            key: 'action',
+            fixed: 'right',
+            width: 150,
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button
+                        type="primary"
+                        onClick={() => handleProcess(record)}
+                    >
+                        处理
+                    </Button>
+                    <Button
+                        danger
+                        onClick={() => showDeleteConfirm(record.requestid)}
+                    >
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>求助帖管理面板</h2>
+            <Table
+                rowKey="requestid"
+                columns={columns}
+                dataSource={requests}
+                loading={loading}
+                scroll={{ x: 1600 }}
+                pagination={{ pageSize: 10 }}
+                bordered
+                size="middle"
+            />
+        </div>
+    );
+};
+
+export default RequestAdminPanel;
diff --git a/src/components/RequestBoard.css b/src/components/RequestBoard.css
new file mode 100644
index 0000000..0fbe1a9
--- /dev/null
+++ b/src/components/RequestBoard.css
@@ -0,0 +1,443 @@
+/* 容器和布局 */
+.request-container {
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 20px;
+}
+
+.request-header {
+    margin-bottom: 30px;
+    border-bottom: 1px solid #f0f0f0;
+    padding-bottom: 20px;
+}
+
+.request-search {
+    background-color: #fff8f0;
+    border-radius: 10px;
+    padding: 20px;
+    margin-bottom: 30px;
+    box-shadow: 0 4px 12px rgba(255, 102, 0, 0.1);
+}
+
+.request-money-total {
+    background-color: #fff1e6;
+    border-radius: 8px;
+    padding: 10px 15px;
+    display: inline-block;
+    font-size: 16px;
+}
+
+/* 卡片样式 */
+.request-card {
+    background-color: white;
+    border-radius: 12px;
+    padding: 20px;
+    margin-bottom: 20px;
+    box-shadow: 0 4px 15px rgba(255, 102, 0, 0.08);
+    transition: all 0.3s ease;
+    border: 1px solid #ffe8d6;
+}
+
+.request-card:hover {
+    transform: translateY(-5px);
+    box-shadow: 0 10px 25px rgba(255, 102, 0, 0.15);
+}
+
+.request-card-title {
+    font-size: 18px;
+    font-weight: 700;
+    color: #d15700;
+    margin-bottom: 8px;
+}
+
+.request-card-money {
+    font-size: 20px;
+    font-weight: 800;
+    color: #ff5722;
+    letter-spacing: 0.5px;
+}
+
+.request-card-content {
+    color: #555;
+    line-height: 1.6;
+    margin: 15px 0;
+    padding: 15px;
+    background-color: #f9f9f9;
+    border-radius: 8px;
+    border-left: 4px solid #ffaa33;
+}
+
+.request-card-meta {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+    margin: 15px 0;
+    padding: 10px 0;
+    border-top: 1px dashed #ffe0b3;
+    border-bottom: 1px dashed #ffe0b3;
+    font-size: 14px;
+}
+
+.request-meta-item {
+    display: flex;
+    align-items: center;
+    gap: 5px;
+}
+
+.request-meta-label {
+    font-weight: 600;
+    color: #ff8d00;
+}
+
+.request-card-image-container {
+    margin: 15px 0;
+}
+
+.request-card-image {
+    max-width: 300px;
+    border-radius: 8px;
+    border: 1px solid #ffd8b3;
+    box-shadow: 0 4px 8px rgba(255, 140, 0, 0.15);
+}
+
+/* 用户信息 - 重点修改 */
+.request-user-info-container {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+    padding: 10px;
+    background-color: #fffaf0;
+    border-radius: 10px;
+    box-shadow: 0 2px 8px rgba(255, 140, 0, 0.1);
+    min-width: 140px;
+}
+
+.request-user-divider {
+    height: 1px;
+    width: 100%;
+    background-color: #ffd8b3;
+    margin: 4px 0;
+}
+
+.request-user-info {
+    padding: 5px;
+}
+
+.request-user-details {
+    min-width: 60px;
+    overflow: hidden;
+}
+
+/* 按钮样式 */
+.request-button {
+    padding: 10px 16px;
+    border: none;
+    border-radius: 8px;
+    font-weight: 600;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+}
+
+.request-button:hover {
+    transform: translateY(-2px);
+}
+
+.request-button-back {
+    background-color: #f5f5f5;
+    color: #666;
+}
+
+.request-button-back:hover {
+    background-color: #e0e0e0;
+}
+
+.request-button-create {
+    background: linear-gradient(135deg, #ffa500, #ff7043);
+    color: white;
+    box-shadow: 0 4px 10px rgba(255, 140, 0, 0.3);
+}
+
+.request-button-create:hover {
+    background: linear-gradient(135deg, #ff8c00, #ff5722);
+    box-shadow: 0 6px 14px rgba(255, 140, 0, 0.4);
+}
+
+.request-button-search {
+    background: linear-gradient(135deg, #4db6ac, #26a69a);
+    color: white;
+    box-shadow: 0 4px 10px rgba(77, 182, 172, 0.3);
+}
+
+.request-button-search:hover {
+    background: linear-gradient(135deg, #26a69a, #00897b);
+}
+
+.request-button-submit {
+    background: linear-gradient(135deg, #ffa726, #fb8c00);
+    color: white;
+    padding: 12px 30px;
+    font-size: 16px;
+    box-shadow: 0 4px 12px rgba(255, 140, 0, 0.4);
+}
+
+.request-button-submit:hover {
+    background: linear-gradient(135deg, #fb8c00, #f57c00);
+}
+
+.request-button-takeover {
+    background: linear-gradient(135deg, #42a5f5, #1e88e5);
+    color: white;
+    box-shadow: 0 4px 10px rgba(66, 165, 245, 0.3);
+    width: 100%;
+    font-size: 13px;
+    padding: 8px 12px;
+}
+
+.request-button-takeover:hover {
+    background: linear-gradient(135deg, #1e88e5, #1565c0);
+}
+
+.request-button-delete {
+    background: linear-gradient(135deg, #ef5350, #e53935);
+    color: white;
+    box-shadow: 0 4px 10px rgba(239, 83, 80, 0.3);
+    font-size: 13px;
+    padding: 8px 12px;
+}
+
+.request-button-delete:hover {
+    background: linear-gradient(135deg, #e53935, #c62828);
+}
+
+/* 标签页 */
+.request-tab {
+    padding: 8px 16px;
+    border-radius: 20px;
+    background-color: #f1f1f1;
+    border: 1px solid #e0e0e0;
+    font-weight: 600;
+    color: #666;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    font-size: 13px;
+}
+
+.request-tab-active {
+    background: linear-gradient(135deg, #ffb74d, #ff9800);
+    color: white;
+    border-color: #ff9800;
+    box-shadow: 0 4px 8px rgba(255, 152, 0, 0.2);
+}
+
+/* 表单元素 */
+.request-form {
+    background-color: #fffaf5;
+    border-radius: 12px;
+    padding: 25px;
+    box-shadow: 0 5px 15px rgba(255, 140, 0, 0.1);
+    margin-top: 20px;
+}
+
+.request-label {
+    display: block;
+    margin-bottom: 8px;
+    font-weight: 600;
+    color: #ff8d00;
+    font-size: 14px;
+}
+
+.request-input {
+    width: 100%;
+    padding: 10px 12px;
+    border: 1px solid #ffd8b3;
+    border-radius: 8px;
+    font-size: 14px;
+    transition: all 0.3s ease;
+    background-color: #fffdfa;
+}
+
+.request-input:focus {
+    outline: none;
+    border-color: #ffaa33;
+    box-shadow: 0 0 0 3px rgba(255, 170, 51, 0.2);
+}
+
+.request-textarea {
+    width: 100%;
+    padding: 12px 15px;
+    border: 1px solid #ffd8b3;
+    border-radius: 8px;
+    min-height: 120px;
+    resize: vertical;
+    font-size: 14px;
+    background-color: #fffdfa;
+}
+
+.request-textarea:focus {
+    outline: none;
+    border-color: #ffaa33;
+    box-shadow: 0 0 0 3px rgba(255, 170, 51, 0.2);
+}
+
+.request-file {
+    width: 100%;
+    padding: 10px;
+    background: #f9f9f9;
+    border-radius: 8px;
+    font-size: 13px;
+}
+
+/* 空状态 */
+.request-empty {
+    text-align: center;
+    padding: 50px 20px;
+    background-color: white;
+    border-radius: 12px;
+    box-shadow: 0 4px 15px rgba(255, 102, 0, 0.08);
+}
+
+.request-empty-icon {
+    font-size: 48px;
+    color: #ffc107;
+    margin-bottom: 20px;
+}
+
+.request-empty-text {
+    font-size: 18px;
+    color: #ff8d00;
+    font-weight: 500;
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+    .request-container {
+        padding: 15px;
+    }
+
+    .request-card {
+        padding: 15px;
+    }
+
+    .request-header {
+        margin-bottom: 20px;
+    }
+
+    .request-card-title {
+        font-size: 16px;
+    }
+
+    .request-card-money {
+        font-size: 18px;
+    }
+
+    .request-user-info-container {
+        flex-direction: row;
+        flex-wrap: wrap;
+        gap: 10px;
+        min-width: 100%;
+        margin-top: 10px;
+    }
+
+    .request-user-info {
+        flex: 1;
+        min-width: 130px;
+    }
+
+    .request-user-divider {
+        display: none;
+    }
+
+    .request-card-actions {
+        flex-direction: column;
+        gap: 10px;
+    }
+
+    .request-button {
+        padding: 8px 12px;
+        font-size: 12px;
+    }
+
+    .request-button-takeover,
+    .request-button-delete {
+        font-size: 12px;
+    }
+
+    /* 在您的CSS文件中添加以下样式 */
+    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
+
+    body {
+        font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+        background-color: #fffaf5;
+    }
+
+    /* 全局动画效果 */
+    .transition {
+        transition: all 0.3s ease;
+    }
+
+    /* 卡片阴影效果 */
+    .shadow-lg {
+        box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
+    }
+
+    .shadow-md {
+        box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+    }
+
+    /* 圆角 */
+    .rounded-xl {
+        border-radius: 1rem;
+    }
+
+    .rounded-lg {
+        border-radius: 0.75rem;
+    }
+
+    /* 渐变背景 */
+    .bg-gradient-to-r {
+        background-size: 200% auto;
+        transition: background-position 0.5s ease;
+    }
+
+    .bg-gradient-to-r:hover {
+        background-position: right center;
+    }
+
+    /* 表单输入框动画 */
+    input:focus,
+    textarea:focus {
+        transform: translateY(-1px);
+    }
+
+    /* 卡片悬停效果 */
+    .bg-white:hover {
+        transform: translateY(-3px);
+    }
+
+    /* 响应式调整 */
+    @media (max-width: 768px) {
+        .text-xl {
+            font-size: 1.25rem;
+        }
+
+        .text-2xl {
+            font-size: 1.5rem;
+        }
+
+        .p-6 {
+            padding: 1.25rem;
+        }
+
+        .p-12 {
+            padding: 2rem;
+        }
+
+        .grid-cols-2 {
+            grid-template-columns: 1fr;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/components/RequestBoard.jsx b/src/components/RequestBoard.jsx
new file mode 100644
index 0000000..3e63482
--- /dev/null
+++ b/src/components/RequestBoard.jsx
@@ -0,0 +1,660 @@
+import React, { useState, useEffect } from 'react';
+import {
+    createRequest,
+    deleteRequest,
+    updateMoney,
+    findByUserid,
+    findByName,
+    getTotalMoneyByName,
+    updateLoaduserByName,
+    getAllRequests
+} from '../api/request';
+import { useSetState } from '@mantine/hooks';
+import { useNavigate } from 'react-router-dom';
+import './RequestBoard.css';
+
+const RequestBoard = ({ currentUserId, onBack }) => {
+    const storedUser = localStorage.getItem('user');
+    //let currentUserId = null; // 初始化为 null
+
+    if (storedUser) {
+        try {
+            const parsedUser = JSON.parse(storedUser);
+            currentUserId = parsedUser.userid; // 直接赋值
+        } catch (error) {
+            console.error('解析用户数据失败:', error);
+            // 可以在这里处理 JSON 解析错误(如数据损坏)
+        }
+    } else {
+        console.log('用户未登录');
+    }
+
+    // 现在 currentUserId 可以在后续逻辑中使用
+    console.log('当前用户ID:', currentUserId);
+
+    const [requests, setRequests] = useState([]);
+    const [allRequests, setAllRequests] = useState([]);
+    const [searchedRequests, setSearchedRequests] = useState([]);
+    const [userInfos, setUserInfos] = useState({}); // 存储所有用户信息:{ userid: { username, avatar } }
+    const navigate = useNavigate();
+    const [formData, setFormData] = useState({
+        userid: currentUserId,
+        name: '',
+        plot: '',
+        money: '',
+        year: '',
+        country: '',
+        photo: null,
+    });
+    const [searchName, setSearchName] = useState('');
+    const [totalMoney, setTotalMoney] = useState(null);
+    const [viewMode, setViewMode] = useState('my');
+    const [showForm, setShowForm] = useState(false); // 控制表单折叠
+
+    // 获取用户信息的函数
+    const fetchUserInfo = async (userId) => {
+        try {
+            // 如果已经获取过该用户的信息,直接返回
+            if (userInfos[userId]) return;
+
+            const response = await fetch(`http://localhost:8080/user/getDecoration?userid=${userId}`);
+            if (response.ok) {
+                const data = await response.json();
+                if (data.success) {
+                    // 更新用户信息状态
+                    setUserInfos(prev => ({
+                        ...prev,
+                        [userId]: {
+                            username: data.data.username,
+                            avatar: data.data.image,
+                            decoration: data.data.decoration
+                        }
+                    }));
+                } else {
+                    console.error('获取用户信息失败:', data.message);
+                }
+            } else {
+                console.error('获取用户信息失败:', response.statusText);
+            }
+        } catch (error) {
+            console.error('获取用户信息出错:', error);
+        }
+    };
+
+    useEffect(() => {
+        loadUserRequests();
+        loadAllRequests();
+    }, [currentUserId]);
+
+    const loadUserRequests = async () => {
+        const data = await findByUserid(currentUserId);
+        setRequests(data);
+        // 为每个需求贴获取用户信息
+        data.forEach(request => {
+            fetchUserInfo(request.userid); // 获取创建者信息
+            if (request.loaduser) {
+                fetchUserInfo(request.loaduser); // 获取接管者信息
+            }
+        });
+    };
+
+    const loadAllRequests = async () => {
+        const data = await getAllRequests();
+        setAllRequests(data);
+        // 为每个需求贴获取用户信息
+        data.forEach(request => {
+            fetchUserInfo(request.userid); // 获取创建者信息
+            if (request.loaduser) {
+                fetchUserInfo(request.loaduser); // 获取接管者信息
+            }
+        });
+    };
+
+    // 处理搜索的需求贴
+    const processSearchedRequests = (data) => {
+        setSearchedRequests(data);
+        // 为每个需求贴获取用户信息
+        data.forEach(request => {
+            fetchUserInfo(request.userid); // 获取创建者信息
+            if (request.loaduser) {
+                fetchUserInfo(request.loaduser); // 获取接管者信息
+            }
+        });
+    };
+
+    const handleChange = (e) => {
+        const { name, value, files } = e.target;
+        setFormData((prev) => ({
+            ...prev,
+            [name]: files ? files[0] : value,
+        }));
+    };
+
+    const handleCreate = async (e) => {
+        e.preventDefault();
+        const fd = new FormData();
+        Object.entries(formData).forEach(([key, value]) => {
+            if (value !== '' && value !== null) fd.append(key, value);
+        });
+
+        const res = await createRequest(fd);
+        if (res.data === true) {
+            alert('创建成功');
+            setFormData(prev => ({
+                ...prev,
+                name: '',
+                plot: '',
+                money: '',
+                year: '',
+                country: '',
+                photo: null,
+            }));
+            setShowForm(false);
+            loadUserRequests();
+            loadAllRequests();
+        } else {
+            alert('创建失败');
+        }
+    };
+
+    const handleDelete = async (id) => {
+        if (window.confirm('确定要删除这个需求贴吗?')) {
+            await deleteRequest(id);
+            loadUserRequests();
+            loadAllRequests();
+        }
+    };
+
+    const handleUpdateMoney = async (id, newMoney) => {
+        if (!newMoney) return;
+        await updateMoney(id, newMoney);
+        loadUserRequests();
+    };
+
+    const handleSearch = async () => {
+        if (!searchName.trim()) {
+            alert('请输入搜索关键词');
+            return;
+        }
+        const data = await findByName(searchName);
+        const total = await getTotalMoneyByName(searchName);
+        setTotalMoney(total);
+        setViewMode('search');
+        processSearchedRequests(data);
+    };
+
+    const handleProcess = (request) => {
+        navigate(`/uploadfull/${request.requestid}`, {
+            state: {
+                requestid: request.requestid
+            },
+        });
+    };
+
+    const handleUploadLoaduser = async (name, requestid) => {
+        if (window.confirm(`确定要接管 "${name}" 的所有需求贴吗?`)) {
+            try {
+                await updateLoaduserByName(name, currentUserId);
+
+                alert('接管成功');
+                handleProcess({ requestid: requestid });
+                console.log(requestid);
+                loadUserRequests();
+                loadAllRequests();
+            } catch (error) {
+                alert('接管失败,请稍后重试');
+                console.error(error);
+            }
+        }
+    };
+
+    // 渲染用户信息展示
+    const renderUserInfo = (userId, prefix = '') => {
+        if (!userId) return null;
+
+        const userInfo = userInfos[userId];
+
+        return (
+            <div className="request-user-info">
+                <div className="flex items-center gap-2">
+                    <div className="request-user-avatar">
+                        {userInfo?.avatar ? (
+                            <img
+                                src={userInfo.avatar}
+                                alt={`${prefix}头像`}
+                                className="w-8 h-8 rounded-full object-cover border-2 border-orange-200 sm:w-6 sm:h-6"
+                            />
+                        ) : (
+                            <div className="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center text-gray-500 text-xs border-2 border-orange-200 sm:w-6 sm:h-6">
+                                {prefix.charAt(0)}
+                            </div>
+                        )}
+                    </div>
+                    <div className="request-user-details">
+                        <div className="text-xs sm:text-[11px] font-medium text-gray-600">
+                            {prefix}:
+                        </div>
+                        <div className="text-sm sm:text-xs font-medium text-orange-600 truncate max-w-[100px]">
+                            {userInfo?.username || `用户${userId}`}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        );
+    };
+
+    const renderActions = (request) => {
+        if (request.userid === currentUserId) {
+            return (
+                <div className="flex flex-col sm:flex-row gap-2 w-full">
+                    <div className="flex gap-2 flex-1">
+                        <input
+                            type="number"
+                            placeholder="新金额"
+                            onChange={(e) => handleUpdateMoney(request.requestid, e.target.value)}
+                            className="request-input flex-1 text-center py-1 sm:py-0"
+                        />
+                        <button
+                            onClick={() => handleDelete(request.requestid)}
+                            className="request-button request-button-delete"
+                        >
+                            删除
+                        </button>
+                    </div>
+                </div>
+            );
+        }
+        return (
+            <button
+                onClick={() => handleUploadLoaduser(request.name, request.requestid)}
+                className="request-button request-button-takeover"
+            >
+                接管任务
+            </button>
+        );
+    };
+
+    return (
+        <div className="request-container">
+            <div className="request-header">
+                <div className="flex flex-col lg:flex-row justify-between gap-4 mb-6">
+                    <h1 className="text-2xl font-bold text-orange-700 sm:text-xl">需求贴发布区</h1>
+                    <div className="flex flex-wrap gap-2">
+                        <button
+                            className={`request-tab ${viewMode === 'my' ? 'request-tab-active' : ''}`}
+                            onClick={() => setViewMode('my')}
+                        >
+                            我的需求贴
+                        </button>
+                        <button
+                            className={`request-tab ${viewMode === 'all' ? 'request-tab-active' : ''}`}
+                            onClick={() => setViewMode('all')}
+                        >
+                            所有需求贴
+                        </button>
+                        <button
+                            className="request-button request-button-back"
+                            onClick={onBack}
+                        >
+                            返回主页面
+                        </button>
+                        <button
+                            onClick={() => setShowForm(!showForm)}
+                            className="request-button request-button-create"
+                        >
+                            {showForm ? '收起表单' : '创建新需求贴'}
+                        </button>
+                    </div>
+                </div>
+
+                {/* 折叠表单 */}
+                {showForm && (
+                    <form className="request-form" onSubmit={handleCreate}>
+                        <h2 className="text-xl font-semibold text-orange-700 mb-4 sm:text-lg">发布新需求</h2>
+                        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+                            <div>
+                                <label className="request-label">需求标题 *</label>
+                                <input
+                                    name="name"
+                                    placeholder="请输入需求标题"
+                                    className="request-input"
+                                    value={formData.name}
+                                    onChange={handleChange}
+                                    required
+                                />
+                            </div>
+                            <div>
+                                <label className="request-label">所需金额 (¥) *</label>
+                                <input
+                                    name="money"
+                                    type="number"
+                                    placeholder="请输入金额"
+                                    className="request-input"
+                                    value={formData.money}
+                                    onChange={handleChange}
+                                    min="1"
+                                    required
+                                />
+                            </div>
+                        </div>
+
+                        <div className="mt-4">
+                            <label className="request-label">详细描述 *</label>
+                            <textarea
+                                name="plot"
+                                placeholder="请详细描述您的需求..."
+                                className="request-textarea"
+                                value={formData.plot}
+                                onChange={handleChange}
+                                required
+                            />
+                        </div>
+
+                        <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
+                            <div>
+                                <label className="request-label">年份</label>
+                                <input
+                                    name="year"
+                                    type="number"
+                                    placeholder="如:2023"
+                                    className="request-input"
+                                    value={formData.year}
+                                    onChange={handleChange}
+                                />
+                            </div>
+                            <div>
+                                <label className="request-label">国家/地区</label>
+                                <input
+                                    name="country"
+                                    placeholder="如:中国"
+                                    className="request-input"
+                                    value={formData.country}
+                                    onChange={handleChange}
+                                />
+                            </div>
+                            <div>
+                                <label className="request-label">相关图片</label>
+                                <input
+                                    name="photo"
+                                    type="file"
+                                    className="request-file"
+                                    onChange={handleChange}
+                                />
+                            </div>
+                        </div>
+
+                        <button
+                            type="submit"
+                            className="request-button request-button-submit mt-6"
+                        >
+                            发布需求贴
+                        </button>
+                    </form>
+                )}
+            </div>
+
+            {/* 搜索区域 */}
+            <div className="request-search">
+                <h2 className="text-xl font-semibold text-orange-700 mb-4 sm:text-lg">搜索需求贴</h2>
+                <div className="flex flex-col sm:flex-row gap-3">
+                    <input
+                        type="text"
+                        placeholder="输入需求标题关键词..."
+                        value={searchName}
+                        onChange={(e) => setSearchName(e.target.value)}
+                        className="request-input flex-1"
+                    />
+                    <button
+                        onClick={handleSearch}
+                        className="request-button request-button-search"
+                    >
+                        搜索需求
+                    </button>
+                </div>
+
+                {totalMoney !== null && viewMode === 'search' && (
+                    <div className="request-money-total mt-4">
+                        <span className="font-medium">"{searchName}" 需求总金额:</span>
+                        <span className="font-bold text-red-600 ml-2">¥{totalMoney}</span>
+                    </div>
+                )}
+            </div>
+
+            {/* 搜索结果 */}
+            {viewMode === 'search' && searchedRequests.length > 0 && (
+                <div className="request-results">
+                    <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-6 gap-3">
+                        <h2 className="text-xl font-semibold text-orange-700 sm:text-lg">
+                            搜索结果:<span className="text-orange-500">{searchedRequests.length}</span> 条需求
+                        </h2>
+                        <button
+                            onClick={() => setViewMode('my')}
+                            className="request-button request-button-back"
+                        >
+                            返回我的需求
+                        </button>
+                    </div>
+
+                    <div className="request-cards">
+                        {searchedRequests.map((request) => (
+                            <div key={request.requestid} className="request-card">
+                                <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
+                                    <div className="flex-1 min-w-0">
+                                        <h3 className="request-card-title">{request.name}</h3>
+                                        <div className="request-card-money">¥{request.money}</div>
+                                    </div>
+                                    <div className="request-user-info-container">
+                                        {renderUserInfo(request.userid, '创建者')}
+                                        {request.loaduser && (
+                                            <>
+                                                <div className="request-user-divider"></div>
+                                                {renderUserInfo(request.loaduser, '接管者')}
+                                            </>
+                                        )}
+                                    </div>
+                                </div>
+
+                                <div className="request-card-content">
+                                    {request.plot}
+                                </div>
+
+                                <div className="request-card-meta">
+                                    {request.year && (
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">年份:</span>
+                                            <span>{request.year}</span>
+                                        </div>
+                                    )}
+                                    {request.country && (
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">地区:</span>
+                                            <span>{request.country}</span>
+                                        </div>
+                                    )}
+                                    <div className="request-meta-item">
+                                        <span className="request-meta-label">发布时间:</span>
+                                        <span>{new Date(request.requestTime).toLocaleString()}</span>
+                                    </div>
+                                </div>
+
+                                {request.photo && (
+                                    <div className="request-card-image-container">
+                                        <img
+                                            src={`http://localhost:8080${request.photo}`}
+                                            alt="需求贴配图"
+                                            className="request-card-image"
+                                        />
+                                    </div>
+                                )}
+
+                                <div className="request-card-actions">
+                                    {renderActions(request)}
+                                </div>
+                            </div>
+                        ))}
+                    </div>
+                </div>
+            )}
+
+            {/* 我的需求贴 */}
+            {viewMode === 'my' && (
+                <div className="request-my">
+                    <h2 className="text-xl font-semibold text-orange-700 mb-6 sm:text-lg">我的需求贴</h2>
+
+                    {requests.length === 0 ? (
+                        <div className="request-empty">
+                            <div className="request-empty-icon">📋</div>
+                            <p className="request-empty-text">您还没有发布任何需求贴</p>
+                            <button
+                                className="request-button request-button-create mt-4"
+                                onClick={() => {
+                                    setShowForm(true);
+                                    document.querySelector('.request-form')?.scrollIntoView({ behavior: 'smooth' });
+                                }}
+                            >
+                                立即发布需求
+                            </button>
+                        </div>
+                    ) : (
+                        <div className="request-cards">
+                            {requests.map((request) => (
+                                <div key={request.requestid} className="request-card">
+                                    <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
+                                        <div className="flex-1 min-w-0">
+                                            <h3 className="request-card-title">{request.name}</h3>
+                                            <div className="request-card-money">¥{request.money}</div>
+                                        </div>
+                                        <div className="request-user-info-container">
+                                            {renderUserInfo(request.userid, '创建者')}
+                                            {request.loaduser && (
+                                                <>
+                                                    <div className="request-user-divider"></div>
+                                                    {renderUserInfo(request.loaduser, '接管者')}
+                                                </>
+                                            )}
+                                        </div>
+                                    </div>
+
+                                    <div className="request-card-content">
+                                        {request.plot}
+                                    </div>
+
+                                    <div className="request-card-meta">
+                                        {request.year && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">年份:</span>
+                                                <span>{request.year}</span>
+                                            </div>
+                                        )}
+                                        {request.country && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">地区:</span>
+                                                <span>{request.country}</span>
+                                            </div>
+                                        )}
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">发布时间:</span>
+                                            <span>{new Date(request.requestTime).toLocaleString()}</span>
+                                        </div>
+                                    </div>
+
+                                    {request.photo && (
+                                        <div className="request-card-image-container">
+                                            <img
+                                                src={`http://localhost:8080${request.photo}`}
+                                                alt="需求贴配图"
+                                                className="request-card-image"
+                                            />
+                                        </div>
+                                    )}
+
+                                    <div className="request-card-actions">
+                                        {renderActions(request)}
+                                    </div>
+                                </div>
+                            ))}
+                        </div>
+                    )}
+                </div>
+            )}
+
+            {/* 所有需求贴 */}
+            {viewMode === 'all' && (
+                <div className="request-all">
+                    <div className="flex justify-between items-center mb-6">
+                        <h2 className="text-xl font-semibold text-orange-700 sm:text-lg">所有需求贴</h2>
+                        <span className="text-gray-600">共 {allRequests.length} 条需求</span>
+                    </div>
+
+                    {allRequests.length === 0 ? (
+                        <div className="request-empty">
+                            <div className="request-empty-icon">📭</div>
+                            <p className="request-empty-text">当前平台暂无需求贴</p>
+                        </div>
+                    ) : (
+                        <div className="request-cards">
+                            {allRequests.map((request) => (
+                                <div key={request.requestid} className="request-card">
+                                    <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
+                                        <div className="flex-1 min-w-0">
+                                            <h3 className="request-card-title">{request.name}</h3>
+                                            <div className="request-card-money">¥{request.money}</div>
+                                        </div>
+                                        <div className="request-user-info-container">
+                                            {renderUserInfo(request.userid, '创建者')}
+                                            {request.loaduser && (
+                                                <>
+                                                    <div className="request-user-divider"></div>
+                                                    {renderUserInfo(request.loaduser, '接管者')}
+                                                </>
+                                            )}
+                                        </div>
+                                    </div>
+
+                                    <div className="request-card-content">
+                                        {request.plot}
+                                    </div>
+
+                                    <div className="request-card-meta">
+                                        {request.year && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">年份:</span>
+                                                <span>{request.year}</span>
+                                            </div>
+                                        )}
+                                        {request.country && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">地区:</span>
+                                                <span>{request.country}</span>
+                                            </div>
+                                        )}
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">发布时间:</span>
+                                            <span>{new Date(request.requestTime).toLocaleString()}</span>
+                                        </div>
+                                    </div>
+
+                                    {request.photo && (
+                                        <div className="request-card-image-container">
+                                            <img
+                                                src={`http://localhost:8080${request.photo}`}
+                                                alt="需求贴配图"
+                                                className="request-card-image"
+                                            />
+                                        </div>
+                                    )}
+
+                                    <div className="request-card-actions">
+                                        {renderActions(request)}
+                                    </div>
+                                </div>
+                            ))}
+                        </div>
+                    )}
+                </div>
+            )}
+        </div>
+    );
+};
+
+export default RequestBoard;
\ No newline at end of file
diff --git a/src/components/Torrentdetail.jsx b/src/components/Torrentdetail.jsx
new file mode 100644
index 0000000..a955b7b
--- /dev/null
+++ b/src/components/Torrentdetail.jsx
@@ -0,0 +1,206 @@
+import React, { useEffect, useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom'; // 添加 useNavigate
+import axios from 'axios';
+import {
+  Row,
+  Col,
+  Card,
+  Descriptions,
+  Table,
+  Typography,
+  Spin,
+  Tag,
+  Button, // 添加 Button 组件
+} from 'antd';
+import { Image as AntdImage } from 'antd';
+import '../TorrentDetail.css'; // 引入样式
+
+const { Title, Text } = Typography;
+
+const TorrentDetail = () => {
+  const { id } = useParams();
+  const navigate = useNavigate(); // 获取导航函数
+  const [torrent, setTorrent] = useState(null);
+  const [seeders, setSeeders] = useState([]);
+  const [loading, setLoading] = useState(true);
+  const [torrentLoading, setTorrentLoading] = useState(true);
+  const [seedersLoading, setSeedersLoading] = useState(false);
+
+  useEffect(() => {
+    const fetchTorrentDetails = async () => {
+      try {
+        setTorrentLoading(true);
+        const torrentRes = await axios.get(`http://localhost:8080/torrent/${id}`);
+        setTorrent(torrentRes.data);
+
+        setSeedersLoading(true);
+        const seedersRes = await axios.get(`http://localhost:8080/torrent/${torrentRes.data.infoHash}/seeders`);
+        setSeeders(seedersRes.data);
+      } catch (err) {
+        console.error('获取数据失败', err);
+      } finally {
+        setTorrentLoading(false);
+        setSeedersLoading(false);
+        setLoading(false);
+      }
+    };
+
+    fetchTorrentDetails();
+  }, [id]);
+
+  const formatSize = (bytes) => {
+    if (bytes === 0) return '0 B';
+    const k = 1024;
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  const formatSpeed = (bytesPerSec) => {
+    if (bytesPerSec < 1024) return bytesPerSec.toFixed(2) + ' B/s';
+    if (bytesPerSec < 1024 * 1024) return (bytesPerSec / 1024).toFixed(2) + ' KB/s';
+    return (bytesPerSec / (1024 * 1024)).toFixed(2) + ' MB/s';
+  };
+
+  const columns = [
+    {
+      title: '用户名',
+      dataIndex: 'username',
+      key: 'username',
+      align: 'center',
+      render: (text) => <Tag color="orange">{text}</Tag>,
+    },
+    {
+      title: '已上传',
+      dataIndex: 'uploaded',
+      key: 'uploaded',
+      align: 'center',
+      render: (text) => <Text>{formatSize(text)}</Text>,
+    },
+    {
+      title: '上传速度',
+      dataIndex: 'uploadSpeed',
+      key: 'uploadSpeed',
+      align: 'center',
+      render: (text) => <Text>{formatSpeed(text)}</Text>,
+    },
+    {
+      title: '已下载',
+      dataIndex: 'downloaded',
+      key: 'downloaded',
+      align: 'center',
+      render: (text) => <Text>{formatSize(text)}</Text>,
+    },
+    {
+      title: '下载速度',
+      dataIndex: 'downloadSpeed',
+      key: 'downloadSpeed',
+      align: 'center',
+      render: (text) => text > 0 ? <Text>{formatSpeed(text)}</Text> : <Text>-</Text>,
+    },
+    {
+      title: '客户端',
+      dataIndex: 'client',
+      key: 'client',
+      align: 'center',
+    },
+    {
+      title: '最后活动',
+      dataIndex: 'lastEvent',
+      key: 'lastEvent',
+      align: 'center',
+    },
+  ];
+
+  if (loading) return <div className="page-wrapper"><Spin size="large" /></div>;
+
+  return (
+    <div className="page-wrapper">
+      {/* 添加返回按钮 */}
+      <div className="mb-4">
+        <Button 
+          type="primary" 
+          onClick={() => navigate(-1)} // 返回上一页
+          style={{ marginBottom: '16px' }}
+        >
+          返回列表
+        </Button>
+      </div>
+
+      <Row gutter={[16, 16]}>
+        <Col xs={24} md={8}>
+          <Card bordered={false} className="custom-card h-full">
+            {torrent.coverImagePath ? (
+              <AntdImage
+                src={torrent.coverImagePath}
+                alt="Torrent Cover"
+                className="w-full h-64 object-cover rounded"
+                placeholder={
+                  <div className="w-full h-64 flex items-center justify-center bg-gray-100">
+                    <Spin size="small" />
+                  </div>
+                }
+                preview={false}
+              />
+            ) : (
+              <div className="w-full h-64 flex items-center justify-center bg-gray-100 rounded">
+                <Text type="secondary">无封面图片</Text>
+              </div>
+            )}
+          </Card>
+        </Col>
+
+        <Col xs={24} md={16}>
+          <Card className="info-card">
+            <Title level={1} className="info-title">
+              {torrent?.torrentTitle || '加载中...'}
+            </Title>
+
+            <Descriptions
+              bordered
+              column={{ xs: 1, sm: 2 }}
+              size="middle"
+              className="custom-descriptions"
+              labelStyle={{ fontWeight: 'bold', color: '#a15c00', fontSize: '16px' }}
+              contentStyle={{ fontSize: '15px' }}
+            >
+              <Descriptions.Item label="简介">{torrent.description || '暂无简介'}</Descriptions.Item>
+              <Descriptions.Item label="上传人">{torrent.uploader_id || '未知用户'}</Descriptions.Item>
+              <Descriptions.Item label="上传时间">{new Date(torrent.uploadTime).toLocaleString()}</Descriptions.Item>
+              <Descriptions.Item label="文件大小"><Text>{formatSize(torrent.torrentSize)}</Text></Descriptions.Item>
+              <Descriptions.Item label="下载数"><Text>{torrent.downloadCount || 0}</Text></Descriptions.Item>
+              <Descriptions.Item label="做种数"><Text>{seeders.length}</Text></Descriptions.Item>
+              <Descriptions.Item label="文件分辨率">{torrent.dpi || '未知'}</Descriptions.Item>
+              <Descriptions.Item label="文件字幕">{torrent.caption || '无'}</Descriptions.Item>
+              <Descriptions.Item label="最后做种时间">
+                {torrent.lastseed ? new Date(torrent.lastseed).toLocaleString() : '暂无'}
+              </Descriptions.Item>
+            </Descriptions>
+          </Card>
+        </Col>
+      </Row>
+
+      <Card className="custom-card mt-4">
+        <Title level={4} style={{ color: '#d46b08' }}>当前做种用户 ({seeders.length})</Title>
+        {seedersLoading ? (
+          <div className="p-4 text-center"><Spin size="small" /></div>
+        ) : seeders.length > 0 ? (
+          <Table
+            columns={columns}
+            dataSource={seeders}
+            rowKey={(record, index) => index}
+            pagination={false}
+            size="small"
+            className="custom-table"
+          />
+        ) : (
+          <div className="p-4 text-center text-gray-500 bg-gray-50 rounded">
+            当前没有用户在做种
+          </div>
+        )}
+      </Card>
+    </div>
+  );
+};
+
+export default TorrentDetail;
\ No newline at end of file
diff --git a/src/components/chat.css b/src/components/chat.css
new file mode 100644
index 0000000..b02d961
--- /dev/null
+++ b/src/components/chat.css
@@ -0,0 +1,216 @@
+/* chat.css */
+.chatbox-container {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    background: #fafafa;
+    border: 1px solid #d9d9d9;
+    border-radius: 10px;
+    overflow: hidden;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.chatbox-header {
+    padding: 16px;
+    background-color: #f0f5ff;
+    border-bottom: 1px solid #adc6ff;
+    text-align: center;
+}
+
+.chatbox-content {
+    flex: 1;
+    padding: 16px;
+    background-color: #fff;
+    overflow-y: auto;
+    scrollbar-width: thin;
+    scrollbar-color: #91d5ff transparent;
+}
+
+.chatbox-content::-webkit-scrollbar {
+    width: 8px;
+}
+
+.chatbox-content::-webkit-scrollbar-thumb {
+    background-color: #91d5ff;
+    border-radius: 4px;
+}
+
+.chatbox-content::-webkit-scrollbar-track {
+    background: transparent;
+}
+
+.no-messages {
+    color: #999;
+    text-align: center;
+    margin-top: 40px;
+    font-size: 14px;
+}
+
+.chat-message {
+    display: flex;
+    align-items: flex-end;
+    margin-bottom: 10px;
+    gap: 8px;
+    max-width: 100%;
+}
+
+.chat-message.sender {
+    justify-content: flex-end;
+}
+
+.chat-message.receiver {
+    justify-content: flex-start;
+}
+
+.message-bubble-wrapper {
+    max-width: 75%;
+}
+
+.message-bubble {
+    padding: 10px 14px;
+    border-radius: 14px;
+    font-size: 14px;
+    word-break: break-word;
+    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
+}
+
+.chat-message.sender .message-bubble {
+    background-color: #69c0ff;
+    color: #fff;
+    border-bottom-right-radius: 0;
+}
+
+.chat-message.receiver .message-bubble {
+    background-color: #e6f7ff;
+    color: #000;
+    border-bottom-left-radius: 0;
+}
+
+.message-time {
+    font-size: 10px;
+    color: #666;
+    margin-top: 4px;
+    text-align: right;
+}
+
+.avatar {
+    flex-shrink: 0;
+    user-select: none;
+    box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
+}
+
+.chatbox-footer {
+    display: flex;
+    padding: 12px;
+    border-top: 1px solid #f0f0f0;
+    background-color: #fff;
+    gap: 8px;
+    align-items: flex-end;
+}
+
+.chat-input {
+    flex: 1;
+    border-radius: 8px;
+    resize: none;
+}
+
+.send-btn {
+    min-width: 80px;
+    border-radius: 8px;
+    height: 44px;
+}
+
+.emoji-btn {
+    background: white;
+    border: none;
+    padding: 6px;
+    border-radius: 8px;
+    color: #666;
+    font-size: 18px;
+    cursor: pointer;
+    height: 44px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.emoji-btn:hover {
+    background-color: #f0f0f0;
+    color: #333;
+}
+
+.emoji-picker {
+    display: grid;
+    grid-template-columns: repeat(8, 1fr);
+    gap: 6px;
+    padding: 10px;
+    width: 280px;
+    max-height: 260px;
+    overflow-y: auto;
+}
+
+.emoji-item {
+    font-size: 20px;
+    padding: 4px;
+    cursor: pointer;
+    text-align: center;
+    transition: all 0.2s ease;
+}
+
+.emoji-item:hover {
+    transform: scale(1.2);
+    background: #f0f9ff;
+    border-radius: 4px;
+}
+
+.emoji-popover .ant-popover-inner {
+    padding: 0;
+    border-radius: 8px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.emoji-popover .ant-popover-title {
+    padding: 8px;
+    border-bottom: 1px solid #f0f0f0;
+    font-weight: bold;
+    background-color: #f9f9f9;
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+    .chatbox-container {
+        border-radius: 0;
+        border: none;
+    }
+
+    .chatbox-header {
+        padding: 12px;
+    }
+
+    .chatbox-content {
+        padding: 12px;
+    }
+
+    .message-bubble-wrapper {
+        max-width: 85%;
+    }
+
+    .chatbox-footer {
+        padding: 8px;
+        gap: 6px;
+    }
+
+    .emoji-picker {
+        width: 240px;
+        grid-template-columns: repeat(7, 1fr);
+    }
+
+    .send-btn {
+        min-width: 60px;
+        height: 40px;
+    }
+
+    .emoji-btn {
+        height: 40px;
+    }
+}
\ No newline at end of file
diff --git a/src/components/torrentdetailcomplain.jsx b/src/components/torrentdetailcomplain.jsx
new file mode 100644
index 0000000..10bbd62
--- /dev/null
+++ b/src/components/torrentdetailcomplain.jsx
@@ -0,0 +1,346 @@
+import React, { useState, useEffect } from 'react';
+import { useParams, useNavigate, useLocation  } from 'react-router-dom';
+import { useSearchParams } from 'react-router-dom';
+import {
+  Descriptions,
+  Table,
+  Button,
+  Modal,
+  Image,
+  message,
+  Spin,
+  Input,
+  Select,
+  Pagination,
+  Space,
+  Card
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import axios from 'axios';
+
+const { confirm } = Modal;
+const { Option } = Select;
+
+//const { confirm } = Modal;
+
+const TorrentDetailcomplain = () => {
+  const { id } = useParams(); // 从URL获取种子ID
+  const navigate = useNavigate(); // 用于返回上一页
+  const [torrent, setTorrent] = useState(null);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [isLoading, setIsLoading] = useState(false);
+  //const [searchParams] = useSearchParams();
+  const location = useLocation(); // 添加这行获取location对象
+  // 在组件状态中添加
+  // 获取参数并设置默认值
+  //const [manageId, setManageId] = useState(parseInt(searchParams.get('manageid')) || 1);
+ // 正确从location.state获取参数
+  const { duser, torrentid } = location.state || {};
+  const [rewardUserId, setRewardUserId] = useState(duser);
+  const [creditAmount, setCreditAmount] = useState(3);
+  const [torrentId, setTorrentId] = useState(torrentid); // 使用state中的torrentid或URL中的id
+
+  console.log('Torrent ID:', torrentId); // 调试输出
+  console.log('Reward User ID:', rewardUserId); // 调试输出
+  const currentUserId = 1; // 示例,实际应从认证系统获取
+
+
+  // 格式化日期
+  const formatDate = (dateString) => {
+    if (!dateString) return '未知';
+    const date = new Date(dateString);
+    return date.toLocaleString('zh-CN', {
+      year: 'numeric',
+      month: '2-digit',
+      day: '2-digit',
+      hour: '2-digit',
+      minute: '2-digit'
+    });
+  };
+
+  // 处理删除种子
+  const handleDeleteTorrent = async (torrentId) => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+
+    confirm({
+      title: '确认删除',
+      icon: <ExclamationCircleOutlined />,
+      content: '确定要删除这个种子吗?此操作不可恢复!',
+      onOk: async () => {
+        try {
+          await axios.delete(`http://localhost:8080/torrent/delete/${torrentId}`, {
+            params: { userid: currentUserId }
+          });
+          // 成功删除后,更新状态或返回上一页
+          setTorrent(null); // 清空当前种子详情
+          navigate(-1); // 返回上一页
+          message.success('种子删除成功');
+        } catch (err) {
+          console.error('删除种子失败', err);
+          if (err.response && err.response.status === 403) {
+            message.error('无权删除此种子');
+          } else {
+            message.error('删除种子失败');
+          }
+        }
+      }
+    });
+  };
+
+
+  const handleDownloadTorrent = async (torrentId) => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+
+    setIsLoading(true); // 开始加载
+    try {
+      // 使用axios发送带有参数的GET请求
+      // const response = await axios.get(`http://localhost:8080/torrent/download/${torrentId}`, {
+      //   params: { userId: currentUserId },  // 正确添加请求参数
+      //   responseType: 'blob'  // 重要:指定响应类型为blob以处理文件下载
+      // });
+
+      // // 创建下载链接
+      // const url = window.URL.createObjectURL(new Blob([response.data]));
+      // const link = document.createElement('a');
+      // link.href = url;
+      // //link.setAttribute('download', 'torrent_file.torrent');  // 可以设置为动态文件名
+      // document.body.appendChild(link);
+      // link.click();
+      // document.body.removeChild(link);
+      // window.URL.revokeObjectURL(url);
+      open(`http://localhost:8080/torrent/download/${torrentId}?userId=${currentUserId}`, '_blank');
+
+      message.success('种子下载开始');
+    } catch (err) {
+      console.error('下载种子失败', err);
+      if (err.response?.status === 404) {
+        message.error('种子不存在');
+      } else {
+        message.error('下载失败: ' + (err.response?.data?.message || err.message));
+      }
+    } finally {
+      setIsLoading(false); // 结束加载
+    }
+  };
+
+
+  // 格式化文件大小
+  const formatFileSize = (bytes) => {
+    if (bytes === 0) return '0 Bytes';
+    const k = 1024;
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  // 在组件函数内部添加这个函数
+  const getPromotionName = (promotionId) => {
+    const promotionMap = {
+      1: '上传加倍',
+      2: '下载减半',
+      3: '免费下载',
+      0: '无促销'
+    };
+
+    return promotionMap[promotionId] || '未知促销';
+  };
+
+  // 获取种子详情
+  useEffect(() => {
+    const fetchTorrentDetail = async () => {
+      try {
+        const response = await axios.get(`http://localhost:8080/torrent/${torrentId}`);
+        if (response.status === 200) {
+          setTorrent(response.data);
+        } else {
+          setError('获取种子详情失败');
+        }
+      } catch (err) {
+        console.error('获取种子详情失败:', err);
+        if (err.response) {
+          if (err.response.status === 404) {
+            setError('种子不存在');
+          } else {
+            setError('获取种子详情失败: ' + err.response.data);
+          }
+        } else {
+          setError('网络错误,请稍后重试');
+        }
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchTorrentDetail();
+  }, [id]);
+
+  // 奖励保种积分处理函数(修正版)
+  const handleAddCredit = async (torrentId) => {
+    if (!currentUserId) { // 需要定义manageUserId
+      message.warning('缺少必要权限');
+      return;
+    }
+
+    setIsLoading(true);
+    try {
+      const params = new URLSearchParams();
+      params.append('manageid', currentUserId);
+      params.append('userid', rewardUserId);
+      params.append('credit', creditAmount);
+
+      const response = await axios.post(`http://localhost:8080/torrent/deducecredit`, params.toString(), {
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded'
+        }
+      });
+
+      if (response.data.success !== false) {
+        message.success(`成功扣除 ${creditAmount} 保种积分`);
+      } else {
+        message.error(response.data.message || '奖励积分失败');
+      }
+    } catch (err) {
+      console.error('奖励积分失败', err);
+      if (err.response?.status === 500) {
+        message.error('服务器错误: ' + (err.response.data?.message || '未知错误'));
+      } else {
+        message.error('奖励积分失败: ' + (err.response?.data?.message || err.message));
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  console.log('Torrent Detail:', torrent);
+
+  // 返回上一页
+  const handleBack = () => {
+    navigate(-1); // 返回上一页
+  };
+
+  // 如果正在加载
+  if (loading) {
+    return (
+      <div className="flex justify-center items-center h-96">
+        <Spin size="large" tip="加载中..." />
+      </div>
+    );
+  }
+
+  // 如果有错误
+  if (error) {
+    return (
+      <div className="p-6">
+        <Card>
+          <div className="text-center p-6">
+            <ExclamationCircleOutlined className="text-2xl text-red-500 mb-4" />
+            <h3 className="text-lg font-medium text-red-600 mb-2">错误</h3>
+            <p className="text-gray-600">{error}</p>
+            <Button type="primary" onClick={handleBack} className="mt-4">
+              返回
+            </Button>
+          </div>
+        </Card>
+      </div>
+    );
+  }
+
+  // 如果种子不存在
+  if (!torrent) {
+    return (
+      <div className="p-6">
+        <Card>
+          <div className="text-center p-6">
+            <ExclamationCircleOutlined className="text-2xl text-yellow-500 mb-4" />
+            <h3 className="text-lg font-medium text-yellow-600 mb-2">种子不存在</h3>
+            <p className="text-gray-600">抱歉,您查找的种子不存在或已被删除。</p>
+            <Button type="primary" onClick={handleBack} className="mt-4">
+              返回
+            </Button>
+          </div>
+        </Card>
+      </div>
+    );
+  }
+
+  // 渲染种子详情
+  return (
+    <div className="p-6">
+      <Card
+        title="种子详情"
+        extra={
+          <Button type="primary" onClick={handleBack}>
+            返回列表
+          </Button>
+        }
+      >
+        {/* 使用Descriptions组件展示详情 */}
+        <Descriptions bordered column={1}>
+          <Descriptions.Item label="ID">{torrent.torrentid}</Descriptions.Item>
+          {/* 新增的封面图片展示 */}
+          {torrent.coverImagePath && (
+            <Descriptions.Item label="封面图片">
+              <Image
+                src={torrent.coverImagePath}
+                alt="种子封面"
+                width={200}  // 设置图片宽度
+                placeholder={
+                  <div className="w-48 h-32 bg-gray-200 flex items-center justify-center">
+                    加载中...
+                  </div>
+                }
+              />
+            </Descriptions.Item>
+          )}
+          <Descriptions.Item label="文件名">{torrent.filename}</Descriptions.Item>
+          <Descriptions.Item label="大小">{formatFileSize(torrent.torrentSize)}</Descriptions.Item>
+          <Descriptions.Item label="上传者ID">{torrent.uploader_id}</Descriptions.Item>
+          <Descriptions.Item label="上传时间">{formatDate(torrent.uploadTime)}</Descriptions.Item>
+          <Descriptions.Item label="下载次数">{torrent.downloadCount}</Descriptions.Item>
+          <Descriptions.Item label="促销">
+            {getPromotionName(torrent.promotionid)}
+          </Descriptions.Item>
+          <Descriptions.Item label="描述">
+            {torrent.description || '无描述'}
+          </Descriptions.Item>
+        </Descriptions>
+
+
+        {/* 操作按钮区域 */}
+        <div className="mt-6 flex justify-end space-x-4">
+          <Button
+            danger
+            onClick={() => handleDeleteTorrent(torrent.torrentid)}
+            loading={isLoading}
+          >
+            删除
+          </Button>
+          <Button
+            type="primary"
+            onClick={() => handleDownloadTorrent(torrent.torrentid)}
+            loading={isLoading}
+          >
+            下载
+          </Button>
+          {/* 新增的奖励保种积分按钮 */}
+          <Button
+            type="default"
+            onClick={() => handleAddCredit(torrent.torrentid)}
+            loading={isLoading}
+          >
+            扣除保种积分
+          </Button>
+        </div>
+      </Card>
+    </div>
+  );
+};
+
+export default TorrentDetailcomplain;
\ No newline at end of file
diff --git a/src/components/torrentdetailhelp.jsx b/src/components/torrentdetailhelp.jsx
new file mode 100644
index 0000000..8019e4c
--- /dev/null
+++ b/src/components/torrentdetailhelp.jsx
@@ -0,0 +1,353 @@
+import React, { useState, useEffect } from 'react';
+import { useParams, useNavigate, useLocation, useSearchParams } from 'react-router-dom'; // 添加 useLocation
+import {
+  Descriptions,
+  Table,
+  Button,
+  Modal,
+  Image,
+  message,
+  Spin,
+  Input,
+  Select,
+  Pagination,
+  Space,
+  Card
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import axios from 'axios';
+
+const { confirm } = Modal;
+const { Option } = Select;
+
+//const { confirm } = Modal;
+
+const TorrentDetailhelp = () => {
+   // 从URL获取种子ID
+  const navigate = useNavigate(); // 用于返回上一页
+  const [torrent, setTorrent] = useState(null);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [isLoading, setIsLoading] = useState(false);
+  const [searchParams] = useSearchParams();
+  // 在组件状态中添加
+  // 获取参数并设置默认值
+  //const [manageId, setManageId] = useState(parseInt(searchParams.get('manageid')) || 1);
+  // const [rewardUserId, setRewardUserId] = useState(parseInt(searchParams.get('userid')) || 1);
+  // const [creditAmount, setCreditAmount] = useState(parseInt(searchParams.get('credit')) || 1);
+  const location = useLocation();
+
+  // 从路由state获取参数(可能为空)
+  const { loaduser, money, torrentid, helpedid } = location.state || {};
+
+  // 设置默认值
+  const [rewardUserId, setUserId] = useState(loaduser || null);
+  const [creditAmount, setCreditAmount] = useState(money || 1); // 默认1积分
+  const [torrentId, setTorrentId] = useState(torrentid); // 默认值为路由传递的torrentid
+  const [helpedId, setHelpedId] = useState(helpedid || null); // 新增的帮助者ID
+
+
+  const currentUserId = 1; // 示例,实际应从认证系统获取
+
+
+  // 格式化日期
+  const formatDate = (dateString) => {
+    if (!dateString) return '未知';
+    const date = new Date(dateString);
+    return date.toLocaleString('zh-CN', {
+      year: 'numeric',
+      month: '2-digit',
+      day: '2-digit',
+      hour: '2-digit',
+      minute: '2-digit'
+    });
+  };
+
+  console.log("Helped ID:", helpedId);
+
+  // 处理删除种子
+  const handleDeleteTorrent = async (torrentId) => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+
+    confirm({
+      title: '确认删除',
+      icon: <ExclamationCircleOutlined />,
+      content: '确定要删除这个种子吗?此操作不可恢复!',
+      onOk: async () => {
+        try {
+          await axios.delete(`http://localhost:8080/torrent/delete/${torrentId}`, {
+            params: { userid: currentUserId }
+          });
+          // 成功删除后,更新状态或返回上一页
+          setTorrent(null); // 清空当前种子详情
+          navigate(-1); // 返回上一页
+          message.success('种子删除成功');
+        } catch (err) {
+          console.error('删除种子失败', err);
+          if (err.response && err.response.status === 403) {
+            message.error('无权删除此种子');
+          } else {
+            message.error('删除种子失败');
+          }
+        }
+      }
+    });
+  };
+
+
+  const handleDownloadTorrent = async (torrentId) => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+
+    setIsLoading(true); // 开始加载
+    try {
+      // 使用axios发送带有参数的GET请求
+      // const response = await axios.get(`http://localhost:8080/torrent/download/${torrentId}`, {
+      //   params: { userId: currentUserId },  // 正确添加请求参数
+      //   responseType: 'blob'  // 重要:指定响应类型为blob以处理文件下载
+      // });
+
+      // // 创建下载链接
+      // const url = window.URL.createObjectURL(new Blob([response.data]));
+      // const link = document.createElement('a');
+      // link.href = url;
+      // //link.setAttribute('download', 'torrent_file.torrent');  // 可以设置为动态文件名
+      // document.body.appendChild(link);
+      // link.click();
+      // document.body.removeChild(link);
+      // window.URL.revokeObjectURL(url);
+      open(`http://localhost:8080/torrent/download/${torrentId}?userId=${currentUserId}`, '_blank');
+
+      message.success('种子下载开始');
+    } catch (err) {
+      console.error('下载种子失败', err);
+      if (err.response?.status === 404) {
+        message.error('种子不存在');
+      } else {
+        message.error('下载失败: ' + (err.response?.data?.message || err.message));
+      }
+    } finally {
+      setIsLoading(false); // 结束加载
+    }
+  };
+
+
+  // 格式化文件大小
+  const formatFileSize = (bytes) => {
+    if (bytes === 0) return '0 Bytes';
+    const k = 1024;
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  // 在组件函数内部添加这个函数
+  const getPromotionName = (promotionId) => {
+    const promotionMap = {
+      1: '上传加倍',
+      2: '下载减半',
+      3: '免费下载',
+      0: '无促销'
+    };
+
+    return promotionMap[promotionId] || '未知促销';
+  };
+
+  // 获取种子详情
+  useEffect(() => {
+    const fetchTorrentDetail = async () => {
+      try {
+        const response = await axios.get(`http://localhost:8080/torrent/${torrentid}`);
+        if (response.status === 200) {
+          setTorrent(response.data);
+        } else {
+          setError('获取种子详情失败');
+        }
+      } catch (err) {
+        console.error('获取种子详情失败:', err);
+        if (err.response) {
+          if (err.response.status === 404) {
+            setError('种子不存在');
+          } else {
+            setError('获取种子详情失败: ' + err.response.data);
+          }
+        } else {
+          setError('网络错误,请稍后重试');
+        }
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchTorrentDetail();
+  }, [torrentid]);
+
+  // 奖励保种积分处理函数(修正版)
+  const handleAddCredit = async (torrentId) => {
+    if (!currentUserId) { // 需要定义manageUserId
+      message.warning('缺少必要权限');
+      return;
+    }
+
+    setIsLoading(true);
+    try {
+      const params = new URLSearchParams();
+      params.append('manageid', currentUserId);
+      params.append('userid', rewardUserId);
+      params.append('credit', creditAmount);
+      params.append('helpedId', helpedId);
+
+      const response = await axios.post(`http://localhost:8080/torrent/addcredit`, params.toString(), {
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded'
+        }
+      });
+
+      if (response.data.success !== false) {
+        message.success(`成功奖励 ${creditAmount} 保种积分`);
+      } else {
+        message.error(response.data.message || '奖励积分失败');
+      }
+    } catch (err) {
+      console.error('奖励积分失败', err);
+      if (err.response?.status === 500) {
+        message.error('服务器错误: ' + (err.response.data?.message || '未知错误'));
+      } else {
+        message.error('奖励积分失败: ' + (err.response?.data?.message || err.message));
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  console.log('Torrent Detail:', torrent);
+
+  // 返回上一页
+  const handleBack = () => {
+    navigate(-1); // 返回上一页
+  };
+
+  // 如果正在加载
+  if (loading) {
+    return (
+      <div className="flex justify-center items-center h-96">
+        <Spin size="large" tip="加载中..." />
+      </div>
+    );
+  }
+
+  // 如果有错误
+  if (error) {
+    return (
+      <div className="p-6">
+        <Card>
+          <div className="text-center p-6">
+            <ExclamationCircleOutlined className="text-2xl text-red-500 mb-4" />
+            <h3 className="text-lg font-medium text-red-600 mb-2">错误</h3>
+            <p className="text-gray-600">{error}</p>
+            <Button type="primary" onClick={handleBack} className="mt-4">
+              返回
+            </Button>
+          </div>
+        </Card>
+      </div>
+    );
+  }
+
+  // 如果种子不存在
+  if (!torrent) {
+    return (
+      <div className="p-6">
+        <Card>
+          <div className="text-center p-6">
+            <ExclamationCircleOutlined className="text-2xl text-yellow-500 mb-4" />
+            <h3 className="text-lg font-medium text-yellow-600 mb-2">种子不存在</h3>
+            <p className="text-gray-600">抱歉,您查找的种子不存在或已被删除。</p>
+            <Button type="primary" onClick={handleBack} className="mt-4">
+              返回
+            </Button>
+          </div>
+        </Card>
+      </div>
+    );
+  }
+
+  // 渲染种子详情
+  return (
+    <div className="p-6">
+      <Card
+        title="种子详情"
+        extra={
+          <Button type="primary" onClick={handleBack}>
+            返回列表
+          </Button>
+        }
+      >
+        {/* 使用Descriptions组件展示详情 */}
+        <Descriptions bordered column={1}>
+          <Descriptions.Item label="ID">{torrent.torrentid}</Descriptions.Item>
+          {/* 新增的封面图片展示 */}
+          {torrent.coverImagePath && (
+            <Descriptions.Item label="封面图片">
+              <Image
+                src={torrent.coverImagePath}
+                alt="种子封面"
+                width={200}  // 设置图片宽度
+                placeholder={
+                  <div className="w-48 h-32 bg-gray-200 flex items-center justify-center">
+                    加载中...
+                  </div>
+                }
+              />
+            </Descriptions.Item>
+          )}
+          <Descriptions.Item label="文件名">{torrent.filename}</Descriptions.Item>
+          <Descriptions.Item label="大小">{formatFileSize(torrent.torrentSize)}</Descriptions.Item>
+          <Descriptions.Item label="上传者ID">{torrent.uploader_id}</Descriptions.Item>
+          <Descriptions.Item label="上传时间">{formatDate(torrent.uploadTime)}</Descriptions.Item>
+          <Descriptions.Item label="下载次数">{torrent.downloadCount}</Descriptions.Item>
+          <Descriptions.Item label="促销">
+            {getPromotionName(torrent.promotionid)}
+          </Descriptions.Item>
+          <Descriptions.Item label="描述">
+            {torrent.description || '无描述'}
+          </Descriptions.Item>
+        </Descriptions>
+
+
+        {/* 操作按钮区域 */}
+        <div className="mt-6 flex justify-end space-x-4">
+          <Button
+            danger
+            onClick={() => handleDeleteTorrent(torrent.torrentid)}
+            loading={isLoading}
+          >
+            删除
+          </Button>
+          <Button
+            type="primary"
+            onClick={() => handleDownloadTorrent(torrent.torrentid)}
+            loading={isLoading}
+          >
+            下载
+          </Button>
+          {/* 新增的奖励保种积分按钮 */}
+          <Button
+            type="default"
+            onClick={() => handleAddCredit(torrent.torrentid)}
+            loading={isLoading}
+          >
+            奖励保种积分
+          </Button>
+        </div>
+      </Card>
+    </div>
+  );
+};
+
+export default TorrentDetailhelp;
\ No newline at end of file
diff --git a/src/components/torrentlist.jsx b/src/components/torrentlist.jsx
new file mode 100644
index 0000000..c760999
--- /dev/null
+++ b/src/components/torrentlist.jsx
@@ -0,0 +1,902 @@
+import { useState, useEffect } from 'react';
+import { Link } from 'react-router-dom';
+//import { Layout, Menu, Button, Radio,Input, } from 'antd';
+import { Layout, Input, Button, Radio, Spin, message, Modal, Pagination } from 'antd';
+const { Header, Content, Sider } = Layout;
+import '../filter.css';
+import '../torrentlist.css';
+import '../complain.css';
+import axios from 'axios';
+import Navbar from './Navbar';
+import {createComplain} from '../api/complain'; // 假设举报API在这个路径
+
+// 常量配置集中管理
+const FILTER_OPTIONS = {
+  // 通用选项
+  common: {
+    resolution: [
+      { value: '720p', label: '720p' },
+      { value: '1080p', label: '1080p' },
+      { value: '2K', label: '2K' },
+      { value: '4K', label: '4K' },
+      { value: '8K', label: '8K' },
+      { value: '其他', label: '其他' },
+    ],
+    region: {
+      movie: [
+        { value: '大陆', label: '大陆' },
+        { value: '港台', label: '港台' },
+        { value: '欧美', label: '欧美' },
+        { value: '日韩', label: '日韩' },
+        { value: '其他', label: '其他' },
+      ],
+      variety: [
+        { value: '大陆', label: '大陆' },
+        { value: '港台', label: '港台' },
+        { value: '欧美', label: '欧美' },
+        { value: '日韩', label: '日韩' },
+        { value: '其他', label: '其他' },
+      ],
+      sports: [
+        { value: '亚洲', label: '亚洲' },
+        { value: '欧洲', label: '欧洲' },
+        { value: '美洲', label: '美洲' },
+        { value: '其他', label: '其他' },
+      ]
+    },
+    genre: {
+      movie: [
+        { value: '动作', label: '动作' },
+        { value: '喜剧', label: '喜剧' },
+        { value: '爱情', label: '爱情' },
+        { value: '科幻', label: '科幻' },
+        { value: '恐怖', label: '恐怖' },
+        { value: '冒险', label: '冒险' },
+        { value: '历史', label: '历史' },
+        { value: '悬疑', label: '悬疑' },
+        { value: '其他', label: '其他' },
+      ],
+      music: [
+        { value: '流行', label: '流行' },
+        { value: '摇滚', label: '摇滚' },
+        { value: '电子', label: '电子' },
+        { value: '古典', label: '古典' },
+        { value: '爵士', label: '爵士' },
+        { value: '民谣', label: '民谣' },
+        { value: '说唱', label: '说唱' },
+        { value: '其他', label: '其他' },
+      ],
+      anime: [
+        { value: '新番连载', label: '新番连载' },
+        { value: '剧场版', label: '剧场版' },
+        { value: 'OVA', label: 'OVA' },
+        { value: '完结动漫', label: '完结动漫' },
+        { value: '其他', label: '其他' },
+      ],
+      game: [
+        { value: '角色扮演', label: '角色扮演' },
+        { value: '射击', label: '射击' },
+        { value: '冒险', label: '冒险' },
+        { value: '策略', label: '策略' },
+        { value: '体育', label: '体育' },
+        { value: '桌面游戏', label: '桌面游戏' },
+        { value: '其他', label: '其他' },
+      ],
+      variety: [
+        { value: '真人秀', label: '真人秀' },
+        { value: '选秀', label: '选秀' },
+        { value: '访谈', label: '访谈' },
+        { value: '音乐', label: '音乐' },
+        { value: '游戏', label: '游戏' },
+        { value: '其他', label: '其他' },
+      ],
+      learning: [
+        { value: '计算机', label: '计算机' },
+        { value: '软件', label: '软件' },
+        { value: '人文', label: '人文' },
+        { value: '外语', label: '外语' },
+        { value: '理工科', label: '理工科' },
+        { value: '其他', label: '其他' },
+      ],
+      sports: [
+        { value: '足球', label: '足球' },
+        { value: '篮球', label: '篮球' },
+        { value: '网球', label: '网球' },
+        { value: '乒乓球', label: '乒乓球' },
+        { value: '羽毛球', label: '羽毛球' },
+        { value: '其他', label: '其他' },
+      ],
+      // 其他类型...
+    }
+  },
+
+  // 分类特定选项
+  categories: {
+    1: { // 电影
+      name: '电影',
+      filters: [
+        { id: 'resolution', label: '分辨率', type: 'select' },
+        {
+          id: 'codec_format', label: '编码格式', type: 'select',
+          options: [
+            { value: 'H.264', label: 'H.264' },
+            { value: 'H.265', label: 'H.265' },
+            { value: 'AV1', label: 'AV1' },
+            { value: 'VC1', label: 'VC1' },
+            { value: 'X264', label: 'X264' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        { id: 'region', label: '地区', type: 'select' },
+        { id: 'genre', label: '类型', type: 'select' }
+      ]
+    },
+    2: { // 电视剧
+      name: '剧集',
+      filters: [
+        {
+          id: 'region', label: '地区', type: 'select',
+          options: [
+            { value: '大陆', label: '大陆' },
+            { value: '港台', label: '港台' },
+            { value: '欧美', label: '欧美' },
+            { value: '日韩', label: '日韩' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '分辨率', type: 'select',
+          options: [
+            { value: '720p', label: '720p' },
+            { value: '1080p', label: '1080p' },
+            { value: '2K', label: '2K' },
+            { value: '4K', label: '4K' },
+            { value: '8K', label: '8K' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '真人秀', label: '真人秀' },
+            { value: '选秀', label: '选秀' },
+            { value: '访谈', label: '访谈' },
+            { value: '游戏', label: '游戏' },
+            { value: '音乐', label: '音乐' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    3: { // 音乐
+      name: '音乐',
+      filters: [
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '专辑', label: '专辑' },
+            { value: '单曲', label: '单曲' },
+            { value: 'EP', label: 'EP' },
+            { value: '现场', label: '现场' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'style', label: '风格', type: 'select',
+          options: [
+            { value: '流行', label: '流行' },
+            { value: '摇滚', label: '摇滚' },
+            { value: '电子', label: '电子' },
+            { value: '古典', label: '古典' },
+            { value: '爵士', label: '爵士' },
+            { value: '民谣', label: '民谣' },
+            { value: '说唱', label: '说唱' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '格式', type: 'select',
+          options: [
+            { value: 'MP3', label: 'MP3' },
+            { value: 'FLAC', label: 'FLAC' },
+            { value: 'WAV', label: 'WAV' },
+            { value: 'AAC', label: 'AAC' },
+            { value: 'OGG', label: 'OGG' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    4: { // 动漫
+      name: '动漫',
+      filters: [
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '新番连载', label: '新番连载' },
+            { value: '剧场版', label: '剧场版' },
+            { value: 'OVA', label: 'OVA' },
+            { value: '完结动漫', label: '完结动漫' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '格式', type: 'select',
+          options: [
+            { value: 'ZIP', label: 'ZIP' },
+            { value: 'RAR', label: 'RAR' },
+            { value: '7Z', label: '7Z' },
+            { value: 'MKV', label: 'MKV' },
+            { value: 'MP4', label: 'MP4' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'resolution', label: '分辨率', type: 'select',
+          options: [
+            { value: '720p', label: '720p' },
+            { value: '1080p', label: '1080p' },
+            { value: '2K', label: '2K' },
+            { value: '4K', label: '4K' },
+            { value: '8K', label: '8K' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    5: { // 游戏
+      name: '游戏',
+      filters: [
+        {
+          id: 'platform', label: '平台', type: 'select',
+          options: [
+            { value: 'PC', label: 'PC' },
+            { value: 'PS5', label: 'PS5' },
+            { value: 'Xbox', label: 'Xbox' },
+            { value: 'Switch', label: 'Switch' },
+            { value: '手机', label: '手机' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '角色扮演', label: '角色扮演' },
+            { value: '射击', label: '射击' },
+            { value: '冒险', label: '冒险' },
+            { value: '策略', label: '策略' },
+            { value: '体育', label: '体育' },
+            { value: '桌面游戏', label: '桌面游戏' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'data_format', label: '数据类型', type: 'select',
+          options: [
+            { value: '压缩包', label: '压缩包' },
+            { value: '补丁', label: '补丁' },
+            { value: '安装包', label: '安装包' },
+            { value: 'nds', label: 'nds' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'language', label: '语言', type: 'select',
+          options: [
+            { value: '中文', label: '中文' },
+            { value: '英文', label: '英文' },
+            { value: '日文', label: '日文' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    6: { // 综艺
+      name: '综艺',
+      filters: [
+        {
+          id: 'is_mainland', label: '是否大陆综艺', type: 'select',
+          options: [
+            { value: 'true', label: '是' },
+            { value: 'false', label: ' 不是' },
+          ]
+        },
+        {
+          id: 'format', label: '分辨率', type: 'select',
+          options: [
+            { value: '720p', label: '720p' },
+            { value: '1080p', label: '1080p' },
+            { value: '2K', label: '2K' },
+            { value: '4K', label: '4K' },
+            { value: '8K', label: '8K' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '真人秀', label: '真人秀' },
+            { value: '选秀', label: '选秀' },
+            { value: '访谈', label: '访谈' },
+            { value: '游戏', label: '游戏' },
+            { value: '音乐', label: '音乐' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    7: { // 体育
+      name: '体育',
+      filters: [
+        {
+          id: 'genre', label: '体育类型', type: 'select',
+          options: [
+            { value: '足球', label: '足球' },
+            { value: '篮球', label: '篮球' },
+            { value: '网球', label: '网球' },
+            { value: '乒乓球', label: '乒乓球' },
+            { value: '羽毛球', label: '羽毛球' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'event_type', label: '赛事类型', type: 'select',
+          options: [
+            { value: '足球', label: '足球' },
+            { value: '篮球', label: '篮球' },
+            { value: '网球', label: '网球' },
+            { value: '乒乓球', label: '乒乓球' },
+            { value: '羽毛球', label: '羽毛球' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '分辨率', type: 'select',
+          options: [
+            { value: '720p', label: '720p' },
+            { value: '1080p', label: '1080p' },
+            { value: '2K', label: '2K' },
+            { value: '4K', label: '4K' },
+            { value: '8K', label: '8K' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    8: { // 软件
+      name: '软件',
+      filters: [
+        {
+          id: 'platform', label: '平台', type: 'select',
+          options: [
+            { value: 'Windows', label: 'Windows' },
+            { value: 'Mac', label: 'Mac' },
+            { value: 'Linux', label: 'Linux' },
+            { value: 'Android', label: 'Android' },
+            { value: 'iOS', label: 'iOS' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '格式', type: 'select',
+          options: [
+            { value: 'EXE', label: 'EXE' },
+            { value: 'DMG', label: 'DMG' },
+            { value: '光盘镜像', label: '光盘镜像' },
+            { value: 'APK', label: 'APK' },
+            { value: 'IPA', label: 'IPA' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '系统软件', label: '系统软件' },
+            { value: '应用软件', label: '应用软件' },
+            { value: '游戏软件', label: '游戏软件' },
+            { value: '驱动程序', label: '驱动程序' },
+            { value: '办公软件', label: '办公软件' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+      ]
+    },
+    9: { // 学习
+      name: '学习',
+      filters: [
+        {
+          id: 'genre', label: '类型', type: 'select',
+          options: [
+            { value: '计算机', label: '计算机' },
+            { value: '软件', label: '软件' },
+            { value: '人文', label: '人文' },
+            { value: '外语', label: '外语' },
+            { value: '理工科', label: '理工科' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '格式', type: 'select',
+          options: [
+            { value: 'PDF', label: 'PDF' },
+            { value: 'EPUB', label: 'EPUB' },
+            { value: '视频', label: '视频' },
+            { value: '音频', label: '音频' },
+            { value: 'PPT', label: 'PPT' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    10: { // 纪录片
+      name: '纪录片',
+      filters: [
+        {
+          id: 'source', label: '视频源', type: 'select',
+          options: [
+            { value: 'CCTV', label: 'CCTV' },
+            { value: '卫视', label: '卫视' },
+            { value: '国家地理', label: '国家地理' },
+            { value: 'BBC', label: 'BBC' },
+            { value: 'Discovery', label: 'Discovery' },
+            { value: '其他', label: '其他' },
+          ]
+        },
+        {
+          id: 'format', label: '格式', type: 'select',
+          options: [
+            { value: '720p', label: '720p' },
+            { value: '1080p', label: '1080p' },
+            { value: '2K', label: '2K' },
+            { value: '4K', label: '4K' },
+            { value: '8K', label: '8K' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    },
+    11: { // 其他
+      name: '其他',
+      filters: [
+        {
+          id: 'gener', label: '类型', type: 'select',
+          options: [
+            { value: '电子书', label: '电子书' },
+            { value: '视频', label: '视频' },
+            { value: 'MP3', label: 'MP3' },
+            { value: '图片', label: '图片' },
+            { value: '其他', label: '其他' },
+          ]
+        }
+      ]
+    }
+    // 其他分类配置...
+  }
+};
+
+
+
+function TorrentList() {
+  const [torrents, setTorrents] = useState([]);
+  const [categories, setCategories] = useState([]);
+  const [selectedCategory, setSelectedCategory] = useState("");
+  const [filters, setFilters] = useState({});
+  const [isLoading, setIsLoading] = useState(false);
+  const [error, setError] = useState(null);
+  //const userId = localStorage.getItem('userId'); // 假设用户ID存储在localStorage中
+  const userId = 1; // 确保是数字类型
+  const [usernames, setUsernames] = useState({});
+  const [searchKeyword, setSearchKeyword] = useState('');
+  // [新增] 分页相关状态
+  const [currentPage, setCurrentPage] = useState(1);  // 当前页码
+  const [itemsPerPage, setItemsPerPage] = useState(10);  // 每页显示的项目数
+  const [totalItems, setTotalItems] = useState(0);  // 确保这行存在
+const [isReportModalVisible, setIsReportModalVisible] = useState(false);
+const [currentTorrentId, setCurrentTorrentId] = useState(null);
+const [reportContent, setReportContent] = useState('');
+const [currentTorrent, setCurrentTorrent] = useState({});
+const[currentTorrentUploaderId, setCurrentTorrentUploaderId] = useState(null);
+  // 获取所有分类
+  useEffect(() => {
+    const fetchCategories = async () => {
+      try {
+        const res = await axios.get('http://localhost:8080/categories');
+        setCategories(res.data);
+      } catch (err) {
+        console.error('加载分类失败', err);
+        setError('加载分类失败,请稍后重试');
+      }
+    };
+    fetchCategories();
+  }, []);
+
+  
+// 获取分类筛选配置
+const getCategoryFilters = (categoryId) => {
+  
+  const category = FILTER_OPTIONS.categories[categoryId];
+  if (!category) return [];
+
+  return category.filters.map(filter => {
+    // 自动填充通用选项
+    if (filter.id === 'resolution' && !filter.options) {
+      return { ...filter, options: FILTER_OPTIONS.common.resolution };
+    }
+    if (filter.id === 'region' && !filter.options) {
+      const regionType = categoryId === 8 ? 'sports' : 'movie';
+      return { ...filter, options: FILTER_OPTIONS.common.region[regionType] };
+    }
+    if (filter.id === 'genre' && !filter.options) {
+      const genreType = categoryId === 3 ? 'music' : 'movie';
+      return { ...filter, options: FILTER_OPTIONS.common.genre[genreType] };
+    }
+    return filter;
+  });
+};
+
+// 显示举报模态框
+const showReportModal = (torrentId) => {
+  setCurrentTorrentId(torrentId);
+  setReportContent('');
+  setIsReportModalVisible(true);
+};
+
+// 处理举报提交
+const handleReportSubmit = async () => {
+  if (!reportContent.trim()) {
+    message.error('请输入举报内容');
+    return;
+  }
+
+  try {
+    const currentTorrentData = torrents.find(t => t.torrentid === currentTorrentId);
+    const duser = currentTorrentData ? currentTorrentData.uploader_id : null;
+    const complainData = {
+      puse: userId,  // 举报人ID
+      duser: duser,  // 被举报人ID
+      content: reportContent,
+      torrentid: currentTorrentId,
+      
+    };
+    console.log('举报数据:', complainData)
+
+    await createComplain(complainData);
+    message.success('举报提交成功');
+    setIsReportModalVisible(false);
+  } catch (error) {
+    console.error('举报提交失败:', error);
+    message.error('举报提交失败,请稍后重试');
+  }
+  };
+
+
+
+// 格式化日期显示
+const formatDate = (dateString) => {
+  const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' };
+  return new Date(dateString).toLocaleString('zh-CN', options);
+};
+
+// 获取促销方式名称
+const getPromotionName = (promotionId) => {
+  switch (promotionId) {
+    case 1: return '上传加倍';
+    case 2: return '下载免费';
+    case 3: return '下载减半';
+    default: return '没有促销';
+  }
+};
+
+  // 搜索种子
+  const handleSearch = async () => {
+    if (!searchKeyword.trim()) {
+      fetchAllTorrents();
+      return;
+    }
+
+    setIsLoading(true);
+    setError(null);
+    try {
+      const res = await axios.get(`http://localhost:8080/torrent/search`, {
+        params: { keyword: searchKeyword },
+      });
+      setTorrents(res.data);
+      //setCurrentPage(1); // 搜索后重置为第一页
+    } catch (err) {
+      console.error('搜索失败', err);
+      setError('搜索失败,请稍后重试');
+      message.error('搜索失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  // 获取种子数据
+  // [修改] 获取种子数据
+  useEffect(() => {
+    const fetchTorrents = async () => {
+      setIsLoading(true);
+      setError(null);
+      try {
+        let url = selectedCategory
+          ? `http://localhost:8080/torrent/listByCategorywithfilter?categoryid=${selectedCategory}`
+          : `http://localhost:8080/torrent/list`;
+
+        // [修改] 添加筛选参数(不再需要page和limit参数)
+        const params = new URLSearchParams();
+        Object.entries(filters).forEach(([key, value]) => {
+          if (value) params.append(key, value);
+        });
+
+        // [修改] 只有当有筛选参数时才添加
+        if (params.toString()) {
+          const separator = selectedCategory ? '&' : '?';
+          url += separator + params.toString();
+        }
+
+        const res = await axios.get(url);
+        setTorrents(res.data);  // [修改] 存储所有数据,不再分页
+        setTotalItems(res.data.length);  // [新增] 设置总数据量
+      } catch (err) {
+        console.error('获取种子失败', err);
+        setError('获取种子列表失败,请稍后重试');
+      } finally {
+        setIsLoading(false);
+      }
+    };
+
+    const timer = setTimeout(fetchTorrents, 300);
+    return () => clearTimeout(timer);
+  }, [selectedCategory, filters]);  // [注意] 依赖项不变
+
+  // [新增] 前端分页处理函数
+  const paginateData = (data, currentPage, itemsPerPage) => {
+    const startIndex = (currentPage - 1) * itemsPerPage;
+    const endIndex = startIndex + itemsPerPage;
+    return data.slice(startIndex, endIndex);
+  };
+
+  const currentTorrents = paginateData(torrents, currentPage, itemsPerPage);
+  useEffect(() => {
+    const fetchUsernames = async () => {
+      if (torrents.length === 0) return;
+
+      const usernamePromises = torrents.map(async (torrent) => {
+        if (torrent.uploader_id && !usernames[torrent.uploader_id]) {
+          try {
+            const response = await fetch(`http://localhost:8080/torrent/${torrent.uploader_id}/username`);
+            if (response.ok) {
+              const username = await response.text();
+              return { [torrent.uploader_id]: username };
+            }
+          } catch (error) {
+            console.error(`Failed to fetch username for uploader_id ${torrent.uploader_id}:`, error);
+          }
+        }
+        return {};
+      });
+
+      const results = await Promise.all(usernamePromises);
+      const mergedUsernames = results.reduce((acc, curr) => ({ ...acc, ...curr }), {});
+      setUsernames((prev) => ({ ...prev, ...mergedUsernames }));
+    };
+
+    fetchUsernames();
+  }, [torrents]);
+
+
+  // 切换分类时重置筛选条件
+  const handleCategoryChange = (categoryId) => {
+    setSelectedCategory(categoryId);
+    setFilters({});
+  };
+
+  // 格式化文件大小
+  const formatFileSize = (bytes) => {
+    if (bytes === 0) return '0 Bytes';
+    const k = 1024;
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  // 处理筛选条件变化
+  const handleFilterChange = (e) => {
+    const { name, value } = e.target;
+    setFilters(prev => ({ ...prev, [name]: value }));
+  };
+
+
+
+  // 下载种子
+  const handleDownload = (torrentId) => {
+    //window.open(`http://localhost:8080/torrent/download/${torrentId}`, '_blank');
+    window.open(`http://localhost:8080/torrent/download/${torrentId}?userId=${userId}`, '_blank');
+
+  };
+
+  // 获取当前分类的筛选配置
+  const currentFilters = getCategoryFilters(selectedCategory);
+
+  return (
+    <div className="p-4 max-w-7xl mx-auto">
+      <Navbar />
+      {/* <h1 className="text-2xl font-bold mb-6">种子列表</h1> */}
+
+      {/* 搜索框 */}
+      <div className="mb-4 flex items-center">
+        <Input
+          placeholder="搜索种子..."
+          value={searchKeyword}
+          onChange={(e) => setSearchKeyword(e.target.value)}
+          style={{ width: 300 }}
+          onPressEnter={handleSearch}
+        />
+        <Button
+          type="primary"
+          onClick={handleSearch}
+          style={{ marginLeft: 8 }}
+        >
+          搜索
+        </Button>
+      </div>
+
+      <div className="filter-container">
+        <div className="filter-container">
+          <div className="filter-row">
+            <label className="filter-label">选择分类:</label>
+            <Radio.Group
+              onChange={(e) => handleCategoryChange(e.target.value)}
+              value={selectedCategory}
+              className="flex space-x-2" // 添加 flex 布局
+            >
+              <Radio.Button className="custom-radio-btn" value="">
+                全部分类
+              </Radio.Button>
+              {categories.map(cat => (
+                <Radio.Button key={cat.categoryid} className="custom-radio-btn" value={cat.categoryid}>
+                  {cat.category_name}
+                </Radio.Button>
+              ))}
+            </Radio.Group>
+          </div>
+
+        </div>
+
+        {currentFilters.length > 0 &&
+          currentFilters.map(filter => (
+            <div key={filter.id} className="filter-row">
+              <label className="filter-label">{filter.label}:</label>
+              <Radio.Group
+                onChange={(e) => handleFilterChange({ target: { name: filter.id, value: e.target.value } })}
+                value={filters[filter.id] || ''}
+              >
+                <Radio.Button className="custom-radio-btn" value="">全部</Radio.Button>
+                {filter.options.map(option => (
+                  <Radio.Button key={option.value} className="custom-radio-btn" value={option.value}>
+                    {option.label}
+                  </Radio.Button>
+                ))}
+              </Radio.Group>
+            </div>
+          ))}
+      </div>
+
+
+      {/* 错误提示 */}
+      {error && (
+        <div className="mb-4 p-3 bg-red-100 text-red-700 rounded border border-red-200">
+          {error}
+        </div>
+      )}
+
+
+      {isLoading ? (
+        <div className="loading-container">
+          <div className="spinner"></div>
+        </div>
+      ) : (
+        <div className="torrents-container">
+          {torrents.length > 0 ? (
+            <div className="torrents-grid">
+              {currentTorrents.map(torrent => (
+                <div key={torrent.torrentid} className="torrent-card">
+                  <div className="cover">
+                    {torrent.coverImagePath ? (
+                      <img
+                        src={torrent.coverImagePath}
+                        alt="封面"
+                        className="cover-image"
+                      />
+                    ) : (
+                      <div className="no-cover">无封面</div>
+                    )}
+                  </div>
+
+                  <div className="info">
+                    <h3 className="title" title={torrent.filename}>
+                      {torrent.filename}
+                    </h3>
+                    <p className="description" title={torrent.description}>
+                      {torrent.description || '暂无描述'}
+                    </p>
+
+                    <div className="details">
+                      <span>大小: {formatFileSize(torrent.torrentSize)}</span>
+                      <span>上传者: {usernames[torrent.uploader_id]}</span>
+                      <span>上传时间: {new Date(torrent.uploadTime).toLocaleDateString()}</span>
+                      <span>下载次数: {torrent.downloadCount}</span>
+                      <span>促销: {getPromotionName(torrent.promotionid)}</span>
+                    </div>
+
+                    <div className="actions">
+                      <button
+                        onClick={() => handleDownload(torrent.torrentid)}
+                        className="btn btn-download"
+                      >
+                        下载
+                      </button>
+                      <Link
+                        to={`/torrent/${torrent.torrentid}`}
+                        className="btn btn-detail"
+                      >
+                        详情
+                      </Link>
+                    </div>
+
+                    {/* 新增举报按钮 */}
+                   
+<button
+  className="report-btn"
+  onClick={() => showReportModal(torrent.torrentid)}
+>
+  举报
+</button>
+
+                    {/* 添加举报模态框 */}
+
+
+                  </div>
+                </div>
+              ))}
+            </div>
+          ) : (
+            <div className="no-data">没有找到符合条件的种子</div>
+          )}
+        </div>
+      )}
+      <Modal
+        title="举报内容"
+        open={isReportModalVisible}
+        onOk={handleReportSubmit}
+        onCancel={() => setIsReportModalVisible(false)}
+        okText="提交"
+        cancelText="取消"
+      >
+        <p>您正在举报种子ID: {currentTorrentId}</p>
+        <Input.TextArea
+          rows={4}
+          value={reportContent}
+          onChange={(e) => setReportContent(e.target.value)}
+          placeholder="请输入举报原因..."
+        />
+      </Modal>
+      {/* // [新增] 分页组件 */}
+      {totalItems > 0 && (
+        <div className="pagination-container mt-6 flex justify-center">
+          <Pagination
+            current={currentPage}
+            pageSize={itemsPerPage}
+            total={totalItems}
+            onChange={(page) => setCurrentPage(page)}  // [新增] 页码变化处理
+            showSizeChanger={false}  // [可选] 是否显示每页条数选择器
+            showTotal={(total) => `共 ${total} 条记录`}  // [可选] 显示总条数
+          />
+        </div>
+      )}
+
+    </div>
+  );
+}
+
+export default TorrentList;
\ No newline at end of file
diff --git a/src/components/torrentmanage.jsx b/src/components/torrentmanage.jsx
new file mode 100644
index 0000000..4756b35
--- /dev/null
+++ b/src/components/torrentmanage.jsx
@@ -0,0 +1,443 @@
+import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { 
+  Table, 
+  Button, 
+  Modal, 
+  Image, 
+  message, 
+  Spin, 
+  Input, 
+  Select,
+  Pagination,
+  Space
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import axios from 'axios';
+
+const { confirm } = Modal;
+const { Option } = Select;
+
+const TorrentManagement = () => {
+  // 状态管理
+  const [torrents, setTorrents] = useState([]);
+  const [isLoading, setIsLoading] = useState(false);
+  const [error, setError] = useState(null);
+  const [selectedTorrentId, setSelectedTorrentId] = useState(null);
+  const [promotionOptions, setPromotionOptions] = useState([
+    { value: 1, label: '上传加倍' },
+    { value: 2, label: '下载减半' },
+    { value: 3, label: '免费下载' },
+    { value: 0, label: '无促销' }
+  ]);
+  const [selectedPromotion, setSelectedPromotion] = useState(null);
+  const [showPromotionWarning, setShowPromotionWarning] = useState(false);
+  const [currentUserId, setCurrentUserId] = useState(null);
+  const [applyPromotionsLoading, setApplyPromotionsLoading] = useState(false);
+  const [usernames, setUsernames] = useState({});
+  const [searchKeyword, setSearchKeyword] = useState('');
+  const [currentPage, setCurrentPage] = useState(1);
+  const [pageSize, setPageSize] = useState(10);
+  const navigate = useNavigate(); // 用于导航到详情页
+
+  // 获取当前用户ID
+  useEffect(() => {
+    const userId = 1; // 示例,实际从认证系统获取
+    setCurrentUserId(userId ? parseInt(userId) : null);
+  }, []);
+
+  // 获取所有种子数据
+  useEffect(() => {
+    fetchAllTorrents();
+  }, [searchKeyword]);
+
+  // 获取所有种子数据的函数
+  const fetchAllTorrents = async () => {
+    setIsLoading(true);
+    setError(null);
+    try {
+      const res = await axios.get('http://localhost:8080/torrent/list');
+      setTorrents(res.data);
+      setCurrentPage(1); // 重置为第一页
+    } catch (err) {
+      console.error('获取种子失败', err);
+      setError('获取种子列表失败,请稍后重试');
+      message.error('获取种子列表失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  console.log('当前种子列表:', torrents);
+
+  // 在组件加载时,批量获取所有 uploader_id 对应的 username
+  useEffect(() => {
+    const fetchUsernames = async () => {
+      if (torrents.length === 0) return;
+
+      const usernamePromises = torrents.map(async (torrent) => {
+        if (torrent.uploader_id && !usernames[torrent.uploader_id]) {
+          try {
+            const response = await fetch(`http://localhost:8080/torrent/${torrent.uploader_id}/username`);
+            if (response.ok) {
+              const username = await response.text();
+              return { [torrent.uploader_id]: username };
+            }
+          } catch (error) {
+            console.error(`Failed to fetch username for uploader_id ${torrent.uploader_id}:`, error);
+          }
+        }
+        return {};
+      });
+
+      const results = await Promise.all(usernamePromises);
+      const mergedUsernames = results.reduce((acc, curr) => ({ ...acc, ...curr }), {});
+      setUsernames((prev) => ({ ...prev, ...mergedUsernames }));
+    };
+
+    fetchUsernames();
+  }, [torrents]);
+
+  // 处理删除种子
+  const handleDeleteTorrent = async (torrentId) => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+
+    confirm({
+      title: '确认删除',
+      icon: <ExclamationCircleOutlined />,
+      content: '确定要删除这个种子吗?此操作不可恢复!',
+      onOk: async () => {
+        try {
+          await axios.delete(`http://localhost:8080/torrent/delete/${torrentId}`, {
+            params: { userid: currentUserId }
+          });
+          setTorrents(torrents.filter(torrent => torrent.torrentid !== torrentId));
+          message.success('种子删除成功');
+        } catch (err) {
+          console.error('删除种子失败', err);
+          if (err.response && err.response.status === 403) {
+            message.error('无权删除此种子');
+          } else {
+            message.error('删除种子失败');
+          }
+        }
+      }
+    });
+  };
+
+  // 搜索种子
+  const handleSearch = async () => {
+    if (!searchKeyword.trim()) {
+      fetchAllTorrents();
+      return;
+    }
+
+    setIsLoading(true);
+    setError(null);
+    try {
+      const res = await axios.get(`http://localhost:8080/torrent/search`, {
+        params: { keyword: searchKeyword },
+      });
+      setTorrents(res.data);
+      setCurrentPage(1); // 搜索后重置为第一页
+    } catch (err) {
+      console.error('搜索失败', err);
+      setError('搜索失败,请稍后重试');
+      message.error('搜索失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  // 处理修改促销方式
+  const handlePromotionChange = (torrentId, newPromotion) => {
+    setSelectedTorrentId(torrentId);
+    setSelectedPromotion(newPromotion);
+    setShowPromotionWarning(true);
+  };
+
+  // 确认修改促销方式
+  const confirmPromotionChange = async () => {
+    if (selectedTorrentId && selectedPromotion !== null) {
+      try {
+        await axios.post('http://localhost:8080/torrent/setPromotion', null, {
+          params: {
+            userid: currentUserId,
+            torrentId: selectedTorrentId,
+            promotionId: selectedPromotion
+          }
+        });
+        setTorrents(torrents.map(torrent =>
+          torrent.torrentid === selectedTorrentId
+            ? { ...torrent, promotionid: selectedPromotion }
+            : torrent
+        ));
+        setShowPromotionWarning(false);
+        message.success('促销方式修改成功');
+      } catch (err) {
+        console.error('修改促销方式失败', err);
+        if (err.response && err.response.status === 403) {
+          message.error('无权修改此种子的促销方式');
+        } else {
+          message.error('修改促销方式失败');
+        }
+      }
+    }
+  };
+
+  // 取消修改促销方式
+  const cancelPromotionChange = () => {
+    setShowPromotionWarning(false);
+    setSelectedTorrentId(null);
+    setSelectedPromotion(null);
+  };
+
+  // 触发检查(应用促销规则)
+  const handleApplyPromotions = async () => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+    
+    setApplyPromotionsLoading(true);
+    try {
+      const res = await axios.post('http://localhost:8080/torrent/applyPromotions', null, {
+        params: { userid: currentUserId }
+      });
+      
+      if (res.data.success) {
+        message.success(res.data.message);
+        fetchAllTorrents(); // 刷新种子列表
+      }
+    } catch (err) {
+      console.error('应用促销规则失败', err);
+      if (err.response && err.response.status === 403) {
+        message.error('无权执行此操作');
+      } else {
+        message.error('应用促销规则失败');
+      }
+    } finally {
+      setApplyPromotionsLoading(false);
+    }
+  };
+
+  // 分页数据计算
+  const getCurrentPageData = () => {
+    const start = (currentPage - 1) * pageSize;
+    const end = start + pageSize;
+    return torrents.slice(start, end);
+  };
+
+  // 页码变化处理
+  const handlePageChange = (page) => {
+    setCurrentPage(page);
+  };
+
+  // 每页条数变化处理
+  const handlePageSizeChange = (current, size) => {
+    setPageSize(size);
+    setCurrentPage(1); // 重置为第一页
+  };
+
+  // 格式化日期
+  const formatDate = (dateString) => {
+    const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' };
+    return new Date(dateString).toLocaleString('zh-CN', options);
+  };
+
+  // 格式化文件大小
+  const formatFileSize = (bytes) => {
+    if (bytes === 0) return '0 Bytes';
+    const k = 1024;
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  // 获取促销方式名称
+  const getPromotionName = (promotionId) => {
+    if (promotionId === null) return '无促销';
+    const option = promotionOptions.find(opt => opt.value === promotionId);
+    return option ? option.label : '未知促销';
+  };
+
+  const handleViewDetails = (torrentId) => {
+    navigate(`/admin/${torrentId}`);  // 使用已定义的 navigate 变量
+  };
+
+  return (
+    <div className="p-4 max-w-7xl mx-auto">
+      <h1 className="text-2xl font-bold mb-6">种子管理</h1>
+
+      {/* 搜索框 */}
+      <div className="mb-4 flex items-center">
+        <Input
+          placeholder="搜索种子..."
+          value={searchKeyword}
+          onChange={(e) => setSearchKeyword(e.target.value)}
+          style={{ width: 300 }}
+          onPressEnter={handleSearch}
+        />
+        <Button 
+          type="primary" 
+          onClick={handleSearch}
+          style={{ marginLeft: 8 }}
+        >
+          搜索
+        </Button>
+      </div>
+
+      {/* 右上角按钮 */}
+      <Button
+        type="primary"
+        loading={applyPromotionsLoading}
+        onClick={handleApplyPromotions}
+        style={{ marginBottom: 16 }}
+      >
+        触发检查
+      </Button>
+
+      {/* 加载状态 */}
+      {isLoading && <Spin size="large" style={{ display: 'block', margin: '100px auto' }} />}
+
+      {/* 错误提示 */}
+      {error && <div className="mb-4 p-3 bg-red-100 text-red-700 rounded border border-red-200">{error}</div>}
+
+      {/* 种子列表表格 */}
+      {!isLoading && !error && (
+        <>
+          <Table
+            columns={[
+              {
+                title: '封面',
+                dataIndex: 'coverImagePath',
+                key: 'coverImagePath',
+                render: (text) => text ? (
+                  <Image 
+                    src={text} 
+                    width={50} 
+                    height={50} 
+                    preview={{ maskClosable: true }}
+                  />
+                ) : (
+                  <div className="w-16 h-16 bg-gray-200 flex items-center justify-center">无封面</div>
+                )
+              },
+              {
+                title: '名称',
+                dataIndex: 'filename',
+                key: 'filename'
+              },
+              {
+                title: '描述',
+                dataIndex: 'description',
+                key: 'description'
+              },
+              {
+                title: '大小',
+                dataIndex: 'torrentSize',
+                key: 'torrentSize',
+                render: (size) => formatFileSize(size)
+              },
+              {
+                title: '上传者',
+                dataIndex: 'uploader_id',
+                key: 'uploader_id',
+                render: (id) => usernames[id] || id
+              },
+              {
+                title: '上传时间',
+                dataIndex: 'uploadTime',
+                key: 'uploadTime',
+                render: (time) => formatDate(time)
+              },
+              {
+                title: '下载次数',
+                dataIndex: 'downloadCount',
+                key: 'downloadCount'
+              },
+              {
+                title: '促销',
+                dataIndex: 'promotionid',
+                key: 'promotionid',
+                render: (id) => getPromotionName(id)
+              },
+              {
+                title: '操作',
+                key: 'action',
+                render: (_, record) => (
+                  <Space>
+                    <Button 
+                      danger 
+                      onClick={() => handleDeleteTorrent(record.torrentid)}
+                      loading={isLoading}
+                    >
+                      删除
+                    </Button>
+                    <Select
+                      value={record.promotionid}
+                      onChange={(value) => handlePromotionChange(record.torrentid, value)}
+                      style={{ width: 120 }}
+                      disabled={isLoading}
+                    >
+                      {promotionOptions.map(option => (
+                        <Option key={option.value} value={option.value}>{option.label}</Option>
+                      ))}
+                    </Select>
+                    <Button 
+                type="primary" 
+                size="small"
+                onClick={() => handleViewDetails(record.torrentid)}  // 使用处理函数
+              >
+                查看详情
+              </Button>
+                  </Space>
+                )
+              }
+            ]}
+            dataSource={getCurrentPageData()}
+            rowKey="torrentid"
+            pagination={false}
+            loading={isLoading}
+          />
+
+          {/* 分页控件 */}
+          {torrents.length > 0 && (
+            <div style={{ marginTop: 16, textAlign: 'center' }}>
+              <Pagination
+                current={currentPage}
+                pageSize={pageSize}
+                total={torrents.length}
+                onChange={handlePageChange}
+                onShowSizeChange={handlePageSizeChange}
+                showSizeChanger
+                showTotal={(total) => `共 ${total} 条记录`}
+                pageSizeOptions={['10', '20', '50']}
+              />
+            </div>
+          )}
+        </>
+      )}
+
+      {/* 促销方式修改确认弹窗 */}
+      <Modal
+        title="确认修改促销方式"
+        open={showPromotionWarning}
+        onOk={confirmPromotionChange}
+        onCancel={cancelPromotionChange}
+        okText="确认"
+        cancelText="取消"
+      >
+        <p>
+          您确定要将种子 ID 为 
+          <span className="font-bold">{selectedTorrentId}</span> 的促销方式修改为
+          <span className="font-bold">「{getPromotionName(selectedPromotion)}」</span> 吗?
+        </p>
+      </Modal>
+    </div>
+  );
+};
+
+export default TorrentManagement;
\ No newline at end of file
diff --git a/src/components/upload-full.jsx b/src/components/upload-full.jsx
new file mode 100644
index 0000000..bb68fab
--- /dev/null
+++ b/src/components/upload-full.jsx
@@ -0,0 +1,2005 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+import "../upload.css";
+import "../uploadtorrent.css";
+import { Form, Input, Select, Button, Typography, Space, message,Switch } from 'antd';
+import { useParams, useNavigate, useLocation, useSearchParams } from 'react-router-dom'; // 添加 useLocation
+import { InboxOutlined } from '@ant-design/icons';
+const { TextArea } = Input;
+const { Text } = Typography;
+
+
+function UploadTorrentFull() {
+  const [userid,setuserid] = useState(1);
+  const [title, setTitle] = useState('');
+  const [description, setDescription] = useState('');
+  const [categoryId, setCategoryId] = useState('');
+  const [file, setFile] = useState(null);
+  const [categories, setCategories] = useState([]);
+  const [showSuccess, setShowSuccess] = useState(false);
+  const [form] = Form.useForm();
+  const location = useLocation(); // 添加这行获取location对象
+    // 在组件状态中添加
+    // 获取参数并设置默认值
+    //const [manageId, setManageId] = useState(parseInt(searchParams.get('manageid')) || 1);
+   // 正确从location.state获取参数
+    const {requestid} = location.state || {};
+  
+  // 通用参数
+  const [dpi, setDpi] = useState('');
+  const [caption, setCaption] = useState('');
+  const [region, setRegion] = useState('');
+  const [year, setYear] = useState('');
+  const [genre, setGenre] = useState('');
+  const [format, setFormat] = useState('');
+  const [resolution, setResolution] = useState('');
+  const [coverImage, setCoverImage] = useState(null);
+  
+  // 特殊参数
+  const [codecFormat, setCodecFormat] = useState('');
+  const [platform, setPlatform] = useState('');
+  const [language, setLanguage] = useState('');
+  const [eventType, setEventType] = useState('');
+  const [source, setSource] = useState('');
+  const [style, setStyle] = useState('');
+  const [dataType, setdataType] = useState('');
+  const [isMainland, setIsMainland] = useState(false);
+
+  // 根据分类显示不同的表单字段
+  const [showMovieFields, setShowMovieFields] = useState(false);
+  const [showMusicFields, setShowMusicFields] = useState(false);
+  const [showGameFields, setShowGameFields] = useState(false);
+  const [showTvFields, setShowTvFields] = useState(false);
+  const [showAnimeFields, setShowAnimeFields] = useState(false);
+  const [showlearningFields, setShowlearningFields] = useState(false);
+  const [showsoftwareFields, setShowsoftwareFields] = useState(false);
+  const [showvarietyFields, setShowvarietyFields] = useState(false);
+  const [showsportsFields, setShowsportsFields] = useState(false);
+  const [showdocFields, setShowdocFields] = useState(false);
+  const [showotherFields, setShowotherFields] = useState(false);
+  // 其他分类字段...
+  // 编码格式选项
+  const codecFormats = [
+    { value: 'H.264', label: 'H.264' },
+    { value: 'H.265', label: 'H.265' },
+    { value: 'AV1', label: 'AV1' },
+    { value: 'VP9', label: 'VP9' },
+    { value: 'VC1', label: 'VC1' },
+    { value: 'X264', label: 'X264' },
+  ];
+  const regions = [
+    { value: '大陆', label: '大陆' },
+    { value: '港台', label: '港台' },
+    { value: '欧美', label: '欧美' },
+    { value: '日韩', label: '日韩' },
+    { value: '其他', label: '其他' },
+  ];
+  const genres = [
+    { value: '动作', label: '动作' },
+    { value: '喜剧', label: '喜剧' },
+    { value: '爱情', label: '爱情' },
+    { value: '科幻', label: '科幻' },
+    { value: '恐怖', label: '恐怖' },
+    { value: '动作', label: '动作' },
+    { value: '冒险', label: '冒险' },
+    { value: '历史', label: '历史' },
+    { value: '悬疑', label: '悬疑' },
+    { value: '其他', label: '其他' },
+  ];
+  const resolutions = [
+    { value: '720p', label: '720p' },
+    { value: '1080p', label: '1080p' },
+    { value: '2K', label: '2K' },
+    { value: '4K', label: '4K' },
+    { value: '8K', label: '8K' },
+    { value: '其他', label: '其他' },
+  ];
+
+
+  const eventTypes = [
+    { value: '足球', label: '足球' },
+    { value: '篮球', label: '篮球' },
+    { value: '网球', label: '网球' },
+    { value: '乒乓球', label: '乒乓球' },
+    { value: '羽毛球', label: '羽毛球' },
+  ]
+  const styles = [
+    { value: '大陆综艺', label: '大陆综艺' },
+    { value: '日韩综艺', label: '日韩综艺' },
+    { value: '欧美综艺', label: '欧美综艺' },
+    { value: '其他', label: '其他' },
+  ]
+  const platforms = [
+    { value: 'PC', label: 'PC' },
+    { value: 'PS5', label: 'PS5' },
+    { value: 'Xbox', label: 'Xbox' },
+    { value: 'Switch', label: 'Switch' },
+    { value: '手机', label: '手机' },
+    { value: '其他', label: '其他' },
+  ]
+  const gamegenres = [
+    { value: '角色扮演', label: '角色扮演' },
+    { value: '射击', label: '射击' },
+    { value: '冒险', label: '冒险' },
+    { value: '策略', label: '策略' },
+    { value: '体育', label: '体育' },
+    { value: '桌面游戏', label: '桌面游戏'},
+    { value: '其他', label: '其他' },
+  ]
+  const dataTypes = [
+    { value: '压缩包', label: '压缩包' },
+    { value: '补丁', label: '补丁' },
+    { value: '安装包', label: '安装包' },
+    { value: 'nds', label: 'nds' },
+    { value: '其他', label: '其他' },
+  ]
+  const languages = [
+    { value: '中文', label: '中文' },
+    { value: '英文', label: '英文' },
+    { value: '日文', label: '日文' },
+    { value: '其他', label: '其他' },
+  ]
+  const musicgenres = [
+    { value: '专辑', label: '专辑' },
+    { value: '单曲', label: '单曲' },
+    { value: 'EP', label: 'EP' },
+    { value: '现场', label: '现场' },
+    { value: '其他', label: '其他' },
+  ]
+  const musicstyles = [
+    { value: '流行', label: '流行' },
+    { value: '摇滚', label: '摇滚' },
+    { value: '电子', label: '电子' },
+    { value: '古典', label: '古典' },
+    { value: '爵士', label: '爵士' },
+    { value: '民谣', label: '民谣' },
+    { value: '说唱', label: '说唱' },
+    { value: '其他', label: '其他' },
+  ]
+  const musicformats = [
+    { value: 'MP3', label: 'MP3' },
+    { value: 'FLAC', label: 'FLAC' },
+    { value: 'WAV', label: 'WAV' },
+    { value: 'AAC', label: 'AAC' },
+    { value: 'OGG', label: 'OGG' },
+    { value: '其他', label: '其他' },
+  ]
+  const anigenres = [
+    { value: '新番连载', label: '新番连载' },
+    { value: '剧场版', label: '剧场版' },
+    { value: 'OVA', label: 'OVA' },
+    { value: '完结动漫', label: '完结动漫' },
+    { value: '其他', label: '其他' },
+  ]
+  const animeformats = [
+    { value: 'ZIP', label: 'ZIP' },
+    { value: 'RAR', label: 'RAR' },
+    { value: '7Z', label: '7Z' },
+    { value: 'MKV', label: 'MKV' },
+    { value: 'MP4', label: 'MP4' },
+    { value: '其他', label: '其他' },
+  ]
+  const varietygenres = [
+    { value: '真人秀', label: '真人秀' },
+    { value: '选秀', label: '选秀' },
+    { value: '访谈', label: '访谈' },
+    { value: '游戏', label: '游戏' },
+    { value: '音乐', label: '音乐' },
+    { value: '其他', label: '其他' },
+  ]
+  const sportsgenres = [
+    { value: '足球', label: '足球' },
+    { value: '篮球', label: '篮球' },
+    { value: '网球', label: '网球' },
+    { value: '乒乓球', label: '乒乓球' },
+    { value: '羽毛球', label: '羽毛球' },
+    { value: '其他', label: '其他' },
+  ]
+  const softwaregenres = [
+    { value: '系统软件', label: '系统软件' },
+    { value: '应用软件', label: '应用软件' },
+    { value: '游戏软件', label: '游戏软件' },
+    { value: '驱动程序', label: '驱动程序' },
+    { value: '办公软件', label: '办公软件' },
+    { value: '其他', label: '其他' },
+  ]
+  const softwareplatforms = [
+    { value: 'Windows', label: 'Windows' },
+    { value: 'Mac', label: 'Mac' },
+    { value: 'Linux', label: 'Linux' },
+    { value: 'Android', label: 'Android' },
+    { value: 'iOS', label: 'iOS' },
+    { value: '其他', label: '其他' },
+  ]
+  const softwareformats = [
+    { value: 'EXE', label: 'EXE' }, 
+    { value: 'DMG', label: 'DMG' },
+    { value: '光盘镜像', label: '光盘镜像' },
+    { value: 'APK', label: 'APK' },
+    { value: 'IPA', label: 'IPA' },
+    { value: '其他', label: '其他' },
+  ]
+  const learninggenres = [
+    { value: '计算机', label: '计算机' },
+    { value: '软件', label: '软件' },
+    { value: '人文', label: '人文' },
+    { value: '外语', label: '外语' },
+    { value: '理工类', label: '理工类' },
+    { value: '其他', label: '其他' },
+  ]
+  const learningformats = [
+    { value: 'PDF', label: 'PDF' },
+    { value: 'EPUB', label: 'EPUB' },
+    { value: '视频', label: '视频' },
+    { value: '音频', label: '音频' },
+    { value: 'PPT', label: 'PPT' },
+    { value: '其他', label: '其他' },
+  ]
+  const sourceTypes = [
+    { value: 'CCTV', label: 'CCTV' },
+    { value: '卫视', label: '卫视' },
+    { value: '国家地理', label: '国家地理' },
+    { value: 'BBC', label: 'BBC' },
+    { value: 'Discovery', label: 'Discovery' },
+    { value: '其他', label: '其他' },
+  ]
+  const othergenres = [
+    { value: '电子书', label: '电子书' },
+    { value: '视频', label: '视频' },
+    { value: 'MP3', label: 'MP3' },
+    { value: '图片', label: '图片' },
+    { value: '其他', label: '其他' },
+  ]
+  useEffect(() => {
+    axios.get('http://localhost:8080/categories')
+      .then(res => setCategories(res.data))
+      .catch(err => console.error('加载分类失败', err));
+  }, []);
+
+  // 根据选择的分类显示不同的表单字段
+  useEffect(() => {
+    setShowMovieFields(categoryId === '1');
+    setShowMusicFields(categoryId === '3');
+    setShowGameFields(categoryId === '5');
+    setShowTvFields(categoryId === '2');
+    setShowAnimeFields(categoryId === '4');
+    setShowlearningFields(categoryId === '9');
+    setShowsoftwareFields(categoryId === '8');
+    setShowvarietyFields(categoryId === '6');
+    setShowsportsFields(categoryId === '7');
+    setShowdocFields(categoryId === '10');
+    setShowotherFields(categoryId === '11');
+    // 其他分类...
+  }, [categoryId]);
+
+  
+  const handleSubmit = async (e) => {
+    //e.preventDefault();
+    if (!coverImage) {
+      alert('请选择一个 图片 文件');
+      return;
+    }
+    if (!file) {
+      alert('请选择一个 .torrent 文件');
+      return;
+    }
+
+    if (!categoryId) {
+      alert('请选择分类');
+      return;
+    }
+    
+
+    const formData = new FormData();
+    formData.append('userid', userid);
+    formData.append('file', file);
+    // Add cover image if it exists
+    formData.append('coverImage', coverImage);
+    formData.append('title', title);
+    formData.append('description', description);
+    formData.append('categoryId', categoryId);
+    formData.append('requestId', requestid);
+
+    
+    // 通用参数
+    if (dpi) formData.append('dpi', dpi);
+    if (caption) formData.append('caption', caption);
+    if (region) formData.append('region', region);
+    if (year) formData.append('year', year);
+    if (genre) formData.append('genre', genre);
+    if (format) formData.append('format', format);
+    if (resolution) formData.append('resolution', resolution);
+    
+    // 特殊参数
+    if (codecFormat) formData.append('codecFormat', codecFormat);
+    if (platform) formData.append('platform', platform);
+    if (language) formData.append('language', language);
+    if (eventType) formData.append('eventType', eventType);
+    if (source) formData.append('source', source);
+    if (style) formData.append('style', style);
+    if (dataType) formData.append('dataType', dataType);
+    formData.append('isMainland', isMainland.toString());
+
+    try {
+      const response = await axios.post('http://localhost:8080/torrent/fullrequest', formData, {
+        headers: { 'Content-Type': 'multipart/form-data' },
+        responseType: 'blob',
+      });
+
+      // 创建下载链接
+      const url = window.URL.createObjectURL(new Blob([response.data]));
+      const link = document.createElement('a');
+      link.href = url;
+      link.setAttribute('download', file.name);
+      document.body.appendChild(link);
+      link.click();
+      link.remove();
+
+      // 显示成功提示
+      setShowSuccess(true);
+      // 清空表单
+      setTitle('');
+      setDescription('');
+      setCategoryId('');
+      setFile(null);
+      // 清空其他字段...
+    } catch (err) {
+      console.error('上传失败', err.response?.data || err.message);
+      alert(err.response?.data || '上传失败,请检查后端是否启动');
+    }
+  };
+
+//   return (
+//   <div className="max-w-2xl mx-auto mt-10 p-6 bg-white shadow rounded">
+//   <h2 className="text-2xl font-bold mb-6 text-orange-800 text-center border-b-2 border-orange-200 pb-3">上传种子</h2>
+//   <form onSubmit={handleSubmit} className="space-y-6">
+//     {/* 封面图片 - 大型上传区域 */}
+//     <div className="form-group text-center">
+//       <label className="upload-area text-orange-800 font-medium cursor-pointer p-8 border-2 border-dashed border-orange-300 rounded-lg hover:border-orange-400 transition-colors">
+//         <svg xmlns="http://www.w3.org/2000/svg" className="mx-auto h-12 w-12 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+//           <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
+//         </svg>
+//         <p className="mt-2 text-sm">点击或拖拽上传封面图片</p>
+//         <input 
+//           type="file" 
+//           accept="image/*" 
+//           onChange={(e) => setCoverImage(e.target.files[0])} 
+//           className="hidden"
+//           id="cover-image-upload"
+//         />
+//       </label>
+//       <input 
+//         type="file" 
+//         accept="image/*" 
+//         onChange={(e) => setCoverImage(e.target.files[0])} 
+//         className="sr-only"
+//         id="cover-image-upload-real"
+//       />
+//     </div>
+
+//     {/* 种子文件 - 大型上传区域 */}
+//     <div className="form-group text-center">
+//       <label className="upload-area text-orange-800 font-medium cursor-pointer p-8 border-2 border-dashed border-orange-300 rounded-lg hover:border-orange-400 transition-colors">
+//         <svg xmlns="http://www.w3.org/2000/svg" className="mx-auto h-12 w-12 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+//           <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
+//         </svg>
+//         <p className="mt-2 text-sm">点击或拖拽上传种子文件(.torrent)</p>
+//         <input 
+//           type="file" 
+//           accept=".torrent" 
+//           onChange={(e) => setFile(e.target.files[0])} 
+//           className="hidden"
+//           id="torrent-file-upload"
+//           required
+//         />
+//       </label>
+//       <input 
+//         type="file" 
+//         accept=".torrent" 
+//         onChange={(e) => setFile(e.target.files[0])} 
+//         className="sr-only"
+//         id="torrent-file-upload-real"
+//         required
+//       />
+//     </div>
+
+//     {/* 标题 */}
+//     <div className="form-group">
+//       <label className="form-label text-orange-800 text-center">标题</label>
+//       <input
+//         type="text"
+//         placeholder="输入种子标题"
+//         value={title}
+//         onChange={(e) => setTitle(e.target.value)}
+//         className="form-control text-center"
+//         required
+//       />
+//     </div>
+
+//     {/* 描述 */}
+//     <div className="form-group">
+//       <label className="form-label text-orange-800 text-center">描述</label>
+//       <textarea
+//         placeholder="输入种子描述"
+//         value={description}
+//         onChange={(e) => setDescription(e.target.value)}
+//         className="form-control text-center"
+//         rows={3}
+//       />
+//     </div>
+
+//     {/* 分类 - 美化下拉框 */}
+//     <div className="form-group">
+//       <label className="form-label text-orange-800 text-center">分类</label>
+//       <div className="relative">
+//         <select
+//           value={categoryId}
+//           onChange={(e) => setCategoryId(e.target.value)}
+//           className="custom-select"
+//           required
+//         >
+//           <option value="">请选择分类</option>
+//           {categories.map(cat => (
+//             <option key={cat.categoryid} value={cat.categoryid}>{cat.category_name}</option>
+//           ))}
+//         </select>
+//         <div className="select-arrow">
+//           <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//             <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//           </svg>
+//         </div>
+//       </div>
+//     </div>
+
+//     {/* 动态字段 - 电影 */}
+//     {showMovieFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">字幕/说明</label>
+//           <input
+//             type="text"
+//             placeholder="输入字幕/说明"
+//             value={caption}
+//             onChange={(e) => setCaption(e.target.value)}
+//             className="form-control text-center"
+//           />
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">地区</label>
+//           <div className="relative">
+//             <select
+//               value={region}
+//               onChange={(e) => setRegion(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择地区</option>
+//               {regions.map((region) => (
+//                 <option key={region.value} value={region.value}>
+//                   {region.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">年份</label>
+//           <input
+//             type="text"
+//             placeholder="输入年份"
+//             value={year}
+//             onChange={(e) => setYear(e.target.value)}
+//             className="form-control text-center"
+//           />
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">类型</label>
+//           <div className="relative">
+//             <select
+//               value={genre}
+//               onChange={(e) => setGenre(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择类型</option>
+//               {genres.map((format) => (
+//                 <option key={format.value} value={format.value}>
+//                   {format.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">编码格式</label>
+//           <div className="relative">
+//             <select
+//               value={codecFormat}
+//               onChange={(e) => setCodecFormat(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择编码格式</option>
+//               {codecFormats.map((format) => (
+//                 <option key={format.value} value={format.value}>
+//                   {format.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">分辨率</label>
+//           <div className="relative">
+//             <select
+//               value={resolution}
+//               onChange={(e) => setResolution(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择分辨率</option>
+//               {resolutions.map((resolution) => (
+//                 <option key={resolution.value} value={resolution.value}>
+//                   {resolution.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 剧集 */}
+//     {showTvFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">地区</label>
+//           <select
+//             value={region}
+//             onChange={(e) => setRegion(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择地区</option>
+//             {regions.map((region) => (
+//               <option key={region.value} value={region.value}>
+//                 {region.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {genres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 游戏 */}
+//     {showGameFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">平台</label>
+//           <select
+//             value={platform}
+//             onChange={(e) => setPlatform(e.target.value)} 
+//             className="form-control"
+//           >
+//             <option value="">请选择平台</option>
+//             {platforms.map((platform) => (
+//               <option key={platform.value} value={platform.value}>
+//                 {platform.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>  
+//             {gamegenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">语言</label>
+//           <select
+//             value={language}
+//             onChange={(e) => setLanguage(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择语言</option>
+//             {languages.map((language) => (
+//               <option key={language.value} value={language.value}>
+//                 {language.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">数据类型</label>
+//           <select
+//             value={dataType}
+//             onChange={(e) => setdataType(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择数据类型</option>
+//             {dataTypes.map((dataType) => (
+//               <option key={dataType.value} value={dataType.value}>
+//                 {dataType.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 综艺 */}
+//     {showvarietyFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="flex items-center">
+//             <input
+//               type="checkbox"
+//               checked={isMainland}
+//               onChange={(e) => setIsMainland(e.target.checked)}
+//               className="mr-2"
+//             />
+//             是否大陆综艺
+//           </label>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={style}
+//             onChange={(e) => setStyle(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {varietygenres.map((style) => (
+//               <option key={style.value} value={style.value}>
+//                 {style.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 动漫 */}
+//     {showAnimeFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {anigenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {animeformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">分辨率</label>
+//           <select
+//             value={resolution}
+//             onChange={(e) => setResolution(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择分辨率</option>
+//             {resolutions.map((resolution) => (
+//               <option key={resolution.value} value={resolution.value}>
+//                 {resolution.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 学习 */}
+//     {showlearningFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {learninggenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {learningformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 软件 */}
+//     {showsoftwareFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">平台</label>
+//           <select
+//             value={platform}
+//             onChange={(e) => setPlatform(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择平台</option>
+//             {softwareplatforms.map((platform) => (
+//               <option key={platform.value} value={platform.value}>
+//                 {platform.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {softwaregenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {softwareformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 体育 */}
+//     {showsportsFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {sportsgenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">赛事类型</label>
+//           <select
+//             value={eventType}
+//             onChange={(e) => setEventType(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择赛事类型</option>
+//             {eventTypes.map((eventType) => (
+//               <option key={eventType.value} value={eventType.value}>
+//                 {eventType.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 纪录片 */}
+//     {showdocFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">年份</label>
+//           <input
+//             type="text"
+//             placeholder="如 1999, 2020"
+//             value={year}
+//             onChange={(e) => setYear(e.target.value)}
+//             className="form-control"
+//           />
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">视频源</label>
+//           <select
+//             value={source}
+//             onChange={(e) => setSource(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择视频源</option>
+//             {sourceTypes.map((source) => (
+//               <option key={source.value} value={source.value}>
+//                 {source.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 音乐 */}
+//     {showMusicFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {musicgenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">地区</label>
+//           <select
+//             value={region}
+//             onChange={(e) => setRegion(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择地区</option>
+//             {regions.map((region) => (
+//               <option key={region.value} value={region.value}>
+//                 {region.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">风格</label>
+//           <select
+//             value={style}
+//             onChange={(e) => setStyle(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择风格</option>
+//             {musicstyles.map((style) => (
+//               <option key={style.value} value={style.value}>
+//                 {style.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {musicformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 其他 */}
+//     {showotherFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {othergenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+
+//     {/* 其他动态字段... (保持相同的美化样式) */}
+//     {/* 这里省略了其他动态字段的代码,但它们都使用相同的自定义下拉框样式 */}
+    
+//     {/* 提交按钮 - 居中 */}
+//     <div className="text-center">
+//       <button 
+//         type="submit" 
+//         className="submit-btn"
+//       >
+//         上传种子
+//       </button>
+//     </div>
+
+//     {showSuccess && (
+//       <div className="success-message text-center">
+//         上传成功!
+//       </div>
+//     )}
+//   </form>
+// </div>
+//   );
+// }
+return (
+    <div className="container">
+      <div className="card">
+        <h2 className="title">上传种子</h2>
+        <Form
+          layout="vertical"
+          onFinish={handleSubmit}
+          className="form"
+        >
+         {/* 封面图片 - 自定义上传区域 */}
+<Form.Item
+  name="coverImage"
+   label={<span style={{ fontSize: '19px'  , fontWeight: 'bold'}}>封面图片</span>} 
+  rules={[{ required: true, message: '请上传封面图片' }]}
+>
+  <div 
+    className="uploadArea"
+    onClick={() => document.getElementById('cover-image-upload').click()}
+  >
+    <InboxOutlined className="uploadIcon" />
+    <p className="uploadText">点击或拖拽上传封面图片</p>
+    <input
+      type="file"
+      accept="image/*"
+      onChange={(e) => {
+        setCoverImage(e.target.files[0]);
+        form.setFieldsValue({ coverImage: e.target.files[0] });
+      }}
+      className="hiddenInput"
+      id="cover-image-upload"
+    />
+  </div>
+</Form.Item>
+
+{/* 种子文件 - 自定义上传区域 */}
+<Form.Item
+  name="torrentFile"
+   label={<span style={{ fontSize: '19px' , fontWeight: 'bold'}}>种子文件</span>} 
+  rules={[{ required: true, message: '请上传.torrent文件' }]}
+>
+  <div 
+    className="uploadArea"
+    onClick={() => document.getElementById('torrent-file-upload').click()}
+  >
+    <InboxOutlined className="uploadIcon" />
+    <p className="uploadText">点击或拖拽上传种子文件(.torrent)</p>
+    <input
+      type="file"
+      accept=".torrent"
+      onChange={(e) => {
+        setFile(e.target.files[0]);
+        form.setFieldsValue({ torrentFile: e.target.files[0] });
+      }}
+      className="hiddenInput"
+      id="torrent-file-upload"
+    />
+  </div>
+</Form.Item>
+
+          {/* 标题 */}
+          <Form.Item
+            name="title"
+            label={<span style={{ fontSize: '19px'  , fontWeight: 'bold'}}>标题</span>}  // 直接包裹label
+            rules={[{ required: true, message: '请输入标题' }]}
+            //labelCol={{ style: { fontSize: '30px !important ' } }} // ✅ 调整 Label 字体
+          >
+            <Input
+              placeholder="输入种子标题"
+              value={title}
+              onChange={(e) => {
+                setTitle(e.target.value);
+                form.setFieldsValue({ title: e.target.value });
+              }}
+              //style={styles.input}
+              style={{ fontSize: '19px' }} // ✅ 调整 Input 字体
+            />
+          </Form.Item>
+
+          {/* 描述 */}
+          <Form.Item
+            name="description"
+             label={<span style={{ fontSize: '19px'  , fontWeight: 'bold'}}>描述</span>} 
+          >
+            <TextArea
+              placeholder="输入种子描述"
+              value={description}
+              onChange={(e) => {
+                setDescription(e.target.value);
+                form.setFieldsValue({ description: e.target.value });
+              }}
+              rows={3}
+              style={styles.textArea}
+            />
+          </Form.Item>
+
+          {/* 分类 - 美化下拉框 */}
+          <Form.Item
+            name="categoryId"
+             label={<span style={{ fontSize: '19px' , fontWeight: 'bold' }}>分类</span>} 
+            rules={[{ required: true, message: '请选择分类' }]}
+          >
+            <Select
+              placeholder="请选择分类"
+              value={categoryId}
+              onChange={(value) => {
+                const stringValue = String(value);
+                setCategoryId(stringValue);
+                console.log('Selected category ID:', stringValue);
+                form.setFieldsValue({ categoryId: value });
+                // 触发分类变化后的逻辑
+                setShowMovieFields(value === '1');
+                setShowTvFields(value === '2');
+                setShowAnimeFields(value === '4');
+                setShowGameFields(value === '5');
+                setShowvarietyFields(value === '6');
+                setShowMusicFields(value === '3');
+                setShowlearningFields(value === '9');
+                setShowsoftwareFields(value === '8');
+                setShowsportsFields(value === '7');
+                setShowdocFields(value === '10');
+                setShowotherFields(value === '11');
+              }}
+              style={styles.select}
+            >
+              <Option value="">请选择分类</Option>
+              {categories.map(cat => (
+                <Option key={cat.categoryid} value={cat.categoryid}>{cat.category_name}</Option>
+              ))}
+            </Select>
+          </Form.Item>
+
+      {/* 动态字段 - 电影 */}
+      {showMovieFields && (
+        <>
+          <Form.Item
+            name="caption"
+            label="字幕/说明"
+            rules={[{ required: true, message: '请输入字幕/说明' }]}
+          >
+            <Input
+              placeholder="输入字幕/说明"
+              value={caption}
+              onChange={(e) => {
+                setCaption(e.target.value);
+                form.setFieldsValue({ caption: e.target.value });
+              }}
+              className="text-center"
+            />
+          </Form.Item>
+          <Form.Item
+            name="region"
+            label="地区"
+          >
+            <Select
+              placeholder="请选择地区"
+              value={region}
+              onChange={(value) => {
+                setRegion(value);
+                form.setFieldsValue({ region: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择地区</Option>
+              {regions.map((region) => (
+                <Option key={region.value} value={region.value}>
+                  {region.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="year"
+            label="年份"
+          >
+            <Input
+              placeholder="输入年份"
+              value={year}
+              onChange={(e) => {
+                setYear(e.target.value);
+                form.setFieldsValue({ year: e.target.value });
+              }}
+              className="text-center"
+            />
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {genres.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="codecFormat"
+            label="编码格式"
+          >
+            <Select
+              placeholder="请选择编码格式"
+              value={codecFormat}
+              onChange={(value) => {
+                setCodecFormat(value);
+                form.setFieldsValue({ codecFormat: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择编码格式</Option>
+              {codecFormats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="resolution"
+            label="分辨率"
+          >
+            <Select
+              placeholder="请选择分辨率"
+              value={resolution}
+              onChange={(value) => {
+                setResolution(value);
+                form.setFieldsValue({ resolution: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择分辨率</Option>
+              {resolutions.map((resolution) => (
+                <Option key={resolution.value} value={resolution.value}>
+                  {resolution.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 剧集 */}
+      {showTvFields && (
+        <>
+          <Form.Item
+            name="region"
+            label="地区"
+          >
+            <Select
+              placeholder="请选择地区"
+              value={region}
+              onChange={(value) => {
+                setRegion(value);
+                form.setFieldsValue({ region: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择地区</Option>
+              {regions.map((region) => (
+                <Option key={region.value} value={region.value}>
+                  {region.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {genres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 游戏 */}
+      {showGameFields && (
+        <>
+          <Form.Item
+            name="platform"
+            label="平台"
+          >
+            <Select
+              placeholder="请选择平台"
+              value={platform}
+              onChange={(value) => {
+                setPlatform(value);
+                form.setFieldsValue({ platform: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择平台</Option>
+              {platforms.map((platform) => (
+                <Option key={platform.value} value={platform.value}>
+                  {platform.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {gamegenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="language"
+            label="语言"
+          >
+            <Select
+              placeholder="请选择语言"
+              value={language}
+              onChange={(value) => {
+                setLanguage(value);
+                form.setFieldsValue({ language: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择语言</Option>
+              {languages.map((language) => (
+                <Option key={language.value} value={language.value}>
+                  {language.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="dataType"
+            label="数据类型"
+          >
+            <Select
+              placeholder="请选择数据类型"
+              value={dataType}
+              onChange={(value) => {
+                setDataType(value);
+                form.setFieldsValue({ dataType: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择数据类型</Option>
+              {dataTypes.map((dataType) => (
+                <Option key={dataType.value} value={dataType.value}>
+                  {dataType.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 综艺 */}
+      {showvarietyFields && (
+        <>
+          <Form.Item
+            name="isMainland"
+            label="是否大陆综艺"
+            valuePropName="checked"
+          >
+            <Switch 
+              checked={isMainland}
+              onChange={(checked) => {
+                setIsMainland(checked);
+                form.setFieldsValue({ isMainland: checked });
+              }}
+            />
+          </Form.Item>
+          <Form.Item
+            name="style"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={style}
+              onChange={(value) => {
+                setStyle(value);
+                form.setFieldsValue({ style: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {varietygenres.map((style) => (
+                <Option key={style.value} value={style.value}>
+                  {style.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 动漫 */}
+      {showAnimeFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {anigenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {animeformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="resolution"
+            label="分辨率"
+          >
+            <Select
+              placeholder="请选择分辨率"
+              value={resolution}
+              onChange={(value) => {
+                setResolution(value);
+                form.setFieldsValue({ resolution: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择分辨率</Option>
+              {resolutions.map((resolution) => (
+                <Option key={resolution.value} value={resolution.value}>
+                  {resolution.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 学习 */}
+      {showlearningFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {learninggenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {learningformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 软件 */}
+      {showsoftwareFields && (
+        <>
+          <Form.Item
+            name="platform"
+            label="平台"
+          >
+            <Select
+              placeholder="请选择平台"
+              value={platform}
+              onChange={(value) => {
+                setPlatform(value);
+                form.setFieldsValue({ platform: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择平台</Option>
+              {softwareplatforms.map((platform) => (
+                <Option key={platform.value} value={platform.value}>
+                  {platform.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {softwaregenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {softwareformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 体育 */}
+      {showsportsFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {sportsgenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="eventType"
+            label="赛事类型"
+          >
+            <Select
+              placeholder="请选择赛事类型"
+              value={eventType}
+              onChange={(value) => {
+                setEventType(value);
+                form.setFieldsValue({ eventType: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择赛事类型</Option>
+              {eventTypes.map((eventType) => (
+                <Option key={eventType.value} value={eventType.value}>
+                  {eventType.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 纪录片 */}
+      {showdocFields && (
+        <>
+          <Form.Item
+            name="year"
+            label="年份"
+          >
+            <Input
+              placeholder="如 1999, 2020"
+              value={year}
+              onChange={(e) => {
+                setYear(e.target.value);
+                form.setFieldsValue({ year: e.target.value });
+              }}
+              className="w-full"
+            />
+          </Form.Item>
+          <Form.Item
+            name="source"
+            label="视频源"
+          >
+            <Select
+              placeholder="请选择视频源"
+              value={source}
+              onChange={(value) => {
+                setSource(value);
+                form.setFieldsValue({ source: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择视频源</Option>
+              {sourceTypes.map((source) => (
+                <Option key={source.value} value={source.value}>
+                  {source.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 音乐 */}
+      {showMusicFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {musicgenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="region"
+            label="地区"
+          >
+            <Select
+              placeholder="请选择地区"
+              value={region}
+              onChange={(value) => {
+                setRegion(value);
+                form.setFieldsValue({ region: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择地区</Option>
+              {regions.map((region) => (
+                <Option key={region.value} value={region.value}>
+                  {region.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="style"
+            label="风格"
+          >
+            <Select
+              placeholder="请选择风格"
+              value={style}
+              onChange={(value) => {
+                setStyle(value);
+                form.setFieldsValue({ style: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择风格</Option>
+              {musicstyles.map((style) => (
+                <Option key={style.value} value={style.value}>
+                  {style.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {musicformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 其他 */}
+      {showotherFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {othergenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+ {/* 提交按钮 */}
+          <Form.Item>
+            <Button 
+              type="primary" 
+              htmlType="submit" 
+              className="submitButton"
+              onMouseOver={(e) => e.target.style.backgroundColor = '#ff7f00'}
+              onMouseOut={(e) => e.target.style.backgroundColor = '#ff8c00'}
+            >
+              上传种子
+            </Button>
+          </Form.Item>
+
+          {showSuccess && (
+            <div className="successMessage">
+              上传成功!
+            </div>
+          )}
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+export default UploadTorrentFull;
+
diff --git a/src/components/upload.jsx b/src/components/upload.jsx
new file mode 100644
index 0000000..c297fa8
--- /dev/null
+++ b/src/components/upload.jsx
@@ -0,0 +1,2002 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+import "../upload.css";
+import "../uploadtorrent.css";
+import { Form, Input, Select, Button, Typography, Space, message,Switch } from 'antd';
+import { InboxOutlined } from '@ant-design/icons';
+const { TextArea } = Input;
+const { Text } = Typography;
+import Navbar from './Navbar';
+
+
+function UploadTorrent() {
+  const [userid,setuserid] = useState(1);
+  const [title, setTitle] = useState('');
+  const [description, setDescription] = useState('');
+  const [categoryId, setCategoryId] = useState('');
+  const [file, setFile] = useState(null);
+  const [categories, setCategories] = useState([]);
+  const [showSuccess, setShowSuccess] = useState(false);
+  const [form] = Form.useForm();
+  
+  // 通用参数
+  const [dpi, setDpi] = useState('');
+  const [caption, setCaption] = useState('');
+  const [region, setRegion] = useState('');
+  const [year, setYear] = useState('');
+  const [genre, setGenre] = useState('');
+  const [format, setFormat] = useState('');
+  const [resolution, setResolution] = useState('');
+  const [coverImage, setCoverImage] = useState(null);
+  
+  // 特殊参数
+  const [codecFormat, setCodecFormat] = useState('');
+  const [platform, setPlatform] = useState('');
+  const [language, setLanguage] = useState('');
+  const [eventType, setEventType] = useState('');
+  const [source, setSource] = useState('');
+  const [style, setStyle] = useState('');
+  const [dataType, setdataType] = useState('');
+  const [isMainland, setIsMainland] = useState(false);
+
+  // 根据分类显示不同的表单字段
+  const [showMovieFields, setShowMovieFields] = useState(false);
+  const [showMusicFields, setShowMusicFields] = useState(false);
+  const [showGameFields, setShowGameFields] = useState(false);
+  const [showTvFields, setShowTvFields] = useState(false);
+  const [showAnimeFields, setShowAnimeFields] = useState(false);
+  const [showlearningFields, setShowlearningFields] = useState(false);
+  const [showsoftwareFields, setShowsoftwareFields] = useState(false);
+  const [showvarietyFields, setShowvarietyFields] = useState(false);
+  const [showsportsFields, setShowsportsFields] = useState(false);
+  const [showdocFields, setShowdocFields] = useState(false);
+  const [showotherFields, setShowotherFields] = useState(false);
+  // 其他分类字段...
+  // 编码格式选项
+  const codecFormats = [
+    { value: 'H.264', label: 'H.264' },
+    { value: 'H.265', label: 'H.265' },
+    { value: 'AV1', label: 'AV1' },
+    { value: 'VP9', label: 'VP9' },
+    { value: 'VC1', label: 'VC1' },
+    { value: 'X264', label: 'X264' },
+  ];
+  const regions = [
+    { value: '大陆', label: '大陆' },
+    { value: '港台', label: '港台' },
+    { value: '欧美', label: '欧美' },
+    { value: '日韩', label: '日韩' },
+    { value: '其他', label: '其他' },
+  ];
+  const genres = [
+    { value: '动作', label: '动作' },
+    { value: '喜剧', label: '喜剧' },
+    { value: '爱情', label: '爱情' },
+    { value: '科幻', label: '科幻' },
+    { value: '恐怖', label: '恐怖' },
+    { value: '动作', label: '动作' },
+    { value: '冒险', label: '冒险' },
+    { value: '历史', label: '历史' },
+    { value: '悬疑', label: '悬疑' },
+    { value: '其他', label: '其他' },
+  ];
+  const resolutions = [
+    { value: '720p', label: '720p' },
+    { value: '1080p', label: '1080p' },
+    { value: '2K', label: '2K' },
+    { value: '4K', label: '4K' },
+    { value: '8K', label: '8K' },
+    { value: '其他', label: '其他' },
+  ];
+
+
+  const eventTypes = [
+    { value: '足球', label: '足球' },
+    { value: '篮球', label: '篮球' },
+    { value: '网球', label: '网球' },
+    { value: '乒乓球', label: '乒乓球' },
+    { value: '羽毛球', label: '羽毛球' },
+  ]
+  const styles = [
+    { value: '大陆综艺', label: '大陆综艺' },
+    { value: '日韩综艺', label: '日韩综艺' },
+    { value: '欧美综艺', label: '欧美综艺' },
+    { value: '其他', label: '其他' },
+  ]
+  const platforms = [
+    { value: 'PC', label: 'PC' },
+    { value: 'PS5', label: 'PS5' },
+    { value: 'Xbox', label: 'Xbox' },
+    { value: 'Switch', label: 'Switch' },
+    { value: '手机', label: '手机' },
+    { value: '其他', label: '其他' },
+  ]
+  const gamegenres = [
+    { value: '角色扮演', label: '角色扮演' },
+    { value: '射击', label: '射击' },
+    { value: '冒险', label: '冒险' },
+    { value: '策略', label: '策略' },
+    { value: '体育', label: '体育' },
+    { value: '桌面游戏', label: '桌面游戏'},
+    { value: '其他', label: '其他' },
+  ]
+  const dataTypes = [
+    { value: '压缩包', label: '压缩包' },
+    { value: '补丁', label: '补丁' },
+    { value: '安装包', label: '安装包' },
+    { value: 'nds', label: 'nds' },
+    { value: '其他', label: '其他' },
+  ]
+  const languages = [
+    { value: '中文', label: '中文' },
+    { value: '英文', label: '英文' },
+    { value: '日文', label: '日文' },
+    { value: '其他', label: '其他' },
+  ]
+  const musicgenres = [
+    { value: '专辑', label: '专辑' },
+    { value: '单曲', label: '单曲' },
+    { value: 'EP', label: 'EP' },
+    { value: '现场', label: '现场' },
+    { value: '其他', label: '其他' },
+  ]
+  const musicstyles = [
+    { value: '流行', label: '流行' },
+    { value: '摇滚', label: '摇滚' },
+    { value: '电子', label: '电子' },
+    { value: '古典', label: '古典' },
+    { value: '爵士', label: '爵士' },
+    { value: '民谣', label: '民谣' },
+    { value: '说唱', label: '说唱' },
+    { value: '其他', label: '其他' },
+  ]
+  const musicformats = [
+    { value: 'MP3', label: 'MP3' },
+    { value: 'FLAC', label: 'FLAC' },
+    { value: 'WAV', label: 'WAV' },
+    { value: 'AAC', label: 'AAC' },
+    { value: 'OGG', label: 'OGG' },
+    { value: '其他', label: '其他' },
+  ]
+  const anigenres = [
+    { value: '新番连载', label: '新番连载' },
+    { value: '剧场版', label: '剧场版' },
+    { value: 'OVA', label: 'OVA' },
+    { value: '完结动漫', label: '完结动漫' },
+    { value: '其他', label: '其他' },
+  ]
+  const animeformats = [
+    { value: 'ZIP', label: 'ZIP' },
+    { value: 'RAR', label: 'RAR' },
+    { value: '7Z', label: '7Z' },
+    { value: 'MKV', label: 'MKV' },
+    { value: 'MP4', label: 'MP4' },
+    { value: '其他', label: '其他' },
+  ]
+  const varietygenres = [
+    { value: '真人秀', label: '真人秀' },
+    { value: '选秀', label: '选秀' },
+    { value: '访谈', label: '访谈' },
+    { value: '游戏', label: '游戏' },
+    { value: '音乐', label: '音乐' },
+    { value: '其他', label: '其他' },
+  ]
+  const sportsgenres = [
+    { value: '足球', label: '足球' },
+    { value: '篮球', label: '篮球' },
+    { value: '网球', label: '网球' },
+    { value: '乒乓球', label: '乒乓球' },
+    { value: '羽毛球', label: '羽毛球' },
+    { value: '其他', label: '其他' },
+  ]
+  const softwaregenres = [
+    { value: '系统软件', label: '系统软件' },
+    { value: '应用软件', label: '应用软件' },
+    { value: '游戏软件', label: '游戏软件' },
+    { value: '驱动程序', label: '驱动程序' },
+    { value: '办公软件', label: '办公软件' },
+    { value: '其他', label: '其他' },
+  ]
+  const softwareplatforms = [
+    { value: 'Windows', label: 'Windows' },
+    { value: 'Mac', label: 'Mac' },
+    { value: 'Linux', label: 'Linux' },
+    { value: 'Android', label: 'Android' },
+    { value: 'iOS', label: 'iOS' },
+    { value: '其他', label: '其他' },
+  ]
+  const softwareformats = [
+    { value: 'EXE', label: 'EXE' }, 
+    { value: 'DMG', label: 'DMG' },
+    { value: '光盘镜像', label: '光盘镜像' },
+    { value: 'APK', label: 'APK' },
+    { value: 'IPA', label: 'IPA' },
+    { value: '其他', label: '其他' },
+  ]
+  const learninggenres = [
+    { value: '计算机', label: '计算机' },
+    { value: '软件', label: '软件' },
+    { value: '人文', label: '人文' },
+    { value: '外语', label: '外语' },
+    { value: '理工类', label: '理工类' },
+    { value: '其他', label: '其他' },
+  ]
+  const learningformats = [
+    { value: 'PDF', label: 'PDF' },
+    { value: 'EPUB', label: 'EPUB' },
+    { value: '视频', label: '视频' },
+    { value: '音频', label: '音频' },
+    { value: 'PPT', label: 'PPT' },
+    { value: '其他', label: '其他' },
+  ]
+  const sourceTypes = [
+    { value: 'CCTV', label: 'CCTV' },
+    { value: '卫视', label: '卫视' },
+    { value: '国家地理', label: '国家地理' },
+    { value: 'BBC', label: 'BBC' },
+    { value: 'Discovery', label: 'Discovery' },
+    { value: '其他', label: '其他' },
+  ]
+  const othergenres = [
+    { value: '电子书', label: '电子书' },
+    { value: '视频', label: '视频' },
+    { value: 'MP3', label: 'MP3' },
+    { value: '图片', label: '图片' },
+    { value: '其他', label: '其他' },
+  ]
+  useEffect(() => {
+    axios.get('http://localhost:8080/categories')
+      .then(res => setCategories(res.data))
+      .catch(err => console.error('加载分类失败', err));
+  }, []);
+
+  // 根据选择的分类显示不同的表单字段
+  useEffect(() => {
+    setShowMovieFields(categoryId === '1');
+    setShowMusicFields(categoryId === '3');
+    setShowGameFields(categoryId === '5');
+    setShowTvFields(categoryId === '2');
+    setShowAnimeFields(categoryId === '4');
+    setShowlearningFields(categoryId === '9');
+    setShowsoftwareFields(categoryId === '8');
+    setShowvarietyFields(categoryId === '6');
+    setShowsportsFields(categoryId === '7');
+    setShowdocFields(categoryId === '10');
+    setShowotherFields(categoryId === '11');
+    // 其他分类...
+  }, [categoryId]);
+
+
+  
+  const handleSubmit = async (e) => {
+    //e.preventDefault();
+    if (!coverImage) {
+      alert('请选择一个 图片 文件');
+      return;
+    }
+    if (!file) {
+      alert('请选择一个 .torrent 文件');
+      return;
+    }
+
+    if (!categoryId) {
+      alert('请选择分类');
+      return;
+    }
+    
+
+    const formData = new FormData();
+    formData.append('userid', userid);
+    formData.append('file', file);
+    // Add cover image if it exists
+    formData.append('coverImage', coverImage);
+    formData.append('title', title);
+    formData.append('description', description);
+    formData.append('categoryId', categoryId);
+
+    
+    // 通用参数
+    if (dpi) formData.append('dpi', dpi);
+    if (caption) formData.append('caption', caption);
+    if (region) formData.append('region', region);
+    if (year) formData.append('year', year);
+    if (genre) formData.append('genre', genre);
+    if (format) formData.append('format', format);
+    if (resolution) formData.append('resolution', resolution);
+    
+    // 特殊参数
+    if (codecFormat) formData.append('codecFormat', codecFormat);
+    if (platform) formData.append('platform', platform);
+    if (language) formData.append('language', language);
+    if (eventType) formData.append('eventType', eventType);
+    if (source) formData.append('source', source);
+    if (style) formData.append('style', style);
+    if (dataType) formData.append('dataType', dataType);
+    formData.append('isMainland', isMainland.toString());
+
+    try {
+      const response = await axios.post('http://localhost:8080/torrent/upload', formData, {
+        headers: { 'Content-Type': 'multipart/form-data' },
+        responseType: 'blob',
+      });
+
+      // 创建下载链接
+      const url = window.URL.createObjectURL(new Blob([response.data]));
+      const link = document.createElement('a');
+      link.href = url;
+      link.setAttribute('download', file.name);
+      document.body.appendChild(link);
+      link.click();
+      link.remove();
+
+      // 显示成功提示
+      setShowSuccess(true);
+      // 清空表单
+      setTitle('');
+      setDescription('');
+      setCategoryId('');
+      setFile(null);
+      // 清空其他字段...
+    } catch (err) {
+      console.error('上传失败', err.response?.data || err.message);
+      alert(err.response?.data || '上传失败,请检查后端是否启动');
+    }
+  };
+
+//   return (
+//   <div className="max-w-2xl mx-auto mt-10 p-6 bg-white shadow rounded">
+//   <h2 className="text-2xl font-bold mb-6 text-orange-800 text-center border-b-2 border-orange-200 pb-3">上传种子</h2>
+//   <form onSubmit={handleSubmit} className="space-y-6">
+//     {/* 封面图片 - 大型上传区域 */}
+//     <div className="form-group text-center">
+//       <label className="upload-area text-orange-800 font-medium cursor-pointer p-8 border-2 border-dashed border-orange-300 rounded-lg hover:border-orange-400 transition-colors">
+//         <svg xmlns="http://www.w3.org/2000/svg" className="mx-auto h-12 w-12 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+//           <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
+//         </svg>
+//         <p className="mt-2 text-sm">点击或拖拽上传封面图片</p>
+//         <input 
+//           type="file" 
+//           accept="image/*" 
+//           onChange={(e) => setCoverImage(e.target.files[0])} 
+//           className="hidden"
+//           id="cover-image-upload"
+//         />
+//       </label>
+//       <input 
+//         type="file" 
+//         accept="image/*" 
+//         onChange={(e) => setCoverImage(e.target.files[0])} 
+//         className="sr-only"
+//         id="cover-image-upload-real"
+//       />
+//     </div>
+
+//     {/* 种子文件 - 大型上传区域 */}
+//     <div className="form-group text-center">
+//       <label className="upload-area text-orange-800 font-medium cursor-pointer p-8 border-2 border-dashed border-orange-300 rounded-lg hover:border-orange-400 transition-colors">
+//         <svg xmlns="http://www.w3.org/2000/svg" className="mx-auto h-12 w-12 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+//           <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
+//         </svg>
+//         <p className="mt-2 text-sm">点击或拖拽上传种子文件(.torrent)</p>
+//         <input 
+//           type="file" 
+//           accept=".torrent" 
+//           onChange={(e) => setFile(e.target.files[0])} 
+//           className="hidden"
+//           id="torrent-file-upload"
+//           required
+//         />
+//       </label>
+//       <input 
+//         type="file" 
+//         accept=".torrent" 
+//         onChange={(e) => setFile(e.target.files[0])} 
+//         className="sr-only"
+//         id="torrent-file-upload-real"
+//         required
+//       />
+//     </div>
+
+//     {/* 标题 */}
+//     <div className="form-group">
+//       <label className="form-label text-orange-800 text-center">标题</label>
+//       <input
+//         type="text"
+//         placeholder="输入种子标题"
+//         value={title}
+//         onChange={(e) => setTitle(e.target.value)}
+//         className="form-control text-center"
+//         required
+//       />
+//     </div>
+
+//     {/* 描述 */}
+//     <div className="form-group">
+//       <label className="form-label text-orange-800 text-center">描述</label>
+//       <textarea
+//         placeholder="输入种子描述"
+//         value={description}
+//         onChange={(e) => setDescription(e.target.value)}
+//         className="form-control text-center"
+//         rows={3}
+//       />
+//     </div>
+
+//     {/* 分类 - 美化下拉框 */}
+//     <div className="form-group">
+//       <label className="form-label text-orange-800 text-center">分类</label>
+//       <div className="relative">
+//         <select
+//           value={categoryId}
+//           onChange={(e) => setCategoryId(e.target.value)}
+//           className="custom-select"
+//           required
+//         >
+//           <option value="">请选择分类</option>
+//           {categories.map(cat => (
+//             <option key={cat.categoryid} value={cat.categoryid}>{cat.category_name}</option>
+//           ))}
+//         </select>
+//         <div className="select-arrow">
+//           <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//             <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//           </svg>
+//         </div>
+//       </div>
+//     </div>
+
+//     {/* 动态字段 - 电影 */}
+//     {showMovieFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">字幕/说明</label>
+//           <input
+//             type="text"
+//             placeholder="输入字幕/说明"
+//             value={caption}
+//             onChange={(e) => setCaption(e.target.value)}
+//             className="form-control text-center"
+//           />
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">地区</label>
+//           <div className="relative">
+//             <select
+//               value={region}
+//               onChange={(e) => setRegion(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择地区</option>
+//               {regions.map((region) => (
+//                 <option key={region.value} value={region.value}>
+//                   {region.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">年份</label>
+//           <input
+//             type="text"
+//             placeholder="输入年份"
+//             value={year}
+//             onChange={(e) => setYear(e.target.value)}
+//             className="form-control text-center"
+//           />
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">类型</label>
+//           <div className="relative">
+//             <select
+//               value={genre}
+//               onChange={(e) => setGenre(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择类型</option>
+//               {genres.map((format) => (
+//                 <option key={format.value} value={format.value}>
+//                   {format.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">编码格式</label>
+//           <div className="relative">
+//             <select
+//               value={codecFormat}
+//               onChange={(e) => setCodecFormat(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择编码格式</option>
+//               {codecFormats.map((format) => (
+//                 <option key={format.value} value={format.value}>
+//                   {format.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800 text-center">分辨率</label>
+//           <div className="relative">
+//             <select
+//               value={resolution}
+//               onChange={(e) => setResolution(e.target.value)}
+//               className="custom-select"
+//             >
+//               <option value="">请选择分辨率</option>
+//               {resolutions.map((resolution) => (
+//                 <option key={resolution.value} value={resolution.value}>
+//                   {resolution.label}
+//                 </option>
+//               ))}
+//             </select>
+//             <div className="select-arrow">
+//               <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-orange-500" viewBox="0 0 20 20" fill="currentColor">
+//                 <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
+//               </svg>
+//             </div>
+//           </div>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 剧集 */}
+//     {showTvFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">地区</label>
+//           <select
+//             value={region}
+//             onChange={(e) => setRegion(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择地区</option>
+//             {regions.map((region) => (
+//               <option key={region.value} value={region.value}>
+//                 {region.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {genres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 游戏 */}
+//     {showGameFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">平台</label>
+//           <select
+//             value={platform}
+//             onChange={(e) => setPlatform(e.target.value)} 
+//             className="form-control"
+//           >
+//             <option value="">请选择平台</option>
+//             {platforms.map((platform) => (
+//               <option key={platform.value} value={platform.value}>
+//                 {platform.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>  
+//             {gamegenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">语言</label>
+//           <select
+//             value={language}
+//             onChange={(e) => setLanguage(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择语言</option>
+//             {languages.map((language) => (
+//               <option key={language.value} value={language.value}>
+//                 {language.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">数据类型</label>
+//           <select
+//             value={dataType}
+//             onChange={(e) => setdataType(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择数据类型</option>
+//             {dataTypes.map((dataType) => (
+//               <option key={dataType.value} value={dataType.value}>
+//                 {dataType.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 综艺 */}
+//     {showvarietyFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="flex items-center">
+//             <input
+//               type="checkbox"
+//               checked={isMainland}
+//               onChange={(e) => setIsMainland(e.target.checked)}
+//               className="mr-2"
+//             />
+//             是否大陆综艺
+//           </label>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={style}
+//             onChange={(e) => setStyle(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {varietygenres.map((style) => (
+//               <option key={style.value} value={style.value}>
+//                 {style.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 动漫 */}
+//     {showAnimeFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {anigenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {animeformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">分辨率</label>
+//           <select
+//             value={resolution}
+//             onChange={(e) => setResolution(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择分辨率</option>
+//             {resolutions.map((resolution) => (
+//               <option key={resolution.value} value={resolution.value}>
+//                 {resolution.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 学习 */}
+//     {showlearningFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {learninggenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {learningformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 软件 */}
+//     {showsoftwareFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">平台</label>
+//           <select
+//             value={platform}
+//             onChange={(e) => setPlatform(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择平台</option>
+//             {softwareplatforms.map((platform) => (
+//               <option key={platform.value} value={platform.value}>
+//                 {platform.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {softwaregenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {softwareformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 体育 */}
+//     {showsportsFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {sportsgenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">赛事类型</label>
+//           <select
+//             value={eventType}
+//             onChange={(e) => setEventType(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择赛事类型</option>
+//             {eventTypes.map((eventType) => (
+//               <option key={eventType.value} value={eventType.value}>
+//                 {eventType.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 纪录片 */}
+//     {showdocFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">年份</label>
+//           <input
+//             type="text"
+//             placeholder="如 1999, 2020"
+//             value={year}
+//             onChange={(e) => setYear(e.target.value)}
+//             className="form-control"
+//           />
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">视频源</label>
+//           <select
+//             value={source}
+//             onChange={(e) => setSource(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择视频源</option>
+//             {sourceTypes.map((source) => (
+//               <option key={source.value} value={source.value}>
+//                 {source.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {resolutions.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 音乐 */}
+//     {showMusicFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {musicgenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">地区</label>
+//           <select
+//             value={region}
+//             onChange={(e) => setRegion(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择地区</option>
+//             {regions.map((region) => (
+//               <option key={region.value} value={region.value}>
+//                 {region.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">风格</label>
+//           <select
+//             value={style}
+//             onChange={(e) => setStyle(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择风格</option>
+//             {musicstyles.map((style) => (
+//               <option key={style.value} value={style.value}>
+//                 {style.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">格式</label>
+//           <select
+//             value={format}
+//             onChange={(e) => setFormat(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择格式</option>
+//             {musicformats.map((format) => (
+//               <option key={format.value} value={format.value}>
+//                 {format.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+//     {/* 动态字段 - 其他 */}
+//     {showotherFields && (
+//       <>
+//         <div className="form-group">
+//           <label className="form-label text-orange-800">类型</label>
+//           <select
+//             value={genre}
+//             onChange={(e) => setGenre(e.target.value)}
+//             className="form-control"
+//           >
+//             <option value="">请选择类型</option>
+//             {othergenres.map((genre) => (
+//               <option key={genre.value} value={genre.value}>
+//                 {genre.label}
+//               </option>
+//             ))}
+//           </select>
+//         </div>
+//       </>
+//     )}
+
+
+//     {/* 其他动态字段... (保持相同的美化样式) */}
+//     {/* 这里省略了其他动态字段的代码,但它们都使用相同的自定义下拉框样式 */}
+    
+//     {/* 提交按钮 - 居中 */}
+//     <div className="text-center">
+//       <button 
+//         type="submit" 
+//         className="submit-btn"
+//       >
+//         上传种子
+//       </button>
+//     </div>
+
+//     {showSuccess && (
+//       <div className="success-message text-center">
+//         上传成功!
+//       </div>
+//     )}
+//   </form>
+// </div>
+//   );
+// }
+return (
+  <div>
+  <Navbar  style={{ width: '100%' }}/>
+    <div className="container">
+      <div className="card">
+        <h2 className="title">上传种子</h2>
+        <Form
+          layout="vertical"
+          onFinish={handleSubmit}
+          className="form"
+        >
+         {/* 封面图片 - 自定义上传区域 */}
+<Form.Item
+  name="coverImage"
+   label={<span style={{ fontSize: '19px'  , fontWeight: 'bold'}}>封面图片</span>} 
+  rules={[{ required: true, message: '请上传封面图片' }]}
+>
+  <div 
+    className="uploadArea"
+    onClick={() => document.getElementById('cover-image-upload').click()}
+  >
+    <InboxOutlined className="uploadIcon" />
+    <p className="uploadText">点击或拖拽上传封面图片</p>
+    <input
+      type="file"
+      accept="image/*"
+      onChange={(e) => {
+        setCoverImage(e.target.files[0]);
+        form.setFieldsValue({ coverImage: e.target.files[0] });
+      }}
+      className="hiddenInput"
+      id="cover-image-upload"
+    />
+  </div>
+</Form.Item>
+
+{/* 种子文件 - 自定义上传区域 */}
+<Form.Item
+  name="torrentFile"
+   label={<span style={{ fontSize: '19px' , fontWeight: 'bold'}}>种子文件</span>} 
+  rules={[{ required: true, message: '请上传.torrent文件' }]}
+>
+  <div 
+    className="uploadArea"
+    onClick={() => document.getElementById('torrent-file-upload').click()}
+  >
+    <InboxOutlined className="uploadIcon" />
+    <p className="uploadText">点击或拖拽上传种子文件(.torrent)</p>
+    <input
+      type="file"
+      accept=".torrent"
+      onChange={(e) => {
+        setFile(e.target.files[0]);
+        form.setFieldsValue({ torrentFile: e.target.files[0] });
+      }}
+      className="hiddenInput"
+      id="torrent-file-upload"
+    />
+  </div>
+</Form.Item>
+
+          {/* 标题 */}
+          <Form.Item
+            name="title"
+            label={<span style={{ fontSize: '19px'  , fontWeight: 'bold'}}>标题</span>}  // 直接包裹label
+            rules={[{ required: true, message: '请输入标题' }]}
+            //labelCol={{ style: { fontSize: '30px !important ' } }} // ✅ 调整 Label 字体
+          >
+            <Input
+              placeholder="输入种子标题"
+              value={title}
+              onChange={(e) => {
+                setTitle(e.target.value);
+                form.setFieldsValue({ title: e.target.value });
+              }}
+              //style={styles.input}
+              style={{ fontSize: '19px' }} // ✅ 调整 Input 字体
+            />
+          </Form.Item>
+
+          {/* 描述 */}
+          <Form.Item
+            name="description"
+             label={<span style={{ fontSize: '19px'  , fontWeight: 'bold'}}>描述</span>} 
+          >
+            <TextArea
+              placeholder="输入种子描述"
+              value={description}
+              onChange={(e) => {
+                setDescription(e.target.value);
+                form.setFieldsValue({ description: e.target.value });
+              }}
+              rows={3}
+              style={styles.textArea}
+            />
+          </Form.Item>
+
+          {/* 分类 - 美化下拉框 */}
+          <Form.Item
+            name="categoryId"
+             label={<span style={{ fontSize: '19px' , fontWeight: 'bold' }}>分类</span>} 
+            rules={[{ required: true, message: '请选择分类' }]}
+          >
+            <Select
+              placeholder="请选择分类"
+              value={categoryId}
+              onChange={(value) => {
+                const stringValue = String(value);
+                setCategoryId(stringValue);
+                console.log('Selected category ID:', stringValue);
+                form.setFieldsValue({ categoryId: value });
+                // 触发分类变化后的逻辑
+                setShowMovieFields(value === '1');
+                setShowTvFields(value === '2');
+                setShowAnimeFields(value === '4');
+                setShowGameFields(value === '5');
+                setShowvarietyFields(value === '6');
+                setShowMusicFields(value === '3');
+                setShowlearningFields(value === '9');
+                setShowsoftwareFields(value === '8');
+                setShowsportsFields(value === '7');
+                setShowdocFields(value === '10');
+                setShowotherFields(value === '11');
+              }}
+              style={styles.select}
+            >
+              <Option value="">请选择分类</Option>
+              {categories.map(cat => (
+                <Option key={cat.categoryid} value={cat.categoryid}>{cat.category_name}</Option>
+              ))}
+            </Select>
+          </Form.Item>
+
+      {/* 动态字段 - 电影 */}
+      {showMovieFields && (
+        <>
+          <Form.Item
+            name="caption"
+            label="字幕/说明"
+            rules={[{ required: true, message: '请输入字幕/说明' }]}
+          >
+            <Input
+              placeholder="输入字幕/说明"
+              value={caption}
+              onChange={(e) => {
+                setCaption(e.target.value);
+                form.setFieldsValue({ caption: e.target.value });
+              }}
+              className="text-center"
+            />
+          </Form.Item>
+          <Form.Item
+            name="region"
+            label="地区"
+          >
+            <Select
+              placeholder="请选择地区"
+              value={region}
+              onChange={(value) => {
+                setRegion(value);
+                form.setFieldsValue({ region: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择地区</Option>
+              {regions.map((region) => (
+                <Option key={region.value} value={region.value}>
+                  {region.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="year"
+            label="年份"
+          >
+            <Input
+              placeholder="输入年份"
+              value={year}
+              onChange={(e) => {
+                setYear(e.target.value);
+                form.setFieldsValue({ year: e.target.value });
+              }}
+              className="text-center"
+            />
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {genres.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="codecFormat"
+            label="编码格式"
+          >
+            <Select
+              placeholder="请选择编码格式"
+              value={codecFormat}
+              onChange={(value) => {
+                setCodecFormat(value);
+                form.setFieldsValue({ codecFormat: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择编码格式</Option>
+              {codecFormats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="resolution"
+            label="分辨率"
+          >
+            <Select
+              placeholder="请选择分辨率"
+              value={resolution}
+              onChange={(value) => {
+                setResolution(value);
+                form.setFieldsValue({ resolution: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择分辨率</Option>
+              {resolutions.map((resolution) => (
+                <Option key={resolution.value} value={resolution.value}>
+                  {resolution.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 剧集 */}
+      {showTvFields && (
+        <>
+          <Form.Item
+            name="region"
+            label="地区"
+          >
+            <Select
+              placeholder="请选择地区"
+              value={region}
+              onChange={(value) => {
+                setRegion(value);
+                form.setFieldsValue({ region: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择地区</Option>
+              {regions.map((region) => (
+                <Option key={region.value} value={region.value}>
+                  {region.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {genres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 游戏 */}
+      {showGameFields && (
+        <>
+          <Form.Item
+            name="platform"
+            label="平台"
+          >
+            <Select
+              placeholder="请选择平台"
+              value={platform}
+              onChange={(value) => {
+                setPlatform(value);
+                form.setFieldsValue({ platform: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择平台</Option>
+              {platforms.map((platform) => (
+                <Option key={platform.value} value={platform.value}>
+                  {platform.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {gamegenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="language"
+            label="语言"
+          >
+            <Select
+              placeholder="请选择语言"
+              value={language}
+              onChange={(value) => {
+                setLanguage(value);
+                form.setFieldsValue({ language: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择语言</Option>
+              {languages.map((language) => (
+                <Option key={language.value} value={language.value}>
+                  {language.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="dataType"
+            label="数据类型"
+          >
+            <Select
+              placeholder="请选择数据类型"
+              value={dataType}
+              onChange={(value) => {
+                setDataType(value);
+                form.setFieldsValue({ dataType: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择数据类型</Option>
+              {dataTypes.map((dataType) => (
+                <Option key={dataType.value} value={dataType.value}>
+                  {dataType.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 综艺 */}
+      {showvarietyFields && (
+        <>
+          <Form.Item
+            name="isMainland"
+            label="是否大陆综艺"
+            valuePropName="checked"
+          >
+            <Switch 
+              checked={isMainland}
+              onChange={(checked) => {
+                setIsMainland(checked);
+                form.setFieldsValue({ isMainland: checked });
+              }}
+            />
+          </Form.Item>
+          <Form.Item
+            name="style"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={style}
+              onChange={(value) => {
+                setStyle(value);
+                form.setFieldsValue({ style: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {varietygenres.map((style) => (
+                <Option key={style.value} value={style.value}>
+                  {style.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 动漫 */}
+      {showAnimeFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {anigenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {animeformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="resolution"
+            label="分辨率"
+          >
+            <Select
+              placeholder="请选择分辨率"
+              value={resolution}
+              onChange={(value) => {
+                setResolution(value);
+                form.setFieldsValue({ resolution: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择分辨率</Option>
+              {resolutions.map((resolution) => (
+                <Option key={resolution.value} value={resolution.value}>
+                  {resolution.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 学习 */}
+      {showlearningFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {learninggenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {learningformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 软件 */}
+      {showsoftwareFields && (
+        <>
+          <Form.Item
+            name="platform"
+            label="平台"
+          >
+            <Select
+              placeholder="请选择平台"
+              value={platform}
+              onChange={(value) => {
+                setPlatform(value);
+                form.setFieldsValue({ platform: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择平台</Option>
+              {softwareplatforms.map((platform) => (
+                <Option key={platform.value} value={platform.value}>
+                  {platform.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {softwaregenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {softwareformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 体育 */}
+      {showsportsFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {sportsgenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="eventType"
+            label="赛事类型"
+          >
+            <Select
+              placeholder="请选择赛事类型"
+              value={eventType}
+              onChange={(value) => {
+                setEventType(value);
+                form.setFieldsValue({ eventType: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择赛事类型</Option>
+              {eventTypes.map((eventType) => (
+                <Option key={eventType.value} value={eventType.value}>
+                  {eventType.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 纪录片 */}
+      {showdocFields && (
+        <>
+          <Form.Item
+            name="year"
+            label="年份"
+          >
+            <Input
+              placeholder="如 1999, 2020"
+              value={year}
+              onChange={(e) => {
+                setYear(e.target.value);
+                form.setFieldsValue({ year: e.target.value });
+              }}
+              className="w-full"
+            />
+          </Form.Item>
+          <Form.Item
+            name="source"
+            label="视频源"
+          >
+            <Select
+              placeholder="请选择视频源"
+              value={source}
+              onChange={(value) => {
+                setSource(value);
+                form.setFieldsValue({ source: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择视频源</Option>
+              {sourceTypes.map((source) => (
+                <Option key={source.value} value={source.value}>
+                  {source.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {resolutions.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 音乐 */}
+      {showMusicFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {musicgenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="region"
+            label="地区"
+          >
+            <Select
+              placeholder="请选择地区"
+              value={region}
+              onChange={(value) => {
+                setRegion(value);
+                form.setFieldsValue({ region: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择地区</Option>
+              {regions.map((region) => (
+                <Option key={region.value} value={region.value}>
+                  {region.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="style"
+            label="风格"
+          >
+            <Select
+              placeholder="请选择风格"
+              value={style}
+              onChange={(value) => {
+                setStyle(value);
+                form.setFieldsValue({ style: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择风格</Option>
+              {musicstyles.map((style) => (
+                <Option key={style.value} value={style.value}>
+                  {style.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name="format"
+            label="格式"
+          >
+            <Select
+              placeholder="请选择格式"
+              value={format}
+              onChange={(value) => {
+                setFormat(value);
+                form.setFieldsValue({ format: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择格式</Option>
+              {musicformats.map((format) => (
+                <Option key={format.value} value={format.value}>
+                  {format.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+
+      {/* 动态字段 - 其他 */}
+      {showotherFields && (
+        <>
+          <Form.Item
+            name="genre"
+            label="类型"
+          >
+            <Select
+              placeholder="请选择类型"
+              value={genre}
+              onChange={(value) => {
+                setGenre(value);
+                form.setFieldsValue({ genre: value });
+              }}
+              className="w-full"
+            >
+              <Option value="">请选择类型</Option>
+              {othergenres.map((genre) => (
+                <Option key={genre.value} value={genre.value}>
+                  {genre.label}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </>
+      )}
+ {/* 提交按钮 */}
+          <Form.Item>
+            <Button 
+              type="primary" 
+              htmlType="submit" 
+              className="submitButton"
+              onMouseOver={(e) => e.target.style.backgroundColor = '#ff7f00'}
+              onMouseOut={(e) => e.target.style.backgroundColor = '#ff8c00'}
+            >
+              上传种子
+            </Button>
+          </Form.Item>
+
+          {showSuccess && (
+            <div className="successMessage">
+              上传成功!
+            </div>
+          )}
+        </Form>
+      </div>
+    </div>
+    </div>
+  );
+}
+
+export default UploadTorrent;
+
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/main.jsx b/src/main.jsx
new file mode 100644
index 0000000..62c9250
--- /dev/null
+++ b/src/main.jsx
@@ -0,0 +1,11 @@
+// src/main.jsx 或 src/index.jsx
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import { BrowserRouter } from 'react-router-dom';
+import App from './App';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+  <BrowserRouter>
+    <App />
+  </BrowserRouter>
+);
diff --git a/src/pages/AdminPage.jsx b/src/pages/AdminPage.jsx
new file mode 100644
index 0000000..f9af360
--- /dev/null
+++ b/src/pages/AdminPage.jsx
@@ -0,0 +1,135 @@
+import React, { useState } from 'react';
+import { Layout, Menu, Button } from 'antd';
+import {
+    FileTextOutlined,
+    FlagOutlined,
+    TagsOutlined,
+    DeploymentUnitOutlined,
+    HomeOutlined,
+    FileSearchOutlined
+} from '@ant-design/icons';
+import { useNavigate } from 'react-router-dom';
+import PostAdminPanel from '../components/PostAdminPanel';
+import AdminActivityManager from '../components/AdminActivityManager';
+import ActivityAdminPanel from '../components/ActivityAdminPanel';
+import RequestAdminPanel from '../components/RequestAdminPanel';
+import ComplainAdminPanel from '../components/ComplainAdminPanel';
+import TorrentManagement from '../components/torrentmanage';
+import UserManagement from '../components/UserManagement';
+
+const { Header, Sider, Content, Footer } = Layout;
+
+const AdminPage = () => {
+    const navigate = useNavigate();
+    const [selectedKey, setSelectedKey] = useState('posts');
+
+    const renderContent = () => {
+        switch (selectedKey) {
+            case 'posts':
+                return <PostAdminPanel />;
+            case 'activities':
+                return <ActivityAdminPanel />;
+            case 'requests':
+                return <RequestAdminPanel />;
+            case 'complain':
+                return <ComplainAdminPanel />;
+            case 'torrent':
+                return <TorrentManagement/>;
+                 case 'user':
+                return <UserManagement/>;
+            default:
+                return null;
+        }
+    };
+
+    return (
+        <Layout style={{ minHeight: '100vh' }}>
+            {/* 侧边栏 */}
+            <Sider breakpoint="lg" collapsedWidth="0" theme="dark">
+                <div className="logo" style={{
+                    height: 64,
+                    display: 'flex',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                    fontSize: 22,
+                    color: 'white',
+                    fontWeight: 'bold',
+                }}>
+                    后台管理
+                </div>
+                <Menu
+                    theme="dark"
+                    mode="inline"
+                    selectedKeys={[selectedKey]}
+                    onClick={({ key }) => setSelectedKey(key)}
+                    items={[
+                        {
+                            key: 'posts',
+                            icon: <FileTextOutlined />,
+                            label: '帖子管理',
+                        },
+                        {
+                            key: 'activities',
+                            icon: <DeploymentUnitOutlined />,
+                            label: '公告管理',
+                        },
+                        {
+                            key: 'requests',
+                            icon: <FileSearchOutlined />,
+                            label: '求助帖管理',
+                        },
+                        {
+                            key: 'complain',
+                            icon: <FlagOutlined />,
+                            label: '举报管理',
+                        },
+                        {
+                            key: 'torrent',
+                            icon: <TagsOutlined />,
+                            label: '种子管理',
+                        },
+                                                {
+                            key: 'user',
+                            icon: <TagsOutlined />,
+                            label: '用户管理',
+                        },
+                    ]}
+                />
+                <div style={{ padding: 16 }}>
+                    <Button
+                        type="primary"
+                        block
+                        icon={<HomeOutlined />}
+                        onClick={() => navigate('/')}
+                    >
+                        返回首页
+                    </Button>
+                </div>
+            </Sider>
+
+            {/* 内容区 */}
+            <Layout>
+                <Header style={{ background: '#fff', padding: '0 24px', fontSize: 20 }}>
+                    {(() => {
+                        switch (selectedKey) {
+                            case 'posts': return '📄 帖子管理';
+                            case 'activities': return '🎯 公告管理';
+                            case 'requests': return '🆘 求助帖管理';
+                            case 'complain': return '🚨 举报管理';
+                            case 'torrent': return '🧲 种子管理';
+                            default: return '';
+                        }
+                    })()}
+                </Header>
+                <Content style={{ margin: '24px 16px 0', padding: 24, background: '#fff', minHeight: '85vh' }}>
+                    {renderContent()}
+                </Content>
+                <Footer style={{ textAlign: 'center' }}>
+                    PT管理系统 ©{new Date().getFullYear()} Created by Jiaxin Liu, Man Yang, Shuo Wang
+                </Footer>
+            </Layout>
+        </Layout>
+    );
+};
+
+export default AdminPage;
diff --git a/src/pages/Community.jsx b/src/pages/Community.jsx
new file mode 100644
index 0000000..38d6623
--- /dev/null
+++ b/src/pages/Community.jsx
@@ -0,0 +1,53 @@
+// src/pages/Home.jsx
+import React, { useState, useEffect } from 'react';
+import { getActivityPreviews, getFullActivities } from '../api/activity';
+import Post from '../components/Post';
+import Navbar from '../components/Navbar'; // ✅ 导入导航栏组件
+import { AppstoreOutlined } from '@ant-design/icons';
+import { Row, Col, Card, Space } from 'antd';
+import './Home.css';
+
+const Community = () => {
+    const [activityPreviews, setActivityPreviews] = useState([]);
+    const [fullActivities, setFullActivities] = useState([]);
+    const [selectedActivityId, setSelectedActivityId] = useState(null);
+
+    useEffect(() => {
+        getActivityPreviews().then(res => setActivityPreviews(res.data));
+        getFullActivities().then(res => setFullActivities(res.data));
+    }, []);
+
+    return (
+        <div style={{ minHeight: '100vh', backgroundColor: '#f0f2f5' }}>
+            {/* 导航栏 */}
+            <Navbar />
+
+            {/* 内容区域 */}
+            <div style={{ padding: 24 }}>
+                {/* 帖子区域 */}
+                <Row justify="center">
+                    <Col
+                        xs={24}
+                        sm={24}
+                        md={24}
+                        lg={22}
+                        xl={20}
+                        xxl={18}
+                        style={{ maxWidth: 1400, width: '100%' }}
+                    >
+                        <Card
+                            title={<Space><AppstoreOutlined />最新帖子</Space>}
+                            bordered={false}
+                            bodyStyle={{ padding: 24 }}
+                            style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.15)', borderRadius: 8 }}
+                        >
+                            <Post />
+                        </Card>
+                    </Col>
+                </Row>
+            </div>
+        </div>
+    );
+};
+
+export default Community;
diff --git a/src/pages/Friend.css b/src/pages/Friend.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/pages/Friend.css
diff --git a/src/pages/Friend.jsx b/src/pages/Friend.jsx
new file mode 100644
index 0000000..fbb384d
--- /dev/null
+++ b/src/pages/Friend.jsx
@@ -0,0 +1,128 @@
+import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { getActivityPreviews, getFullActivities } from '../api/activity';
+import FriendManager from '../components/FriendManager';
+import ChatBox from '../components/ChatBox';
+import Navbar from '../components/Navbar';
+import { TeamOutlined, MessageOutlined } from '@ant-design/icons';
+import { Layout, Row, Col, Typography, Empty, Spin } from 'antd';
+import './Friend.css';
+
+const { Title, Text } = Typography;
+const { Content } = Layout;
+
+const Friend = () => {
+    const navigate = useNavigate();
+
+    // 使用 localStorage 获取当前登录用户
+    const [currentUser, setCurrentUser] = useState(null);
+    const [loading, setLoading] = useState(true);
+
+    useEffect(() => {
+        // 从 localStorage 获取用户信息
+        const userData = localStorage.getItem('user');
+        if (userData) {
+            try {
+                const user = JSON.parse(userData);
+                setCurrentUser(user);
+            } catch (e) {
+                console.error('Failed to parse user data');
+                navigate('/login');
+            } finally {
+                setLoading(false);
+            }
+        } else {
+            // 未登录则重定向到登录页
+            navigate('/login');
+        }
+    }, [navigate]);
+
+    const [selectedRelation, setSelectedRelation] = useState(null);
+    const [activityPreviews, setActivityPreviews] = useState([]);
+    const [fullActivities, setFullActivities] = useState([]);
+    const [selectedActivityId, setSelectedActivityId] = useState(null);
+
+    useEffect(() => {
+        if (currentUser) {
+            getActivityPreviews().then(res => setActivityPreviews(res.data));
+            getFullActivities().then(res => setFullActivities(res.data));
+        }
+    }, [currentUser]);
+
+    if (loading) {
+        return (
+            <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
+                <Spin size="large" />
+            </div>
+        );
+    }
+
+    return (
+        <Layout style={{ minHeight: '100vh', background: '#f0f2f5', padding: '24px' }}>
+            <Content>
+                <Navbar />
+                <Row justify="space-between" align="middle" style={{ marginBottom: 24 }} />
+
+                <Row gutter={24} style={{ height: 'calc(100vh - 140px)' }}>
+                    {/* 好友管理 - 左侧 */}
+                    <Col xs={24} sm={24} md={10} lg={8} xl={6} style={{ background: '#fff', borderRadius: 8, padding: 24, boxShadow: '0 2px 8px rgba(0,0,0,0.1)', overflowY: 'auto' }}>
+                        <Title level={4} style={{ color: '#722ed1', marginBottom: 24 }}>
+                            <TeamOutlined style={{ marginRight: 8 }} />
+                            好友管理
+                        </Title>
+                        <FriendManager
+                            currentUser={currentUser} // 传递真实登录用户
+                            onSelectRelation={setSelectedRelation}
+                        />
+                    </Col>
+
+                    {/* 聊天窗口 - 右侧 */}
+                    <Col
+                        xs={24}
+                        sm={24}
+                        md={14}
+                        lg={16}
+                        xl={18}
+                        style={{
+                            background: '#fff',
+                            borderRadius: 8,
+                            padding: 24,
+                            boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
+                            display: 'flex',
+                            flexDirection: 'column',
+                        }}
+                    >
+                        <Title level={4} style={{ color: '#eb2f96', marginBottom: 24 }}>
+                            <MessageOutlined style={{ marginRight: 8 }} />
+                            聊天窗口
+                        </Title>
+
+                        <div style={{ flex: 1, minHeight: 0 }}>
+                            {selectedRelation ? (
+                                <div style={{ height: 'calc(100vh - 220px)' }}>
+                                    <ChatBox
+                                        senderId={currentUser.userid} // 使用真实用户ID
+                                        receiverId={selectedRelation.friendId}
+                                    />
+                                </div>
+                            ) : (
+                                <Empty
+                                    image={Empty.PRESENTED_IMAGE_SIMPLE}
+                                    description={<Text type="secondary">请选择一位好友开始聊天</Text>}
+                                    style={{
+                                        height: '100%',
+                                        display: 'flex',
+                                        justifyContent: 'center',
+                                        alignItems: 'center',
+                                    }}
+                                />
+                            )}
+                        </div>
+                    </Col>
+                </Row>
+            </Content>
+        </Layout>
+    );
+};
+
+export default Friend;
\ 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/Home.css b/src/pages/Home.css
new file mode 100644
index 0000000..8510372
--- /dev/null
+++ b/src/pages/Home.css
@@ -0,0 +1,20 @@
+.home-layout {
+    min-height: 100vh;
+    background-color: #f0f2f5;
+}
+
+.home-header {
+    background-color: #001529;
+    padding: 0 24px;
+    height: 64px;
+}
+
+.home-content {
+    padding: 24px 0;
+}
+
+.post-card {
+    background: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
\ No newline at end of file
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
new file mode 100644
index 0000000..437feda
--- /dev/null
+++ b/src/pages/Home.jsx
@@ -0,0 +1,74 @@
+// pages/Home.js
+import React, { useState, useEffect } from 'react';
+import { getActivityPreviews, getFullActivities } from '../api/activity';
+import RecommendAll from '../components/RecommendAll'; // 假设你有一个推荐预览组件
+import RecommendPreview from '../components/RecommendPreview';
+import Navbar from '../components/Navbar'; // 导航栏组件
+
+const Home = () => {
+  const [activityPreviews, setActivityPreviews] = useState([]);
+  const [fullActivities, setFullActivities] = useState([]);
+  const [selectedActivityId, setSelectedActivityId] = useState(null);
+
+  useEffect(() => {
+    getActivityPreviews().then(res => setActivityPreviews(res.data));
+    getFullActivities().then(res => setFullActivities(res.data));
+  }, []);
+
+  const selectedActivity = fullActivities.find(
+    activity => activity.activityid === selectedActivityId
+  );
+
+  return (
+    <div>
+      <Navbar className="fixed top-0 left-0 w-full z-50" /> {/* 导航栏组件 */}
+      <h1 className="text-3xl font-bold text-center mb-4">社交互动平台 - 首页</h1>
+      
+      {/* 活动区域 */}
+      <div className="bg-white p-4 rounded shadow mb-8">
+        <h2 className="text-xl font-semibold mb-4">活动预览</h2>
+        {!selectedActivity ? (
+          <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
+            {activityPreviews.map(activity => (
+              <div key={activity.activityid} className="border p-3 rounded shadow">
+                <h3 className="text-lg font-medium mb-2">{activity.title}</h3>
+                <img
+                  src={activity.photo}
+                  alt={activity.title}
+                  className="w-full h-40 object-cover mb-2 rounded"
+                />
+                <button
+                  className="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600"
+                  onClick={() => setSelectedActivityId(activity.activityid)}
+                >
+                  查看详情
+                </button>
+              </div>
+            ))}
+          </div>
+        ) : (
+          <div className="p-4 border rounded shadow">
+            <button
+              className="mb-4 text-blue-600 underline"
+              onClick={() => setSelectedActivityId(null)}
+            >
+              ← 返回列表
+            </button>
+            <h3 className="text-2xl font-bold mb-2">{selectedActivity.title}</h3>
+            <img
+              src={selectedActivity.photo}
+              alt={selectedActivity.title}
+              className="w-full h-60 object-cover rounded mb-4"
+            />
+            <p className="mb-2"><strong>内容:</strong>{selectedActivity.content}</p>
+            <p className="mb-2"><strong>时间:</strong>{selectedActivity.time}</p>
+            <p className="mb-2"><strong>奖励:</strong>{selectedActivity.award}</p>
+          </div>
+        )}
+      </div>
+       <RecommendPreview />
+    </div>
+  );
+};
+
+export default Home;
\ No newline at end of file
diff --git a/src/pages/MainPage.css b/src/pages/MainPage.css
new file mode 100644
index 0000000..91325c9
--- /dev/null
+++ b/src/pages/MainPage.css
@@ -0,0 +1,63 @@
+/* src/pages/MainPage.css */
+
+.main-page-wrapper {
+    min-height: 100vh;
+    background-color: #f0f2f5;
+    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+
+.main-page-content {
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 32px 16px;
+}
+
+/* 欢迎区 */
+.main-page-header {
+    margin-bottom: 32px;
+    text-align: center;
+}
+
+.main-page-header h1 {
+    font-size: 32px;
+    color: #333;
+    margin-bottom: 8px;
+}
+
+.main-page-subtitle {
+    font-size: 16px;
+    color: #666;
+}
+
+/* 卡片样式通用区 */
+.card-section {
+    background: #fff;
+    padding: 24px;
+    border-radius: 12px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+    margin-bottom: 32px;
+}
+
+.section-title {
+    font-size: 22px;
+    font-weight: 600;
+    margin-bottom: 20px;
+    border-bottom: 1px solid #eaeaea;
+    padding-bottom: 10px;
+}
+
+/* 推荐资源占位样式 */
+.placeholder-box {
+    height: 150px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border: 2px dashed #ccc;
+    border-radius: 8px;
+    background-color: #fafafa;
+}
+
+.placeholder-text {
+    color: #999;
+    font-size: 16px;
+}
\ No newline at end of file
diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx
new file mode 100644
index 0000000..bf82c2e
--- /dev/null
+++ b/src/pages/MainPage.jsx
@@ -0,0 +1,41 @@
+// src/pages/MainPage.jsx
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import Navbar from '../components/Navbar';
+import ActivityBoard from '../components/ActivityBoard';
+import './MainPage.css';
+import RecommendPreview from'../components/RecommendPreview'; // 引入推荐预览样式
+
+const MainPage = () => {
+    const navigate = useNavigate();
+    const currentUser = {
+        id: 2,
+        username: '测试用户',
+    };
+
+    return (
+        <div className="main-page-wrapper">
+            {/* 顶部导航栏 */}
+            <Navbar />
+
+            <main className="main-page-content">
+
+                {/* 公告区域 */}
+                <section className="card-section">
+                    <ActivityBoard />
+                </section>
+
+                {/* 推荐下载资源预留区域 */}
+                <section className="card-section">
+                    {/* <h2 className="section-title">📥 推荐下载资源</h2>
+                    <div className="placeholder-box"> */}
+                        {/* <p className="placeholder-text">这里将展示为你推荐的种子资源,敬请期待~</p> */}
+                        <RecommendPreview/>
+                    {/* </div> */}
+                </section>
+            </main>
+        </div>
+    );
+};
+
+export default MainPage;
diff --git a/src/pages/managetorrentdetail.jsx b/src/pages/managetorrentdetail.jsx
new file mode 100644
index 0000000..029d06d
--- /dev/null
+++ b/src/pages/managetorrentdetail.jsx
@@ -0,0 +1,287 @@
+import React, { useState, useEffect } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import { 
+   Descriptions,
+  Table, 
+  Button, 
+  Modal, 
+  Image, 
+  message, 
+  Spin, 
+  Input, 
+  Select,
+  Pagination,
+  Space,
+  Card
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import axios from 'axios';
+import '../torrentdetailmanage.css'; // 引入样式
+
+const { confirm } = Modal;
+const { Option } = Select;
+
+//const { confirm } = Modal;
+
+const TorrentDetailmanage = () => {
+  const { id } = useParams(); // 从URL获取种子ID
+  const navigate = useNavigate(); // 用于返回上一页
+  const [torrent, setTorrent] = useState(null);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [isLoading, setIsLoading] = useState(false);
+
+  console.log('Torrent ID:', id);
+
+  const currentUserId = 1; // 示例,实际应从认证系统获取
+  
+
+  // 格式化日期
+  const formatDate = (dateString) => {
+    if (!dateString) return '未知';
+    const date = new Date(dateString);
+    return date.toLocaleString('zh-CN', {
+      year: 'numeric',
+      month: '2-digit',
+      day: '2-digit',
+      hour: '2-digit',
+      minute: '2-digit'
+    });
+  };
+
+  // 处理删除种子
+  const handleDeleteTorrent = async (torrentId) => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+
+    confirm({
+      title: '确认删除',
+      icon: <ExclamationCircleOutlined />,
+      content: '确定要删除这个种子吗?此操作不可恢复!',
+      onOk: async () => {
+        try {
+          await axios.delete(`http://localhost:8080/torrent/delete/${torrentId}`, {
+            params: { userid: currentUserId }
+          });
+          // 成功删除后,更新状态或返回上一页
+          setTorrent(null); // 清空当前种子详情
+          navigate(-1); // 返回上一页
+          message.success('种子删除成功');
+        } catch (err) {
+          console.error('删除种子失败', err);
+          if (err.response && err.response.status === 403) {
+            message.error('无权删除此种子');
+          } else {
+            message.error('删除种子失败');
+          }
+        }
+      }
+    });
+  };
+
+
+const handleDownloadTorrent = async (torrentId) => {
+  if (!currentUserId) {
+    message.warning('请先登录');
+    return;
+  }
+
+  setIsLoading(true); // 开始加载
+  try {
+    // 使用axios发送带有参数的GET请求
+    // const response = await axios.get(`http://localhost:8080/torrent/download/${torrentId}`, {
+    //   params: { userId: currentUserId },  // 正确添加请求参数
+    //   responseType: 'blob'  // 重要:指定响应类型为blob以处理文件下载
+    // });
+
+    // // 创建下载链接
+    // const url = window.URL.createObjectURL(new Blob([response.data]));
+    // const link = document.createElement('a');
+    // link.href = url;
+    // //link.setAttribute('download', 'torrent_file.torrent');  // 可以设置为动态文件名
+    // document.body.appendChild(link);
+    // link.click();
+    // document.body.removeChild(link);
+    // window.URL.revokeObjectURL(url);
+    open(`http://localhost:8080/torrent/download/${torrentId}?userId=${currentUserId}`, '_blank');
+
+    message.success('种子下载开始');
+  } catch (err) {
+    console.error('下载种子失败', err);
+    if (err.response?.status === 404) {
+      message.error('种子不存在');
+    } else {
+      message.error('下载失败: ' + (err.response?.data?.message || err.message));
+    }
+  } finally {
+    setIsLoading(false); // 结束加载
+  }
+};
+
+
+  // 格式化文件大小
+  const formatFileSize = (bytes) => {
+    if (bytes === 0) return '0 Bytes';
+    const k = 1024;
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  // 在组件函数内部添加这个函数
+const getPromotionName = (promotionId) => {
+  const promotionMap = {
+    1: '上传加倍',
+    2: '下载减半',
+    3: '免费下载',
+    0: '无促销'
+  };
+  
+  return promotionMap[promotionId] || '未知促销';
+};
+
+  // 获取种子详情
+  useEffect(() => {
+    const fetchTorrentDetail = async () => {
+      try {
+        const response = await axios.get(`http://localhost:8080/torrent/${id}`);
+        if (response.status === 200) {
+          setTorrent(response.data);
+        } else {
+          setError('获取种子详情失败');
+        }
+      } catch (err) {
+        console.error('获取种子详情失败:', err);
+        if (err.response) {
+          if (err.response.status === 404) {
+            setError('种子不存在');
+          } else {
+            setError('获取种子详情失败: ' + err.response.data);
+          }
+        } else {
+          setError('网络错误,请稍后重试');
+        }
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchTorrentDetail();
+  }, [id]);
+
+  console.log('Torrent Detail:', torrent);
+
+  // 返回上一页
+  const handleBack = () => {
+    navigate(-1); // 返回上一页
+  };
+
+  // 如果正在加载
+  if (loading) {
+    return (
+      <div className="flex justify-center items-center h-96">
+        <Spin size="large" tip="加载中..." />
+      </div>
+    );
+  }
+
+  // 如果有错误
+  if (error) {
+    return (
+      <div className="p-6">
+        <Card>
+          <div className="text-center p-6">
+            <ExclamationCircleOutlined className="text-2xl text-red-500 mb-4" />
+            <h3 className="text-lg font-medium text-red-600 mb-2">错误</h3>
+            <p className="text-gray-600">{error}</p>
+            <Button type="primary" onClick={handleBack} className="mt-4">
+              返回
+            </Button>
+          </div>
+        </Card>
+      </div>
+    );
+  }
+
+  // 如果种子不存在
+  if (!torrent) {
+    return (
+      <div className="p-6">
+        <Card>
+          <div className="text-center p-6">
+            <ExclamationCircleOutlined className="text-2xl text-yellow-500 mb-4" />
+            <h3 className="text-lg font-medium text-yellow-600 mb-2">种子不存在</h3>
+            <p className="text-gray-600">抱歉,您查找的种子不存在或已被删除。</p>
+            <Button type="primary" onClick={handleBack} className="mt-4">
+              返回
+            </Button>
+          </div>
+        </Card>
+      </div>
+    );
+  }
+
+return (
+  <div className="torrent-detail-page">
+    <Card
+      className="torrent1-card"
+      title={<div className="torrent-title">种子详情</div>}
+      extra={
+        <Button type="primary" onClick={handleBack}>
+          返回列表
+        </Button>
+      }
+    >
+      <Descriptions bordered column={1} size="middle">
+        <Descriptions.Item label="ID">{torrent.torrentid}</Descriptions.Item>
+
+        {torrent.coverImagePath && (
+          <Descriptions.Item label="封面图片">
+            <Image
+              className="torrent-cover-image"
+              src={torrent.coverImagePath}
+              alt="种子封面"
+              width={260}
+              height={160}
+              placeholder={
+                <div className="w-60 h-40 bg-gray-200 flex items-center justify-center">
+                  加载中...
+                </div>
+              }
+            />
+          </Descriptions.Item>
+        )}
+
+        <Descriptions.Item label="文件名">{torrent.filename}</Descriptions.Item>
+        <Descriptions.Item label="大小">{formatFileSize(torrent.torrentSize)}</Descriptions.Item>
+        <Descriptions.Item label="上传者ID">{torrent.uploader_id}</Descriptions.Item>
+        <Descriptions.Item label="上传时间">{formatDate(torrent.uploadTime)}</Descriptions.Item>
+        <Descriptions.Item label="下载次数">{torrent.downloadCount}</Descriptions.Item>
+        <Descriptions.Item label="促销">{getPromotionName(torrent.promotionid)}</Descriptions.Item>
+        <Descriptions.Item label="描述">{torrent.description || '无描述'}</Descriptions.Item>
+      </Descriptions>
+
+      <div className="torrent-buttons">
+        <Button 
+          danger 
+          onClick={() => handleDeleteTorrent(torrent.torrentid)}
+          loading={isLoading}
+        >
+          删除
+        </Button>
+        <Button 
+          type="primary" 
+          onClick={() => handleDownloadTorrent(torrent.torrentid)}
+          loading={isLoading}
+        >
+          下载
+        </Button>
+      </div>
+    </Card>
+  </div>
+);
+};
+
+export default TorrentDetailmanage;
\ No newline at end of file
diff --git a/src/test/TorrentDetail.test.jsx b/src/test/TorrentDetail.test.jsx
new file mode 100644
index 0000000..a540a81
--- /dev/null
+++ b/src/test/TorrentDetail.test.jsx
@@ -0,0 +1,91 @@
+import React from 'react';
+import { render, screen, waitFor } from '@testing-library/react';
+import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import axios from 'axios';
+import TorrentDetail from '../components/Torrentdetail';
+import { vi } from 'vitest';
+
+
+beforeAll(() => {
+  Object.defineProperty(window, 'matchMedia', {
+    writable: true,
+    value: vi.fn().mockImplementation((query) => ({
+      matches: false,
+      media: query,
+      onchange: null,
+      addListener: vi.fn(),
+      removeListener: vi.fn(),
+      addEventListener: vi.fn(),
+      removeEventListener: vi.fn(),
+      dispatchEvent: vi.fn(),
+    })),
+  });
+});
+
+
+// 模拟 axios
+vi.mock('axios');
+
+describe('TorrentDetail Page', () => {
+  const mockTorrent = {
+    torrentTitle: '测试种子',
+    uploader_id: 'uploader123',
+    description: '这是一个测试种子描述',
+    uploadTime: '2024-06-01T12:00:00Z',
+    torrentSize: 104857600,
+    downloadCount: 10,
+    dpi: '1080p',
+    caption: '简体中文',
+    lastseed: '2024-06-05T14:00:00Z',
+    coverImagePath: 'http://example.com/cover.jpg',
+    infoHash: 'abc123'
+  };
+
+  const mockSeeders = [
+    {
+      username: 'Seeder1',
+      uploaded: 204857600,
+      uploadSpeed: 1048576,
+      downloaded: 102400,
+      downloadSpeed: 0,
+      client: 'qBittorrent',
+      lastEvent: '2024-06-06T11:22:00Z'
+    }
+  ];
+
+  beforeEach(() => {
+    axios.get.mockImplementation((url) => {
+      if (url.includes('/torrent/abc123/seeders')) {
+        return Promise.resolve({ data: mockSeeders });
+      }
+      if (url.includes('/torrent/123')) {
+        return Promise.resolve({ data: mockTorrent });
+      }
+      return Promise.reject(new Error('not found'));
+    });
+  });
+
+  afterEach(() => {
+    vi.clearAllMocks();
+  });
+
+  test('renders torrent detail and seeders correctly', async () => {
+    render(
+      <MemoryRouter initialEntries={['/torrent/123']}>
+        <Routes>
+          <Route path="/torrent/:id" element={<TorrentDetail />} />
+        </Routes>
+      </MemoryRouter>
+    );
+
+    expect(document.querySelector('.ant-spin')).toBeInTheDocument();
+
+
+    await waitFor(() => {
+      expect(screen.getByText('测试种子')).toBeInTheDocument();
+      expect(screen.getByText('uploader123')).toBeInTheDocument();
+      expect(screen.getByText(/1080p/)).toBeInTheDocument();
+      expect(screen.getByText('Seeder1')).toBeInTheDocument();
+    });
+  });
+});
diff --git a/src/test/TorrentDetailhelp.test.jsx b/src/test/TorrentDetailhelp.test.jsx
new file mode 100644
index 0000000..8dd2ea5
--- /dev/null
+++ b/src/test/TorrentDetailhelp.test.jsx
@@ -0,0 +1,348 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { MemoryRouter, useParams, useNavigate, useLocation } from 'react-router-dom';
+import TorrentDetailcomplain from '../components/TorrentDetailcomplain';
+import axios from 'axios';
+
+// 模拟 axios
+vi.mock('axios');
+
+// 模拟 react-router-dom 的 hooks
+vi.mock('react-router-dom', async () => {
+  const actual = await vi.importActual('react-router-dom');
+  return {
+    ...actual,
+    useParams: vi.fn(),
+    useNavigate: vi.fn(),
+    useLocation: vi.fn(),
+  };
+});
+
+describe('TorrentDetailcomplain 组件', () => {
+  const mockTorrent = {
+    torrentid: 1,
+    filename: '测试种子文件',
+    torrentSize: 1024 * 1024 * 10, // 10MB
+    uploader_id: 123,
+    uploadTime: '2023-01-01T12:00:00',
+    downloadCount: 100,
+    promotionid: 1,
+    description: '这是一个测试种子',
+    coverImagePath: 'http://example.com/cover.jpg',
+  };
+
+  const mockNavigate = vi.fn();
+  const mockLocation = {
+    state: {
+      duser: 456,
+      torrentid: 1,
+    },
+  };
+
+  beforeEach(() => {
+    vi.clearAllMocks();
+    
+    // 设置模拟的路由 hooks
+    vi.mocked(useParams).mockReturnValue({ id: '1' });
+    vi.mocked(useNavigate).mockReturnValue(mockNavigate);
+    vi.mocked(useLocation).mockReturnValue(mockLocation);
+    
+    // 模拟 axios.get 返回种子详情
+    axios.get.mockResolvedValueOnce({ data: mockTorrent });
+  });
+
+  it('应该正确渲染而不崩溃', async () => {
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 验证一些基本元素是否存在
+    expect(screen.getByText('ID: 1')).toBeInTheDocument();
+    expect(screen.getByText('文件名: 测试种子文件')).toBeInTheDocument();
+    expect(screen.getByText('大小: 10.00 MB')).toBeInTheDocument();
+    expect(screen.getByText('上传者ID: 123')).toBeInTheDocument();
+    expect(screen.getByText('上传时间: 2023/01/01 12:00')).toBeInTheDocument();
+    expect(screen.getByText('下载次数: 100')).toBeInTheDocument();
+    expect(screen.getByText('促销: 上传加倍')).toBeInTheDocument();
+    expect(screen.getByText('描述: 这是一个测试种子')).toBeInTheDocument();
+  });
+
+  it('应该加载种子详情数据', async () => {
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/torrent/1');
+    });
+  });
+
+  it('应该正确显示封面图片', async () => {
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 验证封面图片是否渲染
+    const image = screen.getByAltText('种子封面');
+    expect(image).toBeInTheDocument();
+    expect(image).toHaveAttribute('src', 'http://example.com/cover.jpg');
+  });
+
+  it('应该正确处理删除种子按钮点击', async () => {
+    // 模拟 confirm 对话框
+    vi.mocked(axios.delete).mockResolvedValueOnce({});
+
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 点击删除按钮
+    const deleteButton = screen.getByText('删除');
+    userEvent.click(deleteButton);
+
+    // 验证 confirm 对话框是否被调用
+    // 注意:由于我们使用了 antd 的 Modal.confirm,我们需要检查 axios.delete 是否被调用
+    // 这里我们直接验证 axios.delete 是否被调用
+    await waitFor(() => {
+      expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/torrent/delete/1', {
+        params: { userid: 1 },
+      });
+    });
+
+    // 验证导航是否被调用
+    await waitFor(() => {
+      expect(mockNavigate).toHaveBeenCalledWith(-1);
+    });
+
+    // 验证成功消息是否被调用
+    expect(vi.mocked(message.success)).toHaveBeenCalledWith('种子删除成功');
+  });
+
+  it('应该正确处理下载种子按钮点击', async () => {
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 点击下载按钮
+    const downloadButton = screen.getByText('下载');
+    userEvent.click(downloadButton);
+
+    // 验证 axios.get 是否被调用(注意:我们实际上使用了 window.open)
+    // 由于我们直接使用了 window.open,我们需要验证它是否被调用
+    // 这里我们无法直接验证 window.open,但可以验证没有错误发生
+    // 我们可以验证组件没有崩溃
+    expect(screen.getByText('种子详情')).toBeInTheDocument();
+  });
+
+  it('应该正确处理扣除保种积分按钮点击', async () => {
+    // 模拟 axios.post
+    vi.mocked(axios.post).mockResolvedValueOnce({ data: { success: true } });
+
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 点击扣除保种积分按钮
+    const creditButton = screen.getByText('扣除保种积分');
+    userEvent.click(creditButton);
+
+    // 验证 axios.post 是否被调用
+    await waitFor(() => {
+      expect(axios.post).toHaveBeenCalledWith(
+        'http://localhost:8080/torrent/deducecredit',
+        'manageid=1&userid=456&credit=3',
+        {
+          headers: {
+            'Content-Type': 'application/x-www-form-urlencoded',
+          },
+        }
+      );
+    });
+
+    // 验证成功消息是否被调用
+    expect(vi.mocked(message.success)).toHaveBeenCalledWith('成功扣除 3 保种积分');
+  });
+
+  it('应该正确处理删除种子失败的情况', async () => {
+    // 模拟 axios.delete 失败
+    vi.mocked(axios.delete).mockRejectedValueOnce({
+      response: {
+        status: 403,
+        data: '无权删除此种子',
+      },
+    });
+
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 点击删除按钮
+    const deleteButton = screen.getByText('删除');
+    userEvent.click(deleteButton);
+
+    // 验证 axios.delete 是否被调用
+    await waitFor(() => {
+      expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/torrent/delete/1', {
+        params: { userid: 1 },
+      });
+    });
+
+    // 验证错误消息是否被调用
+    expect(vi.mocked(message.error)).toHaveBeenCalledWith('无权删除此种子');
+  });
+
+  it('应该正确处理下载种子失败的情况', async () => {
+    // 模拟 window.open 失败(我们无法直接模拟 window.open,所以这个测试可能有限)
+    // 由于我们直接使用了 window.open,我们无法直接测试它的失败情况
+    // 我们可以测试组件在点击按钮后没有崩溃
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 点击下载按钮
+    const downloadButton = screen.getByText('下载');
+    userEvent.click(downloadButton);
+
+    // 验证组件没有崩溃
+    expect(screen.getByText('种子详情')).toBeInTheDocument();
+  });
+
+  it('应该正确处理扣除保种积分失败的情况', async () => {
+    // 模拟 axios.post 失败
+    vi.mocked(axios.post).mockRejectedValueOnce({
+      response: {
+        status: 500,
+        data: { message: '服务器错误' },
+      },
+    });
+
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待数据加载
+    await waitFor(() => {
+      expect(screen.getByText('种子详情')).toBeInTheDocument();
+    });
+
+    // 点击扣除保种积分按钮
+    const creditButton = screen.getByText('扣除保种积分');
+    userEvent.click(creditButton);
+
+    // 验证 axios.post 是否被调用
+    await waitFor(() => {
+      expect(axios.post).toHaveBeenCalledWith(
+        'http://localhost:8080/torrent/deducecredit',
+        'manageid=1&userid=456&credit=3',
+        {
+          headers: {
+            'Content-Type': 'application/x-www-form-urlencoded',
+          },
+        }
+      );
+    });
+
+    // 验证错误消息是否被调用
+    expect(vi.mocked(message.error)).toHaveBeenCalledWith('服务器错误: 服务器错误');
+  });
+
+  it('应该正确处理种子不存在的情况', async () => {
+    // 模拟 axios.get 返回 404
+    axios.get.mockRejectedValueOnce({
+      response: {
+        status: 404,
+      },
+    });
+
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待错误状态
+    await waitFor(() => {
+      expect(screen.queryByText('种子详情')).not.toBeInTheDocument();
+    });
+
+    // 验证错误消息是否显示
+    expect(screen.getByText('种子不存在')).toBeInTheDocument();
+    expect(screen.getByText('抱歉,您查找的种子不存在或已被删除。')).toBeInTheDocument();
+  });
+
+  it('应该正确处理网络错误的情况', async () => {
+    // 模拟 axios.get 网络错误
+    axios.get.mockRejectedValueOnce({
+      message: '网络错误',
+    });
+
+    render(
+      <MemoryRouter>
+        <TorrentDetailcomplain />
+      </MemoryRouter>
+    );
+
+    // 等待错误状态
+    await waitFor(() => {
+      expect(screen.queryByText('种子详情')).not.toBeInTheDocument();
+    });
+
+    // 验证错误消息是否显示
+    expect(screen.getByText('网络错误,请稍后重试')).toBeInTheDocument();
+  });
+});
\ No newline at end of file
diff --git a/src/test/TorrentList.search.test.jsx b/src/test/TorrentList.search.test.jsx
new file mode 100644
index 0000000..6c588fd
--- /dev/null
+++ b/src/test/TorrentList.search.test.jsx
@@ -0,0 +1,65 @@
+// TorrentList.test.jsx
+import React from 'react';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import TorrentList from '../components/TorrentList';
+import axios from 'axios';
+import { MemoryRouter } from 'react-router-dom'; // ✅ 引入 MemoryRouter
+
+
+import { vi } from 'vitest';
+beforeAll(() => {
+  Object.defineProperty(window, 'matchMedia', {
+    writable: true,
+    value: vi.fn().mockImplementation((query) => ({
+      matches: false,
+      media: query,
+      onchange: null,
+      addListener: vi.fn(),
+      removeListener: vi.fn(),
+      addEventListener: vi.fn(),
+      removeEventListener: vi.fn(),
+      dispatchEvent: vi.fn(),
+    })),
+  });
+});
+
+vi.mock('axios');
+
+
+
+describe('TorrentList - 搜索功能', () => {
+  test('搜索关键词后应正确调用接口并显示结果', async () => {
+    const mockTorrents = [
+      { id: 1, title: '测试种子1', uploader_id: 123 },
+      { id: 2, title: '测试种子2', uploader_id: 456 },
+    ];
+
+    axios.get.mockResolvedValueOnce({ data: mockTorrents });
+
+    render(
+      <MemoryRouter>
+        <TorrentList />
+      </MemoryRouter>
+    );
+
+    // 输入关键词
+    const input = screen.getByPlaceholderText(/搜索种子/i);
+    fireEvent.change(input, { target: { value: '测试' } });
+
+    // 模拟点击搜索按钮
+    const button = screen.getByRole('button', { name: /搜\s*索/i });
+    fireEvent.click(button);
+
+
+    // 等待并断言结果被渲染
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith(
+        'http://localhost:8080/torrent/search',
+        { params: { keyword: '测试' } }
+      );
+    });
+
+    // expect(await screen.findByText('测试种子1')).toBeInTheDocument();
+    // expect(await screen.findByText('测试种子2')).toBeInTheDocument();
+  });
+});
diff --git a/src/test/TorrentUpload.test.jsx b/src/test/TorrentUpload.test.jsx
new file mode 100644
index 0000000..482184e
--- /dev/null
+++ b/src/test/TorrentUpload.test.jsx
@@ -0,0 +1,489 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { MemoryRouter } from 'react-router-dom';
+import UploadTorrent from '../components/upload';
+import { Form, Select } from 'antd';
+
+// 模拟 axios
+vi.mock('axios');
+
+// 模拟 antd 的 message
+vi.mock('antd', async () => {
+  const actual = await vi.importActual('antd');
+  return {
+    ...actual,
+    message: {
+      success: vi.fn(),
+      error: vi.fn(),
+    },
+  };
+});
+
+describe('UploadTorrent 组件', () => {
+  const mockCategories = [
+    { categoryid: '1', category_name: '电影' },
+    { categoryid: '2', category_name: '剧集' },
+    { categoryid: '3', category_name: '音乐' },
+    { categoryid: '4', category_name: '动漫' },
+    { categoryid: '5', category_name: '游戏' },
+    { categoryid: '6', category_name: '综艺' },
+    { categoryid: '7', category_name: '体育' },
+    { categoryid: '8', category_name: '软件' },
+    { categoryid: '9', category_name: '学习资料' },
+    { categoryid: '10', category_name: '纪录片' },
+    { categoryid: '11', category_name: '音乐' },
+  ];
+
+  beforeEach(() => {
+    vi.clearAllMocks();
+    // 模拟 axios.get 返回分类数据
+    vi.mocked(axios.get).mockResolvedValueOnce({ data: mockCategories });
+  });
+
+  it('应该正确渲染而不崩溃', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(screen.getByText('上传种子')).toBeInTheDocument();
+    });
+
+    // 验证一些基本元素是否存在
+    expect(screen.getByText('封面图片')).toBeInTheDocument();
+    expect(screen.getByText('种子文件')).toBeInTheDocument();
+    expect(screen.getByText('标题')).toBeInTheDocument();
+    expect(screen.getByText('描述')).toBeInTheDocument();
+    expect(screen.getByText('分类')).toBeInTheDocument();
+    expect(screen.getByText('上传种子')).toBeInTheDocument();
+  });
+
+  it('应该加载分类数据', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 验证分类下拉框是否渲染了正确的选项
+    const categorySelect = screen.getByLabelText('分类');
+    expect(categorySelect).toBeInTheDocument();
+
+    // 打开下拉菜单并检查选项
+    fireEvent.mouseDown(categorySelect);
+    mockCategories.forEach(category => {
+      expect(screen.getByText(category.category_name)).toBeInTheDocument();
+    });
+  });
+
+  it('应该在选择分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"电影"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('电影'));
+
+    // 验证电影相关的字段是否显示
+    expect(screen.getByLabelText('字幕/说明')).toBeInTheDocument();
+    expect(screen.getByLabelText('地区')).toBeInTheDocument();
+    expect(screen.getByLabelText('年份')).toBeInTheDocument();
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('编码格式')).toBeInTheDocument();
+    expect(screen.getByLabelText('分辨率')).toBeInTheDocument();
+  });
+
+  it('应该在选择"剧集"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"剧集"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('剧集'));
+
+    // 验证剧集相关的字段是否显示
+    expect(screen.getByLabelText('地区')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+  });
+
+  it('应该在选择"游戏"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"游戏"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('游戏'));
+
+    // 验证游戏相关的字段是否显示
+    expect(screen.getByLabelText('平台')).toBeInTheDocument();
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('语言')).toBeInTheDocument();
+    expect(screen.getByLabelText('数据类型')).toBeInTheDocument();
+  });
+
+  it('应该在选择"综艺"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"综艺"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('综艺'));
+
+    // 验证综艺相关的字段是否显示
+    expect(screen.getByLabelText('是否大陆综艺')).toBeInTheDocument();
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+  });
+
+  it('应该在选择"动漫"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"动漫"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('动漫'));
+
+    // 验证动漫相关的字段是否显示
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+    expect(screen.getByLabelText('分辨率')).toBeInTheDocument();
+  });
+
+  it('应该在选择"学习资料"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"学习资料"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('学习资料'));
+
+    // 验证学习资料相关的字段是否显示
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+  });
+
+  it('应该在选择"纪录片"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"纪录片"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('纪录片'));
+
+    // 验证纪录片相关的字段是否显示
+    expect(screen.getByLabelText('年份')).toBeInTheDocument();
+    expect(screen.getByLabelText('视频源')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+  });
+
+  it('应该在选择"音乐"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"音乐"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('音乐'));
+
+    // 验证音乐相关的字段是否显示
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('地区')).toBeInTheDocument();
+    expect(screen.getByLabelText('风格')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+  });
+
+  it('应该在选择"软件"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"软件"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('软件'));
+
+    // 验证软件相关的字段是否显示
+    expect(screen.getByLabelText('平台')).toBeInTheDocument();
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+  });
+
+  it('应该在选择"体育"分类后显示相应的动态字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"体育"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('体育'));
+
+    // 验证体育相关的字段是否显示
+    expect(screen.getByLabelText('类型')).toBeInTheDocument();
+    expect(screen.getByLabelText('格式')).toBeInTheDocument();
+    expect(screen.getByLabelText('赛事类型')).toBeInTheDocument();
+  });
+
+  it('应该在选择分类后正确设置状态', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择"电影"分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('电影'));
+
+    // 验证状态是否正确设置
+    // 注意:由于状态是组件内部的,我们需要通过 UI 变化来间接验证
+    // 这里我们验证电影相关的字段是否显示
+    expect(screen.getByLabelText('字幕/说明')).toBeInTheDocument();
+  });
+
+  it('应该在选择种子文件后更新状态', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 模拟文件选择
+    const fileInput = screen.getByLabelText('种子文件').querySelector('input');
+    const mockFile = new File(['torrent content'], 'test.torrent', { type: 'application/x-bittorrent' });
+    fireEvent.change(fileInput, { target: { files: [mockFile] } });
+
+    // 验证文件是否被设置(通过 UI 变化间接验证)
+    // 由于我们无法直接访问组件状态,我们可以通过表单验证状态来间接验证
+    // 这里我们只是验证文件输入是否正常工作
+    expect(fileInput).toBeInTheDocument();
+  });
+
+  it('应该在选择封面图片后更新状态', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 模拟图片选择
+    const imageInput = screen.getByLabelText('封面图片').querySelector('input');
+    const mockImage = new File(['image content'], 'test.jpg', { type: 'image/jpeg' });
+    fireEvent.change(imageInput, { target: { files: [mockImage] } });
+
+    // 验证图片是否被设置(通过 UI 变化间接验证)
+    expect(imageInput).toBeInTheDocument();
+  });
+
+  it('应该在表单提交时验证必填字段', async () => {
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 直接提交表单而不填写任何字段
+    const submitButton = screen.getByText('上传种子');
+    fireEvent.click(submitButton);
+
+    // 验证错误消息是否显示
+    // 注意:由于我们使用了 antd 的 Form,错误消息可能由 antd 内部处理
+    // 我们可以通过检查是否有错误提示来验证
+    // 这里我们只是验证表单提交被调用
+    // 更详细的验证可能需要更复杂的测试设置
+  });
+
+  it('应该在填写所有必填字段后成功提交表单', async () => {
+    // 模拟 axios.post
+    vi.mocked(axios.post).mockResolvedValueOnce({ data: {} });
+
+    render(
+      <MemoryRouter>
+        <UploadTorrent />
+      </MemoryRouter>
+    );
+
+    // 等待分类数据加载
+    await waitFor(() => {
+      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
+    });
+
+    // 选择分类
+    const categorySelect = screen.getByLabelText('分类');
+    fireEvent.mouseDown(categorySelect);
+    fireEvent.click(screen.getByText('电影'));
+
+    // 填写标题
+    const titleInput = screen.getByLabelText('标题');
+    fireEvent.change(titleInput, { target: { value: '测试电影' } });
+
+    // 填写描述
+    const descriptionInput = screen.getByLabelText('描述');
+    fireEvent.change(descriptionInput, { target: { value: '这是一个测试电影的描述' } });
+
+    // 选择封面图片
+    const imageInput = screen.getByLabelText('封面图片').querySelector('input');
+    const mockImage = new File(['image content'], 'test.jpg', { type: 'image/jpeg' });
+    fireEvent.change(imageInput, { target: { files: [mockImage] } });
+
+    // 选择种子文件
+    const fileInput = screen.getByLabelText('种子文件').querySelector('input');
+    const mockFile = new File(['torrent content'], 'test.torrent', { type: 'application/x-bittorrent' });
+    fireEvent.change(fileInput, { target: { files: [mockFile] } });
+
+    // 填写电影相关字段
+    const captionInput = screen.getByLabelText('字幕/说明');
+    fireEvent.change(captionInput, { target: { value: '测试字幕' } });
+
+    const regionSelect = screen.getByLabelText('地区');
+    fireEvent.mouseDown(regionSelect);
+    fireEvent.click(screen.getByText('大陆'));
+
+    const yearInput = screen.getByLabelText('年份');
+    fireEvent.change(yearInput, { target: { value: '2023' } });
+
+    const genreSelect = screen.getByLabelText('类型');
+    fireEvent.mouseDown(genreSelect);
+    fireEvent.click(screen.getByText('动作'));
+
+    const codecFormatSelect = screen.getByLabelText('编码格式');
+    fireEvent.mouseDown(codecFormatSelect);
+    fireEvent.click(screen.getByText('H.264'));
+
+    const resolutionSelect = screen.getByLabelText('分辨率');
+    fireEvent.mouseDown(resolutionSelect);
+    fireEvent.click(screen.getByText('1080p'));
+
+    // 提交表单
+    const submitButton = screen.getByText('上传种子');
+    fireEvent.click(submitButton);
+
+    // 验证 axios.post 是否被调用
+    expect(axios.post).toHaveBeenCalledWith(
+      'http://localhost:8080/torrent/upload',
+      expect.any(FormData),
+      {
+        headers: { 'Content-Type': 'multipart/form-data' },
+        responseType: 'blob',
+      }
+    );
+
+    // 验证成功消息是否显示
+    expect(vi.mocked(message.success)).toHaveBeenCalledWith('上传成功!');
+  });
+});
\ No newline at end of file
diff --git a/src/test/setup.js b/src/test/setup.js
new file mode 100644
index 0000000..43c149b
--- /dev/null
+++ b/src/test/setup.js
@@ -0,0 +1,2 @@
+// src/test/setup.js
+import '@testing-library/jest-dom';
diff --git a/src/torrentdetailmanage.css b/src/torrentdetailmanage.css
new file mode 100644
index 0000000..b38cf6d
--- /dev/null
+++ b/src/torrentdetailmanage.css
@@ -0,0 +1,53 @@
+/* TorrentDetail.css */
+
+body, html, #root {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+  background-color: #f4f6f9;
+  font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
+}
+
+.torrent-detail-page {
+  min-height: 100vh;
+  padding: 32px 48px;
+  background-color: #f4f6f9;
+  box-sizing: border-box;
+}
+
+.torrent1-card {
+  width: 100%;
+  max-width: 1080px;
+  min-width: 1000px; /* 确保不会太窄 */
+  margin: 0 auto;
+  border-radius: 16px;
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
+  border: none;
+  background: #fff;
+  padding: 32px;
+}
+
+.torrent-title {
+  font-size: 28px;
+  font-weight: 600;
+  color: #d46b08;
+  margin-bottom: 20px;
+}
+
+.torrent-cover-image {
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
+  border: 1px solid #eee;
+}
+
+.torrent-buttons {
+  margin-top: 32px;
+  display: flex;
+  justify-content: flex-end;
+  gap: 20px;
+}
+
+.torrent-buttons .ant-btn {
+  font-size: 16px;
+  padding: 10px 28px;
+}
diff --git a/src/torrentlist.css b/src/torrentlist.css
new file mode 100644
index 0000000..b6fa9d1
--- /dev/null
+++ b/src/torrentlist.css
@@ -0,0 +1,168 @@
+/* 加载状态 */
+.loading-container {
+  height: 16rem; /* 64 x 4 */
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.spinner {
+  border: 4px solid #f3f3f3;
+  border-top: 4px solid #f59e0b; /* 橙黄色 */
+  border-radius: 50%;
+  width: 48px;
+  height: 48px;
+  animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+  to { transform: rotate(360deg); }
+}
+
+/* 容器和网格 */
+.torrents-container {
+  padding: 16px;
+  background-color: #f9fafb;
+  min-height: 100vh;
+}
+
+.torrents-grid {
+  display: grid;
+  /* grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));   */
+  grid-template-columns: repeat(4, 1fr); /* 固定每行4列 */
+  gap: 24px;
+}
+
+.torrents1-grid {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr); /* 固定每行4列 */
+  gap: 24px;
+}
+
+
+/* 卡片样式 */
+.torrent-card {
+  background-color: white;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgb(0 0 0 / 0.1);
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  transition: box-shadow 0.3s ease;
+}
+
+.torrent-card:hover {
+  box-shadow: 0 6px 16px rgb(0 0 0 / 0.15);
+}
+
+/* 封面区域 */
+.cover {
+  height: 160px;
+  overflow: hidden;
+  background-color: #e5e7eb;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.cover-image {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.no-cover {
+  color: #9ca3af;
+  font-size: 14px;
+}
+
+/* 信息区域 */
+.info {
+  padding: 16px;
+  flex-grow: 1;
+  display: flex;
+  flex-direction: column;
+}
+
+.title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #d97706; /* 橙色 */
+  margin: 0 0 6px 0;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.description {
+  font-size: 14px;
+  color: #6b7280;
+  margin: 0 0 12px 0;
+  height: 36px; /* 限制两行高度 */
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.details {
+  font-size: 12px;
+  color: #6b7280;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-bottom: 16px;
+}
+
+.details span {
+  white-space: nowrap;
+}
+
+/* 操作按钮 */
+.actions {
+  margin-top: auto;
+  display: flex;
+  gap: 12px;
+}
+
+.btn {
+  flex: 1;
+  padding: 8px 12px;
+  border-radius: 6px;
+  font-size: 14px;
+  font-weight: 600;
+  cursor: pointer;
+  text-align: center;
+  text-decoration: none;
+  user-select: none;
+  transition: background-color 0.3s ease;
+  border: none;
+}
+
+.btn-download {
+  background-color: #f97316; /* 明亮橙色 */
+  color: white;
+}
+
+.btn-download:hover {
+  background-color: #ea580c; /* 深橙 */
+}
+
+.btn-detail {
+  background-color: #e5e7eb;
+  color: #374151;
+  display: inline-flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.btn-detail:hover {
+  background-color: #d1d5db;
+}
+
+/* 没有数据提示 */
+.no-data {
+  text-align: center;
+  color: #6b7280;
+  font-size: 18px;
+  margin-top: 80px;
+}
+
diff --git a/src/upload.css b/src/upload.css
new file mode 100644
index 0000000..3e35e89
--- /dev/null
+++ b/src/upload.css
@@ -0,0 +1,151 @@
+
+
+  /* 表单组样式 */
+  .form-group {
+    margin-bottom: 1rem;
+  }
+  
+  .form-label {
+    display: block;
+    margin-bottom: 0.5rem;
+    font-weight: 500;
+  }
+  
+  .form-control {
+    width: 100%;
+    padding: 0.5rem;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    transition: border-color 0.3s;
+  }
+  
+  .form-control:focus {
+    outline: none;
+    border-color: #ff8c00;
+    box-shadow: 0 0 0 3px rgba(255, 140, 0, 0.2);
+  }
+  
+  /* 提交按钮样式 */
+  .submit-btn {
+    background-color: #ff8c00;
+    color: white;
+    padding: 0.5rem 1rem;
+    border: none;
+    border-radius: 4px;
+    cursor: pointer;
+    font-weight: 500;
+    transition: background-color 0.3s;
+  }
+  
+  .submit-btn:hover {
+    background-color: #ff7f00;
+  }
+  
+  /* 成功消息样式 */
+  .success-message {
+    margin-top: 1rem;
+    padding: 0.75rem;
+    background-color: #fff3cd;
+    color: #856404;
+    border: 1px solid #ffeeba;
+    border-radius: 4px;
+  }
+
+  /* 表单组样式 */
+  .form-group {
+    margin-bottom: 1.5rem;
+  }
+  
+  .form-label {
+    display: block;
+    margin-bottom: 0.5rem;
+    font-weight: 500;
+  }
+  
+  .form-control {
+    width: 100%;
+    padding: 0.75rem;
+    border: 1px solid #ddd;
+    border-radius: 8px;
+    transition: border-color 0.3s;
+    font-size: 1rem;
+  }
+  
+  .form-control:focus {
+    outline: none;
+    border-color: #ff8c00;
+    box-shadow: 0 0 0 3px rgba(255, 140, 0, 0.2);
+  }
+  
+  /* 上传区域样式 */
+  .upload-area {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.3s;
+  }
+  
+  .upload-area:hover {
+    background-color: rgba(255, 140, 0, 0.05);
+  }
+  
+  /* 自定义下拉框样式 */
+  .custom-select {
+    width: 100%;
+    padding: 0.75rem 2.5rem 0.75rem 1rem;
+    border: 1px solid #ddd;
+    border-radius: 8px;
+    appearance: none;
+    background-color: white;
+    font-size: 1rem;
+    cursor: pointer;
+    transition: border-color 0.3s;
+  }
+  
+  .custom-select:focus {
+    outline: none;
+    border-color: #ff8c00;
+    box-shadow: 0 0 0 3px rgba(255, 140, 0, 0.2);
+  }
+  
+  .select-arrow {
+    position: absolute;
+    right: 1rem;
+    top: 50%;
+    transform: translateY(-50%);
+    pointer-events: none;
+  }
+  
+  /* 提交按钮样式 */
+  .submit-btn {
+    background-color: #ff8c00;
+    color: white;
+    padding: 0.75rem 2rem;
+    border: none;
+    border-radius: 8px;
+    cursor: pointer;
+    font-weight: 600;
+    font-size: 1rem;
+    transition: background-color 0.3s;
+    display: inline-block;
+  }
+  
+  .submit-btn:hover {
+    background-color: #ff7f00;
+  }
+  
+  /* 成功消息样式 */
+  .success-message {
+    margin-top: 1.5rem;
+    padding: 0.75rem 1.5rem;
+    background-color: #fff3cd;
+    color: #856404;
+    border: 1px solid #ffeeba;
+    border-radius: 8px;
+  }
+  
+  /* 居中布局 */
+  .text-center {
+    text-align: center;
+  }
diff --git a/src/uploadtorrent.css b/src/uploadtorrent.css
new file mode 100644
index 0000000..213336c
--- /dev/null
+++ b/src/uploadtorrent.css
@@ -0,0 +1,95 @@
+/* UploadTorrent.css */
+.container {
+  min-height: 100vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 10px;
+}
+
+.card {
+  width: 100%;
+  max-width: 1000px;;
+  min-width: 800px;  /* 最小宽度 800px(确保不会太窄) */
+  margin: 0 auto;
+  padding: 20px;
+  background-color: #fff;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  border-radius: 8px;
+}
+
+.title {
+  text-align: center;
+  font-size: 1.5rem;
+  font-weight: bold;
+  color: #ff8c00;
+  margin-bottom: 20px;
+  padding-bottom: 10px;
+  border-bottom: 2px solid #ffe0b2;
+}
+
+.form {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.uploadArea {
+  text-align: center;
+  padding: 20px;
+  border: 2px dashed #ffe0b2;
+  border-radius: 8px;
+  cursor: pointer;
+  transition: border-color 0.3s;
+}
+
+.uploadArea:hover {
+  border-color: #ff8c00;
+}
+
+.uploadIcon {
+  color: #ffe0b2;
+  font-size: 2rem;
+}
+
+.uploadText {
+  margin-top: 10px;
+  font-size: 0.8rem;
+  color: #666;
+}
+
+.hiddenInput {
+  display: none;
+}
+
+.input {
+  width: 100%;
+  text-align: center;
+}
+
+.textArea {
+  width: 100%;
+  text-align: center;
+}
+
+.select {
+  width: 100%;
+}
+
+.submitButton {
+  width: 100%;
+  background-color: #ff8c00;
+  border-color: #ff8c00;
+}
+
+.submitButton:hover {
+  background-color: #ff7f00;
+  border-color: #ff7f00;
+}
+
+.successMessage {
+  text-align: center;
+  color: green;
+  font-weight: bold;
+  margin-top: 10px;
+}