"use client"; import QrScanner from "qr-scanner"; import { useRouter } from "next/navigation"; import { startTransition, useEffect, useEffectEvent, useRef, useState, } from "react"; function extractDeviceUuid(rawValue: string) { const trimmedValue = rawValue.trim(); if (!trimmedValue) { return null; } try { const parsedUrl = new URL(trimmedValue); return ( parsedUrl.searchParams.get("deviceUuid") || parsedUrl.searchParams.get("device") || null ); } catch { return trimmedValue; } } export function ScanClient() { const router = useRouter(); const videoRef = useRef(null); const scannerRef = useRef(null); const [statusText, setStatusText] = useState("正在准备镜头……"); const [errorText, setErrorText] = useState(null); const handleDecode = useEffectEvent(async (result: { data: string }) => { const scannedValue = extractDeviceUuid(result.data); if (!scannerRef.current || !scannedValue) { return; } scannerRef.current.stop(); setErrorText(null); setStatusText("识别到了设备,正在打开绑定页面……"); startTransition(() => { router.replace( `/bind?deviceUuid=${encodeURIComponent(scannedValue)}&source=scan`, ); }); }); useEffect(() => { let cancelled = false; async function startScanner() { if (!videoRef.current) { return; } try { const hasCamera = await QrScanner.hasCamera(); if (!hasCamera) { setErrorText("当前设备没有可用摄像头,请改用手动粘贴设备码。"); setStatusText("无法打开镜头"); return; } const scanner = new QrScanner( videoRef.current, (result) => { void handleDecode(result as { data: string }); }, { preferredCamera: "environment", highlightCodeOutline: true, highlightScanRegion: true, returnDetailedScanResult: true, onDecodeError: () => {}, }, ); scannerRef.current = scanner; await scanner.start(); if (!cancelled) { setStatusText("请将长辈手机上的二维码放到取景框内。"); } } catch (error) { setErrorText( error instanceof Error ? error.message : "镜头启动失败,请检查权限后重试。", ); setStatusText("镜头启动失败"); } } void startScanner(); return () => { cancelled = true; scannerRef.current?.destroy(); scannerRef.current = null; }; }, []); return (
); }