feat: 完善堡垒机与 Agent 智能运维能力
- 支持 Windows Agent 构建、安装脚本和统一上报协议 - 增强 RDP 剪贴板、虚拟盘和文件传输能力 - 新增 AIOps 上下文工具、告警 RCA trace 落库和回放接口 - 重构 docs 模块文档并补充终端、堡垒机、监控、AI Agent 设计
This commit is contained in:
1 parent
a9513c2056
commit
e0d652d211
169 files changed
+12192
-9116
No files matched your search
@@ -78,6 +78,7 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const timerRef = useRef<number | null>(null);
|
||||
const replaySeqRef = useRef(0);
|
||||
const [fullscreen, setFullscreen] = useState(false);
|
||||
const [status, setStatus] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -100,13 +101,26 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
ctx.putImageData(new ImageData(pixels, frame.width, frame.height), frame.x, frame.y);
|
||||
};
|
||||
|
||||
const drawReplay = async (nextIndex: number) => {
|
||||
const frame = playableFrames[nextIndex];
|
||||
const clearReplayCanvas = () => {
|
||||
const canvas = canvasRef.current;
|
||||
const ctx = canvas?.getContext('2d');
|
||||
if (!frame || !canvas || !ctx) return;
|
||||
if (!canvas || !ctx) return null;
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
await drawImageFrame(ctx, frame);
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
return ctx;
|
||||
};
|
||||
|
||||
const drawReplay = async (nextIndex: number, rebuild = false) => {
|
||||
const ctx = rebuild ? clearReplayCanvas() : canvasRef.current?.getContext('2d');
|
||||
if (!ctx) return;
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
const start = rebuild ? 0 : nextIndex;
|
||||
for (let i = start; i <= nextIndex; i += 1) {
|
||||
const frame = playableFrames[i];
|
||||
if (frame) await drawImageFrame(ctx, frame);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -161,6 +175,11 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
const text = typeof raw === 'string' ? raw : String(raw || '');
|
||||
const record = JSON.parse(text || '{}') as RdpRecord;
|
||||
const list = (record.frames || []).filter((f) => f.type === 'bitmap' && f.image);
|
||||
const sessionFrame = (record.frames || []).find((f) => f.type === 'session' && f.width && f.height);
|
||||
const sizeFrame = sessionFrame || list.find((f) => f.width && f.height);
|
||||
if (sizeFrame?.width && sizeFrame?.height) {
|
||||
setCanvasSize({ width: sizeFrame.width, height: sizeFrame.height });
|
||||
}
|
||||
setFrames(list);
|
||||
setStatus(list.length ? '' : '该 RDP 会话没有可播放画面帧');
|
||||
setPlaying(list.length > 0);
|
||||
@@ -196,7 +215,12 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
}, [playing, mode, playableFrames.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === 'replay' && playableFrames.length > 0) void drawReplay(index);
|
||||
if (mode !== 'replay' || playableFrames.length === 0) return;
|
||||
const seq = replaySeqRef.current + 1;
|
||||
replaySeqRef.current = seq;
|
||||
void drawReplay(index, true).then(() => {
|
||||
if (replaySeqRef.current !== seq) return;
|
||||
});
|
||||
}, [index, playableFrames.length, mode]);
|
||||
|
||||
const displayHeight = fullscreen ? 'calc(100vh - 88px)' : '560px';
|
||||
|
||||
Reference in new issue
Block a user