/** * Review 面板 - 内嵌 Webview 悬浮窗 * * 双栏 Diff + Accept/Reject 按钮,不弹系统窗口 */ import * as vscode from 'vscode'; import { ChangeSetManager } from '../snapshot/snapshotManager'; import { ChangeSet, FileChange, FileChangeStatus } from '../models/types'; export class ReviewPanel { private panel: vscode.WebviewPanel | undefined; constructor( private changeSetManager: ChangeSetManager ) {} show(): void { const changeSet = this.changeSetManager.getCurrentSet(); if (!changeSet || changeSet.changes.length === 0) { return; } if (this.panel) { this.panel.reveal(vscode.ViewColumn.Active); this.sendData(changeSet); return; } this.panel = vscode.window.createWebviewPanel( 'aiDiffReview', 'AI Diff Review', { viewColumn: vscode.ViewColumn.Active, preserveFocus: false }, { enableScripts: true, retainContextWhenHidden: true } ); this.panel.webview.html = this.getHtml(); this.panel.webview.onDidReceiveMessage((msg: any) => { switch (msg.type) { case 'ready': this.sendData(changeSet); break; case 'acceptFile': this.changeSetManager.updateFileStatus(msg.fileId, 'accepted'); this.changeSetManager.applyFileChange(msg.fileId); this.refresh(); break; case 'rejectFile': this.changeSetManager.updateFileStatus(msg.fileId, 'rejected'); this.changeSetManager.rejectFileChange(msg.fileId); this.refresh(); break; case 'acceptAll': this.changeSetManager.updateAllStatus('accepted'); this.changeSetManager.applyAllAccepted(); this.refresh(); break; case 'rejectAll': this.changeSetManager.updateAllStatus('rejected'); this.changeSetManager.rejectAll(); this.refresh(); break; } }); this.panel.onDidDispose(() => { this.panel = undefined; }); } private refresh(): void { const changeSet = this.changeSetManager.getCurrentSet(); if (changeSet && this.panel) { this.sendData(changeSet); } } private sendData(changeSet: ChangeSet): void { this.panel?.webview.postMessage({ type: 'init', changeSet }); } dispose(): void { this.panel?.dispose(); this.panel = undefined; } private getHtml(): string { return /*html*/`

🔍 AI Diff Review

`; } }