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

@@ -0,0 +1 @@
import{g as Ue,j as e,q as Te,G as Fe,N as Je,p as Ge,s as de,O as Ke,i as qe,a as Ze,r as p,B as v,L as je,R as es,S as ss,I as Ve,D as Ne,b as ve,c as Se,d as Ce,e as Ee,f as ts}from"./index-DfyorCky.js";import{C as oe,a as ne,b as os,c as ns,d as as}from"./card-C55cvSHg.js";import{L as ae}from"./label-BK0h2apY.js";import{B as _e}from"./badge-xNW8x0G1.js";import{S as ce,a as re,b as le,c as ie,d as Z}from"./select-D5qUzdAs.js";import{T as cs}from"./textarea-NXY8u32k.js";import{k as _}from"./kubernetes-J8O09fK7.js";import{t as j}from"./index-a3ybMjbR.js";import{B as rs}from"./box-TTGA1p57.js";import{Z as ls}from"./zap-D2uWSK32.js";import{P as Me}from"./pencil-BqUotcjf.js";import{R as is}from"./refresh-cw-DUB_tAG-.js";import{P as ps}from"./plus-CUG-9kpu.js";import{S as ds}from"./save-DoGGjfwC.js";import{T as ms}from"./trash-2-Dx32pOzT.js";import"./index-CWVNW_qu.js";const us=[["path",{d:"M9 17H7A5 5 0 0 1 7 7h2",key:"8i5ue5"}],["path",{d:"M15 7h2a5 5 0 1 1 0 10h-2",key:"1b9ql8"}],["line",{x1:"8",x2:"16",y1:"12",y2:"12",key:"1jonct"}]],$e=Ue("link-2",us),pe={cluster:"集群",loadbalancer:"Ingress",service:"Service",app:"Deployment",server:"Node",database:"数据库",external:"外部服务",custom:"自定义"},xs=[{value:"database",label:"数据库",desc:"MySQL / Redis / PostgreSQL 等"},{value:"external",label:"外部服务",desc:"外部 API / CDN / DNS 等"},{value:"custom",label:"自定义",desc:"其他自定义节点"}],X=u=>u.startsWith("custom-");function $(u,h="h-5 w-5"){switch(u){case"server":return e.jsx(Te,{"code-path":"src/components/kubernetes/topology-helpers.tsx:31:27",className:h});case"loadbalancer":return e.jsx(Ke,{"code-path":"src/components/kubernetes/topology-helpers.tsx:32:33",className:h});case"cluster":return e.jsx(de,{"code-path":"src/components/kubernetes/topology-helpers.tsx:33:28",className:h});case"app":return e.jsx(Ge,{"code-path":"src/components/kubernetes/topology-helpers.tsx:34:24",className:h});case"service":return e.jsx(Je,{"code-path":"src/components/kubernetes/topology-helpers.tsx:35:28",className:h});case"database":return e.jsx(Fe,{"code-path":"src/components/kubernetes/topology-helpers.tsx:36:29",className:h});case"external":return e.jsx(ls,{"code-path":"src/components/kubernetes/topology-helpers.tsx:37:29",className:h});case"custom":return e.jsx(rs,{"code-path":"src/components/kubernetes/topology-helpers.tsx:38:27",className:h});default:return e.jsx(Te,{"code-path":"src/components/kubernetes/topology-helpers.tsx:39:21",className:h})}}function ee(u){switch(u){case"server":return"bg-blue-500/20 text-blue-400 border-blue-500/30";case"loadbalancer":return"bg-purple-500/20 text-purple-400 border-purple-500/30";case"cluster":return"bg-cyan-500/20 text-cyan-400 border-cyan-500/30";case"app":return"bg-rose-500/20 text-rose-400 border-rose-500/30";case"service":return"bg-emerald-500/20 text-emerald-400 border-emerald-500/30";case"database":return"bg-amber-500/20 text-amber-400 border-amber-500/30";case"external":return"bg-orange-500/20 text-orange-400 border-orange-500/30";case"custom":return"bg-slate-500/20 text-slate-400 border-slate-500/30";default:return"bg-slate-500/20 text-slate-400 border-slate-500/30"}}function hs(u,h,D,Y,x){const V=[],l=[],z=Math.max(1,h.length,D.length,Y.length,x.length),L=Math.max(900,Math.min(z*130,2400)),r=[60,180,320,480,640],N=o=>{const i=Math.min(o,12);if(i===0)return[];if(i===1)return[L/2];const c=L/(i+1);return Array.from({length:i},(d,g)=>c*(g+1))},E=`cluster-${u.id}`;V.push({id:E,name:u.name||"集群",type:"cluster",x:L/2,y:r[0],data:{kind:"cluster",version:u.version,status:u.status,api_server:u.api_server,node_count:u.node_count,pod_count:u.pod_count}});const R=h.slice(0,12),B=N(R.length);R.forEach((o,i)=>{const c=`ingress-${o.id}`;V.push({id:c,name:o.name,type:"loadbalancer",x:B[i],y:r[1],data:{kind:"ingress",namespace:o.namespace,backend:o.backend,tls:o.tls,hosts:o.hosts}}),l.push({id:`e-${E}-${c}`,source:E,target:c,label:"route"})});const f=D.slice(0,12),A=N(f.length);f.forEach((o,i)=>{const c=`service-${o.id}`;V.push({id:c,name:o.name,type:"service",x:A[i],y:r[2],data:{kind:"service",namespace:o.namespace,type:o.type,cluster_ip:o.cluster_ip,external_ip:o.external_ip,selector:o.selector}})}),R.length>0&&f.length>0?R.forEach(o=>{const i=`ingress-${o.id}`,c=(o.backend||"").split(":")[0].trim();let d=f.filter(g=>g.name===c);d.length===0&&(d=f.filter(g=>g.namespace===o.namespace)),d.length===0&&(d=[f[0]]),d.forEach(g=>l.push({id:`e-${i}-service-${g.id}`,source:i,target:`service-${g.id}`,label:"→"}))}):f.length>0&&f.forEach(o=>l.push({id:`e-${E}-service-${o.id}`,source:E,target:`service-${o.id}`,label:"expose"}));const T=Y.slice(0,12),F=N(T.length);T.forEach((o,i)=>{const c=`deploy-${o.id}`;V.push({id:c,name:o.name,type:"app",x:F[i],y:r[3],data:{kind:"deployment",namespace:o.namespace,replicas:o.replicas,ready_replicas:o.ready_replicas,available_replicas:o.available_replicas,image:o.image}})}),f.length>0&&T.length>0&&f.forEach(o=>{const i=`s Line truncated