feat(audit): F1+F2 告警静默规则标记完成 + 审计日志CSV导出实现

F1 告警静默规则 [done]:
- 后端 alert_silence.go: CRUD + Toggle (onetime/daily/weekly 三模式)
- 告警引擎 isSilenced 集成 (alert_engine.go)
- 前端 SilenceRuleTab + SilenceDialog
- 路由 /alerts/silences 已注册

F2 审计日志导出 [done]:
- 重写 ExportAuditLogs: 真正的 CSV 导出 (encoding/csv + UTF-8 BOM)
- 支持 module/action/username/startTime/endTime 筛选
- 导出限制 10000 条防溢出,自动记录审计日志
- JSON 格式向后兼容 (format=json)
- 前端 exportLogs 传递查询参数

同时包含累积的前期工作:
- 目录重构 internal/ -> controller/model/router (v0.55-v0.57)
- 后端分层架构 dto/repository/service/utils
- 审计模块全功能 (终端审计/操作审计/登录日志)
- asciicast v2 录制格式
- SFTP 文件浏览器
- StatStrip 紧凑统计条
- 在线会话自动刷新
- LiveMonitor WebSocket 诊断修复

验证: go build ✅ | npm run build ✅ | Docker 部署 ✅ | 10 回归端点 ✅ | CSV 导出 ✅ | 静默 CRUD ✅
This commit is contained in:
attacker committed 2026-06-25 20:16:30 +08:00
1 parent e57718998a
commit 77c234b060
314 files changed
+10050 -4065

No files matched your search

+61 -6
View File
@@ -2,11 +2,13 @@
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, type ListResponse } from '../http';
import { isOnline, timeAgo, asList } from '../../components/agent/agentUtils';
export const auditApi = {
getLogs: async (params?: { page?: number; page_size?: number; module?: string; action?: string }) => {
return http.get<ListResponse>('/audit/logs', params);
getLogs: async (params?: { page?: number; page_size?: number; module?: string; action?: string; username?: string; start_time?: string; end_time?: string }) => {
return http.get<ListResponse>('/audit/logs', params as Record<string, string | number | boolean | undefined>);
},
getLogDetail: async (id: number | string) => {
return http.get(`/audit/logs/${id}`);
},
getModules: async () => {
return http.get('/audit/modules');
@@ -17,6 +19,17 @@ export const auditApi = {
getStatistics: async () => {
return http.get('/audit/statistics');
},
exportLogs: async (params?: Record<string, string | number | boolean | undefined>) => {
// Build URL with query params for server-side CSV export
const qs = new URLSearchParams();
qs.set('format', 'csv');
if (params) {
Object.entries(params).forEach(([k, v]) => {
if (v !== undefined && v !== null && v !== '') qs.set(k, String(v));
});
}
return http.download(`/audit/logs/export?${qs.toString()}`);
},
clearLogs: async () => {
return http.post('/audit/logs/clear');
},
@@ -24,9 +37,51 @@ export const auditApi = {
// ==================== 终端会话审计 API(WebSSH 录制) ==================== // Logan.Li
export const terminalSessionApi = {
list: async (params?: { page?: number; page_size?: number; server_id?: number; username?: string; status?: string }) => {
return http.get<ListResponse>('/terminal-sessions', params as Record<string, string | number | boolean | undefined>);
},
get: async (id: number) => {
return http.get(`/terminal-sessions/${id}`);
},
getRecord: async (id: number) => {
return http.get<string>(`/terminal-sessions/${id}/record`);
},
kill: async (id: number) => {
return http.post(`/terminal-sessions/${id}/kill`);
},
download: async (id: number) => {
return http.download(`/terminal-sessions/${id}/download`, `session-${id}.cast`);
},
delete: async (id: number) => {
return http.delete(`/terminal-sessions/${id}`);
},
batchDelete: async (ids: number[]) => {
return http.post('/terminal-sessions/batch-delete', { ids });
},
};
// ==================== 会话命令审计 API ====================
export const sessionCommandApi = {
list: async (params?: { page?: number; page_size?: number; session_id?: number; username?: string }) => {
return http.get<ListResponse>('/session-commands', params as Record<string, string | number | boolean | undefined>);
},
};
// ==================== 登录日志 API ====================
export const loginLogApi = {
list: async (params?: { page?: number; page_size?: number; username?: string; status?: string }) => {
return http.get<ListResponse>('/login-logs', params as Record<string, string | number | boolean | undefined>);
},
};
// ==================== 审批流程 API ====================
export const approvalApi = {
getTemplates: async () => {
return http.get('/approvals/templates');
getTemplates: async (params?: { type?: string; category?: string }) => {
return http.get('/approvals/templates', params);
},
getTemplate: async (id: number | string) => {
return http.get(`/approvals/templates/${id}`);
@@ -40,7 +95,7 @@ export const approvalApi = {
deleteTemplate: async (id: number | string) => {
return http.delete(`/approvals/templates/${id}`);
},
getProcesses: async (params?: { page?: number; page_size?: number; status?: string }) => {
getProcesses: async (params?: { page?: number; page_size?: number; status?: string; category?: string }) => {
return http.get('/approvals/processes', params);
},
createProcess: async ( data: any) => {