feat(qr-scanner): integrate jsQR for QR code scanning fallback
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
|||||||
QrCode,
|
QrCode,
|
||||||
Xmark,
|
Xmark,
|
||||||
} from "@gravity-ui/icons";
|
} from "@gravity-ui/icons";
|
||||||
|
import jsQR from "jsqr";
|
||||||
import { api } from "@/lib/api";
|
import { api } from "@/lib/api";
|
||||||
import dayjs from "@/lib/dayjs";
|
import dayjs from "@/lib/dayjs";
|
||||||
|
|
||||||
@@ -155,21 +156,35 @@ function QrScanner({ onResult, onClose }: ScannerProps) {
|
|||||||
|
|
||||||
if (!mountedRef.current) return;
|
if (!mountedRef.current) return;
|
||||||
|
|
||||||
if (!("BarcodeDetector" in window)) {
|
const useNative = "BarcodeDetector" in window;
|
||||||
if (mountedRef.current) setError("当前浏览器不支持实时扫描,请升级至最新版本");
|
if (useNative) {
|
||||||
return;
|
detector = new (window as any).BarcodeDetector({ formats: ["qr_code"] });
|
||||||
}
|
}
|
||||||
|
|
||||||
detector = new (window as any).BarcodeDetector({ formats: ["qr_code"] });
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
const scan = async () => {
|
const scan = async () => {
|
||||||
if (!scanningRef.current || !videoRef.current) return;
|
if (!scanningRef.current || !videoRef.current) return;
|
||||||
try {
|
try {
|
||||||
|
if (useNative) {
|
||||||
const codes: Array<{ rawValue: string }> = await detector.detect(videoRef.current);
|
const codes: Array<{ rawValue: string }> = await detector.detect(videoRef.current);
|
||||||
if (codes.length > 0) {
|
if (codes.length > 0) {
|
||||||
onResult(codes[0].rawValue);
|
onResult(codes[0].rawValue);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (ctx) {
|
||||||
|
const video = videoRef.current;
|
||||||
|
canvas.width = video.videoWidth;
|
||||||
|
canvas.height = video.videoHeight;
|
||||||
|
ctx.drawImage(video, 0, 0);
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
||||||
|
if (code) {
|
||||||
|
onResult(code.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
requestAnimationFrame(scan);
|
requestAnimationFrame(scan);
|
||||||
};
|
};
|
||||||
@@ -411,8 +426,7 @@ function ChargePageContent() {
|
|||||||
.filter((cp) => cp.registrationStatus === "Accepted")
|
.filter((cp) => cp.registrationStatus === "Accepted")
|
||||||
.map((cp) => {
|
.map((cp) => {
|
||||||
const online =
|
const online =
|
||||||
!!cp.lastHeartbeatAt &&
|
!!cp.lastHeartbeatAt && dayjs().diff(dayjs(cp.lastHeartbeatAt), "second") < 120;
|
||||||
dayjs().diff(dayjs(cp.lastHeartbeatAt), "second") < 120;
|
|
||||||
const availableCount = cp.connectors.filter(
|
const availableCount = cp.connectors.filter(
|
||||||
(c) => c.status === "Available",
|
(c) => c.status === "Available",
|
||||||
).length;
|
).length;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"better-auth": "catalog:",
|
"better-auth": "catalog:",
|
||||||
"dayjs": "catalog:",
|
"dayjs": "catalog:",
|
||||||
|
"jsqr": "^1.4.0",
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"qrcode.react": "^4.2.0",
|
"qrcode.react": "^4.2.0",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
|
|||||||
Reference in New Issue
Block a user