From 8e920c2a94df58831bfb9e70e1fc7f5a5fa06ceb 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:19:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=8F=B3=E9=94=AE?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=9B=BE=E7=89=87=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 qrCodeParser.ts 中添加 parseQrCodeFromUrl 函数,支持从图片 URL 解析二维码 - 在 QrCodeToUrlSection 中使用 useContextMenuData 接收右键菜单传递的图片 URL - 自动下载图片并解析二维码,显示解析结果 --- pages/QrCode/QrCodeToUrlSection.tsx | 36 ++++++++++++++++++++++++++++- utils/qrCodeParser.ts | 21 +++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/pages/QrCode/QrCodeToUrlSection.tsx b/pages/QrCode/QrCodeToUrlSection.tsx index 1bc99ed..24f70cb 100644 --- a/pages/QrCode/QrCodeToUrlSection.tsx +++ b/pages/QrCode/QrCodeToUrlSection.tsx @@ -20,8 +20,9 @@ import ClearIcon from '@mui/icons-material/Clear'; import CopyButton from '@/components/CopyButton'; import { qrCodePageStyles } from '@/config/pageTheme'; import { useSnackbar } from '@/components/GlobalSnackbar'; -import { parseQrCodeFromFile } from '@/utils/qrCodeParser'; +import { parseQrCodeFromFile, parseQrCodeFromUrl } from '@/utils/qrCodeParser'; import { useTranslation } from 'react-i18next'; +import { useContextMenuData } from '@/utils/useContextMenuData'; interface QrCodeToUrlSectionProps { expanded: boolean; @@ -46,6 +47,39 @@ 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/qrCodeParser.ts b/utils/qrCodeParser.ts index 0148c99..5727c28 100644 --- a/utils/qrCodeParser.ts +++ b/utils/qrCodeParser.ts @@ -35,3 +35,24 @@ 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}` }; + } +}