第二次迭代优化
This commit is contained in:
@@ -3,6 +3,7 @@ import { nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import { QrCode, X } from 'lucide-vue-next'
|
||||
import jsQR from 'jsqr'
|
||||
import { parseWriteOffCode, type WriteOffCodePayload } from '@/utils/writeOffCode'
|
||||
|
||||
const router = useRouter()
|
||||
@@ -13,7 +14,10 @@ const scanError = ref('')
|
||||
|
||||
let stream: MediaStream | null = null
|
||||
let detector: { detect: (source: HTMLVideoElement) => Promise<Array<{ rawValue: string }>> } | null = null
|
||||
let canvas: HTMLCanvasElement | null = null
|
||||
let canvasContext: CanvasRenderingContext2D | null = null
|
||||
let frameId = 0
|
||||
let lastDecodeAt = 0
|
||||
|
||||
const getBarcodeDetector = () => {
|
||||
return (window as unknown as {
|
||||
@@ -36,6 +40,8 @@ const stopScan = () => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.srcObject = null
|
||||
}
|
||||
detector = null
|
||||
lastDecodeAt = 0
|
||||
}
|
||||
|
||||
const goConfirm = (payload: WriteOffCodePayload) => {
|
||||
@@ -54,14 +60,41 @@ const handleCodeValue = (rawValue: string) => {
|
||||
goConfirm(payload)
|
||||
}
|
||||
|
||||
const detectWithBarcodeDetector = async (video: HTMLVideoElement) => {
|
||||
if (!detector) return ''
|
||||
const results = await detector.detect(video)
|
||||
return results[0]?.rawValue || ''
|
||||
}
|
||||
|
||||
const detectWithJsQr = (video: HTMLVideoElement) => {
|
||||
const width = video.videoWidth
|
||||
const height = video.videoHeight
|
||||
if (!width || !height) return ''
|
||||
|
||||
if (!canvas) {
|
||||
canvas = document.createElement('canvas')
|
||||
}
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
canvasContext = canvas.getContext('2d', { willReadFrequently: true })
|
||||
}
|
||||
if (!canvasContext) return ''
|
||||
|
||||
canvasContext.drawImage(video, 0, 0, width, height)
|
||||
const imageData = canvasContext.getImageData(0, 0, width, height)
|
||||
return jsQR(imageData.data, width, height, { inversionAttempts: 'dontInvert' })?.data || ''
|
||||
}
|
||||
|
||||
const detectLoop = async () => {
|
||||
if (!scanning.value || !videoRef.value || !detector) return
|
||||
if (!scanning.value || !videoRef.value) return
|
||||
const video = videoRef.value
|
||||
|
||||
try {
|
||||
if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
|
||||
const results = await detector.detect(video)
|
||||
const value = results[0]?.rawValue
|
||||
const now = Date.now()
|
||||
if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA && now - lastDecodeAt > 120) {
|
||||
lastDecodeAt = now
|
||||
const value = detector ? await detectWithBarcodeDetector(video) : detectWithJsQr(video)
|
||||
if (value) {
|
||||
handleCodeValue(value)
|
||||
return
|
||||
@@ -79,16 +112,16 @@ const detectLoop = async () => {
|
||||
const startScan = async () => {
|
||||
if (scanning.value || loading.value) return
|
||||
const BarcodeDetector = getBarcodeDetector()
|
||||
if (!BarcodeDetector) {
|
||||
scanError.value = '当前浏览器不支持摄像头扫码'
|
||||
showToast('当前浏览器不支持摄像头扫码')
|
||||
if (!navigator.mediaDevices?.getUserMedia) {
|
||||
scanError.value = '当前浏览器无法打开摄像头'
|
||||
showToast('当前浏览器无法打开摄像头')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
scanError.value = ''
|
||||
try {
|
||||
detector = new BarcodeDetector({ formats: ['qr_code'] })
|
||||
detector = BarcodeDetector ? new BarcodeDetector({ formats: ['qr_code'] }) : null
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
|
||||
Reference in New Issue
Block a user