更新路由守卫

Change-Id: Iddd1d006202a03e8a97e3a90d64d9a43c5d2cb78
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>
-  );
+)
 }