Explorar o código

计件宝声音改成网页播放

zh hai 10 meses
pai
achega
04c149aeee

BIN=BIN
src/assets/sounds/error.mp3


BIN=BIN
src/assets/sounds/relogin.mp3


BIN=BIN
src/assets/sounds/scanner_error.mp3


BIN=BIN
src/assets/sounds/scanner_repeat.mp3


BIN=BIN
src/assets/sounds/tip.mp3


+ 177 - 147
src/views/piece/dashboard/index.vue

@@ -103,59 +103,28 @@
     </van-col>
   </van-row>
   <van-button class="add" icon="setting-o" type="primary" @click="_openSetting" />
-  <van-sticky>
-    <van-dialog
-      v-model:show="setting.show"
-      title="设置"
-      class="setting-dialog"
-      show-cancel-button
-      :before-close="_verifyMac"
-      @confirm="_saveMac"
-      @closed="_closeSetting"
-      width="380px">
-
-      <van-notice-bar
-        wrapable
-        left-icon="volume-o"
-        :scrollable="false"
-        :text="hintMessage"
-      />
-
-      <van-cell-group inset>
-        <van-field
-          v-model="setting.mac"
-          label="MAC地址"
-          placeholder="请输入MAC地址"
-        />
-        <van-field
-          v-model="setting.password"
-          type="password"
-          label="密码"
-          placeholder="设置密码"
-        />
-      </van-cell-group>
 
-      <van-notice-bar color="#1989fa" background="#ecf9ff" @click="checkUpdate"
-                      style="font-size: 16px; padding-left: 10px" left-icon="info-o">
-        版本号:{{ versionName }} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(点击检查更新)
-      </van-notice-bar>
-    </van-dialog>
-  </van-sticky>
+  <audio ref="errorAudio" controls hidden="true"  :src="errorPath" />
+  <audio ref="tipAudio" controls hidden="true"  :src="tipPath" />
+  <audio ref="repeatAudio" controls hidden="true"  :src="repeatPath" />
+  <audio ref="reLoginAudio" controls hidden="true"  :src="reLoginPath" />
+  <audio ref="scanErrorAudio" controls hidden="true"  :src="scanErrorPath" />
 </template>
 
 <script setup>
 import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
 import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
-import { scanSuccess, scanError } from '@/utils/android'
-import { getVersionName, checkUpdate, saveUserId, getUserId, scanRepeat, saveMacAddress, listErrRecords, reLoginTip,
-   readMacAddress, pageDelivery, addDelivery, isDeliveryNoExists, markAsPushed, getErrRecordsCount, removeUserId, scanErr } from '@/utils/androidPiece'
+import {
+  getVersionName, saveUserId, getUserId, saveMacAddress, listErrRecords, readMacAddress,
+  pageDelivery, addDelivery, isDeliveryNoExists, markAsPushed, getErrRecordsCount, removeUserId
+} from '@/utils/androidPiece'
 import { showLoadingToast, showNotify } from 'vant'
 import { getUserIdByCert, getUserNameById } from '@/api/login/index'
 import { receive, getScanDriverInfo } from '@/api/scan/index'
 import { formatDateTime } from '@/utils/date'
 
 // 在输入对话框或界面中添加提示文本
-const hintMessage = ref(`请前往:设置 → 关于平板电脑 → 设备WLAN MAC 地址 长按复制并粘贴到此处。`);
+const hintMessage = ref(`请前往:设置 → 关于平板电脑 → 设备WLAN MAC 地址 长按复制并粘贴到此处。`)
 const mac = ref('')
 const userInfo = ref({
   userId: '',
@@ -176,8 +145,8 @@ const preDeliveryNo = ref('')
 // 小青蛙位置属性
 const frogPosition = ref({
   warehouse: '',
-  type:'',
-  code:''
+  type: '',
+  code: ''
 })
 
 
@@ -191,13 +160,13 @@ const updateNetworkStatus = () => {
 const logout = () => {
   if (!userInfo.value.userId) {
     scanError()
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先登录!' });
+    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先登录!' })
     return
   }
   userInfo.value = {}
   removeUserId()
   scanSuccess()
-  showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '已退出登录!' });
+  showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '已退出登录!' })
 }
 
 // 网络提示
@@ -272,7 +241,7 @@ const _openScan = () => {
   openListener()
   setTimeout(() => {
     scanInit(debounceScan)
-  },300)
+  }, 300)
 }
 
 const pushing = ref(false)
@@ -293,17 +262,17 @@ const debounceScan = (code) => {
 const _handlerScan = (code) => {
   code = fixDuplicateText(code)
   // 校验扫描的是否为登录二维码
-  const regex = /\{"sign":"([^"]*)",\s*"identity":(\d+)\}/;
+  const regex = /\{"sign":"([^"]*)",\s*"identity":(\d+)\}/
   if (code !== null && regex.test(code)) {
     const match = regex.exec(code)
     const sign = match[1]
     const identity = match[2]
-    getUserIdByCert({sign: sign, identity: identity}).then(res => {
+    getUserIdByCert({ sign: sign, identity: identity }).then(res => {
       if (res && res.data) {
         userInfo.value.userId = res.data
         getUserName(res.data)
       } else {
-        showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '登录失败!' });
+        showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '登录失败!' })
       }
     })
   } else {
@@ -311,16 +280,16 @@ const _handlerScan = (code) => {
     if (typeof code !== 'string' || code.length < 11 || code.length > 25) {
       console.log(code)
       scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请扫描正确的快递单号!' });
+      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请扫描正确的快递单号!' })
       return
     }
     // 数字0-9,大写字母A-Z,部分特殊字符(空格、! " % & ' ( ) * + , - . / : ; < = > ? _)
-    const code128BPattern = /^[\x20-\x7F]+$/;
+    const code128BPattern = /^[\x20-\x7F]+$/
     // 检查是否只包含有效字符
     if (!code128BPattern.test(code)) {
       console.log(code)
       scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请扫描正确的快递单号!' });
+      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请扫描正确的快递单号!' })
       return
     }
     // 添加滚动到顶部的逻辑
@@ -335,29 +304,33 @@ const _handlerScan = (code) => {
     // 校验是否已登录
     if (!userInfo.value.userId) {
       scanError()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先登录!' });
+      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先登录!' })
       return
     }
     // 校验是否为空
     if (!code) {
       scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先扫描快递单号!' });
+      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先扫描快递单号!' })
       return
     }
 
     if (pushing.value) {
       scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '正在提交中,请稍后扫描!' });
+      showNotify({
+        type: 'danger',
+        style: 'font-size: 30px !important;height:50px',
+        message: '正在提交中,请稍后扫描!'
+      })
       return
     }
-    pushing.value =  true  // 请求状态锁
+    pushing.value = true  // 请求状态锁
 
     // 校验是否已扫描
     if (list.value.some(item => item.code === code)) {
       scanRepeat()
       pushing.value = false
       message.value = '该快递单已扫描!'
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' });
+      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' })
       return
     }
 
@@ -366,7 +339,7 @@ const _handlerScan = (code) => {
       scanRepeat()
       pushing.value = false
       message.value = '该快递单已扫描!'
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' });
+      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' })
       return
     }
 
@@ -374,7 +347,7 @@ const _handlerScan = (code) => {
       message: '上传中...',
       forbidClick: true,
       duration: 0 // 禁止自动关闭
-    });
+    })
     // 校验是否已存在
     const currentTime = formatDateTime(new Date())
     message.value = ''
@@ -386,7 +359,8 @@ const _handlerScan = (code) => {
       operatorName: userInfo.value.name,
       isPush: 1,
       preDeliveryNo: preDeliveryNo.value,
-      version: versionName.value }
+      version: versionName.value
+    }
 
     receive(dto).then(res => {
       if (res && res.code === 200) {
@@ -394,19 +368,23 @@ const _handlerScan = (code) => {
         if (result === -1) {
           scanRepeat()
           message.value = '该快递单已扫描!'
-          showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' });
+          showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' })
           return
         }
         if (result === -2) {
           scanErr()
-          showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '添加失败,请联系开发人员!' });
+          showNotify({
+            type: 'danger',
+            style: 'font-size: 30px !important;height:50px',
+            message: '添加失败,请联系开发人员!'
+          })
           return
         }
         preDeliveryNo.value = code
         scanSuccess()
         message.value = code + '扫描成功!'
         list.value.unshift(dto)
-        showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '扫描成功!' });
+        showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '扫描成功!' })
       }
     }).catch(err => {
       if (err.code === 700) {
@@ -415,9 +393,13 @@ const _handlerScan = (code) => {
       } else {
         scanErr()
       }
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: `扫描失败!${err.message}` });
+      showNotify({
+        type: 'danger',
+        style: 'font-size: 30px !important;height:50px',
+        message: `扫描失败!${err.message}`
+      })
     }).finally(() => {
-      toast.close();
+      toast.close()
       pushing.value = false
     })
   }
@@ -425,90 +407,90 @@ const _handlerScan = (code) => {
 
 function fixDuplicateText(input) {
   // 改进版正则表达式(支持任意字符且精确匹配完全重复)
-  const regex = /^(.+?)\1$/; // 非贪婪模式防止误匹配
-  const match = input.match(regex);
+  const regex = /^(.+?)\1$/ // 非贪婪模式防止误匹配
+  const match = input.match(regex)
   // 返回处理逻辑
-  return match ? match[1] : input;
+  return match ? match[1] : input
 }
 
 
 // 在外部定义一个防抖函数映射表,用于跟踪每个单据的防抖状态
-const debounceMap = new Map();
+const debounceMap = new Map()
 
 // 防抖函数封装
 const debounce = (func, wait = 500) => {
-  let timer;
+  let timer
   return (...args) => {
-    clearTimeout(timer);
+    clearTimeout(timer)
     timer = setTimeout(() => {
-      func.apply(this, args);
-    }, wait);
-  };
-};
+      func.apply(this, args)
+    }, wait)
+  }
+}
 
 // 修改后的推送函数
 const _rePush = (item) => {
-  if (!item || item.isPush === 1) return;
+  if (!item || item.isPush === 1) return
   let status = false
   showLoadingToast({
     message: '上传中...',
     forbidClick: true,
     closeToast: status
-  });
+  })
   // 初始化当前单据的防抖状态
   if (!debounceMap.has(item.deliveryNo)) {
     debounceMap.set(item.deliveryNo, {
       isPushing: false,  // 请求状态锁
       debouncedFn: debounce(() => {
-        const entry = debounceMap.get(item.deliveryNo);
-        if (!entry || entry.isPushing) return;
+        const entry = debounceMap.get(item.deliveryNo)
+        if (!entry || entry.isPushing) return
 
-        entry.isPushing = true;  // 加锁
+        entry.isPushing = true  // 加锁
 
         const dto = {
           deliveryNo: item.deliveryNo,
           machine: item.machine,
           operator: item.operator,
           operationTime: item.operationTime
-        };
+        }
 
         receive(dto).then(res => {
-          const result = markAsPushed(item.deliveryNo);
-          entry.isPushing = false;  // 请求完成解锁
-          item.isPush = 1;
-          scanSuccess();
+          const result = markAsPushed(item.deliveryNo)
+          entry.isPushing = false  // 请求完成解锁
+          item.isPush = 1
+          scanSuccess()
           status = true
           errNum.value -= 1
           showNotify({
             type: 'success',
             style: 'font-size: 30px !important;height:50px',
             message: '推送成功!'
-          });
+          })
         }).catch(err => {
-          entry.isPushing = false;  // 请求失败解锁
-          scanError();
+          entry.isPushing = false  // 请求失败解锁
+          scanError()
           status = true
           showNotify({
             type: 'danger',
             style: 'font-size: 30px !important;height:50px',
             message: `推单失败!${err.message}`
-          });
-        });
+          })
+        })
       }, 500)  // 500ms防抖时间
-    });
+    })
   }
 
   // 执行防抖函数
-  const { debouncedFn } = debounceMap.get(item.deliveryNo);
-  debouncedFn();
-};
+  const { debouncedFn } = debounceMap.get(item.deliveryNo)
+  debouncedFn()
+}
 
 const getUserName = (userId) => {
   getUserNameById(userId, mac.value).then(res => {
     if (res && res.data) {
       saveUserId(userInfo.value.userId)
       userInfo.value.name = res.data
-      showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '登录成功!' });
+      showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '登录成功!' })
     }
   })
 }
@@ -536,29 +518,30 @@ const _closeSetting = () => {
 }
 
 const _saveMac = () => {
-  if(!isValidMacAddress(setting.value.mac)) {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请输入正确的MAC地址!' });
+  if (!isValidMacAddress(setting.value.mac)) {
+    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请输入正确的MAC地址!' })
     return
   }
   if (!isValidPassword(setting.value.password)) {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请输入正确的密码!' });
+    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请输入正确的密码!' })
     return
   }
-  if(!saveMacAddress(setting.value.mac)) {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: 'MAC保存失败!' });
+  if (!saveMacAddress(setting.value.mac)) {
+    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: 'MAC保存失败!' })
     return
   }
-  showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: 'MAC保存成功!' });
+  showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: 'MAC保存成功!' })
   mac.value = setting.value.mac
   getFrogPosition()
 }
 
 function isValidMacAddress(mac) {
-  const regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
-  return mac !== null && regex.test(mac);
+  const regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/
+  return mac !== null && regex.test(mac)
 }
+
 function isValidPassword(password) {
-  return password === '123456';
+  return password === '123456'
 }
 
 // 网络状态和ip
@@ -566,18 +549,18 @@ const ipAddress = ref(null)
 
 // 获取 IP 地址
 const fetchIP = async () => {
-  const RTCPeerConnection = window.RTCPeerConnection;
+  const RTCPeerConnection = window.RTCPeerConnection
   if (RTCPeerConnection) {
-    const pc = new RTCPeerConnection({ iceServers: [] });
-    pc.createDataChannel('');
+    const pc = new RTCPeerConnection({ iceServers: [] })
+    pc.createDataChannel('')
     pc.createOffer()
       .then(sdp => pc.setLocalDescription(sdp))
-      .catch(console.error);
+      .catch(console.error)
     pc.onicecandidate = e => {
-      if (!e.candidate) return;
-      const ip = /([0-9]{1,3}(\.[0-9]{1,3}){3})/.exec(e.candidate.candidate)?.[1];
-      if (ip) ipAddress.value = ip;
-    };
+      if (!e.candidate) return
+      const ip = /([0-9]{1,3}(\.[0-9]{1,3}){3})/.exec(e.candidate.candidate)?.[1]
+      if (ip) ipAddress.value = ip
+    }
   }
 }
 
@@ -590,36 +573,36 @@ const size = ref(10)
 // 模拟数据加载
 const onLoad = () => {
   if (refreshing.value) {
-    list.value = [];
-    refreshing.value = false;
+    list.value = []
+    refreshing.value = false
   }
   const result = pageDelivery(page.value, size.value)
   if (result.size < size.value) {
-    finished.value = true;
+    finished.value = true
   } else {
     page.value += 1
   }
   list.value.push(...result)
-  loading.value = false;
-};
-const refreshing = ref(false);
+  loading.value = false
+}
+const refreshing = ref(false)
 const onRefresh = () => {
   // 清空列表数据
-  finished.value = false;
+  finished.value = false
 
   // 重新加载数据
   // 将 loading 设置为 true,表示处于加载状态
-  loading.value = true;
+  loading.value = true
   page.value = 1
-  onLoad();
-};
+  onLoad()
+}
 const isOnePush = ref(false)
 const _one_click_push = () => {
   isOnePush.value = true
   const result = listErrRecords()
   if (result && result != '[]') {
-    const records = JSON.parse(result);
-    const promises = []; // 收集所有请求的Promise
+    const records = JSON.parse(result)
+    const promises = [] // 收集所有请求的Promise
 
     records.forEach(item => {
       // 初始化当前单据的防抖状态
@@ -627,60 +610,107 @@ const _one_click_push = () => {
         const debounceEntry = {
           isPushing: false,
           debouncedFn: debounce(() => {
-            const entry = debounceMap.get(item.deliveryNo);
-            if (!entry || entry.isPushing) return;
+            const entry = debounceMap.get(item.deliveryNo)
+            if (!entry || entry.isPushing) return
 
-            entry.isPushing = true;  // 加锁
+            entry.isPushing = true  // 加锁
 
             const dto = {
               deliveryNo: item.deliveryNo,
               machine: item.machine,
               operator: item.operator,
               operationTime: item.operationTime
-            };
+            }
 
             // 将请求包装成Promise并收集
             const promise = receive(dto)
               .then(res => {
-                const result = markAsPushed(item.deliveryNo);
+                const result = markAsPushed(item.deliveryNo)
                 list.value.filter(entry => entry.deliveryNo === item.deliveryNo).forEach(entry => {
-                  entry.isPush = 1;
+                  entry.isPush = 1
                 })
                 errNum.value -= 1
               })
               .finally(() => {
-                entry.isPushing = false; // 无论成功失败都解锁
-              });
+                entry.isPushing = false // 无论成功失败都解锁
+              })
 
-            promises.push(promise); // 添加到Promise数组
-            return promise;
+            promises.push(promise) // 添加到Promise数组
+            return promise
           }, 500)
-        };
-        debounceMap.set(item.deliveryNo, debounceEntry);
+        }
+        debounceMap.set(item.deliveryNo, debounceEntry)
       }
 
       // 立即执行防抖函数并收集Promise
-      const promise = debounceMap.get(item.deliveryNo).debouncedFn();
-      if (promise) promises.push(promise);
-    });
+      const promise = debounceMap.get(item.deliveryNo).debouncedFn()
+      if (promise) promises.push(promise)
+    })
 
     // 所有请求完成后重置状态
     Promise.allSettled(promises)
       .then(_ => {
-        scanSuccess();
-        showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '数据已推送!' });
+        scanSuccess()
+        showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '数据已推送!' })
       })
       .catch(_ => {
-        scanError();
-        showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '存在数据推送失败!' });
+        scanError()
+        showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '存在数据推送失败!' })
       }).finally(() => {
-      isOnePush.value = false;
-    });
+      isOnePush.value = false
+    })
   } else {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '暂无异常数据!' });
-    isOnePush.value = false; // 没有数据时立即重置
+    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '暂无异常数据!' })
+    isOnePush.value = false // 没有数据时立即重置
   }
 }
+
+
+const errorPath = ref(new URL('@/assets/sounds/error.mp3', import.meta.url).href)
+const tipPath = ref(new URL('@/assets/sounds/tip.mp3', import.meta.url).href)
+const repeatPath = ref(new URL('@/assets/sounds/scanner_repeat.mp3', import.meta.url).href)
+const reLoginPath = ref(new URL('@/assets/sounds/relogin.mp3', import.meta.url).href)
+const scanErrorPath = ref(new URL('@/assets/sounds/scanner_error.mp3', import.meta.url).href)
+// 失败提示
+const errorAudio = ref(null)
+const scanError = () => {
+  // 本地链接
+  nextTick(() => {
+    errorAudio.value?.play()
+  })
+}
+// 成功提示
+const tipAudio = ref(null)
+const scanSuccess = () => {
+  // 本地链接
+  nextTick(() => {
+    tipAudio.value?.play()
+  })
+}
+// 重复扫描提示
+const repeatAudio = ref(null)
+const scanRepeat = () => {
+  // 本地链接
+  nextTick(() => {
+    repeatAudio.value?.play()
+  })
+}
+// 重新登录提示语
+const reLoginAudio = ref(null)
+const reLoginTip = () => {
+  // 本地链接
+  nextTick(() => {
+    reLoginAudio.value?.play()
+  })
+}
+// 扫描错误提示
+const scanErrorAudio = ref(null)
+const scanErr = () => {
+  // 本地链接
+  nextTick(() => {
+    scanErrorAudio.value?.play()
+  })
+}
 </script>
 
 <style scoped lang="sass">