From 9f1324fb9e73e5b53ac67542227e63cdc0b505ba Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 09 七月 2026 15:44:53 +0800
Subject: [PATCH] 手机扫码改为PDA扫码

---
 src/pages/inspectionUpload/upload.vue                |  116 +---
 src/pages/works.vue                                  |  166 ++++--
 src/pages/equipmentManagement/upkeep/add.vue         |   57 ++
 src/components/pda-scan/pda-scan.vue                 |  137 ++++++
 doc/uniapp-pda-scan.md                               |  341 +++++++++++++++
 src/pages/equipmentManagement/repair/add.vue         |   57 ++
 src/components/pda-media-upload/pda-media-upload.vue |  396 ++++++++++++++++++
 7 files changed, 1,132 insertions(+), 138 deletions(-)

diff --git a/doc/uniapp-pda-scan.md b/doc/uniapp-pda-scan.md
new file mode 100644
index 0000000..b35c852
--- /dev/null
+++ b/doc/uniapp-pda-scan.md
@@ -0,0 +1,341 @@
+# uni-app PDA 鎵爜锛圓ndroid 骞挎挱锛夋帴鍏ユ墜鍐�
+
+閫傜敤鍦烘櫙锛氬伐涓� PDA / 鎵弿鏋澶団�滄寜涓嬬墿鐞嗘壂鐮侀敭鍚庯紝鐢辩郴缁熶互骞挎挱锛圔roadcast锛夋柟寮忚緭鍑烘壂鐮佸唴瀹光�濈殑妯″紡銆�  
+鐩爣鏁堟灉锛氶〉闈㈠彧闇�瑕佸紩鍏ヤ竴涓粍浠跺苟鐩戝惉涓�涓簨浠讹紝灏辫兘鍍忔湰椤圭洰涓�鏍锋帴鏀� PDA 鎵爜缁撴灉锛涘悓鏃跺湪娌℃湁 PDA 鑳藉姏鐨勯」鐩腑鍙檷绾т负鐩告満鎵爜锛坄uni.scanCode`锛夈��
+
+---
+
+## 1. 鍘熺悊姒傝锛堟湰椤圭洰鐨勭敤娉曪級
+
+鏈」鐩殑 PDA 鎵爜閾捐矾鏄細
+
+- 缁勪欢鐩戝惉 Android 骞挎挱锛屾嬁鍒� `intent.getStringExtra(extraKey)` 鐨勫瓧绗︿覆
+- 灏嗘壂鐮佸瓧绗︿覆閫氳繃 `uni.$emit('scan', { code })` 鎶涗负鍏ㄥ眬浜嬩欢
+- 椤甸潰鍦� `onShow` 鏃� `uni.$on('scan', cb)` 鎺ユ敹锛屼笟鍔¢噷瑙f瀽 `data.code` 骞惰皟鐢ㄦ帴鍙�
+
+瀵瑰簲瀹炵幇鏂囦欢锛�
+
+- PDA 骞挎挱鐩戝惉缁勪欢锛歔scan.vue](file:///d:/newcode/mes-ocea-unapp/components/scan/scan.vue#L18-L91)
+- 椤甸潰鎺ユ敹绀轰緥锛歔productBack/index.vue](file:///d:/newcode/mes-ocea-unapp/pages/wareHouse/productBack/index.vue#L96-L127)
+
+---
+
+## 2. 鎺ュ叆鍓嶇疆鏉′欢
+
+**骞冲彴闄愬埗**
+
+- 浠呮敮鎸� `APP-PLUS`锛堟墦鍖呮垚 App锛変笖 `Android` 璁惧
+- H5 / 灏忕▼搴� / iOS 涓嶆敮鎸� `plus.android`锛岄渶瑕佽蛋鐩告満鎵爜闄嶇骇鏂规
+
+**浣犲繀椤绘嬁鍒拌澶囩殑涓ら」閰嶇疆**
+
+- `action`锛氭壂鐮佸箍鎾殑 Action锛堜緥濡傛湰椤圭洰鏌愪簺 PDA 涓� `com.service.scanner.data`锛�
+- `extraKey`锛氬箍鎾� Intent 涓瓨鏀炬壂鐮佸瓧绗︿覆鐨� key锛堜緥濡傛湰椤圭洰涓� `ScanCode`锛�
+
+鑾峰彇鏂瑰紡锛堟帹鑽愰『搴忥級锛�
+
+- 鏌ョ湅 PDA 鍘傚晢鎵弿鏈嶅姟/鎵弿璁剧疆閲岀殑鈥滃箍鎾緭鍑衡�濋厤缃紙閫氬父鑳界洿鎺ョ湅鍒� Action 涓� extraKey锛�
+- 鍚戣澶囧巶鍟�/闆嗘垚鍟嗙储瑕佸箍鎾崗璁紙鏈�鍙潬锛�
+- 涓存椂鍦ㄩ」鐩噷鎶� `action/extraKey` 鎵撴棩蹇楋紙鏈」鐩凡鎵撳嵃锛夛紝缁撳悎鍘傚晢鏂囨。纭
+
+---
+
+## 3. 鍙縼绉荤殑閫氱敤缁勪欢锛圴ue2/Vue3 閫氱敤锛�
+
+uni-app 鐨� Vue3 椤圭洰渚濈劧鏀寔 Options API锛屽洜姝ゆ帹鑽愮敤 Options API 鍐欎竴涓粍浠讹紝杈惧埌涓�浠界粍浠跺悓鏃跺吋瀹� Vue2 涓� Vue3銆�
+
+### 3.1 鏂板缁勪欢鏂囦欢
+
+鍦ㄤ綘鐨勭洰鏍囬」鐩腑鏂板缓锛�
+
+- `components/pda-scan/pda-scan.vue`
+
+鍐呭濡備笅锛堝彲鐩存帴澶嶅埗锛夛細
+
+```vue
+<template>
+	<view />
+</template>
+
+<script>
+let mainActivity;
+let receiver;
+let intentFilter;
+let isRegistered = false;
+let lock = false;
+
+export default {
+	name: "pda-scan",
+	props: {
+		eventName: {
+			type: String,
+			default: "scan"
+		},
+		action: {
+			type: String,
+			default: ""
+		},
+		extraKey: {
+			type: String,
+			default: ""
+		},
+		debounceMs: {
+			type: Number,
+			default: 150
+		},
+		autoStart: {
+			type: Boolean,
+			default: true
+		}
+	},
+	created() {
+		this.init();
+	},
+	onHide() {
+		this.stop();
+	},
+	beforeDestroy() {
+		this.stop();
+	},
+	beforeUnmount() {
+		this.stop();
+	},
+	methods: {
+		init() {
+			// #ifdef APP-PLUS
+			if (!this.autoStart) return;
+			if (!plus || plus.os.name !== "Android") return;
+
+			uni.getSystemInfo({
+				success: (sys) => {
+					const cfg = this.resolveBroadcastConfig(sys);
+					if (!cfg.action || !cfg.extraKey) return;
+					this.initAndroidReceiver(cfg.action, cfg.extraKey);
+					this.start();
+				}
+			});
+			// #endif
+		},
+		resolveBroadcastConfig(sys) {
+			const brand = String(sys.brand || "").toUpperCase();
+			const model = String(sys.model || "").toUpperCase();
+
+			if (this.action && this.extraKey) {
+				return { action: this.action, extraKey: this.extraKey };
+			}
+
+			if (brand.indexOf("DROI") !== -1 || model.indexOf("MV-IDP5204") !== -1) {
+				return { action: "com.service.scanner.data", extraKey: "ScanCode" };
+			}
+
+			return { action: "", extraKey: "" };
+		},
+		initAndroidReceiver(action, extraKey) {
+			const _this = this;
+			mainActivity = plus.android.runtimeMainActivity();
+			const IntentFilter = plus.android.importClass("android.content.IntentFilter");
+			intentFilter = new IntentFilter();
+			intentFilter.addAction(action);
+
+			receiver = plus.android.implements("io.dcloud.feature.internal.reflect.BroadcastReceiver", {
+				onReceive(context, intent) {
+					plus.android.importClass(intent);
+					const code = intent.getStringExtra(extraKey);
+					_this.emitCode(code);
+				}
+			});
+		},
+		start() {
+			// #ifdef APP-PLUS
+			if (!plus || plus.os.name !== "Android") return;
+			if (!mainActivity || !receiver || !intentFilter) return;
+			if (isRegistered) return;
+			try {
+				mainActivity.registerReceiver(receiver, intentFilter);
+				isRegistered = true;
+			} catch (e) {}
+			// #endif
+		},
+		stop() {
+			// #ifdef APP-PLUS
+			if (!plus || plus.os.name !== "Android") return;
+			if (!mainActivity || !receiver) return;
+			if (!isRegistered) return;
+			try {
+				mainActivity.unregisterReceiver(receiver);
+			} catch (e) {}
+			isRegistered = false;
+			// #endif
+		},
+		emitCode(code) {
+			const value = code == null ? "" : String(code);
+			if (!value) return;
+
+			if (lock) return;
+			lock = true;
+			setTimeout(() => {
+				lock = false;
+			}, this.debounceMs);
+
+			uni.$emit(this.eventName, { code: value });
+		}
+	}
+};
+</script>
+```
+
+### 3.2 浣犻渶瑕佹敼鍝噷
+
+1) 璁惧閫傞厤锛堟渶鍏抽敭锛�  
+淇敼 `resolveBroadcastConfig()` 閲屽 `action/extraKey` 鐨勮繑鍥為�昏緫锛屽姞鍏ヤ綘璁惧鐨勫箍鎾厤缃��
+
+2) 涔熷彲浠ヤ笉鏀逛唬鐮侊紝鐩存帴浼犲弬瑕嗙洊锛堟帹鑽愮敤浜庡璁惧/澶氱幆澧冿級
+
+```vue
+<pda-scan action="浣犵殑action" extraKey="浣犵殑extraKey" />
+```
+
+---
+
+## 4. 椤甸潰渚х敤娉曪紙PDA 骞挎挱鎵爜锛�
+
+### 4.1 Vue2 椤甸潰锛圤ptions API锛夌ず渚�
+
+```vue
+<template>
+	<view>
+		<pda-scan />
+	</view>
+</template>
+
+<script>
+import PdaScan from "@/components/pda-scan/pda-scan.vue";
+
+export default {
+	components: { PdaScan },
+	data() {
+		return {
+			lastCode: ""
+		};
+	},
+	onShow() {
+		uni.$off("scan");
+		uni.$on("scan", (data) => {
+			this.handleScan(data.code);
+		});
+	},
+	onHide() {
+		uni.$off("scan");
+	},
+	methods: {
+		handleScan(code) {
+			this.lastCode = code;
+		}
+	}
+};
+</script>
+```
+
+### 4.2 Vue3 椤甸潰锛坄<script setup>`锛夌ず渚�
+
+```vue
+<template>
+	<view>
+		<pda-scan />
+	</view>
+</template>
+
+<script setup>
+import PdaScan from "@/components/pda-scan/pda-scan.vue";
+import { onShow, onHide } from "@dcloudio/uni-app";
+
+function handleScan(code) {}
+
+onShow(() => {
+	uni.$off("scan");
+	uni.$on("scan", (data) => {
+		handleScan(data.code);
+	});
+});
+
+onHide(() => {
+	uni.$off("scan");
+});
+</script>
+```
+
+---
+
+## 5. 鐩告満鎵爜闄嶇骇锛堟病鏈� PDA 渚濊禆涔熻兘鐢級
+
+褰撻」鐩窇鍦ㄩ潪 `APP-PLUS`銆佹垨 iOS銆佹垨娌℃湁閰嶇疆 `action/extraKey` 鏃讹紝PDA 骞挎挱涓嶄細鐢熸晥銆傚缓璁彁渚涗竴涓寜閽蛋鐩告満鎵爜锛�
+
+```js
+function goCameraScan() {
+	uni.scanCode({
+		success: (res) => {
+			handleScan(res.result);
+		}
+	});
+}
+```
+
+杩欐牱浣犵殑涓氬姟澶勭悊鍑芥暟鍙鍐欎竴娆★細`handleScan(code)`銆�
+
+---
+
+## 6. 涓氬姟渚цВ鏋愬缓璁紙鍏煎鈥滅函瀛楃涓叉潯鐮� / JSON 浜岀淮鐮佲�濓級
+
+鏈」鐩涓〉闈㈢殑鎯敤妯″紡鏄細
+
+- 濡傛灉 `code` 鏄� JSON锛堜緥濡傚寘鍚� `sn_no` / `lot_batch_no`锛夛紝鍏� `JSON.parse`
+- 涓嶆槸 JSON 灏卞綋鍋氭櫘閫氭潯鐮佸瓧绗︿覆
+
+鍙洿鎺ュ鐢ㄤ笅闈㈢殑瑙f瀽鍑芥暟锛�
+
+```js
+function normalizeScanText(raw) {
+	if (raw == null) return "";
+	return String(raw).replace(/\n/g, "").replace(/\s*/g, "").trim();
+}
+
+function parseScan(raw) {
+	const text = normalizeScanText(raw);
+	if (!text) return { text: "", data: null };
+	try {
+		const data = JSON.parse(text);
+		return { text, data };
+	} catch (e) {
+		return { text, data: null };
+	}
+}
+```
+
+---
+
+## 7. 甯歌闂鎺掓煡娓呭崟
+
+- App 杩愯鍦� H5/灏忕▼搴忕幆澧冿細涓嶄細瑙﹀彂骞挎挱鐩戝惉锛堝彧鑳界浉鏈烘壂鐮侊級
+- iOS锛氫笉鏀寔 `plus.android`
+- Android 璁惧鎵爜娌″弽搴旓細
+  - 璁惧鏄惁寮�鍚簡鈥滃箍鎾緭鍑衡��
+  - `action/extraKey` 鏄惁鍖归厤锛堜竴涓瓧绗︿笉瀵归兘鏀朵笉鍒�/鍙栦笉鍒扮爜锛�
+  - 鏄惁瀛樺湪澶氫釜椤甸潰鍚屾椂 `uni.$on('scan')` 瀵艰嚧閫昏緫涓叉壈锛堝缓璁〉闈� `onShow` 鍏� `uni.$off`锛�
+- 鎶ラ敊 `unregisterReceiver`锛�
+  - 澶氬彂鐢熷湪鈥滄湭 register 灏� unregister鈥濓紝缁勪欢閲屽凡鍋� `isRegistered` 涓� try/catch 淇濇姢锛涘鏋滀綘鏀逛唬鐮佸悗鍙堝嚭鐜帮紝浼樺厛妫�鏌� `start/stop` 鏄惁琚噸澶嶈皟鐢�
+
+---
+
+## 8. 涓庢湰椤圭洰淇濇寔涓�鑷寸殑浜嬩欢鍗忚
+
+涓轰簡璁╀綘鍦ㄥ叾浠栭」鐩噷澶嶅埢鈥滄嬁鍒版壂鐮佸悗椤甸潰鐩存帴澶勭悊鈥濈殑浣撻獙锛屽缓璁繚鎸侊細
+
+- 浜嬩欢鍚嶏細`scan`
+- 浜嬩欢鍙傛暟锛歚{ code: string }`
+
+濡傛灉浣犺鏀逛簨浠跺悕锛堜緥濡傚涓壂鐮佹簮鍖哄垎锛夛紝缁勪欢鎻愪緵浜� `eventName`锛�
+
+```vue
+<pda-scan eventName="scan_pda" />
+```
+
diff --git a/src/components/pda-media-upload/pda-media-upload.vue b/src/components/pda-media-upload/pda-media-upload.vue
new file mode 100644
index 0000000..c9fd8e5
--- /dev/null
+++ b/src/components/pda-media-upload/pda-media-upload.vue
@@ -0,0 +1,396 @@
+<template>
+  <view class="pda-media-upload">
+    <view class="upload-buttons">
+      <u-button type="primary"
+                @click="pickMedia('image')"
+                :loading="uploading"
+                :disabled="disabled || modelValue.length >= limit"
+                :customStyle="{ marginRight: '10px', flex: 1 }">
+        <u-icon name="camera"
+                size="18"
+                color="#fff"
+                style="margin-right: 5px"></u-icon>
+        {{ uploading ? "涓婁紶涓�..." : "鎷嶇収" }}
+      </u-button>
+      <u-button type="success"
+                @click="pickMedia('video')"
+                :loading="uploading"
+                :disabled="disabled || modelValue.length >= limit"
+                :customStyle="{ flex: 1 }">
+        <uni-icons type="videocam"
+                   size="18"
+                   color="#fff"
+                   style="margin-right: 5px"></uni-icons>
+        {{ uploading ? "涓婁紶涓�..." : "鎷嶈棰�" }}
+      </u-button>
+    </view>
+    <view v-if="uploading"
+          class="upload-progress">
+      <u-line-progress :percentage="uploadProgress"
+                       :showText="true"
+                       activeColor="#409eff"></u-line-progress>
+    </view>
+    <view v-if="modelValue.length > 0"
+          class="file-list">
+      <view v-for="(file, index) in modelValue"
+            :key="index"
+            class="file-item">
+        <view class="file-preview-container">
+          <image v-if="file.type === 'image' || (file.type !== 'video' && !file.type)"
+                 :src="file.url || file.tempFilePath || file.path || file.downloadUrl"
+                 class="file-preview"
+                 mode="aspectFill" />
+          <view v-else-if="file.type === 'video'"
+                class="video-preview">
+            <uni-icons type="videocam"
+                       size="18"
+                       color="#fff"
+                       style="margin-right: 5px"></uni-icons>
+            <text class="video-text">瑙嗛</text>
+          </view>
+          <view class="delete-btn"
+                @click="removeFile(index)">
+            <u-icon name="close"
+                    size="12"
+                    color="#fff"></u-icon>
+          </view>
+        </view>
+        <view class="file-info">
+          <text class="file-name">{{ file.bucketFilename || file.name || (file.type === 'image' ? '鍥剧墖' : '瑙嗛') }}</text>
+          <text class="file-size">{{ formatFileSize(file.size) }}</text>
+        </view>
+      </view>
+    </view>
+    <view v-else
+          class="empty-state">
+      <text>璇烽�夋嫨瑕佷笂浼犵殑鍥剧墖鎴栬棰�</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref } from "vue";
+  import { getToken } from "@/utils/auth";
+
+  const props = defineProps({
+    modelValue: { type: Array, default: () => [] },
+    action: { type: String, default: "" },
+    uploadUrl: { type: String, default: "" },
+    limit: { type: Number, default: 10 },
+    uploadType: { type: Number, default: 10 },
+    formData: { type: Object, default: () => ({}) },
+    disabled: { type: Boolean, default: false },
+  });
+
+  const emit = defineEmits([
+    "update:modelValue",
+    "uploaded",
+    "uploading",
+    "progress",
+    "choose-media",
+  ]);
+
+  const uploading = ref(false);
+  const uploadProgress = ref(0);
+
+  // 鐩戝惉涓婁紶鐘舵�侊紝鍙戝嚭浜嬩欢
+  const watchUploading = val => {
+    emit("uploading", val);
+  };
+  // 鐩戝惉杩涘害锛屽彂鍑轰簨浠�
+  const watchProgress = val => {
+    emit("progress", val);
+  };
+
+  const showToast = message => {
+    uni.showToast({ title: message, icon: "none" });
+  };
+
+  const updateList = list => {
+    emit("update:modelValue", list);
+  };
+
+  const formatFileSize = size => {
+    if (!size) return "0 B";
+    const units = ["B", "KB", "MB", "GB"];
+    let index = 0;
+    let fileSize = size;
+    while (fileSize >= 1024 && index < units.length - 1) {
+      fileSize /= 1024;
+      index++;
+    }
+    return `${fileSize.toFixed(2)} ${units[index]}`;
+  };
+
+  const removeFile = index => {
+    const next = props.modelValue.slice();
+    next.splice(index, 1);
+    updateList(next);
+  };
+
+  const uploadFile = file => {
+    const url = props.action || props.uploadUrl;
+    if (!url) {
+      showToast("鏈厤缃笂浼犲湴鍧�");
+      return;
+    }
+
+    const token = getToken();
+    if (!token) {
+      showToast("鐢ㄦ埛鏈櫥褰�");
+      return;
+    }
+
+    uploading.value = true;
+    watchUploading(true);
+    uploadProgress.value = 0;
+    watchProgress(0);
+
+    const uploadTask = uni.uploadFile({
+      url: url,
+      filePath: file.tempFilePath,
+      name: "files",
+      header: {
+        Authorization: `Bearer ${token}`,
+      },
+      formData: {
+        type: props.uploadType,
+        ...props.formData,
+      },
+      success: res => {
+        try {
+          const data = JSON.parse(res.data);
+          if (data.code === 200) {
+            const resultData = Array.isArray(data.data)
+              ? data.data[0]
+              : data.data;
+            const finalUrl = resultData.url || resultData.previewURL;
+            const finalName = resultData.name || resultData.originalFilename;
+            const finalId =
+              resultData.tempId || resultData.id || resultData.tempFileId;
+
+            const uploadedFile = {
+              ...file,
+              ...resultData,
+              url: finalUrl,
+              name: finalName,
+              tempId: finalId,
+              status: "success",
+            };
+
+            updateList(props.modelValue.concat([uploadedFile]));
+            emit("uploaded", uploadedFile);
+            uni.showToast({ title: "涓婁紶鎴愬姛", icon: "success" });
+          } else {
+            showToast(data.msg || "涓婁紶澶辫触");
+          }
+        } catch (e) {
+          showToast("瑙f瀽鍝嶅簲澶辫触");
+        }
+      },
+      fail: err => {
+        console.error("涓婁紶澶辫触:", err);
+        showToast("涓婁紶澶辫触");
+      },
+      complete: () => {
+        uploading.value = false;
+        watchUploading(false);
+      },
+    });
+
+    uploadTask.onProgressUpdate(res => {
+      uploadProgress.value = res.progress;
+      watchProgress(res.progress);
+    });
+  };
+
+  const pickMedia = type => {
+    emit("choose-media", type);
+
+    if (props.modelValue.length >= props.limit) {
+      showToast(`鏈�澶氬彧鑳介�夋嫨${props.limit}涓枃浠禶);
+      return;
+    }
+
+    const remaining = props.limit - props.modelValue.length;
+
+    if (typeof uni.chooseMedia === "function") {
+      uni.chooseMedia({
+        count: Math.min(remaining, 1),
+        mediaType: [type || "image"],
+        sizeType: ["compressed", "original"],
+        sourceType: ["camera"],
+        success: res => {
+          try {
+            const files = res?.tempFiles || [];
+            if (!files.length) throw new Error("鏈幏鍙栧埌鏂囦欢");
+
+            files.forEach((tf, idx) => {
+              const filePath = tf.tempFilePath || tf.path || "";
+              const fileType = tf.fileType || type || "image";
+              const ext = fileType === "video" ? "mp4" : "jpg";
+              const file = {
+                tempFilePath: filePath,
+                path: filePath,
+                type: fileType,
+                name: `${fileType}_${Date.now()}_${idx}.${ext}`,
+                size: tf.size || 0,
+                duration: tf.duration || 0,
+                createTime: Date.now(),
+              };
+              uploadFile(file);
+            });
+          } catch (err) {
+            showToast(err.message || "澶勭悊鏂囦欢澶辫触");
+          }
+        },
+        fail: err => {
+          console.error("閫夋嫨濯掍綋澶辫触:", err);
+          showToast("閫夋嫨澶辫触");
+        },
+      });
+      return;
+    }
+
+    if (type === "video") {
+      uni.chooseVideo({
+        sourceType: ["camera"],
+        success: res => {
+          const file = {
+            tempFilePath: res.tempFilePath,
+            path: res.tempFilePath,
+            type: "video",
+            name: `video_${Date.now()}.mp4`,
+            size: res.size || 0,
+            duration: res.duration || 0,
+            createTime: Date.now(),
+          };
+          uploadFile(file);
+        },
+        fail: () => {
+          showToast("閫夋嫨瑙嗛澶辫触");
+        },
+      });
+      return;
+    }
+
+    uni.chooseImage({
+      count: Math.min(remaining, 9),
+      sizeType: ["compressed"],
+      sourceType: ["camera"],
+      success: res => {
+        const list = res.tempFilePaths || res.tempFiles || [];
+        list.forEach((src, idx) => {
+          const path = typeof src === "string" ? src : src.path;
+          const file = {
+            tempFilePath: path,
+            path: path,
+            type: "image",
+            name: `image_${Date.now()}_${idx}.jpg`,
+            size: 0,
+            createTime: Date.now(),
+          };
+          uploadFile(file);
+        });
+      },
+      fail: () => {
+        showToast("閫夋嫨鍥剧墖澶辫触");
+      },
+    });
+  };
+</script>
+
+<style scoped>
+  .upload-buttons {
+    display: flex;
+  }
+
+  .upload-progress {
+    margin-top: 12px;
+  }
+
+  .file-list {
+    margin-top: 12px;
+  }
+
+  .file-item {
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    background: #f7f8fa;
+    border-radius: 10px;
+    margin-bottom: 10px;
+  }
+
+  .file-preview-container {
+    position: relative;
+    width: 60px;
+    height: 60px;
+    border-radius: 8px;
+    overflow: hidden;
+    margin-right: 12px;
+    background: #e9edf2;
+  }
+
+  .file-preview {
+    width: 100%;
+    height: 100%;
+  }
+
+  .video-preview {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: rgba(0, 0, 0, 0.5);
+  }
+
+  .video-text {
+    font-size: 12px;
+    color: #fff;
+  }
+
+  .delete-btn {
+    position: absolute;
+    top: 4px;
+    right: 4px;
+    width: 18px;
+    height: 18px;
+    border-radius: 9px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: rgba(0, 0, 0, 0.5);
+  }
+
+  .file-info {
+    flex: 1;
+    min-width: 0;
+    display: flex;
+    flex-direction: column;
+    gap: 4px;
+  }
+
+  .file-name {
+    font-size: 13px;
+    color: #333;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .file-size {
+    font-size: 12px;
+    color: #999;
+  }
+
+  .empty-state {
+    margin-top: 12px;
+    padding: 14px 0;
+    text-align: center;
+    color: #999;
+    font-size: 13px;
+  }
+</style>
+
diff --git a/src/components/pda-scan/pda-scan.vue b/src/components/pda-scan/pda-scan.vue
new file mode 100644
index 0000000..341200f
--- /dev/null
+++ b/src/components/pda-scan/pda-scan.vue
@@ -0,0 +1,137 @@
+<template>
+  <view />
+</template>
+
+<script>
+  let mainActivity;
+  let receiver;
+  let intentFilter;
+  let isRegistered = false;
+  let lock = false;
+
+  export default {
+    name: "PdaScan",
+    props: {
+      active: { type: Boolean, default: true },
+      eventName: { type: String, default: "scan" },
+      action: { type: String, default: "" },
+      extraKey: { type: String, default: "" },
+      debounceMs: { type: Number, default: 150 },
+    },
+    mounted() {
+      this.init();
+      if (this.active) this.start();
+    },
+    beforeUnmount() {
+      this.stop();
+    },
+    watch: {
+      active(val) {
+        if (val) {
+          this.init();
+          this.start();
+        } else {
+          this.stop();
+        }
+      },
+    },
+    methods: {
+      canUseAndroidBroadcast() {
+        try {
+          if (typeof plus === "undefined") return false;
+          if (!plus.os || plus.os.name !== "Android") return false;
+          if (!plus.android) return false;
+          return true;
+        } catch (e) {
+          return false;
+        }
+      },
+      resolveBroadcastConfig(sys) {
+        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: "" };
+      },
+      init() {
+        if (!this.canUseAndroidBroadcast()) return;
+        if (mainActivity && receiver && intentFilter) return;
+
+        let sys = {};
+        try {
+          sys = uni.getSystemInfoSync() || {};
+        } catch (e) {
+          sys = {};
+        }
+
+        const cfg = this.resolveBroadcastConfig(sys);
+        if (!cfg.action || !cfg.extraKey) return;
+        this.initAndroidReceiver(cfg.action, cfg.extraKey);
+      },
+      initAndroidReceiver(action, extraKey) {
+        const _this = this;
+        mainActivity = plus.android.runtimeMainActivity();
+        const IntentFilter = plus.android.importClass(
+          "android.content.IntentFilter"
+        );
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(action);
+
+        receiver = plus.android.implements(
+          "io.dcloud.feature.internal.reflect.BroadcastReceiver",
+          {
+            onReceive(context, intent) {
+              plus.android.importClass(intent);
+              const code = intent.getStringExtra(extraKey);
+              _this.emitCode(code);
+            },
+          }
+        );
+      },
+      start() {
+        if (!this.canUseAndroidBroadcast()) return;
+        if (!mainActivity || !receiver || !intentFilter) return;
+        if (isRegistered) return;
+        try {
+          mainActivity.registerReceiver(receiver, intentFilter);
+          isRegistered = true;
+        } catch (e) {}
+      },
+      stop() {
+        if (!this.canUseAndroidBroadcast()) return;
+        if (!mainActivity || !receiver) return;
+        if (!isRegistered) return;
+        try {
+          mainActivity.unregisterReceiver(receiver);
+        } catch (e) {}
+        isRegistered = false;
+      },
+      emitCode(code) {
+        const value = code == null ? "" : String(code);
+        const text = value.replace(/\n/g, "").trim();
+        if (!text) return;
+
+        if (lock) return;
+        lock = true;
+        setTimeout(() => {
+          lock = false;
+        }, this.debounceMs);
+
+        const payload = { code: text };
+        uni.$emit(this.eventName, payload);
+        this.$emit("scan", payload);
+      },
+    },
+  };
+</script>
diff --git a/src/pages/equipmentManagement/repair/add.vue b/src/pages/equipmentManagement/repair/add.vue
index 39ab9a4..4e15bf3 100644
--- a/src/pages/equipmentManagement/repair/add.vue
+++ b/src/pages/equipmentManagement/repair/add.vue
@@ -129,6 +129,8 @@
                         @confirm="onDateConfirm"
                         @cancel="showDate = false"
                         mode="date" />
+    <PdaScan :active="pdaScanActive"
+             eventName="scan_repair_device" />
   </view>
 </template>
 
@@ -137,6 +139,7 @@
   import { onShow, onLoad } from "@dcloudio/uni-app";
   import PageHeader from "@/components/PageHeader.vue";
   import CommonUpload from "@/components/CommonUpload.vue";
+  import PdaScan from "@/components/pda-scan/pda-scan.vue";
   import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
   import {
     addRepair,
@@ -185,6 +188,8 @@
   // 鎵爜鐩稿叧鐘舵��
   const isScanning = ref(false);
   const scanTimer = ref(null);
+  const pdaScanActive = ref(false);
+  const pdaScanTimer = ref(null);
 
   // 琛ㄥ崟楠岃瘉瑙勫垯
   const formRules = {
@@ -296,7 +301,51 @@
       return;
     }
 
-    // 璋冪敤uni-app鐨勬壂鐮丄PI
+    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);
+      });
+      pdaScanActive.value = true;
+      uni.showToast({ title: "璇蜂娇鐢≒DA鎵爜", icon: "none" });
+      pdaScanTimer.value = setTimeout(() => {
+        pdaScanActive.value = false;
+        uni.$off("scan_repair_device");
+        pdaScanTimer.value = null;
+      }, 20000);
+      return;
+    }
+
     uni.scanCode({
       scanType: ["qrCode", "barCode"],
       success: res => {
@@ -388,6 +437,10 @@
     if (scanTimer.value) {
       clearTimeout(scanTimer.value);
     }
+    if (pdaScanTimer.value) {
+      clearTimeout(pdaScanTimer.value);
+    }
+    uni.$off("scan_repair_device");
   });
 
   // 鎻愪氦琛ㄥ崟
@@ -522,4 +575,4 @@
     margin-left: 8px;
     cursor: pointer;
   }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/pages/equipmentManagement/upkeep/add.vue b/src/pages/equipmentManagement/upkeep/add.vue
index 5f3bd40..457b265 100644
--- a/src/pages/equipmentManagement/upkeep/add.vue
+++ b/src/pages/equipmentManagement/upkeep/add.vue
@@ -85,6 +85,8 @@
                         @confirm="onDateConfirm"
                         @cancel="showDate = false"
                         mode="date" />
+    <PdaScan :active="pdaScanActive"
+             eventName="scan_upkeep_device" />
   </view>
 </template>
 
@@ -93,6 +95,7 @@
   import { onShow } from "@dcloudio/uni-app";
   import PageHeader from "@/components/PageHeader.vue";
   import CommonUpload from "@/components/CommonUpload.vue";
+  import PdaScan from "@/components/pda-scan/pda-scan.vue";
   import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
   import {
     addUpkeep,
@@ -140,6 +143,8 @@
   // 鎵爜鐩稿叧鐘舵��
   const isScanning = ref(false);
   const scanTimer = ref(null);
+  const pdaScanActive = ref(false);
+  const pdaScanTimer = ref(null);
 
   // 琛ㄥ崟楠岃瘉瑙勫垯
   const formRules = {
@@ -210,7 +215,51 @@
       return;
     }
 
-    // 璋冪敤uni-app鐨勬壂鐮丄PI
+    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);
+      });
+      pdaScanActive.value = true;
+      uni.showToast({ title: "璇蜂娇鐢≒DA鎵爜", icon: "none" });
+      pdaScanTimer.value = setTimeout(() => {
+        pdaScanActive.value = false;
+        uni.$off("scan_upkeep_device");
+        pdaScanTimer.value = null;
+      }, 20000);
+      return;
+    }
+
     uni.scanCode({
       scanType: ["qrCode", "barCode"],
       success: res => {
@@ -309,6 +358,10 @@
     if (scanTimer.value) {
       clearTimeout(scanTimer.value);
     }
+    if (pdaScanTimer.value) {
+      clearTimeout(pdaScanTimer.value);
+    }
+    uni.$off("scan_upkeep_device");
   });
 
   // 鎻愪氦琛ㄥ崟
@@ -441,4 +494,4 @@
     margin-left: 8px;
     cursor: pointer;
   }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/pages/inspectionUpload/upload.vue b/src/pages/inspectionUpload/upload.vue
index e85cba8..785601e 100644
--- a/src/pages/inspectionUpload/upload.vue
+++ b/src/pages/inspectionUpload/upload.vue
@@ -61,77 +61,18 @@
       <view class="section-card"
             v-if="hasException === true">
         <view class="section-title">宸℃鐓х墖/瑙嗛</view>
-        <!-- 褰撳墠鍒嗙被鐨勪笂浼犲尯鍩� -->
-        <view class="upload-area">
-          <view class="upload-buttons">
-            <u-button type="primary"
-                      @click="chooseMedia('image')"
-                      :loading="uploading"
-                      :disabled="beforeModelValue.length >= uploadConfig.limit"
-                      :customStyle="{ marginRight: '10px', flex: 1 }">
-              <u-icon name="camera"
-                      size="18"
-                      color="#fff"
-                      style="margin-right: 5px"></u-icon>
-              {{ uploading ? '涓婁紶涓�...' : '鎷嶇収' }}
-            </u-button>
-            <u-button type="success"
-                      @click="chooseMedia('video')"
-                      :loading="uploading"
-                      :disabled="beforeModelValue.length >= uploadConfig.limit"
-                      :customStyle="{ flex: 1 }">
-              <uni-icons type="videocam"
-                         size="18"
-                         color="#fff"
-                         style="margin-right: 5px"></uni-icons>
-              {{ uploading ? '涓婁紶涓�...' : '鎷嶈棰�' }}
-            </u-button>
-          </view>
-          <!-- 涓婁紶杩涘害 -->
-          <view v-if="uploading"
-                class="upload-progress">
-            <u-line-progress :percentage="uploadProgress"
-                             :showText="true"
-                             activeColor="#409eff"></u-line-progress>
-          </view>
-          <!-- 褰撳墠鍒嗙被鐨勬枃浠跺垪琛� -->
-          <view v-if="beforeModelValue.length > 0"
-                class="file-list">
-            <view v-for="(file, index) in beforeModelValue"
-                  :key="index"
-                  class="file-item">
-              <view class="file-preview-container">
-                <image v-if="file.type === 'image' || (file.type !== 'video' && !file.type)"
-                       :src="file.url || file.tempFilePath || file.path || file.downloadUrl"
-                       class="file-preview"
-                       mode="aspectFill" />
-                <view v-else-if="file.type === 'video'"
-                      class="video-preview">
-                  <uni-icons type="videocam"
-                             size="18"
-                             color="#fff"
-                             style="margin-right: 5px"></uni-icons>
-                  <text class="video-text">瑙嗛</text>
-                </view>
-                <!-- 鍒犻櫎鎸夐挳 -->
-                <view class="delete-btn"
-                      @click="removeFile(index)">
-                  <u-icon name="close"
-                          size="12"
-                          color="#fff"></u-icon>
-                </view>
-              </view>
-              <view class="file-info">
-                <text class="file-name">{{ file.bucketFilename || file.name || (file.type === 'image' ? '鍥剧墖' : '瑙嗛') }}</text>
-                <text class="file-size">{{ formatFileSize(file.size) }}</text>
-              </view>
-            </view>
-          </view>
-          <view v-if="beforeModelValue.length === 0"
-                class="empty-state">
-            <text>璇烽�夋嫨瑕佷笂浼犵殑鍥剧墖鎴栬棰�</text>
-          </view>
-        </view>
+        <!-- 浣跨敤 PDA 濯掍綋涓婁紶缁勪欢 -->
+        <PdaMediaUpload v-model="beforeModelValue"
+                        :action="uploadFileUrl"
+                        :limit="uploadConfig.limit"
+                        :fileSize="uploadConfig.fileSize"
+                        :formData="{ type: 10 }"
+                        :allowCamera="true"
+                        :allowVideo="true"
+                        @update:modelValue="handleFilesUpdate"
+                        @choose-media="handleChooseMedia"
+                        @uploading="uploading = $event"
+                        @progress="uploadProgress = $event" />
         <!-- 缁熻淇℃伅 -->
         <view class="upload-summary">
           <text class="summary-text">
@@ -166,8 +107,9 @@
 
 <script setup>
   import { ref, computed, onMounted } from "vue";
-  import { onLoad } from "@dcloudio/uni-app";
+  import { onLoad, onShow, onHide } 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";
   import { getToken } from "@/utils/auth";
   import config from "@/config";
@@ -590,10 +532,34 @@
     });
   };
 
-  // 鍒犻櫎鏂囦欢
-  const removeFile = index => {
-    beforeModelValue.value.splice(index, 1);
+  // 鐩戝惉鏂囦欢鍒楄〃鍙樺寲锛堢粍浠跺唴閮ㄥ鐞嗗垹闄わ紝鐖剁粍浠跺彧鍚屾锛�
+  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>
diff --git a/src/pages/works.vue b/src/pages/works.vue
index fc7eed5..d3c5d17 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -299,6 +299,8 @@
         </up-grid>
       </view>
     </view>
+    <PdaScan :active="pdaScanActive"
+             eventName="scan_work_report" />
     <DownloadProgressMask />
   </view>
 </template>
@@ -308,6 +310,7 @@
   import { userLoginFacotryList } from "@/api/login";
   import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
   import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
+  import PdaScan from "@/components/pda-scan/pda-scan.vue";
   import modal from "@/plugins/modal";
   import useUserStore from "@/store/modules/user";
 
@@ -315,6 +318,8 @@
   const show = ref(false);
   const factoryList = ref([]);
   const factoryListTem = ref([]);
+  const pdaScanActive = ref(false);
+  let scanWorkReportTimer = null;
   const iconStyle = {
     fontSize: "1.125rem",
     color: "#2979ff",
@@ -1072,78 +1077,121 @@
       });
   }
   const getcode = async () => {
-    uni.scanCode({
-      success: async res => {
-        // 瑙f瀽浜岀淮鐮佸唴瀹�
-        const scanResult = res.result;
-        let orderRow = "";
+    const canUsePdaBroadcast = () => {
+      try {
+        if (typeof plus === "undefined") return false;
+        if (plus?.os?.name !== "Android") return false;
+        if (!plus?.android) return false;
 
-        // 鍒ゆ柇鎵弿缁撴灉鏄惁涓虹函鏁板瓧锛坕d锛�
-        const isNumericId = /^\d+$/.test(scanResult.trim());
+        const sys = uni.getSystemInfoSync?.() || {};
+        const brand = String(sys?.brand || "").toUpperCase();
+        const model = String(sys?.model || "").toUpperCase();
 
-        if (isNumericId) {
-          // 濡傛灉鏄函鏁板瓧锛屾牴鎹� id 鑾峰彇宸ュ崟鏁版嵁
-          const workOrderId = scanResult.trim();
-          modal.loading("姝e湪鑾峰彇宸ュ崟淇℃伅...");
-          try {
-            const workRes = await getProductWorkOrderById({ id: workOrderId });
-            modal.closeLoading();
+        return (
+          brand.includes("DROI") ||
+          model.includes("MV-IDP5204") ||
+          model.includes("IDP")
+        );
+      } catch (e) {
+        return false;
+      }
+    };
 
-            console.log("宸ュ崟鏌ヨ缁撴灉:", workRes);
+    const handleWorkReportScan = async scanResultRaw => {
+      const scanResult = scanResultRaw == null ? "" : String(scanResultRaw);
+      let orderRow = "";
 
-            if (workRes.code === 200 && workRes.data) {
-              // 鏂版帴鍙h繑鍥炵殑鏄崟涓璞★紝涓嶆槸鏁扮粍
-              const workData = workRes.data;
-              console.log("宸ュ崟鏁版嵁:", workData);
+      const isNumericId = /^\d+$/.test(scanResult.trim());
 
-              if (workData.endOrder === true) {
-                modal.msgError("璇ヨ鍗曞凡缁撴潫锛屾棤娉曟姤宸�");
-                return;
-              }
+      if (isNumericId) {
+        const workOrderId = scanResult.trim();
+        modal.loading("姝e湪鑾峰彇宸ュ崟淇℃伅...");
+        try {
+          const workRes = await getProductWorkOrderById({ id: workOrderId });
+          modal.closeLoading();
 
-              orderRow = JSON.stringify(workData);
+          console.log("宸ュ崟鏌ヨ缁撴灉:", workRes);
 
-              console.log("鏋勯�犵殑orderRow:", orderRow);
-            } else {
-              modal.msgError("鏈壘鍒板搴旂殑宸ュ崟淇℃伅");
+          if (workRes.code === 200 && workRes.data) {
+            const workData = workRes.data;
+            console.log("宸ュ崟鏁版嵁:", workData);
+
+            if (workData.endOrder === true) {
+              modal.msgError("璇ヨ鍗曞凡缁撴潫锛屾棤娉曟姤宸�");
               return;
             }
-          } catch (error) {
-            modal.closeLoading();
-            console.error("鑾峰彇宸ュ崟淇℃伅澶辫触:", error);
-            modal.msgError("鑾峰彇宸ュ崟淇℃伅澶辫触: " + (error.message || "鏈煡閿欒"));
-            return;
-          }
-        } else {
-          // 濡傛灉涓嶆槸绾暟瀛楋紝灏濊瘯浠庢壂鐮佺粨鏋滀腑鎻愬彇orderRow鍙傛暟
-          try {
-            // 澶勭悊娣峰悎鏍煎紡: http://...?orderRow={...}
-            const orderRowStart = scanResult.indexOf("orderRow={");
-            if (orderRowStart !== -1) {
-              // 鎻愬彇浠巓rderRow={寮�濮嬬殑JSON鍐呭
-              const jsonPart = scanResult.substring(orderRowStart + 9); // 9鏄�"orderRow=".length
-              orderRow = jsonPart;
-            } else {
-              // 濡傛灉鐩存帴鏄疛SON瀛楃涓诧紝灏濊瘯瑙f瀽
-              orderRow = scanResult;
-            }
-          } catch (e) {
-            console.error(e, "瑙f瀽澶辫触====????=====");
-            orderRow = "";
-          }
 
-          // 楠岃瘉鏄惁涓烘湁鏁堢殑JSON
-          try {
-            JSON.parse(orderRow);
-          } catch (error) {
-            modal.msgError("璁㈠崟瑙f瀽澶辫触锛岃妫�鏌ヤ簩缁寸爜鏍煎紡");
+            orderRow = JSON.stringify(workData);
+
+            console.log("鏋勯�犵殑orderRow:", orderRow);
+          } else {
+            modal.msgError("鏈壘鍒板搴旂殑宸ュ崟淇℃伅");
             return;
           }
+        } catch (error) {
+          modal.closeLoading();
+          console.error("鑾峰彇宸ュ崟淇℃伅澶辫触:", error);
+          modal.msgError("鑾峰彇宸ュ崟淇℃伅澶辫触: " + (error.message || "鏈煡閿欒"));
+          return;
         }
-        // 鎵爜鎴愬姛鍚庤烦杞埌鐢熶骇鎶ュ伐椤甸潰锛屽苟浼犻�抩rderRow鍙傛暟
-        uni.navigateTo({
-          url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`,
-        });
+      } 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, "瑙f瀽澶辫触====????=====");
+          orderRow = "";
+        }
+
+        try {
+          JSON.parse(orderRow);
+        } catch (error) {
+          modal.msgError("璁㈠崟瑙f瀽澶辫触锛岃妫�鏌ヤ簩缁寸爜鏍煎紡");
+          return;
+        }
+      }
+
+      uni.navigateTo({
+        url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`,
+      });
+    };
+
+    if (canUsePdaBroadcast()) {
+      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");
+        if (scanWorkReportTimer) {
+          clearTimeout(scanWorkReportTimer);
+          scanWorkReportTimer = null;
+        }
+        await handleWorkReportScan(data?.code);
+      });
+      pdaScanActive.value = true;
+      uni.showToast({
+        title: "璇蜂娇鐢≒DA鎵爜",
+        icon: "none",
+      });
+      scanWorkReportTimer = setTimeout(() => {
+        pdaScanActive.value = false;
+        uni.$off("scan_work_report");
+        scanWorkReportTimer = null;
+      }, 20000);
+      return;
+    }
+
+    uni.scanCode({
+      success: async res => {
+        await handleWorkReportScan(res.result);
       },
       fail: err => {
         uni.showToast({

--
Gitblit v1.9.3