Files
IC-Coder-Plugin/src/views/ICViewProvider.ts
Roe-xin 77b54aebf0 feat: 添加用户手册功能
- 新增用户手册 Markdown 文档及配套截图
   - 新增打开用户手册命令
   - 在侧边栏和主面板中集成用户手册入口
   - 优化用户手册打开方式,支持 Markdown 预览
2026-03-10 16:29:37 +08:00

349 lines
10 KiB
TypeScript

import * as vscode from "vscode";
import { getWebviewContent } from "./webviewContent";
import { isTokenExpired } from "../utils/jwtUtils";
import {
handleUserMessage,
insertCodeToEditor,
handleReadFile,
handleCreateFile,
handleUpdateFile,
handleRenameFile,
handleReplaceInFile,
handleUserAnswer,
abortCurrentDialog,
handleOptimizePrompt,
} from "../utils/messageHandler";
import { setCustomConfig } from "../config/settings";
/**
* 创建并显示IC 侧边栏视图
*/
export function showICHelperPanel(context: vscode.ExtensionContext) {
// 创建WebView面板
const panel = vscode.window.createWebviewPanel(
"icCoder", // 面板ID
"IC Coder", // 面板标题
vscode.ViewColumn.Beside, // 显示在旁边
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [
vscode.Uri.joinPath(context.extensionUri, "media"),
vscode.Uri.joinPath(context.extensionUri, "dist", "assets")
],
}
);
// 设置标签页图标
panel.iconPath = vscode.Uri.joinPath(
context.extensionUri,
"media",
"icon.png"
);
// 获取页面内图标URI
const iconUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "media", "icon.png")
);
// 获取模型图标URI
const autoIconUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "dist", "assets", "model", "Auto.png")
);
const liteIconUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "dist", "assets", "model", "lite.png")
);
const syIconUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "dist", "assets", "model", "Sy.png")
);
const maxIconUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "dist", "assets", "model", "Max.png")
);
// 获取二维码图片URI
const qrCodeUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "dist", "assets", "QRCode", "wx.png")
);
// 获取Logo URI
const logoUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "media", "homepage-logo.png")
);
// 设置HTML内容
panel.webview.html = getWebviewContent(
iconUri.toString(),
autoIconUri.toString(),
liteIconUri.toString(),
syIconUri.toString(),
maxIconUri.toString(),
qrCodeUri.toString(),
logoUri.toString()
);
// 处理消息
panel.webview.onDidReceiveMessage(
(message) => {
console.log("[ICViewProvider] ====== 收到 WebView 消息 ======");
console.log("[ICViewProvider] command:", message.command);
console.log("[ICViewProvider] 完整消息:", JSON.stringify(message));
switch (message.command) {
case "sendMessage":
handleUserMessage(panel, message.text, context.extensionPath, message.mode);
break;
case "readFile":
handleReadFile(panel, message.filePath);
break;
case "updateFile":
handleUpdateFile(panel, message.filePath, message.content);
break;
case "renameFile":
handleRenameFile(panel, message.oldPath, message.newPath);
break;
case "replaceInFile":
handleReplaceInFile(
panel,
message.filePath,
message.searchText,
message.replaceText
);
break;
case "insertCode":
insertCodeToEditor(message.code);
break;
case "createFile":
handleCreateFile(
panel,
message.filePath,
message.content,
message.overwrite
);
break;
case "showInfo":
vscode.window.showInformationMessage(message.text);
break;
case "showWarning":
vscode.window.showWarningMessage(message.message);
break;
// 新增:打开用户手册
case "openUserManual":
vscode.commands.executeCommand("ic-coder.openUserManual");
break;
// 新增:处理用户回答
case "submitAnswer":
handleUserAnswer(
message.askId,
message.selected,
message.customInput,
message.answers
);
break;
// 新增:中止对话
case "abortDialog":
void abortCurrentDialog();
break;
// 新增:优化提示词
case "optimizePrompt":
handleOptimizePrompt(panel, message.prompt);
break;
// 保存通用设置
case "saveGeneralSettings":
context.globalState.update('generalSettings', message.settings);
// 更新运行时配置(包括清空)
setCustomConfig({ backendUrl: message.settings.backendUrl || '' });
vscode.window.showInformationMessage('设置已保存');
break;
// 加载通用设置
case "loadGeneralSettings":
const settings = context.globalState.get('generalSettings');
panel.webview.postMessage({
command: 'loadedGeneralSettings',
settings: settings
});
break;
}
},
undefined,
context.subscriptions
);
}
/**
* 侧边栏视图提供者
*/
export class ICViewProvider implements vscode.WebviewViewProvider {
private _view?: vscode.WebviewView;
constructor(
private readonly extensionUri: vscode.Uri,
private readonly context: vscode.ExtensionContext
) {
// 【已禁用】监听认证状态变化 - 无需登录
}
/**
* 【已禁用】刷新登录状态并更新视图 - 无需登录
*/
private async refreshLoginStatus(): Promise<void> {
// 无需刷新登录状态
}
/**
* 【已禁用】检查登录状态 - 无需登录
*/
private async checkLoginStatus(): Promise<boolean> {
return true; // 始终返回已登录状态
}
resolveWebviewView(webviewView: vscode.WebviewView) {
console.log('[ICViewProvider] ========== resolveWebviewView 被调用 ==========');
// 保存引用以便后续刷新
this._view = webviewView;
webviewView.webview.options = {
enableScripts: true,
localResourceRoots: [
vscode.Uri.joinPath(this.extensionUri, "media"),
vscode.Uri.joinPath(this.extensionUri, "src", "assets")
],
};
console.log('[ICViewProvider] Webview options 已设置');
console.log('[ICViewProvider] extensionUri:', this.extensionUri.toString());
// 【已禁用】登录检查 - 直接显示"开始使用"按钮
webviewView.webview.html = this.getWebviewContent(webviewView.webview, true);
// 处理侧边栏的消息
webviewView.webview.onDidReceiveMessage(
(message) => {
if (message.command === "openChat") {
vscode.commands.executeCommand("ic-coder.openChat");
} else if (message.command === "login") {
vscode.commands.executeCommand("ic-coder.login");
} else if (message.command === "logout") {
// 退出登录(前端已有确认对话框)
vscode.commands.executeCommand("ic-coder.logout");
} else if (message.command === "openICCoder") {
// 打开 IC Coder 官网
vscode.env.openExternal(vscode.Uri.parse('https://www.iccoder.com'));
} else if (message.command === "openUserManual") {
// 打开用户手册
vscode.commands.executeCommand("ic-coder.openUserManual");
} else if (message.command === "openExternalUrl") {
// 打开外部链接
if (message.url) {
vscode.env.openExternal(vscode.Uri.parse(message.url));
}
} else if (message.command === "saveGeneralSettings") {
// 保存通用设置
this.context.globalState.update('generalSettings', message.settings);
if (message.settings.backendUrl) {
setCustomConfig({ backendUrl: message.settings.backendUrl });
}
vscode.window.showInformationMessage('设置已保存');
} else if (message.command === "loadGeneralSettings") {
// 加载通用设置
const settings = this.context.globalState.get('generalSettings');
webviewView.webview.postMessage({
command: 'loadedGeneralSettings',
settings: settings
});
}
},
undefined,
this.context.subscriptions
);
}
private getWebviewContent(
webview: vscode.Webview,
isLoggedIn: boolean
): string {
console.log('[ICViewProvider] 开始生成 HTML 内容, isLoggedIn:', isLoggedIn);
const logoUri = webview.asWebviewUri(
vscode.Uri.joinPath(this.extensionUri, "media", "icon.png")
);
return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 0;
padding: 0;
font-family: var(--vscode-font-family);
color: var(--vscode-foreground);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg,
var(--vscode-editor-background) 0%,
color-mix(in srgb, var(--vscode-editor-background) 85%, var(--vscode-button-background) 15%) 50%,
color-mix(in srgb, var(--vscode-editor-background) 90%, var(--vscode-button-background) 10%) 100%);
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
padding: 20px;
}
.container img {
margin-bottom: 16px;
}
.container h2 {
margin: 0 0 16px 0;
}
.btn {
width: 200px;
padding: 8px 12px;
margin: 4px 0;
background: #007ACC;
color: #ffffff;
border: none;
border-radius: 4px;
cursor: pointer;
text-align: center;
}
.btn:hover {
background: #005a9e;
}
</style>
</head>
<body>
<div class="container">
<img src="${logoUri}" alt="IC Coder" width="120" />
<h2>欢迎使用 IC Coder</h2>
${isLoggedIn
? '<button class="btn" onclick="openChat()">开始使用</button>'
: '<button class="btn" onclick="login()">登录账户</button>'
}
</div>
<script>
console.log('[Webview] 脚本已加载');
const vscode = acquireVsCodeApi();
function openChat() {
console.log('[Webview] 点击开始创作');
vscode.postMessage({ command: 'openChat' });
}
function login() {
console.log('[Webview] 点击登录');
vscode.postMessage({ command: 'login' });
}
console.log('[Webview] 初始化完成');
</script>
</body>
</html>`;
}
}