import Awesome from '../background/awesome.js' import MSG_TYPE from '../static/js/common.js'; import Settings from './settings.js'; import Statistics from '../background/statistics.js'; import toolMap from '../background/tools.js'; // 工具分类定义 const TOOL_CATEGORIES = [ { key: 'dev', name: '开发工具类', tools: ['json-format', 'json-diff', 'code-beautify', 'code-compress', 'postman', 'websocket', 'regexp','page-timing'] }, { key: 'encode', name: '编解码转换类', tools: ['en-decode', 'trans-radix', 'timestamp', 'trans-color'] }, { key: 'image', name: '图像处理类', tools: ['qr-code', 'image-base64', 'svg-converter', 'chart-maker', 'poster-maker' ,'screenshot', 'color-picker'] }, { key: 'productivity', name: '效率工具类', tools: ['aiagent', 'sticky-notes', 'html2markdown', 'page-monkey'] }, { key: 'calculator', name: '计算工具类', tools: ['crontab', 'loan-rate', 'password'] }, { key: 'other', name: '其他工具', tools: [] } ]; // Vue实例 new Vue({ el: '#marketContainer', data: { manifest: { version: '0.0.0' }, searchKey: '', currentCategory: '', sortType: 'default', viewMode: 'list', // 默认网格视图 categories: TOOL_CATEGORIES, favorites: new Set(), recentUsed: [], loading: true, originalTools: {}, // 保存原始工具数据 currentView: 'all', // 当前视图类型(all/installed/favorites/recent) activeTools: {}, // 当前显示的工具列表 installedCount: 0, // 已安装工具数量 // 版本相关 latestVersion: '', // 最新版本号 needUpdate: false, // 是否需要更新 // 设置相关 showSettingsModal: false, defaultKey: 'Alt+Shift+J', // 默认快捷键 countDown: 0, // 夜间模式倒计时 selectedOpts: [], // 选中的选项 menuDownloadCrx: false, // 菜单-插件下载 menuFeHelperSeting: false, // 菜单-FeHelper设置 isFirefox: false, // 是否Firefox浏览器 // 打赏相关 showDonateModal: false, donate: { text: '感谢你对FeHelper的认可和支持!', image: './donate.jpeg' }, // 确认对话框 confirmDialog: { show: false, title: '操作确认', message: '', callback: null, data: null }, recentCount: 0, showDashboard: false, // 是否显示DashBoard dashboardData: null, // DashBoard数据 }, async created() { await this.initData(); this.recentCount = (await Statistics.getRecentUsedTools(10)).length; // 初始化后更新已安装工具数量 this.updateInstalledCount(); // 恢复用户的视图模式设置 this.loadViewMode(); // 加载设置项 this.loadSettings(); // 检查浏览器类型 this.checkBrowserType(); // 检查版本更新 this.checkVersionUpdate(); // 检查URL中是否有donate_from参数 this.checkDonateParam(); // 埋点:自动触发options chrome.runtime.sendMessage({ type: 'fh-dynamic-any-thing', thing: 'statistics-tool-usage', params: { tool_name: 'options' } }); }, computed: { filteredTools() { if (this.loading) { return []; } // 获取当前工具列表 let result = Object.values(this.activeTools).map(tool => ({ ...tool, favorite: this.favorites.has(tool.key) })); // 搜索过滤 if (this.searchKey) { const key = this.searchKey.toLowerCase(); result = result.filter(tool => tool.name.toLowerCase().includes(key) || tool.tips.toLowerCase().includes(key) ); } // 分类过滤,在所有视图下生效 if (this.currentCategory) { const category = TOOL_CATEGORIES.find(c => c.key === this.currentCategory); const categoryTools = category ? category.tools : []; result = result.filter(tool => categoryTools.includes(tool.key)); } // 排序 switch (this.sortType) { case 'newest': result.sort((a, b) => (b.updateTime || 0) - (a.updateTime || 0)); break; case 'hot': result.sort((a, b) => (b.updateTime || 0) - (a.updateTime || 0)); break; default: const allTools = TOOL_CATEGORIES.reduce((acc, category) => { acc.push(...category.tools); return acc; }, []); result.sort((a, b) => { const indexA = allTools.indexOf(a.key); const indexB = allTools.indexOf(b.key); // 如果工具不在任何类别中,放到最后 if (indexA === -1 && indexB === -1) { return a.key.localeCompare(b.key); // 字母顺序排序 } if (indexA === -1) return 1; if (indexB === -1) return -1; return indexA - indexB; }); } return result; } }, methods: { async initData() { try { this.loading = true; // 获取manifest信息 const manifest = await chrome.runtime.getManifest(); this.manifest = manifest; // 从 Awesome.getAllTools 获取工具列表 const tools = await Awesome.getAllTools(); // 获取收藏数据 const favorites = await this.getFavoritesData(); this.favorites = new Set(favorites); // 获取最近使用数据 const recentUsed = await this.getRecentUsedData(); this.recentUsed = recentUsed; this.recentCount = recentUsed.length; // 获取已安装工具列表 const installedTools = await Awesome.getInstalledTools(); // 处理工具数据 const processedTools = {}; Object.entries(tools).forEach(([key, tool]) => { // 检查工具是否已安装 const isInstalled = installedTools.hasOwnProperty(key); // 检查是否有右键菜单 const hasMenu = tool.menu || false; processedTools[key] = { ...tool, key, // 添加key到工具对象中 updateTime: Date.now() - Math.floor(Math.random() * 30) * 24 * 60 * 60 * 1000, installed: isInstalled, // 使用实时安装状态 inContextMenu: hasMenu, // 使用实时菜单状态 systemInstalled: tool.systemInstalled || false, // 是否系统预装 favorite: this.favorites.has(key) }; }); this.originalTools = processedTools; // 初始化activeTools为所有工具 this.activeTools = { ...processedTools }; // 更新"其他工具"类别 this.updateOtherCategory(Object.keys(processedTools)); // 默认选中"全部分类" this.currentCategory = ''; } catch (error) { console.error('初始化数据失败:', error); } finally { this.loading = false; } }, // 更新"其他工具"类别,将未分类的工具添加到此类别 updateOtherCategory(allToolKeys) { // 获取所有已分类的工具 const categorizedTools = new Set(); TOOL_CATEGORIES.forEach(category => { if (category.key !== 'other') { category.tools.forEach(tool => categorizedTools.add(tool)); } }); // 找出未分类的工具 const uncategorizedTools = allToolKeys.filter(key => !categorizedTools.has(key)); // 更新"其他工具"类别 const otherCategory = TOOL_CATEGORIES.find(category => category.key === 'other'); if (otherCategory) { otherCategory.tools = uncategorizedTools; } }, // 检查版本更新 async checkVersionUpdate() { try { // 获取已安装的版本号 const currentVersion = this.manifest.version; // 尝试从本地存储获取最新版本信息,避免频繁请求 const cachedData = await new Promise(resolve => { chrome.storage.local.get('fehelper_latest_version_data', data => { resolve(data.fehelper_latest_version_data || null); }); }); // 检查是否需要重新获取版本信息: // 1. 缓存不存在 // 2. 缓存已过期(超过24小时) // 3. 缓存的当前版本与实际版本不同(说明插件已更新) const now = Date.now(); const cacheExpired = !cachedData || !cachedData.timestamp || (now - cachedData.timestamp > 24 * 60 * 60 * 1000); const versionChanged = cachedData && cachedData.currentVersion !== currentVersion; if (cacheExpired || versionChanged) { try { console.log('开始获取最新版本信息...'); // 使用shields.io的JSON API获取最新版本号 const response = await fetch('https://img.shields.io/chrome-web-store/v/pkgccpejnmalmdinmhkkfafefagiiiad.json'); if (!response.ok) { throw new Error(`HTTP错误:${response.status}`); } const data = await response.json(); // 提取版本号 - shields.io返回的数据中包含版本信息 let latestVersion = ''; if (data && data.value) { // 去掉版本号前的'v'字符(如果有) latestVersion = data.value.replace(/^v/, ''); console.log('获取到最新版本号:', latestVersion); } // 比较版本号 const needUpdate = this.compareVersions(currentVersion, latestVersion) < 0; console.log('当前版本:', currentVersion, '最新版本:', latestVersion, '需要更新:', needUpdate); // 保存到本地存储中 await chrome.storage.local.set({ 'fehelper_latest_version_data': { timestamp: now, currentVersion, // 保存当前检查时的版本号 latestVersion, needUpdate } }); this.latestVersion = latestVersion; this.needUpdate = needUpdate; } catch (fetchError) { console.error('获取最新版本信息失败:', fetchError); // 获取失败时不显示更新按钮 this.needUpdate = false; // 如果是版本变更导致的重新检查,但获取失败,则使用缓存数据 if (versionChanged && cachedData) { this.latestVersion = cachedData.latestVersion || ''; // 比较新的currentVersion和缓存的latestVersion this.needUpdate = this.compareVersions(currentVersion, cachedData.latestVersion) < 0; } } } else { // 使用缓存数据 console.log('使用缓存的版本信息'); this.latestVersion = cachedData.latestVersion || ''; this.needUpdate = cachedData.needUpdate || false; } } catch (error) { console.error('检查版本更新失败:', error); this.needUpdate = false; // 出错时不显示更新提示 } }, // 比较版本号:如果v1 < v2返回-1,v1 = v2返回0,v1 > v2返回1 compareVersions(v1, v2) { // 将版本号拆分为数字数组 const v1Parts = v1.split('.').map(Number); const v2Parts = v2.split('.').map(Number); // 计算两个版本号中较长的长度 const maxLength = Math.max(v1Parts.length, v2Parts.length); // 比较每一部分 for (let i = 0; i < maxLength; i++) { // 获取当前部分,如果不存在则视为0 const part1 = v1Parts[i] || 0; const part2 = v2Parts[i] || 0; // 比较当前部分 if (part1 < part2) return -1; if (part1 > part2) return 1; } // 所有部分都相等 return 0; }, // 打开Chrome商店页面 openStorePage() { try { console.log('开始请求检查更新...'); // 使用Chrome Extension API请求检查更新 // Manifest V3中requestUpdateCheck返回Promise,结果是一个对象而不是数组 chrome.runtime.requestUpdateCheck().then(result => { // 正确获取status和details,它们是result对象的属性 console.log('更新检查结果:', result); const status = result.status; const details = result.details; console.log('更新检查状态:', status, '详情:', details); this.handleUpdateStatus(status, details); }).catch(error => { console.error('更新检查失败:', error); this.handleUpdateError(error); }); } catch (error) { console.error('请求更新出错:', error); this.handleUpdateError(error); } }, // 处理更新状态 handleUpdateStatus(status, details) { console.log(`处理更新状态: ${status}`, details); if (status === 'update_available') { console.log('发现更新:', details); // 显示更新通知 this.showNotification({ title: 'FeHelper 更新', message: '已发现新版本,正在更新...' }); // 重新加载扩展以应用更新 setTimeout(() => { console.log('重新加载扩展...'); chrome.runtime.reload(); }, 1000); } else if (status === 'no_update') { // 如果没有可用更新,但用户点击了更新按钮 this.showNotification({ title: 'FeHelper 更新', message: '您的FeHelper已经是最新版本。' }); } else { // 其他情况,如更新检查失败等 console.log('其他更新状态:', status); // 备选方案:跳转到官方网站 chrome.tabs.create({ url: 'https://baidufe.com/fehelper' }); this.showNotification({ title: 'FeHelper 更新', message: '自动更新失败,请访问FeHelper官网手动获取最新版本。' }); } }, // 处理更新错误 handleUpdateError(error) { console.error('更新过程中出错:', error); // 出错时跳转到官方网站 chrome.tabs.create({ url: 'https://baidufe.com/fehelper' }); this.showNotification({ title: 'FeHelper 更新错误', message: '更新过程中出现错误,请手动检查更新。' }); }, // 显示通知的统一方法 showNotification(options) { try { console.log('准备显示通知:', options); // 定义通知ID,方便后续关闭 const notificationId = 'fehelper-update-notification'; const simpleNotificationId = 'fehelper-simple-notification'; // 直接尝试创建通知,不检查权限 // Chrome扩展在manifest中已声明notifications权限,应该可以直接使用 const notificationOptions = { type: 'basic', iconUrl: chrome.runtime.getURL('static/img/fe-48.png'), title: options.title || 'FeHelper', message: options.message || '', priority: 2, requireInteraction: false, // 改为false,因为我们会手动关闭 silent: false // 播放音效 }; console.log('通知选项:', notificationOptions); // 首先尝试直接创建通知 chrome.notifications.create(notificationId, notificationOptions, (createdId) => { const error = chrome.runtime.lastError; if (error) { console.error('创建通知出错:', error); // 通知创建失败,尝试使用alert作为备选方案 alert(`${options.title}: ${options.message}`); // 再尝试使用不同的选项创建通知 const simpleOptions = { type: 'basic', iconUrl: chrome.runtime.getURL('static/img/fe-48.png'), title: options.title || 'FeHelper', message: options.message || '' }; // 使用简化选项再次尝试 chrome.notifications.create(simpleNotificationId, simpleOptions, (simpleId) => { if (chrome.runtime.lastError) { console.error('简化通知创建也失败:', chrome.runtime.lastError); } else { console.log('简化通知已创建,ID:', simpleId); // 3秒后自动关闭简化通知 setTimeout(() => { chrome.notifications.clear(simpleId, (wasCleared) => { console.log('简化通知已关闭:', wasCleared); }); }, 3000); } }); } else { console.log('通知已成功创建,ID:', createdId); // 3秒后自动关闭通知 setTimeout(() => { chrome.notifications.clear(createdId, (wasCleared) => { console.log('通知已关闭:', wasCleared); }); }, 3000); } }); // 同时使用内置UI显示消息 this.showInPageNotification(options); } catch (error) { console.error('显示通知时出错:', error); // 降级为alert alert(`${options.title}: ${options.message}`); } }, // 在页面内显示通知消息 showInPageNotification(options) { try { // 创建一个通知元素 const notificationEl = document.createElement('div'); notificationEl.className = 'in-page-notification'; notificationEl.innerHTML = `
${options.title || 'FeHelper'}
${options.message || ''}
`; // 添加样式 const style = document.createElement('style'); style.textContent = ` .in-page-notification { position: fixed; bottom: 20px; right: 20px; background-color: #4285f4; color: white; padding: 15px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); z-index: 9999; display: flex; align-items: center; justify-content: space-between; min-width: 300px; animation: slideIn 0.3s ease-out; } .notification-content { flex: 1; } .notification-title { font-weight: bold; margin-bottom: 5px; } .notification-message { font-size: 14px; } .notification-close { background: none; border: none; color: white; font-size: 20px; cursor: pointer; margin-left: 10px; padding: 0 5px; } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } } `; // 添加到页面 document.head.appendChild(style); document.body.appendChild(notificationEl); // 点击关闭按钮移除通知 const closeBtn = notificationEl.querySelector('.notification-close'); if (closeBtn) { closeBtn.addEventListener('click', () => { notificationEl.style.animation = 'slideOut 0.3s ease-out forwards'; notificationEl.addEventListener('animationend', () => { notificationEl.remove(); }); }); } // 3秒后自动移除(从5秒改为3秒) setTimeout(() => { notificationEl.style.animation = 'slideOut 0.3s ease-out forwards'; notificationEl.addEventListener('animationend', () => { notificationEl.remove(); }); }, 3000); console.log('页内通知已显示,将在3秒后自动关闭'); } catch (error) { console.error('创建页内通知出错:', error); } }, async getFavoritesData() { return new Promise((resolve) => { chrome.storage.local.get('favorites', (result) => { resolve(result.favorites || []); }); }); }, async getRecentUsedData() { // 直接从Statistics模块获取最近使用的工具 return await Statistics.getRecentUsedTools(10); }, async saveFavorites() { try { await chrome.storage.local.set({ favorites: Array.from(this.favorites) }); // 更新工具的收藏状态 Object.keys(this.originalTools).forEach(key => { this.originalTools[key].favorite = this.favorites.has(key); }); } catch (error) { console.error('保存收藏失败:', error); } }, handleSearch() { // 搜索时不重置视图类型,允许在已过滤的结果中搜索 }, handleCategoryChange(category) { // 切换到全部工具视图 if (this.currentView !== 'all') { this.currentView = 'all'; this.updateActiveTools('all'); } this.currentCategory = category; this.searchKey = ''; // 确保工具显示正确 this.activeTools = { ...this.originalTools }; this.showDashboard = false; }, handleSort() { // 排序逻辑已在computed中实现 }, getCategoryCount(categoryKey) { const category = TOOL_CATEGORIES.find(c => c.key === categoryKey); const categoryTools = category ? category.tools : []; return categoryTools.length; }, async getInstalledCount() { try { // 使用Awesome.getInstalledTools实时获取已安装工具数量 const installedTools = await Awesome.getInstalledTools(); return Object.keys(installedTools).length; } catch (error) { console.error('获取已安装工具数量失败:', error); // 回退到本地数据 return Object.values(this.originalTools).filter(tool => tool.installed || tool.systemInstalled || false ).length; } }, getFavoritesCount() { return this.favorites.size; }, getToolCategory(toolKey) { for (const category of TOOL_CATEGORIES) { if (category.tools.includes(toolKey)) { return category.key; } } return 'other'; }, async showMyInstalled() { this.currentView = 'installed'; this.currentCategory = ''; this.searchKey = ''; await this.updateActiveTools('installed'); // 更新已安装工具数量 await this.updateInstalledCount(); this.showDashboard = false; }, showMyFavorites() { this.currentView = 'favorites'; this.currentCategory = ''; this.searchKey = ''; this.updateActiveTools('favorites'); this.showDashboard = false; }, async showRecentUsed() { this.currentView = 'recent'; this.currentCategory = ''; this.searchKey = ''; // 拉取DashBoard数据并显示 this.dashboardData = await Statistics.getDashboardData(); this.showDashboard = true; // 不再更新工具列表 }, // 关闭DashBoard,恢复工具列表 closeDashboard() { this.showDashboard = false; this.currentView = 'all'; this.updateActiveTools('all'); }, // 重置工具列表到原始状态 resetTools() { this.currentView = 'all'; }, // 安装工具 async installTool(toolKey) { try { // 查找可能存在的按钮元素 const btnElement = document.querySelector(`button[data-tool="${toolKey}"]`); let elProgress = null; // 如果是通过按钮点击调用的,获取进度条元素 if (btnElement) { if (btnElement.getAttribute('data-undergoing') === '1') { return false; } btnElement.setAttribute('data-undergoing', '1'); elProgress = btnElement.querySelector('span.x-progress'); } // 显示安装进度 let pt = 1; await Awesome.install(toolKey); // 只有当进度条元素存在时才更新文本内容 if (elProgress) { elProgress.textContent = `(${pt}%)`; let ptInterval = setInterval(() => { elProgress.textContent = `(${pt}%)`; pt += Math.floor(Math.random() * 20); if(pt > 100) { clearInterval(ptInterval); elProgress.textContent = ``; // 在进度条完成后显示安装成功的通知 this.showInPageNotification({ message: `${this.originalTools[toolKey].name} 安装成功!`, type: 'success', duration: 3000 }); } }, 100); } else { // 如果没有进度条元素,直接显示通知 this.showInPageNotification({ message: `${this.originalTools[toolKey].name} 安装成功!`, type: 'success', duration: 3000 }); } // 更新原始数据和当前活动数据 this.originalTools[toolKey].installed = true; if (this.activeTools[toolKey]) { this.activeTools[toolKey].installed = true; } // 更新已安装工具数量 this.updateInstalledCount(); // 如果按钮存在,更新其状态 if (btnElement) { btnElement.setAttribute('data-undergoing', '0'); } // 发送消息通知后台更新 chrome.runtime.sendMessage({ type: MSG_TYPE.DYNAMIC_TOOL_INSTALL_OR_OFFLOAD, toolName: toolKey, action: 'install', showTips: true }); } catch (error) { console.error('安装工具失败:', error); // 显示安装失败的通知 this.showInPageNotification({ message: `安装失败:${error.message || '未知错误'}`, type: 'error', duration: 5000 }); } }, // 卸载工具 async uninstallTool(toolKey) { try { // 使用自定义确认对话框而非浏览器原生的confirm this.showConfirm({ title: '卸载确认', message: `确定要卸载"${this.originalTools[toolKey].name}"工具吗?`, callback: async (key) => { try { await chrome.runtime.sendMessage({ type: MSG_TYPE.DYNAMIC_TOOL_INSTALL_OR_OFFLOAD, toolName: key, action: 'offload', showTips: true }); // 调用Awesome.offLoad卸载工具 await Awesome.offLoad(key); // 更新原始数据和当前活动数据 this.originalTools[key].installed = false; this.originalTools[key].inContextMenu = false; if (this.activeTools[key]) { this.activeTools[key].installed = false; this.activeTools[key].inContextMenu = false; } // 更新已安装工具数量 this.updateInstalledCount(); // 显示卸载成功的通知 this.showInPageNotification({ message: `${this.originalTools[key].name} 已成功卸载!`, type: 'success', duration: 3000 }); } catch (error) { console.error('卸载工具失败:', error); // 显示卸载失败的通知 this.showInPageNotification({ message: `卸载失败:${error.message || '未知错误'}`, type: 'error', duration: 5000 }); } }, data: toolKey }); } catch (error) { console.error('准备卸载过程中出错:', error); } }, // 切换右键菜单 async toggleContextMenu(toolKey) { try { const tool = this.originalTools[toolKey]; const newState = !tool.inContextMenu; // 更新菜单状态 await Awesome.menuMgr(toolKey, newState ? 'install' : 'offload'); // 更新原始数据和当前活动数据 tool.inContextMenu = newState; if (this.activeTools[toolKey]) { this.activeTools[toolKey].inContextMenu = newState; } // 发送消息通知后台更新右键菜单 chrome.runtime.sendMessage({ type: MSG_TYPE.DYNAMIC_TOOL_INSTALL_OR_OFFLOAD, action: `menu-${newState ? 'install' : 'offload'}`, showTips: false, menuOnly: true }); } catch (error) { console.error('切换右键菜单失败:', error); } }, // 切换收藏状态 async toggleFavorite(toolKey) { try { if (this.favorites.has(toolKey)) { this.favorites.delete(toolKey); // 更新原始数据和当前活动数据 this.originalTools[toolKey].favorite = false; if (this.activeTools[toolKey]) { this.activeTools[toolKey].favorite = false; } } else { this.favorites.add(toolKey); // 更新原始数据和当前活动数据 this.originalTools[toolKey].favorite = true; if (this.activeTools[toolKey]) { this.activeTools[toolKey].favorite = true; } } await this.saveFavorites(); // 如果是在收藏视图,需要更新视图 if (this.currentView === 'favorites') { this.updateActiveTools('favorites'); } } catch (error) { console.error('切换收藏状态失败:', error); } }, async updateActiveTools(view) { if (this.loading || Object.keys(this.originalTools).length === 0) { return; } switch (view) { case 'installed': // 使用Awesome.getInstalledTools实时获取已安装工具 try { const installedTools = await Awesome.getInstalledTools(); // 合并installedTools与originalTools的数据 this.activeTools = Object.fromEntries( Object.entries(this.originalTools).filter(([key]) => installedTools.hasOwnProperty(key) ) ); } catch (error) { console.error('获取已安装工具失败:', error); // 回退到本地数据 this.activeTools = Object.fromEntries( Object.entries(this.originalTools).filter(([_, tool]) => tool.installed || tool.systemInstalled || false ) ); } break; case 'favorites': this.activeTools = Object.fromEntries( Object.entries(this.originalTools).filter(([key]) => this.favorites.has(key)) ); break; case 'recent': // 切换recent时,recentUsed已在showRecentUsed中实时拉取 this.activeTools = Object.fromEntries( Object.entries(this.originalTools).filter(([key]) => this.recentUsed.includes(key)) ); break; case 'all': default: this.activeTools = { ...this.originalTools }; // 分类过滤在computed属性中处理 break; } }, // 新增更新已安装工具数量的方法 async updateInstalledCount() { this.installedCount = await this.getInstalledCount(); }, // 加载用户保存的视图模式 async loadViewMode() { try { const result = await new Promise(resolve => { chrome.storage.local.get('fehelper_view_mode', result => { resolve(result.fehelper_view_mode); }); }); if (result) { this.viewMode = result; } } catch (error) { console.error('加载视图模式失败:', error); } }, // 保存用户的视图模式选择 async saveViewMode(mode) { try { this.viewMode = mode; await chrome.storage.local.set({ 'fehelper_view_mode': mode }); } catch (error) { console.error('保存视图模式失败:', error); } }, // 加载设置项 async loadSettings() { try { Settings.getOptions(async (opts) => { let selectedOpts = []; Object.keys(opts).forEach(key => { if(String(opts[key]) === 'true') { selectedOpts.push(key); } }); this.selectedOpts = selectedOpts; // 加载右键菜单设置 this.menuDownloadCrx = await Awesome.menuMgr('download-crx', 'get') === '1'; this.menuFeHelperSeting = await Awesome.menuMgr('fehelper-setting', 'get') !== '0'; // 获取快捷键 chrome.commands.getAll((commands) => { for (let command of commands) { if (command.name === '_execute_action') { this.defaultKey = command.shortcut || 'Alt+Shift+J'; break; } } }); }); } catch (error) { console.error('加载设置项失败:', error); } }, // 检查浏览器类型 checkBrowserType() { try { this.isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; } catch (error) { console.error('检查浏览器类型失败:', error); this.isFirefox = false; } }, // 显示设置模态框 showSettings() { this.showSettingsModal = true; }, // 关闭设置模态框 closeSettings() { this.showSettingsModal = false; }, // 显示打赏模态框 openDonateModal() { this.showDonateModal = true; }, // 关闭打赏模态框 closeDonateModal() { this.showDonateModal = false; }, // 显示确认对话框 showConfirm(options) { this.confirmDialog = { show: true, title: options.title || '操作确认', message: options.message || '确定要执行此操作吗?', callback: options.callback || null, data: options.data || null }; }, // 确认操作 confirmAction() { if (this.confirmDialog.callback) { this.confirmDialog.callback(this.confirmDialog.data); } this.confirmDialog.show = false; }, // 取消确认 cancelConfirm() { this.confirmDialog.show = false; }, // 保存设置 async saveSettings() { try { // 构建设置对象 let opts = {}; ['OPT_ITEM_CONTEXTMENUS', 'FORBID_OPEN_IN_NEW_TAB', 'CONTENT_SCRIPT_ALLOW_ALL_FRAMES', 'JSON_PAGE_FORMAT', 'AUTO_DARK_MODE', 'ALWAYS_DARK_MODE'].forEach(key => { opts[key] = this.selectedOpts.includes(key).toString(); }); // 保存设置 - 直接传递对象,settings.js已增加对对象类型的支持 Settings.setOptions(opts, async () => { try { // 处理右键菜单 const crxAction = this.menuDownloadCrx ? 'install' : 'offload'; const settingAction = this.menuFeHelperSeting ? 'install' : 'offload'; await Promise.all([ Awesome.menuMgr('download-crx', crxAction), Awesome.menuMgr('fehelper-setting', settingAction) ]); // 通知后台更新右键菜单 chrome.runtime.sendMessage({ type: MSG_TYPE.DYNAMIC_TOOL_INSTALL_OR_OFFLOAD, action: 'menu-change', menuOnly: true }); // 关闭弹窗 this.closeSettings(); // 显示提示 this.showNotification({ title: 'FeHelper 设置', message: '设置已保存!' }); } catch (innerError) { console.error('保存菜单设置失败:', innerError); this.showNotification({ title: 'FeHelper 设置错误', message: '保存菜单设置失败: ' + innerError.message }); } }); } catch (error) { console.error('保存设置失败:', error); this.showNotification({ title: 'FeHelper 设置错误', message: '保存设置失败: ' + error.message }); } }, // 设置快捷键 setShortcuts() { chrome.tabs.create({ url: 'chrome://extensions/shortcuts' }); }, // 体验夜间模式 turnLight(event) { event.preventDefault(); // 获取body元素 const body = document.body; // 切换夜间模式 if (body.classList.contains('dark-mode')) { body.classList.remove('dark-mode'); } else { body.classList.add('dark-mode'); // 设置倒计时 this.countDown = 10; // 启动倒计时 const timer = setInterval(() => { this.countDown--; if (this.countDown <= 0) { clearInterval(timer); body.classList.remove('dark-mode'); } }, 1000); } }, // 检查URL中的donate_from参数并显示打赏弹窗 checkDonateParam() { try { const urlParams = new URLSearchParams(window.location.search); const donateFrom = urlParams.get('donate_from'); if (donateFrom) { console.log('检测到打赏来源参数:', donateFrom); // 记录打赏来源 chrome.storage.local.set({ 'fehelper_donate_from': donateFrom, 'fehelper_donate_time': Date.now() }); // 等待工具数据加载完成 this.$nextTick(() => { // 在所有工具中查找匹配项 let matchedTool = null; // 首先尝试直接匹配工具key if (this.originalTools && this.originalTools[donateFrom]) { matchedTool = this.originalTools[donateFrom]; } else if (this.originalTools) { // 如果没有直接匹配,尝试在所有工具中查找部分匹配 for (const [key, tool] of Object.entries(this.originalTools)) { if (key.includes(donateFrom) || donateFrom.includes(key) || (tool.name && tool.name.includes(donateFrom)) || (donateFrom && donateFrom.includes(tool.name))) { matchedTool = tool; break; } } } // 更新打赏文案 if (matchedTool) { this.donate.text = `看起来【${matchedTool.name}】工具帮助到了你,感谢你的认可!`; } else { // 没有匹配到特定工具,使用通用文案 this.donate.text = `感谢你对FeHelper的认可和支持!`; } // 显示打赏弹窗 this.showDonateModal = true; }); } } catch (error) { console.error('处理打赏参数时出错:', error); } }, // 补充 getRecentCount,保证模板调用不报错,且数据源唯一 async getRecentCount() { const recent = await Statistics.getRecentUsedTools(10); return recent.length; }, renderDashboard() { const dashboardContainerId = 'fh-dashboard-panel'; let container = document.getElementById(dashboardContainerId); // 只在showDashboard且currentView为recent时隐藏工具列表 const grid = document.querySelector('.tools-grid'); if (!this.showDashboard || this.currentView !== 'recent') { if (container) container.style.display = 'none'; if (grid) grid.style.display = ''; return; } if (grid) grid.style.display = 'none'; if (!container) { container = document.createElement('div'); container.id = dashboardContainerId; container.style = 'padding:32px; background:#fff; border-radius:8px; margin:24px; box-shadow:0 2px 12px #eee; min-width:700px;'; const main = document.querySelector('.market-main') || document.querySelector('.market-content'); if (main) main.prepend(container); else document.body.appendChild(container); } container.style.display = 'block'; const data = this.dashboardData || {}; // 工具ID转中文名和icon const toolName = (key) => (this.originalTools && this.originalTools[key] && this.originalTools[key].name) ? this.originalTools[key].name : key; const toolIcon = (key) => { if (toolMap[key] && toolMap[key].menuConfig && toolMap[key].menuConfig[0] && toolMap[key].menuConfig[0].icon) { return toolMap[key].menuConfig[0].icon; } return toolName(key).slice(0,1); }; // 插入美观样式 if (!document.getElementById('fh-dashboard-style')) { const style = document.createElement('style'); style.id = 'fh-dashboard-style'; style.innerHTML = ` .fh-dashboard-cards { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 24px;} .fh-card { background: linear-gradient(135deg,#f7f9fa 60%,#e3eafc 100%); border-radius: 12px; box-shadow:0 2px 8px #f0f0f0; padding:18px 24px; min-width:120px; flex:1; text-align:center; font-size:15px;} .fh-card.main { background: linear-gradient(135deg,#e3fcec 60%,#e3eafc 100%);} .fh-card-num { font-size:32px; font-weight:bold; margin-bottom:4px;} .fh-calendar { display:inline-block; margin-left:12px; } .fh-cal-cell { display:inline-block; width:18px; height:18px; line-height:18px; text-align:center; border-radius:3px; margin:1px; background:#eee; color:#888; font-size:12px;} .fh-cal-cell.used { background:#4285f4; color:#fff; font-weight:bold;} .fh-dashboard-section { background:#fff; border-radius:12px; box-shadow:0 1px 4px #f0f0f0; padding:18px 24px; margin-bottom:24px;} .fh-dashboard-header { margin-bottom:24px; } .fh-dashboard-header h2 { font-size:22px; margin:0; } .fh-tool-bar { display:inline-block; width:18px; height:18px; border-radius:3px; background:#e3eafc; margin-right:6px; vertical-align:middle; } .fh-tool-bar-inner { display:inline-block; height:100%; border-radius:3px; background:#4285f4; } .fh-tool-list { margin:0; padding:0; list-style:none; } .fh-tool-list li { margin-bottom:10px; } .fh-tool-icon { display:inline-block; width:18px; height:18px; border-radius:3px; background:#e3eafc; margin-right:6px; vertical-align:middle; text-align:center; font-size:14px; } .fh-dashboard-sub { color:#888; font-size:13px; margin-bottom:8px; } `; document.head.appendChild(style); } // 30天活跃日历 const today = new Date(); let calendar = '
'; for(let i=29;i>=0;i--){ const d = new Date(today.getTime()-i*86400000); const ds = d.toISOString().slice(0,10); const used = data.allDates && data.allDates.includes(ds); calendar += `${d.getDate()}`; } calendar += '
'; // 主卡片区块 let html = `

FeHelper 使用统计仪表盘 (近30天)

${data.totalCount||0}
总使用次数
${data.activeDays||0}
活跃天数
${data.firstDate||'-'}
~
${data.lastDate||'-'}
统计区间
${data.maxStreak||0}
最长连续活跃天数
${data.monthCount||0}
本月使用次数
${data.weekCount||0}
本周使用次数
${data.avgPerDay||0}
平均每日使用
${data.maxDay.date||'-'}
${data.maxDay.count||0}
最活跃日
${data.daysSinceLast||0}
最近未使用天数
近30天活跃日历:
${calendar}
最近10天活跃趋势:
${ (data.dailyTrend||[]).map(d=>{ const max = Math.max(...(data.dailyTrend||[]).map(x=>x.count),1); return `
`; }).join('') }
${(data.dailyTrend||[]).map(d=>`${d.date.slice(5)}`).join('')}
使用最多的工具:
最近10次使用的工具:
`; container.innerHTML = html; window.__vue__ = this; }, }, watch: { // 监听currentView变化 currentView: { immediate: true, handler(newView) { this.updateActiveTools(newView); } }, // 监听currentCategory变化 currentCategory: { handler(newCategory) { // 保证在视图模式之外的分类切换也能正确显示 if (this.currentView === 'all') { this.activeTools = { ...this.originalTools }; } // 重置搜索条件 if (this.searchKey) { this.searchKey = ''; } } }, showDashboard(val) { this.renderDashboard(); }, dashboardData(val) { this.renderDashboard(); }, }, mounted() { this.$nextTick(() => { this.renderDashboard(); }); }, }); // 添加滚动事件监听 window.addEventListener('scroll', () => { const header = document.querySelector('.market-header'); const sidebar = document.querySelector('.market-sidebar'); if (window.scrollY > 10) { header.classList.add('scrolled'); sidebar && sidebar.classList.add('scrolled'); } else { header.classList.remove('scrolled'); sidebar && sidebar.classList.remove('scrolled'); } }); // 页面加载后自动采集 if (window.chrome && chrome.runtime && chrome.runtime.sendMessage) { Awesome.collectAndSendClientInfo(); }