首页、学情、任务绑定接口

This commit is contained in:
hexi
2026-11-06 16:43:41 +08:00
parent af73453035
commit 4a19192d73
16 changed files with 965 additions and 236 deletions
+43 -32
View File
@@ -16,11 +16,6 @@
</template>
<script setup lang="ts">
// #ifdef WEB
import { BrowserQRCodeReader } from '@zxing/browser'
import type { IScannerControls } from '@zxing/browser'
// #endif
type Props = {
cooldown?: number
active?: boolean
@@ -39,10 +34,10 @@
let lastScannedAt = 0
// #ifdef WEB
const videoContainerId = `qr-scanner-${Date.now()}`
let scannerControls: IScannerControls | null = null
let scanVideo: HTMLVideoElement | null = null
let scanStream: MediaStream | null = null
let isPageActive = false
let restartTimer: number | null = null
let scanTimer: number | null = null
// #endif
function emitScan(result: string) {
@@ -77,7 +72,7 @@
}
async function startWebScanner() {
if (!isPageActive || !props.active || scannerControls != null) return
if (!isPageActive || !props.active || scanStream != null) return
const video = getScanVideo()
if (video == null) {
handleCameraError()
@@ -85,39 +80,55 @@
}
try {
const reader = new BrowserQRCodeReader()
scannerControls = await reader.decodeFromConstraints(
{ video: { facingMode: 'environment' } },
video,
(result, _error, controls) => {
if (!result) return
controls.stop()
scannerControls = null
emitScan(result.getText())
scheduleRestart()
}
)
const BarcodeDetectorClass = (window as any).BarcodeDetector
if (BarcodeDetectorClass == null || navigator.mediaDevices == null) {
handleCameraError()
return
}
scanStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
video.srcObject = scanStream
await video.play()
const detector = new BarcodeDetectorClass({ formats: ['qr_code'] })
void scanWebFrame(detector)
} catch (_error) {
stopWebScanner()
handleCameraError()
}
}
function scheduleRestart() {
if (!isPageActive || !props.active || restartTimer != null) return
restartTimer = setTimeout(() => {
restartTimer = null
void startWebScanner()
}, props.cooldown)
async function scanWebFrame(detector: any) {
if (!isPageActive || !props.active || scanVideo == null || scanStream == null) return
try {
const results = await detector.detect(scanVideo)
if (results.length > 0) {
emitScan(results[0].rawValue as string)
}
} catch (_error) {
handleCameraError()
return
}
scanTimer = setTimeout(() => {
scanTimer = null
void scanWebFrame(detector)
}, 250)
}
function stopWebScanner() {
if (restartTimer != null) {
clearTimeout(restartTimer)
restartTimer = null
if (scanTimer != null) {
clearTimeout(scanTimer)
scanTimer = null
}
if (scannerControls != null) {
scannerControls.stop()
scannerControls = null
if (scanStream != null) {
scanStream.getTracks().forEach((track) => {
track.stop()
})
scanStream = null
}
if (scanVideo != null) {
scanVideo.srcObject = null
}
}