From c7b4b9a2f4c0f05aeb60a9e3f5fba5d9a3676f3f Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 18 八月 2025 16:22:42 +0800
Subject: [PATCH] 中强恒兴设备管理页面添加

---
 src/components/QRCodeGenerator/index.vue |  541 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 541 insertions(+), 0 deletions(-)

diff --git a/src/components/QRCodeGenerator/index.vue b/src/components/QRCodeGenerator/index.vue
new file mode 100644
index 0000000..1708130
--- /dev/null
+++ b/src/components/QRCodeGenerator/index.vue
@@ -0,0 +1,541 @@
+<template>
+  <div class="qr-code-generator">
+    <!-- 浜岀淮鐮佺敓鎴愯〃鍗� -->
+    <el-form :model="form" :rules="rules" ref="formRef" label-width="120px" class="qr-form">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="鏍囪瘑绫诲瀷" prop="type">
+            <el-select v-model="form.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="content">
+            <el-input 
+              v-model="form.content" 
+              placeholder="璇疯緭鍏ヨ缂栫爜鐨勫唴瀹�"
+              :type="form.type === 'security' ? 'textarea' : 'text'"
+              :rows="form.type === 'security' ? 3 : 1"
+            ></el-input>
+          </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="form.size" 
+              :min="100" 
+              :max="500" 
+              :step="50"
+              style="width: 100%"
+            ></el-input-number>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="杈硅窛" prop="margin">
+            <el-input-number 
+              v-model="form.margin" 
+              :min="0" 
+              :max="10" 
+              :step="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="foregroundColor">
+            <el-color-picker v-model="form.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="form.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>
+            <el-button type="primary" @click="generateCode" :loading="generating">
+              鐢熸垚{{ form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�' }}
+            </el-button>
+            <el-button @click="resetForm">閲嶇疆</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <!-- 鐢熸垚鐨勭爜鏄剧ず鍖哄煙 -->
+    <div v-if="generatedCodeUrl" class="code-display">
+      <el-divider content-position="center">
+        {{ form.type === 'qrcode' ? '鐢熸垚鐨勪簩缁寸爜' : '鐢熸垚鐨勯槻浼爜' }}
+      </el-divider>
+      
+      <div class="code-container">
+        <div class="code-image">
+          <img :src="generatedCodeUrl" :alt="form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'" />
+        </div>
+        
+        <div class="code-info">
+          <p><strong>鍐呭锛�</strong>{{ form.content }}</p>
+          <p><strong>绫诲瀷锛�</strong>{{ form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�' }}</p>
+          <p><strong>灏哄锛�</strong>{{ form.size }}x{{ form.size }}px</p>
+          <p><strong>鐢熸垚鏃堕棿锛�</strong>{{ generateTime }}</p>
+        </div>
+      </div>
+      
+      <div class="code-actions">
+        <el-button type="success" @click="downloadCode" icon="Download">
+          涓嬭浇鍥剧墖
+        </el-button>
+        <el-button type="primary" @click="copyToClipboard" icon="CopyDocument">
+          澶嶅埗鍐呭
+        </el-button>
+        <el-button @click="printCode" icon="Printer">
+          鎵撳嵃
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 鎵归噺鐢熸垚瀵硅瘽妗� -->
+    <el-dialog v-model="batchDialogVisible" title="鎵归噺鐢熸垚" width="600px">
+      <el-form :model="batchForm" label-width="120px">
+        <el-form-item label="鐢熸垚鏁伴噺">
+          <el-input-number v-model="batchForm.quantity" :min="1" :max="100" style="width: 100%"></el-input-number>
+        </el-form-item>
+        <el-form-item label="鍓嶇紑">
+          <el-input v-model="batchForm.prefix" placeholder="璇疯緭鍏ュ墠缂�锛屽锛歅ROD_"></el-input>
+        </el-form-item>
+        <el-form-item label="璧峰缂栧彿">
+          <el-input-number v-model="batchForm.startNumber" :min="1" style="width: 100%"></el-input-number>
+        </el-form-item>
+      </el-form>
+      
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="batchDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary" @click="generateBatchCodes">寮�濮嬬敓鎴�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 鎵归噺鐢熸垚缁撴灉 -->
+    <div v-if="batchCodes.length > 0" class="batch-results">
+      <el-divider content-position="center">鎵归噺鐢熸垚缁撴灉</el-divider>
+      
+      <div class="batch-grid">
+        <div 
+          v-for="(code, index) in batchCodes" 
+          :key="index" 
+          class="batch-item"
+        >
+          <img :src="code.url" :alt="code.content" />
+          <p class="batch-content">{{ code.content }}</p>
+          <el-button size="small" @click="downloadSingleCode(code)">涓嬭浇</el-button>
+        </div>
+      </div>
+      
+      <div class="batch-actions">
+        <el-button type="success" @click="downloadAllCodes">涓嬭浇鍏ㄩ儴</el-button>
+        <el-button @click="clearBatchCodes">娓呯┖缁撴灉</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from 'vue'
+import QRCode from 'qrcode'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Download, CopyDocument, Printer } from '@element-plus/icons-vue'
+
+// 瀹氫箟缁勪欢鍚嶇О
+defineOptions({
+  name: 'QRCodeGenerator'
+})
+
+// 琛ㄥ崟鏁版嵁
+const form = reactive({
+  type: 'qrcode',
+  content: '',
+  size: 200,
+  margin: 2,
+  foregroundColor: '#000000',
+  backgroundColor: '#FFFFFF'
+})
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = {
+  type: [{ required: true, message: '璇烽�夋嫨鏍囪瘑绫诲瀷', trigger: 'change' }],
+  content: [{ required: true, message: '璇疯緭鍏ュ唴瀹�', trigger: 'blur' }]
+}
+
+// 鍝嶅簲寮忔暟鎹�
+const formRef = ref()
+const generating = ref(false)
+const generatedCodeUrl = ref('')
+const generateTime = ref('')
+const batchDialogVisible = ref(false)
+const batchForm = reactive({
+  quantity: 10,
+  prefix: '',
+  startNumber: 1
+})
+const batchCodes = ref([])
+
+// 鐢熸垚浜岀淮鐮佹垨闃蹭吉鐮�
+const generateCode = async () => {
+  try {
+    await formRef.value.validate()
+    
+    if (!form.content.trim()) {
+      ElMessage.warning('璇疯緭鍏ヨ缂栫爜鐨勫唴瀹�')
+      return
+    }
+    
+    generating.value = true
+    
+    if (form.type === 'qrcode') {
+      // 鐢熸垚浜岀淮鐮�
+      generatedCodeUrl.value = await QRCode.toDataURL(form.content, {
+        width: form.size,
+        margin: form.margin,
+        color: {
+          dark: form.foregroundColor,
+          light: form.backgroundColor
+        },
+        errorCorrectionLevel: 'M'
+      })
+    } else {
+      // 鐢熸垚闃蹭吉鐮侊紙浣跨敤浜岀淮鐮佹妧鏈紝浣嗗唴瀹规牸寮忎笉鍚岋級
+      const securityContent = generateSecurityCode(form.content)
+      generatedCodeUrl.value = await QRCode.toDataURL(securityContent, {
+        width: form.size,
+        margin: form.margin,
+        color: {
+          dark: form.foregroundColor,
+          light: form.backgroundColor
+        },
+        errorCorrectionLevel: 'H' // 闃蹭吉鐮佷娇鐢ㄦ渶楂樼籂閿欑骇鍒�
+      })
+    }
+    
+    generateTime.value = new Date().toLocaleString()
+    ElMessage.success('鐢熸垚鎴愬姛锛�')
+    
+  } catch (error) {
+    console.error('鐢熸垚澶辫触:', error)
+    ElMessage.error('鐢熸垚澶辫触锛�' + error.message)
+  } finally {
+    generating.value = false
+  }
+}
+
+// 鐢熸垚闃蹭吉鐮佸唴瀹�
+const generateSecurityCode = (content) => {
+  const timestamp = Date.now()
+  const random = Math.random().toString(36).substr(2, 8)
+  return `SEC_${content}_${timestamp}_${random}`
+}
+
+// 涓嬭浇鐢熸垚鐨勭爜
+const downloadCode = () => {
+  if (!generatedCodeUrl.value) {
+    ElMessage.warning('璇峰厛鐢熸垚鐮�')
+    return
+  }
+  
+  const a = document.createElement('a')
+  a.href = generatedCodeUrl.value
+  a.download = `${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}_${new Date().getTime()}.png`
+  document.body.appendChild(a)
+  a.click()
+  document.body.removeChild(a)
+  ElMessage.success('涓嬭浇鎴愬姛锛�')
+}
+
+// 澶嶅埗鍐呭鍒板壀璐存澘
+const copyToClipboard = async () => {
+  try {
+    await navigator.clipboard.writeText(form.content)
+    ElMessage.success('鍐呭宸插鍒跺埌鍓创鏉�')
+  } catch (error) {
+    // 闄嶇骇鏂规
+    const textArea = document.createElement('textarea')
+    textArea.value = form.content
+    document.body.appendChild(textArea)
+    textArea.select()
+    document.execCommand('copy')
+    document.body.removeChild(textArea)
+    ElMessage.success('鍐呭宸插鍒跺埌鍓创鏉�')
+  }
+}
+
+// 鎵撳嵃鐮�
+const printCode = () => {
+  if (!generatedCodeUrl.value) {
+    ElMessage.warning('璇峰厛鐢熸垚鐮�')
+    return
+  }
+  
+  const printWindow = window.open('', '_blank')
+  printWindow.document.write(`
+    <html>
+      <head>
+        <title>鎵撳嵃${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}</title>
+        <style>
+          body { text-align: center; padding: 20px; }
+          img { max-width: 100%; height: auto; }
+          .info { margin: 20px 0; }
+        </style>
+      </head>
+      <body>
+        <h2>${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}</h2>
+        <img src="${generatedCodeUrl.value}" alt="${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}" />
+        <div class="info">
+          <p><strong>鍐呭锛�</strong>${form.content}</p>
+          <p><strong>鐢熸垚鏃堕棿锛�</strong>${generateTime.value}</p>
+        </div>
+      </body>
+    </html>
+  `)
+  printWindow.document.close()
+  printWindow.print()
+}
+
+// 閲嶇疆琛ㄥ崟
+const resetForm = () => {
+  formRef.value.resetFields()
+  generatedCodeUrl.value = ''
+  generateTime.value = ''
+  batchCodes.value = []
+}
+
+// 鎵归噺鐢熸垚
+const generateBatchCodes = async () => {
+  if (!batchForm.prefix.trim()) {
+    ElMessage.warning('璇疯緭鍏ュ墠缂�')
+    return
+  }
+  
+  batchCodes.value = []
+  generating.value = true
+  
+  try {
+    for (let i = 0; i < batchForm.quantity; i++) {
+      const number = batchForm.startNumber + i
+      const content = `${batchForm.prefix}${number.toString().padStart(6, '0')}`
+      
+      let codeUrl
+      if (form.type === 'qrcode') {
+        codeUrl = await QRCode.toDataURL(content, {
+          width: form.size,
+          margin: form.margin,
+          color: {
+            dark: form.foregroundColor,
+            light: form.backgroundColor
+          }
+        })
+      } else {
+        const securityContent = generateSecurityCode(content)
+        codeUrl = await QRCode.toDataURL(securityContent, {
+          width: form.size,
+          margin: form.margin,
+          color: {
+            dark: form.foregroundColor,
+            light: form.backgroundColor
+          }
+        })
+      }
+      
+      batchCodes.value.push({
+        content,
+        url: codeUrl
+      })
+    }
+    
+    ElMessage.success(`鎵归噺鐢熸垚瀹屾垚锛屽叡鐢熸垚 ${batchForm.quantity} 涓爜`)
+    batchDialogVisible.value = false
+    
+  } catch (error) {
+    console.error('鎵归噺鐢熸垚澶辫触:', error)
+    ElMessage.error('鎵归噺鐢熸垚澶辫触锛�' + error.message)
+  } finally {
+    generating.value = false
+  }
+}
+
+// 涓嬭浇鍗曚釜鎵归噺鐢熸垚鐨勭爜
+const downloadSingleCode = (code) => {
+  const a = document.createElement('a')
+  a.href = code.url
+  a.download = `${code.content}.png`
+  document.body.appendChild(a)
+  a.click()
+  document.body.removeChild(a)
+}
+
+// 涓嬭浇鎵�鏈夋壒閲忕敓鎴愮殑鐮�
+const downloadAllCodes = async () => {
+  if (batchCodes.value.length === 0) {
+    ElMessage.warning('娌℃湁鍙笅杞界殑鐮�')
+    return
+  }
+  
+  try {
+    // 浣跨敤JSZip鎵撳寘涓嬭浇
+    const JSZip = await import('jszip')
+    const zip = new JSZip.default()
+    
+    batchCodes.value.forEach((code, index) => {
+      // 灏哹ase64杞崲涓篵lob
+      const base64Data = code.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(`${code.content}.png`, byteArray)
+    })
+    
+    const content = await zip.generateAsync({ type: 'blob' })
+    const a = document.createElement('a')
+    a.href = URL.createObjectURL(content)
+    a.download = `鎵归噺${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}_${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('鎵归噺涓嬭浇澶辫触锛岃閫愪釜涓嬭浇')
+  }
+}
+
+// 娓呯┖鎵归噺鐢熸垚缁撴灉
+const clearBatchCodes = () => {
+  batchCodes.value = []
+}
+
+// 鏆撮湶鏂规硶缁欑埗缁勪欢
+defineExpose({
+  generateCode,
+  downloadCode,
+  resetForm,
+  form
+})
+</script>
+
+<style scoped>
+.qr-code-generator {
+  padding: 20px;
+}
+
+.qr-form {
+  background: #f8f9fa;
+  padding: 20px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+}
+
+.code-display {
+  margin-top: 30px;
+}
+
+.code-container {
+  display: flex;
+  justify-content: center;
+  align-items: flex-start;
+  gap: 40px;
+  margin: 20px 0;
+}
+
+.code-image img {
+  border: 2px solid #e0e0e0;
+  border-radius: 8px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+}
+
+.code-info {
+  text-align: left;
+  min-width: 200px;
+}
+
+.code-info p {
+  margin: 8px 0;
+  color: #666;
+}
+
+.code-actions {
+  text-align: center;
+  margin: 20px 0;
+}
+
+.code-actions .el-button {
+  margin: 0 10px;
+}
+
+.batch-results {
+  margin-top: 30px;
+}
+
+.batch-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+  gap: 20px;
+  margin: 20px 0;
+}
+
+.batch-item {
+  text-align: center;
+  padding: 15px;
+  border: 1px solid #e0e0e0;
+  border-radius: 8px;
+  background: #fff;
+}
+
+.batch-item img {
+  width: 100px;
+  height: 100px;
+  margin-bottom: 10px;
+}
+
+.batch-content {
+  font-size: 12px;
+  color: #666;
+  margin: 10px 0;
+  word-break: break-all;
+}
+
+.batch-actions {
+  text-align: center;
+  margin: 20px 0;
+}
+
+.batch-actions .el-button {
+  margin: 0 10px;
+}
+
+@media (max-width: 768px) {
+  .code-container {
+    flex-direction: column;
+    align-items: center;
+  }
+  
+  .batch-grid {
+    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+  }
+}
+</style>

--
Gitblit v1.9.3