feat: 完成采购订单功能。

This commit is contained in:
c
2026-03-07 17:31:55 +08:00
parent 324c1c0a73
commit d75f33dda7
4 changed files with 706 additions and 65 deletions

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import QRCode from "qrcode";
import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
const props = defineProps({
title: {
@@ -10,6 +11,10 @@ const props = defineProps({
type: String,
default: "",
},
qrCodeList: {
type: Array as () => Array<{ qrContent: string; label?: string }>,
default: () => [],
},
qrCodeSize: {
type: Number,
default: 200,
@@ -26,13 +31,19 @@ const props = defineProps({
const visible = defineModel<boolean>("visible");
const qrCodeDataUrl = ref("");
const qrCodeDataUrls = ref<Array<{ dataUrl: string; label?: string }>>([]);
const loading = ref(false);
const currentIndex = ref(0);
const generateQrCode = async () => {
if (!props.qrCodeContent) {
return;
if (props.qrCodeList.length > 0) {
await generateAllQrCodes();
} else if (props.qrCodeContent) {
await generateSingleQrCode();
}
};
const generateSingleQrCode = async () => {
loading.value = true;
try {
qrCodeDataUrl.value = await QRCode.toDataURL(props.qrCodeContent, {
@@ -50,12 +61,55 @@ const generateQrCode = async () => {
}
};
const generateAllQrCodes = async () => {
loading.value = true;
try {
const results = [];
for (const item of props.qrCodeList) {
const dataUrl = await QRCode.toDataURL(item.qrContent, {
width: props.qrCodeSize,
margin: 2,
color: {
dark: "#000000",
light: "#ffffff",
},
});
results.push({ dataUrl, label: item.label || item.partNumber || "" });
}
qrCodeDataUrls.value = results;
currentIndex.value = 0;
} catch (error) {
console.error("Generate QR codes failed:", error);
} finally {
loading.value = false;
}
};
const handlePrint = () => {
const printWindow = window.open("", "_blank");
if (!printWindow) {
return;
}
let imagesHtml = "";
if (props.qrCodeList.length > 0) {
for (const item of qrCodeDataUrls.value) {
imagesHtml += `
<div class="qrcode-item">
<img src="${item.dataUrl}" alt="QR Code" />
${props.showLabel && item.label ? `<div class="label">${item.label}</div>` : ""}
</div>
`;
}
} else {
imagesHtml = `
<div class="qrcode-item">
<img src="${qrCodeDataUrl.value}" alt="QR Code" />
${props.showLabel ? `<div class="label">${props.label || props.qrCodeContent}</div>` : ""}
</div>
`;
}
const imgHtml = `
<!DOCTYPE html>
<html>
@@ -63,12 +117,13 @@ const handlePrint = () => {
<title>${props.title || "QR Code"}</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
}
.qrcode-item {
display: inline-block;
margin: 10px;
text-align: center;
}
img {
max-width: 100%;
}
@@ -82,12 +137,14 @@ const handlePrint = () => {
body {
padding: 0;
}
.qrcode-item {
page-break-inside: avoid;
}
}
</style>
</head>
<body>
<img src="${qrCodeDataUrl.value}" alt="QR Code" />
${props.showLabel ? `<div class="label">${props.label || props.qrCodeContent}</div>` : ""}
${imagesHtml}
</body>
</html>
`;
@@ -102,23 +159,53 @@ const handlePrint = () => {
};
const handleDownload = () => {
const link = document.createElement("a");
link.download = `${props.label || props.qrCodeContent || "qrcode"}.png`;
link.href = qrCodeDataUrl.value;
link.click();
if (props.qrCodeList.length > 0) {
const currentItem = qrCodeDataUrls.value[currentIndex.value];
const link = document.createElement("a");
link.download = `${currentItem.label || "qrcode"}.png`;
link.href = currentItem.dataUrl;
link.click();
} else {
const link = document.createElement("a");
link.download = `${props.label || props.qrCodeContent || "qrcode"}.png`;
link.href = qrCodeDataUrl.value;
link.click();
}
};
const prevQrCode = () => {
if (currentIndex.value > 0) {
currentIndex.value--;
}
};
const nextQrCode = () => {
if (currentIndex.value < qrCodeDataUrls.value.length - 1) {
currentIndex.value++;
}
};
watch(
() => props.qrCodeContent,
() => {
if (visible.value && props.qrCodeContent) {
generateQrCode();
if (visible.value && props.qrCodeContent && props.qrCodeList.length === 0) {
generateSingleQrCode();
}
}
);
watch(
() => props.qrCodeList,
() => {
if (visible.value && props.qrCodeList.length > 0) {
generateAllQrCodes();
}
},
{ deep: true }
);
watch(visible, newVal => {
if (newVal && props.qrCodeContent) {
if (newVal) {
generateQrCode();
}
});
@@ -128,25 +215,47 @@ watch(visible, newVal => {
<el-dialog
:title="title"
v-model="visible"
width="400px"
width="450px"
: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 v-if="props.qrCodeList.length > 0" class="qrcode-list-container">
<div v-if="qrCodeDataUrls.length > 0" class="qrcode-display">
<img :src="qrCodeDataUrls[currentIndex].dataUrl" alt="QR Code" />
<div v-if="showLabel && qrCodeDataUrls[currentIndex].label" class="qrcode-label">
{{ qrCodeDataUrls[currentIndex].label }}
</div>
</div>
<div v-if="qrCodeDataUrls.length > 0 && qrCodeDataUrls.length > 1" class="qrcode-navigation">
<el-button :disabled="currentIndex === 0" @click="prevQrCode" circle>
<el-icon><ArrowLeft /></el-icon>
</el-button>
<span class="qrcode-pagination">{{ currentIndex + 1 }} / {{ qrCodeDataUrls.length }}</span>
<el-button :disabled="currentIndex === qrCodeDataUrls.length - 1" @click="nextQrCode" circle>
<el-icon><ArrowRight /></el-icon>
</el-button>
</div>
<div v-if="qrCodeDataUrls.length === 0 && !loading" class="qrcode-placeholder">
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
</div>
</div>
<div v-else class="qrcode-placeholder">
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
<div v-else>
<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-if="!loading" class="qrcode-placeholder">
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
</div>
</div>
</div>
<template #footer>
<el-button @click="visible = false">{{ $t("_button.cancel") }}</el-button>
<el-button type="primary" @click="handleDownload" :disabled="!qrCodeDataUrl">
<el-button type="primary" @click="handleDownload" :disabled="!qrCodeDataUrl && qrCodeDataUrls.length === 0">
{{ $t("_button.download") }}
</el-button>
<el-button type="success" @click="handlePrint" :disabled="!qrCodeDataUrl">
<el-button type="success" @click="handlePrint" :disabled="!qrCodeDataUrl && qrCodeDataUrls.length === 0">
{{ $t("_button.print") }}
</el-button>
</template>
@@ -162,6 +271,13 @@ watch(visible, newVal => {
min-height: 200px;
}
.qrcode-list-container {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.qrcode-display {
display: flex;
flex-direction: column;
@@ -181,6 +297,20 @@ watch(visible, newVal => {
word-break: break-all;
}
.qrcode-navigation {
display: flex;
gap: 10px;
align-items: center;
margin-top: 15px;
}
.qrcode-pagination {
min-width: 60px;
font-size: 14px;
color: #606266;
text-align: center;
}
.qrcode-placeholder {
font-size: 14px;
color: #909399;