lisongyi 2 недель назад
Родитель
Сommit
51fc1bf17d
1 измененных файлов с 61 добавлено и 205 удалено
  1. 61 205
      src/views/processing/groupScan/index.vue

+ 61 - 205
src/views/processing/groupScan/index.vue

@@ -25,6 +25,11 @@
         </div>
 
         <div class="context">
+          <div class="scan-tips">
+            <van-icon name="scan" size="20" />
+            <span>请扫描或手动输入快递单号</span>
+          </div>
+
           <div class="express-input-box">
             <div class="express-input-text">
               <div>快递单号</div>
@@ -35,43 +40,21 @@
               :style="expressNo !== '' ? 'border: 2px solid #07c160' : ''"
               clearable
               v-model="expressNo"
-              placeholder="扫描面单条码后自动填充,也可手动输入"
+              placeholder="扫描后自动填充,也可手动输入"
+              @keyup.enter="handleSubmit"
             />
           </div>
 
-          <div class="upload-section">
-            <div class="upload-tips">
-              <van-icon name="photo" size="20" />
-              <span>请拍摄或选择面单图片,识别一维码</span>
-            </div>
-
-            <van-uploader
-              v-model="uploadImages"
-              :max-count="1"
-              :before-read="beforeReadImage"
-              :after-read="afterReadImage"
-              preview-full-image
-              capture="camera"
-              accept="image/*"
+          <div class="action-section">
+            <van-button
+              type="primary"
+              block
+              :loading="submitting"
+              :disabled="!expressNo.trim()"
+              @click="handleSubmit"
             >
-              <template #preview-cover>
-                <div class="preview-cover">
-                  <van-icon name="photo" />
-                </div>
-              </template>
-            </van-uploader>
-
-            <div class="upload-footer">
-              <van-button
-                type="primary"
-                block
-                :loading="submitting"
-                :disabled="!expressNo.trim()"
-                @click="handleSubmit"
-              >
-                {{ submitting ? '提交中...' : '提交' }}
-              </van-button>
-            </div>
+              {{ submitting ? '提交中...' : '提交' }}
+            </van-button>
           </div>
         </div>
       </div>
@@ -80,155 +63,26 @@
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { onMounted, onUnmounted, ref } from 'vue'
 import { showNotify, showFailToast, showLoadingToast, closeToast } from 'vant'
 import { submitProcessingGroupScan } from '@/api/processing/index'
-import { getHeader, goBack, scanSuccess, scanError } from '@/utils/android'
-import Quagga from '@ericblade/quagga2'
+import { androidFocus, getHeader, goBack, scanSuccess, scanError } from '@/utils/android'
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
+import { barcodeToUpperCase } from '@/utils/dataType'
 
 try {
   getHeader()
+  androidFocus()
 } catch (error) {
   console.log(error)
 }
 
-const uploadImages = ref([])
 const submitting = ref(false)
 const expressNo = ref('')
 const expressNoRef = ref(null)
-const recognizing = ref(false)
-
-const beforeReadImage = (file) => {
-  const files = Array.isArray(file) ? file : [file]
-  for (const f of files) {
-    if (f.name.toLowerCase().endsWith('.heic') || f.name.toLowerCase().endsWith('.heif')) {
-      showFailToast('不支持HEIC/HEIF格式的图片')
-      return false
-    }
-    if (!/^image\//.test(f.type)) {
-      showFailToast('请上传图片文件')
-      return false
-    }
-  }
-  return true
-}
-
-const recognizeBarcode = async (file) => {
-  return new Promise((resolve) => {
-    try {
-      recognizing.value = true
-      const img = new Image()
-      const url = URL.createObjectURL(file)
-
-      img.onload = () => {
-        try {
-          const canvas = document.createElement('canvas')
-          const ctx = canvas.getContext('2d')
-          canvas.width = img.width
-          canvas.height = img.height
-          ctx.drawImage(img, 0, 0)
-
-          Quagga.decodeSingle(
-            {
-              decoder: {
-                readers: ['code_128_reader'],
-              },
-              locate: true,
-              src: canvas.toDataURL(),
-              numOfWorkers: 0,
-            },
-            (result) => {
-              if (result && result.codeResult && result.codeResult.code) {
-                const barcodeText = result.codeResult.code
-                URL.revokeObjectURL(url)
-                recognizing.value = false
-                scanSuccess()
-                resolve(barcodeText)
-              } else {
-                Quagga.decodeSingle(
-                  {
-                    decoder: {
-                      readers: [
-                        'code_128_reader',
-                        'ean_reader',
-                        'ean_8_reader',
-                        'code_39_reader',
-                        'code_39_vin_reader',
-                        'codabar_reader',
-                        'upc_reader',
-                        'upc_e_reader',
-                        'i2of5_reader',
-                      ],
-                    },
-                    locate: true,
-                    src: canvas.toDataURL(),
-                    numOfWorkers: 0,
-                  },
-                  (fallbackResult) => {
-                    URL.revokeObjectURL(url)
-                    recognizing.value = false
-                    if (fallbackResult && fallbackResult.codeResult && fallbackResult.codeResult.code) {
-                      scanSuccess()
-                      resolve(fallbackResult.codeResult.code)
-                    } else {
-                      scanError()
-                      resolve(null)
-                    }
-                  }
-                )
-              }
-            }
-          )
-        } catch (error) {
-          URL.revokeObjectURL(url)
-          recognizing.value = false
-          scanError()
-          resolve(null)
-        }
-      }
-
-      img.onerror = () => {
-        URL.revokeObjectURL(url)
-        recognizing.value = false
-        scanError()
-        resolve(null)
-      }
-
-      img.src = url
-    } catch (error) {
-      recognizing.value = false
-      scanError()
-      resolve(null)
-    }
-  })
-}
-
-const afterReadImage = async (file) => {
-  const files = Array.isArray(file) ? file : [file]
-  for (const fileItem of files) {
-    const originalFile = fileItem.file
-    if (!originalFile) continue
-
-    showNotify({ type: 'primary', message: '正在识别条码...' })
-    const barcodeResult = await recognizeBarcode(originalFile)
-    if (barcodeResult) {
-      expressNo.value = barcodeResult
-      showNotify({
-        type: 'success',
-        message: `识别到快递单号: ${barcodeResult}`,
-      })
-    } else {
-      showNotify({
-        type: 'warning',
-        message: '未识别到条码,请确保图片清晰或手动输入',
-      })
-    }
-  }
-}
 
 const resetForm = () => {
   expressNo.value = ''
-  uploadImages.value = []
 }
 
 const handleSubmit = async () => {
@@ -237,6 +91,7 @@ const handleSubmit = async () => {
     showFailToast('请先扫描或输入快递单号')
     return
   }
+  if (submitting.value) return
 
   submitting.value = true
   showLoadingToast({ message: '提交中...', forbidClick: true })
@@ -260,6 +115,25 @@ const handleSubmit = async () => {
     submitting.value = false
   }
 }
+
+const _handlerScan = (code) => {
+  const barcode = barcodeToUpperCase(code?.trim())
+  if (!barcode) {
+    scanError()
+    return
+  }
+  expressNo.value = barcode
+  scanSuccess()
+}
+
+onMounted(() => {
+  openListener()
+  scanInit(_handlerScan)
+})
+
+onUnmounted(() => {
+  closeListener()
+})
 </script>
 
 <style scoped lang="sass">
@@ -283,9 +157,26 @@ const handleSubmit = async () => {
   padding: 15px
   overflow-y: auto
 
+.scan-tips
+  display: flex
+  align-items: center
+  justify-content: center
+  margin-bottom: 20px
+  padding: 16px
+  background: #fff
+  border-radius: 8px
+  color: #666
+  font-size: 16px
+
+  span
+    margin-left: 8px
+
 .express-input-box
   margin-bottom: 20px
   padding: 10px 5px
+  background: #fff
+  border-radius: 8px
+
   .express-input-text
     display: flex
     justify-content: space-between
@@ -293,7 +184,8 @@ const handleSubmit = async () => {
     font-size: 18px
     font-weight: bold
     margin: 10px 0
-    padding: 5px 0
+    padding: 5px 10px 0
+
   .express-input
     background: #eff0f2
     padding: 10px 20px
@@ -301,44 +193,8 @@ const handleSubmit = async () => {
     border: 2px solid #0077ff
     font-weight: 500
 
-.upload-section
+.action-section
   background: #fff
   padding: 20px
   border-radius: 8px
-
-.upload-tips
-  display: flex
-  align-items: center
-  justify-content: center
-  margin-bottom: 20px
-  color: #666
-  font-size: 16px
-
-  span
-    margin-left: 8px
-
-.upload-footer
-  margin-top: 20px
-
-.preview-cover
-  position: absolute
-  bottom: 0
-  box-sizing: border-box
-  width: 100%
-  padding: 4px
-  color: #fff
-  font-size: 12px
-  text-align: center
-  background: rgba(0, 0, 0, 0.3)
-
-:deep(.van-uploader__upload)
-  width: 100px
-  height: 100px
-  margin: 0 auto
-  display: block
-
-:deep(.van-uploader__preview-image)
-  width: 100px
-  height: 100px
-  margin: 0 auto
 </style>