141 lines
3.6 KiB
Vue
141 lines
3.6 KiB
Vue
<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.", "Error");
|
|
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!", "Error");
|
|
};
|
|
image.src = url;
|
|
}
|
|
</script>
|