From 95f44bd509e286290a18639531de3e05768c3a90 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 24 六月 2025 16:46:07 +0800
Subject: [PATCH] 1.巡检管理-二维码管理联调 2.巡检管理-现场巡检记录开发联调 3.巡检上传-现场巡检开发联调

---
 src/views/inspectionUpload/index.vue |  290 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 279 insertions(+), 11 deletions(-)

diff --git a/src/views/inspectionUpload/index.vue b/src/views/inspectionUpload/index.vue
index 559c05e..560fc01 100644
--- a/src/views/inspectionUpload/index.vue
+++ b/src/views/inspectionUpload/index.vue
@@ -15,8 +15,46 @@
         />
       </el-tabs>
       <div>
+        <!-- 鎵爜妯″潡 -->
+        <div v-if="activeTab === 'qrCode'" class="scan-section">
+          <div class="scan-controls">
+            <el-button
+                type="primary"
+                :loading="scanLoading"
+                @click="toggleScan"
+            >
+              {{ scanButtonText }}
+            </el-button>
+          </div>
+          
+          <!-- 鎵爜瑙嗛瀹瑰櫒 -->
+          <div v-show="isScanning" class="qr-video-container">
+            <video
+                ref="qrVideo"
+                class="qr-video"
+                playsinline
+                webkit-playsinline
+            ></video>
+            <div class="scan-overlay"></div>
+          </div>
+          
+          <!-- 鐘舵�佹彁绀� -->
+          <div class="status-info">
+            <el-alert
+                v-if="cameraError"
+                :title="cameraError"
+                type="error"
+                show-icon
+                closable
+            />
+            <div v-if="isScanning" class="scanning-text">
+              <el-icon :color="statusColor"><Loading /></el-icon>
+              姝e湪鎵弿浜岀淮鐮�...
+            </div>
+          </div>
+        </div>
         <div>
-          <el-table ref="table" :data="tableData" height="480" v-loading="tableLoading">
+          <el-table ref="table" :data="tableData" height="480" v-loading="tableLoading" v-if="activeTab !== 'qrCode'">
             <el-table-column label="搴忓彿" type="index" width="60" align="center" />
             <el-table-column prop="taskName" label="宸℃浠诲姟鍚嶇О" :show-overflow-tooltip="true"></el-table-column>
             <el-table-column prop="port" label="鍦扮偣" :show-overflow-tooltip="true"></el-table-column>
@@ -25,6 +63,26 @@
             <el-table-column fixed="right" label="鎿嶄綔">
               <template #default="scope">
                 <el-button link type="primary" @click="handleAdd(scope.row)">涓婁紶</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+          <el-table ref="table" :data="tableData" height="480" v-loading="tableLoading" v-if="activeTab === 'qrCode'">
+            <el-table-column label="搴忓彿" type="index" width="60" align="center" />
+            <el-table-column prop="deviceName" label="璁惧鍚嶇О" :show-overflow-tooltip="true">
+              <template #default="scope">
+                {{scope.row.qrCode.deviceName}}
+              </template>
+            </el-table-column>
+            <el-table-column prop="location" label="鎵�鍦ㄤ綅缃弿杩�" :show-overflow-tooltip="true">
+              <template #default="scope">
+                {{scope.row.qrCode.location}}
+              </template>
+            </el-table-column>
+            <el-table-column prop="scanner" label="宸℃浜�"></el-table-column>
+            <el-table-column prop="scanTime" label="宸℃鏃堕棿"></el-table-column>
+            <el-table-column fixed="right" label="鎿嶄綔">
+              <template #default="scope">
+                <el-button link type="primary" @click="viewFile(scope.row)">鏌ョ湅闄勪欢</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -40,22 +98,31 @@
       </div>
     </el-card>
     <form-dia ref="formDia" @closeDia="handleQuery"></form-dia>
+    <qr-code-form-dia ref="qrCodeFormDia" @closeDia="handleQuery"></qr-code-form-dia>
+    <view-qr-code-files ref="viewQrCodeFiles"></view-qr-code-files>
   </div>
 </template>
 
 <script setup>
 import Pagination from "@/components/Pagination/index.vue";
-import {inspectionTaskList} from "@/api/inspectionManagement/index.js";
 import {onMounted, ref} from "vue";
 import FormDia from "@/views/inspectionUpload/components/formDia.vue";
+import {ElMessage} from "element-plus";
+import QrScanner from 'qr-scanner'
+import QrCodeFormDia from "@/views/inspectionUpload/components/qrCodeFormDia.vue";
+import {qrCodeList, qrCodeScanRecordList} from "@/api/inspectionUpload/index.js";
+import {inspectionTaskList} from "@/api/inspectionManagement/index.js";
+import ViewQrCodeFiles from "@/views/inspectionManagement/components/viewQrCodeFiles.vue";
 const formDia = ref()
+const qrCodeFormDia = ref()
+const viewQrCodeFiles = ref()
 // 褰撳墠鏍囩
 const activeTab = ref("task");
 const tabName = ref("task");
 // 鏍囩椤垫暟鎹�
 const tabs = reactive([
-  { name: "task", label: "浠诲姟涓嬪彂" },
-  { name: "qrCode", label: "浜岀淮鐮佺鐞�" },
+  { name: "task", label: "鐢熶骇宸℃" },
+  { name: "qrCode", label: "鐜板満宸℃" },
 ]);
 // 琛ㄦ牸
 const tableData = ref([]);
@@ -63,10 +130,32 @@
 const total = ref(0);
 const pageNum = ref(1);
 const pageSize = ref(10);
+// 鎵爜鐩稿叧鐘舵��
+const qrVideo = ref(null)
+const isScanning = ref(false)
+const scanLoading = ref(false)
+const cameraError = ref(null)
+const scanner = ref(null)
+const hasInit = ref(false)
 
-onMounted(() => {
+const statusColor = computed(() => {
+  return isScanning.value ? '#67C23A' : '#F56C6C'
+})
+// 鐢熷懡鍛ㄦ湡绠$悊浼樺寲
+onMounted(async () => {
   handleTabClick({ props: { name: "task" } });
-});
+  if (!import.meta.env.SSR && QrScanner) { // [!code focus]
+    await initScanner()
+  }
+})
+
+onBeforeUnmount(async () => {
+  if (scanner.value) {
+    await scanner.value.destroy()
+    scanner.value = null
+  }
+  hasInit.value = false
+})
 // 鏍囩椤电偣鍑�
 const handleTabClick = (tab) => {
   tabName.value = tab.props.name;
@@ -81,11 +170,19 @@
 }
 const getList = () => {
   tableLoading.value = true;
-  inspectionTaskList({size: pageSize.value, current: pageNum.value}).then(res => {
-    tableLoading.value = false;
-    tableData.value = res.data.records;
-    total.value = res.data.total;
-  })
+  if (tabName.value === "task") {
+    inspectionTaskList({size: pageSize.value, current: pageNum.value}).then(res => {
+      tableLoading.value = false;
+      tableData.value = res.data.records;
+      total.value = res.data.total;
+    })
+  } else {
+    qrCodeScanRecordList({size: pageSize.value, current: pageNum.value}).then(res => {
+      tableLoading.value = false;
+      tableData.value = res.data.records;
+      total.value = res.data.total;
+    })
+  }
 };
 // 涓婁紶
 const handleAdd = (row) => {
@@ -93,10 +190,181 @@
     formDia.value?.openDialog(row)
   })
 }
+// 鏌ョ湅闄勪欢
+const viewFile = (row) => {
+  nextTick(() => {
+    viewQrCodeFiles.value?.openDialog(row)
+  })
+}
+// 鎵爜鎸夐挳鏂囨湰
+const scanButtonText = computed(() => {
+  if (scanLoading.value) return '姝e湪鍒濆鍖�...'
+  return isScanning.value ? '鍋滄鎵爜' : '寮�濮嬫壂鐮�'
+})
 
+// 澧炲己鍨嬪垵濮嬪寲
+const initScanner = async () => {
+  try {
+    await nextTick() // 纭繚DOM鏇存柊
+    // 鏂板澶氶噸绌哄�兼牎楠�
+    if (!qrVideo.value || !QrScanner) {
+      throw new Error('渚濊禆鏈纭垵濮嬪寲')
+    }
+    // 澧炲姞鎽勫儚澶存潈闄愰妫�鏌�
+    const hasCamera = await QrScanner.hasCamera()
+    if (!hasCamera) {
+      throw new Error('鏈娴嬪埌鍙敤鎽勫儚澶�')
+    }
+    // 鏄惧紡閿�姣佹棫瀹炰緥
+    if (scanner.value) {
+      await scanner.value.destroy()
+    }
+    // 鍒涘缓鏂板疄渚�
+    scanner.value = new QrScanner(
+        qrVideo.value,
+        result => {
+          handleScanSuccess(result)
+          // stopScan()
+        },
+        {
+          preferredCamera: 'environment',
+          maxScansPerSecond: 5,
+          returnDetailedScanResult: true
+        }
+    )
+    // 鏂板纭欢鍔犻�熸娴�
+    if (!scanner.value._qrWorker) {
+      throw new Error('纭欢鍔犻�熶笉鍙敤')
+    }
+    hasInit.value = true
+  } catch (e) {
+    // handleInitError(e)
+  }
+}
+// 鎵弿鎴愬姛澶勭悊
+const handleScanSuccess = async (result) => {
+  try {
+    // 娣诲姞鏁版嵁鏍¢獙
+    ElMessage.success('璇嗗埆鎴愬姛')
+    callBackendAPI(JSON.parse(result.data))
+    await stopScan()
+  } catch (error) {
+    ElMessage.warning(error.message)
+    await startScan() // 鏁版嵁鏃犳晥鏃剁户缁壂鎻�
+  }
+}
+const callBackendAPI = (result) => {
+  nextTick(() => {
+    qrCodeFormDia.value?.openDialog(result)
+  })
+}
+// 鍒囨崲鎵爜鐘舵��
+const toggleScan = async () => {
+  if (isScanning.value) {
+    await stopScan()
+  } else {
+    await startScan()
+  }
+}
+
+// 澧炲己鍚姩鏂规硶
+const startScan = async () => {
+  if (!scanner.value || !hasInit.value) { // 鏂板鐘舵�佹鏌�
+    await initScanner()
+  }
+  
+  try {
+    await scanner.value.start()
+    isScanning.value = true
+  } catch (e) {
+    ElMessage.error(`鍚姩澶辫触: ${e.message}`)
+    hasInit.value = false
+  }
+}
+
+// 鍋滄鎵爜
+const stopScan = async () => {
+  try {
+    await scanner.value.stop()
+    isScanning.value = false
+  } catch (err) {
+    console.error('鍋滄鎽勫儚澶村け璐�:', err)
+  }
+}
+
+
+// 閿欒澶勭悊澧炲己
+const handleInitError = (error) => {
+  console.error('鍒濆鍖栧け璐�:', error)
+  const msg = {
+    'NotAllowedError': '璇峰厑璁告憚鍍忓ご鏉冮檺',
+    'NotFoundError': '鏈壘鍒版憚鍍忓ご璁惧',
+    'NotSupportedError': '娴忚鍣ㄤ笉鏀寔鎵爜鍔熻兘'
+  }[error.name] || error.message
+  
+  ElMessage.error(`鍒濆鍖栧け璐�: ${msg}`)
+}
 
 </script>
 
 <style scoped>
+.qr-video-container {
+  position: relative;
+  width: 100%;
+  max-width: 500px;
+  margin: 0 auto;
+  background: #000;
+  border-radius: 8px;
+  overflow: hidden;
+}
 
+.qr-video {
+  width: 100%;
+  height: auto;
+  object-fit: cover;
+}
+
+.scan-overlay {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 70%;
+  height: 70%;
+  border: 3px solid #409eff;
+  border-radius: 8px;
+  box-shadow: 0 0 20px rgba(64, 158, 255, 0.3);
+  animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+  0% { opacity: 0.8; }
+  50% { opacity: 0.4; }
+  100% { opacity: 0.8; }
+}
+
+.status-info {
+  margin-top: 16px;
+  text-align: center;
+}
+
+.scanning-text {
+  color: #409eff;
+  margin-top: 8px;
+}
+
+.table-section {
+  margin-top: 24px;
+}
+
+/* 绉诲姩绔紭鍖� */
+@media (max-width: 768px) {
+  .qr-video-container {
+    height: 60vh;
+  }
+  
+  .el-table {
+    font-size: 12px;
+  }
+}
 </style>
\ No newline at end of file

--
Gitblit v1.9.3