上传和查看帖子

Change-Id: I6a7987a94d35481c52e610a760816b60b773a378
diff --git a/1.txt b/1.txt
deleted file mode 100644
index e69de29..0000000
--- a/1.txt
+++ /dev/null
diff --git a/API/API-TRM/WZY/xhs_front/README.md b/API/API-TRM/WZY/xhs_front/README.md
new file mode 100644
index 0000000..6f35930
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/README.md
@@ -0,0 +1,185 @@
+# 小红书内容创作平台
+
+这是一个基于 React + Vite 构建的小红书内容创作平台界面,完全复制了小红书官方创作服务平台的设计和功能。
+
+## 功能特性 ✨
+
+### 🎨 界面设计
+- **完全还原小红书官方设计**:精确复制了小红书创作服务平台的视觉风格
+- **响应式布局**:支持桌面端和移动端适配
+- **现代化UI**:使用 Lucide React 图标库,提供清晰美观的界面
+
+### 📤 上传功能
+- **双模式上传**:支持图片上传和视频上传两种模式
+- **拖拽上传**:支持文件拖拽到上传区域
+- **点击上传**:点击按钮选择文件上传
+- **文件验证**:
+  - 图片:支持 JPEG、JPG、PNG、WebP 格式,最大 32MB
+  - 视频:支持 MP4、MOV、AVI 格式,最大 2GB
+- **实时进度显示**:带有动画效果的上传进度条
+
+### 🖼️ 文件管理
+- **文件预览**:上传后实时显示文件缩略图
+- **文件信息**:显示文件名、大小等详细信息
+- **批量管理**:支持单个删除和批量清除
+- **文件计数**:实时显示已上传文件数量
+
+### 🎯 交互体验
+- **拖拽反馈**:拖拽时提供视觉反馈效果
+- **加载状态**:上传过程中的加载动画
+- **操作提示**:完成上传后的成功提示
+- **悬停效果**:按钮和文件项的悬停交互
+
+### 🗂️ 导航系统
+- **侧边栏导航**:完整的功能菜单
+- **可展开子菜单**:数据看板等功能的子选项
+- **活跃状态**:当前选中页面的高亮显示
+- **固定布局**:头部和侧边栏固定定位
+
+## 技术栈 🛠️
+
+- **前端框架**:React 19.1.0
+- **构建工具**:Vite 6.0.5
+- **图标库**:Lucide React 0.468.0
+- **样式**:纯 CSS(无预处理器)
+- **开发语言**:JavaScript + JSX
+
+## 安装运行 🚀
+
+1. **安装依赖**
+   ```bash
+   npm install
+   ```
+
+2. **启动开发服务器**
+   ```bash
+   npm run dev
+   ```
+
+3. **打开浏览器**
+   ```
+   http://localhost:5173
+   ```
+
+4. **构建生产版本**
+   ```bash
+   npm run build
+   ```
+
+## 项目结构 📁
+
+```
+发布页面/
+├── public/              # 静态资源
+│   └── vite.svg        # Vite 图标
+├── src/
+│   ├── App.jsx         # 主应用组件
+│   ├── App.css         # 主样式文件
+│   ├── index.css       # 全局样式
+│   └── main.jsx        # 应用入口
+├── index.html          # HTML 入口文件
+├── package.json        # 项目配置
+├── vite.config.js      # Vite 配置
+└── README.md          # 项目说明
+```
+
+## 核心功能实现 💡
+
+### 文件上传处理
+```javascript
+const handleFileUpload = () => {
+  const input = document.createElement('input')
+  input.type = 'file'
+  input.accept = activeTab === 'video' ? 'video/*' : 'image/*'
+  input.multiple = activeTab === 'image'
+  
+  input.onchange = (e) => {
+    const files = Array.from(e.target.files)
+    if (files.length > 0 && validateFiles(files)) {
+      simulateUpload(files)
+    }
+  }
+  
+  input.click()
+}
+```
+
+### 拖拽上传实现
+```javascript
+const handleDrop = (e) => {
+  e.preventDefault()
+  e.stopPropagation()
+  setIsDragOver(false)
+  
+  const files = Array.from(e.dataTransfer.files)
+  if (files.length > 0 && validateFiles(files)) {
+    simulateUpload(files)
+  }
+}
+```
+
+### 文件验证机制
+```javascript
+const validateFiles = (files) => {
+  const validImageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
+  const validVideoTypes = ['video/mp4', 'video/mov', 'video/avi']
+  
+  const validTypes = activeTab === 'video' ? validVideoTypes : validImageTypes
+  const maxSize = activeTab === 'video' ? 2 * 1024 * 1024 * 1024 : 32 * 1024 * 1024
+  
+  return files.every(file => 
+    validTypes.includes(file.type) && file.size <= maxSize
+  )
+}
+```
+
+## 样式特色 🎨
+
+### 响应式设计
+- 桌面端:固定侧边栏布局
+- 移动端:隐藏侧边栏,堆叠布局
+- 自适应文件网格:根据屏幕大小调整列数
+
+### 动画效果
+- 拖拽时的放大效果
+- 进度条的流光动画
+- 文件项的悬停过渡
+- 页面切换的淡入效果
+
+### 色彩方案
+- 主色调:#ff4757(小红书红)
+- 背景色:#f5f7fa(浅灰蓝)
+- 文字色:#333(深灰)
+- 边框色:#e8eaed(浅灰)
+
+## 待扩展功能 🔮
+
+- **后端集成**:连接真实的文件上传 API
+- **用户认证**:登录注册功能
+- **内容编辑**:笔记内容编辑器
+- **数据统计**:真实的数据看板功能
+- **社交功能**:评论、点赞等互动功能
+
+## 开发说明 📝
+
+这个项目完全基于前端实现,所有的上传功能都是模拟的。文件预览使用了 `URL.createObjectURL()` 来生成本地预览链接。在实际部署时,需要:
+
+1. 集成后端文件上传 API
+2. 实现用户认证系统
+3. 添加数据持久化
+4. 优化性能和安全性
+
+## 浏览器兼容性 🌐
+
+- Chrome 90+
+- Firefox 88+
+- Safari 14+
+- Edge 90+
+
+## 许可证 📄
+
+MIT License
+
+---
+
+**注意**:本项目仅用于学习和演示目的,请遵守相关法律法规和平台使用条款。
diff --git a/API/API-TRM/WZY/xhs_front/index.html b/API/API-TRM/WZY/xhs_front/index.html
new file mode 100644
index 0000000..b919940
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/index.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>小红书创作服务平台</title>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="/src/main.jsx"></script>
+  </body>
+</html>
diff --git a/API/API-TRM/WZY/xhs_front/package.json b/API/API-TRM/WZY/xhs_front/package.json
new file mode 100644
index 0000000..b1d8b25
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "xiaohongshu-creator-platform",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "lucide-react": "^0.468.0",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
+    "react-router-dom": "^7.6.2"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-react": "^4.3.4",
+    "vite": "^6.0.5"
+  }
+}
diff --git a/API/API-TRM/WZY/xhs_front/public/vite.svg b/API/API-TRM/WZY/xhs_front/public/vite.svg
new file mode 100644
index 0000000..ee9fada
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/public/vite.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
diff --git a/API/API-TRM/WZY/xhs_front/src/App.css b/API/API-TRM/WZY/xhs_front/src/App.css
new file mode 100644
index 0000000..8fdd8d7
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/App.css
@@ -0,0 +1,585 @@
+.app {
+  display: flex;
+  min-height: 100vh;
+  background-color: #f5f7fa;
+}
+
+/* Header */
+.header {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 60px;
+  background: #fff;
+  border-bottom: 1px solid #e8eaed;
+  display: flex;
+  align-items: center;
+  padding: 0 20px;
+  z-index: 1000;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.header-left {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.logo {
+  background: #ff4757;
+  color: white;
+  padding: 6px 12px;
+  border-radius: 6px;
+  font-size: 14px;
+  font-weight: bold;
+}
+
+.header-title {
+  font-size: 18px;
+  font-weight: 500;
+  color: #333;
+}
+
+.header-right {
+  margin-left: auto;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.user-info {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  color: #666;
+  font-size: 14px;
+}
+
+/* Sidebar */
+.sidebar {
+  position: fixed;
+  left: 0;
+  top: 60px;
+  width: 200px;
+  height: calc(100vh - 60px);
+  background: #fff;
+  border-right: 1px solid #e8eaed;
+  overflow-y: auto;
+  z-index: 999;
+}
+
+.publish-btn {
+  margin: 16px;
+  background: #ff4757;
+  color: white;
+  padding: 10px 16px;
+  border-radius: 6px;
+  font-size: 14px;
+  font-weight: 500;
+  text-align: center;
+  transition: background 0.2s;
+}
+
+.publish-btn:hover {
+  background: #ff3742;
+}
+
+.nav-menu {
+  padding: 0;
+  list-style: none;
+}
+
+.nav-item {
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.nav-link {
+  display: flex;
+  align-items: center;
+  padding: 12px 20px;
+  color: #333;
+  font-size: 14px;
+  transition: all 0.2s;
+  gap: 8px;
+}
+
+.nav-link:hover {
+  background: #f8f9fa;
+  color: #ff4757;
+}
+
+.nav-link.active {
+  background: linear-gradient(135deg, #ff4757, #ff6b7a);
+  color: white;
+  font-weight: 500;
+}
+
+.nav-link.active .lucide {
+  color: white;
+}
+
+.nav-submenu {
+  padding-left: 20px;
+  background: #fafafa;
+}
+
+.nav-submenu .nav-link {
+  padding: 8px 20px;
+  font-size: 13px;
+  color: #666;
+}
+
+.nav-submenu .nav-link:hover {
+  color: #ff4757;
+}
+
+/* Main Content */
+.main-content {
+  margin-left: 200px;
+  padding-top: 60px;
+  flex: 1;
+  min-height: 100vh;
+}
+
+.content-wrapper {
+  padding: 20px;
+  /* 原来是 max-width:1200px; */
+  max-width: none;      /* 或者直接注释掉这一行 */
+  width: auto;          /* 确保它能撑满父级 */
+  margin: 0;            /* 取消水平 auto 居中 */
+}
+
+/* Upload Area */
+.upload-tabs {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 30px;
+  border-bottom: 1px solid #e8eaed;
+}
+
+.upload-tab {
+  padding: 12px 0;
+  font-size: 16px;
+  color: #666;
+  cursor: pointer;
+  border-bottom: 2px solid transparent;
+  transition: all 0.2s;
+}
+
+.upload-tab.active {
+  color: #ff4757;
+  border-bottom-color: #ff4757;
+  font-weight: 500;
+}
+
+.upload-area {
+  background: #fff;
+  border-radius: 8px;
+  padding: 80px 40px;
+  text-align: center;
+  border: 2px dashed #ddd;
+  margin-bottom: 40px;
+  transition: all 0.2s;
+  min-height: 300px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  position: relative;
+}
+
+.upload-area:hover {
+  border-color: #ff4757;
+  background: #fff8f8;
+}
+
+.upload-area.drag-over {
+  border-color: #ff4757;
+  background: #fff0f0;
+  transform: scale(1.02);
+}
+
+.upload-icon {
+  width: 100px;
+  height: 100px;
+  margin: 0 auto 30px;
+  background: #f8f9fa;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 40px;
+  color: #ccc;
+  transition: all 0.3s ease;
+}
+
+.upload-area:hover .upload-icon {
+  background: #ff475710;
+  color: #ff4757;
+  transform: scale(1.1);
+}
+
+.upload-area.drag-over .upload-icon {
+  background: #ff475720;
+  color: #ff4757;
+  transform: scale(1.2);
+}
+
+.upload-title {
+  font-size: 20px;
+  color: #333;
+  margin-bottom: 12px;
+  font-weight: 500;
+}
+
+.upload-subtitle {
+  font-size: 14px;
+  color: #999;
+  margin-bottom: 30px;
+}
+
+.upload-btn {
+  background: #ff4757;
+  color: white;
+  padding: 14px 28px;
+  border-radius: 6px;
+  font-size: 16px;
+  font-weight: 500;
+  transition: background 0.2s;
+  min-width: 120px;
+}
+
+.upload-btn:hover:not(:disabled) {
+  background: #ff3742;
+}
+
+.upload-btn:disabled {
+  background: #ccc;
+  cursor: not-allowed;
+}
+
+.upload-btn.uploading {
+  background: #ff4757;
+  opacity: 0.8;
+}
+
+/* File Preview */
+.file-preview-area {
+  background: #fff;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 40px;
+  border: 1px solid #e8eaed;
+}
+
+/* Preview Header */
+.preview-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 16px;
+}
+
+.preview-title {
+  font-size: 16px;
+  color: #333;
+  margin-bottom: 16px;
+  font-weight: 500;
+}
+
+.clear-files-btn {
+  background: #ff4757;
+  color: white;
+  padding: 6px 12px;
+  border-radius: 4px;
+  font-size: 12px;
+  transition: background 0.2s;
+}
+
+.clear-files-btn:hover {
+  background: #ff3742;
+}
+
+.file-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+  gap: 16px;
+}
+
+.file-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 12px;
+  border: 1px solid #f0f0f0;
+  border-radius: 6px;
+  transition: all 0.2s ease;
+  position: relative;
+}
+
+.file-item:hover {
+  border-color: #ff4757;
+  box-shadow: 0 2px 8px rgba(255, 71, 87, 0.1);
+}
+
+.file-item:hover .remove-file-btn {
+  opacity: 1;
+}
+
+.remove-file-btn {
+  position: absolute;
+  top: 4px;
+  right: 4px;
+  background: rgba(255, 71, 87, 0.8);
+  color: white;
+  border-radius: 50%;
+  width: 20px;
+  height: 20px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 14px;
+  font-weight: bold;
+  opacity: 0;
+  transition: all 0.2s;
+}
+
+.file-thumbnail {
+  width: 80px;
+  height: 80px;
+  border-radius: 6px;
+  overflow: hidden;
+  margin-bottom: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #f8f9fa;
+}
+
+.file-thumbnail img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.video-thumbnail {
+  color: #666;
+}
+
+.file-info {
+  text-align: center;
+  width: 100%;
+}
+
+.file-name {
+  font-size: 12px;
+  color: #333;
+  margin-bottom: 4px;
+  font-weight: 500;
+}
+
+.file-size {
+  font-size: 11px;
+  color: #999;
+}
+
+/* Upload Progress */
+.progress-container {
+  margin-top: 20px;
+  width: 100%;
+  max-width: 400px;
+}
+
+.progress-bar {
+  width: 100%;
+  height: 8px;
+  background-color: #f0f0f0;
+  border-radius: 4px;
+  overflow: hidden;
+  margin-bottom: 8px;
+}
+
+.progress-fill {
+  height: 100%;
+  background: linear-gradient(90deg, #ff4757, #ff6b7a);
+  border-radius: 4px;
+  transition: width 0.3s ease;
+  position: relative;
+}
+
+.progress-fill::after {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
+  animation: shimmer 1.5s infinite;
+}
+
+@keyframes shimmer {
+  0% { transform: translateX(-100%); }
+  100% { transform: translateX(100%); }
+}
+
+.progress-text {
+  text-align: center;
+  font-size: 12px;
+  color: #666;
+  font-weight: 500;
+}
+
+/* Upload Info */
+.upload-info {
+  display: flex;
+  gap: 60px;
+  justify-content: center;
+  margin-top: 40px;
+  padding: 20px;
+  opacity: 1;
+  transition: opacity 0.3s ease;
+}
+
+.upload-info.fade-in {
+  animation: fadeIn 0.3s ease-in-out;
+}
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(10px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.info-item {
+  text-align: center;
+  flex: 1;
+  max-width: 300px;
+}
+
+.info-title {
+  font-size: 16px;
+  color: #333;
+  margin-bottom: 12px;
+  font-weight: 500;
+}
+
+.info-desc {
+  font-size: 13px;
+  color: #666;
+  line-height: 1.6;
+}
+
+/* Page Content Styles */
+.page-content {
+  padding: 40px;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  margin: 20px 0;
+  min-height: 500px;
+}
+
+.page-header {
+  margin-bottom: 40px;
+  padding-bottom: 20px;
+  border-bottom: 1px solid #e8eaed;
+}
+
+.page-title {
+  font-size: 24px;
+  font-weight: 600;
+  color: #333;
+  margin: 0;
+}
+
+.page-body {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-height: 400px;
+}
+
+.placeholder-content {
+  text-align: center;
+  max-width: 400px;
+}
+
+.placeholder-icon {
+  color: #ff4757;
+  margin-bottom: 20px;
+  display: flex;
+  justify-content: center;
+}
+
+.placeholder-title {
+  font-size: 20px;
+  font-weight: 500;
+  color: #333;
+  margin: 0 0 15px 0;
+}
+
+.placeholder-desc {
+  font-size: 14px;
+  color: #666;
+  line-height: 1.6;
+  margin: 0;
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+  .sidebar {
+    transform: translateX(-100%);
+    transition: transform 0.3s;
+  }
+  
+  .main-content {
+    margin-left: 0;
+  }
+  
+  .header-title {
+    display: none;
+  }
+  
+  .upload-area {
+    padding: 60px 20px;
+    margin: 0 10px 30px;
+  }
+  
+  .upload-info {
+    flex-direction: column;
+    gap: 30px;
+    padding: 10px;
+  }
+  
+  .content-wrapper {
+    padding: 15px;
+  }
+  
+  .upload-tabs {
+    gap: 15px;
+  }
+  
+  .page-content {
+    padding: 20px;
+    margin: 10px;
+  }
+  
+  .page-title {
+    font-size: 20px;
+  }
+  
+  .placeholder-title {
+    font-size: 18px;
+  }
+  
+  .placeholder-desc {
+    font-size: 13px;
+  }
+}
diff --git a/API/API-TRM/WZY/xhs_front/src/App.jsx b/API/API-TRM/WZY/xhs_front/src/App.jsx
new file mode 100644
index 0000000..9a79c5c
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/App.jsx
@@ -0,0 +1,23 @@
+import React from 'react'
+import { BrowserRouter as Router } from 'react-router-dom'
+import Header from './components/Header'
+import Sidebar from './components/Sidebar'
+import AppRouter from './router'
+
+import './App.css'
+
+export default function App() {
+  return (
+    <Router>
+      <div className="app">
+        <Header />
+        <Sidebar />
+        <main className="main-content">
+          <div className="content-wrapper">
+            <AppRouter />
+          </div>
+        </main>
+      </div>
+    </Router>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/components/Header.jsx b/API/API-TRM/WZY/xhs_front/src/components/Header.jsx
new file mode 100644
index 0000000..60a50b7
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/components/Header.jsx
@@ -0,0 +1,20 @@
+import React from 'react'
+import { User } from 'lucide-react'
+import '../App.css' // 或者单独的 Header.css
+
+export default function Header() {
+  return (
+    <header className="header">
+      <div className="header-left">
+        <div className="logo">小红书</div>
+        <h1 className="header-title">创作服务平台</h1>
+      </div>
+      <div className="header-right">
+        <div className="user-info">
+          <User size={16} />
+          <span>小红薯63081EA1</span>
+        </div>
+      </div>
+    </header>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/components/HomeFeed.jsx b/API/API-TRM/WZY/xhs_front/src/components/HomeFeed.jsx
new file mode 100644
index 0000000..a7f70b5
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/components/HomeFeed.jsx
@@ -0,0 +1,72 @@
+import React, { useState } from 'react'
+import { ThumbsUp } from 'lucide-react'
+import '../style/HomeFeed.css'
+
+const mockItems = Array.from({ length: 20 }).map((_, i) => ({
+  id: i,
+  title: `示例标题 ${i + 1}`,
+  author: `作者 ${i + 1}`,
+  avatar: `https://i.pravatar.cc/40?img=${i + 1}`,
+  img: `https://picsum.photos/seed/${i}/300/200`,
+  likes: Math.floor(Math.random() * 1000)
+}))
+
+const categories = [
+  '推荐','穿搭','美食','彩妆','影视',
+  '职场','情感','家居','游戏','旅行','健身'
+]
+
+export default function HomeFeed() {
+  const [activeCat, setActiveCat] = useState('推荐')
+  const items = mockItems.filter(() => true) // 可按 activeCat 过滤
+
+  return (
+    <div className="home-feed">
+      {/* 顶部分类 */}
+      <nav className="feed-tabs">
+        {categories.map(cat => (
+          <button
+            key={cat}
+            className={cat === activeCat ? 'tab active' : 'tab'}
+            onClick={() => setActiveCat(cat)}
+          >
+            {cat}
+          </button>
+        ))}
+      </nav>
+
+      {/* 瀑布流卡片区 */}
+      <div className="feed-grid">
+        {items.map(item => (
+          <div key={item.id} className="feed-card">
+            {/* 封面图 */}
+            <img
+              className="card-img"
+              src={item.img}
+              alt={item.title}
+            />
+
+            {/* 标题 */}
+            <h3 className="card-title">{item.title}</h3>
+
+            {/* 底部作者 + 点赞 */}
+            <div className="card-footer">
+              <div className="card-author">
+                <img
+                  className="avatar"
+                  src={item.avatar}
+                  alt={item.author}
+                />
+                <span className="username">{item.author}</span>
+              </div>
+              <div className="card-likes">
+                <ThumbsUp size={16} />
+                <span className="likes-count">{item.likes}</span>
+              </div>
+            </div>
+          </div>
+        ))}
+      </div>
+    </div>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/components/PlaceholderPage.jsx b/API/API-TRM/WZY/xhs_front/src/components/PlaceholderPage.jsx
new file mode 100644
index 0000000..b290eb4
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/components/PlaceholderPage.jsx
@@ -0,0 +1,55 @@
+import React from 'react'
+import {
+  Home,
+  BookOpen,
+  Activity,
+  Users
+} from 'lucide-react'
+import '../App.css' // 或 PlaceholderPage.css
+
+const icons = {
+  home: Home,
+  notebooks: BookOpen,
+  activity: Activity,
+  notes: BookOpen,
+  creator: Users,
+  journal: BookOpen,
+}
+
+const titles = {
+  home:      '欢迎来到小红书创作平台',
+  notebooks: '笔记管理功能开发中',
+  activity:  '活动中心功能开发中',
+  notes:     '笔记灵感功能开发中',
+  creator:   '创作学院功能开发中',
+  journal:   '创作日刊功能开发中',
+}
+
+const descs = {
+  home:      '在这里您可以管理您的创作内容,查看数据分析,获取创作灵感。',
+  notebooks: '这里将显示您的所有笔记,支持编辑、删除、分类等操作。',
+  activity:  '这里将展示最新的平台活动,让您参与更多有趣的创作活动。',
+  notes:     '这里将为您提供创作灵感和写作建议,帮助您创作更好的内容。',
+  creator:   '这里将提供创作技巧教学和平台规则说明,助您成为优秀创作者。',
+  journal:   '这里将展示创作相关的最新资讯和平台动态。',
+}
+
+export default function PlaceholderPage({ pageId }) {
+  const Icon = icons[pageId] || Home
+  return (
+    <div className="page-content">
+      <div className="page-header">
+        <h1 className="page-title">{titles[pageId]}</h1>
+      </div>
+      <div className="page-body">
+        <div className="placeholder-content">
+          <div className="placeholder-icon">
+            <Icon size={48} />
+          </div>
+          <h3 className="placeholder-title">{titles[pageId]}</h3>
+          <p className="placeholder-desc">{descs[pageId]}</p>
+        </div>
+      </div>
+    </div>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/components/Sidebar.jsx b/API/API-TRM/WZY/xhs_front/src/components/Sidebar.jsx
new file mode 100644
index 0000000..b6acad5
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/components/Sidebar.jsx
@@ -0,0 +1,95 @@
+import React, { useState, useEffect } from 'react'
+import { NavLink, useLocation, useNavigate } from 'react-router-dom'
+import {
+  Home,
+  BookOpen,
+  BarChart3,
+  Activity,
+  Users,
+  ChevronDown,
+} from 'lucide-react'
+
+
+const menuItems = [
+  { id: 'home',      label: '首页',       icon: Home,      path: '/home' },
+  { id: 'notebooks', label: '笔记管理',   icon: BookOpen,  path: '/notebooks' },
+  {
+    id: 'dashboard',
+    label: '数据看板',
+    icon: BarChart3,
+    path: '/dashboard',
+    submenu: [
+      { id: 'overview', label: '账号概况', path: '/dashboard/overview' },
+      { id: 'content',  label: '内容分析', path: '/dashboard/content'  },
+      { id: 'fans',     label: '粉丝数据', path: '/dashboard/fans'     },
+    ]
+  },
+  { id: 'activity', label: '活动中心', icon: Activity, path: '/activity' },
+  { id: 'notes',    label: '笔记灵感', icon: BookOpen, path: '/notes'    },
+  { id: 'creator',  label: '创作学院', icon: Users,    path: '/creator'  },
+  { id: 'journal',  label: '创作日刊', icon: BookOpen, path: '/journal'  },
+]
+
+export default function Sidebar() {
+  const [expandedMenu, setExpandedMenu] = useState(null)
+  const location = useLocation()
+  const navigate = useNavigate()
+
+  useEffect(() => {
+    if (location.pathname.startsWith('/dashboard')) {
+      setExpandedMenu('dashboard')
+    }
+  }, [location.pathname])
+
+  const toggleMenu = item => {
+    if (item.submenu) {
+      setExpandedMenu(expandedMenu === item.id ? null : item.id)
+    } else {
+      navigate(item.path)
+      setExpandedMenu(null)
+    }
+  }
+
+  return (
+    <aside className="sidebar">
+      <button className="publish-btn">发布笔记</button>
+      <nav className="nav-menu">
+        {menuItems.map(item => (
+          <div key={item.id} className="nav-item">
+            <a
+              href="#"
+              className={`nav-link${location.pathname === item.path ? ' active' : ''}`}
+              onClick={e => { e.preventDefault(); toggleMenu(item) }}
+            >
+              <item.icon size={16} />
+              <span>{item.label}</span>
+              {item.submenu && (
+                <ChevronDown
+                  size={16}
+                  style={{
+                    marginLeft: 'auto',
+                    transform: expandedMenu === item.id ? 'rotate(180deg)' : 'rotate(0deg)',
+                    transition: 'transform 0.3s ease'
+                  }}
+                />
+              )}
+            </a>
+            {item.submenu && expandedMenu === item.id && (
+              <div className="nav-submenu">
+                {item.submenu.map(sub => (
+                  <NavLink
+                    key={sub.id}
+                    to={sub.path}
+                    className={({ isActive }) => `nav-link${isActive ? ' active' : ''}`}
+                  >
+                    {sub.label}
+                  </NavLink>
+                ))}
+              </div>
+            )}
+          </div>
+        ))}
+      </nav>
+    </aside>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/components/UploadPage.jsx b/API/API-TRM/WZY/xhs_front/src/components/UploadPage.jsx
new file mode 100644
index 0000000..e6db861
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/components/UploadPage.jsx
@@ -0,0 +1,200 @@
+import React, { useState } from 'react'
+import { Image, Video } from 'lucide-react'
+
+
+export default function UploadPage() {
+  const [activeTab, setActiveTab]         = useState('image')
+  const [isDragOver, setIsDragOver]       = useState(false)
+  const [isUploading, setIsUploading]     = useState(false)
+  const [uploadedFiles, setUploadedFiles] = useState([])
+  const [uploadProgress, setUploadProgress] = useState(0)
+
+  const validateFiles = files => {
+    const imgTypes = ['image/jpeg','image/jpg','image/png','image/webp']
+    const vidTypes = ['video/mp4','video/mov','video/avi']
+    const types = activeTab==='video'? vidTypes : imgTypes
+    const max   = activeTab==='video'? 2*1024*1024*1024 : 32*1024*1024
+
+    const invalid = files.filter(f => !types.includes(f.type) || f.size > max)
+    if (invalid.length) {
+      alert(`发现 ${invalid.length} 个无效文件,请检查文件格式和大小`)
+      return false
+    }
+    return true
+  }
+
+  const simulateUpload = files => {
+    setIsUploading(true)
+    setUploadProgress(0)
+    setUploadedFiles(files)
+    const iv = setInterval(() => {
+      setUploadProgress(p => {
+        if (p >= 100) {
+          clearInterval(iv)
+          setIsUploading(false)
+          alert(`成功上传了 ${files.length} 个文件`)
+          return 100
+        }
+        return p + 10
+      })
+    }, 200)
+  }
+
+  const handleFileUpload = () => {
+    if (isUploading) return
+    const input = document.createElement('input')
+    input.type = 'file'
+    input.accept = activeTab==='video'? 'video/*' : 'image/*'
+    input.multiple = activeTab==='image'
+    input.onchange = e => {
+      const files = Array.from(e.target.files)
+      if (files.length > 0 && validateFiles(files)) simulateUpload(files)
+    }
+    input.click()
+  }
+
+  const handleDragOver  = e => { e.preventDefault(); e.stopPropagation(); setIsDragOver(true) }
+  const handleDragLeave = e => { e.preventDefault(); e.stopPropagation(); setIsDragOver(false) }
+  const handleDrop      = e => {
+    e.preventDefault(); e.stopPropagation(); setIsDragOver(false)
+    if (isUploading) return
+    const files = Array.from(e.dataTransfer.files)
+    if (files.length > 0 && validateFiles(files)) simulateUpload(files)
+  }
+
+  const clearFiles = () => setUploadedFiles([])
+  const removeFile = idx => setUploadedFiles(f => f.filter((_,i) => i!==idx))
+
+  return (
+    <>
+      <div className="upload-tabs">
+        <button
+          className={`upload-tab${activeTab==='video'?' active':''}`}
+          onClick={() => setActiveTab('video')}
+        >上传视频</button>
+        <button
+          className={`upload-tab${activeTab==='image'?' active':''}`}
+          onClick={() => setActiveTab('image')}
+        >上传图文</button>
+      </div>
+
+      <div
+        className={`upload-area${isDragOver?' drag-over':''}`}
+        onDragOver={handleDragOver}
+        onDragLeave={handleDragLeave}
+        onDrop={handleDrop}
+      >
+        <div className="upload-icon">
+          {activeTab==='video'? <Video/> : <Image/>}
+        </div>
+        <h2 className="upload-title">
+          {activeTab==='video'
+            ? '拖拽视频到此处或点击上传'
+            : '拖拽图片到此处或点击上传'
+          }
+        </h2>
+        <p className="upload-subtitle">(需支持上传格式)</p>
+        <button
+          className={`upload-btn${isUploading?' uploading':''}`}
+          onClick={handleFileUpload}
+          disabled={isUploading}
+        >
+          {isUploading
+            ? `上传中... ${uploadProgress}%`
+            : activeTab==='video'
+              ? '上传视频'
+              : '上传图片'
+          }
+        </button>
+
+        {isUploading && (
+          <div className="progress-container">
+            <div className="progress-bar">
+              <div
+                className="progress-fill"
+                style={{ width: `${uploadProgress}%` }}
+              />
+            </div>
+            <div className="progress-text">{uploadProgress}%</div>
+          </div>
+        )}
+      </div>
+
+      {uploadedFiles.length > 0 && (
+        <div className="file-preview-area">
+          <div className="preview-header">
+            <h3 className="preview-title">已上传文件 ({uploadedFiles.length})</h3>
+            <button className="clear-files-btn" onClick={clearFiles}>
+              清除所有
+            </button>
+          </div>
+          <div className="file-grid">
+            {uploadedFiles.map((file, i) => (
+              <div key={i} className="file-item">
+                <button
+                  className="remove-file-btn"
+                  onClick={() => removeFile(i)}
+                  title="删除文件"
+                >×</button>
+                {file.type.startsWith('image/') ? (
+                  <div className="file-thumbnail">
+                    <img src={URL.createObjectURL(file)} alt={file.name} />
+                  </div>
+                ) : (
+                  <div className="file-thumbnail video-thumbnail">
+                    <Video size={24} />
+                  </div>
+                )}
+                <div className="file-info">
+                  <div className="file-name" title={file.name}>
+                    {file.name.length > 20
+                      ? file.name.slice(0,17) + '...'
+                      : file.name
+                    }
+                  </div>
+                  <div className="file-size">
+                    {(file.size/1024/1024).toFixed(2)} MB
+                  </div>
+                </div>
+              </div>
+            ))}
+          </div>
+        </div>
+      )}
+
+      <div className="upload-info fade-in">
+        {activeTab==='image' ? (
+          <>
+            <div className="info-item">
+              <h3 className="info-title">图片大小</h3>
+              <p className="info-desc">最大32MB</p>
+            </div>
+            <div className="info-item">
+              <h3 className="info-title">图片格式</h3>
+              <p className="info-desc">png/jpg/jpeg/webp</p>
+            </div>
+            <div className="info-item">
+              <h3 className="info-title">分辨率</h3>
+              <p className="info-desc">建议720×960及以上</p>
+            </div>
+          </>
+        ) : (
+          <>
+            <div className="info-item">
+              <h3 className="info-title">视频大小</h3>
+              <p className="info-desc">最大2GB,时长≤5分钟</p>
+            </div>
+            <div className="info-item">
+              <h3 className="info-title">视频格式</h3>
+              <p className="info-desc">mp4/mov</p>
+            </div>
+            <div className="info-item">
+              <h3 className="info-title">分辨率</h3>
+              <p className="info-desc">建议720P及以上</p>
+            </div>
+          </>
+        )}
+      </div>
+    </>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/index.css b/API/API-TRM/WZY/xhs_front/src/index.css
new file mode 100644
index 0000000..72c144a
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/index.css
@@ -0,0 +1,29 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+body {
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  background-color: #f5f7fa;
+}
+
+button {
+  border: none;
+  background: none;
+  cursor: pointer;
+  font-family: inherit;
+}
+
+a {
+  text-decoration: none;
+  color: inherit;
+}
+
+#root {
+  width: 100%;
+  min-height: 100vh;
+}
diff --git a/API/API-TRM/WZY/xhs_front/src/main.jsx b/API/API-TRM/WZY/xhs_front/src/main.jsx
new file mode 100644
index 0000000..b9a1a6d
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/main.jsx
@@ -0,0 +1,10 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import './index.css'
+import App from './App.jsx'
+
+createRoot(document.getElementById('root')).render(
+  <StrictMode>
+    <App />
+  </StrictMode>,
+)
diff --git a/API/API-TRM/WZY/xhs_front/src/router/index.jsx b/API/API-TRM/WZY/xhs_front/src/router/index.jsx
new file mode 100644
index 0000000..64191ac
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/router/index.jsx
@@ -0,0 +1,24 @@
+import React from 'react'
+import { Routes, Route, Navigate } from 'react-router-dom'
+import UploadPage from '../components/UploadPage'
+import PlaceholderPage from '../components/PlaceholderPage'
+import HomeFeed from '../components/HomeFeed'
+
+export default function AppRouter() {
+  return (
+    <Routes>
+      <Route path="/" element={<Navigate to="/dashboard" replace />} />
+
+      <Route path="/home"      element={<HomeFeed />} />
+      <Route path="/notebooks" element={<PlaceholderPage pageId="notebooks" />} />
+      <Route path="/activity"  element={<PlaceholderPage pageId="activity" />} />
+      <Route path="/notes"     element={<PlaceholderPage pageId="notes" />} />
+      <Route path="/creator"   element={<PlaceholderPage pageId="creator" />} />
+      <Route path="/journal"   element={<PlaceholderPage pageId="journal" />} />
+
+      <Route path="/dashboard/*" element={<UploadPage />} />
+
+      <Route path="*" element={<PlaceholderPage pageId="home" />} />
+    </Routes>
+  )
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/src/style/HomeFeed.css b/API/API-TRM/WZY/xhs_front/src/style/HomeFeed.css
new file mode 100644
index 0000000..f1bf75d
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/src/style/HomeFeed.css
@@ -0,0 +1,116 @@
+/* --------- 容器 & Tabs --------- */
+.home-feed {
+  padding: 20px;
+}
+
+.feed-tabs {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  margin-bottom: 20px;
+}
+
+.feed-tabs .tab {
+  padding: 6px 12px;
+  border: none;
+  background: #f0f0f0;
+  border-radius: 16px;
+  cursor: pointer;
+  transition: background 0.2s;
+}
+
+.feed-tabs .tab.active {
+  background: #ff4757;
+  color: #fff;
+}
+
+/* --------- 瀑布流布局 --------- */
+.feed-grid {
+  display: grid;
+  grid-gap: 16px;
+  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
+}
+
+/* --------- 卡片样式及最大高度限制 --------- */
+.feed-card {
+  display: flex;
+  flex-direction: column;
+  max-height: 360px;      /* 卡片最大高度 */
+  overflow: hidden;       /* 超出部分隐藏 */
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.1);
+  transition: transform 0.2s;
+}
+
+.feed-card:hover {
+  transform: translateY(-4px);
+}
+
+/* 封面图固定高度 */
+.card-img {
+  width: 100%;
+  height: 180px;         /* 固定图片区域高度 */
+  object-fit: cover;
+  flex-shrink: 0;        /* 不随容器收缩 */
+}
+
+/* 标题填充剩余空间 */
+.card-title {
+  font-size: 14px;
+  color: #333;
+  margin: 12px;
+  line-height: 1.4;
+  flex: 1;               /* 占满中间区域 */
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2; /* 最多两行 */
+  -webkit-box-orient: vertical;
+}
+
+/* --------- 底部:作者 + 点赞 --------- */
+.card-footer {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 12px;
+  border-top: 1px solid #f0f0f0;
+  background: #fff;
+  flex-shrink: 0;        /* 保持在底部 */
+}
+
+/* 作者区域 */
+.card-author {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.card-author .avatar {
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  object-fit: cover;
+}
+
+.card-author .username {
+  font-size: 13px;
+  color: #333;
+}
+
+/* 点赞区域 */
+.card-likes {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+}
+
+.card-likes svg {
+  color: #ff4757;
+}
+
+.card-likes .likes-count {
+  font-size: 13px;
+  color: #666;
+}
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_front/vite.config.js b/API/API-TRM/WZY/xhs_front/vite.config.js
new file mode 100644
index 0000000..8b0f57b
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_front/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vite.dev/config/
+export default defineConfig({
+  plugins: [react()],
+})
diff --git a/API/API-TRM/WZY/xhs_server/__pycache__/app.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/__pycache__/app.cpython-312.pyc
new file mode 100644
index 0000000..215bc7f
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/__pycache__/app.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/__pycache__/config.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/__pycache__/config.cpython-312.pyc
new file mode 100644
index 0000000..4e1a3be
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/__pycache__/config.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/__pycache__/extensions.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/__pycache__/extensions.cpython-312.pyc
new file mode 100644
index 0000000..27ba8c2
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/__pycache__/extensions.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/all_tables.sql b/API/API-TRM/WZY/xhs_server/all_tables.sql
new file mode 100644
index 0000000..fd5d1e5
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/all_tables.sql
@@ -0,0 +1,182 @@
+/*
+数据库设计说明:
+1.	核心表结构:
+	users:存储用户信息,包含角色管理和账号状态
+	posts:核心内容表,支持多模态内容(图文/视频/文档)
+	behaviors:记录用户互动行为(点赞/收藏/浏览等)
+	comments:评论系统,支持多级回复
+	follows:用户社交关系
+2.	推荐系统支持:
+	posts.heat 字段存储动态计算的热度值
+	behaviors 表记录用户行为用于协同过滤
+	user_tags 表构建用户兴趣画像
+	通过 post_tags 实现内容标签分类
+3.	多模态内容处理:
+	posts.media_urls 使用 JSON 类型存储多个资源 URL
+	posts.type 区分不同类型的内容(图文/视频/文档)
+4.	审核与安全:
+	audits 表记录内容审核历史
+	posts.status 管理内容生命周期状态
+	logs 表记录系统操作和访问日志
+5.	性能优化:
+	为查询频繁字段添加索引(热度/行为类型/时间)
+	使用 JSON 类型存储灵活数据(通知内容/媒体资源)
+	通过 heat 字段预计算支持热门排序
+6.	扩展性设计:
+	用户画像系统通过 user_tags 表实现
+	通知系统支持多种互动类型
+	行为表设计支持未来扩展新行为类型
+*/
+
+DROP DATABASE IF EXISTS redbook;
+
+-- 创建数据库
+CREATE DATABASE IF NOT EXISTS redbook DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
+USE redbook;
+
+-- 用户表
+CREATE TABLE users (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID',
+    username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
+    password VARCHAR(255) NOT NULL COMMENT '加密密码',
+    email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
+    avatar VARCHAR(255) COMMENT '头像URL',
+    role ENUM('user', 'admin') DEFAULT 'user' COMMENT '角色',
+    bio VARCHAR(255) COMMENT '个人简介',
+    status ENUM('active', 'banned', 'muted') DEFAULT 'active' COMMENT '账号状态',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB COMMENT='用户表';
+
+-- 标签表
+CREATE TABLE tags (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '标签ID',
+    name VARCHAR(50) NOT NULL UNIQUE COMMENT '标签名称',
+    description VARCHAR(255) COMMENT '标签描述',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
+) ENGINE=InnoDB COMMENT='内容标签表';
+
+-- 话题/超话表
+CREATE TABLE topics (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '话题ID',
+    name VARCHAR(100) NOT NULL UNIQUE COMMENT '话题名称',
+    description TEXT COMMENT '话题描述',
+    status ENUM('active', 'archived') DEFAULT 'active' COMMENT '状态',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
+) ENGINE=InnoDB COMMENT='话题/超话表';
+
+-- 内容帖子表
+CREATE TABLE posts (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '帖子ID',
+    user_id INT NOT NULL COMMENT '作者ID',
+    topic_id INT COMMENT '所属话题ID',
+    type ENUM('text', 'image', 'video', 'document') DEFAULT 'text' COMMENT '内容类型',
+    title VARCHAR(255) NOT NULL COMMENT '标题',
+    content TEXT NOT NULL COMMENT '正文内容',
+    media_urls JSON COMMENT '媒体资源URL数组',
+    status ENUM('draft', 'pending', 'published', 'deleted', 'rejected') DEFAULT 'draft' COMMENT '状态',
+    heat INT DEFAULT 0 COMMENT '热度值',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+    FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE SET NULL
+) ENGINE=InnoDB COMMENT='内容帖子表';
+
+-- 帖子标签关联表
+CREATE TABLE post_tags (
+    post_id INT NOT NULL COMMENT '帖子ID',
+    tag_id INT NOT NULL COMMENT '标签ID',
+    PRIMARY KEY (post_id, tag_id),
+    FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
+    FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='帖子标签关联表';
+
+-- 用户行为表
+CREATE TABLE behaviors (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '行为ID',
+    user_id INT NOT NULL COMMENT '用户ID',
+    post_id INT NOT NULL COMMENT '帖子ID',
+    type ENUM('like', 'comment', 'favorite', 'view', 'share') NOT NULL COMMENT '行为类型',
+    value INT DEFAULT 1 COMMENT '行为值',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '行为时间',
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+    FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='用户行为记录表';
+
+-- 评论表
+CREATE TABLE comments (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '评论ID',
+    post_id INT NOT NULL COMMENT '帖子ID',
+    user_id INT NOT NULL COMMENT '用户ID',
+    parent_id INT DEFAULT NULL COMMENT '父评论ID',
+    content TEXT NOT NULL COMMENT '评论内容',
+    status ENUM('active', 'deleted') DEFAULT 'active' COMMENT '状态',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+    FOREIGN KEY (parent_id) REFERENCES comments(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='评论表';
+
+-- 用户关注关系表
+CREATE TABLE follows (
+    follower_id INT NOT NULL COMMENT '关注者ID',
+    followee_id INT NOT NULL COMMENT '被关注者ID',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '关注时间',
+    PRIMARY KEY (follower_id, followee_id),
+    FOREIGN KEY (follower_id) REFERENCES users(id) ON DELETE CASCADE,
+    FOREIGN KEY (followee_id) REFERENCES users(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='用户关注关系表';
+
+-- 通知表
+CREATE TABLE notifications (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '通知ID',
+    user_id INT NOT NULL COMMENT '接收用户ID',
+    type ENUM('like', 'comment', 'follow', 'system', 'audit') NOT NULL COMMENT '通知类型',
+    content JSON NOT NULL COMMENT '通知内容',
+    is_read BOOLEAN DEFAULT FALSE COMMENT '是否已读',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='用户通知表';
+
+-- 审核记录表
+CREATE TABLE audits (
+    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '审核ID',
+    post_id INT NOT NULL COMMENT '帖子ID',
+    admin_id INT NOT NULL COMMENT '管理员ID',
+    result ENUM('approved', 'rejected') NOT NULL COMMENT '审核结果',
+    reason VARCHAR(255) COMMENT '审核原因',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '审核时间',
+    FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
+    FOREIGN KEY (admin_id) REFERENCES users(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='内容审核记录表';
+
+-- 日志表
+CREATE TABLE logs (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '日志ID',
+    user_id INT DEFAULT NULL COMMENT '用户ID',
+    type ENUM('access', 'error', 'behavior', 'system') NOT NULL COMMENT '日志类型',
+    content TEXT NOT NULL COMMENT '日志内容',
+    ip VARCHAR(45) COMMENT 'IP地址',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
+) ENGINE=InnoDB COMMENT='系统日志表';
+
+-- 用户兴趣标签表(用户画像)
+CREATE TABLE user_tags (
+    user_id INT NOT NULL COMMENT '用户ID',
+    tag_id INT NOT NULL COMMENT '标签ID',
+    weight FLOAT DEFAULT 1.0 COMMENT '兴趣权重',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (user_id, tag_id),
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+    FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
+) ENGINE=InnoDB COMMENT='用户兴趣标签表';
+
+-- 索引优化
+CREATE INDEX idx_posts_heat ON posts(heat);
+CREATE INDEX idx_behaviors_type ON behaviors(type);
+CREATE INDEX idx_notifications_read ON notifications(is_read);
+CREATE INDEX idx_logs_created ON logs(created_at);
+CREATE INDEX idx_comments_post ON comments(post_id);
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_server/app.py b/API/API-TRM/WZY/xhs_server/app.py
new file mode 100644
index 0000000..226bf18
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/app.py
@@ -0,0 +1,25 @@
+# app.py
+from flask import Flask
+from config     import Config
+from extensions import db, migrate  # ← 改自 extensions
+
+def create_app():
+    app = Flask(__name__)
+    app.config.from_object(Config)
+
+    db.init_app(app)
+    migrate.init_app(app, db)
+
+    # 在工厂函数里再导入、注册蓝图
+    from routes.posts    import posts_bp
+    from routes.comments import comments_bp
+
+    app.register_blueprint(posts_bp,    url_prefix='/posts')
+    app.register_blueprint(comments_bp, url_prefix='/posts/<int:post_id>/comments')
+    return app
+
+app = create_app()
+
+if __name__ == '__main__':
+    # 只有直接用 python app.py 时,这段才会执行
+    app.run(host='0.0.0.0', port=5000, debug=True)
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_server/config.py b/API/API-TRM/WZY/xhs_server/config.py
new file mode 100644
index 0000000..b83aead
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/config.py
@@ -0,0 +1,12 @@
+# config.py
+import os
+
+basedir = os.path.abspath(os.path.dirname(__file__))
+
+class Config:
+    SECRET_KEY = os.environ.get('SECRET_KEY', 'you-will-never-guess')
+    SQLALCHEMY_DATABASE_URI = os.environ.get(
+        'DATABASE_URL',
+        'mysql+pymysql://root:password@localhost/redbook?charset=utf8mb4'
+    )
+    SQLALCHEMY_TRACK_MODIFICATIONS = False
diff --git a/API/API-TRM/WZY/xhs_server/extensions.py b/API/API-TRM/WZY/xhs_server/extensions.py
new file mode 100644
index 0000000..3563787
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/extensions.py
@@ -0,0 +1,6 @@
+# extensions.py(根目录,同级于 app.py)
+from flask_sqlalchemy import SQLAlchemy
+from flask_migrate    import Migrate
+
+db      = SQLAlchemy()
+migrate = Migrate()
diff --git a/API/API-TRM/WZY/xhs_server/manage.py b/API/API-TRM/WZY/xhs_server/manage.py
new file mode 100644
index 0000000..15ab995
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/manage.py
@@ -0,0 +1,12 @@
+# manage.py
+from flask_script import Manager
+from flask_migrate import MigrateCommand
+
+from app import app, db
+
+manager = Manager(app)
+# 添加 db 子命令: migrate, upgrade, downgrade 等
+manager.add_command('db', MigrateCommand)
+
+if __name__ == '__main__':
+    manager.run()
diff --git a/API/API-TRM/WZY/xhs_server/models/__init__.py b/API/API-TRM/WZY/xhs_server/models/__init__.py
new file mode 100644
index 0000000..f7cef7b
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__init__.py
@@ -0,0 +1,12 @@
+# models/__init__.py
+# --------------------------------------------------
+# 绝**对**不要**从** app.py 导入 db!
+# 改成:
+from extensions import db
+
+from .user     import User
+from .topic    import Topic
+from .tag      import Tag
+from .post     import Post, post_tags
+from .behavior import Behavior
+from .comment  import Comment
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/__init__.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..fe53b2a
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/behavior.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/behavior.cpython-312.pyc
new file mode 100644
index 0000000..71f3757
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/behavior.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/comment.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/comment.cpython-312.pyc
new file mode 100644
index 0000000..393c6d3
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/comment.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/post.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/post.cpython-312.pyc
new file mode 100644
index 0000000..1d64737
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/post.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/tag.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/tag.cpython-312.pyc
new file mode 100644
index 0000000..d76c0e0
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/tag.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/topic.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/topic.cpython-312.pyc
new file mode 100644
index 0000000..a779595
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/topic.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/__pycache__/user.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/models/__pycache__/user.cpython-312.pyc
new file mode 100644
index 0000000..e3841c7
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/__pycache__/user.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/models/behavior.py b/API/API-TRM/WZY/xhs_server/models/behavior.py
new file mode 100644
index 0000000..aed413f
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/behavior.py
@@ -0,0 +1,13 @@
+# models/behavior.py
+from extensions import db
+from datetime import datetime
+
+class Behavior(db.Model):
+    __tablename__ = 'behaviors'
+
+    id = db.Column(db.BigInteger, primary_key=True)
+    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
+    post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), nullable=False)
+    type = db.Column(db.Enum('like', 'comment', 'favorite', 'view', 'share'), nullable=False)
+    value = db.Column(db.Integer, default=1, nullable=False)
+    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
diff --git a/API/API-TRM/WZY/xhs_server/models/comment.py b/API/API-TRM/WZY/xhs_server/models/comment.py
new file mode 100644
index 0000000..ce25287
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/comment.py
@@ -0,0 +1,24 @@
+# models/comment.py
+from extensions import db
+from datetime import datetime
+
+class Comment(db.Model):
+    __tablename__ = 'comments'
+
+    id = db.Column(db.Integer, primary_key=True)
+    post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), nullable=False)
+    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
+    parent_id = db.Column(db.Integer, db.ForeignKey('comments.id', ondelete='CASCADE'))
+    content = db.Column(db.Text, nullable=False)
+    status = db.Column(db.Enum('active', 'deleted'), default='active', nullable=False)
+    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
+    updated_at = db.Column(db.DateTime, default=datetime.utcnow,
+                           onupdate=datetime.utcnow, nullable=False)
+
+    # self-referential replies
+    replies = db.relationship(
+        'Comment',
+        backref=db.backref('parent', remote_side=[id]),
+        lazy='dynamic',
+        cascade='all, delete-orphan'
+    )
diff --git a/API/API-TRM/WZY/xhs_server/models/post.py b/API/API-TRM/WZY/xhs_server/models/post.py
new file mode 100644
index 0000000..ab99191
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/post.py
@@ -0,0 +1,32 @@
+# models/post.py
+from extensions import db
+from datetime import datetime
+
+# association table for Post <-> Tag
+post_tags = db.Table(
+    'post_tags',
+    db.Column('post_id', db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), primary_key=True),
+    db.Column('tag_id', db.Integer, db.ForeignKey('tags.id', ondelete='CASCADE'), primary_key=True)
+)
+
+class Post(db.Model):
+    __tablename__ = 'posts'
+
+    id = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
+    topic_id = db.Column(db.Integer, db.ForeignKey('topics.id', ondelete='SET NULL'))
+    type = db.Column(db.Enum('text', 'image', 'video', 'document'), default='text', nullable=False)
+    title = db.Column(db.String(255), nullable=False)
+    content = db.Column(db.Text, nullable=False)
+    media_urls = db.Column(db.JSON)
+    status = db.Column(db.Enum('draft', 'pending', 'published', 'deleted', 'rejected'),
+                       default='draft', nullable=False)
+    heat = db.Column(db.Integer, default=0, nullable=False)
+    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
+    updated_at = db.Column(db.DateTime, default=datetime.utcnow,
+                           onupdate=datetime.utcnow, nullable=False)
+
+    # relationships
+    tags = db.relationship('Tag', secondary=post_tags, backref=db.backref('posts', lazy='dynamic'))
+    behaviors = db.relationship('Behavior', backref='post', lazy='dynamic', cascade='all, delete')
+    comments = db.relationship('Comment', backref='post', lazy='dynamic', cascade='all, delete')
diff --git a/API/API-TRM/WZY/xhs_server/models/tag.py b/API/API-TRM/WZY/xhs_server/models/tag.py
new file mode 100644
index 0000000..7753a38
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/tag.py
@@ -0,0 +1,13 @@
+# models/tag.py
+from extensions import db
+from datetime import datetime
+
+class Tag(db.Model):
+    __tablename__ = 'tags'
+
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String(50), unique=True, nullable=False)
+    description = db.Column(db.String(255))
+    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
+
+    # posts relationship via association table defined in post.py
diff --git a/API/API-TRM/WZY/xhs_server/models/topic.py b/API/API-TRM/WZY/xhs_server/models/topic.py
new file mode 100644
index 0000000..d0e5a2e
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/topic.py
@@ -0,0 +1,14 @@
+# models/topic.py
+from extensions import db
+from datetime import datetime
+
+class Topic(db.Model):
+    __tablename__ = 'topics'
+
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String(100), unique=True, nullable=False)
+    description = db.Column(db.Text)
+    status = db.Column(db.Enum('active', 'archived'), default='active', nullable=False)
+    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
+
+    posts = db.relationship('Post', backref='topic', lazy='dynamic', cascade='all, delete')
diff --git a/API/API-TRM/WZY/xhs_server/models/user.py b/API/API-TRM/WZY/xhs_server/models/user.py
new file mode 100644
index 0000000..f27e7d3
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/models/user.py
@@ -0,0 +1,68 @@
+# models/user.py
+
+from datetime import datetime
+from extensions import db
+
+# 关联表:用户关注关系
+follows = db.Table(
+    'follows',
+    db.Column('follower_id', db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True),
+    db.Column('followee_id', db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True),
+    db.Column('created_at', db.DateTime, default=datetime.utcnow, nullable=False)
+)
+
+class User(db.Model):
+    __tablename__ = 'users'
+
+    id = db.Column(db.Integer, primary_key=True)
+    username = db.Column(db.String(50), unique=True, nullable=False)
+    password = db.Column(db.String(255), nullable=False)
+    email = db.Column(db.String(100), unique=True, nullable=False)
+    avatar = db.Column(db.String(255))
+    role = db.Column(db.Enum('user', 'admin'), default='user', nullable=False)
+    bio = db.Column(db.String(255))
+    status = db.Column(db.Enum('active', 'banned', 'muted'), default='active', nullable=False)
+    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
+    updated_at = db.Column(
+        db.DateTime,
+        default=datetime.utcnow,
+        onupdate=datetime.utcnow,
+        nullable=False
+    )
+
+    # 用户发布的帖子
+    posts = db.relationship(
+        'Post',
+        backref='author',
+        lazy='dynamic',
+        cascade='all, delete-orphan'
+    )
+
+    # 用户的互动行为
+    behaviors = db.relationship(
+        'Behavior',
+        backref='user',
+        lazy='dynamic',
+        cascade='all, delete-orphan'
+    )
+
+    # 用户发表的评论
+    comments = db.relationship(
+        'Comment',
+        backref='user',
+        lazy='dynamic',
+        cascade='all, delete-orphan'
+    )
+
+    # 用户关注的对象列表
+    following = db.relationship(
+        'User',
+        secondary=follows,
+        primaryjoin=(id == follows.c.follower_id),
+        secondaryjoin=(id == follows.c.followee_id),
+        backref=db.backref('followers', lazy='dynamic'),
+        lazy='dynamic'
+    )
+
+    def __repr__(self):
+        return f"<User {self.username!r} id={self.id}>"
diff --git a/API/API-TRM/WZY/xhs_server/requirements.txt b/API/API-TRM/WZY/xhs_server/requirements.txt
new file mode 100644
index 0000000..4db9d23
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/requirements.txt
@@ -0,0 +1,6 @@
+# requirements.txt
+Flask>=2.0
+Flask-SQLAlchemy>=2.5
+Flask-Migrate>=3.1
+Flask-Script>=2.0
+PyMySQL>=1.0
diff --git a/API/API-TRM/WZY/xhs_server/routes/__init__.py b/API/API-TRM/WZY/xhs_server/routes/__init__.py
new file mode 100644
index 0000000..5410dd3
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/routes/__init__.py
@@ -0,0 +1,4 @@
+# routes/__init__.py
+from flask import Blueprint
+
+# 可以在这里统一注册蓝图,也可以直接在 app.py 中 import
diff --git a/API/API-TRM/WZY/xhs_server/routes/__pycache__/__init__.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/routes/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..acde7ed
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/routes/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/routes/__pycache__/comments.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/routes/__pycache__/comments.cpython-312.pyc
new file mode 100644
index 0000000..4bd83ee
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/routes/__pycache__/comments.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc b/API/API-TRM/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc
new file mode 100644
index 0000000..119a503
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc
Binary files differ
diff --git a/API/API-TRM/WZY/xhs_server/routes/comments.py b/API/API-TRM/WZY/xhs_server/routes/comments.py
new file mode 100644
index 0000000..2d5b654
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/routes/comments.py
@@ -0,0 +1,46 @@
+# routes/comments.py
+from flask import Blueprint, request, jsonify, abort
+from extensions      import db
+from models.comment  import Comment
+from models.behavior import Behavior
+
+comments_bp = Blueprint('comments', __name__)
+
+@comments_bp.route('', methods=['POST'])
+def add_comment(post_id):
+    data = request.get_json() or {}
+    user_id = data.get('user_id')
+    content = data.get('content')
+    if not user_id or not content:
+        return jsonify({'error': 'user_id and content required'}), 400
+
+    comment = Comment(
+        post_id=post_id,
+        user_id=user_id,
+        content=content,
+        parent_id=data.get('parent_id')
+    )
+    db.session.add(comment)
+    # 记录行为
+    beh = Behavior(user_id=user_id, post_id=post_id, type='comment')
+    db.session.add(beh)
+    db.session.commit()
+    return jsonify({'id': comment.id}), 201
+
+@comments_bp.route('', methods=['GET'])
+def list_comments(post_id):
+    def serialize(c):
+        return {
+            'id': c.id,
+            'user_id': c.user_id,
+            'content': c.content,
+            'created_at': c.created_at.isoformat(),
+            'replies': [serialize(r) for r in c.replies]
+        }
+
+    comments = Comment.query.filter_by(
+        post_id=post_id,
+        status='active',
+        parent_id=None
+    ).order_by(Comment.created_at.asc()).all()
+    return jsonify([serialize(c) for c in comments])
diff --git a/API/API-TRM/WZY/xhs_server/routes/posts.py b/API/API-TRM/WZY/xhs_server/routes/posts.py
new file mode 100644
index 0000000..e01bdd8
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/routes/posts.py
@@ -0,0 +1,150 @@
+# routes/posts.py
+from flask import Blueprint, request, jsonify, abort
+from extensions    import db
+from models.post   import Post
+from models.behavior import Behavior
+
+posts_bp = Blueprint('posts', __name__)
+
+@posts_bp.route('', methods=['POST'])
+def create_post():
+    data = request.get_json() or {}
+    post = Post(**data)
+    db.session.add(post)
+    db.session.commit()
+    return jsonify({'id': post.id}), 201
+
+@posts_bp.route('', methods=['GET'])
+def list_posts():
+    posts = Post.query.filter_by(status='published').all()
+    return jsonify([{
+        'id': p.id,
+        'title': p.title,
+        'heat': p.heat,
+        'created_at': p.created_at.isoformat()
+    } for p in posts])
+
+@posts_bp.route('/<int:post_id>', methods=['GET'])
+def get_post(post_id):
+    post = Post.query.get_or_404(post_id)
+    return jsonify({
+        'id': post.id,
+        'user_id': post.user_id,
+        'title': post.title,
+        'content': post.content,
+        'media_urls': post.media_urls,
+        'status': post.status,
+        'heat': post.heat,
+        'created_at': post.created_at.isoformat(),
+        'updated_at': post.updated_at.isoformat()
+    })
+
+@posts_bp.route('/<int:post_id>', methods=['PUT'])
+def update_post(post_id):
+    """
+    修改帖子
+    URL 参数:
+      post_id - 要修改的帖子 ID
+    JSON Body 可选字段:
+      title       (string)
+      content     (string)
+      topic_id    (int)     — 必须是 topics 表中已有的 ID
+      media_urls  (list)    — 字符串数组
+      status      (string)  — 'draft','pending','published','deleted','rejected'
+    """
+    post = Post.query.get_or_404(post_id)
+    data = request.get_json() or {}
+    # 只更新客户端传来的字段
+    for key in ('title','content','topic_id','media_urls','status'):
+        if key in data:
+            setattr(post, key, data[key])
+    db.session.commit()
+    return '', 204
+
+@posts_bp.route('/<int:post_id>', methods=['DELETE'])
+def delete_post(post_id):
+    post = Post.query.get_or_404(post_id)
+    db.session.delete(post)
+    db.session.commit()
+    return '', 204
+
+
+@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
+def post_action(post_id, action):
+    """
+    支持的 action: like, favorite, view, share
+    对于 like 和 favorite,保证每个用户每帖只做一次。
+    """
+    if action not in ('like', 'favorite', 'view', 'share'):
+        abort(400, 'Invalid action')
+
+    data = request.get_json() or {}
+    user_id = data.get('user_id')
+    if not user_id:
+        abort(400, 'user_id required')
+
+    # 对 like/favorite 做去重检查
+    if action in ('like', 'favorite'):
+        exists = Behavior.query.filter_by(
+            user_id=user_id,
+            post_id=post_id,
+            type=action
+        ).first()
+        if exists:
+            return jsonify({'error': f'already {action}d'}), 400
+
+    # 创建行为记录
+    beh = Behavior(user_id=user_id, post_id=post_id, type=action)
+    db.session.add(beh)
+
+    # 更新热度
+    post = Post.query.get_or_404(post_id)
+    post.heat += 1
+
+    db.session.commit()
+    return '', 201
+
+
+# 取消点赞
+@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
+def unlike(post_id):
+    user_id = request.get_json(silent=True) and request.get_json().get('user_id')
+    if not user_id:
+        abort(400, 'user_id required')
+    # 查找已有的 like 行为
+    beh = Behavior.query.filter_by(
+        user_id=user_id,
+        post_id=post_id,
+        type='like'
+    ).first()
+    if not beh:
+        return jsonify({'error': 'not liked yet'}), 400
+
+    db.session.delete(beh)
+    # 更新热度,确保不降到负数
+    post = Post.query.get_or_404(post_id)
+    post.heat = max(post.heat - 1, 0)
+    db.session.commit()
+    return '', 204
+
+# 取消收藏
+@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
+def unfavorite(post_id):
+    user_id = request.get_json(silent=True) and request.get_json().get('user_id')
+    if not user_id:
+        abort(400, 'user_id required')
+    # 查找已有的 favorite 行为
+    beh = Behavior.query.filter_by(
+        user_id=user_id,
+        post_id=post_id,
+        type='favorite'
+    ).first()
+    if not beh:
+        return jsonify({'error': 'not favorited yet'}), 400
+
+    db.session.delete(beh)
+    # 更新热度
+    post = Post.query.get_or_404(post_id)
+    post.heat = max(post.heat - 1, 0)
+    db.session.commit()
+    return '', 204
\ No newline at end of file
diff --git a/API/API-TRM/WZY/xhs_server/utils/auth.py b/API/API-TRM/WZY/xhs_server/utils/auth.py
new file mode 100644
index 0000000..24704d1
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/utils/auth.py
@@ -0,0 +1,38 @@
+# utils/auth.py
+import os
+import jwt
+from functools import wraps
+from flask import request, jsonify, current_app
+from models.user import User
+from app import db
+
+def generate_token(user_id):
+    payload = {
+        'user_id': user_id,
+        # you can add exp, iat here
+    }
+    token = jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256')
+    return token
+
+def verify_token(token):
+    try:
+        payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])
+        user = User.query.get(payload['user_id'])
+        return user
+    except Exception:
+        return None
+
+def login_required(f):
+    @wraps(f)
+    def decorated(*args, **kwargs):
+        auth_header = request.headers.get('Authorization', None)
+        if not auth_header or not auth_header.startswith('Bearer '):
+            return jsonify({'error': 'Authorization header missing or invalid'}), 401
+        token = auth_header.split()[1]
+        user = verify_token(token)
+        if not user or user.status != 'active':
+            return jsonify({'error': 'Invalid or expired token'}), 401
+        # attach user to request context if needed
+        request.current_user = user
+        return f(*args, **kwargs)
+    return decorated
diff --git a/API/API-TRM/WZY/xhs_server/utils/serializers.py b/API/API-TRM/WZY/xhs_server/utils/serializers.py
new file mode 100644
index 0000000..1ed5445
--- /dev/null
+++ b/API/API-TRM/WZY/xhs_server/utils/serializers.py
@@ -0,0 +1,16 @@
+# utils/serializers.py
+from marshmallow import Schema, fields, validate, ValidationError
+
+class PostSchema(Schema):
+    user_id = fields.Int(required=True)
+    topic_id = fields.Int(required=False, allow_none=True)
+    type = fields.Str(validate=validate.OneOf(['text','image','video','document']), missing='text')
+    title = fields.Str(required=True, validate=validate.Length(min=1, max=255))
+    content = fields.Str(required=True)
+    media_urls = fields.List(fields.Url(), required=False)
+    status = fields.Str(validate=validate.OneOf(['draft','pending','published','deleted','rejected']), missing='draft')
+
+class CommentSchema(Schema):
+    user_id = fields.Int(required=True)
+    content = fields.Str(required=True, validate=validate.Length(min=1))
+    parent_id = fields.Int(required=False, allow_none=True)