diff --git a/src/extension.ts b/src/extension.ts index e1c67b4..80f49c3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -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) => { diff --git a/src/panels/ICHelperPanel.ts b/src/panels/ICHelperPanel.ts index c8f2007..3a239d9 100644 --- a/src/panels/ICHelperPanel.ts +++ b/src/panels/ICHelperPanel.ts @@ -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", [], { diff --git a/src/services/creditsService.ts b/src/services/creditsService.ts index 09a3a9f..475d379 100644 --- a/src/services/creditsService.ts +++ b/src/services/creditsService.ts @@ -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('icCoderCreditsBalance'); + if (savedBalance !== undefined) { + cachedBalance = savedBalance; + lastUpdateTime = Date.now(); + console.log('[CreditsService] 从持久化存储加载余额:', savedBalance); + } +} + +/** + * 保存余额到持久化存储 + */ +async function saveBalance(balance: number): Promise { + 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 { cachedBalance = null; lastUpdateTime = 0; + if (extensionContext) { + await extensionContext.globalState.update('icCoderCreditsBalance', undefined); + } console.log('[CreditsService] 余额缓存已清除'); } diff --git a/src/services/userService.ts b/src/services/userService.ts index c02a2e6..e91d641 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -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 { 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 { 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 { } } + // 打印 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('icCoderUserInfo') || null; + const userInfo = extensionContext.globalState.get('icCoderUserInfo') || null; + + // 从 creditsService 加载余额并合并到用户信息中 + if (userInfo) { + const cachedCredits = getCachedBalance(); + if (cachedCredits !== null) { + userInfo.credits = cachedCredits; + console.log('[UserService] 从 creditsService 加载余额:', cachedCredits); + } + } + + return userInfo; } /** diff --git a/src/utils/messageHandler.ts b/src/utils/messageHandler.ts index b0ee6b1..6e73e34 100644 --- a/src/utils/messageHandler.ts +++ b/src/utils/messageHandler.ts @@ -18,7 +18,7 @@ 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"; @@ -200,6 +200,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, diff --git a/src/views/userInfoComponent.ts b/src/views/userInfoComponent.ts index 444ad59..95bb043 100644 --- a/src/views/userInfoComponent.ts +++ b/src/views/userInfoComponent.ts @@ -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(); + } } // 绑定下拉面板事件 diff --git a/src/views/webviewContent.ts b/src/views/webviewContent.ts index 9cd5e20..a4d03be 100644 --- a/src/views/webviewContent.ts +++ b/src/views/webviewContent.ts @@ -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;