QRCode Scanner

Coding | December 2023Read in Outline

<template>
    <Stack flex="1" p="5">
        <Stack justifyContent="center" gap="2" alignItems="center" flex="1">
            <Text fontSize="sm" fontWeight="bold">
                QRコードを画面中央に合わせてください
            </Text>
            <Stack p="5" bgColor="white" rounded="md" w="full">
                <Box id="qrcode-reader" ref="root" w="full" aspectRatio="1" />
            </Stack>
            <Button variant="link" @click="restartVideo">
                カメラを再起動する
            </Button>
        </Stack>
        <AppLink :href="'/ticket/use/emergency-code'" w="full">
            <Button shape="pill" size="xl" w="full">救済コードを入力</Button>
        </AppLink>
        <AppDialog v-model="cameraError" :closeable="false">
            <Stack>
                <Stack px="4" py="8" justifyContent="center">
                    <Text fontWeight="bold">カメラにアクセスできません</Text>
                    <Text>
                        端末の設定を変更し カメラへのアクセスをONにします
                    </Text>
                </Stack>
                <HStack>
                    <Button
                        variant="link"
                        w="full"
                        p="4"
                        @click="cameraError = false"
                    >
                        キャンセル
                    </Button>
                    <Button variant="link" w="full" p="4" @click="restartVideo">
                        やり直す
                    </Button>
                </HStack>
            </Stack>
        </AppDialog>
    </Stack>
</template>

<script lang="ts" setup>
    import { Html5Qrcode } from 'html5-qrcode'
    import type { ComponentPublicInstance } from 'vue'
    import debounce from 'lodash/debounce'
    import type Box from '~/components/core/layout/Box'

    const scanner = ref<Html5Qrcode>()
    const root = ref<ComponentPublicInstance<typeof Box>>()
    const cameraError = ref(false)

    const startQRScan = async () => {
        scanner.value = new Html5Qrcode(/* element id */ 'qrcode-reader')
        const element = root.value?.$el as HTMLDivElement
        const height = element.offsetHeight
        const width = element.offsetWidth
        const minWidth = Math.min(height, width)
        const config = {
            fps: 10,
            qrbox: { width: minWidth * 0.667, height: minWidth * 0.667 },
            aspectRatio: Math.ceil((width / height) * 100) / 100
        }

        try {
            await scanner.value.start(
                { facingMode: 'environment' },
                config,
                (_, result) => {
                    // do something when code is read
                    console.log(result)
                },
                (_, error) => {
                    // parse error, ignore it.
                    // console.log(error)
                }
            )
        } catch (error: unknown) {
            console.log(error)
            cameraError.value = true
        }
    }

    const restartVideo = debounce(async () => {
        cameraError.value = false
        if (scanner.value?.isScanning) {
            await scanner.value?.stop()
        }
        await startQRScan()
    }, 100)

    onMounted(() => {
        startQRScan()
        window.addEventListener('resize', restartVideo)
    })

    onUnmounted(() => {
        if (scanner.value?.isScanning) {
            scanner.value?.stop()
        }
        window.removeEventListener('resize', restartVideo)
    })
</script>

<style></style>

© 2023-2024 HamP, Assets used in the site belongs to respective owner | View Source