zhangwencui
2026-07-14 10ae883d6368fb8fc3f95620f610c3aaf6c6a3cd
PDA扫码调试
已添加1个文件
已修改6个文件
1004 ■■■■ 文件已修改
src/components/ScanWaitMask.vue 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/pda-media-upload/pda-media-upload.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/pda-scan/pda-scan.vue 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/repair/add.vue 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/upkeep/add.vue 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inspectionUpload/upload.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/works.vue 231 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ScanWaitMask.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,220 @@
<template>
  <view v-if="show" class="swm-mask" @touchmove.stop.prevent @tap.stop>
    <view class="swm-card" @tap.stop>
      <view class="swm-figure">
        <view v-if="status === 'waiting'" class="swm-scan-box">
          <view class="swm-scan-line" />
          <view class="swm-scan-corner tl" />
          <view class="swm-scan-corner tr" />
          <view class="swm-scan-corner bl" />
          <view class="swm-scan-corner br" />
        </view>
        <view v-else-if="status === 'done'" class="swm-check">
          <view class="swm-check-mark" />
        </view>
        <view v-else class="swm-warn">
          <view class="swm-warn-bar" />
          <view class="swm-warn-dot" />
        </view>
      </view>
      <view class="swm-title">{{ titleText }}</view>
      <view class="swm-sub">{{ subText }}</view>
    </view>
  </view>
</template>
<script setup>
  import { computed } from "vue";
  const props = defineProps({
    show: { type: Boolean, default: false },
    status: { type: String, default: "waiting" },
    title: { type: String, default: "" },
    subTitle: { type: String, default: "" },
  });
  const titleText = computed(() => {
    if (props.title) return props.title;
    if (props.status === "done") return "扫码完成";
    if (props.status === "timeout") return "扫码超时";
    return "等待扫码";
  });
  const subText = computed(() => {
    if (props.subTitle) return props.subTitle;
    if (props.status === "done") return "正在处理扫码结果";
    if (props.status === "timeout") return "未收到扫码数据,请重试";
    return "请对准二维码/条码进行扫描";
  });
</script>
<style scoped lang="scss">
  .swm-mask {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 9999;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .swm-card {
    width: 620rpx;
    padding: 36rpx 32rpx 30rpx;
    background: #ffffff;
    border-radius: 24rpx;
    box-shadow: 0 16rpx 44rpx rgba(0, 0, 0, 0.22);
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .swm-figure {
    width: 260rpx;
    height: 260rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 18rpx;
  }
  .swm-title {
    font-size: 34rpx;
    font-weight: 700;
    color: rgba(0, 0, 0, 0.88);
    margin-bottom: 10rpx;
  }
  .swm-sub {
    font-size: 26rpx;
    color: rgba(0, 0, 0, 0.55);
    text-align: center;
    line-height: 38rpx;
  }
  .swm-scan-box {
    width: 220rpx;
    height: 220rpx;
    border-radius: 22rpx;
    background: rgba(25, 137, 250, 0.06);
    position: relative;
    overflow: hidden;
  }
  .swm-scan-line {
    position: absolute;
    left: 14rpx;
    right: 14rpx;
    height: 6rpx;
    top: 18rpx;
    border-radius: 6rpx;
    background: linear-gradient(90deg, rgba(25, 137, 250, 0), #1989fa, rgba(25, 137, 250, 0));
    animation: swmScan 1.2s linear infinite;
  }
  .swm-scan-corner {
    position: absolute;
    width: 34rpx;
    height: 34rpx;
    border-color: #1989fa;
    border-style: solid;
  }
  .swm-scan-corner.tl {
    left: 0;
    top: 0;
    border-width: 6rpx 0 0 6rpx;
    border-top-left-radius: 20rpx;
  }
  .swm-scan-corner.tr {
    right: 0;
    top: 0;
    border-width: 6rpx 6rpx 0 0;
    border-top-right-radius: 20rpx;
  }
  .swm-scan-corner.bl {
    left: 0;
    bottom: 0;
    border-width: 0 0 6rpx 6rpx;
    border-bottom-left-radius: 20rpx;
  }
  .swm-scan-corner.br {
    right: 0;
    bottom: 0;
    border-width: 0 6rpx 6rpx 0;
    border-bottom-right-radius: 20rpx;
  }
  @keyframes swmScan {
    0% {
      transform: translateY(0);
      opacity: 0.9;
    }
    90% {
      opacity: 0.95;
    }
    100% {
      transform: translateY(180rpx);
      opacity: 0.55;
    }
  }
  .swm-check {
    width: 180rpx;
    height: 180rpx;
    border-radius: 90rpx;
    background: rgba(18, 185, 129, 0.12);
    border: 6rpx solid rgba(18, 185, 129, 0.85);
    position: relative;
  }
  .swm-check-mark {
    position: absolute;
    left: 58rpx;
    top: 72rpx;
    width: 56rpx;
    height: 30rpx;
    border-left: 10rpx solid rgba(18, 185, 129, 0.95);
    border-bottom: 10rpx solid rgba(18, 185, 129, 0.95);
    transform: rotate(-45deg);
  }
  .swm-warn {
    width: 180rpx;
    height: 180rpx;
    border-radius: 90rpx;
    background: rgba(245, 158, 11, 0.12);
    border: 6rpx solid rgba(245, 158, 11, 0.9);
    position: relative;
  }
  .swm-warn-bar {
    position: absolute;
    left: 50%;
    top: 44rpx;
    width: 10rpx;
    height: 72rpx;
    border-radius: 10rpx;
    transform: translateX(-50%);
    background: rgba(245, 158, 11, 0.95);
  }
  .swm-warn-dot {
    position: absolute;
    left: 50%;
    bottom: 42rpx;
    width: 14rpx;
    height: 14rpx;
    border-radius: 14rpx;
    transform: translateX(-50%);
    background: rgba(245, 158, 11, 0.95);
  }
</style>
src/components/pda-media-upload/pda-media-upload.vue
@@ -93,11 +93,9 @@
  const uploading = ref(false);
  const uploadProgress = ref(0);
  // ç›‘听上传状态,发出事件
  const watchUploading = val => {
    emit("uploading", val);
  };
  // ç›‘听进度,发出事件
  const watchProgress = val => {
    emit("progress", val);
  };
@@ -393,4 +391,3 @@
    font-size: 13px;
  }
</style>
src/components/pda-scan/pda-scan.vue
@@ -18,9 +18,17 @@
      extraKey: { type: String, default: "" },
      debounceMs: { type: Number, default: 150 },
    },
    data() {
      return {
        _ensureTimer: null,
        _ensureTries: 0,
      };
    },
    mounted() {
      this.init();
      if (this.active) this.start();
      this.ensureStarted();
    },
    onHide() {
      this.stop();
    },
    beforeUnmount() {
      this.stop();
@@ -28,14 +36,45 @@
    watch: {
      active(val) {
        if (val) {
          this.init();
          this.start();
          this.ensureStarted();
        } else {
          this.stop();
        }
      },
    },
    methods: {
      ensureStarted() {
        if (!this.active) return;
        this._ensureTries = 0;
        if (this._ensureTimer) {
          clearInterval(this._ensureTimer);
          this._ensureTimer = null;
        }
        const tick = () => {
          if (!this.active) return;
          if (isRegistered) return;
          this.init();
          this.start();
          this._ensureTries += 1;
          if (isRegistered) {
            if (this._ensureTimer) {
              clearInterval(this._ensureTimer);
              this._ensureTimer = null;
            }
          } else if (this._ensureTries >= 50) {
            if (this._ensureTimer) {
              clearInterval(this._ensureTimer);
              this._ensureTimer = null;
            }
          }
        };
        tick();
        if (!isRegistered) {
          this._ensureTimer = setInterval(tick, 200);
        }
      },
      canUseAndroidBroadcast() {
        try {
          if (typeof plus === "undefined") return false;
@@ -47,22 +86,22 @@
        }
      },
      resolveBroadcastConfig(sys) {
        try {
          const brand = String(sys?.brand || "").toUpperCase();
          const model = String(sys?.model || "").toUpperCase();
          if (
            brand.includes("DROI") ||
            model.includes("MV-IDP5204") ||
            model.includes("IDP")
          ) {
            return { action: "com.service.scanner.data", extraKey: "ScanCode" };
          }
        } catch (e) {}
        if (this.action && this.extraKey) {
          return { action: this.action, extraKey: this.extraKey };
        }
        const brand = String(sys?.brand || "").toUpperCase();
        const model = String(sys?.model || "").toUpperCase();
        if (
          brand.includes("DROI") ||
          model.includes("MV-IDP5204") ||
          model.includes("IDP")
        ) {
          return { action: "com.service.scanner.data", extraKey: "ScanCode" };
        }
        return { action: "", extraKey: "" };
        return { action: "com.service.scanner.data", extraKey: "ScanCode" };
      },
      init() {
        if (!this.canUseAndroidBroadcast()) return;
@@ -86,14 +125,157 @@
          "android.content.IntentFilter"
        );
        intentFilter = new IntentFilter();
        intentFilter.addAction(action);
        const pickActions = v => {
          const list = [];
          if (v) {
            String(v)
              .split(/[,\s]+/)
              .map(s => s.trim())
              .filter(Boolean)
              .forEach(a => list.push(a));
          }
          [
            "com.service.scanner.data",
            "com.scanner.broadcast",
            "com.android.scanner.broadcast",
            "com.seuic.scanner.data",
            "com.android.scanner.receiver",
            "com.android.scanner.result",
            "com.rfid.SCAN",
            "com.honeywell.decode.intent.action",
            "com.symbol.datawedge.data",
            "com.symbol.datawedge.api.RESULT_ACTION",
            "com.datalogic.decodewedge.decode_action",
            "android.intent.ACTION_DECODE_DATA",
            "android.intent.action.SCANRESULT",
            "android.intent.action.DECODE_DATA",
            "scan.rcv.message",
          ].forEach(a => {
            if (!list.includes(a)) list.push(a);
          });
          return list;
        };
        const actions = pickActions(action);
        actions.forEach(a => intentFilter.addAction(a));
        const pickExtraKeys = key => {
          const list = [];
          if (key) {
            String(key)
              .split(/[,\s]+/)
              .map(s => s.trim())
              .filter(Boolean)
              .forEach(k => list.push(k));
          }
          [
            "ScanCode",
            "scanCode",
            "barcode",
            "barCode",
            "data",
            "DATA",
            "code",
            "CODE",
            "result",
            "RESULT",
            "scannerdata",
            "decode_data",
            "SCAN_RESULT",
            "data_string",
            "com.symbol.datawedge.data_string",
            "com.symbol.datawedge.label_type",
          ].forEach(k => {
            if (!list.includes(k)) list.push(k);
          });
          return list;
        };
        const extraKeys = pickExtraKeys(extraKey);
        receiver = plus.android.implements(
          "io.dcloud.feature.internal.reflect.BroadcastReceiver",
          {
            onReceive(context, intent) {
              plus.android.importClass(intent);
              const code = intent.getStringExtra(extraKey);
              let code = "";
              for (let i = 0; i < extraKeys.length; i++) {
                const k = extraKeys[i];
                try {
                  const v = intent.getStringExtra(k);
                  if (v) {
                    code = v;
                    break;
                  }
                } catch (e) {}
                try {
                  const bytes = intent.getByteArrayExtra(k);
                  if (bytes && bytes.length) {
                    const JString = plus.android.importClass("java.lang.String");
                    code = new JString(bytes);
                    if (code) break;
                  }
                } catch (e) {}
              }
              if (!code) {
                try {
                  const ds = intent.getDataString();
                  if (ds) code = ds;
                } catch (e) {}
              }
              if (!code) {
                try {
                  const extras = intent.getExtras();
                  if (extras) {
                    plus.android.importClass(extras);
                    const keySet = extras.keySet();
                    if (keySet) {
                      plus.android.importClass(keySet);
                      const it = keySet.iterator();
                      if (it) {
                        plus.android.importClass(it);
                        while (it.hasNext()) {
                          const k = it.next();
                          const ks = String(k);
                          let v = "";
                          try {
                            v = extras.getString(ks);
                          } catch (e) {}
                          if (!v) {
                            try {
                              const any = extras.get(ks);
                              if (any != null) v = String(any);
                            } catch (e) {}
                          }
                          const text = (v == null ? "" : String(v))
                            .replace(/\n/g, "")
                            .trim();
                          if (
                            text &&
                            text.length >= 3 &&
                            text.length <= 300 &&
                            /[0-9A-Za-z]/.test(text) &&
                            !text.includes("android.") &&
                            !text.includes("com.")
                          ) {
                            code = text;
                            break;
                          }
                          if (
                            !code &&
                            text &&
                            text.length >= 3 &&
                            text.length <= 300 &&
                            /[0-9A-Za-z]/.test(text)
                          ) {
                            code = text;
                          }
                        }
                      }
                    }
                  }
                } catch (e) {}
              }
              _this.emitCode(code);
            },
          }
@@ -106,9 +288,15 @@
        try {
          mainActivity.registerReceiver(receiver, intentFilter);
          isRegistered = true;
        } catch (e) {}
        } catch (e) {
          isRegistered = false;
        }
      },
      stop() {
        if (this._ensureTimer) {
          clearInterval(this._ensureTimer);
          this._ensureTimer = null;
        }
        if (!this.canUseAndroidBroadcast()) return;
        if (!mainActivity || !receiver) return;
        if (!isRegistered) return;
src/pages/equipmentManagement/repair/add.vue
@@ -129,8 +129,8 @@
                        @confirm="onDateConfirm"
                        @cancel="showDate = false"
                        mode="date" />
    <PdaScan :active="pdaScanActive"
             eventName="scan_repair_device" />
    <ScanWaitMask :show="scanMaskShow" :status="scanMaskStatus" />
    <PdaScan />
  </view>
</template>
@@ -139,6 +139,7 @@
  import { onShow, onLoad } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import CommonUpload from "@/components/CommonUpload.vue";
  import ScanWaitMask from "@/components/ScanWaitMask.vue";
  import PdaScan from "@/components/pda-scan/pda-scan.vue";
  import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
  import {
@@ -188,8 +189,50 @@
  // æ‰«ç ç›¸å…³çŠ¶æ€
  const isScanning = ref(false);
  const scanTimer = ref(null);
  const pdaScanActive = ref(false);
  const pdaScanTimer = ref(null);
  const pendingDeviceScan = ref(false);
  let pendingDeviceScanTimer = null;
  const scanMaskShow = ref(false);
  const scanMaskStatus = ref("waiting");
  const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
  const canUsePdaBroadcast = () => {
    try {
      if (typeof plus === "undefined") return false;
      if (plus?.os?.name !== "Android") return false;
      if (!plus?.android) return false;
      const sys = uni.getSystemInfoSync?.() || {};
      const brand = String(sys?.brand || "").toUpperCase();
      const model = String(sys?.model || "").toUpperCase();
      return (
        brand.includes("DROI") ||
        model.includes("MV-IDP5204") ||
        model.includes("IDP")
      );
    } catch (e) {
      return false;
    }
  };
  onShow(() => {
    uni.$off("scan");
    uni.$on("scan", data => {
      console.log("onscan");
      console.log("扫码结果:", data.code);
      if (!pendingDeviceScan.value) return;
      pendingDeviceScan.value = false;
      scanMaskStatus.value = "done";
      if (pendingDeviceScanTimer) {
        clearTimeout(pendingDeviceScanTimer);
        pendingDeviceScanTimer = null;
      }
      delay(350).then(() => {
        scanMaskShow.value = false;
        handleScanResult(data.code);
      });
    });
  });
  // è¡¨å•验证规则
  const formRules = {
@@ -296,62 +339,47 @@
  // æ‰«æäºŒç»´ç åŠŸèƒ½
  const startScan = () => {
    if (isScanning.value) {
      showToast("正在扫描中,请稍候...");
      return;
    pendingDeviceScan.value = true;
    scanMaskStatus.value = "waiting";
    scanMaskShow.value = true;
    if (pendingDeviceScanTimer) {
      clearTimeout(pendingDeviceScanTimer);
      pendingDeviceScanTimer = null;
    }
    const canUsePdaBroadcast = () => {
      try {
        if (typeof plus === "undefined") return false;
        if (plus?.os?.name !== "Android") return false;
        if (!plus?.android) return false;
        const sys = uni.getSystemInfoSync?.() || {};
        const brand = String(sys?.brand || "").toUpperCase();
        const model = String(sys?.model || "").toUpperCase();
        return (
          brand.includes("DROI") ||
          model.includes("MV-IDP5204") ||
          model.includes("IDP")
        );
      } catch (e) {
        return false;
      }
    };
    if (canUsePdaBroadcast()) {
      if (pdaScanTimer.value) {
        clearTimeout(pdaScanTimer.value);
        pdaScanTimer.value = null;
      }
      uni.$off("scan_repair_device");
      uni.$on("scan_repair_device", data => {
        pdaScanActive.value = false;
        uni.$off("scan_repair_device");
        if (pdaScanTimer.value) {
          clearTimeout(pdaScanTimer.value);
          pdaScanTimer.value = null;
        }
        handleScanResult(data?.code);
    pendingDeviceScanTimer = setTimeout(() => {
      pendingDeviceScan.value = false;
      pendingDeviceScanTimer = null;
      scanMaskStatus.value = "timeout";
      delay(900).then(() => {
        scanMaskShow.value = false;
      });
      pdaScanActive.value = true;
      uni.showToast({ title: "请使用PDA扫码", icon: "none" });
      pdaScanTimer.value = setTimeout(() => {
        pdaScanActive.value = false;
        uni.$off("scan_repair_device");
        pdaScanTimer.value = null;
      }, 20000);
      return;
    }
    }, 20000);
    if (canUsePdaBroadcast()) return;
    uni.scanCode({
      scanType: ["qrCode", "barCode"],
      success: res => {
        handleScanResult(res.result);
        pendingDeviceScan.value = false;
        scanMaskStatus.value = "done";
        if (pendingDeviceScanTimer) {
          clearTimeout(pendingDeviceScanTimer);
          pendingDeviceScanTimer = null;
        }
        delay(350).then(() => {
          scanMaskShow.value = false;
          handleScanResult(res.result);
        });
      },
      fail: err => {
        pendingDeviceScan.value = false;
        scanMaskStatus.value = "timeout";
        delay(900).then(() => {
          scanMaskShow.value = false;
        });
        if (pendingDeviceScanTimer) {
          clearTimeout(pendingDeviceScanTimer);
          pendingDeviceScanTimer = null;
        }
        console.error("扫码失败:", err);
        showToast("扫码失败,请重试");
      },
@@ -423,10 +451,6 @@
    showDate.value = false;
  };
  onShow(() => {
    // é¡µé¢æ˜¾ç¤ºæ—¶é€»è¾‘
  });
  onMounted(() => {
    // é¡µé¢åŠ è½½æ—¶èŽ·å–è®¾å¤‡åˆ—è¡¨
    loadDeviceName();
@@ -437,10 +461,12 @@
    if (scanTimer.value) {
      clearTimeout(scanTimer.value);
    }
    if (pdaScanTimer.value) {
      clearTimeout(pdaScanTimer.value);
    if (pendingDeviceScanTimer) {
      clearTimeout(pendingDeviceScanTimer);
      pendingDeviceScanTimer = null;
    }
    uni.$off("scan_repair_device");
    scanMaskShow.value = false;
    uni.$off("scan");
  });
  // æäº¤è¡¨å•
src/pages/equipmentManagement/upkeep/add.vue
@@ -85,8 +85,9 @@
                        @confirm="onDateConfirm"
                        @cancel="showDate = false"
                        mode="date" />
    <PdaScan :active="pdaScanActive"
             eventName="scan_upkeep_device" />
    <ScanWaitMask :show="scanMaskShow"
                  :status="scanMaskStatus" />
    <PdaScan />
  </view>
</template>
@@ -95,6 +96,7 @@
  import { onShow } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import CommonUpload from "@/components/CommonUpload.vue";
  import ScanWaitMask from "@/components/ScanWaitMask.vue";
  import PdaScan from "@/components/pda-scan/pda-scan.vue";
  import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
  import {
@@ -143,8 +145,51 @@
  // æ‰«ç ç›¸å…³çŠ¶æ€
  const isScanning = ref(false);
  const scanTimer = ref(null);
  const pdaScanActive = ref(false);
  const pdaScanTimer = ref(null);
  const pendingDeviceScan = ref(false);
  let pendingDeviceScanTimer = null;
  const scanMaskShow = ref(false);
  const scanMaskStatus = ref("waiting");
  const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
  const canUsePdaBroadcast = () => {
    try {
      if (typeof plus === "undefined") return false;
      if (plus?.os?.name !== "Android") return false;
      if (!plus?.android) return false;
      const sys = uni.getSystemInfoSync?.() || {};
      const brand = String(sys?.brand || "").toUpperCase();
      const model = String(sys?.model || "").toUpperCase();
      return (
        brand.includes("DROI") ||
        model.includes("MV-IDP5204") ||
        model.includes("IDP")
      );
    } catch (e) {
      return false;
    }
  };
  onShow(() => {
    uni.$off("scan");
    uni.$on("scan", data => {
      console.log("onscan");
      console.log("扫码结果:", data.code);
      if (!pendingDeviceScan.value) return;
      pendingDeviceScan.value = false;
      scanMaskStatus.value = "done";
      if (pendingDeviceScanTimer) {
        clearTimeout(pendingDeviceScanTimer);
        pendingDeviceScanTimer = null;
      }
      delay(350).then(() => {
        scanMaskShow.value = false;
        processScanResult(data.code);
      });
    });
    getPageParams();
  });
  // è¡¨å•验证规则
  const formRules = {
@@ -210,62 +255,47 @@
  // æ‰«æäºŒç»´ç åŠŸèƒ½
  const startScan = () => {
    if (isScanning.value) {
      showToast("正在扫描中,请稍候...");
      return;
    pendingDeviceScan.value = true;
    scanMaskStatus.value = "waiting";
    scanMaskShow.value = true;
    if (pendingDeviceScanTimer) {
      clearTimeout(pendingDeviceScanTimer);
      pendingDeviceScanTimer = null;
    }
    const canUsePdaBroadcast = () => {
      try {
        if (typeof plus === "undefined") return false;
        if (plus?.os?.name !== "Android") return false;
        if (!plus?.android) return false;
        const sys = uni.getSystemInfoSync?.() || {};
        const brand = String(sys?.brand || "").toUpperCase();
        const model = String(sys?.model || "").toUpperCase();
        return (
          brand.includes("DROI") ||
          model.includes("MV-IDP5204") ||
          model.includes("IDP")
        );
      } catch (e) {
        return false;
      }
    };
    if (canUsePdaBroadcast()) {
      if (pdaScanTimer.value) {
        clearTimeout(pdaScanTimer.value);
        pdaScanTimer.value = null;
      }
      uni.$off("scan_upkeep_device");
      uni.$on("scan_upkeep_device", data => {
        pdaScanActive.value = false;
        uni.$off("scan_upkeep_device");
        if (pdaScanTimer.value) {
          clearTimeout(pdaScanTimer.value);
          pdaScanTimer.value = null;
        }
        handleScanResult(data?.code);
    pendingDeviceScanTimer = setTimeout(() => {
      pendingDeviceScan.value = false;
      pendingDeviceScanTimer = null;
      scanMaskStatus.value = "timeout";
      delay(900).then(() => {
        scanMaskShow.value = false;
      });
      pdaScanActive.value = true;
      uni.showToast({ title: "请使用PDA扫码", icon: "none" });
      pdaScanTimer.value = setTimeout(() => {
        pdaScanActive.value = false;
        uni.$off("scan_upkeep_device");
        pdaScanTimer.value = null;
      }, 20000);
      return;
    }
    }, 20000);
    if (canUsePdaBroadcast()) return;
    uni.scanCode({
      scanType: ["qrCode", "barCode"],
      success: res => {
        handleScanResult(res.result);
        pendingDeviceScan.value = false;
        scanMaskStatus.value = "done";
        if (pendingDeviceScanTimer) {
          clearTimeout(pendingDeviceScanTimer);
          pendingDeviceScanTimer = null;
        }
        delay(350).then(() => {
          scanMaskShow.value = false;
          handleScanResult(res.result);
        });
      },
      fail: err => {
        pendingDeviceScan.value = false;
        scanMaskStatus.value = "timeout";
        delay(900).then(() => {
          scanMaskShow.value = false;
        });
        if (pendingDeviceScanTimer) {
          clearTimeout(pendingDeviceScanTimer);
          pendingDeviceScanTimer = null;
        }
        console.error("扫码失败:", err);
        showToast("扫码失败,请重试");
      },
@@ -342,11 +372,6 @@
    showDate.value = false;
  };
  onShow(() => {
    // é¡µé¢æ˜¾ç¤ºæ—¶èŽ·å–å‚æ•°
    getPageParams();
  });
  onMounted(() => {
    // é¡µé¢åŠ è½½æ—¶èŽ·å–è®¾å¤‡åˆ—è¡¨å’Œå‚æ•°
    loadDeviceName();
@@ -358,10 +383,12 @@
    if (scanTimer.value) {
      clearTimeout(scanTimer.value);
    }
    if (pdaScanTimer.value) {
      clearTimeout(pdaScanTimer.value);
    if (pendingDeviceScanTimer) {
      clearTimeout(pendingDeviceScanTimer);
      pendingDeviceScanTimer = null;
    }
    uni.$off("scan_upkeep_device");
    scanMaskShow.value = false;
    uni.$off("scan");
  });
  // æäº¤è¡¨å•
src/pages/inspectionUpload/upload.vue
@@ -65,12 +65,9 @@
        <PdaMediaUpload v-model="beforeModelValue"
                        :action="uploadFileUrl"
                        :limit="uploadConfig.limit"
                        :fileSize="uploadConfig.fileSize"
                        :uploadType="10"
                        :formData="{ type: 10 }"
                        :allowCamera="true"
                        :allowVideo="true"
                        @update:modelValue="handleFilesUpdate"
                        @choose-media="handleChooseMedia"
                        @uploading="uploading = $event"
                        @progress="uploadProgress = $event" />
        <!-- ç»Ÿè®¡ä¿¡æ¯ -->
@@ -107,7 +104,7 @@
<script setup>
  import { ref, computed, onMounted } from "vue";
  import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
  import { onLoad } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import PdaMediaUpload from "@/components/pda-media-upload/pda-media-upload.vue";
  import { uploadInspectionTask } from "@/api/inspectionManagement";
@@ -526,40 +523,14 @@
      },
    });
    // ç›‘听上传进度
    uploadTask.onProgressUpdate(res => {
      uploadProgress.value = res.progress;
    });
  };
  // ç›‘听文件列表变化(组件内部处理删除,父组件只同步)
  const handleFilesUpdate = files => {
    beforeModelValue.value = files;
  };
  // ç›‘听组件的 choose-media äº‹ä»¶ï¼ˆç”¨äºŽå…¼å®¹æ—§é€»è¾‘,或者在这里添加自定义操作)
  const handleChooseMedia = type => {
    // å¯ä»¥åœ¨è¿™é‡Œæ·»åŠ è‡ªå®šä¹‰çš„å‰ç½®æ“ä½œ
    console.log("用户选择上传类型:", type);
  };
  // PDA æ‰«ç ç›‘听(可选:如果需要通过扫码添加某个标签或信息,在这里处理)
  const handlePdaScan = data => {
    console.log("PDA æ‰«ç ç»“æžœ:", data);
    uni.showToast({
      title: `扫码结果: ${data.code}`,
      icon: "none",
    });
  };
  onShow(() => {
    // é¡µé¢æ˜¾ç¤ºæ—¶ï¼Œç›‘听 PDA æ‰«ç ï¼ˆå¦‚果有需要的话)
    uni.$on("scan_inspection", handlePdaScan);
  });
  onHide(() => {
    uni.$off("scan_inspection");
  });
</script>
<style scoped>
src/pages/works.vue
@@ -299,17 +299,20 @@
        </up-grid>
      </view>
    </view>
    <PdaScan :active="pdaScanActive"
             eventName="scan_work_report" />
    <ScanWaitMask :show="scanMaskShow"
                  :status="scanMaskStatus" />
    <PdaScan />
    <DownloadProgressMask />
  </view>
</template>
<script setup>
  import { ref, onMounted, nextTick, reactive, computed } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { userLoginFacotryList } from "@/api/login";
  import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
  import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
  import ScanWaitMask from "@/components/ScanWaitMask.vue";
  import PdaScan from "@/components/pda-scan/pda-scan.vue";
  import modal from "@/plugins/modal";
  import useUserStore from "@/store/modules/user";
@@ -318,8 +321,11 @@
  const show = ref(false);
  const factoryList = ref([]);
  const factoryListTem = ref([]);
  const pdaScanActive = ref(false);
  const pendingWorkReportScan = ref(false);
  let scanWorkReportTimer = null;
  const scanMaskShow = ref(false);
  const scanMaskStatus = ref("waiting");
  const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
  const iconStyle = {
    fontSize: "1.125rem",
    color: "#2979ff",
@@ -1076,124 +1082,153 @@
        factoryList.value = [];
      });
  }
  const getcode = async () => {
    const canUsePdaBroadcast = () => {
  const canUsePdaBroadcast = () => {
    try {
      if (typeof plus === "undefined") return false;
      if (plus?.os?.name !== "Android") return false;
      if (!plus?.android) return false;
      const sys = uni.getSystemInfoSync?.() || {};
      const brand = String(sys?.brand || "").toUpperCase();
      const model = String(sys?.model || "").toUpperCase();
      return (
        brand.includes("DROI") ||
        model.includes("MV-IDP5204") ||
        model.includes("IDP")
      );
    } catch (e) {
      return false;
    }
  };
  const handleWorkReportScan = async scanResultRaw => {
    const scanResult = scanResultRaw == null ? "" : String(scanResultRaw);
    let orderRow = "";
    const isNumericId = /^\d+$/.test(scanResult.trim());
    if (isNumericId) {
      const workOrderId = scanResult.trim();
      modal.loading("正在获取工单信息...");
      try {
        if (typeof plus === "undefined") return false;
        if (plus?.os?.name !== "Android") return false;
        if (!plus?.android) return false;
        const workRes = await getProductWorkOrderById({ id: workOrderId });
        modal.closeLoading();
        const sys = uni.getSystemInfoSync?.() || {};
        const brand = String(sys?.brand || "").toUpperCase();
        const model = String(sys?.model || "").toUpperCase();
        console.log("工单查询结果:", workRes);
        return (
          brand.includes("DROI") ||
          model.includes("MV-IDP5204") ||
          model.includes("IDP")
        );
      } catch (e) {
        return false;
      }
    };
        if (workRes.code === 200 && workRes.data) {
          const workData = workRes.data;
          console.log("工单数据:", workData);
    const handleWorkReportScan = async scanResultRaw => {
      const scanResult = scanResultRaw == null ? "" : String(scanResultRaw);
      let orderRow = "";
      const isNumericId = /^\d+$/.test(scanResult.trim());
      if (isNumericId) {
        const workOrderId = scanResult.trim();
        modal.loading("正在获取工单信息...");
        try {
          const workRes = await getProductWorkOrderById({ id: workOrderId });
          modal.closeLoading();
          console.log("工单查询结果:", workRes);
          if (workRes.code === 200 && workRes.data) {
            const workData = workRes.data;
            console.log("工单数据:", workData);
            if (workData.endOrder === true) {
              modal.msgError("该订单已结束,无法报工");
              return;
            }
            orderRow = JSON.stringify(workData);
            console.log("构造的orderRow:", orderRow);
          } else {
            modal.msgError("未找到对应的工单信息");
          if (workData.endOrder === true) {
            modal.msgError("该订单已结束,无法报工");
            return;
          }
        } catch (error) {
          modal.closeLoading();
          console.error("获取工单信息失败:", error);
          modal.msgError("获取工单信息失败: " + (error.message || "未知错误"));
          return;
        }
      } else {
        try {
          const orderRowStart = scanResult.indexOf("orderRow={");
          if (orderRowStart !== -1) {
            const jsonPart = scanResult.substring(orderRowStart + 9);
            orderRow = jsonPart;
          } else {
            orderRow = scanResult;
          }
        } catch (e) {
          console.error(e, "解析失败====????=====");
          orderRow = "";
        }
        try {
          JSON.parse(orderRow);
        } catch (error) {
          modal.msgError("订单解析失败,请检查二维码格式");
          orderRow = JSON.stringify(workData);
          console.log("构造的orderRow:", orderRow);
        } else {
          modal.msgError("未找到对应的工单信息");
          return;
        }
      } catch (error) {
        modal.closeLoading();
        console.error("获取工单信息失败:", error);
        modal.msgError("获取工单信息失败: " + (error.message || "未知错误"));
        return;
      }
    } else {
      try {
        const orderRowStart = scanResult.indexOf("orderRow={");
        if (orderRowStart !== -1) {
          const jsonPart = scanResult.substring(orderRowStart + 9);
          orderRow = jsonPart;
        } else {
          orderRow = scanResult;
        }
      } catch (e) {
        console.error(e, "解析失败====????=====");
        orderRow = "";
      }
      uni.navigateTo({
        url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`,
      });
    };
      try {
        JSON.parse(orderRow);
      } catch (error) {
        modal.msgError("订单解析失败,请检查二维码格式");
        return;
      }
    }
    if (canUsePdaBroadcast()) {
    uni.navigateTo({
      url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`,
    });
  };
  onShow(() => {
    uni.$off("scan");
    uni.$on("scan", async data => {
      console.log("onscan");
      console.log("扫码结果:", data.code);
      if (!pendingWorkReportScan.value) return;
      pendingWorkReportScan.value = false;
      scanMaskStatus.value = "done";
      if (scanWorkReportTimer) {
        clearTimeout(scanWorkReportTimer);
        scanWorkReportTimer = null;
      }
      uni.$off("scan_work_report");
      uni.$on("scan_work_report", async data => {
        pdaScanActive.value = false;
        uni.$off("scan_work_report");
      await delay(350);
      scanMaskShow.value = false;
      await handleWorkReportScan(data?.code);
    });
  });
  const getcode = async () => {
    pendingWorkReportScan.value = true;
    scanMaskStatus.value = "waiting";
    scanMaskShow.value = true;
    if (scanWorkReportTimer) {
      clearTimeout(scanWorkReportTimer);
      scanWorkReportTimer = null;
    }
    scanWorkReportTimer = setTimeout(() => {
      pendingWorkReportScan.value = false;
      scanWorkReportTimer = null;
      scanMaskStatus.value = "timeout";
      delay(900).then(() => {
        scanMaskShow.value = false;
      });
    }, 20000);
    if (canUsePdaBroadcast()) return;
    uni.scanCode({
      success: async res => {
        pendingWorkReportScan.value = false;
        scanMaskStatus.value = "done";
        if (scanWorkReportTimer) {
          clearTimeout(scanWorkReportTimer);
          scanWorkReportTimer = null;
        }
        await handleWorkReportScan(data?.code);
      });
      pdaScanActive.value = true;
      uni.showToast({
        title: "请使用PDA扫码",
        icon: "none",
      });
      scanWorkReportTimer = setTimeout(() => {
        pdaScanActive.value = false;
        uni.$off("scan_work_report");
        scanWorkReportTimer = null;
      }, 20000);
      return;
    }
    uni.scanCode({
      success: async res => {
        await delay(350);
        scanMaskShow.value = false;
        await handleWorkReportScan(res.result);
      },
      fail: err => {
        pendingWorkReportScan.value = false;
        scanMaskStatus.value = "timeout";
        delay(900).then(() => {
          scanMaskShow.value = false;
        });
        if (scanWorkReportTimer) {
          clearTimeout(scanWorkReportTimer);
          scanWorkReportTimer = null;
        }
        uni.showToast({
          title: "扫码失败",
          icon: "none",