31 Commits

Author SHA1 Message Date
423c9ddb0e feat:优化后端消息处理逻辑,确保AI响应保存到历史记录并更新面板状态 2026-01-24 17:34:28 +08:00
50eacdafde feat:实现BASIC用户显示升级到Pro的按钮 + 修改退出登录的展现形式 + 退出登录的再次确认 2026-01-19 10:52:39 +08:00
d90cca7cef feat:实现了点击头像和用户名进行跳转到首页
这里还需要完善的地方:
- 跳转到Web端还需要进行登录,如果要自动登录
- 需要后端给个临时的授权码
- 这样就不用前端传递token然后自动登录了
- 避免了token暴露的风险
2026-01-17 10:48:05 +08:00
5347425327 feat:添加设置按钮
- 包含通用设置,里面有语言啊,主题色啊等设置
- 还包含规则设置,里面有系统规则设置等
2026-01-16 14:31:15 +08:00
28d93c7e75 feat:优化IC Coder页面展示
- 优化了字体颜色
- 优化了字体大小等
2026-01-15 15:54:04 +08:00
5339212de9 feat:新增高级特性的按钮
- 里面包含用户手册
- 用户反馈 点击之后弹窗显示微信二维码
2026-01-15 14:30:58 +08:00
73a1510de4 feat:新增页面退出登录的逻辑 2026-01-14 18:32:53 +08:00
606f757699 feat:新增点击示例直接发送之前加一层工作区检测逻辑 2026-01-14 11:52:42 +08:00
342bf22f3f 1.0.2 2026-01-14 00:07:58 +08:00
d2ec73f796 refactor: 重命名 media/description 文件为英文
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 00:07:47 +08:00
c9f597beec 1.0.1 2026-01-14 00:05:02 +08:00
e9a201ef01 fix: 修复 README.md 链接格式
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 00:03:17 +08:00
77a89847cb feat:修改README 2026-01-13 23:17:26 +08:00
c14b7f4dbc feat:修改setting 2026-01-13 23:02:46 +08:00
64724bf48c feat:修改plusher名称 2026-01-13 22:55:20 +08:00
c9e160f2ef feat:修改package.json 2026-01-13 22:52:18 +08:00
3a19cc638f feat:LICENSE放到files里面 2026-01-13 22:46:35 +08:00
a2e8e74572 feat:换到生产服务器 2026-01-13 22:44:30 +08:00
ad96743fad feat:changelog和描述修改 2026-01-13 22:17:46 +08:00
95b1bd7678 Merge branch 'feat/back-to-front' into feat/front-end 2026-01-13 20:45:20 +08:00
94b6fb056f Merge branch 'feat/back-to-front' of https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin into feat/back-to-front 2026-01-13 20:44:57 +08:00
a24fd71636 feat:修改发布文档 2026-01-13 20:44:45 +08:00
f55a5bfbcb style:优化展示区域的样式 2026-01-13 17:05:50 +08:00
83b706d5be fix: 修复 README.md 链接格式并添加 repository 字段 2026-01-13 16:39:59 +08:00
b9e63bc9a9 Merge branch 'feat/back-to-front' into feat/front-end 2026-01-13 16:24:17 +08:00
ef0c8748f7 Merge branch 'feat/back-to-front' of https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin into feat/back-to-front 2026-01-13 16:22:50 +08:00
430a2c4062 feat:暂时删除README.md中的图片 2026-01-13 16:22:37 +08:00
f5bd35c71a fix:解决打包报错的问题 2026-01-13 16:02:42 +08:00
f958683f53 feat:修改插件描述 2026-01-13 15:18:21 +08:00
8cf0e32184 Merge branch 'feat/back-to-front' into feat/front-end 2026-01-13 11:07:53 +08:00
1cbd0c5fe7 Merge branch 'feat/back-to-front' of https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin into feat/back-to-front 2026-01-13 11:06:16 +08:00
35 changed files with 2248 additions and 298 deletions

View File

@ -1,9 +1,23 @@
# Change Log # 更新日志
All notable changes to the "ic-coder" extension will be documented in this file. 所有重要的项目变更都将记录在此文件中。
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. ## [1.0.2] - 2026-01-13
## [Unreleased] IC Coder插件端正式发布。
- Initial release IC Coder 插件端是一个专为 FPGA 开发设计的 VS Code 扩展,提供 AI 驱动的智能辅助功能。
主要功能:
- VCD波形解析
- 自动生成完整工程
- 自动仿真
- 自主代码迭代
- 智能匹配最优模型
- 多线程任务处理
- 实时跟随
- 丰富的上下文工具
- 全双工交互
- 多层次安全保障
- 自动搭建电路架构
- 多平台支持

View File

@ -67,6 +67,11 @@
CO03l8nmFBBTNPDg7lN9a9fYwDdgsRIDVDwTrx6Esggi6HnzmrMTJQQJ99BLACAAAAAAAAAAAAAGAZDOVVyT CO03l8nmFBBTNPDg7lN9a9fYwDdgsRIDVDwTrx6Esggi6HnzmrMTJQQJ99BLACAAAAAAAAAAAAAGAZDOVVyT
``` ```
```
//蔡工的token
6CB3tOZPiwNi6rrOuFHMe6QzrVWBnajW5fJsNgCWu8jtERUCCRnJJQQJ99CAACAAAAAAAAAAAAASAZDO3FnY
```
### 3. 创建发布者账号 ### 3. 创建发布者账号
发布者账号是你在 VS Code 市场的身份标识。 发布者账号是你在 VS Code 市场的身份标识。

View File

@ -1,24 +1,45 @@
# IC Coder Plugin ## 什么是 IC Coder
IC Coder 是一个面向 Verilog/FPGA 开发的智能辅助插件。 **IC Coder** 是一款 **专注于真实 FPGA 研发的 Verilog 智能体编程平台**。我们立志于用 AI 重塑 FPGA 研发效率,让 FPGA 开发者们,都能享受到 AI 发展所带来的科技福利!目标成为全球最好用的 **LLM 生成 Verilog**的平台!
## 功能特性 从 WEB 端到插件端IC Coder 智能体架构完成了**全新升级**,采用当前主流的**层级架构**设计,这种高内聚、低耦合的架构特性,不仅支持更多功能扩展,更预留了充足的迭代空间。当前,插件端拥有了调用本地工具的能力,不再是单纯代码生成的智能体,升级为拥有**语法校验、波形逻辑检查**等工具的**全流程 Verilog 编程智能体平台**,给用户带来更沉浸的**Vibe Verilog Coding**体验。
- Verilog 代码智能生成 ## 输入需求 对话补充需求
- 文件操作支持(创建、读取、修改、删除)
- 集成 iverilog 仿真工具
- VCD 波形文件生成
- 智能对话助手
## 使用说明 **无需**输入完整需求,放心交给智能体补充完善。
安装插件后,点击侧边栏的 IC Coder 图标即可开始使用。 ## Plan 模型下确认设计文档
## 系统要求 **确定**好用户需求以及相关参数后,整理并输出一份 FPGA 开发**设计文档**。Plan 模式下用户可以**进一步**与 IC Coder 沟通需求,或**直接修改**设计文档。
- VS Code 1.107.0 或更高版本 ## 自动搭建电路架构
- 插件已内置 iverilog 工具(Windows 平台)
## 许可证 根据需求自动搭建电路架构,并将电路信号关系结构化
MIT ## 自动仿真
自主搭建 Testbench 仿真平台,自动运行仿真生成波形
## 实时跟随
实时展示全流程执行细节,与智能体协同随时反馈,让 AI 开发更清晰、高效
## VCD 波形解析
自动解析 VCD 波形文件,自动根据需求,检查是否存在逻辑错误
## 自主代码迭代
根据波形解析结果,自动对代码进行优化,然后重新仿真并解析波形,如此迭代,直到仿真无误
## 多层次安全保障
默认本地存储与云端即时加密保障隐私,真正做到了代码全链路加密传输、云端零存储
## 反馈
无论是想与我们深入交流还是遇到任何问题,欢迎您[进入社区](https://iccoder.com:888/community)与我们联系
## 服务条款和隐私协议
请阅读我们的[服务条款](https://iccoder.com:888/guides/legal/terms-of-service)和[隐私协议](https://iccoder.com:888/guides/legal/privacy-policy)了解更多细节。

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View File

@ -1,9 +1,9 @@
{ {
"name": "iccoder", "name": "iccoder",
"displayName": "IC Coder", "displayName": "IC Coder: Agentic Verilog Platform",
"description": "Agentic Verilog Coding Platform for Real-World FPGAs", "description": "Agentic Verilog Coding Platform for Real-World FPGAs",
"version": "0.0.2", "version": "1.0.2",
"publisher": "ICCoder", "publisher": "ICCoderAgenticVerilogPlatform",
"engines": { "engines": {
"vscode": "^1.80.0" "vscode": "^1.80.0"
}, },
@ -21,6 +21,10 @@
"assistant" "assistant"
], ],
"license": "SEE LICENSE IN LICENSE", "license": "SEE LICENSE IN LICENSE",
"repository": {
"type": "git",
"url": "https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin.git"
},
"activationEvents": [ "activationEvents": [
"onCommand:ic-coder.openPanel", "onCommand:ic-coder.openPanel",
"onView:ic-coder-sidebar", "onView:ic-coder-sidebar",
@ -114,7 +118,9 @@
"dist", "dist",
"media", "media",
"tools", "tools",
"src/assets" "src/assets",
"LICENSE",
"CHANGELOG.md"
], ],
"dependencies": { "dependencies": {
"@wavedrom/doppler": "^1.14.0", "@wavedrom/doppler": "^1.14.0",

BIN
src/assets/QRCode/wx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@ -8,7 +8,7 @@ import * as vscode from "vscode";
type Environment = "dev" | "test" | "prod"; type Environment = "dev" | "test" | "prod";
/** 当前环境 - 修改这里切换环境 */ /** 当前环境 - 修改这里切换环境 */
const CURRENT_ENV: Environment = "dev"; const CURRENT_ENV: Environment = "prod";
/** 服务等级类型 */ /** 服务等级类型 */
export type ServiceTier = "lite" | "syntaxic" | "max" | "auto"; export type ServiceTier = "lite" | "syntaxic" | "max" | "auto";
@ -51,8 +51,8 @@ const ENV_CONFIG: Record<Environment, IccoderConfig> = {
}, },
/** 生产环境 - 通过 Gateway 路由 */ /** 生产环境 - 通过 Gateway 路由 */
prod: { prod: {
backendUrl: "https://api.iccoder.com/iccoder", backendUrl: "https://api.iccoder.com",
backendUrlStrongeLoop: "https://api.iccoder.com", backendUrlStrongeLoop: "http://192.168.1.115:2029",
loginUrl: "https://iccoder.com/login", loginUrl: "https://iccoder.com/login",
timeout: 60000, timeout: 60000,
userId: "default-user", userId: "default-user",

File diff suppressed because one or more lines are too long

View File

@ -157,12 +157,8 @@ export function activate(context: vscode.ExtensionContext) {
try { try {
const session = await vscode.authentication.getSession("iccoder", [], { createIfNone: false }); const session = await vscode.authentication.getSession("iccoder", [], { createIfNone: false });
if (session) { if (session) {
// 通过创建新会话并清除偏好来实现登出 // 调用 authProvider 的 removeSession 方法
await vscode.authentication.getSession("iccoder", [], { await authProvider.removeSession(session.id);
clearSessionPreference: true,
forceNewSession: true
});
vscode.window.showInformationMessage("已退出登录");
} else { } else {
vscode.window.showInformationMessage("当前未登录"); vscode.window.showInformationMessage("当前未登录");
} }

View File

@ -131,13 +131,19 @@ export async function showICHelperPanel(
vscode.Uri.joinPath(context.extensionUri, "src", "assets", "model", "Max.png") vscode.Uri.joinPath(context.extensionUri, "src", "assets", "model", "Max.png")
); );
// 获取二维码图片URI
const qrCodeUri = panel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, "src", "assets", "QRCode", "wx.png")
);
// 设置HTML内容 // 设置HTML内容
panel.webview.html = getWebviewContent( panel.webview.html = getWebviewContent(
iconUri.toString(), iconUri.toString(),
autoIconUri.toString(), autoIconUri.toString(),
liteIconUri.toString(), liteIconUri.toString(),
syIconUri.toString(), syIconUri.toString(),
maxIconUri.toString() maxIconUri.toString(),
qrCodeUri.toString()
); );
// 获取并发送用户信息到 webview // 获取并发送用户信息到 webview
@ -156,7 +162,8 @@ export async function showICHelperPanel(
userId: userInfo.userId, userId: userInfo.userId,
nickname: userInfo.nickname, nickname: userInfo.nickname,
username: userInfo.username, username: userInfo.username,
credits: userInfo.credits credits: userInfo.credits,
membership: userInfo.membership
}, },
tierIconUrl: tierIconUrl tierIconUrl: tierIconUrl
}; };
@ -340,6 +347,24 @@ export async function showICHelperPanel(
}); });
} }
break; break;
case "logout":
// 退出登录
vscode.commands.executeCommand("ic-coder.logout");
break;
case "openICCoder":
// 跳转到 IC Coder 官网
vscode.env.openExternal(vscode.Uri.parse("https://www.iccoder.com"));
break;
case "openUserManual":
// 打开用户手册
vscode.env.openExternal(vscode.Uri.parse("https://www.iccoder.com"));
break;
case "openUserFeedback":
// 打开用户反馈二维码弹窗
panel.webview.postMessage({
command: "showFeedbackQRCode"
});
break;
// 处理计划操作(只做模式切换,响应已通过 submitAnswer 发送) // 处理计划操作(只做模式切换,响应已通过 submitAnswer 发送)
case "planAction": case "planAction":
if (message.action === "confirm") { if (message.action === "confirm") {
@ -487,6 +512,20 @@ export async function showICHelperPanel(
hasWorkspace: hasWorkspace, hasWorkspace: hasWorkspace,
}); });
break; break;
case "openExternalUrl":
// 打开外部链接
if (message.url) {
vscode.env.openExternal(vscode.Uri.parse(message.url));
}
break;
case "openICCoder":
// 打开 IC Coder 官网
vscode.env.openExternal(vscode.Uri.parse('https://www.iccoder.com'));
break;
case "logout":
// 退出登录(前端已有确认对话框)
vscode.commands.executeCommand('iccoder.logout');
break;
} }
}, },
undefined, undefined,

File diff suppressed because it is too large Load Diff

View File

@ -213,14 +213,23 @@ async function handleUserMessageWithBackend(
}, },
onComplete: async (segments) => { onComplete: async (segments) => {
// 隐藏状态栏
panel.webview.postMessage({
command: "hideStatus",
});
// 最后一次发送完整的段落
console.log("[MessageHandler] 对话完成, 段落数:", segments.length); console.log("[MessageHandler] 对话完成, 段落数:", segments.length);
// 先保存到历史记录(优先级最高,确保数据不丢失)
try {
// 将完整的 segments 保存到一条 AI 消息中
// 这样加载时可以完整还原对话样式
const textContent = segments
.filter((s) => s.type === "text" && s.content)
.map((s) => s.content)
.join("\n");
await historyManager.addAiMessage(textContent, undefined, segments);
console.log("[MessageHandler] AI响应已保存到历史记录");
} catch (error) {
console.error("[MessageHandler] 保存AI响应历史失败:", error);
}
// 对话完成后重新获取余额(因为已经消耗了 Credits // 对话完成后重新获取余额(因为已经消耗了 Credits
try { try {
console.log("[MessageHandler] 对话完成,重新获取余额..."); console.log("[MessageHandler] 对话完成,重新获取余额...");
@ -232,25 +241,22 @@ async function handleUserMessageWithBackend(
console.error("[MessageHandler] 获取余额失败:", error); console.error("[MessageHandler] 获取余额失败:", error);
} }
const result = await panel.webview.postMessage({ // 尝试更新面板(如果面板已关闭,这些操作会失败,但不影响数据保存)
command: "updateSegments",
segments: segments,
isComplete: true,
});
console.log("[MessageHandler] postMessage 返回值:", result);
// 保存完整的 segments 到历史记录
try { try {
// 将完整的 segments 保存到一条 AI 消息中 // 隐藏状态栏
// 这样加载时可以完整还原对话样式 panel.webview.postMessage({
const textContent = segments command: "hideStatus",
.filter((s) => s.type === "text" && s.content) });
.map((s) => s.content)
.join("\n");
await historyManager.addAiMessage(textContent, undefined, segments); // 最后一次发送完整的段落
const result = await panel.webview.postMessage({
command: "updateSegments",
segments: segments,
isComplete: true,
});
console.log("[MessageHandler] postMessage 返回值:", result);
} catch (error) { } catch (error) {
console.warn("保存AI响应历史失败:", error); console.warn("[MessageHandler] 更新面板失败(面板可能已关闭):", error);
} }
resolve(); resolve();

View File

@ -109,6 +109,9 @@ export function showICHelperPanel(context: vscode.ExtensionContext) {
case "showInfo": case "showInfo":
vscode.window.showInformationMessage(message.text); vscode.window.showInformationMessage(message.text);
break; break;
case "showWarning":
vscode.window.showWarningMessage(message.message);
break;
// 新增:处理用户回答 // 新增:处理用户回答
case "submitAnswer": case "submitAnswer":
handleUserAnswer( handleUserAnswer(
@ -214,6 +217,17 @@ export class ICViewProvider implements vscode.WebviewViewProvider {
vscode.commands.executeCommand("ic-coder.openChat"); vscode.commands.executeCommand("ic-coder.openChat");
} else if (message.command === "login") { } else if (message.command === "login") {
vscode.commands.executeCommand("ic-coder.login"); vscode.commands.executeCommand("ic-coder.login");
} else if (message.command === "logout") {
// 退出登录(前端已有确认对话框)
vscode.commands.executeCommand('iccoder.logout');
} else if (message.command === "openICCoder") {
// 打开 IC Coder 官网
vscode.env.openExternal(vscode.Uri.parse('https://www.iccoder.com'));
} else if (message.command === "openExternalUrl") {
// 打开外部链接
if (message.url) {
vscode.env.openExternal(vscode.Uri.parse(message.url));
}
} }
}, },
undefined, undefined,

View File

@ -3,7 +3,21 @@ import {
getUserInfoComponentStyles, getUserInfoComponentStyles,
getUserInfoComponentScript, getUserInfoComponentScript,
} from "./userInfoComponent"; } from "./userInfoComponent";
import { userAvatarIconSvg } from "../constants/toolIcons"; import {
getMoreOptionsComponentContent,
getMoreOptionsComponentStyles,
getMoreOptionsComponentScript,
} from "./moreOptionsComponent";
import {
getSettingsComponentContent,
getSettingsComponentStyles,
getSettingsComponentScript,
} from "./settingsComponent";
import {
userAvatarIconSvg,
moreIconSvg,
setting,
} from "../constants/toolIcons";
/** /**
* 获取会话历史栏的 HTML 内容 * 获取会话历史栏的 HTML 内容
@ -39,8 +53,23 @@ export function getConversationHistoryBarContent(): string {
</button> </button>
${getUserInfoComponentContent()} ${getUserInfoComponentContent()}
</div> </div>
<div class='setting'>
<button class="setting-btn" title="设置" onclick="openSettingsModal()">
${setting}
</button>
</div>
<div class='more-container'>
<button class="more-button" title="更多选项" onclick="toggleMoreOptionsDropdown()">
${moreIconSvg}
</button>
${getMoreOptionsComponentContent()}
</div>
</div> </div>
</div> </div>
${getSettingsComponentContent()}
`; `;
} }
@ -76,8 +105,8 @@ export function getConversationHistoryBarStyles(): string {
} }
.user-avatar-icon-button { .user-avatar-icon-button {
width: 36px; width: 30px;
height: 36px; height: 30px;
padding: 0; padding: 0;
background: transparent; background: transparent;
color: var(--vscode-foreground); color: var(--vscode-foreground);
@ -111,6 +140,72 @@ export function getConversationHistoryBarStyles(): string {
${getUserInfoComponentStyles()} ${getUserInfoComponentStyles()}
${getSettingsComponentStyles()}
.setting {
position: relative;
}
.setting-btn {
width: 30px;
height: 30px;
padding: 0;
background: transparent;
color: var(--vscode-foreground);
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
flex-shrink: 0;
}
.setting-btn:hover {
background: var(--vscode-toolbar-hoverBackground);
transform: scale(1.1);
}
.setting-btn:active {
transform: scale(0.95);
}
.more-container {
position: relative;
}
.more-button {
width: 30px;
height: 30px;
padding: 0;
background: transparent;
color: var(--vscode-foreground);
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
flex-shrink: 0;
}
.more-button:hover {
background: var(--vscode-toolbar-hoverBackground);
transform: scale(1.1);
}
.more-button:active {
transform: scale(0.95);
}
.more-button.active {
background: var(--vscode-toolbar-hoverBackground);
}
${getMoreOptionsComponentStyles()}
.history-dropdown-button { .history-dropdown-button {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -219,8 +314,8 @@ export function getConversationHistoryBarStyles(): string {
} }
.new-conversation-button { .new-conversation-button {
width: 36px; width: 30px;
height: 36px; height: 30px;
padding: 0; padding: 0;
background: transparent; background: transparent;
color: var(--vscode-foreground); color: var(--vscode-foreground);
@ -275,6 +370,10 @@ export function getConversationHistoryBarScript(): string {
return ` return `
${getUserInfoComponentScript()} ${getUserInfoComponentScript()}
${getMoreOptionsComponentScript()}
${getSettingsComponentScript()}
// 更新用户头像图标按钮显示 // 更新用户头像图标按钮显示
function updateUserAvatarIconButton(userInfo) { function updateUserAvatarIconButton(userInfo) {
const userAvatarIconButton = document.getElementById('userAvatarIconButton'); const userAvatarIconButton = document.getElementById('userAvatarIconButton');

View File

@ -4,21 +4,33 @@
export function getExampleShowcaseContent(): string { export function getExampleShowcaseContent(): string {
return ` return `
<div class="example-showcase" id="exampleShowcase"> <div class="example-showcase" id="exampleShowcase">
<div class="showcase-title">示</div> <div class="showcase-title">示</div>
<div class="example-cards"> <div class="example-cards">
<div class="example-card" onclick="fillExample(0)"> <div class="example-card" onclick="sendExample(0)">
<div class="example-icon">📝</div> <div class="example-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 13H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 17H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 9H9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="example-content"> <div class="example-content">
<div class="example-title">代码生成</div> <div class="example-title">生成一个SPI控制器</div>
<div class="example-desc">生成一个 8 位全加器的 Verilog 代码</div>
</div> </div>
</div> </div>
<div class="example-card" onclick="fillExample(1)"> <div class="example-card" onclick="sendExample(1)">
<div class="example-icon">🔍</div> <div class="example-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="example-content"> <div class="example-content">
<div class="example-title">代码分析</div> <div class="example-title">生成一个GMII接口的以太网UDP通信模块</div>
<div class="example-desc">分析当前项目中的时序逻辑设计</div>
</div> </div>
</div> </div>
</div> </div>
@ -71,26 +83,50 @@ export function getExampleShowcaseStyles(): string {
background: var(--vscode-input-background); background: var(--vscode-input-background);
border: 1px solid var(--vscode-input-border); border: 1px solid var(--vscode-input-border);
border-radius: 8px; border-radius: 8px;
padding: 14px; padding: 12px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 12px; gap: 10px;
position: relative;
overflow: hidden;
}
.example-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(79, 172, 254, 0.1) 0%, rgba(0, 242, 254, 0.1) 50%, rgba(168, 85, 247, 0.1) 100%);
opacity: 0;
transition: opacity 0.3s ease;
}
.example-card:hover::before {
opacity: 1;
} }
.example-card:hover { .example-card:hover {
border-color: var(--vscode-focusBorder); border-color: var(--vscode-focusBorder);
background: var(--vscode-list-hoverBackground); transform: translateY(-3px);
transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
} }
.example-icon { .example-icon {
font-size: 28px;
line-height: 1;
flex-shrink: 0; flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
color: var(--vscode-foreground);
}
.example-icon svg {
width: 20px;
height: 20px;
} }
.example-content { .example-content {
@ -99,12 +135,23 @@ export function getExampleShowcaseStyles(): string {
gap: 4px; gap: 4px;
flex: 1; flex: 1;
min-width: 0; min-width: 0;
position: relative;
z-index: 1;
} }
.example-title { .example-title {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: var(--vscode-foreground); color: var(--vscode-foreground);
line-height: 1.4;
transition: all 0.3s ease;
}
.example-card:hover .example-title {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 50%, #a855f7 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
} }
.example-desc { .example-desc {
@ -175,20 +222,41 @@ export function getExampleShowcaseScript(): string {
return ` return `
// 示例文本数组 // 示例文本数组
const exampleTexts = [ const exampleTexts = [
'生成一个 8 位全加器的 Verilog 代码', '生成一个SPI控制器',
'分析当前项目中的时序逻辑设计' '生成一个GMII接口的以太网UDP通信模块'
]; ];
// 填充示例到输入框 // 存储待发送的示例索引
function fillExample(index) { let pendingExampleIndex = -1;
// 直接发送示例消息
function sendExample(index) {
// 先检查工作区
pendingExampleIndex = index;
vscode.postMessage({
command: 'checkWorkspace'
});
}
// 实际发送示例消息
function doSendExample(index) {
const messageInput = document.getElementById('messageInput'); const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
if (messageInput && exampleTexts[index]) { if (messageInput && exampleTexts[index]) {
messageInput.value = exampleTexts[index]; messageInput.value = exampleTexts[index];
messageInput.focus();
// 触发自动调整高度 // 触发自动调整高度
if (typeof autoResizeTextarea === 'function') { if (typeof autoResizeTextarea === 'function') {
autoResizeTextarea(); autoResizeTextarea();
} }
// 直接触发发送
if (sendButton && typeof sendButton.click === 'function') {
sendButton.click();
} else if (typeof sendMessage === 'function') {
sendMessage();
}
} }
} }

View File

@ -0,0 +1,327 @@
/**
* 获取通用设置组件的 HTML 内容
*/
export function getGeneralSettingsComponentContent(): string {
return `
<div class="general-settings">
<h3 class="settings-section-title">通用设置</h3>
<div class="settings-section">
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">主题</label>
<span class="settings-item-description">选择界面主题</span>
</div>
<select class="settings-select" id="themeSelect">
<option value="auto">跟随系统</option>
<option value="light">浅色</option>
<option value="dark">深色</option>
</select>
</div>
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">语言</label>
<span class="settings-item-description">选择界面语言</span>
</div>
<select class="settings-select" id="languageSelect">
<option value="zh-CN">简体中文</option>
<option value="en-US">English</option>
</select>
</div>
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">自动保存</label>
<span class="settings-item-description">自动保存会话历史</span>
</div>
<label class="settings-switch">
<input type="checkbox" id="autoSaveCheckbox" checked>
<span class="settings-switch-slider"></span>
</label>
</div>
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">显示时间戳</label>
<span class="settings-item-description">在消息中显示时间戳</span>
</div>
<label class="settings-switch">
<input type="checkbox" id="showTimestampCheckbox">
<span class="settings-switch-slider"></span>
</label>
</div>
</div>
<div class="settings-section">
<h4 class="settings-subsection-title">编辑器设置</h4>
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">字体大小</label>
<span class="settings-item-description">设置编辑器字体大小</span>
</div>
<input type="number" class="settings-input" id="fontSizeInput" value="14" min="10" max="24">
</div>
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">代码高亮</label>
<span class="settings-item-description">启用代码语法高亮</span>
</div>
<label class="settings-switch">
<input type="checkbox" id="syntaxHighlightCheckbox" checked>
<span class="settings-switch-slider"></span>
</label>
</div>
</div>
<div class="settings-actions">
<button class="settings-button settings-button-primary" onclick="saveGeneralSettings()">
保存设置
</button>
<button class="settings-button settings-button-secondary" onclick="resetGeneralSettings()">
重置为默认
</button>
</div>
</div>
`;
}
/**
* 获取通用设置组件的 CSS 样式
*/
export function getGeneralSettingsComponentStyles(): string {
return `
.general-settings {
max-width: 600px;
}
.settings-section-title {
margin: 0 0 20px 0;
font-size: 16px;
font-weight: 600;
color: var(--vscode-foreground);
}
.settings-section {
margin-bottom: 32px;
}
.settings-subsection-title {
margin: 0 0 16px 0;
font-size: 14px;
font-weight: 600;
color: var(--vscode-foreground);
opacity: 0.9;
}
.settings-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid var(--vscode-panel-border);
}
.settings-item:last-child {
border-bottom: none;
}
.settings-item-header {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.settings-item-label {
font-size: 14px;
font-weight: 500;
color: var(--vscode-foreground);
}
.settings-item-description {
font-size: 12px;
color: var(--vscode-descriptionForeground);
}
.settings-select {
padding: 6px 12px;
background: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
font-size: 13px;
cursor: pointer;
outline: none;
}
.settings-select:focus {
border-color: var(--vscode-focusBorder);
}
.settings-input {
width: 80px;
padding: 6px 12px;
background: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
font-size: 13px;
outline: none;
}
.settings-input:focus {
border-color: var(--vscode-focusBorder);
}
.settings-switch {
position: relative;
display: inline-block;
width: 44px;
height: 24px;
cursor: pointer;
}
.settings-switch input {
opacity: 0;
width: 0;
height: 0;
}
.settings-switch-slider {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--vscode-input-background);
border: 1px solid var(--vscode-input-border);
border-radius: 24px;
transition: all 0.3s ease;
}
.settings-switch-slider:before {
content: "";
position: absolute;
height: 16px;
width: 16px;
left: 3px;
bottom: 3px;
background: var(--vscode-foreground);
border-radius: 50%;
transition: all 0.3s ease;
}
.settings-switch input:checked + .settings-switch-slider {
background: var(--vscode-button-background);
border-color: var(--vscode-button-background);
}
.settings-switch input:checked + .settings-switch-slider:before {
transform: translateX(20px);
background: var(--vscode-button-foreground);
}
.settings-actions {
display: flex;
gap: 12px;
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid var(--vscode-panel-border);
}
.settings-button {
padding: 8px 16px;
border: none;
border-radius: 4px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.settings-button-primary {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
}
.settings-button-primary:hover {
background: var(--vscode-button-hoverBackground);
}
.settings-button-secondary {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
}
.settings-button-secondary:hover {
background: var(--vscode-button-secondaryHoverBackground);
}
`;
}
/**
* 获取通用设置组件的 JavaScript 脚本
*/
export function getGeneralSettingsComponentScript(): string {
return `
// 保存通用设置
function saveGeneralSettings() {
const settings = {
theme: document.getElementById('themeSelect').value,
language: document.getElementById('languageSelect').value,
autoSave: document.getElementById('autoSaveCheckbox').checked,
showTimestamp: document.getElementById('showTimestampCheckbox').checked,
fontSize: document.getElementById('fontSizeInput').value,
syntaxHighlight: document.getElementById('syntaxHighlightCheckbox').checked,
};
// 发送消息到扩展
vscode.postMessage({
command: 'saveGeneralSettings',
settings: settings
});
// 显示保存成功提示
console.log('通用设置已保存', settings);
}
// 重置通用设置
function resetGeneralSettings() {
document.getElementById('themeSelect').value = 'auto';
document.getElementById('languageSelect').value = 'zh-CN';
document.getElementById('autoSaveCheckbox').checked = true;
document.getElementById('showTimestampCheckbox').checked = false;
document.getElementById('fontSizeInput').value = '14';
document.getElementById('syntaxHighlightCheckbox').checked = true;
console.log('通用设置已重置为默认值');
}
// 加载通用设置
function loadGeneralSettings(settings) {
if (!settings) return;
if (settings.theme) {
document.getElementById('themeSelect').value = settings.theme;
}
if (settings.language) {
document.getElementById('languageSelect').value = settings.language;
}
if (settings.autoSave !== undefined) {
document.getElementById('autoSaveCheckbox').checked = settings.autoSave;
}
if (settings.showTimestamp !== undefined) {
document.getElementById('showTimestampCheckbox').checked = settings.showTimestamp;
}
if (settings.fontSize) {
document.getElementById('fontSizeInput').value = settings.fontSize;
}
if (settings.syntaxHighlight !== undefined) {
document.getElementById('syntaxHighlightCheckbox').checked = settings.syntaxHighlight;
}
}
`;
}

View File

@ -103,7 +103,7 @@ export function getInputAreaStyles(): string {
/* 居中模式:未发起对话时 */ /* 居中模式:未发起对话时 */
.input-area.centered { .input-area.centered {
position: absolute; position: absolute;
top: 55%; top: 60%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
width: calc(100% - 40px); width: calc(100% - 40px);
@ -300,7 +300,6 @@ export function getInputAreaScript(): string {
${getContextDisplayScript()} ${getContextDisplayScript()}
${getContextCompressScript()} ${getContextCompressScript()}
${getOptimizeButtonScript()} ${getOptimizeButtonScript()}
${getExampleShowcaseScript()}
// 对话状态管理 // 对话状态管理
let isConversationActive = false; let isConversationActive = false;
@ -310,6 +309,8 @@ export function getInputAreaScript(): string {
let hasCheckedWorkspace = false; // 是否已经检测过工作区 let hasCheckedWorkspace = false; // 是否已经检测过工作区
let hasWorkspace = true; // 工作区状态 let hasWorkspace = true; // 工作区状态
${getExampleShowcaseScript()}
// 切换输入框布局模式 // 切换输入框布局模式
function updateInputAreaLayout() { function updateInputAreaLayout() {
const inputArea = document.getElementById('inputArea'); const inputArea = document.getElementById('inputArea');

View File

@ -0,0 +1,394 @@
/**
* 更多选项组件
* 包含用户手册和用户反馈入口
*/
/**
* 获取更多选项组件的 HTML 内容
*/
export function getMoreOptionsComponentContent(): string {
return `
<div class="more-options-wrapper">
<!-- 更多选项下拉面板 -->
<div class="more-options-dropdown" id="moreOptionsDropdown">
<div class="more-options-content">
<div class="more-options-header">
<span class="more-options-title">更多选项</span>
</div>
<div class="more-options-body">
<div class="more-option-item" id="userManualOption">
<div class="option-icon">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z" fill="currentColor"/>
</svg>
</div>
<div class="option-text">
<div class="option-label">用户手册</div>
<div class="option-desc">查看使用文档和帮助</div>
</div>
</div>
<div class="more-option-item" id="userFeedbackOption">
<div class="option-icon">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z" fill="currentColor"/>
</svg>
</div>
<div class="option-text">
<div class="option-label">用户反馈</div>
<div class="option-desc">提交问题和建议</div>
</div>
</div>
</div>
</div>
</div>
<!-- 用户反馈二维码弹窗 -->
<div class="feedback-qrcode-modal" id="feedbackQRCodeModal">
<div class="feedback-qrcode-overlay" onclick="closeFeedbackQRCode()"></div>
<div class="feedback-qrcode-content">
<div class="feedback-qrcode-header">
<span class="feedback-qrcode-title">用户反馈</span>
<button class="feedback-qrcode-close" onclick="closeFeedbackQRCode()">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" fill="currentColor"/>
</svg>
</button>
</div>
<div class="feedback-qrcode-body">
<img class="feedback-qrcode-image" id="feedbackQRCodeImage" alt="微信二维码" />
<p class="feedback-qrcode-text">扫描二维码添加微信反馈</p>
</div>
</div>
</div>
</div>
`;
}
/**
* 获取更多选项组件的 CSS 样式
*/
export function getMoreOptionsComponentStyles(): string {
return `
.more-options-wrapper {
position: relative;
}
/* 更多选项下拉面板 */
.more-options-dropdown {
display: none;
position: absolute;
top: calc(100% + 8px);
right: 0;
z-index: 10000;
min-width: 200px;
}
.more-options-dropdown.active {
display: block;
animation: dropdownSlideIn 0.15s ease-out;
}
@keyframes dropdownSlideIn {
from {
opacity: 0;
transform: translateY(-8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.more-options-content {
background: var(--vscode-dropdown-background);
border: 1px solid var(--vscode-dropdown-border);
border-radius: 6px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
overflow: hidden;
}
.more-options-header {
display: none;
}
.more-options-body {
padding: 4px;
}
.more-option-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
cursor: pointer;
transition: background 0.15s ease;
border-radius: 4px;
}
.more-option-item:hover {
background: var(--vscode-list-hoverBackground);
}
.more-option-item:active {
background: var(--vscode-list-activeSelectionBackground);
}
.option-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.8;
}
.option-icon svg {
width: 16px;
height: 16px;
color: var(--vscode-foreground);
}
.option-text {
flex: 1;
}
.option-label {
font-size: 13px;
color: var(--vscode-foreground);
}
.option-desc {
display: none;
}
/* 用户反馈二维码弹窗 */
.feedback-qrcode-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 20000;
align-items: center;
justify-content: center;
}
.feedback-qrcode-modal.active {
display: flex;
animation: fadeIn 0.2s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.feedback-qrcode-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
cursor: pointer;
}
.feedback-qrcode-content {
position: relative;
background: var(--vscode-editor-background);
border: 1px solid var(--vscode-widget-border);
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
max-width: 400px;
width: 90%;
animation: slideUp 0.2s ease-out;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.feedback-qrcode-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid var(--vscode-widget-border);
}
.feedback-qrcode-title {
font-size: 14px;
font-weight: 600;
color: var(--vscode-foreground);
}
.feedback-qrcode-close {
width: 28px;
height: 28px;
padding: 0;
background: transparent;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s ease;
}
.feedback-qrcode-close:hover {
background: var(--vscode-toolbar-hoverBackground);
}
.feedback-qrcode-close svg {
width: 16px;
height: 16px;
color: var(--vscode-foreground);
}
.feedback-qrcode-body {
padding: 24px;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.feedback-qrcode-image {
width: 200px;
height: 200px;
border: 1px solid var(--vscode-widget-border);
border-radius: 8px;
}
.feedback-qrcode-text {
margin: 0;
font-size: 13px;
color: var(--vscode-descriptionForeground);
text-align: center;
}
`;
}
/**
* 获取更多选项组件的 JavaScript 脚本
*/
export function getMoreOptionsComponentScript(): string {
return `
// 切换更多选项下拉面板
function toggleMoreOptionsDropdown() {
const dropdown = document.getElementById('moreOptionsDropdown');
const moreButton = document.querySelector('.more-button');
if (dropdown) {
const isActive = dropdown.classList.contains('active');
if (isActive) {
dropdown.classList.remove('active');
if (moreButton) {
moreButton.classList.remove('active');
}
} else {
dropdown.classList.add('active');
if (moreButton) {
moreButton.classList.add('active');
}
}
}
}
// 关闭更多选项下拉面板
function closeMoreOptionsDropdown() {
const dropdown = document.getElementById('moreOptionsDropdown');
const moreButton = document.querySelector('.more-button');
if (dropdown) {
dropdown.classList.remove('active');
}
if (moreButton) {
moreButton.classList.remove('active');
}
}
// 打开用户手册
function openUserManual() {
console.log('打开用户手册');
vscode.postMessage({ command: 'openUserManual' });
closeMoreOptionsDropdown();
}
// 打开用户反馈
function openUserFeedback() {
console.log('打开用户反馈');
vscode.postMessage({ command: 'openUserFeedback' });
closeMoreOptionsDropdown();
}
// 显示用户反馈二维码弹窗
function showFeedbackQRCode() {
const modal = document.getElementById('feedbackQRCodeModal');
if (modal) {
modal.classList.add('active');
}
}
// 关闭用户反馈二维码弹窗
function closeFeedbackQRCode() {
const modal = document.getElementById('feedbackQRCodeModal');
if (modal) {
modal.classList.remove('active');
}
}
// 绑定更多选项事件
document.addEventListener('DOMContentLoaded', () => {
// 绑定用户手册选项
const userManualOption = document.getElementById('userManualOption');
if (userManualOption) {
userManualOption.addEventListener('click', openUserManual);
}
// 绑定用户反馈选项
const userFeedbackOption = document.getElementById('userFeedbackOption');
if (userFeedbackOption) {
userFeedbackOption.addEventListener('click', openUserFeedback);
}
// 点击页面其他地方关闭下拉面板
document.addEventListener('click', (e) => {
const dropdown = document.getElementById('moreOptionsDropdown');
const moreButton = document.querySelector('.more-button');
const moreContainer = document.querySelector('.more-container');
if (dropdown && dropdown.classList.contains('active')) {
// 如果点击的不是更多按钮和下拉面板内容,则关闭
if (!moreContainer?.contains(e.target)) {
closeMoreOptionsDropdown();
}
}
});
// 阻止下拉面板内容点击事件冒泡
const dropdownContent = document.querySelector('.more-options-content');
if (dropdownContent) {
dropdownContent.addEventListener('click', (e) => {
e.stopPropagation();
});
}
});
`;
}

View File

@ -0,0 +1,177 @@
/**
* 获取规则设置组件的 HTML 内容
*/
export function getRulesSettingsComponentContent(): string {
return `
<div class="rules-settings">
<h3 class="settings-section-title">规则设置</h3>
<div class="settings-section">
<div class="settings-item">
<div class="settings-item-header">
<label class="settings-item-label">启用自定义规则</label>
<span class="settings-item-description">使用自定义规则来控制 AI 行为</span>
</div>
<label class="settings-switch">
<input type="checkbox" id="enableCustomRulesCheckbox" checked>
<span class="settings-switch-slider"></span>
</label>
</div>
</div>
<div class="settings-section">
<h4 class="settings-subsection-title">系统规则</h4>
<div class="rules-textarea-container">
<textarea
class="rules-textarea"
id="systemRulesTextarea"
placeholder="在此输入系统规则,例如:&#10;- 始终使用中文回复&#10;- 代码注释要详细&#10;- 遵循项目编码规范"
rows="8"
></textarea>
<div class="rules-textarea-hint">
系统规则会在每次对话开始时应用
</div>
</div>
</div>
<div class="settings-section">
<h4 class="settings-subsection-title">代码生成规则</h4>
<div class="rules-textarea-container">
<textarea
class="rules-textarea"
id="codeRulesTextarea"
placeholder="在此输入代码生成规则,例如:&#10;- 使用 TypeScript 严格模式&#10;- 函数命名使用驼峰命名法&#10;- 添加必要的错误处理"
rows="8"
></textarea>
<div class="rules-textarea-hint">
这些规则会在生成代码时应用
</div>
</div>
</div>
<div class="settings-section">
<h4 class="settings-subsection-title">Verilog 规则</h4>
<div class="rules-textarea-container">
<textarea
class="rules-textarea"
id="verilogRulesTextarea"
placeholder="在此输入 Verilog 代码规则,例如:&#10;- 使用非阻塞赋值 (<=) 在时序逻辑中&#10;- 模块命名使用小写加下划线&#10;- 添加详细的端口注释"
rows="8"
></textarea>
<div class="rules-textarea-hint">
这些规则会在生成 Verilog 代码时应用
</div>
</div>
</div>
<div class="settings-actions">
<button class="settings-button settings-button-primary" onclick="saveRulesSettings()">
保存规则
</button>
<button class="settings-button settings-button-secondary" onclick="resetRulesSettings()">
重置为默认
</button>
</div>
</div>
`;
}
/**
* 获取规则设置组件的 CSS 样式
*/
export function getRulesSettingsComponentStyles(): string {
return `
.rules-settings {
max-width: 700px;
}
.rules-textarea-container {
margin-top: 8px;
}
.rules-textarea {
width: 100%;
padding: 12px;
background: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
font-size: 13px;
font-family: var(--vscode-editor-font-family);
line-height: 1.5;
resize: vertical;
outline: none;
box-sizing: border-box;
}
.rules-textarea:focus {
border-color: var(--vscode-focusBorder);
}
.rules-textarea::placeholder {
color: var(--vscode-input-placeholderForeground);
opacity: 0.6;
}
.rules-textarea-hint {
margin-top: 8px;
font-size: 12px;
color: var(--vscode-descriptionForeground);
font-style: italic;
}
`;
}
/**
* 获取规则设置组件的 JavaScript 脚本
*/
export function getRulesSettingsComponentScript(): string {
return `
// 保存规则设置
function saveRulesSettings() {
const settings = {
enableCustomRules: document.getElementById('enableCustomRulesCheckbox').checked,
systemRules: document.getElementById('systemRulesTextarea').value,
codeRules: document.getElementById('codeRulesTextarea').value,
verilogRules: document.getElementById('verilogRulesTextarea').value,
};
// 发送消息到扩展
vscode.postMessage({
command: 'saveRulesSettings',
settings: settings
});
// 显示保存成功提示
console.log('规则设置已保存', settings);
}
// 重置规则设置
function resetRulesSettings() {
document.getElementById('enableCustomRulesCheckbox').checked = true;
document.getElementById('systemRulesTextarea').value = '';
document.getElementById('codeRulesTextarea').value = '';
document.getElementById('verilogRulesTextarea').value = '';
console.log('规则设置已重置为默认值');
}
// 加载规则设置
function loadRulesSettings(settings) {
if (!settings) return;
if (settings.enableCustomRules !== undefined) {
document.getElementById('enableCustomRulesCheckbox').checked = settings.enableCustomRules;
}
if (settings.systemRules) {
document.getElementById('systemRulesTextarea').value = settings.systemRules;
}
if (settings.codeRules) {
document.getElementById('codeRulesTextarea').value = settings.codeRules;
}
if (settings.verilogRules) {
document.getElementById('verilogRulesTextarea').value = settings.verilogRules;
}
}
`;
}

View File

@ -0,0 +1,248 @@
import {
getGeneralSettingsComponentContent,
getGeneralSettingsComponentStyles,
getGeneralSettingsComponentScript,
} from "./generalSettingsComponent";
import {
getRulesSettingsComponentContent,
getRulesSettingsComponentStyles,
getRulesSettingsComponentScript,
} from "./rulesSettingsComponent";
/**
* 获取设置面板的 HTML 内容
*/
export function getSettingsComponentContent(): string {
return `
<div class="settings-modal" id="settingsModal">
<div class="settings-modal-overlay" onclick="closeSettingsModal()"></div>
<div class="settings-modal-content">
<div class="settings-modal-header">
<h2 class="settings-modal-title">设置</h2>
<button class="settings-modal-close" onclick="closeSettingsModal()" title="关闭">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" fill="currentColor"/>
</svg>
</button>
</div>
<div class="settings-modal-body">
<div class="settings-nav">
<button class="settings-nav-item active" data-tab="general" onclick="switchSettingsTab('general')">
通用
</button>
<button class="settings-nav-item" data-tab="rules" onclick="switchSettingsTab('rules')">
规则
</button>
</div>
<div class="settings-content">
<div class="settings-tab-content active" id="generalSettings">
${getGeneralSettingsComponentContent()}
</div>
<div class="settings-tab-content" id="rulesSettings">
${getRulesSettingsComponentContent()}
</div>
</div>
</div>
</div>
</div>
`;
}
/**
* 获取设置面板的 CSS 样式
*/
export function getSettingsComponentStyles(): string {
return `
.settings-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
}
.settings-modal.active {
display: flex;
align-items: center;
justify-content: center;
}
.settings-modal-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.settings-modal-content {
position: relative;
width: 90%;
max-width: 800px;
height: 80%;
max-height: 600px;
background: var(--vscode-editor-background);
border: 1px solid var(--vscode-panel-border);
border-radius: 8px;
display: flex;
flex-direction: column;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
.settings-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid var(--vscode-panel-border);
flex-shrink: 0;
}
.settings-modal-title {
margin: 0;
font-size: 18px;
font-weight: 600;
color: var(--vscode-foreground);
}
.settings-modal-close {
width: 32px;
height: 32px;
padding: 0;
background: transparent;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--vscode-foreground);
transition: all 0.2s ease;
}
.settings-modal-close:hover {
background: var(--vscode-toolbar-hoverBackground);
}
.settings-modal-close svg {
width: 20px;
height: 20px;
}
.settings-modal-body {
display: flex;
flex: 1;
overflow: hidden;
}
.settings-nav {
width: 180px;
padding: 16px 0;
border-right: 1px solid var(--vscode-panel-border);
flex-shrink: 0;
overflow-y: auto;
}
.settings-nav-item {
width: 100%;
padding: 10px 20px;
background: transparent;
border: none;
text-align: left;
font-size: 14px;
color: var(--vscode-foreground);
cursor: pointer;
transition: all 0.2s ease;
border-left: 3px solid transparent;
}
.settings-nav-item:hover {
background: var(--vscode-list-hoverBackground);
}
.settings-nav-item.active {
background: var(--vscode-list-activeSelectionBackground);
color: var(--vscode-list-activeSelectionForeground);
border-left-color: var(--vscode-focusBorder);
}
.settings-content {
flex: 1;
overflow-y: auto;
padding: 20px;
}
.settings-tab-content {
display: none;
}
.settings-tab-content.active {
display: block;
}
${getGeneralSettingsComponentStyles()}
${getRulesSettingsComponentStyles()}
`;
}
/**
* 获取设置面板的 JavaScript 脚本
*/
export function getSettingsComponentScript(): string {
return `
${getGeneralSettingsComponentScript()}
${getRulesSettingsComponentScript()}
// 打开设置面板
function openSettingsModal() {
const modal = document.getElementById('settingsModal');
if (modal) {
modal.classList.add('active');
}
}
// 关闭设置面板
function closeSettingsModal() {
const modal = document.getElementById('settingsModal');
if (modal) {
modal.classList.remove('active');
}
}
// 切换设置标签页
function switchSettingsTab(tabName) {
// 更新导航项状态
const navItems = document.querySelectorAll('.settings-nav-item');
navItems.forEach(item => {
if (item.dataset.tab === tabName) {
item.classList.add('active');
} else {
item.classList.remove('active');
}
});
// 更新内容区域
const tabContents = document.querySelectorAll('.settings-tab-content');
tabContents.forEach(content => {
if (content.id === tabName + 'Settings') {
content.classList.add('active');
} else {
content.classList.remove('active');
}
});
}
// 阻止点击模态框内容时关闭
document.addEventListener('click', (event) => {
const modalContent = document.querySelector('.settings-modal-content');
if (modalContent && modalContent.contains(event.target)) {
event.stopPropagation();
}
});
`;
}

View File

@ -14,14 +14,20 @@ export function getUserInfoComponentContent(): string {
<div class="user-detail-dropdown" id="userDetailDropdown"> <div class="user-detail-dropdown" id="userDetailDropdown">
<div class="user-detail-content"> <div class="user-detail-content">
<div class="user-detail-header"> <div class="user-detail-header">
<div class="user-avatar-small"> <div class="user-info-row">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <div class="user-avatar-small clickable" id="userAvatarClickable">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" fill="currentColor"/> <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
</svg> <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" fill="currentColor"/>
</svg>
</div>
<div class="user-name-tier">
<div class="user-detail-name clickable" id="userDetailName">加载中...</div>
<img class="tier-icon-inline" id="tierIconInline" style="display: none;" />
</div>
</div> </div>
<div class="user-name-tier"> <!-- 升级到Pro按钮 (仅BASIC会员显示) -->
<div class="user-detail-name" id="userDetailName">加载中...</div> <div class="upgrade-pro-wrapper" id="upgradeProWrapper" style="display: none;">
<img class="tier-icon-inline" id="tierIconInline" style="display: none;" /> <button class="upgrade-pro-btn" id="upgradeProBtn">升级到 Pro</button>
</div> </div>
</div> </div>
@ -30,10 +36,31 @@ export function getUserInfoComponentContent(): string {
<span class="detail-label">剩余 Credits</span> <span class="detail-label">剩余 Credits</span>
<span class="detail-value" id="creditsDetail">-</span> <span class="detail-value" id="creditsDetail">-</span>
</div> </div>
<div class="user-detail-item logout-item" id="logoutItem">
<span class="detail-label">账户管理</span>
<span class="detail-value logout-link">退出登录</span>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- 退出登录确认对话框 -->
<div class="logout-confirm-modal" id="logoutConfirmModal">
<div class="logout-confirm-overlay"></div>
<div class="logout-confirm-content">
<div class="logout-confirm-header">
<h3>确认退出</h3>
</div>
<div class="logout-confirm-body">
<p>确定要退出登录吗?</p>
</div>
<div class="logout-confirm-footer">
<button class="logout-confirm-btn logout-cancel-btn" id="logoutCancelBtn">取消</button>
<button class="logout-confirm-btn logout-ok-btn" id="logoutOkBtn">确定</button>
</div>
</div>
</div>
`; `;
} }
@ -84,12 +111,18 @@ export function getUserInfoComponentStyles(): string {
.user-detail-header { .user-detail-header {
padding: 16px; padding: 16px;
display: flex; display: flex;
align-items: center; flex-direction: column;
gap: 12px; gap: 12px;
background: linear-gradient(135deg, rgba(0, 122, 204, 0.1) 0%, rgba(88, 166, 255, 0.05) 100%); background: linear-gradient(135deg, rgba(0, 122, 204, 0.1) 0%, rgba(88, 166, 255, 0.05) 100%);
border-bottom: 1px solid var(--vscode-widget-border); border-bottom: 1px solid var(--vscode-widget-border);
} }
.user-info-row {
display: flex;
align-items: center;
gap: 12px;
}
.user-avatar-small { .user-avatar-small {
width: 26px; width: 26px;
height: 26px; height: 26px;
@ -100,6 +133,16 @@ export function getUserInfoComponentStyles(): string {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-shadow: 0 2px 8px rgba(0, 122, 204, 0.3); box-shadow: 0 2px 8px rgba(0, 122, 204, 0.3);
transition: all 0.2s ease;
}
.user-avatar-small.clickable {
cursor: pointer;
}
.user-avatar-small.clickable:hover {
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 122, 204, 0.5);
} }
.user-avatar-small svg { .user-avatar-small svg {
@ -119,6 +162,16 @@ export function getUserInfoComponentStyles(): string {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: var(--vscode-foreground); color: var(--vscode-foreground);
transition: all 0.2s ease;
}
.user-detail-name.clickable {
cursor: pointer;
}
.user-detail-name.clickable:hover {
color: #007acc;
text-decoration: underline;
} }
.tier-icon-inline { .tier-icon-inline {
@ -152,6 +205,19 @@ export function getUserInfoComponentStyles(): string {
margin-bottom: 0; margin-bottom: 0;
} }
.logout-item {
cursor: pointer;
}
.logout-item:hover {
background: var(--vscode-list-hoverBackground);
border-color: rgba(204, 0, 0, 0.3);
}
.logout-item:hover .logout-link {
color: #f48771;
}
.detail-label { .detail-label {
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
@ -168,6 +234,11 @@ export function getUserInfoComponentStyles(): string {
gap: 6px; gap: 6px;
} }
.logout-link {
color: var(--vscode-foreground);
transition: color 0.2s ease;
}
.tier-icon-large { .tier-icon-large {
height: 20px; height: 20px;
object-fit: contain; object-fit: contain;
@ -180,6 +251,136 @@ export function getUserInfoComponentStyles(): string {
object-fit: contain; object-fit: contain;
border-radius: 4px; border-radius: 4px;
} }
.upgrade-pro-wrapper {
margin-top: 8px;
}
.upgrade-pro-btn {
width: 100%;
padding: 6px 12px;
background: linear-gradient(135deg, #007acc 0%, #58a6ff 100%);
color: #ffffff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 11px;
font-weight: 600;
transition: all 0.2s ease;
box-shadow: 0 1px 4px rgba(0, 122, 204, 0.2);
letter-spacing: 0.3px;
}
.upgrade-pro-btn:hover {
background: linear-gradient(135deg, #0098ff 0%, #6bb6ff 100%);
box-shadow: 0 2px 8px rgba(0, 122, 204, 0.4);
transform: translateY(-1px);
}
.upgrade-pro-btn:active {
transform: translateY(0) scale(0.98);
box-shadow: 0 1px 4px rgba(0, 122, 204, 0.3);
}
/* 退出登录确认对话框 */
.logout-confirm-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 20000;
}
.logout-confirm-modal.active {
display: block;
}
.logout-confirm-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.logout-confirm-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--vscode-editor-background);
border: 1px solid var(--vscode-widget-border);
border-radius: 8px;
min-width: 320px;
max-width: 400px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.logout-confirm-header {
padding: 16px 20px;
border-bottom: 1px solid var(--vscode-widget-border);
}
.logout-confirm-header h3 {
margin: 0;
font-size: 14px;
font-weight: 600;
color: var(--vscode-foreground);
}
.logout-confirm-body {
padding: 20px;
}
.logout-confirm-body p {
margin: 0;
font-size: 13px;
color: var(--vscode-foreground);
line-height: 1.5;
}
.logout-confirm-footer {
padding: 12px 20px;
display: flex;
justify-content: flex-end;
gap: 8px;
border-top: 1px solid var(--vscode-widget-border);
}
.logout-confirm-btn {
padding: 6px 16px;
border: none;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.logout-cancel-btn {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
}
.logout-cancel-btn:hover {
background: var(--vscode-button-secondaryHoverBackground);
}
.logout-ok-btn {
background: #f48771;
color: #ffffff;
}
.logout-ok-btn:hover {
background: #e67361;
}
.logout-confirm-btn:active {
transform: scale(0.98);
}
`; `;
} }
@ -214,6 +415,44 @@ export function getUserInfoComponentScript(): string {
} }
} }
// 退出登录
function logout() {
console.log("显示退出登录确认对话框");
// 显示确认对话框
const modal = document.getElementById('logoutConfirmModal');
if (modal) {
modal.classList.add('active');
}
}
// 确认退出登录
function confirmLogout() {
console.log("确认退出登录");
vscode.postMessage({ command: 'logout' });
// 关闭确认对话框
closeLogoutConfirmModal();
}
// 关闭退出登录确认对话框
function closeLogoutConfirmModal() {
const modal = document.getElementById('logoutConfirmModal');
if (modal) {
modal.classList.remove('active');
}
}
// 跳转到 IC Coder 官网
function openICCoder() {
console.log("跳转到 IC Coder 官网");
vscode.postMessage({ command: 'openICCoder' });
}
// 升级到Pro
function upgradeToPro() {
console.log("升级到 Pro - 跳转到 IC Coder 官网");
vscode.postMessage({ command: 'openExternalUrl', url: 'https://www.iccoder.com' });
}
// 关闭用户详情下拉面板 // 关闭用户详情下拉面板
function closeUserDetailModal() { function closeUserDetailModal() {
const dropdown = document.getElementById('userDetailDropdown'); const dropdown = document.getElementById('userDetailDropdown');
@ -260,6 +499,19 @@ export function getUserInfoComponentScript(): string {
} else { } else {
console.warn('[UserInfoComponent] creditsDetail 元素未找到'); console.warn('[UserInfoComponent] creditsDetail 元素未找到');
} }
// 显示或隐藏升级到Pro按钮 (仅BASIC会员显示)
const upgradeProWrapper = document.getElementById('upgradeProWrapper');
const tierCode = currentUserInfo.membership?.tierCode;
if (upgradeProWrapper) {
if (tierCode === 'BASIC') {
upgradeProWrapper.style.display = 'block';
} else {
upgradeProWrapper.style.display = 'none';
}
} else {
console.warn('[UserInfoComponent] upgradeProWrapper 元素未找到');
}
} }
// 更新用户信息显示 // 更新用户信息显示
@ -275,6 +527,66 @@ export function getUserInfoComponentScript(): string {
// 绑定下拉面板事件 // 绑定下拉面板事件
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// 绑定退出登录卡片点击事件
const logoutItem = document.getElementById('logoutItem');
if (logoutItem) {
logoutItem.addEventListener('click', () => {
logout();
});
}
// 绑定退出登录确认对话框按钮
const logoutOkBtn = document.getElementById('logoutOkBtn');
if (logoutOkBtn) {
logoutOkBtn.addEventListener('click', () => {
confirmLogout();
});
}
const logoutCancelBtn = document.getElementById('logoutCancelBtn');
if (logoutCancelBtn) {
logoutCancelBtn.addEventListener('click', () => {
closeLogoutConfirmModal();
});
}
// 点击遮罩层关闭对话框
const logoutConfirmModal = document.getElementById('logoutConfirmModal');
if (logoutConfirmModal) {
const overlay = logoutConfirmModal.querySelector('.logout-confirm-overlay');
if (overlay) {
overlay.addEventListener('click', () => {
closeLogoutConfirmModal();
});
}
}
// 绑定升级到Pro按钮
const upgradeProBtn = document.getElementById('upgradeProBtn');
if (upgradeProBtn) {
upgradeProBtn.addEventListener('click', () => {
upgradeToPro();
});
}
// 绑定头像点击事件
const userAvatar = document.getElementById('userAvatarClickable');
if (userAvatar) {
userAvatar.addEventListener('click', (e) => {
e.stopPropagation();
openICCoder();
});
}
// 绑定用户名点击事件
const userName = document.getElementById('userDetailName');
if (userName) {
userName.addEventListener('click', (e) => {
e.stopPropagation();
openICCoder();
});
}
// 点击页面其他地方关闭下拉面板 // 点击页面其他地方关闭下拉面板
document.addEventListener('click', (e) => { document.addEventListener('click', (e) => {
const dropdown = document.getElementById('userDetailDropdown'); const dropdown = document.getElementById('userDetailDropdown');

View File

@ -33,7 +33,8 @@ export function getWebviewContent(
autoIconUri?: string, autoIconUri?: string,
liteIconUri?: string, liteIconUri?: string,
syIconUri?: string, syIconUri?: string,
maxIconUri?: string maxIconUri?: string,
qrCodeUri?: string
): string { ): string {
// 获取当前环境,只在 dev 和 test 环境下显示快速操作按钮 // 获取当前环境,只在 dev 和 test 环境下显示快速操作按钮
const currentEnv = getCurrentEnv(); const currentEnv = getCurrentEnv();
@ -72,7 +73,10 @@ export function getWebviewContent(
display: none; display: none;
} }
.header h1 { .header h1 {
color: var(--vscode-button-background); background: linear-gradient(to right, #4A9EFF, #7CB8FF, #A8D0FF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin: 0 0 8px 0; margin: 0 0 8px 0;
} }
.chat-container { .chat-container {
@ -395,11 +399,11 @@ export function getWebviewContent(
${getConversationHistoryBarContent()} ${getConversationHistoryBarContent()}
${getProgressBarContent()} ${getProgressBarContent()}
<div class="header"> <div class="header">
<div style="display: flex; align-items: center; justify-content: center; gap: 10px;"> <div style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="${iconUri}" alt="IC Coder" style="width: 28px; height: 28px;" /> <img src="${iconUri}" alt="IC Coder" style="width: 48px; height: 48px;" />
<h1 style="margin: 0;">IC Coder</h1> <h1 style="margin: 0; font-size: 36px;">IC Coder</h1>
</div> </div>
<p>专注于真实FPGA研发的Verilog智能体编程平台</p> <p style="font-size: 16px; margin-top: 12px;">专注于真实FPGA研发的Verilog智能体编程平台</p>
</div> </div>
<div class="chat-container"> <div class="chat-container">
@ -439,6 +443,12 @@ export function getWebviewContent(
let loadingIndicator = null; let loadingIndicator = null;
let currentSegmentedMessage = null; // 当前分段消息容器 let currentSegmentedMessage = null; // 当前分段消息容器
// 设置二维码图片
const feedbackQRCodeImage = document.getElementById('feedbackQRCodeImage');
if (feedbackQRCodeImage && '${qrCodeUri}') {
feedbackQRCodeImage.src = '${qrCodeUri}';
}
// ========== 模式选择器脚本(直接内联,避免模板字符串嵌套问题)========== // ========== 模式选择器脚本(直接内联,避免模板字符串嵌套问题)==========
let currentMode = 'agent'; let currentMode = 'agent';
@ -597,11 +607,13 @@ export function getWebviewContent(
tierName: message.userInfo.tierName, tierName: message.userInfo.tierName,
tierIconUrl: message.tierIconUrl, tierIconUrl: message.tierIconUrl,
registerTime: message.userInfo.registerTime || message.userInfo.createdAt, registerTime: message.userInfo.registerTime || message.userInfo.createdAt,
credits: message.userInfo.credits credits: message.userInfo.credits,
membership: message.userInfo.membership
}; };
console.log('[WebView] 显示用户信息:', userInfoData); console.log('[WebView] 显示用户信息:', userInfoData);
console.log('[WebView] userInfoData.credits:', userInfoData.credits); console.log('[WebView] userInfoData.credits:', userInfoData.credits);
console.log('[WebView] userInfoData.membership:', userInfoData.membership);
// 调用更新用户头像图标按钮的函数 // 调用更新用户头像图标按钮的函数
if (typeof updateUserAvatarIconButton === 'function') { if (typeof updateUserAvatarIconButton === 'function') {
@ -612,6 +624,14 @@ export function getWebviewContent(
} }
break; break;
case 'showFeedbackQRCode':
// 显示用户反馈二维码弹窗
console.log('[WebView] 显示用户反馈二维码弹窗');
if (typeof showFeedbackQRCode === 'function') {
showFeedbackQRCode();
}
break;
case 'resetSegmentedMessage': case 'resetSegmentedMessage':
// 重置分段消息容器(停止对话时调用) // 重置分段消息容器(停止对话时调用)
console.log('[WebView] 重置分段消息容器'); console.log('[WebView] 重置分段消息容器');
@ -635,6 +655,14 @@ export function getWebviewContent(
if (typeof hasWorkspace !== 'undefined') { if (typeof hasWorkspace !== 'undefined') {
hasWorkspace = message.hasWorkspace; hasWorkspace = message.hasWorkspace;
console.log('[WebView] 工作区状态:', hasWorkspace); console.log('[WebView] 工作区状态:', hasWorkspace);
// 如果有待发送的示例,且工作区存在,则发送
if (hasWorkspace && typeof pendingExampleIndex !== 'undefined' && pendingExampleIndex >= 0) {
if (typeof doSendExample === 'function') {
doSendExample(pendingExampleIndex);
pendingExampleIndex = -1; // 重置
}
}
} }
break; break;