feat: 支持右键菜单图片二维码识别
- 在 qrCodeParser.ts 中添加 parseQrCodeFromUrl 函数,支持从图片 URL 解析二维码 - 在 QrCodeToUrlSection 中使用 useContextMenuData 接收右键菜单传递的图片 URL - 自动下载图片并解析二维码,显示解析结果
This commit is contained in:
@@ -20,8 +20,9 @@ import ClearIcon from '@mui/icons-material/Clear';
|
|||||||
import CopyButton from '@/components/CopyButton';
|
import CopyButton from '@/components/CopyButton';
|
||||||
import { qrCodePageStyles } from '@/config/pageTheme';
|
import { qrCodePageStyles } from '@/config/pageTheme';
|
||||||
import { useSnackbar } from '@/components/GlobalSnackbar';
|
import { useSnackbar } from '@/components/GlobalSnackbar';
|
||||||
import { parseQrCodeFromFile } from '@/utils/qrCodeParser';
|
import { parseQrCodeFromFile, parseQrCodeFromUrl } from '@/utils/qrCodeParser';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useContextMenuData } from '@/utils/useContextMenuData';
|
||||||
|
|
||||||
interface QrCodeToUrlSectionProps {
|
interface QrCodeToUrlSectionProps {
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
@@ -46,6 +47,39 @@ const QrCodeToUrlSection = ({
|
|||||||
|
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(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,防止内存泄漏
|
// 清理预览 URL,防止内存泄漏
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -35,3 +35,24 @@ export async function parseQrCodeFromFile(file: File): Promise<QrCodeParseResult
|
|||||||
return { success: false, error: errorMsg };
|
return { success: false, error: errorMsg };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从图片 URL 解析二维码
|
||||||
|
* 先下载图片,然后调用 parseQrCodeFromFile
|
||||||
|
*/
|
||||||
|
export async function parseQrCodeFromUrl(imageUrl: string): Promise<QrCodeParseResult> {
|
||||||
|
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}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user