diff --git a/backend/cmd/main.go b/backend/cmd/main.go
index 9393f1e..b6dd95f 100644
--- a/backend/cmd/main.go
+++ b/backend/cmd/main.go
@@ -104,8 +104,9 @@ func startServer(cfg *config.Config) {
// 日志 API
mux.HandleFunc("/api/logs", api.CORS(handleGetLogs))
mux.HandleFunc("/api/logs/clear", api.CORS(handleClearLogs))
- mux.HandleFunc("/api/logs/query", api.CORS(handleQueryLogs)) // 按模块查询日志
- mux.HandleFunc("/api/logs/stream", handleLogStream) // SSE 实时日志
+ mux.HandleFunc("/api/logs/clear-module", api.CORS(handleClearLogsByModule)) // 按模块清除日志
+ mux.HandleFunc("/api/logs/query", api.CORS(handleQueryLogs)) // 按模块查询日志
+ mux.HandleFunc("/api/logs/stream", handleLogStream) // SSE 实时日志
// S2A 代理 API
mux.HandleFunc("/api/s2a/test", api.CORS(handleS2ATest))
@@ -296,6 +297,26 @@ func handleClearLogs(w http.ResponseWriter, r *http.Request) {
api.Success(w, map[string]string{"message": "日志已清空"})
}
+// handleClearLogsByModule POST /api/logs/clear-module?module=cleaner
+func handleClearLogsByModule(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ api.Error(w, http.StatusMethodNotAllowed, "仅支持 POST")
+ return
+ }
+
+ module := r.URL.Query().Get("module")
+ if module == "" {
+ api.Error(w, http.StatusBadRequest, "缺少 module 参数")
+ return
+ }
+
+ cleared := logger.ClearLogsByModule(module)
+ api.Success(w, map[string]interface{}{
+ "message": fmt.Sprintf("已清除 %d 条 %s 日志", cleared, module),
+ "cleared": cleared,
+ })
+}
+
// handleQueryLogs GET /api/logs/query?module=cleaner&page=1&page_size=5
func handleQueryLogs(w http.ResponseWriter, r *http.Request) {
module := r.URL.Query().Get("module")
diff --git a/backend/internal/api/error_cleaner.go b/backend/internal/api/error_cleaner.go
index 1320a74..53e4777 100644
--- a/backend/internal/api/error_cleaner.go
+++ b/backend/internal/api/error_cleaner.go
@@ -89,13 +89,10 @@ func checkAndCleanErrors() {
}
if len(errorAccounts) == 0 {
- logger.Info("没有错误账号需要清理", "", "cleaner")
lastCleanTime = time.Now()
return
}
- logger.Info(fmt.Sprintf("找到 %d 个错误账号,开始删除...", len(errorAccounts)), "", "cleaner")
-
success := 0
failed := 0
@@ -106,7 +103,6 @@ func checkAndCleanErrors() {
logger.Warning(fmt.Sprintf("删除账号失败: ID=%d, Email=%s, Error=%v", account.ID, account.Email, err), account.Email, "cleaner")
} else {
success++
- logger.Success(fmt.Sprintf("删除账号成功: ID=%d, Email=%s", account.ID, account.Email), account.Email, "cleaner")
}
}
diff --git a/backend/internal/logger/logger.go b/backend/internal/logger/logger.go
index eba6bb1..f7ad706 100644
--- a/backend/internal/logger/logger.go
+++ b/backend/internal/logger/logger.go
@@ -242,3 +242,22 @@ func ClearLogs() {
defer logsMu.Unlock()
logs = make([]LogEntry, 0, 1000)
}
+
+// ClearLogsByModule 按模块清除日志
+func ClearLogsByModule(module string) int {
+ logsMu.Lock()
+ defer logsMu.Unlock()
+
+ // 过滤掉指定模块的日志
+ var newLogs []LogEntry
+ cleared := 0
+ for _, log := range logs {
+ if log.Module != module {
+ newLogs = append(newLogs, log)
+ } else {
+ cleared++
+ }
+ }
+ logs = newLogs
+ return cleared
+}
diff --git a/frontend/src/components/LiveLogViewer.tsx b/frontend/src/components/LiveLogViewer.tsx
index 1b30317..2004e15 100644
--- a/frontend/src/components/LiveLogViewer.tsx
+++ b/frontend/src/components/LiveLogViewer.tsx
@@ -131,8 +131,22 @@ export default function LiveLogViewer({
}
}
- const handleClear = () => {
- setLogs([])
+ const handleClear = async () => {
+ if (!confirm('确定要清空所有日志吗?此操作不可撤销。')) {
+ return
+ }
+ try {
+ const res = await fetch('/api/logs/clear', { method: 'POST' })
+ const data = await res.json()
+ if (data.code === 0) {
+ setLogs([])
+ pausedLogsRef.current = []
+ } else {
+ alert('清空日志失败: ' + (data.message || '未知错误'))
+ }
+ } catch (e) {
+ alert('清空日志失败: ' + (e instanceof Error ? e.message : '网络错误'))
+ }
}
return (
@@ -161,8 +175,8 @@ export default function LiveLogViewer({
diff --git a/frontend/src/pages/Cleaner.tsx b/frontend/src/pages/Cleaner.tsx
index 60faa02..b32bc4e 100644
--- a/frontend/src/pages/Cleaner.tsx
+++ b/frontend/src/pages/Cleaner.tsx
@@ -396,6 +396,31 @@ export default function Cleaner() {
共 {logTotal} 条
+