From 00fe3eddd9b5594880aa719e3fafe919ed5c0a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Wed, 20 May 2026 21:27:36 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=9A=82=E6=97=B6=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=9B=BE=E7=89=87=E4=BA=8C=E7=BB=B4=E7=A0=81=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 qrCode-image 右键菜单配置 - 删除 parseQrCodeFromUrl 函数 - 删除 QrCodeToUrlSection 中的 useContextMenuData 相关代码 - 更新相关测试用例 --- entrypoints/__tests__/background.test.ts | 37 ++--------------- pages/QrCode/QrCodeToUrlSection.tsx | 36 +--------------- utils/__tests__/contextMenu.test.ts | 52 ++---------------------- utils/contextMenu.ts | 22 ---------- utils/qrCodeParser.ts | 21 ---------- 5 files changed, 8 insertions(+), 160 deletions(-) diff --git a/entrypoints/__tests__/background.test.ts b/entrypoints/__tests__/background.test.ts index 5304b2a..21d5d32 100644 --- a/entrypoints/__tests__/background.test.ts +++ b/entrypoints/__tests__/background.test.ts @@ -42,14 +42,14 @@ describe('background 菜单注册与分流', () => { ); }); - it('应该创建图片二维码识别子菜单', () => { + it('应该创建网页链接转二维码子菜单', () => { createAllContextMenus(); expect(chrome.contextMenus.create).toHaveBeenCalledWith( expect.objectContaining({ - id: 'qrCode-image', - title: '🖼️ 识别图中的二维码', - contexts: ['image'], + id: 'qrCode-page', + title: '🔗 网页链接转二维码', + contexts: ['page'], }), ); }); @@ -79,35 +79,6 @@ describe('background 菜单注册与分流', () => { }); }); - it('当点击 qrCode-image 时应返回 qrCode 功能和 srcUrl', () => { - const info = createMockOnClickData({ - menuItemId: 'qrCode-image', - srcUrl: 'https://example.com/image.png', - }); - - const result = parseContextMenuClick('qrCode-image', info); - - expect(result).toEqual({ - success: true, - data: { featureKey: 'qrCode', payload: 'https://example.com/image.png' }, - }); - }); - - it('当图片为 Base64 内联图时应返回错误', () => { - const info = createMockOnClickData({ - menuItemId: 'qrCode-image', - srcUrl: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', - }); - - const result = parseContextMenuClick('qrCode-image', info); - - expect(result).toEqual({ - success: false, - error: '无法识别 Base64 内联图片,请使用图片文件 URL', - }); - }); - it('当没有 selectionText 和 srcUrl 时应返回错误', () => { const info = createMockOnClickData({ menuItemId: 'unknown', diff --git a/pages/QrCode/QrCodeToUrlSection.tsx b/pages/QrCode/QrCodeToUrlSection.tsx index 24f70cb..1bc99ed 100644 --- a/pages/QrCode/QrCodeToUrlSection.tsx +++ b/pages/QrCode/QrCodeToUrlSection.tsx @@ -20,9 +20,8 @@ import ClearIcon from '@mui/icons-material/Clear'; import CopyButton from '@/components/CopyButton'; import { qrCodePageStyles } from '@/config/pageTheme'; import { useSnackbar } from '@/components/GlobalSnackbar'; -import { parseQrCodeFromFile, parseQrCodeFromUrl } from '@/utils/qrCodeParser'; +import { parseQrCodeFromFile } from '@/utils/qrCodeParser'; import { useTranslation } from 'react-i18next'; -import { useContextMenuData } from '@/utils/useContextMenuData'; interface QrCodeToUrlSectionProps { expanded: boolean; @@ -47,39 +46,6 @@ const QrCodeToUrlSection = ({ const fileInputRef = useRef(null); - // 处理右键菜单传递的图片 URL - const handleContextMenuData = useCallback( - async (imageUrl: string) => { - try { - setParsing(true); - setParseError(''); - setParsedUrl(''); - setPreviewUrl(imageUrl); - - const result = await parseQrCodeFromUrl(imageUrl); - - if (result.success && result.data) { - setParsedUrl(result.data); - showMessage(t('qrCode:parseSuccess'), { severity: 'success', autoHideDuration: 1000 }); - } else { - setParseError(result.error || t('qrCode:noQrDetected')); - showMessage(result.error || t('qrCode:noQrDetected'), { - severity: 'error', - autoHideDuration: 1000, - }); - } - } catch (error) { - console.error('解析二维码失败:', error); - showMessage(t('qrCode:parseError'), { severity: 'error', autoHideDuration: 300 }); - } finally { - setParsing(false); - } - }, - [showMessage, t], - ); - - useContextMenuData({ featureKey: 'qrCode', onData: handleContextMenuData }); - // 清理预览 URL,防止内存泄漏 useEffect(() => { return () => { diff --git a/utils/__tests__/contextMenu.test.ts b/utils/__tests__/contextMenu.test.ts index 50847e8..49c09f9 100644 --- a/utils/__tests__/contextMenu.test.ts +++ b/utils/__tests__/contextMenu.test.ts @@ -12,8 +12,8 @@ describe('contextMenu', () => { }); describe('CONTEXT_MENU_CONFIGS', () => { - it('应该包含 8 个菜单项配置', () => { - expect(CONTEXT_MENU_CONFIGS).toHaveLength(8); + it('应该包含 7 个菜单项配置', () => { + expect(CONTEXT_MENU_CONFIGS).toHaveLength(7); }); it('应该有一个父级菜单项 Testing Tools', () => { @@ -36,14 +36,6 @@ describe('contextMenu', () => { ]); }); - it('应该有 1 个 image 上下文的子菜单', () => { - const imageMenus = CONTEXT_MENU_CONFIGS.filter( - (c) => c.contexts[0] === 'image' && c.parentId === 'testing-tools-parent', - ); - expect(imageMenus).toHaveLength(1); - expect(imageMenus[0].id).toBe('qrCode-image'); - }); - it('应该有 2 个 page 上下文的子菜单', () => { const pageMenus = CONTEXT_MENU_CONFIGS.filter( (c) => c.contexts[0] === 'page' && c.parentId === 'testing-tools-parent', @@ -57,7 +49,7 @@ describe('contextMenu', () => { it('应该为每个配置调用 chrome.contextMenus.create', () => { createAllContextMenus(); - expect(chrome.contextMenus.create).toHaveBeenCalledTimes(8); + expect(chrome.contextMenus.create).toHaveBeenCalledTimes(7); }); it('应该使用正确的参数创建菜单项', () => { @@ -89,44 +81,6 @@ describe('contextMenu', () => { ...overrides, }); - it('当点击 qrCode-image 菜单时应返回 qrCode 功能和 srcUrl', () => { - const info = createMockOnClickData({ - srcUrl: 'https://example.com/image.png', - }); - - const result = parseContextMenuClick('qrCode-image', info); - - expect(result).toEqual({ - success: true, - data: { featureKey: 'qrCode', payload: 'https://example.com/image.png' }, - }); - }); - - it('当图片为 Base64 内联图时应返回错误', () => { - const info = createMockOnClickData({ - srcUrl: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', - }); - - const result = parseContextMenuClick('qrCode-image', info); - - expect(result).toEqual({ - success: false, - error: '无法识别 Base64 内联图片,请使用图片文件 URL', - }); - }); - - it('当点击 qrCode-image 菜单但没有 srcUrl 时应返回成功', () => { - const info = createMockOnClickData({}); - - const result = parseContextMenuClick('qrCode-image', info); - - expect(result).toEqual({ - success: true, - data: { featureKey: 'qrCode', payload: '' }, - }); - }); - it('当点击 qrCode-page 菜单时应返回 qrCode 功能和 pageUrl', () => { const info = createMockOnClickData({ pageUrl: 'https://example.com/page', diff --git a/utils/contextMenu.ts b/utils/contextMenu.ts index 288de5a..dc56b9a 100644 --- a/utils/contextMenu.ts +++ b/utils/contextMenu.ts @@ -52,12 +52,6 @@ export const CONTEXT_MENU_CONFIGS: ContextMenuItemConfig[] = [ contexts: [chrome.contextMenus.ContextType.SELECTION], parentId: PARENT_MENU_ID, }, - { - id: 'qrCode-image', - title: '🖼️ 识别图中的二维码', - contexts: [chrome.contextMenus.ContextType.IMAGE], - parentId: PARENT_MENU_ID, - }, { id: 'storageCleaner', title: '🧹 清理当前网站存储', @@ -89,22 +83,6 @@ export function parseContextMenuClick( ): ParseResult { const featureKey = menuItemId as PageType; - if (menuItemId === 'qrCode-image') { - const srcUrl = info.srcUrl || ''; - - if (srcUrl.startsWith('data:image/')) { - return { - success: false, - error: '无法识别 Base64 内联图片,请使用图片文件 URL', - }; - } - - return { - success: true, - data: { featureKey: 'qrCode', payload: srcUrl }, - }; - } - if (menuItemId === 'qrCode-page') { return { success: true, diff --git a/utils/qrCodeParser.ts b/utils/qrCodeParser.ts index 5727c28..0148c99 100644 --- a/utils/qrCodeParser.ts +++ b/utils/qrCodeParser.ts @@ -35,24 +35,3 @@ export async function parseQrCodeFromFile(file: File): Promise { - try { - const response = await fetch(imageUrl); - if (!response.ok) { - return { success: false, error: '无法下载图片' }; - } - - const blob = await response.blob(); - const file = new File([blob], 'qrcode.jpg', { type: blob.type || 'image/jpeg' }); - - return await parseQrCodeFromFile(file); - } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); - return { success: false, error: `下载图片失败: ${errorMsg}` }; - } -}