Merge remote-tracking branch 'refs/remotes/origin/master'

Change-Id: I0879b29d705017b7d6df0ddaae7b1c4d56fa0a53
diff --git a/Merge/front/src/App.jsx b/Merge/front/src/App.jsx
index 3ab9fca..6dab985 100644
--- a/Merge/front/src/App.jsx
+++ b/Merge/front/src/App.jsx
@@ -1,19 +1,44 @@
-import React from 'react';
-import Header from './components/Header';
-import Sidebar from './components/Sidebar';
-import AppRoutes from './router/App';
-import './App.css';
+// src/App.jsx
+import React, { useState, useEffect } from 'react'
+import { useLocation } from 'react-router-dom'
+import Header  from './components/Header'
+import Sidebar from './components/Sidebar'
+import AppRoutes from './router/App'
+import { getUserInfo } from './utils/auth'
+import './App.css'
 
 export default function App() {
+  const location = useLocation()
+
+  // 初始 role = null (未登录或刚进来时)
+  const [role, setRole] = useState(null)
+
+  // 每次路由变化(含登录後 navigate),都重新从 storage 读一遍 userInfo
+  useEffect(() => {
+    const u = getUserInfo()
+    setRole(u?.role || null)
+  }, [location.pathname])
+
+  // 只有普通 user 才显示侧边栏
+  const showSidebar = role === 'user'
+
   return (
     <div className="app">
       <Header />
-      <Sidebar />
-      <main className="main-content">
+
+      {showSidebar && <Sidebar />}
+
+      <main
+        className="main-content"
+        style={{
+          // 没侧边栏时去掉左边距
+          marginLeft: showSidebar ? undefined : 0
+        }}
+      >
         <div className="content-wrapper">
           <AppRoutes />
         </div>
       </main>
     </div>
-  );
-}
\ No newline at end of file
+  )
+}
diff --git a/Merge/front/src/api/posts_wzy.js b/Merge/front/src/api/posts_wzy.js
index b449c43..d901500 100644
--- a/Merge/front/src/api/posts_wzy.js
+++ b/Merge/front/src/api/posts_wzy.js
@@ -1,15 +1,25 @@
 // src/api/posts.js
-const BASE = 'http://10.126.59.25:5714/'  // 如果有代理可以留空,否则填完整域名,如 'http://localhost:3000'
+const BASE = 'http://10.126.59.25:5714'  // 如果有代理可以留空,否则填完整域名,如 'http://localhost:3000'
 
 /**
- * 获取所有已发布的帖子列表
- * GET /posts
+ * 获取帖子列表
+ * - GET /posts
+ * - GET /posts?user_id=123
+ *
+ * @param {number?} userId 可选,传了就加 ?user_id= 用户 ID
+ * @returns Promise<[{ id, title, status, heat, created_at }, …]>
  */
-export async function fetchPosts() {
-  const res = await fetch(`${BASE}/posts`)
-  if (!res.ok) throw new Error(`fetchPosts: ${res.status}`)
-  console.log('fetchPosts response:', res)  // debug: inspect response
-  return res.json()  // 返回 [ { id, title, heat, created_at }, … ]
+export async function fetchPosts(userId) {
+  // 自动拼接 query
+  const url = userId != null
+    ? `${BASE}/posts?user_id=${encodeURIComponent(userId)}`
+    : `${BASE}/posts`
+
+  const res = await fetch(url)
+  if (!res.ok) {
+    throw new Error(`fetchPosts${userId != null ? `(user ${userId})` : ''}: ${res.status}`)
+  }
+  return res.json()
 }
 
 /**
diff --git a/Merge/front/src/components/Admin.js b/Merge/front/src/components/Admin.js
index 2d97495..f73e239 100644
--- a/Merge/front/src/components/Admin.js
+++ b/Merge/front/src/components/Admin.js
@@ -1,21 +1,32 @@
-import 'antd/dist/antd.css';
-import React, { useState, useEffect, useMemo, useCallback } from 'react';
-import { Layout, Tabs, Input, List, Card, Button, Tag, Spin, Typography, Divider } from 'antd';
-import '../style/Admin.css';
-import { fetchPosts, approvePost, rejectPost } from '../api/posts_trm';
+// src/components/Admin.jsx
+import React, { useState, useEffect, useCallback } from 'react'
+import { useParams } from 'react-router-dom'
+import 'antd/dist/antd.css'
+import {
+  Layout,
+  Tabs,
+  Input,
+  List,
+  Card,
+  Button,
+  Tag,
+  Spin,
+  Typography,
+  Divider
+} from 'antd'
+import '../style/Admin.css'
+import { fetchPosts, approvePost, rejectPost } from '../api/posts_trm'
 
-export default function Admin() {
-  const ADMIN_USER_ID = 2;
-  const [posts, setPosts] = useState([]);
-  const [loading, setLoading] = useState(true);
-  const [hasPermission, setHasPermission] = useState(true);
-  const [activeTab, setActiveTab] = useState('all');
-  const [selectedPost, setSelectedPost] = useState(null);
-  const [searchTerm, setSearchTerm] = useState('');
-  
-  // 新增:拖拽相关状态
-  const [leftPanelWidth, setLeftPanelWidth] = useState(300);
-  const [isResizing, setIsResizing] = useState(false);
+export default function AdminPage() {
+  const { userId } = useParams()            // ← 从路由拿到
+  const [posts, setPosts] = useState([])
+  const [loading, setLoading] = useState(true)
+  const [hasPermission, setHasPermission] = useState(true)
+  const [activeTab, setActiveTab] = useState('all')
+  const [selectedPost, setSelectedPost] = useState(null)
+  const [searchTerm, setSearchTerm] = useState('')
+  const [leftPanelWidth, setLeftPanelWidth] = useState(300)
+  const [isResizing, setIsResizing] = useState(false)
 
   const statusColors = {
     draft: 'orange',
@@ -23,12 +34,12 @@
     published: 'green',
     deleted: 'gray',
     rejected: 'red'
-  };
+  }
 
   useEffect(() => {
     async function load() {
       try {
-        const list = await fetchPosts(ADMIN_USER_ID)
+        const list = await fetchPosts(userId)   // ← 传入 userId
         setPosts(list)
       } catch (e) {
         if (e.message === 'Unauthorized') {
@@ -41,10 +52,9 @@
       }
     }
     load()
-  }, [])
+  }, [userId])
 
-  // 过滤并排序
-  const sortedPosts = useMemo(() => {
+  const sortedPosts = React.useMemo(() => {
     return [...posts].sort((a, b) => {
       if (a.status === 'pending' && b.status !== 'pending') return -1
       if (b.status === 'pending' && a.status !== 'pending') return 1
@@ -52,18 +62,10 @@
     })
   }, [posts])
 
-  // 调整:根据 activeTab 及搜索关键词过滤
-  const filteredPosts = useMemo(() => {
-    let list
-    switch (activeTab) {
-      case 'pending':
-        list = sortedPosts.filter(p => p.status === 'pending'); break
-      case 'published':
-        list = sortedPosts.filter(p => p.status === 'published'); break
-      case 'rejected':
-        list = sortedPosts.filter(p => p.status === 'rejected'); break
-      default:
-        list = sortedPosts
+  const filteredPosts = React.useMemo(() => {
+    let list = sortedPosts
+    if (activeTab !== 'all') {
+      list = sortedPosts.filter(p => p.status === activeTab)
     }
     return list.filter(p =>
       p.title.toLowerCase().includes(searchTerm.toLowerCase())
@@ -71,84 +73,101 @@
   }, [sortedPosts, activeTab, searchTerm])
 
   const handleApprove = async id => {
-    await approvePost(id, ADMIN_USER_ID)
-    setPosts(ps => ps.map(x => x.id === id ? { ...x, status: 'published' } : x))
-    // 同步更新选中的帖子状态
+    await approvePost(id, userId)            // ← 传入 userId
+    setPosts(ps =>
+      ps.map(x => (x.id === id ? { ...x, status: 'published' } : x))
+    )
     if (selectedPost?.id === id) {
-      setSelectedPost(prev => ({ ...prev, status: 'published' }));
+      setSelectedPost(prev => ({ ...prev, status: 'published' }))
     }
   }
-  const handleReject  = async id => {
-    await rejectPost(id, ADMIN_USER_ID)
-    setPosts(ps => ps.map(x => x.id === id ? { ...x, status: 'rejected' } : x))
-    // 同步更新选中的帖子状态
-    if (selectedPost?.id === id) {
-      setSelectedPost(prev => ({ ...prev, status: 'rejected' }));
-    }
-  }
-  const handleSelect  = post => setSelectedPost(post)
 
-  // 修复:拖拽处理函数
-  const handleMouseMove = useCallback((e) => {
-    if (!isResizing) return;
-    
-    const newWidth = e.clientX;
-    const minWidth = 200;
-    const maxWidth = window.innerWidth - 300;
-    
-    if (newWidth >= minWidth && newWidth <= maxWidth) {
-      setLeftPanelWidth(newWidth);
+  const handleReject = async id => {
+    await rejectPost(id, userId)             // ← 传入 userId
+    setPosts(ps =>
+      ps.map(x => (x.id === id ? { ...x, status: 'rejected' } : x))
+    )
+    if (selectedPost?.id === id) {
+      setSelectedPost(prev => ({ ...prev, status: 'rejected' }))
     }
-  }, [isResizing]);
+  }
+
+  const handleSelect = post => setSelectedPost(post)
+
+  const handleMouseMove = useCallback(
+    e => {
+      if (!isResizing) return
+      const newWidth = e.clientX
+      const minWidth = 200
+      const maxWidth = window.innerWidth - 300
+      if (newWidth >= minWidth && newWidth <= maxWidth) {
+        setLeftPanelWidth(newWidth)
+      }
+    },
+    [isResizing]
+  )
 
   const handleMouseUp = useCallback(() => {
-    setIsResizing(false);
-    document.removeEventListener('mousemove', handleMouseMove);
-    document.removeEventListener('mouseup', handleMouseUp);
-    document.body.style.cursor = '';
-    document.body.style.userSelect = '';
-  }, [handleMouseMove]);
+    setIsResizing(false)
+    document.removeEventListener('mousemove', handleMouseMove)
+    document.removeEventListener('mouseup', handleMouseUp)
+    document.body.style.cursor = ''
+    document.body.style.userSelect = ''
+  }, [handleMouseMove])
 
-  const handleMouseDown = useCallback((e) => {
-    e.preventDefault();
-    setIsResizing(true);
-    document.addEventListener('mousemove', handleMouseMove);
-    document.addEventListener('mouseup', handleMouseUp);
-    document.body.style.cursor = 'col-resize';
-    document.body.style.userSelect = 'none';
-  }, [handleMouseMove, handleMouseUp]);
+  const handleMouseDown = useCallback(
+    e => {
+      e.preventDefault()
+      setIsResizing(true)
+      document.addEventListener('mousemove', handleMouseMove)
+      document.addEventListener('mouseup', handleMouseUp)
+      document.body.style.cursor = 'col-resize'
+      document.body.style.userSelect = 'none'
+    },
+    [handleMouseMove, handleMouseUp]
+  )
 
-  // 新增:组件卸载时清理事件监听器
   useEffect(() => {
     return () => {
-      document.removeEventListener('mousemove', handleMouseMove);
-      document.removeEventListener('mouseup', handleMouseUp);
-      document.body.style.cursor = '';
-      document.body.style.userSelect = '';
-    };
-  }, [handleMouseMove, handleMouseUp]);
+      document.removeEventListener('mousemove', handleMouseMove)
+      document.removeEventListener('mouseup', handleMouseUp)
+      document.body.style.cursor = ''
+      document.body.style.userSelect = ''
+    }
+  }, [handleMouseMove, handleMouseUp])
 
-  if (loading) return <Spin spinning tip="加载中…" style={{ width: '100%', marginTop: 100 }} />;
-  if (!hasPermission) return <div style={{ textAlign: 'center', marginTop: 100 }}>权限不足</div>;
+  if (loading)
+    return (
+      <Spin
+        spinning
+        tip="加载中…"
+        style={{ width: '100%', marginTop: 100 }}
+      />
+    )
+  if (!hasPermission)
+    return (
+      <div style={{ textAlign: 'center', marginTop: 100 }}>
+        权限不足
+      </div>
+    )
 
-  const { Content } = Layout;
-  const { TabPane } = Tabs;
-  const { Title, Text } = Typography;
+  const { Content } = Layout
+  const { TabPane } = Tabs
+  const { Title, Text } = Typography
 
   return (
     <div style={{ height: '100vh', display: 'flex' }}>
-      {/* 左侧面板 */}
-      <div 
-        style={{ 
+      <div
+        style={{
           width: leftPanelWidth,
-          background: '#fff', 
+          background: '#fff',
           padding: 16,
           borderRight: '1px solid #f0f0f0',
           overflow: 'hidden'
         }}
       >
         <div style={{ marginBottom: 24 }}>
-          <Title level={3}>小红书</Title>
+          <Title level={3}>小红书 管理</Title>
           <Input.Search
             placeholder="搜索帖子标题..."
             value={searchTerm}
@@ -156,26 +175,38 @@
             enterButton
           />
         </div>
-        <Tabs activeKey={activeTab} onChange={key => { setActiveTab(key); setSelectedPost(null); }}>
+        <Tabs
+          activeKey={activeTab}
+          onChange={key => {
+            setActiveTab(key)
+            setSelectedPost(null)
+          }}
+        >
           <TabPane tab="全部" key="all" />
           <TabPane tab="待审核" key="pending" />
           <TabPane tab="已通过" key="published" />
           <TabPane tab="已驳回" key="rejected" />
         </Tabs>
-        <div style={{ height: 'calc(100vh - 200px)', overflow: 'auto' }}>
+        <div
+          style={{
+            height: 'calc(100vh - 200px)',
+            overflow: 'auto'
+          }}
+        >
           <List
             dataSource={filteredPosts}
             pagination={{
               pageSize: 5,
               showSizeChanger: true,
-              pageSizeOptions: ['5','10','20'],
+              pageSizeOptions: ['5', '10', '20'],
               onChange: () => setSelectedPost(null)
             }}
             renderItem={p => (
               <List.Item
                 key={p.id}
                 style={{
-                  background: selectedPost?.id === p.id ? '#e6f7ff' : '',
+                  background:
+                    selectedPost?.id === p.id ? '#e6f7ff' : '',
                   cursor: 'pointer',
                   marginBottom: 8
                 }}
@@ -187,32 +218,38 @@
                       <img
                         src={p.thumbnail}
                         alt=""
-                        style={{ width: 64, height: 64, objectFit: 'cover' }}
+                        style={{
+                          width: 64,
+                          height: 64,
+                          objectFit: 'cover'
+                        }}
                       />
                     )
                   }
                   title={p.title}
-                  description={`${p.createdAt} · ${p.author} · ${p.likes || 0}赞`}
+                  description={`${p.createdAt} · ${p.author} · ${
+                    p.likes || 0
+                  }赞`}
                 />
-                <Tag color={statusColors[p.status]}>{p.status}</Tag>
+                <Tag color={statusColors[p.status]}>
+                  {p.status}
+                </Tag>
               </List.Item>
             )}
           />
         </div>
       </div>
 
-      {/* 拖拽分割条 */}
       <div
         style={{
           width: 5,
           cursor: 'col-resize',
           background: isResizing ? '#1890ff' : '#f0f0f0',
-          transition: isResizing ? 'none' : 'background-color 0.2s',
           position: 'relative',
           flexShrink: 0
         }}
         onMouseDown={handleMouseDown}
-        onSelectStart={(e) => e.preventDefault()}
+        onSelectStart={e => e.preventDefault()}
       >
         <div
           style={{
@@ -228,41 +265,111 @@
         />
       </div>
 
-      {/* 右侧内容区域 */}
-      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
-        <Content style={{ padding: 24, background: '#fff', overflow: 'auto' }}>
+      <div
+        style={{
+          flex: 1,
+          display: 'flex',
+          flexDirection: 'column'
+        }}
+      >
+        <Content
+          style={{
+            padding: 24,
+            background: '#fff',
+            overflow: 'auto'
+          }}
+        >
           {selectedPost ? (
             <Card
-              cover={selectedPost.image && <img alt="cover" src={selectedPost.image} />}
+              cover={
+                selectedPost.image && (
+                  <img
+                    alt="cover"
+                    src={selectedPost.image}
+                  />
+                )
+              }
               title={selectedPost.title}
               extra={
                 <div>
                   {selectedPost.status === 'pending' && (
                     <>
-                      <Button type="primary" onClick={() => handleApprove(selectedPost.id)}>通过</Button>
-                      <Button danger onClick={() => handleReject(selectedPost.id)}>驳回</Button>
+                      <Button
+                        type="primary"
+                        onClick={() =>
+                          handleApprove(selectedPost.id)
+                        }
+                      >
+                        通过
+                      </Button>
+                      <Button
+                        danger
+                        onClick={() =>
+                          handleReject(selectedPost.id)
+                        }
+                      >
+                        驳回
+                      </Button>
                     </>
                   )}
                   {selectedPost.status === 'published' && (
-                    <Button danger onClick={() => handleReject(selectedPost.id)}>驳回</Button>
+                    <Button
+                      danger
+                      onClick={() =>
+                        handleReject(selectedPost.id)
+                      }
+                    >
+                      驳回
+                    </Button>
                   )}
                   {selectedPost.status === 'rejected' && (
                     <>
-                      <Button onClick={() => {
-                        setPosts(ps => ps.map(x => x.id === selectedPost.id ? { ...x, status: 'pending' } : x));
-                        setSelectedPost(prev => ({ ...prev, status: 'pending' }));
-                      }}>恢复待审</Button>
-                      <Button onClick={() => {
-                        setPosts(ps => ps.map(x => x.id === selectedPost.id ? { ...x, status: 'published' } : x));
-                        setSelectedPost(prev => ({ ...prev, status: 'published' }));
-                      }}>恢复已发</Button>
+                      <Button
+                        onClick={() => {
+                          setPosts(ps =>
+                            ps.map(x =>
+                              x.id === selectedPost.id
+                                ? { ...x, status: 'pending' }
+                                : x
+                            )
+                          )
+                          setSelectedPost(prev => ({
+                            ...prev,
+                            status: 'pending'
+                          }))
+                        }}
+                      >
+                        恢复待审
+                      </Button>
+                      <Button
+                        onClick={() => {
+                          setPosts(ps =>
+                            ps.map(x =>
+                              x.id === selectedPost.id
+                                ? {
+                                    ...x,
+                                    status: 'published'
+                                  }
+                                : x
+                            )
+                          )
+                          setSelectedPost(prev => ({
+                            ...prev,
+                            status: 'published'
+                          }))
+                        }}
+                      >
+                        恢复已发
+                      </Button>
                     </>
                   )}
                 </div>
               }
             >
               <Text type="secondary">
-                {`${selectedPost.createdAt} · ${selectedPost.author} · ${selectedPost.likes || 0}赞`}
+                {`${selectedPost.createdAt} · ${selectedPost.author} · ${
+                  selectedPost.likes || 0
+                }赞`}
               </Text>
               <Divider />
               <p>{selectedPost.content}</p>
@@ -274,10 +381,12 @@
               </ul>
             </Card>
           ) : (
-            <Text type="secondary">请选择左侧列表中的帖子查看详情</Text>
+            <Text type="secondary">
+              请选择左侧列表中的帖子查看详情
+            </Text>
           )}
         </Content>
       </div>
     </div>
-  );
+)
 }
diff --git a/Merge/front/src/components/CreatePost.jsx b/Merge/front/src/components/CreatePost.jsx
index 9817ac0..1d2f306 100644
--- a/Merge/front/src/components/CreatePost.jsx
+++ b/Merge/front/src/components/CreatePost.jsx
@@ -1,5 +1,3 @@
-// src/components/CreatePost.jsx
-
 import React, { useState, useEffect } from 'react'
 import { useNavigate, useParams } from 'react-router-dom'
 import UploadPage from './UploadPage'
@@ -8,6 +6,7 @@
   updatePost, 
   fetchPost as fetchPostDetail 
 } from '../api/posts_wzy'
+import { getUserInfo } from '../utils/auth'
 import '../style/CreatePost.css'
 
 export default function CreatePost() {
@@ -36,6 +35,10 @@
     { id: 3, name: '我染上了拼豆' },
   ]
 
+  // 获取当前登录用户id
+  const user = getUserInfo()
+  const currentUserId = user?.id
+
   // 编辑模式:拉取原帖数据填入
   useEffect(() => {
     if (!isEdit) return
@@ -68,6 +71,10 @@
       setError('标题和正文必填')
       return
     }
+    if (!currentUserId) {
+      setError('未获取到用户ID,请重新登录')
+      return
+    }
     setError(null)
     try {
       if (isEdit) {
@@ -81,7 +88,7 @@
         alert('更新成功!')
       } else {
         await createPost({
-          user_id: 1,
+          user_id: currentUserId,
           topic_id: topicId || undefined,
           title: title.trim(),
           content: content.trim(),
diff --git a/Merge/front/src/components/Header.jsx b/Merge/front/src/components/Header.jsx
index 3b21c98..96ae6ac 100644
--- a/Merge/front/src/components/Header.jsx
+++ b/Merge/front/src/components/Header.jsx
@@ -1,13 +1,21 @@
+// src/components/Header.jsx
 import React from 'react'
 import { useNavigate } from 'react-router-dom'
 import { User } from 'lucide-react'
-import '../App.css' // 或者单独的 Header.css
+import { getUserInfo } from '../utils/auth'
+import '../App.css'
 
 export default function Header() {
   const navigate = useNavigate()
+  const user = getUserInfo() || {}
+  const userId = user.id
+  // 假设后端返回的 user 对象里有个 nickname 字段,否则 fallback 到 “小红薯”
+  const displayName = user.nickname || user.username || '小红薯'
 
   const handleUserClick = () => {
-    navigate('/user/1') // 或者使用实际的用户ID
+    if (userId) {
+      navigate(`/user/${userId}`)
+    }
   }
 
   return (
@@ -16,16 +24,19 @@
         <div className="logo">小红书</div>
         <h1 className="header-title">创作服务平台</h1>
       </div>
-      <div 
+      <div
         className="header-right"
         onClick={handleUserClick}
-        style={{ cursor: 'pointer' }}
+        style={{ cursor: userId ? 'pointer' : 'default' }}
       >
         <div className="user-info">
           <User size={16} />
-          <span>小红薯1</span>
+          <span>
+            {displayName}
+            {userId ? userId : ''}
+          </span>
         </div>
       </div>
     </header>
   )
-}
\ No newline at end of file
+}
diff --git a/Merge/front/src/components/NotebookPage.jsx b/Merge/front/src/components/NotebookPage.jsx
index 25264ec..4214213 100644
--- a/Merge/front/src/components/NotebookPage.jsx
+++ b/Merge/front/src/components/NotebookPage.jsx
@@ -3,6 +3,7 @@
 import React, { useState, useEffect } from 'react'
 import { useNavigate } from 'react-router-dom'
 import { fetchPosts, deletePost } from '../api/posts_wzy'
+import { getUserInfo } from '../utils/auth'   // ← 导入 getUserInfo
 import '../style/NotebookPage.css'
 
 export default function NotebookPage() {
@@ -11,13 +12,20 @@
   const [loading, setLoading] = useState(true)
   const [error, setError]     = useState(null)
 
-  // TODO: 替换成真实用户 ID
-  const currentUserId = 2
+  // 从 auth 获取当前用户信息
+  const userInfo = getUserInfo()
+  const currentUserId = userInfo?.id
 
   useEffect(() => {
+    if (!currentUserId) {
+      setError('未获取到用户信息,无法加载帖子。')
+      setLoading(false)
+      return
+    }
+
     async function load() {
       try {
-        // GET /posts?user_id=1
+        // GET /posts?user_id=currentUserId
         const list = await fetchPosts(currentUserId)
         setPosts(list)
       } catch (e) {
@@ -27,7 +35,7 @@
       }
     }
     load()
-  }, [])
+  }, [currentUserId])
 
   async function handleDelete(id) {
     if (!window.confirm('确定要删除该帖子吗?')) return
@@ -41,7 +49,6 @@
   }
 
   function handleEdit(id) {
-    // 假设你在路由里挂载了 /posts/edit/:postId
     navigate(`/posts/edit/${id}`)
   }
 
diff --git a/Merge/front/src/components/RequireAuth.jsx b/Merge/front/src/components/RequireAuth.jsx
new file mode 100644
index 0000000..e217e4f
--- /dev/null
+++ b/Merge/front/src/components/RequireAuth.jsx
@@ -0,0 +1,13 @@
+// src/components/RequireAuth.jsx
+import React from 'react'
+import { Navigate, useLocation } from 'react-router-dom'
+import { isLoggedIn } from '../utils/auth'
+
+export function RequireAuth({ children }) {
+  const location = useLocation()
+  if (!isLoggedIn()) {
+    // 未登录跳到 /login,并保存当前尝试访问的地址
+    return <Navigate to="/login" replace state={{ from: location }} />
+  }
+  return children
+}
diff --git a/Merge/front/src/components/RequireRole.jsx b/Merge/front/src/components/RequireRole.jsx
new file mode 100644
index 0000000..75a4c28
--- /dev/null
+++ b/Merge/front/src/components/RequireRole.jsx
@@ -0,0 +1,17 @@
+// src/components/RequireRole.jsx
+import React from 'react'
+import { Navigate } from 'react-router-dom'
+import { getUserInfo, isLoggedIn } from '../utils/auth'
+
+export function RequireRole({ role, children }) {
+  if (!isLoggedIn()) {
+    // 未登录
+    return <Navigate to="/login" replace />
+  }
+  const user = getUserInfo()
+  if (user.role !== role) {
+    // 角色不匹配,回首页
+    return <Navigate to="/" replace />
+  }
+  return children
+}
diff --git a/Merge/front/src/components/Sidebar.jsx b/Merge/front/src/components/Sidebar.jsx
index 26118b2..92bc8f1 100644
--- a/Merge/front/src/components/Sidebar.jsx
+++ b/Merge/front/src/components/Sidebar.jsx
@@ -24,10 +24,10 @@
       { 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'  },
+  // { 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() {
diff --git a/Merge/front/src/components/SuperAdmin.js b/Merge/front/src/components/SuperAdmin.js
index f24e5d4..0fa6722 100644
--- a/Merge/front/src/components/SuperAdmin.js
+++ b/Merge/front/src/components/SuperAdmin.js
@@ -1,33 +1,48 @@
-import React, { useState, useEffect } from 'react';
-import { NavLink, Outlet } from 'react-router-dom';
-import { Spin } from 'antd';
-import { fetchUserList } from '../api/posts_trm';
-import '../style/SuperAdmin.css';
+// src/components/SuperAdmin.jsx
+import React, { useState, useEffect } from 'react'
+import { NavLink, Outlet, useParams } from 'react-router-dom'
+import { Spin } from 'antd'
+import { fetchUserList } from '../api/posts_trm'
+import '../style/SuperAdmin.css'
 
 export default function SuperAdmin() {
-  const SUPERADMIN_USER_ID = 3;
-  const [loading, setLoading] = useState(true);
-  const [hasPermission, setHasPermission] = useState(true);
+  const { userId } = useParams()             // ← 从路由拿到
+  const [loading, setLoading] = useState(true)
+  const [hasPermission, setHasPermission] = useState(true)
 
   useEffect(() => {
     async function check() {
       try {
-        await fetchUserList(SUPERADMIN_USER_ID);
+        await fetchUserList(userId)          // ← 传入 userId
       } catch (e) {
         if (e.message === 'Unauthorized') {
-          setHasPermission(false);
+          setHasPermission(false)
         } else {
-          console.error(e);
+          console.error(e)
         }
       } finally {
-        setLoading(false);
+        setLoading(false)
       }
     }
-    check();
-  }, []);
+    check()
+  }, [userId])
 
-  if (loading) return <Spin spinning tip="加载中…" style={{ width: '100%', marginTop: 100 }} />;
-  if (!hasPermission) return <div style={{ textAlign: 'center', marginTop: 100 }}>权限不足</div>;
+  if (loading) {
+    return (
+      <Spin
+        spinning
+        tip="加载中…"
+        style={{ width: '100%', marginTop: 100 }}
+      />
+    )
+  }
+  if (!hasPermission) {
+    return (
+      <div style={{ textAlign: 'center', marginTop: 100 }}>
+        权限不足
+      </div>
+    )
+  }
 
   return (
     <div className="super-admin-container">
@@ -36,18 +51,22 @@
         <nav>
           <ul>
             <li>
-              <NavLink 
-                to="users" 
-                end 
-                className={({ isActive }) => isActive ? 'active' : ''}
+              <NavLink
+                to="users"
+                end
+                className={({ isActive }) =>
+                  isActive ? 'active' : ''
+                }
               >
                 用户管理
               </NavLink>
             </li>
             <li>
-              <NavLink 
-                to="dashboard" 
-                className={({ isActive }) => isActive ? 'active' : ''}
+              <NavLink
+                to="dashboard"
+                className={({ isActive }) =>
+                  isActive ? 'active' : ''
+                }
               >
                 平台运行监控
               </NavLink>
@@ -60,5 +79,5 @@
         <Outlet />
       </main>
     </div>
-  );
-}
\ No newline at end of file
+  )
+}
diff --git a/Merge/front/src/components/UserManagement.js b/Merge/front/src/components/UserManagement.js
index a48f8cf..bed6b8f 100644
--- a/Merge/front/src/components/UserManagement.js
+++ b/Merge/front/src/components/UserManagement.js
@@ -1,51 +1,77 @@
-import React, { useState, useEffect } from 'react';
-import '../style/Admin.css';
-import { Select, message, Table } from 'antd';
-import { fetchUserList, giveUser, giveAdmin, giveSuperAdmin } from '../api/posts_trm';
+// src/components/UserManagement.jsx
 
-const { Option } = Select;
-const ROLE_LIST = ['用户', '管理员', '超级管理员'];
+import React, { useState, useEffect } from 'react'
+import { useParams } from 'react-router-dom'
+import { Table, Select, message } from 'antd'
+import {
+  fetchUserList,
+  giveUser,
+  giveAdmin,
+  giveSuperAdmin
+} from '../api/posts_trm'
+import '../style/Admin.css'
 
-function UserManagement({ superAdminId }) {
-  const [users, setUsers] = useState([]);
+const { Option } = Select
+const ROLE_LIST = ['用户', '管理员', '超级管理员']
+
+export default function UserManagement() {
+  // 直接从 URL 参数里拿到 superAdminId
+  const { userId: superAdminId } = useParams()
+
+  const [users, setUsers] = useState([])
 
   useEffect(() => {
     async function load() {
       try {
-        const data = superAdminId
-          ? await fetchUserList(superAdminId)
-          : await fetch('/api/users').then(res => res.json());
-        setUsers(data);
+        // 调用接口获取用户列表
+        const data = await fetchUserList(superAdminId)
+        setUsers(data)
       } catch (e) {
-        console.error(e);
+        console.error(e)
+        message.error('获取用户列表失败:' + e.message)
       }
     }
-    load();
-  }, [superAdminId]);
 
-  // handle role changes
+    // 只有当 superAdminId 有值时才发请求
+    if (superAdminId) {
+      load()
+    }
+  }, [superAdminId])
+
+  // 处理角色变更
   const handleRoleChange = async (userId, newRole) => {
     try {
-      if (newRole === '用户') await giveUser(superAdminId, userId);
-      else if (newRole === '管理员') await giveAdmin(superAdminId, userId);
-      else if (newRole === '超级管理员') await giveSuperAdmin(superAdminId, userId);
-      setUsers(us => us.map(u => u.id === userId ? { ...u, role: newRole } : u));
-      message.success('修改成功');
+      if (newRole === '用户') {
+        await giveUser(superAdminId, userId)
+      } else if (newRole === '管理员') {
+        await giveAdmin(superAdminId, userId)
+      } else if (newRole === '超级管理员') {
+        await giveSuperAdmin(superAdminId, userId)
+      }
+      // 本地更新状态
+      setUsers(us =>
+        us.map(u => (u.id === userId ? { ...u, role: newRole } : u))
+      )
+      message.success('修改成功')
     } catch (e) {
-      console.error(e);
-      message.error('修改失败');
+      console.error(e)
+      message.error('修改失败:' + e.message)
     }
-  };
+  }
 
-  // define table columns
+  // 表格列定义
   const columns = [
     { title: '用户名', dataIndex: 'username', key: 'username' },
-    { title: '角色', dataIndex: 'role', key: 'role' },
+    { title: '角色',   dataIndex: 'role',     key: 'role' },
     {
       title: '操作',
       key: 'action',
       render: (_, record) => {
-        const orderedRoles = [record.role, ...ROLE_LIST.filter(r => r !== record.role)];
+        // 当前角色排第一
+        const orderedRoles = [
+          record.role,
+          ...ROLE_LIST.filter(r => r !== record.role)
+        ]
         return (
           <Select
             value={record.role}
@@ -53,13 +79,15 @@
             onChange={value => handleRoleChange(record.id, value)}
           >
             {orderedRoles.map(r => (
-              <Option key={r} value={r}>{r}</Option>
+              <Option key={r} value={r}>
+                {r}
+              </Option>
             ))}
           </Select>
-        );
-      },
-    },
-  ];
+        )
+      }
+    }
+  ]
 
   return (
     <div className="admin-container">
@@ -70,7 +98,5 @@
         pagination={false}
       />
     </div>
-  );
+  )
 }
-
-export default UserManagement;
diff --git a/Merge/front/src/pages/LoginPage/LoginPage.js b/Merge/front/src/pages/LoginPage/LoginPage.js
index c315b7d..bdd75d0 100644
--- a/Merge/front/src/pages/LoginPage/LoginPage.js
+++ b/Merge/front/src/pages/LoginPage/LoginPage.js
@@ -1,380 +1,240 @@
-import React, { useState, useEffect } from 'react';
-import { Link } from 'react-router-dom';
-import { Input, Checkbox, Modal, Alert } from 'antd';
-import { MailOutlined, LockOutlined, ExclamationCircleOutlined, CheckCircleOutlined } from '@ant-design/icons';
-import { 
-  getRememberedLoginInfo, 
-  saveRememberedLoginInfo, 
-  saveAuthInfo, 
-  isLoggedIn 
-} from '../../utils/auth';
-import { hashPassword } from '../../utils/crypto';
-import './LoginPage.css';
+// src/pages/LoginPage/LoginPage.jsx
 
-const baseURL = 'http://10.126.59.25:8082';
+import React, { useState, useEffect } from 'react'
+import { useNavigate, Link } from 'react-router-dom'
+import { Input, Checkbox, Modal, Alert } from 'antd'
+import {
+  MailOutlined,
+  LockOutlined,
+  ExclamationCircleOutlined,
+  CheckCircleOutlined
+} from '@ant-design/icons'
+import {
+  getRememberedLoginInfo,
+  saveRememberedLoginInfo,
+  saveAuthInfo,
+  isLoggedIn,
+  clearAuthInfo           // ← 新增
+} from '../../utils/auth'
+import { hashPassword } from '../../utils/crypto'
+import './LoginPage.css'
 
-const LoginPage = () => {
+const baseURL = 'http://10.126.59.25:8082'
+
+export default function LoginPage() {
+  const navigate = useNavigate()
+
+  // —— 登录页加载时先清除旧的认证信息 —— 
+  useEffect(() => {
+    clearAuthInfo(/* clearRemembered= */ false)
+  }, [])
+
   const [formData, setFormData] = useState({
     email: '',
     password: ''
-  });
-
-  const [rememberMe, setRememberMe] = useState(false);
-  const [isLoading, setIsLoading] = useState(false);
-  const [errors, setErrors] = useState({
-    email: '',
-    password: ''
-  });
+  })
+  const [rememberMe, setRememberMe] = useState(false)
+  const [isLoading, setIsLoading] = useState(false)
+  const [errors, setErrors] = useState({ email: '', password: '' })
   const [errorModal, setErrorModal] = useState({
     visible: false,
     title: '',
     content: ''
-  });
+  })
   const [successAlert, setSuccessAlert] = useState({
     visible: false,
     message: ''
-  });
+  })
 
   // 显示错误弹窗
   const showErrorModal = (title, content) => {
-    setErrorModal({
-      visible: true,
-      title: title,
-      content: content
-    });
-  };
-
+    setErrorModal({ visible: true, title, content })
+  }
   // 关闭错误弹窗
   const closeErrorModal = () => {
-    setErrorModal({
-      visible: false,
-      title: '',
-      content: ''
-    });
-  };
-
+    setErrorModal({ visible: false, title: '', content: '' })
+  }
   // 显示成功提示
   const showSuccessAlert = (message) => {
-    setSuccessAlert({
-      visible: true,
-      message: message
-    });
-    
-    // 3秒后自动隐藏
+    setSuccessAlert({ visible: true, message })
     setTimeout(() => {
-      setSuccessAlert({
-        visible: false,
-        message: ''
-      });
-    }, 3000);
-  };
+      setSuccessAlert({ visible: false, message: '' })
+    }, 3000)
+  }
 
-  // 页面加载时检查是否有记住的登录信息
+  // 初始化:检查登录 & 填充“记住我”
   useEffect(() => {
-    // 检查是否已经登录
     if (isLoggedIn()) {
-      // 如果已经有token,可以选择直接跳转到主页面
-      // window.location.href = '/test-dashboard';
-      console.log('用户已登录');
+      console.log('用户已登录')
+      // 如果想自动跳转: navigate('/home', { replace: true })
     }
-
-    // 获取记住的登录信息
-    const rememberedInfo = getRememberedLoginInfo();
-    if (rememberedInfo.rememberMe && rememberedInfo.email) {
-      setFormData({
-        email: rememberedInfo.email,
-        password: rememberedInfo.password
-      });
-      setRememberMe(true);
+    const { email, password, rememberMe } = getRememberedLoginInfo()
+    if (rememberMe && email) {
+      setFormData({ email, password })
+      setRememberMe(true)
     }
-  }, []);
+  }, [])
 
   const handleEmailChange = (e) => {
-    const value = e.target.value;
-    setFormData(prev => ({
-      ...prev,
-      email: value
-    }));
-    
-    // 清除邮箱错误提示
-    if (errors.email) {
-      setErrors(prev => ({
-        ...prev,
-        email: ''
-      }));
-    }
-  };
-
+    setFormData(f => ({ ...f, email: e.target.value }))
+    if (errors.email) setErrors(e => ({ ...e, email: '' }))
+  }
   const handlePasswordChange = (e) => {
-    const value = e.target.value;
-    setFormData(prev => ({
-      ...prev,
-      password: value
-    }));
-    
-    // 清除密码错误提示
-    if (errors.password) {
-      setErrors(prev => ({
-        ...prev,
-        password: ''
-      }));
-    }
-  };
-
+    setFormData(f => ({ ...f, password: e.target.value }))
+    if (errors.password) setErrors(e => ({ ...e, password: '' }))
+  }
   const handleRememberMeChange = (e) => {
-    const checked = e.target.checked;
-    setRememberMe(checked);
-    
-    // 如果取消记住我,清除已保存的登录信息
+    const checked = e.target.checked
+    setRememberMe(checked)
     if (!checked) {
-      saveRememberedLoginInfo('', '', false);
+      saveRememberedLoginInfo('', '', false)
     }
-  };
+  }
 
   const validateForm = () => {
-    const newErrors = {
-      email: '',
-      password: ''
-    };
-    
-    let hasError = false;
-    
-    // 验证邮箱
-    if (!formData.email || typeof formData.email !== 'string' || !formData.email.trim()) {
-      newErrors.email = '请输入邮箱地址';
-      hasError = true;
-    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
-      newErrors.email = '请输入有效的邮箱地址';
-      hasError = true;
+    const newErr = { email: '', password: '' }
+    let hasError = false
+    if (!formData.email.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
+      newErr.email = '请输入有效的邮箱地址'
+      hasError = true
     }
-    
-    // 验证密码
-    if (!formData.password || typeof formData.password !== 'string' || !formData.password.trim()) {
-      newErrors.password = '请输入密码';
-      hasError = true;
-    } else if (formData.password.length < 6) {
-      newErrors.password = '密码长度至少6位';
-      hasError = true;
+    if (!formData.password.trim() || formData.password.length < 6) {
+      newErr.password = '密码长度至少6位'
+      hasError = true
     }
-    
-    setErrors(newErrors);
-    return !hasError;
-  };
+    setErrors(newErr)
+    return !hasError
+  }
 
   const handleSubmit = async (e) => {
-    e.preventDefault();
-    
-    // 验证表单
-    if (!validateForm()) {
-      return;
-    }
-    
-    setIsLoading(true);
-    
+    e.preventDefault()
+    if (!validateForm()) return
+
+    setIsLoading(true)
     try {
-      // 发送登录请求到后端
-      const response = await fetch(baseURL + '/login', {
+      const res = await fetch(baseURL + '/login', {
         method: 'POST',
-        headers: {
-          'Content-Type': 'application/json',
-        },
+        headers: { 'Content-Type': 'application/json' },
         body: JSON.stringify({
-          email: formData.email, // 后端支持邮箱登录
-          password: hashPassword(formData.password) // 前端加密密码
+          email: formData.email,
+          password: hashPassword(formData.password)
         })
-      });
-      
-      const result = await response.json();
-      
+      })
+      const result = await res.json()
       if (result.success) {
-        // 显示成功提示
-        showSuccessAlert('登录成功!正在跳转...');
-        
-        // 保存认证信息
-        saveAuthInfo(result.token, result.user, rememberMe);
-        
-        // 保存或清除记住的登录信息
-        saveRememberedLoginInfo(formData.email, formData.password, rememberMe);
-        
-        // 延迟跳转,让用户看到成功提示
+        showSuccessAlert('登录成功!正在跳转...')
+        saveAuthInfo(result.token, result.user, rememberMe)
+        saveRememberedLoginInfo(formData.email, formData.password, rememberMe)
         setTimeout(() => {
-          window.location.href = '/test-dashboard';
-        }, 1500);
+          const uid = result.user.id
+          switch (result.user.role) {
+            case 'admin':
+              navigate(`/admin/${uid}`, { replace: true })
+              break
+            case 'superadmin':
+              navigate(`/superadmin/${uid}/users`, { replace: true })
+              break
+            default:
+              navigate('/home', { replace: true })
+          }
+        }, 1500)
       } else {
-        // 登录失败,显示错误信息
-        let errorTitle = '登录失败';
-        let errorContent = result.message || '登录失败,请检查您的邮箱和密码';
-        
-        // 根据错误类型提供更详细的信息
+        let title = '登录失败'
+        let content = result.message || '登录失败,请检查您的邮箱和密码'
         if (result.message) {
-          if (result.message.includes('邮箱') || result.message.includes('email')) {
-            errorTitle = '邮箱验证失败';
-            errorContent = '您输入的邮箱地址不存在或格式不正确,请检查后重试。';
-          } else if (result.message.includes('密码') || result.message.includes('password')) {
-            errorTitle = '密码验证失败';
-            errorContent = '您输入的密码不正确,请检查后重试。如果忘记密码,请点击"忘记密码"进行重置。';
-          } else if (result.message.includes('用户不存在')) {
-            errorTitle = '用户不存在';
-            errorContent = '该邮箱尚未注册,请先注册账户或检查邮箱地址是否正确。';
-          } else if (result.message.includes('账户被锁定') || result.message.includes('locked')) {
-            errorTitle = '账户被锁定';
-            errorContent = '您的账户因安全原因被暂时锁定,请联系客服或稍后重试。';
+          if (/邮箱|email/.test(result.message)) {
+            title = '邮箱验证失败'
+            content = '请输入正确的邮箱地址'
+          } else if (/密码|password/.test(result.message)) {
+            title = '密码验证失败'
+            content = '密码不正确,请重试'
           }
         }
-        
-        showErrorModal(errorTitle, errorContent);
+        showErrorModal(title, content)
       }
-    } catch (error) {
-      console.error('登录请求失败:', error);
-      
-      // 根据错误类型显示不同的错误信息
-      if (error.name === 'TypeError' && error.message.includes('fetch')) {
-        showErrorModal('网络连接失败', '无法连接到服务器,请检查您的网络连接后重试。如果问题持续存在,请联系客服。');
-      } else if (error.name === 'AbortError') {
-        showErrorModal('请求超时', '请求超时,请检查网络连接后重试。');
-      } else {
-        showErrorModal('登录失败', '网络连接失败,请检查网络或稍后重试。如果问题持续存在,请联系客服。');
-      }
+    } catch (err) {
+      console.error(err)
+      showErrorModal('网络异常', '无法连接到服务器,请稍后重试')
     } finally {
-      setIsLoading(false);
+      setIsLoading(false)
     }
-  };
+  }
 
   return (
     <div className="login-container">
-      <div className="login-background"></div>
-      
+      <div className="login-background" />
       {isLoading && (
         <div className="loading-overlay">
           <div className="loading-content">
-            <div className="loading-spinner-large"></div>
+            <div className="loading-spinner-large" />
             <p className="loading-text">正在登录...</p>
           </div>
         </div>
       )}
-      
       <div className="login-content">
         <div className="login-card">
-          {/* 成功提示 */}
           {successAlert.visible && (
-            <div style={{ marginBottom: '16px' }}>
-              <Alert
-                message={successAlert.message}
-                type="success"
-                icon={<CheckCircleOutlined />}
-                showIcon
-                closable
-                onClose={() => setSuccessAlert({ visible: false, message: '' })}
-                style={{
-                  borderRadius: '8px',
-                  border: '1px solid #b7eb8f',
-                  backgroundColor: '#f6ffed'
-                }}
-              />
-            </div>
+            <Alert
+              message={successAlert.message}
+              type="success"
+              icon={<CheckCircleOutlined />}
+              closable
+              style={{ marginBottom: 16, borderRadius: 8 }}
+            />
           )}
-          
           <div className="login-header">
-            <h1 className="login-title">欢迎来到小红书</h1>
-            <p className="login-subtitle">标记我的生活</p>
+            <h1>欢迎来到小红书</h1>
+            <p>标记我的生活</p>
           </div>
-
           <form className="login-form" onSubmit={handleSubmit}>
             <div className="form-group">
               <Input
                 type="email"
-                id="email"
-                name="email"
-                className={`form-input ${errors.email ? 'input-error' : ''}`}
-                placeholder="请输入您的邮箱"
+                placeholder="邮箱"
                 value={formData.email}
                 onChange={handleEmailChange}
                 prefix={<MailOutlined />}
-                size="large"
-                title=""
                 status={errors.email ? 'error' : ''}
               />
-              {errors.email && (
-                <div className="error-message">
-                  {errors.email}
-                </div>
-              )}
+              {errors.email && <div className="error-message">{errors.email}</div>}
             </div>
-
             <div className="form-group">
               <Input.Password
-                id="password"
-                name="password"
-                className={`form-input ${errors.password ? 'input-error' : ''}`}
-                placeholder="请输入您的密码"
+                placeholder="密码"
                 value={formData.password}
                 onChange={handlePasswordChange}
                 prefix={<LockOutlined />}
-                size="large"
-                title=""
                 status={errors.password ? 'error' : ''}
               />
-              {errors.password && (
-                <div className="error-message">
-                  {errors.password}
-                </div>
-              )}
+              {errors.password && <div className="error-message">{errors.password}</div>}
             </div>
-
             <div className="form-options">
-              <Checkbox 
-                checked={rememberMe}
-                onChange={handleRememberMeChange}
-              >
+              <Checkbox checked={rememberMe} onChange={handleRememberMeChange}>
                 记住我
               </Checkbox>
-              <Link to="/forgot-password" className="forgot-password">忘记密码?</Link>
+              <Link to="/forgot-password">忘记密码?</Link>
             </div>
-
             <button
               type="submit"
               className={`login-button ${isLoading ? 'loading' : ''}`}
               disabled={isLoading}
             >
-              {isLoading ? (
-                <>
-                  <div className="loading-spinner"></div>
-                  登录中...
-                </>
-              ) : (
-                '登录'
-              )}
+              {isLoading ? '登录中...' : '登录'}
             </button>
           </form>
-
           <div className="signup-link">
-            <p>还没有账户? <Link to="/register">立即注册</Link></p>
+            <p>还没有账户?<Link to="/register">立即注册</Link></p>
           </div>
         </div>
       </div>
-
-      {/* 错误弹窗 */}
       <Modal
-        title={
-          <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
-            <ExclamationCircleOutlined style={{ color: '#ff4d4f', fontSize: '18px' }} />
-            {errorModal.title}
-          </div>
-        }
+        title={<><ExclamationCircleOutlined style={{ color: '#ff4d4f' }} /> {errorModal.title}</>}
         open={errorModal.visible}
         onOk={closeErrorModal}
-        onCancel={closeErrorModal}
-        okText="我知道了"
         cancelButtonProps={{ style: { display: 'none' } }}
-        centered
-        className="error-modal"
       >
-        <div style={{ padding: '16px 0', fontSize: '14px', lineHeight: '1.6' }}>
-          {errorModal.content}
-        </div>
+        <p>{errorModal.content}</p>
       </Modal>
     </div>
-  );
-};
-
-export default LoginPage;
+  )
+}
diff --git a/Merge/front/src/router/App.js b/Merge/front/src/router/App.js
index d91b3b7..d7f5f09 100644
--- a/Merge/front/src/router/App.js
+++ b/Merge/front/src/router/App.js
@@ -1,72 +1,86 @@
-import React from 'react';
+// src/router/index.jsx
+import React from 'react'
+import { Routes, Route, Navigate } from 'react-router-dom'
+
+import LoginPage          from '../pages/LoginPage/LoginPage'
+import RegisterPage       from '../pages/RegisterPage/RegisterPage'
+import ForgotPasswordPage from '../pages/ForgotPasswordPage/ForgotPasswordPage'
+import TestDashboard      from '../pages/TestDashboard/TestDashboard'
+
+import HomeFeed           from '../components/HomeFeed'
+import CreatePost         from '../components/CreatePost'
+import NotebookPage       from '../components/NotebookPage'
+import PlaceholderPage    from '../components/PlaceholderPage'
+import UserProfile        from '../components/UserProfile'
+
+import AdminPage          from '../components/Admin'
+import SuperAdmin         from '../components/SuperAdmin'
+import UserManagement     from '../components/UserManagement'
+import LogsDashboard      from '../components/LogsDashboard'
+import TransactionLogs    from '../components/TransactionLogs'
+import PerformanceLogs    from '../components/PerformanceLogs'
+
 import {
-  Routes,
-  Route,
-  Navigate,
-} from 'react-router-dom';
-import AdminPage from '../components/Admin';
-import UserManagement from '../components/UserManagement';
-import LogsDashboard from '../components/LogsDashboard';
-import SuperAdmin from '../components/SuperAdmin';
-
-import CreatePost     from '../components/CreatePost'      // src/components/CreatePost.jsx
-import HomeFeed       from '../components/HomeFeed'        // src/components/HomeFeed.jsx
-import PlaceholderPage from '../components/PlaceholderPage'// src/components/PlaceholderPage.jsx
-import UploadPage     from '../components/UploadPage'      // src/components/UploadPage.jsx
-
-import UserProfile from '../components/UserProfile'; // src/components/UserProfileRoute.jsx
-
-import LoginPage from '../pages/LoginPage/LoginPage';
-import RegisterPage from '../pages/RegisterPage/RegisterPage';
-import ForgotPasswordPage from '../pages/ForgotPasswordPage/ForgotPasswordPage';
-import TestDashboard from '../pages/TestDashboard/TestDashboard';
-
-import TransactionLogs from '../components/TransactionLogs';
-import PerformanceLogs from '../components/PerformanceLogs';
-import NotebookPage    from '../components/NotebookPage'
+  RequireAuth,
+  RequireRole,
+  RequireOwnProfile,
+  RequireAdminOwn,
+  RequireSuperAdminOwn
+} from './Guards'
 
 export default function AppRoutes() {
   return (
     <Routes>
-      <Route path="/posts/new" element={<CreatePost />} />
-    
-      <Route path="/home"      element={<HomeFeed />} />
-
-      <Route path="/notebooks" element={<NotebookPage />} />
-      <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="/user/:userId" element={<UserProfile />} />
-      <Route path="/dashboard/*" element={<UploadPage />} />
-
-      {/* 根路径重定向到 dashboard */}
-      {/* <Route path="/" element={<Navigate to="/dashboard/overview" replace />} /> */}
-
-      <Route path="/" element={<LoginPage />} />
-      <Route path="/login" element={<LoginPage />} />
-      <Route path="/register" element={<RegisterPage />} />
+      {/* 1. 公开路由 */}
+      <Route path="/login"           element={<LoginPage />} />
+      <Route path="/register"        element={<RegisterPage />} />
       <Route path="/forgot-password" element={<ForgotPasswordPage />} />
-      <Route path="/test-dashboard" element={<TestDashboard />} />
 
-      {/* 普通管理员,无 header */}
-      <Route path="admin" element={<AdminPage />} />
+      {/* 2. 受保护路由 */}
+      <Route element={<RequireAuth />}>
+        {/* 2.1 任何登录用户都能看自己的主页 */}
+        <Route element={<RequireOwnProfile />}>
+          <Route path="/user/:userId" element={<UserProfile />} />
+        </Route>
 
-      {/* 超级管理员,只用 SuperAdminLayout */}
-      <Route path="superadmin" element={<SuperAdmin />}>
-        <Route index element={<Navigate to="users" replace />} />
-        <Route path="users" element={<UserManagement superAdminId={3} />} />
+        {/* 2.2 普通用户 */}
+        <Route element={<RequireRole allowedRoles={['user']} />}>
+          <Route path="/home"               element={<HomeFeed />} />
+          <Route path="/posts/new"          element={<CreatePost />} />
+          <Route path="/posts/edit/:postId" element={<CreatePost />} />
+          <Route path="/notebooks"          element={<NotebookPage />} />
+          <Route path="/dashboard/*"        element={<PlaceholderPage />} />
+          <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="/"                   element={<Navigate to="/home" replace />} />
+        </Route>
 
-        {/* dashboard as layout */}
-        <Route path="dashboard" element={<LogsDashboard />}>
-          <Route index element={<Navigate to="transactions" replace />} />
-          <Route path="transactions" element={<TransactionLogs userId={1} />} />
-          <Route path="performance" element={<PerformanceLogs userId={1} />} />
+        {/* 2.3 Admin 自己的页面 */}
+        <Route element={<RequireAdminOwn />}>
+          <Route path="/admin/:userId" element={<AdminPage />} />
+        </Route>
+        <Route element={<RequireRole allowedRoles={['admin']} />}>
+          <Route path="/test-dashboard" element={<TestDashboard />} />
+        </Route>
+
+        {/* 2.4 SuperAdmin 自己的区域 */}
+        <Route element={<RequireSuperAdminOwn />}>
+          <Route path="/superadmin/:userId/*" element={<SuperAdmin />}>
+            <Route index element={<Navigate to="users" replace />} />
+            <Route path="users"     element={<UserManagement />} />
+            <Route path="dashboard" element={<LogsDashboard />}>
+              <Route index element={<Navigate to="transactions" replace />} />
+              <Route path="transactions" element={<TransactionLogs />} />
+              <Route path="performance"  element={<PerformanceLogs />} />
+            </Route>
+          </Route>
         </Route>
       </Route>
 
-      {/* 最后一个兜底,放在最末尾 */}
-      <Route path="*" element={<PlaceholderPage pageId="home" />} />
+      {/* 3. 兜底:未匹配一律回登录 */}
+      <Route path="*" element={<Navigate to="/login" replace />} />
     </Routes>
-  );
-}
\ No newline at end of file
+  )
+}
diff --git a/Merge/front/src/router/Guards.jsx b/Merge/front/src/router/Guards.jsx
new file mode 100644
index 0000000..fe45e30
--- /dev/null
+++ b/Merge/front/src/router/Guards.jsx
@@ -0,0 +1,53 @@
+// src/router/Guards.jsx
+import React from 'react'
+import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom'
+import { getUserInfo } from '../utils/auth'
+
+/** 需登录 */
+export function RequireAuth() {
+  const user = getUserInfo()
+  const location = useLocation()
+  if (!user) {
+    return <Navigate to="/login" state={{ from: location }} replace />
+  }
+  return <Outlet />
+}
+
+/** 需特定角色 */
+export function RequireRole({ allowedRoles }) {
+  const user = getUserInfo()
+  if (!user || !allowedRoles.includes(user.role)) {
+    return <Navigate to="/login" replace />
+  }
+  return <Outlet />
+}
+
+/** 只能访问自己的用户详情 */
+export function RequireOwnProfile() {
+  const user = getUserInfo()
+  const { userId } = useParams()
+  if (!user || user.id.toString() !== userId) {
+    return <Navigate to="/home" replace />
+  }
+  return <Outlet />
+}
+
+/** 只能访问自己的 Admin 页面 */
+export function RequireAdminOwn() {
+  const user = getUserInfo()
+  const { userId } = useParams()
+  if (!user || user.role !== 'admin' || user.id.toString() !== userId) {
+    return <Navigate to="/login" replace />
+  }
+  return <Outlet />
+}
+
+/** 只能访问自己的 SuperAdmin 区 */
+export function RequireSuperAdminOwn() {
+  const user = getUserInfo()
+  const { userId } = useParams()
+  if (!user || user.role !== 'superadmin' || user.id.toString() !== userId) {
+    return <Navigate to="/login" replace />
+  }
+  return <Outlet />
+}
diff --git a/WZY/xhs_front/src/router/index.jsx b/WZY/xhs_front/src/router/index.jsx
index fd959b9..225a714 100644
--- a/WZY/xhs_front/src/router/index.jsx
+++ b/WZY/xhs_front/src/router/index.jsx
@@ -5,7 +5,6 @@
 import CreatePost      from '../components/CreatePost'
 import HomeFeed        from '../components/HomeFeed'
 import NotebookPage    from '../components/NotebookPage'
-import UploadPage      from '../components/UploadPage'
 import PlaceholderPage from '../components/PlaceholderPage'
 
 export default function AppRouter() {