diff --git a/src/extension.ts b/src/extension.ts index ba00e75..50b32d2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -310,6 +310,8 @@ export async function activate(context: vscode.ExtensionContext) { logoutCommand, changeInvitationCodeCommand, testNotificationCommand, + testTrialUserCommand, + testExpiredUserCommand, // TODO: 等待重新实现这些命令 // viewHistoryCommand, // newSessionCommand, diff --git a/src/panels/ExpiredPanel.ts b/src/panels/ExpiredPanel.ts new file mode 100644 index 0000000..f0f7361 --- /dev/null +++ b/src/panels/ExpiredPanel.ts @@ -0,0 +1,78 @@ +/** + * 试用期到期提醒面板 + * 功能:试用期到期时显示续费提示 + * 依赖:vscode + * 使用场景:试用用户到期时显示 + */ + +import * as vscode from 'vscode'; + +export class ExpiredPanel { + public static render() { + const panel = vscode.window.createWebviewPanel( + 'icCoderExpired', + '试用期已到期', + vscode.ViewColumn.One, + { enableScripts: true } + ); + + panel.webview.html = this.getHtmlContent(); + } + + private static getHtmlContent(): string { + return ` + + + + + + + +

⏰ 您的试用期已到期

+

感谢您使用 IC Coder!您的 15 天试用期已结束。

+

如需继续使用,请联系我们获取正式版本。

+ + + + + + + `; + } +} diff --git a/src/panels/ICHelperPanel.ts b/src/panels/ICHelperPanel.ts index 5d23714..9148914 100644 --- a/src/panels/ICHelperPanel.ts +++ b/src/panels/ICHelperPanel.ts @@ -426,12 +426,55 @@ export async function showICHelperPanel( case "checkInvitationCode": // 检查邀请码验证状态 { - const { InvitationService } = require("../services/invitationService"); - const isVerified = await InvitationService.isVerified(context); - panel.webview.postMessage({ - command: "invitationCodeStatus", - verified: isVerified - }); + // 先检查是否是试用用户 + const { getCachedUserInfo } = require("../services/userService"); + const userInfo = getCachedUserInfo(); + + if (userInfo?.isPluginTrial === true) { + // 试用用户,跳过邀请码验证,直接返回已验证 + console.log('[ICHelperPanel] 试用用户,跳过邀请码验证'); + panel.webview.postMessage({ + command: "invitationCodeStatus", + verified: true + }); + } else { + // 正式用户,检查邀请码 + const { InvitationService } = require("../services/invitationService"); + const isVerified = await InvitationService.isVerified(context); + panel.webview.postMessage({ + command: "invitationCodeStatus", + verified: isVerified + }); + } + } + break; + case "checkWelcomeModal": + // 检查是否需要显示欢迎弹窗 + { + console.log('[ICHelperPanel] 收到 checkWelcomeModal 消息'); + const showWelcome = context.globalState.get('showWelcomeModal'); + console.log('[ICHelperPanel] showWelcomeModal 标记值:', showWelcome); + + if (showWelcome) { + // 清除标记并显示欢迎弹窗 + await context.globalState.update('showWelcomeModal', undefined); + console.log('[ICHelperPanel] ✅ 发送 showWelcomeModal 命令到前端'); + panel.webview.postMessage({ + command: "showWelcomeModal" + }); + } else { + console.log('[ICHelperPanel] showWelcomeModal 标记为 false,不显示弹窗'); + } + } + break; + case "checkTrialExpiration": + // 检查试用期是否过期 + { + console.log('[ICHelperPanel] 收到 checkTrialExpiration 消息'); + const { TrialExpirationService } = require("../services/trialExpirationService"); + const trialService = new TrialExpirationService(context, panel); + const isExpired = await trialService.checkExpiration(); + console.log('[ICHelperPanel] 试用期过期状态:', isExpired); } break; case "verifyInvitationCode": diff --git a/src/panels/WelcomePanel.ts b/src/panels/WelcomePanel.ts new file mode 100644 index 0000000..3f60842 --- /dev/null +++ b/src/panels/WelcomePanel.ts @@ -0,0 +1,153 @@ +/** + * 欢迎引导面板 + * 功能:插件试用用户首次登录显示使用教程 + * 依赖:vscode + * 使用场景:试用用户首次登录时显示 + */ + +import * as vscode from 'vscode'; + +export class WelcomePanel { + public static currentPanel: WelcomePanel | undefined; + private readonly _panel: vscode.WebviewPanel; + private _disposables: vscode.Disposable[] = []; + + private constructor(panel: vscode.WebviewPanel) { + this._panel = panel; + this._panel.webview.html = this.getHtmlContent(); + + // 监听来自 webview 的消息 + this._panel.webview.onDidReceiveMessage( + (message) => { + if (message.command === 'close') { + this._panel.dispose(); + } + }, + null, + this._disposables + ); + + // 监听关闭事件 + this._panel.onDidDispose(() => this.dispose(), null, this._disposables); + } + + public static render(context: vscode.ExtensionContext) { + // 避免重复显示 + if (WelcomePanel.currentPanel) { + WelcomePanel.currentPanel._panel.reveal(vscode.ViewColumn.One); + return; + } + + const panel = vscode.window.createWebviewPanel( + 'icCoderWelcome', + '欢迎使用 IC Coder', + vscode.ViewColumn.One, + { + enableScripts: true, + retainContextWhenHidden: true + } + ); + + WelcomePanel.currentPanel = new WelcomePanel(panel); + } + + private getHtmlContent(): string { + return ` + + + + + + 欢迎使用 IC Coder + + + +

🎉 欢迎使用 IC Coder!

+

+ 您已成功激活 15 天试用期,让我们开始探索 IC Coder 的强大功能吧! +

+ +
+

📝 步骤 1:打开聊天面板

+

点击侧边栏的 IC Coder 图标,或使用命令面板搜索 "IC Coder: Open Chat"

+
+ +
+

💬 步骤 2:输入您的需求

+

描述您想要生成的 Verilog 代码或需要帮助的问题,AI 将为您提供专业的解决方案

+
+ +
+

🔬 步骤 3:运行仿真

+

使用 "生成 VCD" 命令运行 iverilog 仿真,并通过波形查看器查看仿真结果

+
+ + + + + + + `; + } + + public dispose() { + WelcomePanel.currentPanel = undefined; + this._panel.dispose(); + while (this._disposables.length) { + const disposable = this._disposables.pop(); + if (disposable) { + disposable.dispose(); + } + } + } +} diff --git a/src/services/trialExpirationService.ts b/src/services/trialExpirationService.ts new file mode 100644 index 0000000..eab2219 --- /dev/null +++ b/src/services/trialExpirationService.ts @@ -0,0 +1,62 @@ +/** + * 试用期过期检测服务 + * 功能:检查插件试用用户是否过期 + * 依赖:vscode, userService + * 使用场景:用户使用功能前检查是否过期 + */ + +import * as vscode from 'vscode'; +import { getCachedUserInfo } from './userService'; + +export class TrialExpirationService { + private context: vscode.ExtensionContext; + private panel?: vscode.WebviewPanel; + + constructor(context: vscode.ExtensionContext, panel?: vscode.WebviewPanel) { + this.context = context; + this.panel = panel; + } + + /** + * 检查是否过期 + * @returns true=已过期,false=未过期 + */ + public async checkExpiration(): Promise { + const userInfo = getCachedUserInfo(); + + // 不是插件试用用户,不需要检查 + if (!userInfo?.isPluginTrial) { + return false; + } + + // 没有过期时间,不检查 + if (!userInfo.pluginTrialExpiresAt) { + return false; + } + + // 检查是否过期 + const now = Date.now(); + if (now >= userInfo.pluginTrialExpiresAt) { + // 已过期 + await this.handleExpired(); + return true; + } + + return false; + } + + /** + * 处理过期逻辑 + */ + private async handleExpired(): Promise { + // 通知前端显示过期弹窗 + if (this.panel) { + this.panel.webview.postMessage({ + command: 'showExpiredModal' + }); + console.log('[TrialExpirationService] 已通知前端显示过期弹窗'); + } else { + console.warn('[TrialExpirationService] panel 未提供,无法显示过期弹窗'); + } + } +} diff --git a/src/services/userService.ts b/src/services/userService.ts index eb33028..7b37292 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -9,6 +9,8 @@ import * as vscode from 'vscode'; import { getStrangeLoopApiUrl, getConfig } from '../config/settings'; import type { UserInfoResponse, MembershipResponse, MultiMembershipVO, MembershipItemVO } from '../types/api'; import { fetchBalanceWithToken, getCachedBalance } from './creditsService'; +import { getIsPluginTrialFromToken } from '../utils/jwtUtils'; +// 移除 WelcomePanel 导入,改用消息通知方式 /** * HTTP 请求选项 @@ -117,6 +119,10 @@ export interface UserInfo { }; // Credits 余额 credits?: number; + // 插件试用用户标识(从 JWT token 中提取) + isPluginTrial?: boolean; + // 试用到期时间(毫秒时间戳) + pluginTrialExpiresAt?: number; } /** @@ -226,6 +232,10 @@ export async function onTokenReceived(token: string): Promise { try { console.log('[UserService] Token 已获取,正在获取用户信息、会员信息和余额...'); + // 从 token 中提取 ispluginTrial 标识 + const isPluginTrial = getIsPluginTrialFromToken(token); + console.log('[UserService] 从 token 中提取 ispluginTrial:', isPluginTrial); + // 并行获取用户信息、会员信息和余额 const [userInfo, membershipInfo, credits] = await Promise.all([ getUserInfo(token), @@ -238,6 +248,12 @@ export async function onTokenReceived(token: string): Promise { return null; } + // 将 token 中的 ispluginTrial 标识添加到用户信息 + if (isPluginTrial !== null) { + userInfo.isPluginTrial = isPluginTrial; + console.log('[UserService] 已将 ispluginTrial 添加到用户信息:', isPluginTrial); + } + // 添加 Credits 余额到用户信息 console.log('[UserService] 获取到的 Credits 余额:', credits); if (credits !== null) { @@ -313,6 +329,34 @@ export async function onTokenReceived(token: string): Promise { // 保存到持久化存储 await saveUserInfo(userInfo); + // 判断是否是插件试用用户 + console.log('[UserService] 检查用户类型,isPluginTrial:', userInfo.isPluginTrial); + console.log('[UserService] extensionContext 是否存在:', !!extensionContext); + + if (userInfo.isPluginTrial === true) { + // 插件试用用户:标记需要显示欢迎弹窗 + const hasWelcomed = extensionContext?.globalState.get('pluginTrialWelcomed'); + console.log('[UserService] 是否已显示过欢迎弹窗:', hasWelcomed); + + if (!hasWelcomed && extensionContext) { + // 设置标记,让聊天面板显示欢迎弹窗 + await extensionContext.globalState.update('showWelcomeModal', true); + await extensionContext.globalState.update('pluginTrialWelcomed', true); + console.log('[UserService] ✅ 已设置欢迎弹窗标记 showWelcomeModal=true'); + + // 验证标记是否设置成功 + const checkMark = extensionContext.globalState.get('showWelcomeModal'); + console.log('[UserService] 验证标记:', checkMark); + } else if (!extensionContext) { + console.error('[UserService] ❌ extensionContext 为 null,无法设置标记'); + } else { + console.log('[UserService] 已经显示过欢迎弹窗,跳过'); + } + } else { + // 正式用户:显示邀请码弹窗(现有逻辑) + console.log('[UserService] 正式用户登录,将在面板中检查邀请码'); + } + return userInfo; } catch (error) { console.error('[UserService] 获取用户信息失败:', error); diff --git a/src/utils/jwtUtils.ts b/src/utils/jwtUtils.ts index f3eb7b7..7858276 100644 --- a/src/utils/jwtUtils.ts +++ b/src/utils/jwtUtils.ts @@ -11,6 +11,7 @@ export interface JwtPayload { user_id?: number; // 用户ID (下划线命名) exp?: number; // 过期时间 iat?: number; // 签发时间 + ispluginTrial?: boolean; // 是否是插件试用用户 [key: string]: unknown; } @@ -102,3 +103,24 @@ export function isTokenExpired( return isExpired; } + +/** + * 从 JWT token 中获取 ispluginTrial 标识 + * @param token JWT token + * @returns true=插件试用用户,false=正式用户,null=无法判断 + */ +export function getIsPluginTrialFromToken(token: string): boolean | null { + const payload = parseJwtPayload(token); + if (!payload) { + return null; + } + + // 检查 ispluginTrial 字段 + if (payload.ispluginTrial !== undefined) { + console.log("[JWT] 从 token 中获取到 ispluginTrial:", payload.ispluginTrial); + return payload.ispluginTrial === true; + } + + console.log("[JWT] token 中没有 ispluginTrial 字段,判定为正式用户"); + return false; +} diff --git a/src/utils/messageHandler.ts b/src/utils/messageHandler.ts index f7647f1..46dd6bf 100644 --- a/src/utils/messageHandler.ts +++ b/src/utils/messageHandler.ts @@ -25,6 +25,7 @@ import { } from "../services/creditsService"; import { optimizePrompt } from "../services/promptOptimizeService"; import { NotificationService } from "../services/notificationService"; +import { TrialExpirationService } from "../services/trialExpirationService"; import type { RunMode, ServiceTier } from "../types/api"; @@ -124,6 +125,21 @@ export async function handleUserMessage( }); return; } + + // 检查试用期是否过期 + const trialService = new TrialExpirationService(context, panel); + const isExpired = await trialService.checkExpiration(); + if (isExpired) { + console.warn("[MessageHandler] 试用期已过期,阻止发送"); + + // 恢复输入状态 + panel.webview.postMessage({ + command: "updateSegments", + segments: [], + isComplete: true, + }); + return; + } } // 记录用户消息到历史(允许失败,不阻塞主流程) diff --git a/src/views/expiredModal.ts b/src/views/expiredModal.ts new file mode 100644 index 0000000..4cfdd44 --- /dev/null +++ b/src/views/expiredModal.ts @@ -0,0 +1,218 @@ +/** + * 试用期过期弹窗 + * 功能:在聊天面板内显示过期提醒模态窗口 + * 依赖:无 + * 使用场景:试用用户过期时在聊天面板内显示 + */ + +/** + * 获取过期弹窗的 HTML 内容 + */ +export function getExpiredModalContent(logoUri?: string): string { + return ` + + + `; +} + +/** + * 获取过期弹窗的 CSS 样式 + */ +export function getExpiredModalStyles(): string { + return ` + /* 过期弹窗样式 */ + .expired-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + font-family: var(--vscode-font-family, "Segoe UI", Tahoma, Geneva, Verdana, sans-serif); + } + + .expired-modal-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(5px); + animation: fadeIn 0.3s ease-out; + } + + .expired-modal-content { + position: relative; + background: var(--vscode-editor-background); + border: 1px solid var(--vscode-widget-border); + border-radius: 12px; + width: 100%; + max-width: 450px; + box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); + animation: modalSlideIn 0.3s cubic-bezier(0.2, 0.8, 0.2, 1); + overflow: hidden; + } + + .expired-logo-corner { + position: absolute; + top: 16px; + left: 24px; + height: 40px; + width: auto; + opacity: 0.9; + z-index: 10; + } + + .expired-modal-header { + padding: 60px 32px 20px; + text-align: center; + } + + .expired-icon { + font-size: 48px; + margin-bottom: 16px; + } + + .expired-modal-header h2 { + margin: 0 0 12px; + font-size: 24px; + font-weight: 600; + color: var(--vscode-errorForeground); + } + + .expired-modal-subtitle { + margin: 0; + font-size: 14px; + color: var(--vscode-descriptionForeground); + line-height: 1.5; + } + + .expired-modal-body { + padding: 0 32px 32px; + text-align: center; + } + + .expired-message { + font-size: 14px; + color: var(--vscode-descriptionForeground); + margin: 20px 0; + line-height: 1.6; + } + + .expired-btn { + width: 100%; + padding: 12px 16px; + font-size: 14px; + font-weight: 600; + border: none; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + background: var(--vscode-button-background); + color: var(--vscode-button-foreground); + transition: all 0.2s; + margin-top: 24px; + } + + .expired-btn:hover { + background: var(--vscode-button-hoverBackground); + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(0,0,0,0.2); + } + + .expired-btn:active { + transform: translateY(0); + } + `; +} + +/** + * 获取过期弹窗的 JavaScript 逻辑 + */ +export function getExpiredModalScript(): string { + return ` + // 过期弹窗逻辑 + (function() { + const modal = document.getElementById('expiredModal'); + const contactBtn = document.getElementById('expiredContactBtn'); + const overlay = modal?.querySelector('.expired-modal-overlay'); + + // 显示过期弹窗 + window.showExpiredModal = function() { + if (modal) { + modal.style.display = 'flex'; + } + }; + + // 隐藏过期弹窗 + window.hideExpiredModal = function() { + if (modal) { + modal.style.display = 'none'; + } + }; + + // 点击"联系我们"按钮 + if (contactBtn) { + contactBtn.addEventListener('click', function() { + // 可以打开联系页面 + // window.open('https://iccoder.com/contact', '_blank'); + hideExpiredModal(); + }); + } + + // 点击遮罩层关闭弹窗 + if (overlay) { + overlay.addEventListener('click', function() { + hideExpiredModal(); + }); + } + + // 阻止点击弹窗内容时关闭 + const content = modal?.querySelector('.expired-modal-content'); + if (content) { + content.addEventListener('click', function(e) { + e.stopPropagation(); + }); + } + + // 监听来自后端的消息 + window.addEventListener('message', function(event) { + const message = event.data; + if (message.command === 'showExpiredModal') { + showExpiredModal(); + } + }); + })(); + `; +} + diff --git a/src/views/inputArea.ts b/src/views/inputArea.ts index 0d01767..7ce0dfe 100644 --- a/src/views/inputArea.ts +++ b/src/views/inputArea.ts @@ -339,12 +339,14 @@ export function getInputAreaScript(): string { if (messageInput) { messageInput.addEventListener('input', autoResizeTextarea); - // 监听点击事件,检测工作区状态和邀请码验证状态 + // 监听点击事件,检测工作区状态、试用期过期和邀请码验证状态 messageInput.addEventListener('focus', () => { if (!hasCheckedWorkspace) { hasCheckedWorkspace = true; vscode.postMessage({ command: 'checkWorkspace' }); } + // 检查试用期是否过期 + vscode.postMessage({ command: 'checkTrialExpiration' }); // 检查邀请码验证状态 vscode.postMessage({ command: 'checkInvitationCode' }); }); diff --git a/src/views/webviewContent.ts b/src/views/webviewContent.ts index a328076..5bb4900 100644 --- a/src/views/webviewContent.ts +++ b/src/views/webviewContent.ts @@ -30,6 +30,16 @@ import { getInvitationModalStyles, getInvitationModalScript, } from "./invitationModal"; +import { + getWelcomeModalContent, + getWelcomeModalStyles, + getWelcomeModalScript, +} from "./welcomeModal"; +import { + getExpiredModalContent, + getExpiredModalStyles, + getExpiredModalScript, +} from "./expiredModal"; /** * 获取 WebView 面板的 HTML 内容 */ @@ -100,6 +110,8 @@ export function getWebviewContent( ${getProgressBarStyles()} ${getInputAreaStyles()} ${getInvitationModalStyles()} + ${getWelcomeModalStyles()} + ${getExpiredModalStyles()} .file-editor-section { margin-bottom: 15px; @@ -466,6 +478,8 @@ export function getWebviewContent( ${getConversationHistoryBarContent()} ${getProgressBarContent()} ${getInvitationModalContent(qrCodeUri, logoUri)} + ${getWelcomeModalContent(logoUri)} + ${getExpiredModalContent(logoUri)}
IC Coder @@ -873,6 +887,8 @@ export function getWebviewContent( ${getProgressBarScript()} ${getInputAreaScript()} ${getInvitationModalScript()} + ${getWelcomeModalScript()} + ${getExpiredModalScript()} `; } diff --git a/src/views/welcomeModal.ts b/src/views/welcomeModal.ts new file mode 100644 index 0000000..a16d64b --- /dev/null +++ b/src/views/welcomeModal.ts @@ -0,0 +1,261 @@ +/** + * 欢迎弹窗(试用用户) + * 功能:在聊天面板内显示欢迎模态窗口 + * 依赖:无 + * 使用场景:试用用户首次登录时在聊天面板内显示 + */ + +/** + * 获取欢迎弹窗的 HTML 内容 + */ +export function getWelcomeModalContent(logoUri?: string): string { + return ` + + + `; +} + +/** + * 获取欢迎弹窗的 CSS 样式 + */ +export function getWelcomeModalStyles(): string { + return ` + /* 欢迎弹窗样式 */ + .welcome-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + font-family: var(--vscode-font-family, "Segoe UI", Tahoma, Geneva, Verdana, sans-serif); + } + + .welcome-modal-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(5px); + animation: fadeIn 0.3s ease-out; + } + + .welcome-modal-content { + position: relative; + background: var(--vscode-editor-background); + border: 1px solid var(--vscode-widget-border); + border-radius: 12px; + width: 100%; + max-width: 500px; + box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); + animation: modalSlideIn 0.3s cubic-bezier(0.2, 0.8, 0.2, 1); + overflow: hidden; + } + + .welcome-logo-corner { + position: absolute; + top: 16px; + left: 24px; + height: 40px; + width: auto; + opacity: 0.9; + z-index: 10; + } + + .welcome-modal-header { + padding: 60px 32px 20px; + text-align: center; + } + + .welcome-icon { + font-size: 48px; + margin-bottom: 16px; + } + + .welcome-modal-header h2 { + margin: 0 0 12px; + font-size: 24px; + font-weight: 600; + color: var(--vscode-foreground); + } + + .welcome-modal-subtitle { + margin: 0; + font-size: 14px; + color: var(--vscode-descriptionForeground); + line-height: 1.5; + } + + .welcome-modal-body { + padding: 0 32px 32px; + } + + .welcome-step { + display: flex; + gap: 16px; + margin: 20px 0; + padding: 16px; + background: var(--vscode-editor-inactiveSelectionBackground); + border-radius: 8px; + border-left: 4px solid var(--vscode-textLink-foreground); + } + + .welcome-step-icon { + font-size: 24px; + flex-shrink: 0; + } + + .welcome-step-content h3 { + margin: 0 0 8px; + font-size: 15px; + font-weight: 600; + color: var(--vscode-textLink-foreground); + } + + .welcome-step-content p { + margin: 0; + font-size: 13px; + color: var(--vscode-descriptionForeground); + line-height: 1.5; + } + + .welcome-btn { + width: 100%; + padding: 12px 16px; + font-size: 14px; + font-weight: 600; + border: none; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + background: var(--vscode-button-background); + color: var(--vscode-button-foreground); + transition: all 0.2s; + margin-top: 24px; + } + + .welcome-btn:hover { + background: var(--vscode-button-hoverBackground); + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(0,0,0,0.2); + } + + .welcome-btn:active { + transform: translateY(0); + } + `; +} + +/** + * 获取欢迎弹窗的 JavaScript 逻辑 + */ +export function getWelcomeModalScript(): string { + return ` + // 欢迎弹窗逻辑 + (function() { + const modal = document.getElementById('welcomeModal'); + const startBtn = document.getElementById('welcomeStartBtn'); + const overlay = modal?.querySelector('.welcome-modal-overlay'); + + // 显示欢迎弹窗 + window.showWelcomeModal = function() { + if (modal) { + modal.style.display = 'flex'; + } + }; + + // 隐藏欢迎弹窗 + window.hideWelcomeModal = function() { + if (modal) { + modal.style.display = 'none'; + } + }; + + // 点击"开始使用"按钮 + if (startBtn) { + startBtn.addEventListener('click', function() { + hideWelcomeModal(); + }); + } + + // 点击遮罩层关闭弹窗 + if (overlay) { + overlay.addEventListener('click', function() { + hideWelcomeModal(); + }); + } + + // 阻止点击弹窗内容时关闭 + const content = modal?.querySelector('.welcome-modal-content'); + if (content) { + content.addEventListener('click', function(e) { + e.stopPropagation(); + }); + } + + // 监听来自后端的消息 + window.addEventListener('message', function(event) { + const message = event.data; + if (message.command === 'showWelcomeModal') { + showWelcomeModal(); + } + }); + + // 页面加载时检查是否需要显示欢迎弹窗 + vscode.postMessage({ command: 'checkWelcomeModal' }); + })(); + `; +}