首页、学情、任务绑定接口
This commit is contained in:
+43
-32
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="activity-chart"><view class="activity-scale"><text class="activity-scale-text">时长(分)</text><text class="activity-scale-text">200</text><text class="activity-scale-text">100</text><text class="activity-scale-text">0</text></view><view class="activity-columns"><view v-for="point in points" :key="point.label" class="activity-column"><view class="activity-bar-wrap"><view class="activity-grid-line activity-grid-line-top"></view><view class="activity-grid-line activity-grid-line-middle"></view><view class="activity-grid-line activity-grid-line-bottom"></view><view class="activity-planned-bar" :style="{ height: point.plannedHeight + 'px' }"></view><view class="activity-study-bar" :style="{ height: point.studyHeight + 'px' }"></view><view v-if="point.newMasteredCount > 0" class="activity-mastery-point" :style="{ bottom: point.newMasteredHeight + 'px' }"><text class="activity-mastery-count">{{ point.newMasteredCount }}</text></view></view><text class="activity-day">{{ point.label }}</text></view></view><view class="activity-mastery-scale"><text class="activity-mastery-scale-text">新增掌握(个)</text><text class="activity-mastery-scale-text">3 个</text><text class="activity-mastery-scale-text">2 个</text><text class="activity-mastery-scale-text">1 个</text><text class="activity-mastery-scale-text">0 个</text></view></view>
|
||||
<view class="activity-chart"><view class="activity-scale"><text class="activity-scale-text">时长(分)</text><text class="activity-scale-text">200</text><text class="activity-scale-text">100</text><text class="activity-scale-text">0</text></view><view class="activity-columns"><view v-for="point in points" :key="point.label" class="activity-column"><view class="activity-bar-wrap"><view class="activity-grid-line activity-grid-line-top"></view><view class="activity-grid-line activity-grid-line-middle"></view><view class="activity-grid-line activity-grid-line-bottom"></view><view class="activity-planned-bar" :style="{ height: point.plannedHeight + 'px' }"></view><view class="activity-study-bar" :style="{ height: point.studyHeight + 'px' }"></view><view v-if="point.newMasteredCount > 0" class="activity-mastery-point" :style="{ bottom: point.newMasteredHeight + 'px' }"><text class="activity-mastery-count">{{ point.newMasteredCount }}</text></view></view><text class="activity-day">{{ point.label }}</text></view></view><view class="activity-mastery-scale"><text class="activity-mastery-scale-text">未攻克(分)</text><text class="activity-mastery-scale-text">90</text><text class="activity-mastery-scale-text">60</text><text class="activity-mastery-scale-text">30</text><text class="activity-mastery-scale-text">0</text></view></view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
Reference in New Issue
Block a user