Initial commit
This commit is contained in:
127
app/components/common/QRcode.vue
Normal file
127
app/components/common/QRcode.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div class="has-text-centered">
|
||||
<div class="mb-4">
|
||||
<p v-if="row && row.fullname"><b>{{row.fullname}}</b></p>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 px-5 is-flex is-justify-content-center">
|
||||
<ClientOnly>
|
||||
<Qrcode
|
||||
v-if="finalLink"
|
||||
:key="finalLink"
|
||||
id="qrcode"
|
||||
:value="finalLink"
|
||||
:size="300"
|
||||
/>
|
||||
</ClientOnly>
|
||||
<div v-if="!finalLink" style="width: 300px; height: 300px; border: 1px dashed #ccc; display: flex; align-items: center; justify-content: center; color: #888;">
|
||||
Không có dữ liệu để tạo QR Code
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 is-flex is-justify-content-center is-gap-1">
|
||||
<a
|
||||
@click="openLink()"
|
||||
class="button is-light is-link is-rounded"
|
||||
:title="isVietnamese ? 'Mở đường dẫn liên kết' : 'Open external link'"
|
||||
v-if="finalLink"
|
||||
>
|
||||
<span class="icon">
|
||||
<SvgIcon v-bind="{ name: 'open.svg', type: 'primary', size: 24 }" />
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
@click="download()"
|
||||
class="button is-light is-link is-rounded"
|
||||
:title="isVietnamese ? 'Tải Xuống QR Code' : 'Download QR Code'"
|
||||
v-if="finalLink"
|
||||
>
|
||||
<span class="icon">
|
||||
<SvgIcon v-bind="{ name: 'download.svg', type: 'primary', size: 24 }" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useStore } from "@/stores/index";
|
||||
|
||||
const store = useStore();
|
||||
const isVietnamese = computed(() => store.lang === "vi")
|
||||
|
||||
const { $getpath, $snackbar } = useNuxtApp()
|
||||
const props = defineProps({
|
||||
row: Object,
|
||||
link: String
|
||||
})
|
||||
|
||||
const finalLink = computed(() => {
|
||||
if (props.link) {
|
||||
return props.link
|
||||
}
|
||||
if (props.row && props.row.code) {
|
||||
const path = $getpath()
|
||||
const baseUrl = path ? path.replace('api.', '') : '';
|
||||
return `${baseUrl}loan/${props.row.code}`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
function openLink() {
|
||||
if (finalLink.value) {
|
||||
window.open(finalLink.value, "_blank")
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function download() {
|
||||
if (!finalLink.value) return;
|
||||
|
||||
let svg = document.getElementById('qrcode');
|
||||
let attempts = 0;
|
||||
|
||||
while (!svg && attempts < 5) {
|
||||
await sleep(100);
|
||||
svg = document.getElementById('qrcode');
|
||||
attempts++;
|
||||
}
|
||||
|
||||
if (!svg) {
|
||||
console.error("QR Code SVG element not found after waiting.");
|
||||
$snackbar(isVietnamese.value ? 'Không tìm thấy mã QR để tải xuống.' : 'QR Code not found for download.', { type: 'is-danger' });
|
||||
return;
|
||||
}
|
||||
|
||||
const serializer = new XMLSerializer()
|
||||
const svgData = serializer.serializeToString(svg)
|
||||
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' })
|
||||
const url = URL.createObjectURL(svgBlob)
|
||||
|
||||
const image = new Image()
|
||||
image.onload = () => {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = 300
|
||||
canvas.height = 300
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.drawImage(image, 0, 0, 300, 300)
|
||||
|
||||
const pngUrl = canvas.toDataURL('image/png')
|
||||
|
||||
const linkElement = document.createElement('a')
|
||||
linkElement.href = pngUrl
|
||||
|
||||
const filename = props.row && props.row.code ? `qrcode-${props.row.code}.png` : 'qrcode.png'
|
||||
linkElement.download = filename
|
||||
linkElement.click()
|
||||
|
||||
URL.revokeObjectURL(url)
|
||||
$snackbar(isVietnamese.value ? 'Đã tải xuống mã QR!' : 'QR Code downloaded!', { type: 'is-success' });
|
||||
}
|
||||
image.src = url
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user