From c7b4b9a2f4c0f05aeb60a9e3f5fba5d9a3676f3f Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期一, 18 八月 2025 16:22:42 +0800 Subject: [PATCH] 中强恒兴设备管理页面添加 --- src/views/tool/qrCodeGenerator/index.vue | 433 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 433 insertions(+), 0 deletions(-) diff --git a/src/views/tool/qrCodeGenerator/index.vue b/src/views/tool/qrCodeGenerator/index.vue new file mode 100644 index 0000000..5fff74a --- /dev/null +++ b/src/views/tool/qrCodeGenerator/index.vue @@ -0,0 +1,433 @@ +<template> + <div class="app-container"> + <el-card class="box-card"> + <template #header> + <div class="card-header"> + <span>浜岀淮鐮佷笌闃蹭吉鐮佺敓鎴愬櫒</span> + <el-button type="primary" @click="showBatchDialog" icon="Plus"> + 鎵归噺鐢熸垚 + </el-button> + </div> + </template> + + <!-- 闆嗘垚浜岀淮鐮佺敓鎴愮粍浠� --> + <QRCodeGenerator ref="qrGeneratorRef" /> + </el-card> + + <!-- 鎵归噺鐢熸垚瀵硅瘽妗� --> + <el-dialog v-model="batchDialogVisible" title="鎵归噺鐢熸垚璁剧疆" width="800px"> + <el-form :model="batchForm" :rules="batchRules" ref="batchFormRef" label-width="120px"> + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鏍囪瘑绫诲瀷" prop="type"> + <el-select v-model="batchForm.type" placeholder="璇烽�夋嫨鏍囪瘑绫诲瀷" style="width: 100%"> + <el-option label="浜岀淮鐮�" value="qrcode"></el-option> + <el-option label="闃蹭吉鐮�" value="security"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鐢熸垚鏁伴噺" prop="quantity"> + <el-input-number + v-model="batchForm.quantity" + :min="1" + :max="1000" + :step="10" + style="width: 100%" + ></el-input-number> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鍓嶇紑" prop="prefix"> + <el-input v-model="batchForm.prefix" placeholder="璇疯緭鍏ュ墠缂�锛屽锛歅ROD_"></el-input> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="璧峰缂栧彿" prop="startNumber"> + <el-input-number v-model="batchForm.startNumber" :min="1" style="width: 100%"></el-input-number> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="灏哄" prop="size"> + <el-input-number + v-model="batchForm.size" + :min="100" + :max="500" + :step="50" + style="width: 100%" + ></el-input-number> + </el-col> + <el-col :span="12"> + <el-form-item label="杈硅窛" prop="margin"> + <el-input-number + v-model="batchForm.margin" + :min="0" + :max="10" + :step="1" + style="width: 100%" + ></el-input-number> + </el-col> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鍓嶆櫙鑹�" prop="foregroundColor"> + <el-color-picker v-model="batchForm.foregroundColor" style="width: 100%"></el-color-picker> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鑳屾櫙鑹�" prop="backgroundColor"> + <el-color-picker v-model="batchForm.backgroundColor" style="width: 100%"></el-color-picker> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="24"> + <el-form-item label="澶囨敞"> + <el-input + v-model="batchForm.remark" + type="textarea" + :rows="3" + placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�" + ></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="batchDialogVisible = false">鍙栨秷</el-button> + <el-button type="primary" @click="startBatchGeneration" :loading="generating"> + 寮�濮嬬敓鎴� + </el-button> + </div> + </template> + </el-dialog> + + <!-- 鎵归噺鐢熸垚杩涘害 --> + <el-dialog v-model="progressDialogVisible" title="鎵归噺鐢熸垚杩涘害" width="500px" :close-on-click-modal="false"> + <div class="progress-container"> + <el-progress + :percentage="progressPercentage" + :status="progressStatus" + :stroke-width="20" + ></el-progress> + <p class="progress-text">{{ progressText }}</p> + <div class="progress-details"> + <p>宸茬敓鎴�: {{ generatedCount }} / {{ totalCount }}</p> + <p>褰撳墠鍐呭: {{ currentContent }}</p> + </div> + </div> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="cancelGeneration" :disabled="!canCancel">鍙栨秷</el-button> + <el-button type="primary" @click="downloadBatchResults" v-if="generationCompleted"> + 涓嬭浇缁撴灉 + </el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import { ref, reactive, computed } from 'vue' +import { ElMessage, ElMessageBox } from 'element-plus' +import QRCodeGenerator from '@/components/QRCodeGenerator/index.vue' +import QRCode from 'qrcode' +import JSZip from 'jszip' + +defineOptions({ + name: 'QRCodeGeneratorPage' +}) + +// 缁勪欢寮曠敤 +const qrGeneratorRef = ref() + +// 鎵归噺鐢熸垚鐩稿叧 +const batchDialogVisible = ref(false) +const progressDialogVisible = ref(false) +const generating = ref(false) +const generationCompleted = ref(false) +const canCancel = ref(true) + +const batchForm = reactive({ + type: 'qrcode', + quantity: 100, + prefix: 'PROD_', + startNumber: 1, + size: 200, + margin: 2, + foregroundColor: '#000000', + backgroundColor: '#FFFFFF', + remark: '' +}) + +const batchRules = { + type: [{ required: true, message: '璇烽�夋嫨鏍囪瘑绫诲瀷', trigger: 'change' }], + quantity: [{ required: true, message: '璇疯緭鍏ョ敓鎴愭暟閲�', trigger: 'blur' }], + prefix: [{ required: true, message: '璇疯緭鍏ュ墠缂�', trigger: 'blur' }], + startNumber: [{ required: true, message: '璇疯緭鍏ヨ捣濮嬬紪鍙�', trigger: 'blur' }] +} + +// 杩涘害鐩稿叧 +const progressPercentage = ref(0) +const progressStatus = ref('') +const progressText = ref('鍑嗗涓�...') +const generatedCount = ref(0) +const totalCount = ref(0) +const currentContent = ref('') + +// 鐢熸垚缁撴灉 +const batchResults = ref([]) + +// 鏄剧ず鎵归噺鐢熸垚瀵硅瘽妗� +const showBatchDialog = () => { + batchDialogVisible.value = true + // 閲嶇疆琛ㄥ崟 + Object.assign(batchForm, { + type: 'qrcode', + quantity: 100, + prefix: 'PROD_', + startNumber: 1, + size: 200, + margin: 2, + foregroundColor: '#000000', + backgroundColor: '#FFFFFF', + remark: '' + }) +} + +// 寮�濮嬫壒閲忕敓鎴� +const startBatchGeneration = async () => { + try { + await batchFormRef.value.validate() + + if (!batchForm.prefix.trim()) { + ElMessage.warning('璇疯緭鍏ュ墠缂�') + return + } + + batchDialogVisible.value = false + progressDialogVisible.value = true + generating.value = true + generationCompleted.value = false + canCancel.value = true + + // 閲嶇疆杩涘害 + progressPercentage.value = 0 + progressStatus.value = '' + progressText.value = '寮�濮嬬敓鎴�...' + generatedCount.value = 0 + totalCount.value = batchForm.quantity + batchResults.value = [] + + await generateBatchCodes() + + } catch (error) { + console.error('鎵归噺鐢熸垚澶辫触:', error) + ElMessage.error('鎵归噺鐢熸垚澶辫触锛�' + error.message) + } +} + +// 鐢熸垚闃蹭吉鐮佸唴瀹� +const generateSecurityCode = (content) => { + const timestamp = Date.now() + const random = Math.random().toString(36).substr(2, 8) + return `SEC_${content}_${timestamp}_${random}` +} + +// 鎵归噺鐢熸垚鐮� +const generateBatchCodes = async () => { + try { + for (let i = 0; i < batchForm.quantity; i++) { + if (!canCancel.value) { + progressText.value = '鐢熸垚宸插彇娑�' + progressStatus.value = 'exception' + break + } + + const number = batchForm.startNumber + i + const content = `${batchForm.prefix}${number.toString().padStart(6, '0')}` + currentContent.value = content + + let codeUrl + if (batchForm.type === 'qrcode') { + codeUrl = await QRCode.toDataURL(content, { + width: batchForm.size, + margin: batchForm.margin, + color: { + dark: batchForm.foregroundColor, + light: batchForm.backgroundColor + }, + errorCorrectionLevel: 'M' + }) + } else { + const securityContent = generateSecurityCode(content) + codeUrl = await QRCode.toDataURL(securityContent, { + width: batchForm.size, + margin: batchForm.margin, + color: { + dark: batchForm.foregroundColor, + light: batchForm.backgroundColor + }, + errorCorrectionLevel: 'H' + }) + } + + batchResults.value.push({ + content, + url: codeUrl, + type: batchForm.type, + generateTime: new Date().toLocaleString() + }) + + generatedCount.value = i + 1 + progressPercentage.value = Math.round(((i + 1) / batchForm.quantity) * 100) + progressText.value = `姝e湪鐢熸垚绗� ${i + 1} 涓爜...` + + // 娣诲姞灏忓欢杩燂紝璁╃敤鎴风湅鍒拌繘搴� + await new Promise(resolve => setTimeout(resolve, 50)) + } + + if (canCancel.value) { + progressText.value = '鐢熸垚瀹屾垚锛�' + progressStatus.value = 'success' + generationCompleted.value = true + ElMessage.success(`鎵归噺鐢熸垚瀹屾垚锛屽叡鐢熸垚 ${batchForm.quantity} 涓爜`) + } + + } catch (error) { + console.error('鎵归噺鐢熸垚澶辫触:', error) + progressText.value = '鐢熸垚澶辫触锛�' + error.message + progressStatus.value = 'exception' + ElMessage.error('鎵归噺鐢熸垚澶辫触锛�' + error.message) + } finally { + generating.value = false + } +} + +// 鍙栨秷鐢熸垚 +const cancelGeneration = () => { + canCancel.value = false + progressText.value = '姝e湪鍙栨秷...' + setTimeout(() => { + progressDialogVisible.value = false + ElMessage.info('鐢熸垚宸插彇娑�') + }, 1000) +} + +// 涓嬭浇鎵归噺鐢熸垚缁撴灉 +const downloadBatchResults = async () => { + if (batchResults.value.length === 0) { + ElMessage.warning('娌℃湁鍙笅杞界殑缁撴灉') + return + } + + try { + const zip = new JSZip() + + // 鍒涘缓璇存槑鏂囦欢 + const readme = `鎵归噺鐢熸垚璇存槑 +绫诲瀷: ${batchForm.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'} +鏁伴噺: ${batchResults.value.length} +鍓嶇紑: ${batchForm.prefix} +璧峰缂栧彿: ${batchForm.startNumber} +灏哄: ${batchForm.size}x${batchForm.size}px +鐢熸垚鏃堕棿: ${new Date().toLocaleString()} +澶囨敞: ${batchForm.remark || '鏃�'} + +鏂囦欢鍒楄〃: +${batchResults.value.map((item, index) => `${index + 1}. ${item.content}.png`).join('\n')} +` + + zip.file('README.txt', readme) + + // 娣诲姞鍥剧墖鏂囦欢 + batchResults.value.forEach((result, index) => { + const base64Data = result.url.split(',')[1] + const byteCharacters = atob(base64Data) + const byteNumbers = new Array(byteCharacters.length) + for (let i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i) + } + const byteArray = new Uint8Array(byteNumbers) + + zip.file(`${result.content}.png`, byteArray) + }) + + const content = await zip.generateAsync({ type: 'blob' }) + const a = document.createElement('a') + a.href = URL.createObjectURL(content) + a.download = `鎵归噺${batchForm.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}_${batchForm.prefix}_${new Date().getTime()}.zip` + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + URL.revokeObjectURL(a.href) + + ElMessage.success('鎵归噺涓嬭浇瀹屾垚锛�') + progressDialogVisible.value = false + + } catch (error) { + console.error('鎵归噺涓嬭浇澶辫触:', error) + ElMessage.error('鎵归噺涓嬭浇澶辫触锛�' + error.message) + } +} + +// 琛ㄥ崟寮曠敤 +const batchFormRef = ref() +</script> + +<style scoped> +.app-container { + padding: 20px; +} + +.box-card { + margin-bottom: 20px; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.progress-container { + text-align: center; + padding: 20px; +} + +.progress-text { + margin: 20px 0; + font-size: 16px; + font-weight: bold; +} + +.progress-details { + margin-top: 20px; + text-align: left; + background: #f8f9fa; + padding: 15px; + border-radius: 8px; +} + +.progress-details p { + margin: 8px 0; + color: #666; +} + +.dialog-footer { + text-align: right; +} +</style> -- Gitblit v1.9.3