Files
erp-frontend/src/components/base/base-qrcode/QrCodeDialog.vue

189 lines
3.8 KiB
Vue

<script lang="ts" setup>
import QRCode from "qrcode";
const props = defineProps({
title: {
type: String,
default: "",
},
qrCodeContent: {
type: String,
default: "",
},
qrCodeSize: {
type: Number,
default: 200,
},
showLabel: {
type: Boolean,
default: true,
},
label: {
type: String,
default: "",
},
});
const visible = defineModel<boolean>("visible");
const qrCodeDataUrl = ref("");
const loading = ref(false);
const generateQrCode = async () => {
if (!props.qrCodeContent) {
return;
}
loading.value = true;
try {
qrCodeDataUrl.value = await QRCode.toDataURL(props.qrCodeContent, {
width: props.qrCodeSize,
margin: 2,
color: {
dark: "#000000",
light: "#ffffff",
},
});
} catch (error) {
console.error("Generate QR code failed:", error);
} finally {
loading.value = false;
}
};
const handlePrint = () => {
const printWindow = window.open("", "_blank");
if (!printWindow) {
return;
}
const imgHtml = `
<!DOCTYPE html>
<html>
<head>
<title>${props.title || "QR Code"}</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
}
img {
max-width: 100%;
}
.label {
margin-top: 10px;
font-size: 16px;
font-weight: bold;
text-align: center;
}
@media print {
body {
padding: 0;
}
}
</style>
</head>
<body>
<img src="${qrCodeDataUrl.value}" alt="QR Code" />
${props.showLabel ? `<div class="label">${props.label || props.qrCodeContent}</div>` : ""}
</body>
</html>
`;
printWindow.document.write(imgHtml);
printWindow.document.close();
printWindow.focus();
setTimeout(() => {
printWindow.print();
printWindow.close();
}, 250);
};
const handleDownload = () => {
const link = document.createElement("a");
link.download = `${props.label || props.qrCodeContent || "qrcode"}.png`;
link.href = qrCodeDataUrl.value;
link.click();
};
watch(
() => props.qrCodeContent,
() => {
if (visible.value && props.qrCodeContent) {
generateQrCode();
}
}
);
watch(visible, newVal => {
if (newVal && props.qrCodeContent) {
generateQrCode();
}
});
</script>
<template>
<el-dialog
:title="title"
v-model="visible"
width="400px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div v-loading="loading" class="qrcode-container">
<div v-if="qrCodeDataUrl" class="qrcode-display">
<img :src="qrCodeDataUrl" alt="QR Code" />
<div v-if="showLabel" class="qrcode-label">{{ label || qrCodeContent }}</div>
</div>
<div v-else class="qrcode-placeholder">
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
</div>
</div>
<template #footer>
<el-button @click="visible = false">{{ $t("_button.cancel") }}</el-button>
<el-button type="primary" @click="handleDownload" :disabled="!qrCodeDataUrl">
{{ $t("_button.download") }}
</el-button>
<el-button type="success" @click="handlePrint" :disabled="!qrCodeDataUrl">
{{ $t("_button.print") }}
</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.qrcode-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 200px;
}
.qrcode-display {
display: flex;
flex-direction: column;
align-items: center;
}
.qrcode-display img {
max-width: 100%;
height: auto;
}
.qrcode-label {
margin-top: 10px;
font-size: 14px;
font-weight: bold;
text-align: center;
word-break: break-all;
}
.qrcode-placeholder {
font-size: 14px;
color: #909399;
}
</style>