15 Commits

Author SHA1 Message Date
21a8abd5cf Merge remote-tracking branch 'origin/feat/front-end' into feat/back-to-front
# Conflicts:
#	src/services/dialogService.ts
2026-01-13 14:34:08 +08:00
58113fb109 feat:Credits不足进行跳转到web端的重置界面 2026-01-12 21:03:37 +08:00
25966bc1e2 feat:显示资源点
- 登录之后就获取资源点并持久化
- 显示剩余资源点到页面上
- 一轮对话完成之后重新获取资源点并且更新缓存
2026-01-12 19:09:19 +08:00
3c93c07afd Merge branch 'feat/back-to-front' into feat/front-end 2026-01-12 18:38:41 +08:00
85a37b546c Merge branch 'feat/back-to-front' of https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin into feat/back-to-front 2026-01-12 18:37:55 +08:00
341b6540fa Merge branch 'feat/back-to-front' into feat/front-end 2026-01-12 18:11:13 +08:00
1d074e5a94 Merge branch 'feat/back-to-front' of https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin into feat/back-to-front 2026-01-12 18:10:34 +08:00
43189e144a feat:输入框下面展示案例和web端的跳转 2026-01-12 18:00:54 +08:00
d08f9a7366 style:spec文档的markdown样式适配 2026-01-12 14:03:20 +08:00
faa7b63aee feat:修复预览波形只能展示一个的bug + iverilog工具映射 2026-01-12 12:01:16 +08:00
e440dd2773 feat:添加更新阶段的映射和icon 2026-01-12 11:38:06 +08:00
a3fd5df8e8 Merge branch 'feat/back-to-front' of https://git.pengyejiatu.com/pengyejiatu/IC-Coder-Plugin into feat/back-to-front 2026-01-12 09:26:44 +08:00
d44b316c9a fix:解决打包错误 2026-01-10 21:26:46 +08:00
939768986c fix:修改了build的错误问题 2026-01-10 21:21:24 +08:00
1e99f3cb20 faat:修改环境为测试服务器的 2026-01-10 21:19:15 +08:00
15 changed files with 401 additions and 66 deletions

View File

@ -1,29 +0,0 @@
# 排除开发文件
.vscode/**
.git/**
.gitignore
node_modules/**
src/**
**/*.ts
**/*.map
# 排除测试文件
test/**
**/*.test.js
# 排除文档
*.md
!README.md
# 排除 waveform_trace Python 源码(只保留 exe
tools/waveform_trace/src/**
tools/waveform_trace/build/**
tools/waveform_trace/dist/**
tools/waveform_trace/build.bat
tools/waveform_trace/build.sh
# 排除打包临时文件
**/__pycache__/**
**/*.pyc
**/*.pyo
**/*.spec

View File

@ -180,3 +180,8 @@ export const userQuestionIconSvg = `<svg t="1767869230062" class="icon" viewBox=
* 用户头像图标 SVG
*/
export const userAvatarIconSvg = `<svg t="1767947405083" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4661" width="16" height="16"><path d="M515.541449 7.082899c-280.359429 0-508.458551 228.120391-508.458551 508.458551s228.120391 508.458551 508.458551 508.458551 508.458551-228.120391 508.458551-508.458551S795.900879 7.082899 515.541449 7.082899zM515.541449 981.864196c-257.132626 0-466.301477-209.190121-466.301477-466.322747 0-257.132626 209.168851-466.322747 466.301477-466.322747s466.301477 209.190121 466.301477 466.322747S772.674075 981.864196 515.541449 981.864196zM614.574414 524.177056 614.574414 524.177056c47.751075-31.96876 79.230625-86.398604 79.230625-148.187857 0-98.437405-79.804915-178.24232-178.24232-178.24232-98.437405 0-178.24232 79.804915-178.24232 178.24232 0 61.810523 31.479551 116.219097 79.251895 148.187857-100.266622 39.519598-171.244501 137.170014-171.244501 251.453545 0 0.23397 0 0.446669 0.02127 0.659369 0 0.04254-0.02127 0.10635-0.02127 0.14889 0 15.612155 12.65563 28.246516 28.267786 28.246516 15.590885 0 21.886796-12.63436 21.886796-28.246516 0-0.340319-0.08508-0.659369-0.10635-1.020958 0.10635-118.005774 102.159649-219.995264 220.207964-219.995264 118.112124 0 220.207964 102.095839 220.207964 220.207964 0 0.14889-1.467628 29.054774 21.971875 29.054774 15.505806 0 28.076356-12.57055 28.076356-28.055086 0-0.06381-0.02127-0.12762-0.02127-0.2127 0-0.25524 0.02127-0.510479 0.02127-0.786989C785.797645 661.34707 714.798496 563.696654 614.574414 524.177056zM515.541449 510.734437c-74.402343 0-134.723968-60.321625-134.723968-134.723968 0-74.423613 60.321625-134.723968 134.723968-134.723968 74.423613 0 134.723968 60.321625 134.723968 134.723968S589.943792 510.734437 515.541449 510.734437z" fill="currentColor" p-id="4662"></path></svg>`;
/**
* 更新阶段图标 SVG
*/
export const updateStageIconSvg = `<svg t="1768188846282" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7848" width="14" height="14"><path d="M83.712 1024c-0.256 0-0.768 0-1.024-0.256-17.408-0.512-31.488-14.848-31.488-32.512V32.512C51.2 14.592 65.792 0 83.712 0h745.472c17.92 0 32.512 14.592 32.512 32.512v280.576c0 18.432-14.592 33.28-32.512 33.28-1.536 0-3.072 0-4.608-0.256-16.128-2.304-27.648-15.872-27.648-32V77.056c0-6.912-5.632-12.288-12.288-12.288H128.256c-6.912 0-12.288 5.632-12.288 12.288v869.632c0 6.912 5.632 12.288 12.288 12.288h238.08c9.728 0 18.944 4.096 25.344 11.52 6.144 7.168 8.96 16.384 7.68 25.6-2.304 16.128-15.872 27.648-32 27.648H83.712v0.256zM534.784 1024c-6.144 0-12.032-2.816-15.616-7.424-3.84-4.352-5.376-10.496-4.352-16.64l27.648-147.968c0-0.512 0.512-1.024 0.768-1.536L867.84 558.336c11.52-11.264 26.624-17.664 42.24-17.664 16.384 0 31.488 6.4 42.752 17.664l53.76 53.504c23.296 23.04 23.552 60.928 0.768 84.736l-0.768 0.768-323.584 294.912c-2.816 2.56-6.4 4.352-9.984 5.12l-134.656 26.368c-0.512 0-2.048 0.256-3.584 0.256z m95.488-182.528c-1.024 0-1.792 0.256-2.56 1.024L590.848 875.52c-0.512 0.512-1.024 1.28-1.28 2.048l-15.104 81.152c-0.256 1.792 0.768 3.072 0.768 3.072 0.768 0.768 1.792 1.28 2.816 1.28H578.816l73.984-14.336c0.768-0.256 1.28-0.512 1.792-0.768l38.4-34.816c0.768-0.768 1.024-1.536 1.024-2.56s-0.256-2.304-1.024-3.072l-60.416-64.768-0.256-0.256c0-0.512-1.024-1.024-2.048-1.024z m217.088-194.56c-1.024 0-1.792 0.256-2.56 1.024l-172.8 155.392c-0.768 0.768-1.28 1.536-1.28 2.816 0 1.024 0.256 2.048 1.024 2.56l60.16 64.768c0.768 0.768 1.792 1.28 2.816 1.28s1.792-0.256 2.56-1.024l173.568-157.952c0.768-0.768 1.024-1.536 1.024-2.56s-0.256-2.048-1.28-3.072L849.92 647.936c-0.512-0.256-1.536-1.024-2.56-1.024z m101.376 28.928c0.768 0.768 1.536 1.024 2.816 1.024 1.024 0 1.792-0.256 2.56-1.024l16.384-14.848 0.512-0.512c3.072-3.584 2.816-8.704-0.512-12.032L916.48 594.944c-1.536-1.536-4.096-2.56-6.144-2.56-2.56 0-4.864 1.024-6.4 2.56-0.256 0.256-0.512 0.512-0.768 0.512l-17.664 15.872 63.232 64.512z" p-id="7849" fill="#8a8a8a"></path><path d="M212.48 419.584h118.016v39.424H212.48v-39.424z m137.472-118.016h118.016v39.424h-118.016v-39.424z m137.728-118.016h196.608v39.424h-196.608V183.552z m0 0" fill="#8a8a8a" p-id="7850"></path><path d="M664.576 242.688h-157.184c-11.776 0-19.712 7.936-19.712 19.712v98.304h-118.016c-11.776 0-19.712 7.936-19.712 19.712V478.72h-117.76c-11.776 0-19.712 7.936-19.712 19.712v118.016c0 11.776 7.936 19.712 19.712 19.712h432.384c11.776 0 19.712-7.936 19.712-19.712V262.144c-0.256-11.776-7.936-19.456-19.712-19.456zM369.664 576.768h-117.76v-39.424h118.016v39.424z m137.728-118.016h-118.016v-39.424h118.016v39.424z m137.472-117.76h-118.016v-39.424h118.016v39.424z m0 0" fill="#8a8a8a" p-id="7851"></path></svg>`;

View File

@ -6,6 +6,7 @@ import { ChatHistoryManager } from "./utils/chatHistoryManager";
import { ICCoderAuthenticationProvider } from "./services/icCoderAuthProvider";
import { VCDFileServer } from "./services/vcdFileServer";
import { initUserService } from "./services/userService";
import { initCreditsService } from "./services/creditsService";
export function activate(context: vscode.ExtensionContext) {
console.log("🎉 IC Coder 插件已激活!");
@ -13,6 +14,9 @@ export function activate(context: vscode.ExtensionContext) {
// 初始化用户服务
initUserService(context);
// 初始化 Credits 服务
initCreditsService(context);
// 初始化 VCD 文件服务器
const vcdFileServer = new VCDFileServer(context.extensionUri);
vcdFileServer.start().then((port) => {

View File

@ -147,16 +147,20 @@ export async function showICHelperPanel(
if (userInfo) {
// 使用缓存的用户信息
console.log('[ICHelperPanel] 使用缓存的用户信息:', userInfo);
console.log('[ICHelperPanel] Credits 余额:', userInfo.credits);
const tierIconUrl = getTierIconUri(panel.webview, context, userInfo.membership?.tierCode);
panel.webview.postMessage({
const messageData = {
command: 'updateUserInfo',
userInfo: {
userId: userInfo.userId,
nickname: userInfo.nickname,
username: userInfo.username
username: userInfo.username,
credits: userInfo.credits
},
tierIconUrl: tierIconUrl
});
};
console.log('[ICHelperPanel] 发送用户信息到前端:', messageData);
panel.webview.postMessage(messageData);
} else {
// 如果没有缓存,从 session 中获取
const session = await vscode.authentication.getSession("iccoder", [], {

View File

@ -22,6 +22,33 @@ let lastUpdateTime: number = 0;
/** 缓存有效期5分钟 */
const CACHE_TTL_MS = 5 * 60 * 1000;
/** ExtensionContext 用于持久化存储 */
let extensionContext: vscode.ExtensionContext | null = null;
/**
* 初始化 Credits 服务(设置 context
*/
export function initCreditsService(context: vscode.ExtensionContext): void {
extensionContext = context;
// 从持久化存储加载余额
const savedBalance = extensionContext.globalState.get<number>('icCoderCreditsBalance');
if (savedBalance !== undefined) {
cachedBalance = savedBalance;
lastUpdateTime = Date.now();
console.log('[CreditsService] 从持久化存储加载余额:', savedBalance);
}
}
/**
* 保存余额到持久化存储
*/
async function saveBalance(balance: number): Promise<void> {
if (extensionContext) {
await extensionContext.globalState.update('icCoderCreditsBalance', balance);
console.log('[CreditsService] 余额已保存到持久化存储:', balance);
}
}
/**
* 更新缓存的余额(从 SSE credit_update 事件调用)
*/
@ -29,6 +56,10 @@ export function updateCachedBalance(balance: number): void {
cachedBalance = balance;
lastUpdateTime = Date.now();
console.log('[CreditsService] 余额已更新:', balance);
// 异步保存到持久化存储
saveBalance(balance).catch(err => {
console.error('[CreditsService] 保存余额失败:', err);
});
}
/**
@ -203,8 +234,11 @@ export async function checkBalanceBeforeSend(): Promise<{
/**
* 清除缓存(登出时调用)
*/
export function clearBalanceCache(): void {
export async function clearBalanceCache(): Promise<void> {
cachedBalance = null;
lastUpdateTime = 0;
if (extensionContext) {
await extensionContext.globalState.update('icCoderCreditsBalance', undefined);
}
console.log('[CreditsService] 余额缓存已清除');
}

View File

@ -8,6 +8,7 @@ import { URL } from 'url';
import * as vscode from 'vscode';
import { getStrangeLoopApiUrl, getConfig } from '../config/settings';
import type { UserInfoResponse, MembershipResponse, MultiMembershipVO, MembershipItemVO } from '../types/api';
import { fetchBalance, getCachedBalance } from './creditsService';
/**
* HTTP 请求选项
@ -114,6 +115,8 @@ export interface UserInfo {
remainingDays?: number;
monthlyCredits?: number;
};
// Credits 余额
credits?: number;
}
/**
@ -221,12 +224,13 @@ function getHighestTierMembership(allMemberships?: MembershipItemVO[]): Membersh
*/
export async function onTokenReceived(token: string): Promise<UserInfo | null> {
try {
console.log('[UserService] Token 已获取,正在获取用户信息会员信息...');
console.log('[UserService] Token 已获取,正在获取用户信息会员信息和余额...');
// 并行获取用户信息会员信息
const [userInfo, membershipInfo] = await Promise.all([
// 并行获取用户信息会员信息和余额
const [userInfo, membershipInfo, credits] = await Promise.all([
getUserInfo(token),
getMembershipInfo(token)
getMembershipInfo(token),
fetchBalance()
]);
if (!userInfo) {
@ -234,6 +238,15 @@ export async function onTokenReceived(token: string): Promise<UserInfo | null> {
return null;
}
// 添加 Credits 余额到用户信息
console.log('[UserService] 获取到的 Credits 余额:', credits);
if (credits !== null) {
userInfo.credits = credits;
console.log('[UserService] Credits 已添加到用户信息');
} else {
console.warn('[UserService] Credits 余额为 null未添加到用户信息');
}
// 打印用户信息到控制台
console.log('='.repeat(60));
console.log('用户信息详情:');
@ -286,6 +299,15 @@ export async function onTokenReceived(token: string): Promise<UserInfo | null> {
}
}
// 打印 Credits 余额
console.log('');
console.log('资源点余额:');
if (userInfo.credits !== undefined) {
console.log(`当前余额: ${userInfo.credits} Credits`);
} else {
console.log('当前余额: 未获取到余额信息');
}
console.log('='.repeat(60));
// 保存到持久化存储
@ -329,7 +351,18 @@ export function getCachedUserInfo(): UserInfo | null {
console.warn('[UserService] ExtensionContext 未初始化');
return null;
}
return extensionContext.globalState.get<UserInfo>('icCoderUserInfo') || null;
const userInfo = extensionContext.globalState.get<UserInfo>('icCoderUserInfo') || null;
// 从 creditsService 加载余额并合并到用户信息中
if (userInfo) {
const cachedCredits = getCachedBalance();
if (cachedCredits !== null) {
userInfo.credits = cachedCredits;
console.log('[UserService] 从 creditsService 加载余额:', cachedCredits);
}
}
return userInfo;
}
/**

View File

@ -18,7 +18,10 @@ import { ChatHistoryManager } from "./chatHistoryManager";
import { dialogManager, DialogSession } from "../services/dialogService";
import { userInteractionManager } from "../services/userInteraction";
import { healthCheck } from "../services/apiClient";
import { checkBalanceBeforeSend } from "../services/creditsService";
import {
checkBalanceBeforeSend,
fetchBalance,
} from "../services/creditsService";
import type { RunMode, ServiceTier } from "../types/api";
@ -39,7 +42,7 @@ export async function handleUserMessage(
text: string,
extensionPath?: string,
mode?: RunMode,
serviceTier?: ServiceTier // 新增:服务等级参数
serviceTier?: ServiceTier // 新增:服务等级参数
) {
console.log("收到用户消息:", text);
@ -78,7 +81,9 @@ export async function handleUserMessage(
"去充值"
);
if (selection === "去充值") {
vscode.env.openExternal(vscode.Uri.parse("https://iccoder.com/recharge"));
vscode.env.openExternal(
vscode.Uri.parse("https://iccoder.com/memberCenter")
);
}
// 恢复输入状态
panel.webview.postMessage({
@ -92,7 +97,14 @@ export async function handleUserMessage(
// 尝试使用后端服务
if (useBackendService && extensionPath) {
try {
await handleUserMessageWithBackend(panel, text, extensionPath, mode, undefined, serviceTier);
await handleUserMessageWithBackend(
panel,
text,
extensionPath,
mode,
undefined,
serviceTier
);
return;
} catch (error) {
console.error("后端服务不可用:", error);
@ -128,7 +140,7 @@ async function handleUserMessageWithBackend(
extensionPath: string,
mode?: RunMode,
reuseTaskId?: string, // 可选,复用现有 taskId用于 Plan 模式确认后继续执行)
serviceTier?: ServiceTier // 新增:服务等级参数
serviceTier?: ServiceTier // 新增:服务等级参数
): Promise<void> {
const historyManager = ChatHistoryManager.getInstance();
@ -137,10 +149,18 @@ async function handleUserMessageWithBackend(
const taskIdToUse = reuseTaskId || historyManager.getCurrentTaskId();
// 创建会话dialogManager 会自动处理旧会话的中止)
currentSession = dialogManager.createSession(extensionPath, taskIdToUse || undefined);
currentSession = dialogManager.createSession(
extensionPath,
taskIdToUse || undefined
);
// 保存 taskId 用于后续操作(如压缩)
lastTaskId = currentSession.getTaskId();
console.log("[MessageHandler] 创建会话: taskId=", lastTaskId, "来源=", taskIdToUse ? "historyManager" : "新生成");
console.log(
"[MessageHandler] 创建会话: taskId=",
lastTaskId,
"来源=",
taskIdToUse ? "historyManager" : "新生成"
);
// 显示状态栏
panel.webview.postMessage({
@ -200,6 +220,17 @@ async function handleUserMessageWithBackend(
// 最后一次发送完整的段落
console.log("[MessageHandler] 对话完成, 段落数:", segments.length);
// 对话完成后重新获取余额(因为已经消耗了 Credits
try {
console.log("[MessageHandler] 对话完成,重新获取余额...");
const newBalance = await fetchBalance();
if (newBalance !== null) {
console.log("[MessageHandler] 余额已更新:", newBalance);
}
} catch (error) {
console.error("[MessageHandler] 获取余额失败:", error);
}
const result = await panel.webview.postMessage({
command: "updateSegments",
segments: segments,
@ -286,7 +317,7 @@ async function handleUserMessageWithBackend(
},
},
mode,
serviceTier // 传递服务等级
serviceTier // 传递服务等级
);
});
}
@ -369,7 +400,14 @@ export async function handlePlanAction(
extensionPath: string,
serviceTier?: ServiceTier
): Promise<void> {
console.log("[handlePlanAction] action:", action, "planTitle:", planTitle, "serviceTier:", serviceTier);
console.log(
"[handlePlanAction] action:",
action,
"planTitle:",
planTitle,
"serviceTier:",
serviceTier
);
switch (action) {
case "confirm":

View File

@ -14,9 +14,7 @@ export function getContextButtonContent(): string {
<path d="M469.333333 469.333333V170.666667h85.333334v298.666666h298.666666v85.333334h-298.666666v298.666666h-85.333334v-298.666666H170.666667v-85.333334h298.666666z" fill="#8a8a8a" p-id="4995"></path>
</svg>
<span class="add-context-label">添加上下文</span>
<svg class="dropdown-arrow" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 714.666667L213.333333 416l42.666667-42.666667L512 629.333333l256-256 42.666667 42.666667z" fill="currentColor"/>
</svg>
</button>
<span class="tooltiptext">添加文件、文件夹、图片或文档作为上下文</span>
</div>

View File

@ -0,0 +1,216 @@
/**
* 获取展示区域的 HTML 内容
*/
export function getExampleShowcaseContent(): string {
return `
<div class="example-showcase" id="exampleShowcase">
<div class="showcase-title">展示</div>
<div class="example-cards">
<div class="example-card" onclick="fillExample(0)">
<div class="example-icon">📝</div>
<div class="example-content">
<div class="example-title">代码生成</div>
<div class="example-desc">生成一个 8 位全加器的 Verilog 代码</div>
</div>
</div>
<div class="example-card" onclick="fillExample(1)">
<div class="example-icon">🔍</div>
<div class="example-content">
<div class="example-title">代码分析</div>
<div class="example-desc">分析当前项目中的时序逻辑设计</div>
</div>
</div>
</div>
<div class="web-link">
<a href="https://iccoder.com" target="_blank" class="web-link-button">
<span class="link-icon">🌐</span>
<span>IC Coder Web端</span>
<span class="link-arrow">→</span>
</a>
</div>
</div>
`;
}
/**
* 获取展示区域的样式
*/
export function getExampleShowcaseStyles(): string {
return `
.example-showcase {
margin-top: 24px;
padding: 0;
opacity: 1;
transition: opacity 0.3s ease;
}
.example-showcase.hidden {
display: none;
}
.showcase-title {
font-size: 14px;
font-weight: 600;
color: var(--vscode-foreground);
margin-bottom: 12px;
text-align: left;
}
.example-cards {
display: flex;
flex-direction: row;
gap: 12px;
margin-bottom: 20px;
}
.example-card {
flex: 1;
min-width: 0;
background: var(--vscode-input-background);
border: 1px solid var(--vscode-input-border);
border-radius: 8px;
padding: 14px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
}
.example-card:hover {
border-color: var(--vscode-focusBorder);
background: var(--vscode-list-hoverBackground);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.example-icon {
font-size: 28px;
line-height: 1;
flex-shrink: 0;
}
.example-content {
display: flex;
flex-direction: column;
gap: 4px;
flex: 1;
min-width: 0;
}
.example-title {
font-size: 13px;
font-weight: 600;
color: var(--vscode-foreground);
}
.example-desc {
font-size: 11px;
color: var(--vscode-descriptionForeground);
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.web-link {
display: flex;
justify-content: center;
padding-top: 20px;
border-top: 1px solid var(--vscode-panel-border);
margin-top: 8px;
}
.web-link-button {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
background: transparent;
border: none;
text-decoration: none;
font-size: 14px;
font-weight: 600;
transition: all 0.2s ease;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 50%, #a855f7 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
outline: none;
}
.web-link-button:focus {
outline: none;
}
.web-link-button:hover {
transform: translateY(-1px);
opacity: 0.8;
}
.link-icon {
font-size: 16px;
}
.link-arrow {
font-size: 16px;
transition: transform 0.2s ease;
}
.web-link-button:hover .link-arrow {
transform: translateX(3px);
}
`;
}
/**
* 获取展示区域的脚本
*/
export function getExampleShowcaseScript(): string {
return `
// 示例文本数组
const exampleTexts = [
'生成一个 8 位全加器的 Verilog 代码',
'分析当前项目中的时序逻辑设计'
];
// 填充示例到输入框
function fillExample(index) {
const messageInput = document.getElementById('messageInput');
if (messageInput && exampleTexts[index]) {
messageInput.value = exampleTexts[index];
messageInput.focus();
// 触发自动调整高度
if (typeof autoResizeTextarea === 'function') {
autoResizeTextarea();
}
}
}
// 监听消息变化,自动隐藏/显示展示区域
function updateShowcaseVisibility() {
const showcase = document.getElementById('exampleShowcase');
if (showcase) {
if (hasMessages) {
showcase.classList.add('hidden');
} else {
showcase.classList.remove('hidden');
}
}
}
// 扩展原有的布局更新函数
const originalUpdateInputAreaLayout = updateInputAreaLayout;
updateInputAreaLayout = function() {
if (originalUpdateInputAreaLayout) {
originalUpdateInputAreaLayout();
}
updateShowcaseVisibility();
};
`;
}

View File

@ -29,16 +29,21 @@ import {
getOptimizeButtonStyles,
getOptimizeButtonScript,
} from "./optimizeButton";
import {
getExampleShowcaseContent,
getExampleShowcaseStyles,
getExampleShowcaseScript,
} from "./exampleShowcase";
import { sendIconSvg, stopIconSvg } from "../constants/toolIcons";
/**
* 获取输入区域的 HTML 内容
*/
export function getInputAreaContent(
autoIcon: string = '',
liteIcon: string = '',
syIcon: string = '',
maxIcon: string = ''
autoIcon: string = "",
liteIcon: string = "",
syIcon: string = "",
maxIcon: string = ""
): string {
return `
<div class="input-area centered" id="inputArea">
@ -71,6 +76,8 @@ export function getInputAreaContent(
</div>
</div>
</div>
<!-- 展示区域:案例和 Web 端链接 -->
${getExampleShowcaseContent()}
</div>
`;
}
@ -86,6 +93,7 @@ export function getInputAreaStyles(): string {
${getContextDisplayStyles()}
${getContextCompressStyles()}
${getOptimizeButtonStyles()}
${getExampleShowcaseStyles()}
.input-area {
border-top: 1px solid var(--vscode-panel-border);
padding-top: 15px;
@ -95,7 +103,7 @@ export function getInputAreaStyles(): string {
/* 居中模式:未发起对话时 */
.input-area.centered {
position: absolute;
top: 50%;
top: 55%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% - 40px);
@ -292,6 +300,7 @@ export function getInputAreaScript(): string {
${getContextDisplayScript()}
${getContextCompressScript()}
${getOptimizeButtonScript()}
${getExampleShowcaseScript()}
// 对话状态管理
let isConversationActive = false;

View File

@ -24,6 +24,7 @@ import {
knowledgeLoadIconSvg,
stateTransitionIconSvg,
userQuestionIconSvg,
updateStageIconSvg,
} from "../constants/toolIcons";
import {
getWaveformPreviewContent,
@ -670,6 +671,7 @@ export function getMessageAreaScript(): string {
const knowledgeLoadIconSvg = \`${knowledgeLoadIconSvg}\`;
const stateTransitionIconSvg = \`${stateTransitionIconSvg}\`;
const userQuestionIconSvg = \`${userQuestionIconSvg}\`;
const updateStageIconSvg = \`${updateStageIconSvg}\`;
${getAgentCardScript()}
@ -724,6 +726,7 @@ export function getMessageAreaScript(): string {
'updateNode': fileWriteIconSvg,
'addStateTransition': stateTransitionIconSvg,
'askUser': userQuestionIconSvg,
'updatePhase': updateStageIconSvg,
};
return iconMap[toolName] || '';
}
@ -756,6 +759,8 @@ export function getMessageAreaScript(): string {
'spawnExplorer': '代码探索',
'spawnDebugger': '波形调试',
'askUser': '用户提问',
'updatePhase': '已更新阶段',
'iverilog': '已完成编译',
};
return toolNameMap[toolName] || toolName;
}

View File

@ -62,9 +62,9 @@ export function getPlanCardStyles(): string {
.plan-summary p { margin: 8px 0; }
.plan-summary ul, .plan-summary ol {
margin: 8px 0;
padding-left: 24px;
padding-left: 0;
}
.plan-summary li { margin: 4px 0; }
.plan-summary li { margin: 4px 0 4px 27px; }
.plan-summary code {
background: var(--vscode-textCodeBlock-background);
padding: 2px 6px;
@ -403,6 +403,12 @@ export function getPlanCardScript(): string {
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
// 标题(必须在转义之后、其他处理之前)
html = html.replace(/^#### (.+)$/gm, '<h4>$1</h4>');
html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
// 代码块 (\`\`\`code\`\`\`)
html = html.replace(/\\x60\\x60\\x60([\\s\\S]*?)\\x60\\x60\\x60/g, '<pre><code>$1</code></pre>');
@ -428,12 +434,6 @@ export function getPlanCardScript(): string {
return table;
});
// 标题
html = html.replace(/^#### (.+)$/gm, '<h4>$1</h4>');
html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
// 粗体和斜体
html = html.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
html = html.replace(/\\*(.+?)\\*/g, '<em>$1</em>');

View File

@ -250,14 +250,27 @@ export function getUserInfoComponentScript(): string {
// 更新剩余 Credits
const creditsDetail = document.getElementById('creditsDetail');
console.log('[UserInfoComponent] 更新 Credits 显示');
console.log('[UserInfoComponent] currentUserInfo.credits:', currentUserInfo.credits);
console.log('[UserInfoComponent] creditsDetail 元素:', creditsDetail);
if (creditsDetail) {
creditsDetail.textContent = currentUserInfo.credits !== undefined ? currentUserInfo.credits.toString() : '-';
const creditsText = currentUserInfo.credits !== undefined ? currentUserInfo.credits.toString() : '-';
creditsDetail.textContent = creditsText;
console.log('[UserInfoComponent] Credits 已更新为:', creditsText);
} else {
console.warn('[UserInfoComponent] creditsDetail 元素未找到');
}
}
// 更新用户信息显示
function updateUserInfoDisplay(userInfo) {
currentUserInfo = userInfo;
console.log('[UserInfoComponent] 更新用户信息:', userInfo);
// 如果下拉面板已打开,立即更新显示
const dropdown = document.getElementById('userDetailDropdown');
if (dropdown && dropdown.classList.contains('active')) {
updateUserDetailModal();
}
}
// 绑定下拉面板事件

View File

@ -174,7 +174,7 @@ export function getWaveformPreviewScript(): string {
const content = document.createElement('div');
content.className = 'waveform-preview-content';
const miniViewerId = 'waveform-mini-' + Date.now();
const miniViewerId = 'waveform-mini-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
const miniViewer = document.createElement('div');
miniViewer.id = miniViewerId;
miniViewer.className = 'waveform-mini-viewer';

View File

@ -588,20 +588,25 @@ export function getWebviewContent(
case 'updateUserInfo':
// 更新用户信息
console.log('[WebView] 收到用户信息:', message.userInfo);
console.log('[WebView] Credits 字段值:', message.userInfo?.credits);
if (message.userInfo) {
const userInfoData = {
nickname: message.userInfo.nickname || message.userInfo.username || '用户',
userId: message.userInfo.userId || message.userInfo.id,
tierName: message.userInfo.tierName,
tierIconUrl: message.tierIconUrl,
registerTime: message.userInfo.registerTime || message.userInfo.createdAt
registerTime: message.userInfo.registerTime || message.userInfo.createdAt,
credits: message.userInfo.credits
};
console.log('[WebView] 显示用户信息:', userInfoData);
console.log('[WebView] userInfoData.credits:', userInfoData.credits);
// 调用更新用户头像图标按钮的函数
if (typeof updateUserAvatarIconButton === 'function') {
updateUserAvatarIconButton(userInfoData);
} else {
console.warn('[WebView] updateUserAvatarIconButton 函数不存在');
}
}
break;