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/qrCodeSimple/index.vue | 526 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 526 insertions(+), 0 deletions(-) diff --git a/src/views/tool/qrCodeSimple/index.vue b/src/views/tool/qrCodeSimple/index.vue new file mode 100644 index 0000000..6f84fce --- /dev/null +++ b/src/views/tool/qrCodeSimple/index.vue @@ -0,0 +1,526 @@ +<template> + <div class="app-container"> + <el-row :gutter="20"> + <!-- 宸︿晶锛氱敓鎴愯〃鍗� --> + <el-col :span="12"> + <el-card class="box-card"> + <template #header> + <div class="card-header"> + <span>浜岀淮鐮佺敓鎴�</span> + </div> + </template> + + <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> + <el-form-item label="鍐呭" prop="content"> + <el-input + v-model="form.content" + type="textarea" + :rows="4" + placeholder="璇疯緭鍏ヨ鐢熸垚浜岀淮鐮佺殑鍐呭锛屽锛氱綉鍧�銆佹枃鏈�佽仈绯绘柟寮忕瓑" + ></el-input> + </el-form-item> + + <el-form-item label="灏哄"> + <el-select v-model="form.size" style="width: 100%"> + <el-option label="灏忓昂瀵� (128x128)" value="128"></el-option> + <el-option label="鏍囧噯灏哄 (256x256)" value="256"></el-option> + <el-option label="澶у昂瀵� (512x512)" value="512"></el-option> + <el-option label="瓒呭ぇ灏哄 (1024x1024)" value="1024"></el-option> + </el-select> + </el-form-item> + + <el-form-item label="鍓嶆櫙鑹�"> + <el-color-picker v-model="form.foregroundColor"></el-color-picker> + </el-form-item> + + <el-form-item label="鑳屾櫙鑹�"> + <el-color-picker v-model="form.backgroundColor"></el-color-picker> + </el-form-item> + + <el-form-item> + <el-button type="primary" @click="generateQRCode" :loading="generating" size="large"> + 鐢熸垚浜岀淮鐮� + </el-button> + <el-button @click="resetForm">閲嶇疆</el-button> + </el-form-item> + </el-form> + </el-card> + </el-col> + + <!-- 鍙充晶锛氶瑙堝拰涓嬭浇 --> + <el-col :span="12"> + <el-card class="box-card"> + <template #header> + <div class="card-header"> + <span>棰勮涓庝笅杞�</span> + <el-button + v-if="qrCodeUrl" + type="success" + @click="downloadQRCode" + icon="Download" + size="small" + > + 涓嬭浇鍥剧墖 + </el-button> + </div> + </template> + + <div v-if="qrCodeUrl" class="preview-container"> + <div class="qr-preview"> + <img :src="qrCodeUrl" alt="鐢熸垚鐨勪簩缁寸爜" /> + </div> + <div class="qr-info"> + <p><strong>鍐呭锛�</strong>{{ form.content }}</p> + <p><strong>灏哄锛�</strong>{{ form.size }}x{{ form.size }}px</p> + <p><strong>鐢熸垚鏃堕棿锛�</strong>{{ generateTime }}</p> + </div> + </div> + + <div v-else class="empty-preview"> + <el-empty description="璇峰厛鐢熸垚浜岀淮鐮�" :image-size="100"></el-empty> + </div> + </el-card> + </el-col> + </el-row> + + <!-- 闃蹭吉鐮佺敓鎴愬尯鍩� --> + <el-row :gutter="20" style="margin-top: 20px;"> + <el-col :span="24"> + <el-card class="box-card"> + <template #header> + <div class="card-header"> + <span>闃蹭吉鐮佺敓鎴�</span> + <el-button type="warning" @click="showSecurityDialog" icon="Shield"> + 鐢熸垚闃蹭吉鐮� + </el-button> + </div> + </template> + + <div class="security-info"> + <p>闃蹭吉鐮佺壒鐐癸細</p> + <ul> + <li>鍖呭惈鏃堕棿鎴冲拰闅忔満鏁帮紝纭繚鍞竴鎬�</li> + <li>浣跨敤鏈�楂樼籂閿欑骇鍒紝鎻愰珮鎵弿鎴愬姛鐜�</li> + <li>鏀寔鎵归噺鐢熸垚鍜屼笅杞�</li> + <li>閫傜敤浜庝骇鍝侀槻浼�佹枃妗i獙璇佺瓑鍦烘櫙</li> + </ul> + </div> + </el-card> + </el-col> + </el-row> + + <!-- 闃蹭吉鐮佺敓鎴愬璇濇 --> + <el-dialog v-model="securityDialogVisible" title="闃蹭吉鐮佺敓鎴�" width="600px"> + <el-form :model="securityForm" :rules="securityRules" ref="securityFormRef" label-width="100px"> + <el-form-item label="浜у搧鍚嶇О" prop="productName"> + <el-input v-model="securityForm.productName" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"></el-input> + </el-form-item> + + <el-form-item label="浜у搧缂栫爜" prop="productCode"> + <el-input v-model="securityForm.productCode" placeholder="璇疯緭鍏ヤ骇鍝佺紪鐮�"></el-input> + </el-form-item> + + <el-form-item label="鎵规鍙�" prop="batchNo"> + <el-input v-model="securityForm.batchNo" placeholder="璇疯緭鍏ユ壒娆″彿"></el-input> + </el-form-item> + + <el-form-item label="鐢熸垚鏁伴噺" prop="quantity"> + <el-input-number + v-model="securityForm.quantity" + :min="1" + :max="100" + style="width: 100%" + ></el-input-number> + </el-form-item> + + <el-form-item label="灏哄"> + <el-select v-model="securityForm.size" style="width: 100%"> + <el-option label="鏍囧噯灏哄 (256x256)" value="256"></el-option> + <el-option label="澶у昂瀵� (512x512)" value="512"></el-option> + </el-select> + </el-form-item> + </el-form> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="securityDialogVisible = false">鍙栨秷</el-button> + <el-button type="primary" @click="generateSecurityCodes" :loading="generatingSecurity"> + 寮�濮嬬敓鎴� + </el-button> + </div> + </template> + </el-dialog> + + <!-- 闃蹭吉鐮佺粨鏋滃睍绀� --> + <el-dialog v-model="securityResultVisible" title="闃蹭吉鐮佺敓鎴愮粨鏋�" width="80%" top="5vh"> + <div v-if="securityResults.length > 0" class="security-results"> + <div class="results-header"> + <p>鍏辩敓鎴� {{ securityResults.length }} 涓槻浼爜</p> + <el-button type="success" @click="downloadAllSecurityCodes" icon="Download"> + 涓嬭浇鍏ㄩ儴 + </el-button> + </div> + + <div class="results-grid"> + <div + v-for="(result, index) in securityResults" + :key="index" + class="result-item" + > + <img :src="result.url" :alt="result.content" /> + <p class="result-content">{{ result.content }}</p> + <el-button size="small" @click="downloadSingleSecurityCode(result)"> + 涓嬭浇 + </el-button> + </div> + </div> + </div> + </el-dialog> + </div> +</template> + +<script setup> +import { ref, reactive } from 'vue' +import { ElMessage } from 'element-plus' +import QRCode from 'qrcode' +import JSZip from 'jszip' + +defineOptions({ + name: 'QRCodeSimple' +}) + +// 浜岀淮鐮佺敓鎴愯〃鍗� +const form = reactive({ + content: '', + size: '256', + foregroundColor: '#000000', + backgroundColor: '#FFFFFF' +}) + +const rules = { + content: [{ required: true, message: '璇疯緭鍏ュ唴瀹�', trigger: 'blur' }] +} + +// 闃蹭吉鐮佺敓鎴愯〃鍗� +const securityForm = reactive({ + productName: '', + productCode: '', + batchNo: '', + quantity: 10, + size: '256' +}) + +const securityRules = { + productName: [{ required: true, message: '璇疯緭鍏ヤ骇鍝佸悕绉�', trigger: 'blur' }], + productCode: [{ required: true, message: '璇疯緭鍏ヤ骇鍝佺紪鐮�', trigger: 'blur' }], + batchNo: [{ required: true, message: '璇疯緭鍏ユ壒娆″彿', trigger: 'blur' }], + quantity: [{ required: true, message: '璇疯緭鍏ョ敓鎴愭暟閲�', trigger: 'blur' }] +} + +// 鍝嶅簲寮忔暟鎹� +const formRef = ref() +const securityFormRef = ref() +const generating = ref(false) +const generatingSecurity = ref(false) +const qrCodeUrl = ref('') +const generateTime = ref('') +const securityDialogVisible = ref(false) +const securityResultVisible = ref(false) +const securityResults = ref([]) + +// 鐢熸垚浜岀淮鐮� +const generateQRCode = async () => { + try { + await formRef.value.validate() + + if (!form.content.trim()) { + ElMessage.warning('璇疯緭鍏ヨ鐢熸垚浜岀淮鐮佺殑鍐呭') + return + } + + generating.value = true + + qrCodeUrl.value = await QRCode.toDataURL(form.content, { + width: parseInt(form.size), + margin: 2, + color: { + dark: form.foregroundColor, + light: form.backgroundColor + }, + errorCorrectionLevel: 'M' + }) + + generateTime.value = new Date().toLocaleString() + ElMessage.success('浜岀淮鐮佺敓鎴愭垚鍔燂紒') + + } catch (error) { + console.error('鐢熸垚浜岀淮鐮佸け璐�:', error) + ElMessage.error('鐢熸垚浜岀淮鐮佸け璐ワ細' + error.message) + } finally { + generating.value = false + } +} + +// 涓嬭浇浜岀淮鐮� +const downloadQRCode = () => { + if (!qrCodeUrl.value) { + ElMessage.warning('璇峰厛鐢熸垚浜岀淮鐮�') + return + } + + const a = document.createElement('a') + a.href = qrCodeUrl.value + a.download = `浜岀淮鐮乢${new Date().getTime()}.png` + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + ElMessage.success('涓嬭浇鎴愬姛锛�') +} + +// 閲嶇疆琛ㄥ崟 +const resetForm = () => { + formRef.value.resetFields() + qrCodeUrl.value = '' + generateTime.value = '' +} + +// 鏄剧ず闃蹭吉鐮佸璇濇 +const showSecurityDialog = () => { + securityDialogVisible.value = true + // 閲嶇疆琛ㄥ崟 + Object.assign(securityForm, { + productName: '', + productCode: '', + batchNo: '', + quantity: 10, + size: '256' + }) +} + +// 鐢熸垚闃蹭吉鐮� +const generateSecurityCodes = async () => { + try { + await securityFormRef.value.validate() + + generatingSecurity.value = true + securityResults.value = [] + + for (let i = 1; i <= securityForm.quantity; i++) { + const timestamp = Date.now() + i // 纭繚姣忎釜鐮侀兘鏈変笉鍚岀殑鏃堕棿鎴� + const random = Math.random().toString(36).substr(2, 8) + const content = `SEC_${securityForm.productCode}_${securityForm.batchNo}_${timestamp}_${random}` + + const codeUrl = await QRCode.toDataURL(content, { + width: parseInt(securityForm.size), + margin: 2, + color: { + dark: '#000000', + light: '#FFFFFF' + }, + errorCorrectionLevel: 'H' // 鏈�楂樼籂閿欑骇鍒� + }) + + securityResults.value.push({ + content, + url: codeUrl, + productName: securityForm.productName, + productCode: securityForm.productCode, + batchNo: securityForm.batchNo, + generateTime: new Date().toLocaleString() + }) + } + + securityDialogVisible.value = false + securityResultVisible.value = true + ElMessage.success(`闃蹭吉鐮佺敓鎴愬畬鎴愶紝鍏辩敓鎴� ${securityForm.quantity} 涓猔) + + } catch (error) { + console.error('鐢熸垚闃蹭吉鐮佸け璐�:', error) + ElMessage.error('鐢熸垚闃蹭吉鐮佸け璐ワ細' + error.message) + } finally { + generatingSecurity.value = false + } +} + +// 涓嬭浇鍗曚釜闃蹭吉鐮� +const downloadSingleSecurityCode = (result) => { + const a = document.createElement('a') + a.href = result.url + a.download = `${result.content}.png` + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + ElMessage.success('涓嬭浇鎴愬姛锛�') +} + +// 涓嬭浇鎵�鏈夐槻浼爜 +const downloadAllSecurityCodes = async () => { + if (securityResults.value.length === 0) { + ElMessage.warning('娌℃湁鍙笅杞界殑闃蹭吉鐮�') + return + } + + try { + const zip = new JSZip() + + // 鍒涘缓璇存槑鏂囦欢 + const readme = `闃蹭吉鐮佺敓鎴愯鏄� +浜у搧鍚嶇О: ${securityForm.productName} +浜у搧缂栫爜: ${securityForm.productCode} +鎵规鍙�: ${securityForm.batchNo} +鏁伴噺: ${securityResults.value.length} +灏哄: ${securityForm.size}x${securityForm.size}px +鐢熸垚鏃堕棿: ${new Date().toLocaleString()} + +鏂囦欢鍒楄〃: +${securityResults.value.map((item, index) => `${index + 1}. ${item.content}.png`).join('\n')} +` + + zip.file('README.txt', readme) + + // 娣诲姞鍥剧墖鏂囦欢 + securityResults.value.forEach((result) => { + 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 = `闃蹭吉鐮乢${securityForm.productCode}_${securityForm.batchNo}_${new Date().getTime()}.zip` + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + URL.revokeObjectURL(a.href) + + ElMessage.success('鎵归噺涓嬭浇瀹屾垚锛�') + + } catch (error) { + console.error('鎵归噺涓嬭浇澶辫触:', error) + ElMessage.error('鎵归噺涓嬭浇澶辫触锛�' + error.message) + } +} +</script> + +<style scoped> +.app-container { + padding: 20px; +} + +.box-card { + margin-bottom: 20px; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.preview-container { + text-align: center; +} + +.qr-preview img { + max-width: 100%; + height: auto; + border: 2px solid #e0e0e0; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.qr-info { + margin-top: 20px; + text-align: left; + background: #f8f9fa; + padding: 15px; + border-radius: 8px; +} + +.qr-info p { + margin: 8px 0; + color: #666; +} + +.empty-preview { + padding: 40px 0; +} + +.security-info { + padding: 20px; + background: #f8f9fa; + border-radius: 8px; +} + +.security-info p { + font-weight: bold; + margin-bottom: 10px; +} + +.security-info ul { + margin: 0; + padding-left: 20px; +} + +.security-info li { + margin: 8px 0; + color: #666; +} + +.security-results { + padding: 20px; +} + +.results-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 1px solid #e0e0e0; +} + +.results-header p { + font-size: 16px; + font-weight: bold; + margin: 0; +} + +.results-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 20px; +} + +.result-item { + text-align: center; + padding: 15px; + border: 1px solid #e0e0e0; + border-radius: 8px; + background: #fff; +} + +.result-item img { + width: 100px; + height: 100px; + margin-bottom: 10px; +} + +.result-content { + font-size: 12px; + color: #666; + margin: 10px 0; + word-break: break-all; +} + +.dialog-footer { + text-align: right; +} +</style> -- Gitblit v1.9.3