修改前端gpu显示页面

Change-Id: I98e2c0b9dd775f6e7c61c294808666ff7c23f224
diff --git a/Merge/back_wzy/__pycache__/config.cpython-310.pyc b/Merge/back_wzy/__pycache__/config.cpython-310.pyc
index f508f8f..c3119cc 100644
--- a/Merge/back_wzy/__pycache__/config.cpython-310.pyc
+++ b/Merge/back_wzy/__pycache__/config.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc b/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc
index 19bfef0..6655141 100644
--- a/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc
+++ b/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/posts.py b/Merge/back_wzy/routes/posts.py
index 6fd2a89..4c89334 100644
--- a/Merge/back_wzy/routes/posts.py
+++ b/Merge/back_wzy/routes/posts.py
@@ -5,12 +5,39 @@
 from models.post   import Post
 from models.behavior import Behavior
 from utils.Fpost import Fpost
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from config import Config
 import json
 
 posts_bp = Blueprint('posts', __name__)
 
+def safe_log(user_id, log_type, message, ip):
+    user_id=1
+    """安全的日志记录函数,不会影响主业务逻辑"""
+    try:
+        engine = create_engine(Config.SQLURL)
+        SessionLocal = sessionmaker(bind=engine)
+        session = SessionLocal()
+        f = Fpost(session)
+        f.recordlog(user_id, log_type, message, ip)
+    except Exception as e:
+        # 方法一:简单打印错误信息
+        print(f"[safe_log] 记录日志失败:{e}")
+        traceback.print_exc()  # 打印完整的堆栈跟踪
+
+        # 方法二:使用 logging 模块(推荐)
+        logger.exception("safe_log: 记录日志时发生异常")
+    finally:
+        # 确保 session 一定关闭
+        try:
+            session.close()
+        except Exception:
+            pass
+
 @posts_bp.route('', methods=['POST'])
 def create_post():
+    user_id = None
     try:
         # 获取文本字段
         user_id = request.form.get('user_id')
@@ -21,6 +48,7 @@
         media_count = int(request.form.get('media_count', 0))
         
         if not user_id or not title or not content:
+            safe_log(int(user_id) if user_id else 0, 'error', '创建帖子失败:缺少必要字段', request.remote_addr)
             return jsonify({'error': '缺少必要字段'}), 400
         
         # 获取上传的文件
@@ -41,9 +69,11 @@
             files=files
         )
         
+        safe_log(int(user_id), 'behavior', f'成功创建帖子,帖子ID: {new_post.id},标题: {title}', request.remote_addr)
         return jsonify({'id': new_post.id}), 201
         
     except Exception as e:
+        safe_log(int(user_id) if user_id else 0, 'error', f'创建帖子时发生异常: {str(e)}', request.remote_addr)
         return jsonify({'error': str(e)}), 500
 
 @posts_bp.route('', methods=['GET'])
@@ -53,38 +83,56 @@
       - GET /posts              返回所有已发布帖子
       - GET /posts?user_id=123  返回指定用户 user_id 的所有帖子
     """
-    user_id = request.args.get('user_id', type=int)
-    query = Post.query
-    if user_id is not None:
-        query = query.filter_by(user_id=user_id)
-    else:
-        query = query.filter_by(status='published')
+    user_id = None
+    try:
+        user_id = request.args.get('user_id', type=int)
+        query = Post.query
+        if user_id is not None:
+            query = query.filter_by(user_id=user_id)
+        else:
+            query = query.filter_by(status='published')
 
-    posts = query.all()
+        posts = query.all()
+        
+        log_msg = f'获取帖子列表成功,共{len(posts)}个帖子'
+        if user_id:
+            log_msg += f',用户ID: {user_id}'
+        safe_log(user_id if user_id else 0, 'access', log_msg, request.remote_addr)
 
-    return jsonify([{
-        'id': p.id,
-        'title': p.title,
-        'status': p.status,                     # 新增 status 字段
-        'heat': p.heat,
-        'created_at': p.created_at.isoformat()
-    } for p in posts])
+        return jsonify([{
+            'id': p.id,
+            'title': p.title,
+            'status': p.status,
+            'heat': p.heat,
+            'created_at': p.created_at.isoformat()
+        } for p in posts])
+        
+    except Exception as e:
+        safe_log(user_id if user_id else 0, 'error', f'获取帖子列表时发生异常: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
 
 @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,
-        'topic_id': post.topic_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()
-    })
+    try:
+        post = Post.query.get_or_404(post_id)
+        safe_log(0, 'access', f'获取帖子详情成功,帖子ID: {post_id},标题: {post.title}', request.remote_addr)
+        
+        return jsonify({
+            'id': post.id,
+            'user_id': post.user_id,
+            'topic_id': post.topic_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()
+        })
+        
+    except Exception as e:
+        safe_log(0, 'error', f'获取帖子详情时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
 
 @posts_bp.route('/<int:post_id>', methods=['PUT'])
 def update_post(post_id):
@@ -142,19 +190,28 @@
             updated_post = post
         
         if not updated_post:
+            safe_log(0, 'error', f'更新帖子失败,帖子不存在,帖子ID: {post_id}', request.remote_addr)
             return jsonify({'error': '帖子不存在'}), 404
-            
+        
+        safe_log(0, 'behavior', f'更新帖子成功,帖子ID: {post_id}', request.remote_addr)
         return '', 204
         
     except Exception as e:
+        safe_log(0, 'error', f'更新帖子时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr)
         return jsonify({'error': str(e)}), 500
 
 @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
+    try:
+        post = Post.query.get_or_404(post_id)
+        db.session.delete(post)
+        db.session.commit()
+        safe_log(0, 'behavior', f'删除帖子成功,帖子ID: {post_id}', request.remote_addr)
+        return '', 204
+        
+    except Exception as e:
+        safe_log(0, 'error', f'删除帖子时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
 
 @posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
 def post_action(post_id, action):
@@ -162,76 +219,105 @@
     支持的 action: like, favorite, view, share
     对于 like 和 favorite,保证每个用户每帖只做一次。
     """
-    if action not in ('like', 'favorite', 'view', 'share'):
-        abort(400, 'Invalid action')
+    user_id = None
+    try:
+        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')
+        data = request.get_json() or {}
+        user_id = data.get('user_id')
+        if not user_id:
+            safe_log(0, 'error', f'执行帖子操作失败,缺少用户ID,帖子ID: {post_id},操作: {action}', request.remote_addr)
+            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
+        # 对 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:
+                safe_log(user_id, 'error', f'重复执行帖子操作,帖子ID: {post_id},操作: {action}', request.remote_addr)
+                return jsonify({'error': f'already {action}d'}), 400
 
-    # 创建行为记录
-    beh = Behavior(user_id=user_id, post_id=post_id, type=action)
-    db.session.add(beh)
+        # 创建行为记录
+        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
+        # 更新热度
+        post = Post.query.get_or_404(post_id)
+        post.heat += 1
 
-    db.session.commit()
-    return '', 201
+        db.session.commit()
+        safe_log(user_id, 'behavior', f'执行帖子操作成功,帖子ID: {post_id},操作: {action}', request.remote_addr)
+        return '', 201
+        
+    except Exception as e:
+        safe_log(user_id if user_id else 0, 'error', f'执行帖子操作时发生异常,帖子ID: {post_id},操作: {action},错误: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
 
 @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
+    user_id = None
+    try:
+        user_id = request.get_json(silent=True) and request.get_json().get('user_id')
+        if not user_id:
+            safe_log(0, 'error', f'取消点赞失败,缺少用户ID,帖子ID: {post_id}', request.remote_addr)
+            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:
+            safe_log(user_id, 'error', f'取消点赞失败,用户尚未点赞,帖子ID: {post_id}', request.remote_addr)
+            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
+        db.session.delete(beh)
+        # 更新热度,确保不降到负数
+        post = Post.query.get_or_404(post_id)
+        post.heat = max(post.heat - 1, 0)
+        db.session.commit()
+        safe_log(user_id, 'behavior', f'取消点赞成功,帖子ID: {post_id}', request.remote_addr)
+        return '', 204
+        
+    except Exception as e:
+        safe_log(user_id if user_id else 0, 'error', f'取消点赞时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
 
 @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
+    user_id = None
+    try:
+        user_id = request.get_json(silent=True) and request.get_json().get('user_id')
+        if not user_id:
+            safe_log(0, 'error', f'取消收藏失败,缺少用户ID,帖子ID: {post_id}', request.remote_addr)
+            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:
+            safe_log(user_id, 'error', f'取消收藏失败,用户尚未收藏,帖子ID: {post_id}', request.remote_addr)
+            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
+        db.session.delete(beh)
+        # 更新热度
+        post = Post.query.get_or_404(post_id)
+        post.heat = max(post.heat - 1, 0)
+        db.session.commit()
+        safe_log(user_id, 'behavior', f'取消收藏成功,帖子ID: {post_id}', request.remote_addr)
+        return '', 204
+        
+    except Exception as e:
+        safe_log(user_id if user_id else 0, 'error', f'取消收藏时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
 
 @posts_bp.route('/<int:post_id>/like/status', methods=['GET'])
 def has_liked(post_id):
@@ -240,14 +326,22 @@
     GET /posts/<post_id>/like/status?user_id=123
     返回 { "liked": true } 或 { "liked": false }
     """
-    user_id = request.args.get('user_id', type=int)
-    if not user_id:
-        abort(400, 'user_id required')
+    user_id = None
+    try:
+        user_id = request.args.get('user_id', type=int)
+        if not user_id:
+            safe_log(0, 'error', f'检查点赞状态失败,缺少用户ID,帖子ID: {post_id}', request.remote_addr)
+            abort(400, 'user_id required')
 
-    exists = Behavior.query.filter_by(
-        user_id=user_id,
-        post_id=post_id,
-        type='like'
-    ).first() is not None
-
-    return jsonify({'liked': exists}), 200
+        exists = Behavior.query.filter_by(
+            user_id=user_id,
+            post_id=post_id,
+            type='like'
+        ).first() is not None
+        
+        safe_log(user_id, 'access', f'检查点赞状态成功,帖子ID: {post_id},结果: {exists}', request.remote_addr)
+        return jsonify({'liked': exists}), 200
+        
+    except Exception as e:
+        safe_log(user_id if user_id else 0, 'error', f'检查点赞状态时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr)
+        return jsonify({'error': str(e)}), 500
diff --git a/Merge/front/src/api/posts_trm.js b/Merge/front/src/api/posts_trm.js
index 8f7e877..2c0fc14 100644
--- a/Merge/front/src/api/posts_trm.js
+++ b/Merge/front/src/api/posts_trm.js
@@ -218,7 +218,11 @@
  * @returns Promise<[ {id, gpu_id, gpu_usage, gpu_memory_usage, timestamp}, … ]>
  */
 export async function fetchGpuUsage(limit = 100) {
-  const token = localStorage.getItem('token')
+  const token = getAuthToken()
+  if (!token || token === 'null') {
+    throw new Error('Token not found or invalid. Please login again.')
+  }
+  
   const res = await fetch(`http://10.126.59.25:8082/gpu-usage?limit=${limit}`, {
     method: 'GET',
     headers: { 
diff --git a/Merge/front/src/components/PerformanceLogs.js b/Merge/front/src/components/PerformanceLogs.js
index 67518de..f0f3d9f 100644
--- a/Merge/front/src/components/PerformanceLogs.js
+++ b/Merge/front/src/components/PerformanceLogs.js
@@ -18,6 +18,12 @@
     const fetchSystemData = fetchSysCost(userId)
       .then(result => {
         // 检查是否是权限错误
+        if (typeof result === 'string' && result.startsWith('<!DOCTYPE')) {
+          // 返回的是 HTML,说明未登录或接口错误
+          setUnauthorized(true);
+          setData([]);
+          return;
+        }
         if (result && result.status === 'error' && result.message === 'Unauthorized') {
           setUnauthorized(true);
           setData([]);
@@ -57,6 +63,11 @@
     // 获取GPU数据
     const fetchGpuData = fetchGpuUsage(100)
       .then(result => {
+        if (typeof result === 'string' && result.startsWith('<!DOCTYPE')) {
+          // 返回的是 HTML,说明未登录或接口错误
+          setGpuData([]);
+          return;
+        }
         console.log('GPU data:', result);
         const processedData = processGpuData(result);
         setGpuData(processedData);
@@ -180,7 +191,7 @@
             />
             <YAxis domain={[0, 100]} label={{ value: '使用率 (%)', angle: -90, position: 'insideLeft' }} />
             <Tooltip 
-              formatter={(val, name) => [`${val?.toFixed(2)}%`, name]}
+              formatter={(val, name) => [`${val != null && typeof val === 'number' ? val.toFixed(2) : val}%`, name]}
               labelFormatter={ts => new Date(ts).toLocaleString()}
             />
             <Legend />
@@ -212,7 +223,7 @@
             />
             <YAxis domain={[0, 'auto']} label={{ value: '内存 (MB)', angle: -90, position: 'insideLeft' }} />
             <Tooltip 
-              formatter={(val, name) => [`${val?.toFixed(2)} MB`, name]}
+              formatter={(val, name) => [`${val != null && typeof val === 'number' ? val.toFixed(2) : val} MB`, name]}
               labelFormatter={ts => new Date(ts).toLocaleString()}
             />
             <Legend />