From 1ae955be732378cff1b5e425be734390a23504bd Mon Sep 17 00:00:00 2001 From: nanako <469449812@qq.com> Date: Tue, 11 Nov 2025 14:46:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=97=A5=E5=BF=97=E6=B8=85?= =?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/handlers.go | 58 +++++++++++ backend/main.go | 1 + frontend/src/features/logs/api/index.js | 13 +++ .../logs/components/RequestLogList.jsx | 97 ++++++++++++++++++- frontend/src/features/logs/index.jsx | 9 +- 5 files changed, 170 insertions(+), 8 deletions(-) diff --git a/backend/api/handlers.go b/backend/api/handlers.go index de8afb6..883740e 100644 --- a/backend/api/handlers.go +++ b/backend/api/handlers.go @@ -392,3 +392,61 @@ func (h *APIHandler) GetRequestLogStatsHandler(c *gin.Context) { "backend_model_stats": backendModelStats, }) } + +// ClearRequestLogsHandler 清空请求日志 +func (h *APIHandler) ClearRequestLogsHandler(c *gin.Context) { + // 获取查询参数 + olderThan := c.Query("older_than") // 清空多少天前的日志 + + var startTime time.Time + if olderThan != "" { + // 解析天数 + var days int + if _, err := fmt.Sscanf(olderThan, "%d", &days); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid older_than parameter, must be a number representing days"}) + return + } + + if days < 0 { + c.JSON(http.StatusBadRequest, gin.H{"error": "older_than must be 0 or greater"}) + return + } + + // 如果是0天,要删除所有日志,不需要时间限制 + if days == 0 { + // 执行删除所有日志的操作 + result := h.DB.Where("1 = 1").Delete(&models.RequestLog{}) + if result.Error != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to clear logs"}) + return + } + + // 返回删除的记录数 + c.JSON(http.StatusOK, gin.H{ + "message": "All logs cleared successfully", + "deleted_count": result.RowsAffected, + "older_than_days": olderThan, + }) + return + } + + startTime = time.Now().AddDate(0, 0, -days) + } else { + // 如果没有指定天数,默认清空30天前的日志 + startTime = time.Now().AddDate(0, 0, -30) + } + + // 执行删除操作 + result := h.DB.Where("created_at < ?", startTime).Delete(&models.RequestLog{}) + if result.Error != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to clear logs"}) + return + } + + // 返回删除的记录数 + c.JSON(http.StatusOK, gin.H{ + "message": "Logs cleared successfully", + "deleted_count": result.RowsAffected, + "older_than_days": olderThan, + }) +} diff --git a/backend/main.go b/backend/main.go index 548a49b..092b856 100644 --- a/backend/main.go +++ b/backend/main.go @@ -82,6 +82,7 @@ func main() { api_.GET("/logs", handler.GetRequestLogsHandler) api_.GET("/logs/stats", handler.GetRequestLogStatsHandler) api_.GET("/logs/:id", handler.GetRequestLogDetailHandler) + api_.DELETE("/logs", handler.ClearRequestLogsHandler) } // 启动HTTP服务器 diff --git a/frontend/src/features/logs/api/index.js b/frontend/src/features/logs/api/index.js index f994826..6e0db33 100644 --- a/frontend/src/features/logs/api/index.js +++ b/frontend/src/features/logs/api/index.js @@ -31,4 +31,17 @@ export const getLogDetail = async (id) => { console.error('获取日志详情失败:', error); throw new Error(error.response?.data?.error || '获取日志详情失败'); } +}; + +// 清空日志 +export const clearLogs = async (olderThanDays = 30) => { + try { + const response = await apiClient.delete('/api/logs', { + params: { older_than: olderThanDays } + }); + return response.data; + } catch (error) { + console.error('清空日志失败:', error); + throw new Error(error.response?.data?.error || '清空日志失败'); + } }; \ No newline at end of file diff --git a/frontend/src/features/logs/components/RequestLogList.jsx b/frontend/src/features/logs/components/RequestLogList.jsx index 9f9f936..adb2f4a 100644 --- a/frontend/src/features/logs/components/RequestLogList.jsx +++ b/frontend/src/features/logs/components/RequestLogList.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef } from 'react'; -import { getRequestLogs, getRequestLogStats } from '../api'; +import { getRequestLogs, getRequestLogStats, clearLogs } from '../api'; import RequestLogDetailModal from './RequestLogDetailModal'; // 自定义防抖 Hook @@ -29,6 +29,9 @@ const RequestLogList = () => { const [totalPages, setTotalPages] = useState(1); const [selectedLog, setSelectedLog] = useState(null); const [showDetailModal, setShowDetailModal] = useState(false); + const [showClearModal, setShowClearModal] = useState(false); + const [clearingLogs, setClearingLogs] = useState(false); + const [clearDays, setClearDays] = useState(30); // 筛选条件 const [filters, setFilters] = useState({ @@ -91,6 +94,29 @@ const RequestLogList = () => { setShowDetailModal(true); }; + const handleClearLogs = async () => { + try { + setClearingLogs(true); + const result = await clearLogs(clearDays); + + // 显示成功消息 + setError(null); + alert(`成功清空 ${result.deleted_count} 条 ${clearDays} 天前的日志记录`); + + // 刷新日志列表和统计 + fetchLogs(); + fetchStats(); + + // 关闭模态框 + setShowClearModal(false); + } catch (err) { + setError(err.message || '清空日志失败'); + console.error('Error clearing logs:', err); + } finally { + setClearingLogs(false); + } + }; + const formatDate = (dateString) => { if (!dateString) return 'N/A'; const date = new Date(dateString); @@ -119,6 +145,17 @@ const RequestLogList = () => { return (
+ {/* 页面标题和操作按钮 */} +
+

请求日志

+ +
+ {/* 统计信息卡片 */} {stats && (
@@ -310,6 +347,64 @@ const RequestLogList = () => { isOpen={showDetailModal} onClose={() => setShowDetailModal(false)} /> + + {/* 清空日志确认模态框 */} + {showClearModal && ( +
+
+

清空日志确认

+ +
+ +
+ { + const value = e.target.value; + if (value === '' || value === null) return; + const numValue = parseInt(value); + if (!isNaN(numValue) && numValue >= 0) { + setClearDays(numValue); + } + }} + className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-red-500" + /> + + {clearDays === 0 ? '所有日志' : '天前'} + +
+

+ {clearDays === 0 + ? '警告:此操作将永久删除所有日志记录,无法恢复。' + : `此操作将永久删除 ${clearDays} 天以前的日志记录,无法恢复。` + } +

+
+ +
+ + +
+
+
+ )}
); }; diff --git a/frontend/src/features/logs/index.jsx b/frontend/src/features/logs/index.jsx index ca28c7b..df8f690 100644 --- a/frontend/src/features/logs/index.jsx +++ b/frontend/src/features/logs/index.jsx @@ -3,13 +3,8 @@ import RequestLogList from './components/RequestLogList'; const LogsPage = () => { return ( -
-
-

请求日志

-
-
- -
+
+
); };