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/productManagement/productIdentifier/index.vue |  708 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 708 insertions(+), 0 deletions(-)

diff --git a/src/views/productManagement/productIdentifier/index.vue b/src/views/productManagement/productIdentifier/index.vue
new file mode 100644
index 0000000..59d8f90
--- /dev/null
+++ b/src/views/productManagement/productIdentifier/index.vue
@@ -0,0 +1,708 @@
+<template>
+  <div class="app-container">
+    <el-card class="box-card">
+             <!-- 鎼滅储鍖哄煙 -->
+       <el-row :gutter="20" class="search-row">
+         <el-col :span="6">
+           <el-input
+             v-model="searchForm.productName"
+             placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
+             clearable
+             @keyup.enter="handleSearch"
+           >
+             <template #prefix>
+               <el-icon><Search /></el-icon>
+             </template>
+           </el-input>
+         </el-col>
+         <el-col :span="6">
+           <el-select v-model="searchForm.identifierType" placeholder="璇烽�夋嫨鏍囪瘑绫诲瀷" clearable>
+             <el-option label="浜岀淮鐮�" value="浜岀淮鐮�"></el-option>
+             <el-option label="闃蹭吉鐮�" value="闃蹭吉鐮�"></el-option>
+           </el-select>
+         </el-col>
+         <el-col :span="6">
+           <el-select v-model="searchForm.status" placeholder="璇烽�夋嫨鐘舵��" clearable>
+             <el-option label="宸茬敓鎴�" value="宸茬敓鎴�"></el-option>
+             <el-option label="宸插垎閰�" value="宸插垎閰�"></el-option>
+             <el-option label="宸蹭娇鐢�" value="宸蹭娇鐢�"></el-option>
+             <el-option label="宸蹭綔搴�" value="宸蹭綔搴�"></el-option>
+           </el-select>
+         </el-col>
+         <el-col :span="6">
+           <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+           <el-button @click="resetSearch">閲嶇疆</el-button>
+           <el-button style="float: right;" type="primary" @click="handleAdd">
+             鏂板鏍囪瘑
+           </el-button>
+         </el-col>
+       </el-row>
+
+      <!-- 浜у搧鏍囪瘑鍒楄〃 -->
+      <el-table
+        :data="filteredList"
+        style="width: 100%"
+        v-loading="loading"
+        border
+        stripe
+        height="calc(100vh - 22em)"
+      >
+        <el-table-column prop="id" label="ID" width="80" align="center"/>
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" width="150" />
+        <el-table-column prop="productCode" label="浜у搧缂栫爜" width="120" />
+        <el-table-column prop="batchNo" label="鎵规鍙�" width="120" />
+        <el-table-column prop="identifierType" label="鏍囪瘑绫诲瀷" width="100">
+          <template #default="scope">
+            <el-tag :type="getIdentifierTypeType(scope.row.identifierType)">
+              {{ scope.row.identifierType }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="identifierCode" label="鏍囪瘑鐮�" />
+        <el-table-column prop="status" label="鐘舵��" width="100">
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ scope.row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="generateTime" label="鐢熸垚鏃堕棿" width="160" />
+        <el-table-column label="鎿嶄綔" fixed="right" align="center" width="280">
+          <template #default="scope">
+            <el-button link type="primary" @click="handleView(scope.row)">鏌ョ湅</el-button>
+            <el-button link type="primary" @click="handleEdit(scope.row)">缂栬緫</el-button>
+            <el-button link type="success" @click="generateQRCode(scope.row)">鐢熸垚浜岀淮鐮�</el-button>
+            <el-button link type="primary" @click="handleExport(scope.row)">瀵煎嚭</el-button>
+            <el-button link type="primary" @click="handleReassign(scope.row)" v-if="scope.row.status === '宸插垎閰�'">閲嶆柊鍒嗛厤</el-button>
+            <el-button link type="danger" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 鍒嗛〉 -->
+      <pagination
+        :total="pagination.total"
+        layout="total, sizes, prev, pager, next, jumper"
+        :page="pagination.currentPage"
+        :limit="pagination.pageSize"
+        @pagination="handleCurrentChange"
+      />
+    </el-card>
+
+    <!-- 鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="700px">
+      <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浜у搧鍚嶇О" prop="productName">
+              <el-input v-model="form.productName" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浜у搧缂栫爜" prop="productCode">
+              <el-input v-model="form.productCode" placeholder="璇疯緭鍏ヤ骇鍝佺紪鐮�"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鎵规鍙�" prop="batchNo">
+              <el-input v-model="form.batchNo" placeholder="璇疯緭鍏ユ壒娆″彿"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏍囪瘑绫诲瀷" prop="identifierType">
+              <el-select v-model="form.identifierType" placeholder="璇烽�夋嫨鏍囪瘑绫诲瀷" style="width: 100%">
+                <el-option label="浜岀淮鐮�" value="浜岀淮鐮�"></el-option>
+                <el-option label="闃蹭吉鐮�" value="闃蹭吉鐮�"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鐢熸垚鏁伴噺" prop="quantity">
+              <el-input-number v-model="form.quantity" :min="1" :max="10000" style="width: 100%"></el-input-number>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵��" prop="status">
+              <el-select v-model="form.status" placeholder="璇烽�夋嫨鐘舵��" style="width: 100%">
+                <el-option label="宸茬敓鎴�" value="宸茬敓鎴�"></el-option>
+                <el-option label="宸插垎閰�" value="宸插垎閰�"></el-option>
+                <el-option label="宸蹭娇鐢�" value="宸蹭娇鐢�"></el-option>
+                <el-option label="宸蹭綔搴�" value="宸蹭綔搴�"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞" prop="remark">
+              <el-input type="textarea" v-model="form.remark" placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�" rows="3"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="handleSubmit">纭� 瀹�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 鏍囪瘑鐢熸垚瀵硅瘽妗� -->
+    <el-dialog v-model="generateDialogVisible" title="鏍囪瘑鐢熸垚" width="500px">
+      <el-form label-width="100px">
+        <el-form-item label="浜у搧鍚嶇О">
+          <span>{{ currentProduct.productName }}</span>
+        </el-form-item>
+        <el-form-item label="浜у搧缂栫爜">
+          <span>{{ currentProduct.productCode }}</span>
+        </el-form-item>
+        <el-form-item label="鎵规鍙�">
+          <span>{{ currentProduct.batchNo }}</span>
+        </el-form-item>
+        <el-form-item label="鏍囪瘑绫诲瀷">
+          <span>{{ currentProduct.identifierType }}</span>
+        </el-form-item>
+        <el-form-item label="鐢熸垚鏁伴噺" prop="generateQuantity">
+          <el-input-number v-model="generateQuantity" :min="1" :max="10000" style="width: 100%"></el-input-number>
+        </el-form-item>
+        <el-form-item label="缂栫爜瑙勫垯" prop="codeRule">
+          <el-select v-model="codeRule" placeholder="璇烽�夋嫨缂栫爜瑙勫垯" style="width: 100%">
+            <el-option label="浜у搧缂栫爜+鎵规鍙�+搴忓彿" value="浜у搧缂栫爜+鎵规鍙�+搴忓彿"></el-option>
+            <el-option label="鏃堕棿鎴�+闅忔満鏁�" value="鏃堕棿鎴�+闅忔満鏁�"></el-option>
+            <el-option label="鑷畾涔夎鍒�" value="鑷畾涔夎鍒�"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鑷畾涔夊墠缂�" prop="customPrefix" v-if="codeRule === '鑷畾涔夎鍒�'">
+          <el-input v-model="customPrefix" placeholder="璇疯緭鍏ヨ嚜瀹氫箟鍓嶇紑"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="generateDialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="generateIdentifiers">鐢� 鎴�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 閲嶆柊鍒嗛厤瀵硅瘽妗� -->
+    <el-dialog v-model="reassignDialogVisible" title="閲嶆柊鍒嗛厤鏍囪瘑" width="500px">
+      <el-form label-width="100px">
+        <el-form-item label="浜у搧鍚嶇О">
+          <span>{{ currentProduct.productName }}</span>
+        </el-form-item>
+        <el-form-item label="鏍囪瘑鐮�">
+          <span>{{ currentProduct.identifierCode }}</span>
+        </el-form-item>
+        <el-form-item label="鏂版壒娆″彿" prop="newBatchNo">
+          <el-input v-model="newBatchNo" placeholder="璇疯緭鍏ユ柊鎵规鍙�"></el-input>
+        </el-form-item>
+        <el-form-item label="鍒嗛厤鍘熷洜" prop="reassignReason">
+          <el-input type="textarea" v-model="reassignReason" rows="3" placeholder="璇疯緭鍏ラ噸鏂板垎閰嶅師鍥�"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="reassignDialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="saveReassign">纭� 瀹�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 浜岀淮鐮侀瑙堝璇濇 -->
+    <el-dialog v-model="qrCodeDialogVisible" title="浜岀淮鐮侀瑙�" width="500px" center>
+      <div class="qr-preview-container">
+        <div v-if="qrCodeUrl" class="qr-image-container">
+          <img :src="qrCodeUrl" alt="浜岀淮鐮�" class="qr-image" />
+          <div class="qr-info">
+            <p><strong>浜у搧鍚嶇О锛�</strong>{{ currentQRProduct.productName }}</p>
+            <p><strong>浜у搧缂栫爜锛�</strong>{{ currentQRProduct.productCode }}</p>
+            <p><strong>鎵规鍙凤細</strong>{{ currentQRProduct.batchNo }}</p>
+            <p><strong>鏍囪瘑鐮侊細</strong>{{ currentQRProduct.identifierCode }}</p>
+            <p><strong>鏍囪瘑绫诲瀷锛�</strong>{{ currentQRProduct.identifierType }}</p>
+          </div>
+        </div>
+        <div v-else class="qr-loading">
+          <el-icon class="is-loading"><Loading /></el-icon>
+          <p>姝e湪鐢熸垚浜岀淮鐮�...</p>
+        </div>
+      </div>
+      
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="qrCodeDialogVisible = false">鍏抽棴</el-button>
+          <el-button 
+            v-if="qrCodeUrl" 
+            type="primary" 
+            @click="copyQRContent" 
+            icon="CopyDocument"
+          >
+            澶嶅埗鍐呭
+          </el-button>
+          <el-button 
+            v-if="qrCodeUrl" 
+            type="success" 
+            @click="downloadQRCode" 
+            icon="Download"
+          >
+            涓嬭浇浜岀淮鐮�
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus, Search, Loading, Download } from '@element-plus/icons-vue'
+import Pagination from '@/components/PIMTable/Pagination.vue'
+import QRCode from 'qrcode'
+
+// 鍝嶅簲寮忔暟鎹�
+const loading = ref(false)
+const searchForm = reactive({
+  productName: '',
+  identifierType: '',
+  status: ''
+})
+
+const identifierList = ref([
+  {
+    id: 1,
+    productName: '宸ヤ笟浼犳劅鍣ˋ鍨�',
+    productCode: 'SENSOR001',
+    batchNo: 'B202312001',
+    identifierType: '浜岀淮鐮�',
+    identifierCode: 'QR_SENSOR001_B202312001_001',
+    status: '宸插垎閰�',
+    generateTime: '2023-12-01 10:00:00',
+    remark: '閲嶈浜у搧鏍囪瘑'
+  },
+  {
+    id: 2,
+    productName: '鎺у埗闈㈡澘B鍨�',
+    productCode: 'PANEL002',
+    batchNo: 'B202312002',
+    identifierType: '闃蹭吉鐮�',
+    identifierCode: 'SEC_PANEL002_B202312002_001',
+    status: '宸茬敓鎴�',
+    generateTime: '2023-12-02 14:30:00',
+    remark: '甯歌浜у搧鏍囪瘑'
+  },
+  {
+    id: 3,
+    productName: '鏁版嵁閲囬泦鍣–鍨�',
+    productCode: 'COLLECTOR003',
+    batchNo: 'B202312003',
+    identifierType: '闃蹭吉鐮�',
+    identifierCode: 'SEC_COLLECTOR003_B202312003_001',
+    status: '宸蹭娇鐢�',
+    generateTime: '2023-12-03 09:15:00',
+    remark: '娴嬭瘯浜у搧鏍囪瘑'
+  }
+])
+
+const pagination = reactive({
+  total: 3,
+  currentPage: 1,
+  pageSize: 10
+})
+
+const dialogVisible = ref(false)
+const dialogTitle = ref('鏂板鏍囪瘑')
+const form = reactive({
+  productName: '',
+  productCode: '',
+  batchNo: '',
+  identifierType: '',
+  quantity: 1,
+  status: '宸茬敓鎴�',
+  remark: ''
+})
+
+const rules = {
+  productName: [{ required: true, message: '璇疯緭鍏ヤ骇鍝佸悕绉�', trigger: 'blur' }],
+  productCode: [{ required: true, message: '璇疯緭鍏ヤ骇鍝佺紪鐮�', trigger: 'blur' }],
+  batchNo: [{ required: true, message: '璇疯緭鍏ユ壒娆″彿', trigger: 'blur' }],
+  identifierType: [{ required: true, message: '璇烽�夋嫨鏍囪瘑绫诲瀷', trigger: 'change' }],
+  quantity: [{ required: true, message: '璇疯緭鍏ョ敓鎴愭暟閲�', trigger: 'blur' }],
+  status: [{ required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change' }]
+}
+
+const isEdit = ref(false)
+const editId = ref(null)
+const generateDialogVisible = ref(false)
+const reassignDialogVisible = ref(false)
+const currentProduct = ref({})
+const generateQuantity = ref(1)
+const codeRule = ref('')
+const customPrefix = ref('')
+const newBatchNo = ref('')
+const reassignReason = ref('')
+const formRef = ref()
+
+// 浜岀淮鐮佺浉鍏冲彉閲�
+const qrCodeDialogVisible = ref(false)
+const qrCodeUrl = ref('')
+const currentQRProduct = ref({})
+
+// 璁$畻灞炴��
+const filteredList = computed(() => {
+  let list = identifierList.value
+  if (searchForm.productName) {
+    list = list.filter(item => item.productName.includes(searchForm.productName))
+  }
+  if (searchForm.identifierType) {
+    list = list.filter(item => item.identifierType === searchForm.identifierType)
+  }
+  if (searchForm.status) {
+    list = list.filter(item => item.status === searchForm.status)
+  }
+  return list
+})
+
+// 鏂规硶
+const getIdentifierTypeType = (type) => {
+  const typeMap = {
+    '浜岀淮鐮�': 'success',
+    '闃蹭吉鐮�': 'warning'
+  }
+  return typeMap[type] || 'info'
+}
+
+const getStatusType = (status) => {
+  const statusMap = {
+    '宸茬敓鎴�': 'info',
+    '宸插垎閰�': 'primary',
+    '宸蹭娇鐢�': 'success',
+    '宸蹭綔搴�': 'danger'
+  }
+  return statusMap[status] || 'info'
+}
+
+const handleSearch = () => {
+  // 鎼滅储閫昏緫宸插湪computed涓鐞�
+}
+
+const resetSearch = () => {
+  searchForm.productName = ''
+  searchForm.identifierType = ''
+  searchForm.status = ''
+}
+
+const handleAdd = () => {
+  dialogTitle.value = '鏂板鏍囪瘑'
+  isEdit.value = false
+  form.productName = ''
+  form.productCode = ''
+  form.batchNo = ''
+  form.identifierType = ''
+  form.quantity = 1
+  form.status = '宸茬敓鎴�'
+  form.remark = ''
+  dialogVisible.value = true
+}
+
+const handleView = (row) => {
+  // 鏌ョ湅鏍囪瘑璇︽儏
+  ElMessage.info('鏌ョ湅鏍囪瘑璇︽儏鍔熻兘寰呭疄鐜�')
+}
+
+const handleEdit = (row) => {
+  dialogTitle.value = '缂栬緫鏍囪瘑'
+  isEdit.value = true
+  editId.value = row.id
+  Object.assign(form, row)
+  dialogVisible.value = true
+}
+
+const handleExport = (row) => {
+  // 瀵煎嚭鏍囪瘑
+  ElMessage.success(`宸插鍑烘爣璇�: ${row.identifierCode}`)
+}
+
+const handleReassign = (row) => {
+  currentProduct.value = row
+  newBatchNo.value = ''
+  reassignReason.value = ''
+  reassignDialogVisible.value = true
+}
+
+const handleDelete = (row) => {
+  ElMessageBox.confirm('纭鍒犻櫎璇ユ爣璇嗗悧锛�', '鎻愮ず', {
+    confirmButtonText: '纭畾',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning'
+  }).then(() => {
+    const index = identifierList.value.findIndex(item => item.id === row.id)
+    if (index > -1) {
+      identifierList.value.splice(index, 1)
+      pagination.total--
+      ElMessage.success('鍒犻櫎鎴愬姛')
+    }
+  })
+}
+
+// 鐢熸垚浜岀淮鐮�
+const generateQRCode = async (row) => {
+  try {
+    // 妫�鏌ュ繀瑕佸瓧娈�
+    if (!row.productName || !row.productCode || !row.batchNo) {
+      ElMessage.warning('浜у搧淇℃伅涓嶅畬鏁达紝鏃犳硶鐢熸垚浜岀淮鐮�')
+      return
+    }
+    
+    currentQRProduct.value = row
+    qrCodeUrl.value = ''
+    qrCodeDialogVisible.value = true
+    
+    // 鏋勫缓浜岀淮鐮佸唴瀹�
+    let qrContent = ''
+    if (row.identifierType === '浜岀淮鐮�') {
+      qrContent = `${row.productName}|${row.productCode}|${row.batchNo}|${row.identifierCode}`
+    } else if (row.identifierType === '闃蹭吉鐮�') {
+      // 闃蹭吉鐮佹牸寮忥細SEC_浜у搧缂栫爜_鎵规鍙穇鏃堕棿鎴砡闅忔満鏁�
+      const timestamp = Date.now()
+      const random = Math.random().toString(36).substr(2, 8)
+      qrContent = `SEC_${row.productCode}_${row.batchNo}_${timestamp}_${random}`
+    }
+    
+    // 鐢熸垚浜岀淮鐮�
+    qrCodeUrl.value = await QRCode.toDataURL(qrContent, {
+      width: 256,
+      margin: 2,
+      color: {
+        dark: '#000000',
+        light: '#FFFFFF'
+      },
+      errorCorrectionLevel: row.identifierType === '闃蹭吉鐮�' ? 'H' : 'M'
+    })
+    
+    ElMessage.success('浜岀淮鐮佺敓鎴愭垚鍔燂紒')
+    
+  } catch (error) {
+    console.error('鐢熸垚浜岀淮鐮佸け璐�:', error)
+    ElMessage.error('鐢熸垚浜岀淮鐮佸け璐ワ細' + error.message)
+    qrCodeDialogVisible.value = false
+  }
+}
+
+// 涓嬭浇浜岀淮鐮�
+const downloadQRCode = () => {
+  if (!qrCodeUrl.value) {
+    ElMessage.warning('璇峰厛鐢熸垚浜岀淮鐮�')
+    return
+  }
+  
+  const a = document.createElement('a')
+  a.href = qrCodeUrl.value
+  a.download = `${currentQRProduct.value.productName}_${currentQRProduct.value.identifierType}_${new Date().getTime()}.png`
+  document.body.appendChild(a)
+  a.click()
+  document.body.removeChild(a)
+  ElMessage.success('涓嬭浇鎴愬姛锛�')
+}
+
+// 澶嶅埗浜岀淮鐮佸唴瀹�
+const copyQRContent = async () => {
+  if (!currentQRProduct.value) {
+    ElMessage.warning('娌℃湁鍙鍒剁殑鍐呭')
+    return
+  }
+  
+  try {
+    let content = ''
+    if (currentQRProduct.value.identifierType === '浜岀淮鐮�') {
+      content = `${currentQRProduct.value.productName}|${currentQRProduct.value.productCode}|${currentQRProduct.value.batchNo}|${currentQRProduct.value.identifierCode}`
+    } else if (currentQRProduct.value.identifierType === '闃蹭吉鐮�') {
+      const timestamp = Date.now()
+      const random = Math.random().toString(36).substr(2, 8)
+      content = `SEC_${currentQRProduct.value.productCode}_${currentQRProduct.value.batchNo}_${timestamp}_${random}`
+    }
+    
+    await navigator.clipboard.writeText(content)
+    ElMessage.success('鍐呭宸插鍒跺埌鍓创鏉�')
+  } catch (error) {
+    // 闄嶇骇鏂规
+    const textArea = document.createElement('textarea')
+    textArea.value = content
+    document.body.appendChild(textArea)
+    textArea.select()
+    document.execCommand('copy')
+    document.body.removeChild(textArea)
+    ElMessage.success('鍐呭宸插鍒跺埌鍓创鏉�')
+  }
+}
+
+const generateIdentifiers = () => {
+  if (!codeRule.value) {
+    ElMessage.warning('璇烽�夋嫨缂栫爜瑙勫垯')
+    return
+  }
+  
+  // 鐢熸垚鏍囪瘑鐨勯�昏緫
+  const newIdentifiers = []
+  for (let i = 1; i <= generateQuantity.value; i++) {
+    let identifierCode = ''
+    if (codeRule.value === '浜у搧缂栫爜+鎵规鍙�+搴忓彿') {
+      identifierCode = `${currentProduct.value.productCode}_${currentProduct.value.batchNo}_${String(i).padStart(3, '0')}`
+    } else if (codeRule.value === '鏃堕棿鎴�+闅忔満鏁�') {
+      identifierCode = `TS_${Date.now()}_${Math.floor(Math.random() * 1000)}`
+    } else if (codeRule.value === '鑷畾涔夎鍒�') {
+      identifierCode = `${customPrefix.value || 'CUSTOM'}_${Date.now()}_${i}`
+    }
+    
+    newIdentifiers.push({
+      id: Math.max(...identifierList.value.map(item => item.id)) + i,
+      productName: currentProduct.value.productName,
+      productCode: currentProduct.value.productCode,
+      batchNo: currentProduct.value.batchNo,
+      identifierType: currentProduct.value.identifierType,
+      identifierCode: identifierCode,
+      status: '宸茬敓鎴�',
+      generateTime: new Date().toLocaleString(),
+      remark: '鎵归噺鐢熸垚'
+    })
+  }
+  
+  identifierList.value.push(...newIdentifiers)
+  pagination.total += newIdentifiers.length
+  ElMessage.success(`鎴愬姛鐢熸垚 ${newIdentifiers.length} 涓爣璇哷)
+  generateDialogVisible.value = false
+}
+
+const saveReassign = () => {
+  if (!newBatchNo.value) {
+    ElMessage.warning('璇疯緭鍏ユ柊鎵规鍙�')
+    return
+  }
+  
+  const index = identifierList.value.findIndex(item => item.id === currentProduct.value.id)
+  if (index > -1) {
+    identifierList.value[index].batchNo = newBatchNo.value
+    identifierList.value[index].status = '宸插垎閰�'
+    ElMessage.success('鏍囪瘑閲嶆柊鍒嗛厤鎴愬姛')
+    reassignDialogVisible.value = false
+  }
+}
+
+const handleSubmit = () => {
+  formRef.value.validate((valid) => {
+    if (valid) {
+      if (isEdit.value) {
+        // 缂栬緫
+        const index = identifierList.value.findIndex(item => item.id === editId.value)
+        if (index > -1) {
+          identifierList.value[index] = { ...form, id: editId.value }
+          ElMessage.success('缂栬緫鎴愬姛')
+        }
+             } else {
+         // 鏂板
+         const newId = Math.max(...identifierList.value.map(item => item.id)) + 1
+         
+         // 鏍规嵁鏍囪瘑绫诲瀷鐢熸垚涓嶅悓鐨勬爣璇嗙爜
+         let identifierCode = ''
+         if (form.identifierType === '浜岀淮鐮�') {
+           identifierCode = `QR_${form.productCode}_${form.batchNo}_001`
+         } else if (form.identifierType === '闃蹭吉鐮�') {
+           identifierCode = `SEC_${form.productCode}_${form.batchNo}_001`
+         }
+         
+         identifierList.value.push({
+           ...form,
+           id: newId,
+           identifierCode: identifierCode,
+           generateTime: new Date().toLocaleString()
+         })
+         pagination.total++
+         ElMessage.success('鏂板鎴愬姛')
+       }
+      dialogVisible.value = false
+    }
+  })
+}
+
+const handleCurrentChange = (val) => {
+  pagination.currentPage = val.page
+  pagination.pageSize = val.limit
+}
+</script>
+
+<style scoped>
+.search-row {
+  margin-bottom: 20px;
+}
+
+.quick-actions-row {
+  margin-bottom: 20px;
+}
+
+.quick-actions-row .el-alert {
+  margin-bottom: 0;
+}
+
+.quick-actions-row .el-alert p {
+  margin: 5px 0;
+  font-size: 14px;
+  line-height: 1.5;
+}
+
+/* 浜岀淮鐮侀瑙堟牱寮� */
+.qr-preview-container {
+  text-align: center;
+  padding: 20px;
+}
+
+.qr-image-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 20px;
+}
+
+.qr-image {
+  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 {
+  text-align: left;
+  background: #f8f9fa;
+  padding: 15px;
+  border-radius: 8px;
+  min-width: 300px;
+}
+
+.qr-info p {
+  margin: 8px 0;
+  color: #666;
+  font-size: 14px;
+}
+
+.qr-loading {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 15px;
+  padding: 40px 0;
+}
+
+.qr-loading .el-icon {
+  font-size: 32px;
+  color: #409EFF;
+}
+
+.qr-loading p {
+  color: #666;
+  margin: 0;
+}
+</style>

--
Gitblit v1.9.3