ssq页面

Change-Id: I11f58d72d9e33eae9ec84f46473fa6144b480501
diff --git a/front/README.md b/front/README.md
deleted file mode 100644
index 58beeac..0000000
--- a/front/README.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# Getting Started with Create React App
-
-This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
-
-## Available Scripts
-
-In the project directory, you can run:
-
-### `npm start`
-
-Runs the app in the development mode.\
-Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
-
-The page will reload when you make changes.\
-You may also see any lint errors in the console.
-
-### `npm test`
-
-Launches the test runner in the interactive watch mode.\
-See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
-
-### `npm run build`
-
-Builds the app for production to the `build` folder.\
-It correctly bundles React in production mode and optimizes the build for the best performance.
-
-The build is minified and the filenames include the hashes.\
-Your app is ready to be deployed!
-
-See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
-
-### `npm run eject`
-
-**Note: this is a one-way operation. Once you `eject`, you can't go back!**
-
-If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
-
-Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
-
-You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
-
-## Learn More
-
-You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
-
-To learn React, check out the [React documentation](https://reactjs.org/).
-
-### Code Splitting
-
-This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
-
-### Analyzing the Bundle Size
-
-This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
-
-### Making a Progressive Web App
-
-This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
-
-### Advanced Configuration
-
-This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
-
-### Deployment
-
-This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
-
-### `npm run build` fails to minify
-
-This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
diff --git a/front/package-lock.json b/front/package-lock.json
index 2fc8ceb..0adbc29 100644
--- a/front/package-lock.json
+++ b/front/package-lock.json
@@ -16,6 +16,7 @@
         "@testing-library/jest-dom": "^6.6.3",
         "@testing-library/react": "^16.3.0",
         "@testing-library/user-event": "^13.5.0",
+        "antd": "^5.25.4",
         "react": "^18.3.1",
         "react-dom": "^18.3.1",
         "react-router-dom": "^6.30.1",
@@ -54,6 +55,121 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/@ant-design/colors": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.2.1.tgz",
+      "integrity": "sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@ant-design/fast-color": "^2.0.6"
+      }
+    },
+    "node_modules/@ant-design/cssinjs": {
+      "version": "1.23.0",
+      "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.23.0.tgz",
+      "integrity": "sha512-7GAg9bD/iC9ikWatU9ym+P9ugJhi/WbsTWzcKN6T4gU0aehsprtke1UAaaSxxkjjmkJb3llet/rbUSLPgwlY4w==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.1",
+        "@emotion/hash": "^0.8.0",
+        "@emotion/unitless": "^0.7.5",
+        "classnames": "^2.3.1",
+        "csstype": "^3.1.3",
+        "rc-util": "^5.35.0",
+        "stylis": "^4.3.4"
+      },
+      "peerDependencies": {
+        "react": ">=16.0.0",
+        "react-dom": ">=16.0.0"
+      }
+    },
+    "node_modules/@ant-design/cssinjs-utils": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.3.tgz",
+      "integrity": "sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg==",
+      "license": "MIT",
+      "dependencies": {
+        "@ant-design/cssinjs": "^1.21.0",
+        "@babel/runtime": "^7.23.2",
+        "rc-util": "^5.38.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@ant-design/cssinjs/node_modules/@emotion/hash": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
+      "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
+      "license": "MIT"
+    },
+    "node_modules/@ant-design/cssinjs/node_modules/@emotion/unitless": {
+      "version": "0.7.5",
+      "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
+      "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
+      "license": "MIT"
+    },
+    "node_modules/@ant-design/cssinjs/node_modules/stylis": {
+      "version": "4.3.6",
+      "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
+      "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
+      "license": "MIT"
+    },
+    "node_modules/@ant-design/fast-color": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz",
+      "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.24.7"
+      },
+      "engines": {
+        "node": ">=8.x"
+      }
+    },
+    "node_modules/@ant-design/icons": {
+      "version": "5.6.1",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.6.1.tgz",
+      "integrity": "sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg==",
+      "license": "MIT",
+      "dependencies": {
+        "@ant-design/colors": "^7.0.0",
+        "@ant-design/icons-svg": "^4.4.0",
+        "@babel/runtime": "^7.24.8",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.31.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "peerDependencies": {
+        "react": ">=16.0.0",
+        "react-dom": ">=16.0.0"
+      }
+    },
+    "node_modules/@ant-design/icons-svg": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz",
+      "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==",
+      "license": "MIT"
+    },
+    "node_modules/@ant-design/react-slick": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz",
+      "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.4",
+        "classnames": "^2.2.5",
+        "json2mq": "^0.2.0",
+        "resize-observer-polyfill": "^1.5.1",
+        "throttle-debounce": "^5.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0"
+      }
+    },
     "node_modules/@babel/code-frame": {
       "version": "7.27.1",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
@@ -3499,6 +3615,155 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
+    "node_modules/@rc-component/async-validator": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz",
+      "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.24.4"
+      },
+      "engines": {
+        "node": ">=14.x"
+      }
+    },
+    "node_modules/@rc-component/color-picker": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz",
+      "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@ant-design/fast-color": "^2.0.6",
+        "@babel/runtime": "^7.23.6",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.38.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@rc-component/context": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz",
+      "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "rc-util": "^5.27.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@rc-component/mini-decimal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz",
+      "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.0"
+      },
+      "engines": {
+        "node": ">=8.x"
+      }
+    },
+    "node_modules/@rc-component/mutate-observer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz",
+      "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.0",
+        "classnames": "^2.3.2",
+        "rc-util": "^5.24.4"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@rc-component/portal": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz",
+      "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.0",
+        "classnames": "^2.3.2",
+        "rc-util": "^5.24.4"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@rc-component/qrcode": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz",
+      "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.24.7",
+        "classnames": "^2.3.2",
+        "rc-util": "^5.38.0"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@rc-component/tour": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz",
+      "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.0",
+        "@rc-component/portal": "^1.0.0-9",
+        "@rc-component/trigger": "^2.0.0",
+        "classnames": "^2.3.2",
+        "rc-util": "^5.24.4"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/@rc-component/trigger": {
+      "version": "2.2.6",
+      "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.6.tgz",
+      "integrity": "sha512-/9zuTnWwhQ3S3WT1T8BubuFTT46kvnXgaERR9f4BTKyn61/wpf/BvbImzYBubzJibU707FxwbKszLlHjcLiv1Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.23.2",
+        "@rc-component/portal": "^1.1.0",
+        "classnames": "^2.3.2",
+        "rc-motion": "^2.0.0",
+        "rc-resize-observer": "^1.3.1",
+        "rc-util": "^5.44.0"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
     "node_modules/@remix-run/router": {
       "version": "1.23.0",
       "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz",
@@ -4998,6 +5263,71 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
+    "node_modules/antd": {
+      "version": "5.25.4",
+      "resolved": "https://registry.npmjs.org/antd/-/antd-5.25.4.tgz",
+      "integrity": "sha512-yXdWqq1NJSZnD1HoPZWnWuQJGVYYnB3h0Ufsz4sbt3T0N9SdJ4G9GPpLMk8Gn9zWtwBekfR4THPVZ9uzAyhBHQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@ant-design/colors": "^7.2.1",
+        "@ant-design/cssinjs": "^1.23.0",
+        "@ant-design/cssinjs-utils": "^1.1.3",
+        "@ant-design/fast-color": "^2.0.6",
+        "@ant-design/icons": "^5.6.1",
+        "@ant-design/react-slick": "~1.1.2",
+        "@babel/runtime": "^7.26.0",
+        "@rc-component/color-picker": "~2.0.1",
+        "@rc-component/mutate-observer": "^1.1.0",
+        "@rc-component/qrcode": "~1.0.0",
+        "@rc-component/tour": "~1.15.1",
+        "@rc-component/trigger": "^2.2.6",
+        "classnames": "^2.5.1",
+        "copy-to-clipboard": "^3.3.3",
+        "dayjs": "^1.11.11",
+        "rc-cascader": "~3.34.0",
+        "rc-checkbox": "~3.5.0",
+        "rc-collapse": "~3.9.0",
+        "rc-dialog": "~9.6.0",
+        "rc-drawer": "~7.3.0",
+        "rc-dropdown": "~4.2.1",
+        "rc-field-form": "~2.7.0",
+        "rc-image": "~7.12.0",
+        "rc-input": "~1.8.0",
+        "rc-input-number": "~9.5.0",
+        "rc-mentions": "~2.20.0",
+        "rc-menu": "~9.16.1",
+        "rc-motion": "^2.9.5",
+        "rc-notification": "~5.6.4",
+        "rc-pagination": "~5.1.0",
+        "rc-picker": "~4.11.3",
+        "rc-progress": "~4.0.0",
+        "rc-rate": "~2.13.1",
+        "rc-resize-observer": "^1.4.3",
+        "rc-segmented": "~2.7.0",
+        "rc-select": "~14.16.8",
+        "rc-slider": "~11.1.8",
+        "rc-steps": "~6.0.1",
+        "rc-switch": "~4.1.0",
+        "rc-table": "~7.50.5",
+        "rc-tabs": "~15.6.1",
+        "rc-textarea": "~1.10.0",
+        "rc-tooltip": "~6.4.0",
+        "rc-tree": "~5.13.1",
+        "rc-tree-select": "~5.27.0",
+        "rc-upload": "~4.9.2",
+        "rc-util": "^5.44.4",
+        "scroll-into-view-if-needed": "^3.1.0",
+        "throttle-debounce": "^5.0.2"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/ant-design"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
     "node_modules/any-promise": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@@ -6037,6 +6367,12 @@
       "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
       "license": "MIT"
     },
+    "node_modules/classnames": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+      "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
+      "license": "MIT"
+    },
     "node_modules/clean-css": {
       "version": "5.3.3",
       "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
@@ -6290,6 +6626,12 @@
       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
       "license": "MIT"
     },
+    "node_modules/compute-scroll-into-view": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz",
+      "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==",
+      "license": "MIT"
+    },
     "node_modules/concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -6353,6 +6695,15 @@
       "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
       "license": "MIT"
     },
+    "node_modules/copy-to-clipboard": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+      "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+      "license": "MIT",
+      "dependencies": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "node_modules/core-js": {
       "version": "3.42.0",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz",
@@ -6885,6 +7236,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/dayjs": {
+      "version": "1.11.13",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+      "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
+      "license": "MIT"
+    },
     "node_modules/debug": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@@ -11427,6 +11784,15 @@
       "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
       "license": "MIT"
     },
+    "node_modules/json2mq": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
+      "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==",
+      "license": "MIT",
+      "dependencies": {
+        "string-convert": "^0.2.0"
+      }
+    },
     "node_modules/json5": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -14242,6 +14608,618 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/rc-cascader": {
+      "version": "3.34.0",
+      "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.34.0.tgz",
+      "integrity": "sha512-KpXypcvju9ptjW9FaN2NFcA2QH9E9LHKq169Y0eWtH4e/wHQ5Wh5qZakAgvb8EKZ736WZ3B0zLLOBsrsja5Dag==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.25.7",
+        "classnames": "^2.3.1",
+        "rc-select": "~14.16.2",
+        "rc-tree": "~5.13.0",
+        "rc-util": "^5.43.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-checkbox": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.5.0.tgz",
+      "integrity": "sha512-aOAQc3E98HteIIsSqm6Xk2FPKIER6+5vyEFMZfo73TqM+VVAIqOkHoPjgKLqSNtVLWScoaM7vY2ZrGEheI79yg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.3.2",
+        "rc-util": "^5.25.2"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-collapse": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.9.0.tgz",
+      "integrity": "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.3.4",
+        "rc-util": "^5.27.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-dialog": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz",
+      "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "@rc-component/portal": "^1.0.0-8",
+        "classnames": "^2.2.6",
+        "rc-motion": "^2.3.0",
+        "rc-util": "^5.21.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-drawer": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.3.0.tgz",
+      "integrity": "sha512-DX6CIgiBWNpJIMGFO8BAISFkxiuKitoizooj4BDyee8/SnBn0zwO2FHrNDpqqepj0E/TFTDpmEBCyFuTgC7MOg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.23.9",
+        "@rc-component/portal": "^1.1.1",
+        "classnames": "^2.2.6",
+        "rc-motion": "^2.6.1",
+        "rc-util": "^5.38.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-dropdown": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.1.tgz",
+      "integrity": "sha512-YDAlXsPv3I1n42dv1JpdM7wJ+gSUBfeyPK59ZpBD9jQhK9jVuxpjj3NmWQHOBceA1zEPVX84T2wbdb2SD0UjmA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.3",
+        "@rc-component/trigger": "^2.0.0",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.44.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.11.0",
+        "react-dom": ">=16.11.0"
+      }
+    },
+    "node_modules/rc-field-form": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.7.0.tgz",
+      "integrity": "sha512-hgKsCay2taxzVnBPZl+1n4ZondsV78G++XVsMIJCAoioMjlMQR9YwAp7JZDIECzIu2Z66R+f4SFIRrO2DjDNAA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.0",
+        "@rc-component/async-validator": "^5.0.3",
+        "rc-util": "^5.32.2"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-image": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.12.0.tgz",
+      "integrity": "sha512-cZ3HTyyckPnNnUb9/DRqduqzLfrQRyi+CdHjdqgsyDpI3Ln5UX1kXnAhPBSJj9pVRzwRFgqkN7p9b6HBDjmu/Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.2",
+        "@rc-component/portal": "^1.0.2",
+        "classnames": "^2.2.6",
+        "rc-dialog": "~9.6.0",
+        "rc-motion": "^2.6.2",
+        "rc-util": "^5.34.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-input": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.8.0.tgz",
+      "integrity": "sha512-KXvaTbX+7ha8a/k+eg6SYRVERK0NddX8QX7a7AnRvUa/rEH0CNMlpcBzBkhI0wp2C8C4HlMoYl8TImSN+fuHKA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.18.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.0.0",
+        "react-dom": ">=16.0.0"
+      }
+    },
+    "node_modules/rc-input-number": {
+      "version": "9.5.0",
+      "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.5.0.tgz",
+      "integrity": "sha512-bKaEvB5tHebUURAEXw35LDcnRZLq3x1k7GxfAqBMzmpHkDGzjAtnUL8y4y5N15rIFIg5IJgwr211jInl3cipag==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "@rc-component/mini-decimal": "^1.0.1",
+        "classnames": "^2.2.5",
+        "rc-input": "~1.8.0",
+        "rc-util": "^5.40.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-mentions": {
+      "version": "2.20.0",
+      "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.20.0.tgz",
+      "integrity": "sha512-w8HCMZEh3f0nR8ZEd466ATqmXFCMGMN5UFCzEUL0bM/nGw/wOS2GgRzKBcm19K++jDyuWCOJOdgcKGXU3fXfbQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.22.5",
+        "@rc-component/trigger": "^2.0.0",
+        "classnames": "^2.2.6",
+        "rc-input": "~1.8.0",
+        "rc-menu": "~9.16.0",
+        "rc-textarea": "~1.10.0",
+        "rc-util": "^5.34.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-menu": {
+      "version": "9.16.1",
+      "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.16.1.tgz",
+      "integrity": "sha512-ghHx6/6Dvp+fw8CJhDUHFHDJ84hJE3BXNCzSgLdmNiFErWSOaZNsihDAsKq9ByTALo/xkNIwtDFGIl6r+RPXBg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "@rc-component/trigger": "^2.0.0",
+        "classnames": "2.x",
+        "rc-motion": "^2.4.3",
+        "rc-overflow": "^1.3.1",
+        "rc-util": "^5.27.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-motion": {
+      "version": "2.9.5",
+      "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.5.tgz",
+      "integrity": "sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.44.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-notification": {
+      "version": "5.6.4",
+      "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.4.tgz",
+      "integrity": "sha512-KcS4O6B4qzM3KH7lkwOB7ooLPZ4b6J+VMmQgT51VZCeEcmghdeR4IrMcFq0LG+RPdnbe/ArT086tGM8Snimgiw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.9.0",
+        "rc-util": "^5.20.1"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-overflow": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.4.1.tgz",
+      "integrity": "sha512-3MoPQQPV1uKyOMVNd6SZfONi+f3st0r8PksexIdBTeIYbMX0Jr+k7pHEDvsXtR4BpCv90/Pv2MovVNhktKrwvw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.37.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-pagination": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-5.1.0.tgz",
+      "integrity": "sha512-8416Yip/+eclTFdHXLKTxZvn70duYVGTvUUWbckCCZoIl3jagqke3GLsFrMs0bsQBikiYpZLD9206Ej4SOdOXQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.3.2",
+        "rc-util": "^5.38.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-picker": {
+      "version": "4.11.3",
+      "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.11.3.tgz",
+      "integrity": "sha512-MJ5teb7FlNE0NFHTncxXQ62Y5lytq6sh5nUw0iH8OkHL/TjARSEvSHpr940pWgjGANpjCwyMdvsEV55l5tYNSg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.24.7",
+        "@rc-component/trigger": "^2.0.0",
+        "classnames": "^2.2.1",
+        "rc-overflow": "^1.3.2",
+        "rc-resize-observer": "^1.4.0",
+        "rc-util": "^5.43.0"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "date-fns": ">= 2.x",
+        "dayjs": ">= 1.x",
+        "luxon": ">= 3.x",
+        "moment": ">= 2.x",
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      },
+      "peerDependenciesMeta": {
+        "date-fns": {
+          "optional": true
+        },
+        "dayjs": {
+          "optional": true
+        },
+        "luxon": {
+          "optional": true
+        },
+        "moment": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/rc-progress": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz",
+      "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.16.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-rate": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.1.tgz",
+      "integrity": "sha512-QUhQ9ivQ8Gy7mtMZPAjLbxBt5y9GRp65VcUyGUMF3N3fhiftivPHdpuDIaWIMOTEprAjZPC08bls1dQB+I1F2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.5",
+        "rc-util": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-resize-observer": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.3.tgz",
+      "integrity": "sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.20.7",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.44.1",
+        "resize-observer-polyfill": "^1.5.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-segmented": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.7.0.tgz",
+      "integrity": "sha512-liijAjXz+KnTRVnxxXG2sYDGd6iLL7VpGGdR8gwoxAXy2KglviKCxLWZdjKYJzYzGSUwKDSTdYk8brj54Bn5BA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-motion": "^2.4.4",
+        "rc-util": "^5.17.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.0.0",
+        "react-dom": ">=16.0.0"
+      }
+    },
+    "node_modules/rc-select": {
+      "version": "14.16.8",
+      "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.16.8.tgz",
+      "integrity": "sha512-NOV5BZa1wZrsdkKaiK7LHRuo5ZjZYMDxPP6/1+09+FB4KoNi8jcG1ZqLE3AVCxEsYMBe65OBx71wFoHRTP3LRg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "@rc-component/trigger": "^2.1.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.0.1",
+        "rc-overflow": "^1.3.1",
+        "rc-util": "^5.16.1",
+        "rc-virtual-list": "^3.5.2"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-dom": "*"
+      }
+    },
+    "node_modules/rc-slider": {
+      "version": "11.1.8",
+      "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.8.tgz",
+      "integrity": "sha512-2gg/72YFSpKP+Ja5AjC5DPL1YnV8DEITDQrcc1eASrUYjl0esptaBVJBh5nLTXCCp15eD8EuGjwezVGSHhs9tQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.5",
+        "rc-util": "^5.36.0"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-steps": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz",
+      "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.16.7",
+        "classnames": "^2.2.3",
+        "rc-util": "^5.16.1"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-switch": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz",
+      "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.21.0",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.30.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-table": {
+      "version": "7.50.5",
+      "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.50.5.tgz",
+      "integrity": "sha512-FDZu8aolhSYd3v9KOc3lZOVAU77wmRRu44R0Wfb8Oj1dXRUsloFaXMSl6f7yuWZUxArJTli7k8TEOX2mvhDl4A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "@rc-component/context": "^1.4.0",
+        "classnames": "^2.2.5",
+        "rc-resize-observer": "^1.1.0",
+        "rc-util": "^5.44.3",
+        "rc-virtual-list": "^3.14.2"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-tabs": {
+      "version": "15.6.1",
+      "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.6.1.tgz",
+      "integrity": "sha512-/HzDV1VqOsUWyuC0c6AkxVYFjvx9+rFPKZ32ejxX0Uc7QCzcEjTA9/xMgv4HemPKwzBNX8KhGVbbumDjnj92aA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.2",
+        "classnames": "2.x",
+        "rc-dropdown": "~4.2.0",
+        "rc-menu": "~9.16.0",
+        "rc-motion": "^2.6.2",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.34.1"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-textarea": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.10.0.tgz",
+      "integrity": "sha512-ai9IkanNuyBS4x6sOL8qu/Ld40e6cEs6pgk93R+XLYg0mDSjNBGey6/ZpDs5+gNLD7urQ14po3V6Ck2dJLt9SA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1",
+        "rc-input": "~1.8.0",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.27.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-tooltip": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.4.0.tgz",
+      "integrity": "sha512-kqyivim5cp8I5RkHmpsp1Nn/Wk+1oeloMv9c7LXNgDxUpGm+RbXJGL+OPvDlcRnx9DBeOe4wyOIl4OKUERyH1g==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.11.2",
+        "@rc-component/trigger": "^2.0.0",
+        "classnames": "^2.3.1",
+        "rc-util": "^5.44.3"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-tree": {
+      "version": "5.13.1",
+      "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.13.1.tgz",
+      "integrity": "sha512-FNhIefhftobCdUJshO7M8uZTA9F4OPGVXqGfZkkD/5soDeOhwO06T/aKTrg0WD8gRg/pyfq+ql3aMymLHCTC4A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.0.1",
+        "rc-util": "^5.16.1",
+        "rc-virtual-list": "^3.5.1"
+      },
+      "engines": {
+        "node": ">=10.x"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-dom": "*"
+      }
+    },
+    "node_modules/rc-tree-select": {
+      "version": "5.27.0",
+      "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.27.0.tgz",
+      "integrity": "sha512-2qTBTzwIT7LRI1o7zLyrCzmo5tQanmyGbSaGTIf7sYimCklAToVVfpMC6OAldSKolcnjorBYPNSKQqJmN3TCww==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.25.7",
+        "classnames": "2.x",
+        "rc-select": "~14.16.2",
+        "rc-tree": "~5.13.0",
+        "rc-util": "^5.43.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-dom": "*"
+      }
+    },
+    "node_modules/rc-upload": {
+      "version": "4.9.2",
+      "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.9.2.tgz",
+      "integrity": "sha512-nHx+9rbd1FKMiMRYsqQ3NkXUv7COHPBo3X1Obwq9SWS6/diF/A0aJ5OHubvwUAIDs+4RMleljV0pcrNUc823GQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.3",
+        "classnames": "^2.2.5",
+        "rc-util": "^5.2.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-util": {
+      "version": "5.44.4",
+      "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.4.tgz",
+      "integrity": "sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.18.3",
+        "react-is": "^18.2.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
+    "node_modules/rc-util/node_modules/react-is": {
+      "version": "18.3.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+      "license": "MIT"
+    },
+    "node_modules/rc-virtual-list": {
+      "version": "3.18.6",
+      "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.18.6.tgz",
+      "integrity": "sha512-TQ5SsutL3McvWmmxqQtMIbfeoE3dGjJrRSfKekgby7WQMpPIFvv4ghytp5Z0s3D8Nik9i9YNOCqHBfk86AwgAA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.20.0",
+        "classnames": "^2.2.6",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.36.0"
+      },
+      "engines": {
+        "node": ">=8.x"
+      },
+      "peerDependencies": {
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0"
+      }
+    },
     "node_modules/react": {
       "version": "18.3.1",
       "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -14756,6 +15734,12 @@
       "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
       "license": "MIT"
     },
+    "node_modules/resize-observer-polyfill": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+      "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
+      "license": "MIT"
+    },
     "node_modules/resolve": {
       "version": "1.22.10",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -15189,6 +16173,15 @@
       "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
       "license": "MIT"
     },
+    "node_modules/scroll-into-view-if-needed": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
+      "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
+      "license": "MIT",
+      "dependencies": {
+        "compute-scroll-into-view": "^3.0.2"
+      }
+    },
     "node_modules/select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -15818,6 +16811,12 @@
         "safe-buffer": "~5.2.0"
       }
     },
+    "node_modules/string-convert": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
+      "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==",
+      "license": "MIT"
+    },
     "node_modules/string-length": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -16613,6 +17612,15 @@
       "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==",
       "license": "MIT"
     },
+    "node_modules/throttle-debounce": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
+      "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.22"
+      }
+    },
     "node_modules/thunky": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
@@ -16637,6 +17645,12 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
+      "license": "MIT"
+    },
     "node_modules/toidentifier": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -16885,7 +17899,7 @@
     },
     "node_modules/typescript": {
       "version": "4.9.5",
-      "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
       "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
       "license": "Apache-2.0",
       "peer": true,
diff --git a/front/package.json b/front/package.json
index 117259a..c25589f 100644
--- a/front/package.json
+++ b/front/package.json
@@ -11,6 +11,7 @@
     "@testing-library/jest-dom": "^6.6.3",
     "@testing-library/react": "^16.3.0",
     "@testing-library/user-event": "^13.5.0",
+    "antd": "^5.25.4",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "react-router-dom": "^6.30.1",
diff --git a/front/src/AnimePage.js b/front/src/AnimePage.js
index d17f3cc..97bf453 100644
--- a/front/src/AnimePage.js
+++ b/front/src/AnimePage.js
@@ -30,17 +30,16 @@
 ];

 

 const areaTabs = [

-  { label: "国创", icon: <EmojiPeopleIcon fontSize="small" /> },

-  { label: "日漫", icon: <EmailIcon fontSize="small" /> },

-  { label: "欧美动漫", icon: <PersonIcon fontSize="small" /> },

-  { label: "韩漫", icon: <EmojiPeopleIcon fontSize="small" /> },

-  // { label: "其他", icon: <PersonIcon fontSize="small" /> },

+  { label: "大陆", icon: <EmojiPeopleIcon fontSize="small" /> },

+  { label: "港台", icon: <EmailIcon fontSize="small" /> },

+  { label: "欧美", icon: <PersonIcon fontSize="small" /> },

+  { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },

+  { label: "其他", icon: <PersonIcon fontSize="small" /> },

 ];

 

 export default function AnimePage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = React.useState(0);

-  const [animeList, setAnimeList] = React.useState([]);

 

   // 每个tab对应的动漫类型

   const animeTypesList = [

@@ -52,15 +51,6 @@
   ];

   const animeTypes = animeTypesList[activeTab] || [];

 

-  React.useEffect(() => {

-    // 假设后端接口为 /api/animes?area=大陆

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => setAnimeList(data))

-      .catch(() => setAnimeList([]));

-  }, [activeTab]);

-

   return (

     <div className="container">

       {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}

@@ -118,39 +108,21 @@
             </tr>

           </thead>

           <tbody>

-            {animeList.length > 0 ? (

-              animeList.map((item, index) => (

-                <tr key={item.id || index}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              animeTypes.map((type, index) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      种子{index + 1}

-                    </a>

-                  </td>

-                  <td>发布者{index + 1}</td>

-                </tr>

-              ))

-            )}

+            {animeTypes.map((type, index) => (

+              <tr key={type}>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    种子{index + 1}

+                  </a>

+                </td>

+                <td>发布者{index + 1}</td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/App.js b/front/src/App.js
index 240f958..225689e 100644
--- a/front/src/App.js
+++ b/front/src/App.js
@@ -1,5 +1,5 @@
 import React from "react";
-import { BrowserRouter as Router, Routes, Route, useNavigate, Link } from "react-router-dom";
+import { BrowserRouter as Router, Routes, Route, useNavigate, Link, Navigate } from "react-router-dom";
 import MovieIcon from "@mui/icons-material/Movie";
 import EmailIcon from "@mui/icons-material/Email";
 import MusicNoteIcon from "@mui/icons-material/MusicNote";
@@ -19,6 +19,8 @@
 import UserProfile from "./UserProfile";
 import PublishPage from "./PublishPage";
 import TorrentDetailPage from './TorrentDetailPage';
+import LoginPage from './LoginPage';
+import RegisterPage from './RegisterPage';
 
 const navItems = [
   { label: "电影", icon: <MovieIcon />, path: "/movie" },
@@ -142,7 +144,9 @@
   return (
     <Router>
       <Routes>
-        <Route path="/" element={<Home />} />
+        <Route path="/login" element={<LoginPage />} />
+        <Route path="/register" element={<RegisterPage />} />
+        <Route path="/" element={<Navigate to="/login" replace />} />
         <Route path="/movie" element={<MoviePage />} />
         <Route path="/tv" element={<TVPage />} />
         <Route path="/music" element={<MusicPage />} />
diff --git a/front/src/GamePage.js b/front/src/GamePage.js
index 2528acd..23383b6 100644
--- a/front/src/GamePage.js
+++ b/front/src/GamePage.js
@@ -21,13 +21,7 @@
   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

-const gameTypesList = [

-  ["PC"],

-  ["主机"],

-  ["移动"],

-  ["掌机"],

-  ["视频"]

-];

+const gameTypes = ["PC", "主机", "移动", "掌机", "视频"];

 

 const areaTabs = [

   { label: "PC", icon: <MovieIcon fontSize="small" /> },

@@ -37,20 +31,15 @@
   { label: "视频", icon: <PersonIcon fontSize="small" /> },

 ];

 

+const exampleTorrents = [

+  { type: "RPG", title: "实例1", id: 1 },

+  { type: "Shooter", title: "实例2", id: 2 },

+  { type: "Adventure", title: "实例3", id: 3 },

+];

+

 export default function GamePage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = useState(0);

-  const [gameList, setGameList] = useState([]);

-

-  const gameTypes = gameTypesList[activeTab] || [];

-

-  React.useEffect(() => {

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => setGameList(data))

-      .catch(() => setGameList([]));

-  }, [activeTab]);

 

   return (

     <div className="container">

@@ -164,39 +153,27 @@
             </tr>

           </thead>

           <tbody>

-            {gameList.length > 0 ? (

-              gameList.map((item, idx) => (

-                <tr key={item.id || idx}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              gameTypes.map((type, idx) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      种子{idx + 1}

-                    </a>

-                  </td>

-                  <td></td>

-                </tr>

-              ))

-            )}

+            {gameTypes.map((type, idx) => (

+              <tr key={type}>

+                <td>

+                  <a

+                    href={`/torrent/${type}`}

+                    style={{ color: "#1a237e", textDecoration: "none" }}

+                  >

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a

+                    href={`/torrent/${type}`}

+                    style={{ color: "#1a237e", textDecoration: "none" }}

+                  >

+                    种子{idx + 1}

+                  </a>

+                </td>

+                <td></td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/InfoPage.js b/front/src/InfoPage.js
index 755d922..1e00527 100644
--- a/front/src/InfoPage.js
+++ b/front/src/InfoPage.js
@@ -40,7 +40,6 @@
 export default function InfoPage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = React.useState(0);

-  const [infoList, setInfoList] = React.useState(0);

 

   // 每个tab对应的资料类型

   const infoTypesList = [

@@ -52,18 +51,6 @@
   ];

   const infoTypes = infoTypesList[activeTab] || [];

 

-  React.useEffect(() => {

-    // 这里假设后端接口为 /api/get-seed-list-by-tag?tag=大陆

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => {

-        console.log('资料区返回数据:', data);

-        setInfoList(data);

-      })

-      .catch(() => setInfoList([]));

-  }, [activeTab]);

-

   return (

     <div className="container">

       {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}

@@ -176,39 +163,27 @@
             </tr>

           </thead>

           <tbody>

-            {infoList.length > 0 ? (

-              infoList.map((item, index) => (

-                <tr key={item.id || index}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              infoTypesList.map((type, index) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      种子{index + 1}

-                    </a>

-                  </td>

-                  <td>发布者{index + 1}</td>

-                </tr>

-              ))

-            )}

+            {infoTypes.map((type, index) => (

+              <tr key={type}>

+                <td>

+                  <a

+                    href={`/torrent/${type}`}

+                    style={{ color: "#1a237e", textDecoration: "none" }}

+                  >

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a

+                    href={`/torrent/${type}`}

+                    style={{ color: "#1a237e", textDecoration: "none" }}

+                  >

+                    种子{index + 1}

+                  </a>

+                </td>

+                <td>发布者{index + 1}</td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/LoginPage.js b/front/src/LoginPage.js
new file mode 100644
index 0000000..59a1b2b
--- /dev/null
+++ b/front/src/LoginPage.js
@@ -0,0 +1,100 @@
+import React, { useState } from 'react';

+import { useNavigate } from 'react-router-dom';

+import { Input } from 'antd';

+import './App.css';

+

+const LoginPage = () => {

+  const [formData, setFormData] = useState({ username: '', password: '' });

+  const [errorMessage, setErrorMessage] = useState('');

+  const navigate = useNavigate();

+

+  const handleChange = (e) => {

+    const { name, value } = e.target;

+    setFormData({ ...formData, [name]: value });

+  };

+

+  const handleLogin = () => {

+    if (formData.password.length < 8) {

+      setErrorMessage('密码必须至少包含八位字符!');

+      return;

+    }

+

+    // Simulate successful login

+    setErrorMessage('');

+    navigate('/');

+  };

+

+  const handleRegister = () => {

+    navigate('/register');

+  };

+

+  // 自动填充注册信息

+  React.useEffect(() => {

+    const regUser = sessionStorage.getItem('registeredUser');

+    if (regUser) {

+      try {

+        const { username, password } = JSON.parse(regUser);

+        setFormData({ username, password });

+        sessionStorage.removeItem('registeredUser');

+      } catch {}

+    }

+  }, []);

+

+  return (

+    <div className="login-page" style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #e0e7ff 0%, #f0f8ff 100%)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>

+      <div className="login-form-container" style={{ width: 360, padding: '40px 32px 80px 32px', borderRadius: 18, boxShadow: '0 8px 32px rgba(60, 80, 180, 0.10)', background: '#fff', position: 'relative' }}>

+        <h1 style={{ textAlign: 'center', marginBottom: 32, color: '#222', fontWeight: 700, fontSize: 32, letterSpacing: 2 }}>欢迎登录</h1>

+        <form className="login-form">

+          <div className="form-row" style={{ marginBottom: 24 }}>

+            <label htmlFor="username" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>用户名</label>

+            <Input

+              placeholder="请输入用户名"

+              id="username"

+              name="username"

+              value={formData.username}

+              onChange={handleChange}

+              required

+              style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}

+            />

+          </div>

+          <div className="form-row" style={{ marginBottom: 24 }}>

+            <label htmlFor="password" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>密码</label>

+            <div style={{ display: 'flex', alignItems: 'center' }}>

+              <Input

+                placeholder="请输入密码"

+                type="password"

+                id="password"

+                name="password"

+                value={formData.password}

+                onChange={handleChange}

+                required

+                style={{ flex: 1, padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}

+              />

+            </div>

+          </div>

+          {errorMessage && <p style={{ color: '#e53935', textAlign: 'center', marginBottom: 18, fontWeight: 500 }}>{errorMessage}</p>}

+          <div className="form-row button-row" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 32, position: 'static', gap: 16 }}>

+            <button

+              type="button"

+              className="login-button"

+              onClick={handleLogin}

+              style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #34c759 0%, #5be584 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2eac2', marginBottom: 12 }}

+            >

+              登录

+            </button>

+            <button

+              type="button"

+              className="register-button"

+              onClick={handleRegister}

+              style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #4f8cff 0%, #6ad1ff 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2d8ea' }}

+            >

+              注册

+            </button>

+          </div>

+        </form>

+      </div>

+    </div>

+  );

+};

+

+export default LoginPage;

diff --git a/front/src/MoviePage.js b/front/src/MoviePage.js
index c84797b..20e4a4f 100644
--- a/front/src/MoviePage.js
+++ b/front/src/MoviePage.js
@@ -26,7 +26,7 @@
   { label: "港台", icon: <EmailIcon fontSize="small" /> },

   { label: "欧美", icon: <PersonIcon fontSize="small" /> },

   { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },

-  // { label: "其他", icon: <PersonIcon fontSize="small" /> },

+  { label: "其他", icon: <PersonIcon fontSize="small" /> },

 ];

 

 const exampleTorrents = [

@@ -38,7 +38,6 @@
 export default function MoviePage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = React.useState(0);

-  const [movieList, setMovieList] = React.useState([]);

 

   // 每个tab对应的电影类型

   const movieTypesList = [

@@ -50,18 +49,6 @@
   ];

   const movieTypes = movieTypesList[activeTab] || [];

 

-  React.useEffect(() => {

-    // 这里假设后端接口为 /api/get-seed-list-by-tag?tag=大陆

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => {

-        console.log('电影区返回数据:', data);

-        setMovieList(data);

-      })

-      .catch(() => setMovieList([]));

-  }, [activeTab]);

-

   return (

     <div className="container">

       {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}

@@ -119,39 +106,21 @@
             </tr>

           </thead>

           <tbody>

-            {movieList.length > 0 ? (

-              movieList.map((item, index) => (

-                <tr key={item.id || index}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              movieTypes.map((type, index) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      种子{index + 1}

-                    </a>

-                  </td>

-                  <td>发布者{index + 1}</td>

-                </tr>

-              ))

-            )}

+            {movieTypes.map((type, index) => (

+              <tr key={type}>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    种子{index + 1}

+                  </a>

+                </td>

+                <td>发布者{index + 1}</td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/MusicPage.js b/front/src/MusicPage.js
index b39b0ee..4a9c465 100644
--- a/front/src/MusicPage.js
+++ b/front/src/MusicPage.js
@@ -22,11 +22,11 @@
 ];

 

 const areaTabs = [

-  { label: "古典音乐", icon: <MovieIcon fontSize="small" /> },

-  { label: "流行音乐", icon: <EmailIcon fontSize="small" /> },

-  { label: "摇滚", icon: <PersonIcon fontSize="small" /> },

-  { label: "电子音乐", icon: <EmojiPeopleIcon fontSize="small" /> },

-  { label: "说唱", icon: <PersonIcon fontSize="small" /> },

+  { label: "大陆", icon: <MovieIcon fontSize="small" /> },

+  { label: "港台", icon: <EmailIcon fontSize="small" /> },

+  { label: "欧美", icon: <PersonIcon fontSize="small" /> },

+  { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },

+  { label: "其他", icon: <PersonIcon fontSize="small" /> },

 ];

 

 const exampleTorrents = [

@@ -38,7 +38,6 @@
 export default function MusicPage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = React.useState(0);

-  const [musicList, setMusicList] = React.useState([]);

 

   // 每个tab对应的音乐类型

   const musicTypesList = [

@@ -50,15 +49,6 @@
   ];

   const musicTypes = musicTypesList[activeTab] || [];

 

-  React.useEffect(() => {

-    // 假设后端接口为 /api/musics?area=大陆

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => setMusicList(data))

-      .catch(() => setMusicList([]));

-  }, [activeTab]);

-

   return (

     <div className="container music-bg">

       {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}

@@ -116,39 +106,21 @@
             </tr>

           </thead>

           <tbody>

-            {musicList.length > 0 ? (

-              musicList.map((item, index) => (

-                <tr key={item.id || index}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              musicTypes.map((type, index) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      种子{index + 1}

-                    </a>

-                  </td>

-                  <td>发布者{index + 1}</td>

-                </tr>

-              ))

-            )}

+            {musicTypes.map((type, index) => (

+              <tr key={type}>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    种子{index + 1}

+                  </a>

+                </td>

+                <td>发布者{index + 1}</td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/PublishPage.js b/front/src/PublishPage.js
index a1a0e8f..81ac790 100644
--- a/front/src/PublishPage.js
+++ b/front/src/PublishPage.js
@@ -9,17 +9,6 @@
     title: '',

     subtitle: ''

   });

-  const [subType, setSubType] = useState('');

-

-  const typeOptions = {

-    '电影': ['大陆', '港台', '欧美', '日韩'],

-    '剧集': ['国产电视剧', '港剧', '欧美剧', '日韩剧'],

-    '音乐': ['古典音乐', '流行音乐', '摇滚', '电子音乐', '说唱'],

-    '动漫': ['国创', '日漫', '欧美动漫', '韩漫'],

-    '游戏': ['PC', '主机', '移动', '掌机', '视频'],

-    '体育': ['篮球', '足球', '羽毛球', '排球', '电竞'],

-    '资料': ['出版物', '学习教程', '素材模板', '演讲交流', '日常娱乐'],

-  };

 

   const handleChange = (e) => {

     const { name, value } = e.target;

@@ -36,37 +25,9 @@
     }

   };

 

-  const handleSubmit = async (e) => {

+  const handleSubmit = (e) => {

     e.preventDefault();

-    // 假设userid和tag可以从表单或用户信息中获取,这里用示例数据

-    const userid = '550e8400-e29b-41d4-a716-446655440000';

-    const tag = formData.type ? formData.type : '高清';

-    if (!formData.torrentFile) {

-      alert('请上传.torrent文件');

-      return;

-    }

-    const data = new FormData();

-    data.append('userid', userid);

-    data.append('title', formData.title);

-    data.append('tag', subType);

-    data.append('file', formData.torrentFile);

-    data.append('subtitle', formData.subtitle);

-    // data.append('subtype', subType);

-    // console.log(data.get('tag'));

-

-    try {

-      const response = await fetch('http://192.168.5.9:8080/api/save-torrent', {

-        method: 'POST',

-        body: data,

-      });

-      if (response.ok) {

-        alert('上传成功!');

-      } else {

-        alert('上传失败');

-      }

-    } catch (err) {

-      alert('网络错误');

-    }

+    console.log('Form Data Submitted:', formData);

   };

 

   return (

@@ -75,7 +36,7 @@
       <form onSubmit={handleSubmit} className="publish-form">

         <div className="form-row">

           <label htmlFor="type">类型</label>

-          <select name="type" id="type" value={formData.type} onChange={e => { handleChange(e); setSubType(''); }} required>

+          <select name="type" id="type" value={formData.type} onChange={handleChange} required>

             <option value="">请选择类型</option>

             <option value="电影">电影</option>

             <option value="剧集">剧集</option>

@@ -86,17 +47,6 @@
             <option value="资料">资料</option>

           </select>

         </div>

-        {formData.type && typeOptions[formData.type] && (

-          <div className="form-row">

-            <label htmlFor="subtype">具体类型</label>

-            <select name="subtype" id="subtype" value={subType} onChange={e => setSubType(e.target.value)} required>

-              <option value="">请选择具体类型</option>

-              {typeOptions[formData.type].map(opt => (

-                <option key={opt} value={opt}>{opt}</option>

-              ))}

-            </select>

-          </div>

-        )}

 

         <div className="form-row">

           <label htmlFor="torrentFile">种子文件</label>

@@ -123,7 +73,7 @@
         </div>

 

         <div className="form-row">

-          <label htmlFor="subtitle">副标题</label>

+          <label htmlFor="subtitle">种子简介</label>

           <input

             type="text"

             id="subtitle"

diff --git a/front/src/RegisterPage.js b/front/src/RegisterPage.js
new file mode 100644
index 0000000..ffd11a4
--- /dev/null
+++ b/front/src/RegisterPage.js
@@ -0,0 +1,109 @@
+import React, { useState } from 'react';

+import { useNavigate } from 'react-router-dom';

+import { Input } from 'antd';

+import './App.css';

+

+const RegisterPage = () => {

+  const [formData, setFormData] = useState({ username: '', password: '', inviteCode: '', confirmPassword: '' });

+  const [errorMessage, setErrorMessage] = useState('');

+  const navigate = useNavigate();

+

+  const handleChange = (e) => {

+    const { name, value } = e.target;

+    setFormData({ ...formData, [name]: value });

+  };

+

+  const handleRegister = () => {

+    if (formData.password.length !== 8) {

+      setErrorMessage('密码必须为八位字符!');

+      return;

+    }

+

+    if (formData.password !== formData.confirmPassword) {

+      setErrorMessage('两次输入的密码不匹配!');

+      return;

+    }

+

+    // Simulate successful registration

+    setErrorMessage('');

+    // 存储注册信息到 sessionStorage

+    sessionStorage.setItem('registeredUser', JSON.stringify({ username: formData.username, password: formData.password }));

+    alert('注册成功!');

+    navigate('/login');

+  };

+

+  return (

+    <div className="register-page" style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #e0e7ff 0%, #f0f8ff 100%)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>

+      <div className="register-form-container" style={{ width: 360, padding: '40px 32px 64px 32px', borderRadius: 18, boxShadow: '0 8px 32px rgba(60, 80, 180, 0.10)', background: '#fff', position: 'relative' }}>

+        <h1 style={{ textAlign: 'center', marginBottom: 32, color: '#222', fontWeight: 700, fontSize: 32, letterSpacing: 2 }}>欢迎注册</h1>

+        <form className="register-form">

+          <div className="form-row" style={{ marginBottom: 24 }}>

+            <label htmlFor="inviteCode" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>被邀请邮箱</label>

+            <Input

+              placeholder="请输入被邀请邮箱"

+              id="inviteCode"

+              name="inviteCode"

+              value={formData.inviteCode || ''}

+              onChange={handleChange}

+              required

+              style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}

+            />

+          </div>

+          <div className="form-row" style={{ marginBottom: 24 }}>

+            <label htmlFor="username" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>用户名</label>

+            <Input

+              placeholder="请输入用户名"

+              id="username"

+              name="username"

+              value={formData.username}

+              onChange={handleChange}

+              required

+              style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}

+            />

+          </div>

+          <div className="form-row" style={{ marginBottom: 24 }}>

+            <label htmlFor="password" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>密码</label>

+            <div style={{ display: 'flex', alignItems: 'center' }}>

+              <Input

+                placeholder="请输入密码"

+                type="password"

+                id="password"

+                name="password"

+                value={formData.password}

+                onChange={handleChange}

+                required

+                style={{ flex: 1, padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}

+              />

+            </div>

+          </div>

+          <div className="form-row" style={{ marginBottom: 24 }}>

+            <label htmlFor="confirmPassword" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>确认密码</label>

+            <Input

+              placeholder="请再次输入密码"

+              type="password"

+              id="confirmPassword"

+              name="confirmPassword"

+              value={formData.confirmPassword || ''}

+              onChange={handleChange}

+              required

+              style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}

+            />

+          </div>

+          {errorMessage && <p style={{ color: '#e53935', textAlign: 'center', marginBottom: 18, fontWeight: 500 }}>{errorMessage}</p>}

+          <div className="form-row button-row" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', position: 'absolute', left: 0, right: 0, bottom: 24 }}>

+            <button

+              type="button"

+              className="register-button"

+              onClick={handleRegister}

+              style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #4f8cff 0%, #6ad1ff 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2d8ea' }}

+            >

+              注册

+            </button>

+          </div>

+        </form>

+      </div>

+    </div>

+  );

+};

+

+export default RegisterPage;

diff --git a/front/src/SportPage.js b/front/src/SportPage.js
index 3299a93..569f022 100644
--- a/front/src/SportPage.js
+++ b/front/src/SportPage.js
@@ -40,7 +40,6 @@
 export default function SportPage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = React.useState(0);

-  const [sportList, setSportList] = React.useState([]);

 

   // 每个tab对应的运动类型

   const sportTypesList = [

@@ -52,15 +51,6 @@
   ];

   const sportTypes = sportTypesList[activeTab] || [];

 

-  React.useEffect(() => {

-    // 假设后端接口为 /api/sports?area=篮球

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => setSportList(data))

-      .catch(() => setSportList([]));

-  }, [activeTab]);

-

   return (

     <div className="container">

       {/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}

@@ -173,39 +163,27 @@
             </tr>

           </thead>

           <tbody>

-            {sportList.length > 0 ? (

-              sportList.map((item, index) => (

-                <tr key={item.id || index}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              sportTypes.map((type, index) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>

-                      种子{index + 1}

-                    </a>

-                  </td>

-                  <td>发布者{index + 1}</td>

-                </tr>

-              ))

-            )}

+            {sportTypes.map((type, index) => (

+              <tr key={type}>

+                <td>

+                  <a

+                    href={`/torrent/${type}`}

+                    style={{ color: "#1a237e", textDecoration: "none" }}

+                  >

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a

+                    href={`/torrent/${type}`}

+                    style={{ color: "#1a237e", textDecoration: "none" }}

+                  >

+                    种子{index + 1}

+                  </a>

+                </td>

+                <td>发布者{index + 1}</td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/TVPage.js b/front/src/TVPage.js
index bf1db6c..13b7391 100644
--- a/front/src/TVPage.js
+++ b/front/src/TVPage.js
@@ -21,37 +21,40 @@
   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

-const tvTypesList = [

-  ["华语剧集(大陆)", "欧美剧集", "日韩剧集", "港台剧集", "其他"], // 大陆

-  ["港台都市", "港台爱情", "港台悬疑", "港台其他"], // 港台

-  ["欧美悬疑", "欧美历史", "欧美其他"], // 欧美

-  ["日韩青春", "日韩家庭", "日韩其他"], // 日韩

-  ["其他类型1", "其他类型2"] // 其他

+const tvTypes = [

+  "华语剧集(大陆)",

+  "欧美剧集",

+  "日韩剧集",

+  "港台剧集",

+  "其他"

 ];

 

 const areaTabs = [

-  { label: "国产电视剧", icon: <MovieIcon fontSize="small" /> },

-  { label: "港剧", icon: <EmailIcon fontSize="small" /> },

-  { label: "欧美剧", icon: <PersonIcon fontSize="small" /> },

-  { label: "日韩剧", icon: <EmojiPeopleIcon fontSize="small" /> },

-  // { label: "其他", icon: <PersonIcon fontSize="small" /> },

+  { label: "大陆", icon: <MovieIcon fontSize="small" /> },

+  { label: "港台", icon: <EmailIcon fontSize="small" /> },

+  { label: "欧美", icon: <PersonIcon fontSize="small" /> },

+  { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },

+  { label: "其他", icon: <PersonIcon fontSize="small" /> },

+];

+

+const exampleTorrents = [

+  { type: "Drama", title: "实例1", id: 1 },

+  { type: "Comedy", title: "实例2", id: 2 },

+  { type: "Sci-Fi", title: "实例3", id: 3 },

 ];

 

 export default function TVPage() {

   const navigate = useNavigate();

   const [activeTab, setActiveTab] = React.useState(0);

-  const [tvList, setTvList] = React.useState([]);

-

-  React.useEffect(() => {

-    // 假设后端接口为 /api/tvs?area=大陆

-    const area = areaTabs[activeTab].label;

-    fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)

-      .then(res => res.json())

-      .then(data => setTvList(data))

-      .catch(() => setTvList([]));

-  }, [activeTab]);

 

   // 每个tab对应的剧集类型

+  const tvTypesList = [

+    ["华语剧集(大陆)", "欧美剧集", "日韩剧集", "港台剧集", "其他"], // 大陆

+    ["港台都市", "港台爱情", "港台悬疑", "港台其他"], // 港台

+    ["欧美悬疑", "欧美历史", "欧美其他"], // 欧美

+    ["日韩青春", "日韩家庭", "日韩其他"], // 日韩

+    ["其他类型1", "其他类型2"] // 其他

+  ];

   const tvTypes = tvTypesList[activeTab] || [];

 

   return (

@@ -111,39 +114,21 @@
             </tr>

           </thead>

           <tbody>

-            {tvList.length > 0 ? (

-              tvList.map((item, index) => (

-                <tr key={item.id || index}>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.seedtag}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {item.title}

-                    </a>

-                  </td>

-                  <td>{item.user.username}</td>

-                </tr>

-              ))

-            ) : (

-              tvTypes.map((type, index) => (

-                <tr key={type}>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      {type}

-                    </a>

-                  </td>

-                  <td>

-                    <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

-                      种子{index + 1}

-                    </a>

-                  </td>

-                  <td>发布者{index + 1}</td>

-                </tr>

-              ))

-            )}

+            {tvTypes.map((type, index) => (

+              <tr key={type}>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    {type}

+                  </a>

+                </td>

+                <td>

+                  <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>

+                    种子{index + 1}

+                  </a>

+                </td>

+                <td></td>

+              </tr>

+            ))}

           </tbody>

         </table>

       </div>

diff --git a/front/src/TorrentDetailPage.js b/front/src/TorrentDetailPage.js
index 8d3ee43..a23dce7 100644
--- a/front/src/TorrentDetailPage.js
+++ b/front/src/TorrentDetailPage.js
@@ -4,81 +4,14 @@
 

 export default function TorrentDetailPage() {

   const { torrentId } = useParams();

-  const [detail, setDetail] = React.useState(null);

-  const [loading, setLoading] = React.useState(true);

-  const [error, setError] = React.useState(null);

-  // 假设你从某个地方获取了 userId(例如登录状态、localStorage 等)

-  const [userId] = React.useState('user1550e8400-e29b-41d4-a716-44665544000023'); // 替换为实际的用户 ID

-

-  const handleClick = () => {

-    // 构造下载 URL,包含 userId 和 torrentId 参数

-    console.log(torrentId)

-    const downloadUrl = `http://192.168.5.9:8080/api/get-torrent?userId=${encodeURIComponent(userId)}&torrentId=${encodeURIComponent(torrentId)}`;

-    

-    // 发起 GET 请求下载文件

-    fetch(downloadUrl)

-      .then(response => {

-        if (!response.ok) {

-          throw new Error('下载失败');

-        }

-        return response.blob();

-      })

-      .then(blob => {

-        // 创建下载链接并触发下载

-        const url = window.URL.createObjectURL(blob);

-        const a = document.createElement('a');

-        a.href = url;

-        a.download = `torrent-${torrentId}.torrent`;

-        document.body.appendChild(a);

-        a.click();

-        window.URL.revokeObjectURL(url);

-        document.body.removeChild(a);

-      })

-      .catch(error => {

-        console.error('下载错误:', error);

-        alert('下载失败: ' + error.message);

-      });

-  };

-

-  React.useEffect(() => {

-    setLoading(true);

-    setError(null);

-    fetch(`http://192.168.5.9:8080/api/torrent-detail?id=${encodeURIComponent(torrentId)}`)

-      .then(res => {

-        if (!res.ok) throw new Error('网络错误');

-        return res.json();

-      })

-      .then(data => {

-        setDetail(data);

-        setLoading(false);

-      })

-      .catch(err => {

-        setError(err.message);

-        setLoading(false);

-      });

-  }, [torrentId]);

-

-  if (loading) return <div className="container"><h1>加载中...</h1></div>;

-  if (error) return <div className="container"><h1>加载失败: {error}</h1></div>;

-  if (!detail) return <div className="container"><h1>未找到详情</h1></div>;

 

   return (

     <div className="container">

       <h1>种子详情页</h1>

-      <h2 style={{ fontSize: 'inherit', fontWeight: 'normal', textAlign: 'left' }}>标题: {detail.title || `种子${torrentId}`}</h2>

-      <p style={{ fontSize: 'inherit', textAlign: 'left' }}>简介: {detail.description || `这是种子${torrentId}的详细信息。`}</p>

+      <h2 style={{ fontSize: 'inherit', fontWeight: 'normal', textAlign: 'left' }}>标题: 种子{torrentId}</h2>

+      <p style={{ fontSize: 'inherit', textAlign: 'left' }}>简介: 这是种子{torrentId}的详细信息。</p>

       <div style={{ textAlign: 'center', marginTop: '20px' }}>

-        <button 

-          style={{ 

-            padding: '10px 20px', 

-            fontSize: '16px', 

-            cursor: 'pointer', 

-            backgroundColor: '#d3f0ff', 

-            border: 'none', 

-            borderRadius: '4px' 

-          }} 

-          onClick={handleClick}

-        >

+        <button style={{ padding: '10px 20px', fontSize: '16px', cursor: 'pointer', backgroundColor: '#d3f0ff', border: 'none', borderRadius: '4px' }}>

           下载

         </button>

       </div>

diff --git a/front/src/UserProfile.js b/front/src/UserProfile.js
index 4737033..0269723 100644
--- a/front/src/UserProfile.js
+++ b/front/src/UserProfile.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";

+import React, { useState } from "react";

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

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

 import "./App.css";

@@ -6,109 +6,21 @@
 export default function UserProfile() {

   const navigate = useNavigate();

   const [userInfo, setUserInfo] = useState({

-    avatar_url: "",

     username: "示例用户",

     email: "user@example.com",

-    invite_left: "",

+    company: "",

     school: "",

-    account_status: "",

-    gender: "",

+    birthday: "",

   });

   const [tempUserInfo, setTempUserInfo] = useState({ ...userInfo });

-  const [userSeeds, setUserSeeds] = useState([]);

-  const [userStats, setUserStats] = useState({

-    magic: 0,

-    upload: 0,

-    download: 0,

-    ratio: 0,

-  });

-

-  // 新增:根据userid从后端获取用户信息

-  useEffect(() => {

-    const fetchUserInfo = async () => {

-      // 假设userid存储在localStorage或其他地方

-      // const userid = localStorage.getItem("userid");

-      const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid

-      if (!userid) return;

-      try {

-        const res = await fetch(`/api/user-profile?userid=${userid}`);

-        if (res.ok) {

-          const data = await res.json();

-          setUserInfo(data);

-          setTempUserInfo(data);

-        }

-      } catch (err) {

-        // 可以根据需要处理错误

-        console.error("获取用户信息失败", err);

-      }

-    };

-    fetchUserInfo();

-  }, []);

-

-  // 动态加载用户上传种子列表

-  useEffect(() => {

-    const fetchUserSeeds = async () => {

-      // const userid = localStorage.getItem("userid");

-      const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid

-      if (!userid) return;

-      try {

-        const res = await fetch(`/api/user-seeds?userid=${userid}`);

-        if (res.ok) {

-          const data = await res.json();

-          setUserSeeds(data);

-        }

-      } catch (err) {

-        console.error("获取种子列表失败", err);

-      }

-    };

-    fetchUserSeeds();

-  }, []);

-

-  // 动态加载用户活跃度信息

-  useEffect(() => {

-    const fetchUserStats = async () => {

-      // const userid = localStorage.getItem("userid");

-      const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid

-      if (!userid) return;

-      try {

-        const res = await fetch(`/api/user-stats?userid=${userid}`);

-        if (res.ok) {

-          const data = await res.json();

-          setUserStats(data);

-        }

-      } catch (err) {

-        console.error("获取活跃度信息失败", err);

-      }

-    };

-    fetchUserStats();

-  }, []);

 

   const handleInputChange = (field, value) => {

     setTempUserInfo({ ...tempUserInfo, [field]: value });

   };

 

-  const handleSave = async () => {

+  const handleSave = () => {

     setUserInfo({ ...tempUserInfo });

-    // 获取userid

-    // const userid = localStorage.getItem("userid");

-    const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid

-    try {

-      const res = await fetch('/api/change-profile', {

-        method: 'POST',

-        headers: {

-          'Content-Type': 'application/json',

-        },

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

-      });

-      if (res.ok) {

-        alert("信息已保存!");

-      } else {

-        alert("保存失败,请重试。");

-      }

-    } catch (err) {

-      alert("保存失败,请检查网络连接。");

-      console.error("保存用户信息失败", err);

-    }

+    alert("信息已保存!");

   };

 

   const handleAvatarClick = () => {

@@ -127,7 +39,7 @@
             <AccountCircleIcon style={{ fontSize: 90, color: '#1a237e', marginBottom: 12 }} />

             {tempUserInfo.avatar && (

               <img

-                src={tempUserInfo.avatar_url}

+                src={tempUserInfo.avatar}

                 alt="用户头像"

                 style={{

                   position: 'absolute',

@@ -155,19 +67,21 @@
           </div>

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

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

-            <span

-              style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }}

-            >

-              {tempUserInfo.email}

-            </span>

+            <input

+              type="email"

+              value={tempUserInfo.email}

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

+              style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}

+            />

           </div>

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

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

-            <span

-              style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }}

-            >

-              {tempUserInfo.invite_left}

-            </span>

+            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>公司:</b>

+            <input

+              type="text"

+              value={tempUserInfo.company}

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

+              style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}

+            />

           </div>

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

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

@@ -179,21 +93,22 @@
             />

           </div>

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

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

-            <span

-              style={{ flex: 1, display: 'flex', alignItems: 'center', padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }}

-            >

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

-              <span style={{

-                display: 'inline-block',

-                width: 12,

-                height: 12,

-                borderRadius: '50%',

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

-                marginLeft: 10,

-                border: '1px solid #b2b2b2',

-              }} />

-            </span>

+            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>生日:</b>

+            <input

+              type="date"

+              value={tempUserInfo.birthday}

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

+              style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}

+            />

+          </div>

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

+            <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>密码:</b>

+            <input

+              type="password"

+              value={tempUserInfo.password || ""}

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

+              style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}

+            />

           </div>

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

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

@@ -272,61 +187,15 @@
       {/* 上传种子列表 */}

       <div style={{ gridColumn: '2 / 3', gridRow: '1 / 2', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}>

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

-        <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, minHeight: 60, padding: 12 }}>

-          {userSeeds.length === 0 ? (

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

-          ) : (

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

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

-                <li

-                  key={seed.seed_id || idx}

-                  style={{ display: 'flex', alignItems: 'center', padding: '10px 0', borderBottom: '1px solid #e0e7ff', cursor: 'pointer' }}

-                  onClick={e => {

-                    // 阻止点击删除按钮时跳转

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

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

-                  }}

-                >

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

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

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

-                  <button

-                    className="delete-btn"

-                    style={{ marginLeft: 18, background: '#e53935', color: '#fff', border: 'none', borderRadius: 6, padding: '4px 14px', cursor: 'pointer', fontSize: 14 }}

-                    onClick={async (e) => {

-                      e.stopPropagation();

-                      // const userid = localStorage.getItem("userid");

-                      const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid

-                      try {

-                        const res = await fetch('/api/delete-seed', {

-                          method: 'POST',

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

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

-                        });

-                        if (res.ok) {

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

-                        } else {

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

-                        }

-                      } catch (err) {

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

-                      }

-                    }}

-                  >删除</button>

-                </li>

-              ))}

-            </ul>

-          )}

+        <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b2b2b2', fontSize: 18 }}>

+          (此处显示上传种子列表)

         </div>

       </div>

       {/* 活跃度模块 */}

       <div style={{ gridColumn: '2 / 3', gridRow: '2 / 3', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}>

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

-        <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, minHeight: 60, padding: 18, display: 'flex', flexDirection: 'column', gap: 12, fontSize: 18 }}>

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

-          <div>上传量:<b style={{ color: '#43a047' }}>{userStats.upload} GB</b></div>

-          <div>下载量:<b style={{ color: '#e53935' }}>{userStats.download} GB</b></div>

-          <div>上传/下载值:<b style={{ color: '#ff9800' }}>{userStats.ratio}</b></div>

+        <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b2b2b2', fontSize: 18 }}>

+          (此处显示活跃度信息)

         </div>

       </div>

     </div>