|
|
@@ -1261,6 +1261,7 @@
|
|
|
import { mapActions, mapGetters } from 'vuex';
|
|
|
import BigNumber from 'bignumber.js';
|
|
|
import headList from '@/components/headList';
|
|
|
+ import { decryptCode } from '@/utils/crypto';
|
|
|
|
|
|
// import dictMixins from '@/mixins/dictMixins';
|
|
|
export default {
|
|
|
@@ -1401,36 +1402,81 @@
|
|
|
await this.getNowFormatDate();
|
|
|
},
|
|
|
mounted() {
|
|
|
- document.addEventListener('keydown', this.handleScanInput);
|
|
|
+ this._barcodeScanHandler = this.handleScanInput.bind(this);
|
|
|
+ document.addEventListener('keydown', this._barcodeScanHandler);
|
|
|
+ this._barcodePasteHandler = this.handleBarcodePaste.bind(this);
|
|
|
+ document.addEventListener('paste', this._barcodePasteHandler);
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
- document.removeEventListener('keydown', this.handleScanInput);
|
|
|
+ if (this._barcodeScanHandler) {
|
|
|
+ document.removeEventListener('keydown', this._barcodeScanHandler);
|
|
|
+ }
|
|
|
+ if (this._barcodePasteHandler) {
|
|
|
+ document.removeEventListener('paste', this._barcodePasteHandler);
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
// 扫码枪键盘事件监听
|
|
|
+ // 通过按键间隔识别扫码枪输入:扫码枪通常 <30ms 一个键,
|
|
|
+ // 进入 scanning 模式后调用 preventDefault,阻止按键打入聚焦的输入框,
|
|
|
+ // 避免行字段被覆盖、表格行被重新渲染。
|
|
|
handleScanInput(e) {
|
|
|
const now = Date.now();
|
|
|
const timeDiff = now - this.scanLastKeyTime;
|
|
|
this.scanLastKeyTime = now;
|
|
|
|
|
|
if (e.key === 'Enter') {
|
|
|
- if (this.scanBuffer.length > 3) {
|
|
|
- this.processScanCode(this.scanBuffer);
|
|
|
+ if (this._scanning && this.scanBuffer.length > 3) {
|
|
|
+ this.processScanCode(decryptCode(this.scanBuffer));
|
|
|
+ // 扫码枪结束,吞掉这次 Enter,避免触发表单提交/单元格回车跳转
|
|
|
+ e.preventDefault();
|
|
|
+ e.stopPropagation();
|
|
|
}
|
|
|
this.scanBuffer = '';
|
|
|
+ this._scanning = false;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 间隔超过 100ms 视为人工输入,重置缓冲
|
|
|
+ if (!e.key || e.key.length !== 1) return;
|
|
|
+
|
|
|
+ // 间隔超过 100ms 视为人工输入,重置缓冲与扫码状态
|
|
|
if (timeDiff > 100) {
|
|
|
this.scanBuffer = '';
|
|
|
+ this._scanning = false;
|
|
|
+ } else if (timeDiff < 30) {
|
|
|
+ // 连续两次按键间隔很短,认定进入扫码状态
|
|
|
+ this._scanning = true;
|
|
|
}
|
|
|
|
|
|
- if (e.key && e.key.length === 1) {
|
|
|
- this.scanBuffer += e.key;
|
|
|
+ this.scanBuffer += e.key;
|
|
|
+
|
|
|
+ // 进入扫码状态后阻止默认行为,避免按键进入聚焦输入框
|
|
|
+ if (this._scanning) {
|
|
|
+ e.preventDefault();
|
|
|
+ e.stopPropagation();
|
|
|
+ // 同时让聚焦输入框失焦,避免极少数情况下首字符已经入框
|
|
|
+ if (
|
|
|
+ document.activeElement &&
|
|
|
+ typeof document.activeElement.blur === 'function'
|
|
|
+ ) {
|
|
|
+ document.activeElement.blur();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 扫码枪粘贴事件监听
|
|
|
+ handleBarcodePaste(e) {
|
|
|
+ const text = (e.clipboardData || window.clipboardData)
|
|
|
+ .getData('text')
|
|
|
+ .trim();
|
|
|
+ console.log('扫码粘贴事件:', text);
|
|
|
+ if (text.length >= 3) {
|
|
|
+ this.processScanCode(decryptCode(text));
|
|
|
}
|
|
|
},
|
|
|
// 处理扫码结果:先匹配产品信息,再匹配包装明细
|
|
|
+ // 直接把 confirmStatus 写到行对象上,便于业务读取与序列化。
|
|
|
+ // 由于 packingList watcher 已去掉 deep,且 productList 本就无 watcher,
|
|
|
+ // 这两次赋值都不会触发表格重渲染。
|
|
|
processScanCode(code) {
|
|
|
console.log('扫描条码:', code);
|
|
|
|
|
|
@@ -1442,13 +1488,10 @@
|
|
|
code === `${item.categoryCode}-${item.batchNo}`
|
|
|
);
|
|
|
if (productIndex > -1) {
|
|
|
- // productList 没有 deep watcher,用 $set 让字段进入响应式,
|
|
|
- // 后续 spread/序列化都能拿到 confirmStatus
|
|
|
- this.$set(this.productList[productIndex], 'confirmStatus', 1);
|
|
|
+ this.productList[productIndex].confirmStatus = 1;
|
|
|
this.$message.success(
|
|
|
`产品信息匹配成功:${this.productList[productIndex].categoryCode}-${this.productList[productIndex].batchNo}`
|
|
|
);
|
|
|
- console.log('修改后的数据', this.productList);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -1468,7 +1511,6 @@
|
|
|
item.engrave === engrave)
|
|
|
);
|
|
|
if (packingIndex > -1) {
|
|
|
- // 直接赋值,避免触发 packingList 的 deep watcher 重新加载
|
|
|
this.packingList[packingIndex].confirmStatus = 1;
|
|
|
this.$message.success(`包装明细匹配成功:${code}`);
|
|
|
return;
|