/**
|
* RFID扫描管理器
|
* 用于在扫码时自动启动RFID扫描
|
* 全局单例,应用启动时自动初始化,应用退出时才清理
|
*/
|
import idataRFID from '@/common/idata-rfid.js';
|
|
class RFIDScanner {
|
constructor() {
|
this.isInitialized = false;
|
this.isInitializing = false; // 正在初始化标志
|
this.isScanning = false;
|
this.powerStatus = 'disconnected';
|
this.scanCallback = null;
|
this.currentInputRef = null; // 当前输入框的引用(用于自动填入)
|
this.moduleTypeIndex = 0; // 当前尝试的模块类型索引:0=UM, 1=SLR, 2=GX
|
this.moduleTypes = [0, 1, 2]; // 模块类型列表
|
this.moduleTypeNames = ['UM模块', 'SLR模块', 'GX模块'];
|
this.initRetryCount = 0;
|
this.maxRetryCount = 3; // 每种模块类型最多尝试3次
|
this.autoStopTimer = null; // 自动停止定时器
|
this.autoStopDelay = 30000; // 30秒后自动停止扫描(延长,避免频繁停止)
|
this.powerCheckTimer = null; // 上电检查定时器
|
this.currentPageInstance = null; // 当前页面实例(用于自动填入)
|
this.globalScanMode = false; // 全局扫描模式(不依赖输入框焦点)
|
this.scanDebounceTimer = null; // 防抖定时器
|
this.scanDebounceDelay = 300; // 防抖延迟300ms
|
}
|
|
/**
|
* 初始化RFID模块(应用启动时调用,全局只初始化一次)
|
*/
|
init() {
|
if (this.isInitialized) {
|
console.log('[RFIDScanner] 模块已初始化,跳过');
|
return;
|
}
|
|
if (this.isInitializing) {
|
console.log('[RFIDScanner] 正在初始化中,跳过');
|
return;
|
}
|
|
this.isInitializing = true;
|
console.log('[RFIDScanner] ========== 开始初始化RFID模块 ==========');
|
|
// 监听上电事件
|
idataRFID.onPowerEvent((e) => {
|
console.log('[RFIDScanner] POWEREvent:', JSON.stringify(e));
|
if (e && e.status === 'connected') {
|
this.powerStatus = 'connected';
|
this.isInitialized = true;
|
this.isInitializing = false;
|
console.log('[RFIDScanner] ✓✓✓ 模块已上电成功!');
|
// 清除重试定时器
|
if (this.powerCheckTimer) {
|
clearTimeout(this.powerCheckTimer);
|
this.powerCheckTimer = null;
|
}
|
} else {
|
this.powerStatus = 'disconnected';
|
console.log('[RFIDScanner] ✗ 模块未上电:', e ? e.msg : '未知错误');
|
}
|
});
|
|
// 监听扫描事件
|
idataRFID.onScanEvent((e) => {
|
console.log('[RFIDScanner] ========== 扫描到标签 ==========');
|
console.log('[RFIDScanner] EPC:', e ? e.epc : 'undefined');
|
console.log('[RFIDScanner] TID:', e ? e.tid : 'undefined');
|
|
// 调用回调函数(回调函数中会更新输入框)
|
if (this.scanCallback) {
|
this.scanCallback(e);
|
}
|
|
// 全局扫描模式:自动填入当前焦点输入框
|
if (this.globalScanMode && e && e.epc) {
|
this.fillCurrentInput(e.epc);
|
}
|
});
|
|
// 开始尝试初始化
|
this.tryInitModule();
|
}
|
|
/**
|
* 尝试初始化模块(自动尝试不同模块类型)
|
*/
|
tryInitModule() {
|
if (this.isInitialized) {
|
return;
|
}
|
|
const moduleType = this.moduleTypes[this.moduleTypeIndex];
|
console.log(`[RFIDScanner] 尝试初始化 ${this.moduleTypeNames[this.moduleTypeIndex]} (类型${moduleType})...`);
|
|
idataRFID.initUHF(moduleType, (ret) => {
|
console.log(`[RFIDScanner] initUHF(${moduleType}) result:`, ret);
|
|
// 等待上电结果(最多等待3秒)
|
this.powerCheckTimer = setTimeout(() => {
|
if (!this.isInitialized && this.powerStatus !== 'connected') {
|
console.log(`[RFIDScanner] ${this.moduleTypeNames[this.moduleTypeIndex]} 初始化超时,尝试下一个模块类型`);
|
this.initRetryCount++;
|
|
if (this.initRetryCount >= this.maxRetryCount) {
|
// 当前模块类型尝试次数用完,切换到下一个
|
this.moduleTypeIndex = (this.moduleTypeIndex + 1) % this.moduleTypes.length;
|
this.initRetryCount = 0;
|
console.log(`[RFIDScanner] 切换到 ${this.moduleTypeNames[this.moduleTypeIndex]}`);
|
}
|
|
// 延迟后重试
|
setTimeout(() => {
|
if (!this.isInitialized) {
|
this.tryInitModule();
|
}
|
}, 2000);
|
}
|
}, 3000);
|
});
|
}
|
|
/**
|
* 开始扫描(在扫码输入框获得焦点时调用,或扫码按键触发)
|
* @param {Object} inputRef - 输入框引用对象,用于自动填入扫描结果 {epc: ''}
|
* @param {Function} callback - 扫描到标签时的回调函数(可选)
|
*/
|
startScan(inputRef = null, callback = null) {
|
// 防抖处理,避免快速点击
|
if (this.scanDebounceTimer) {
|
clearTimeout(this.scanDebounceTimer);
|
}
|
|
this.scanDebounceTimer = setTimeout(() => {
|
this._doStartScan(inputRef, callback);
|
}, this.scanDebounceDelay);
|
}
|
|
/**
|
* 实际执行开始扫描
|
*/
|
_doStartScan(inputRef = null, callback = null) {
|
console.log('[RFIDScanner] ========== 开始扫描 ==========');
|
console.log('[RFIDScanner] 当前状态 - isScanning:', this.isScanning, 'powerStatus:', this.powerStatus);
|
|
// 如果未初始化,先初始化(确保模块已上电)
|
if (!this.isInitialized && !this.isInitializing) {
|
console.log('[RFIDScanner] 模块未初始化,开始初始化...');
|
this.init();
|
}
|
|
// 如果已经在扫描,直接返回
|
if (this.isScanning) {
|
console.log('[RFIDScanner] 已在扫描中,跳过');
|
return;
|
}
|
|
// 设置扫描回调和输入框引用
|
this.scanCallback = callback;
|
this.currentInputRef = inputRef;
|
|
// 如果不是全局扫描模式,设置当前页面实例
|
if (!this.globalScanMode && typeof getCurrentPages === 'function') {
|
const pages = getCurrentPages();
|
if (pages.length > 0) {
|
this.currentPageInstance = pages[pages.length - 1].$vm;
|
}
|
}
|
|
// 检查上电状态
|
if (this.powerStatus !== 'connected') {
|
console.log('[RFIDScanner] ⚠ RFID正在上电,请稍候...');
|
idataRFID.showToast('RFID正在上电,请稍候...', 1);
|
// 等待上电完成后再开始扫描
|
const checkPowerAndStart = () => {
|
if (this.powerStatus === 'connected' && !this.isScanning) {
|
console.log('[RFIDScanner] 模块已上电,开始扫描...');
|
this.doStartScan();
|
} else if (!this.isScanning) {
|
console.log('[RFIDScanner] 等待模块上电...');
|
// 如果未上电,等待1秒后重试(最多等待10秒)
|
setTimeout(() => {
|
if (!this.isScanning && this.powerStatus !== 'connected') {
|
checkPowerAndStart();
|
}
|
}, 1000);
|
}
|
};
|
setTimeout(() => {
|
checkPowerAndStart();
|
}, 500);
|
return;
|
}
|
|
// 如果已上电,直接开始扫描
|
this.doStartScan();
|
}
|
|
/**
|
* 执行开始扫描操作
|
*/
|
doStartScan() {
|
// 如果已经在扫描,不重复调用
|
if (this.isScanning) {
|
console.log('[RFIDScanner] 已在扫描中,跳过');
|
return;
|
}
|
|
console.log('[RFIDScanner] 模块已上电,开始扫描...');
|
idataRFID.startOrStopRFID((ret) => {
|
console.log('[RFIDScanner] startOrStopRFID result:', JSON.stringify(ret));
|
if (ret && ret.code === 'success') {
|
if (ret.msg === 'start') {
|
// 成功启动
|
this.isScanning = true;
|
console.log('[RFIDScanner] ✓ RFID扫描已启动');
|
idataRFID.showToast('RFID扫描已启动', 1);
|
|
// 设置自动停止定时器(30秒后自动停止,避免频繁停止)
|
if (this.autoStopTimer) {
|
clearTimeout(this.autoStopTimer);
|
}
|
this.autoStopTimer = setTimeout(() => {
|
console.log('[RFIDScanner] 自动停止扫描(超时)');
|
this.stopScan();
|
}, this.autoStopDelay);
|
} else if (ret.msg === 'stop') {
|
// 如果返回stop,说明当前状态是启动的,调用后变成了停止
|
// 这种情况不应该发生,但需要处理
|
console.log('[RFIDScanner] ⚠ 扫描状态异常,收到stop消息');
|
this.isScanning = false;
|
} else {
|
console.log('[RFIDScanner] ⚠ 未知的扫描状态:', ret.msg);
|
}
|
} else {
|
console.log('[RFIDScanner] ⚠ 启动扫描失败:', ret ? ret.msg : '未知错误');
|
idataRFID.showToast('启动扫描失败', 1);
|
}
|
});
|
}
|
|
/**
|
* 停止扫描(在扫码输入框失去焦点或输入完成时调用)
|
* 注意:只停止扫描,不下电,保持模块上电状态
|
*/
|
stopScan() {
|
// 防抖处理
|
if (this.scanDebounceTimer) {
|
clearTimeout(this.scanDebounceTimer);
|
this.scanDebounceTimer = null;
|
}
|
|
if (!this.isScanning) {
|
console.log('[RFIDScanner] 当前未在扫描,跳过停止操作');
|
return;
|
}
|
|
console.log('[RFIDScanner] ========== 停止扫描 ==========');
|
|
// 清除自动停止定时器
|
if (this.autoStopTimer) {
|
clearTimeout(this.autoStopTimer);
|
this.autoStopTimer = null;
|
}
|
|
// 先设置状态为false,避免重复调用
|
this.isScanning = false;
|
|
idataRFID.startOrStopRFID((ret) => {
|
console.log('[RFIDScanner] stop scan result:', JSON.stringify(ret));
|
if (ret && ret.code === 'success') {
|
if (ret.msg === 'stop') {
|
console.log('[RFIDScanner] ✓ RFID扫描已停止(模块保持上电状态)');
|
} else if (ret.msg === 'start') {
|
// 如果返回start,说明当前状态是停止的,调用后变成了启动
|
// 这种情况不应该发生,但需要处理
|
console.log('[RFIDScanner] ⚠ 扫描状态异常,收到start消息,重新设置为停止');
|
this.isScanning = true;
|
// 立即再次停止
|
setTimeout(() => {
|
this.stopScan();
|
}, 100);
|
}
|
}
|
});
|
|
// 清除回调和输入框引用(但不清除globalScanMode,因为可能还需要继续扫描)
|
this.scanCallback = null;
|
this.currentInputRef = null;
|
}
|
|
/**
|
* 获取上电状态
|
*/
|
getPowerStatus() {
|
return this.powerStatus;
|
}
|
|
/**
|
* 获取扫描状态
|
*/
|
getScanningStatus() {
|
return this.isScanning;
|
}
|
|
/**
|
* 全局扫描模式:为当前焦点输入框启动扫描(扫码按键触发)
|
*/
|
startScanForCurrentInput() {
|
console.log('[RFIDScanner] ========== 全局扫描模式启动 ==========');
|
|
// 如果正在扫描,先停止
|
if (this.isScanning) {
|
console.log('[RFIDScanner] 当前正在扫描,先停止');
|
this.stopScan();
|
// 等待停止完成后再启动
|
setTimeout(() => {
|
this._startScanForCurrentInput();
|
}, 500);
|
return;
|
}
|
|
this._startScanForCurrentInput();
|
}
|
|
/**
|
* 实际执行全局扫描
|
*/
|
_startScanForCurrentInput() {
|
// 确保设置了当前页面实例
|
if (typeof getCurrentPages === 'function') {
|
const pages = getCurrentPages();
|
if (pages.length > 0) {
|
this.currentPageInstance = pages[pages.length - 1].$vm;
|
console.log('[RFIDScanner] 已设置当前页面实例:', pages[pages.length - 1].route);
|
}
|
}
|
|
this.globalScanMode = true;
|
this.startScan(null, (tagData) => {
|
if (tagData && tagData.epc) {
|
console.log('[RFIDScanner] 扫描到标签,自动填入当前输入框:', tagData.epc);
|
this.fillCurrentInput(tagData.epc);
|
// 扫描成功后停止(延迟一下,确保填入完成)
|
setTimeout(() => {
|
this.stopScan();
|
}, 500);
|
}
|
});
|
}
|
|
/**
|
* 自动填入当前焦点输入框
|
*/
|
fillCurrentInput(epc) {
|
try {
|
console.log('[RFIDScanner] ========== 尝试自动填入EPC:', epc);
|
|
// 优先使用保存的页面实例
|
let vm = null;
|
if (this.currentPageInstance) {
|
vm = this.currentPageInstance;
|
console.log('[RFIDScanner] 使用保存的页面实例');
|
} else if (typeof getCurrentPages === 'function') {
|
// 如果保存的实例没有找到,尝试从getCurrentPages获取
|
const pages = getCurrentPages();
|
if (pages.length > 0) {
|
const currentPage = pages[pages.length - 1];
|
console.log('[RFIDScanner] 当前页面:', currentPage.route);
|
if (currentPage && currentPage.$vm) {
|
vm = currentPage.$vm;
|
// 更新保存的实例
|
this.currentPageInstance = vm;
|
}
|
}
|
}
|
|
if (!vm) {
|
console.log('[RFIDScanner] 未找到页面实例,无法自动填入');
|
return;
|
}
|
|
// 检查常见的输入框变量名(按优先级)
|
// 优先查找可能有焦点的输入框
|
const inputFields = ['barcode', 'matnr', 'locNo', 'orderNo', 'sourceSite', 'targetSite'];
|
let filled = false;
|
|
for (let field of inputFields) {
|
if (vm[field] !== undefined) {
|
console.log(`[RFIDScanner] 找到输入框变量 ${field},当前值:`, vm[field]);
|
vm[field] = epc;
|
console.log(`[RFIDScanner] ✓✓✓ 已自动填入EPC到 ${field}:`, epc);
|
idataRFID.showToast('已自动填入', 1);
|
filled = true;
|
break; // 只填入第一个找到的
|
}
|
}
|
|
if (!filled) {
|
console.log('[RFIDScanner] 未找到输入框变量,无法自动填入');
|
console.log('[RFIDScanner] 页面实例data:', Object.keys(vm.$data || {}));
|
}
|
} catch (error) {
|
console.error('[RFIDScanner] 自动填入失败:', error);
|
}
|
}
|
|
/**
|
* 单标签读无过滤(在输入框获得焦点时调用)
|
* @param {String} fieldName - 要填入的字段名(如 'barcode', 'matnr' 等)
|
* @param {Function} callback - 读取成功后的回调函数(可选)
|
*/
|
readSingleTagWithoutFilter(fieldName = null, callback = null) {
|
console.log('[RFIDScanner] ========== 单标签读无过滤 ==========');
|
console.log('[RFIDScanner] 字段名:', fieldName);
|
|
// 如果未初始化,先初始化(确保模块已上电)
|
if (!this.isInitialized && !this.isInitializing) {
|
console.log('[RFIDScanner] 模块未初始化,开始初始化...');
|
this.init();
|
}
|
|
// 检查上电状态
|
if (this.powerStatus !== 'connected') {
|
console.log('[RFIDScanner] ⚠ RFID正在上电,请稍候...');
|
idataRFID.showToast('RFID正在上电,请稍候...', 1);
|
// 等待上电完成后再读取
|
const checkPowerAndRead = () => {
|
if (this.powerStatus === 'connected') {
|
console.log('[RFIDScanner] 模块已上电,开始单标签读取...');
|
this._doReadSingleTag(fieldName, callback);
|
} else {
|
console.log('[RFIDScanner] 等待模块上电...');
|
setTimeout(() => {
|
if (this.powerStatus !== 'connected') {
|
checkPowerAndRead();
|
}
|
}, 1000);
|
}
|
};
|
setTimeout(() => {
|
checkPowerAndRead();
|
}, 500);
|
return;
|
}
|
|
// 如果已上电,直接读取
|
this._doReadSingleTag(fieldName, callback);
|
}
|
|
/**
|
* 执行单标签读取操作
|
*/
|
_doReadSingleTag(fieldName = null, callback = null) {
|
// 确保设置了当前页面实例
|
if (typeof getCurrentPages === 'function') {
|
const pages = getCurrentPages();
|
if (pages.length > 0) {
|
this.currentPageInstance = pages[pages.length - 1].$vm;
|
}
|
}
|
|
// 调用单标签读无过滤
|
// readBank: 1->EPC, startBlock: 2, len: 6, pwd: "00000000"
|
idataRFID.readTagWithoutFilter(1, 2, 6, "00000000", (ret) => {
|
console.log('[RFIDScanner] readTagWithoutFilter result:', JSON.stringify(ret));
|
|
if (ret && ret.code === 'success' && ret.data) {
|
const epc = ret.data.trim();
|
console.log('[RFIDScanner] ✓✓✓ 成功读取到标签 EPC:', epc);
|
|
// 如果有回调函数,先调用回调
|
if (callback && typeof callback === 'function') {
|
callback({ epc: epc, tid: '' });
|
}
|
|
// 如果指定了字段名,自动填入
|
if (fieldName) {
|
this.fillFieldByName(fieldName, epc);
|
} else {
|
// 如果没有指定字段名,自动填入当前焦点输入框
|
this.fillCurrentInput(epc);
|
}
|
|
idataRFID.showToast('读取成功', 1);
|
} else {
|
console.log('[RFIDScanner] ✗ 读取失败:', ret ? ret.msg : '未知错误');
|
if (ret && ret.code === 'fail') {
|
idataRFID.showToast('读取失败: ' + (ret.msg || '未知错误'), 1);
|
}
|
}
|
});
|
}
|
|
/**
|
* 根据字段名填入值
|
*/
|
fillFieldByName(fieldName, value) {
|
try {
|
console.log(`[RFIDScanner] 尝试填入字段 ${fieldName}:`, value);
|
|
// 优先使用保存的页面实例
|
let vm = null;
|
if (this.currentPageInstance) {
|
vm = this.currentPageInstance;
|
} else if (typeof getCurrentPages === 'function') {
|
const pages = getCurrentPages();
|
if (pages.length > 0 && pages[pages.length - 1].$vm) {
|
vm = pages[pages.length - 1].$vm;
|
this.currentPageInstance = vm;
|
}
|
}
|
|
if (!vm) {
|
console.log('[RFIDScanner] 未找到页面实例,无法填入');
|
return;
|
}
|
|
if (vm[fieldName] !== undefined) {
|
vm[fieldName] = value;
|
console.log(`[RFIDScanner] ✓✓✓ 已填入字段 ${fieldName}:`, value);
|
idataRFID.showToast('已自动填入', 1);
|
} else {
|
console.log(`[RFIDScanner] 字段 ${fieldName} 不存在`);
|
}
|
} catch (error) {
|
console.error('[RFIDScanner] 填入字段失败:', error);
|
}
|
}
|
|
/**
|
* 设置当前页面实例(页面onShow时调用)
|
*/
|
setCurrentPageInstance(pageInstance) {
|
this.currentPageInstance = pageInstance;
|
}
|
|
/**
|
* 清理资源(应用退出时调用,全局只调用一次)
|
*/
|
cleanup() {
|
console.log('[RFIDScanner] ========== 清理RFID资源(应用退出) ==========');
|
this.stopScan();
|
idataRFID.closeUHF();
|
idataRFID.removeEventListeners();
|
this.isInitialized = false;
|
this.isInitializing = false;
|
this.isScanning = false;
|
this.powerStatus = 'disconnected';
|
this.scanCallback = null;
|
this.currentInputRef = null;
|
if (this.powerCheckTimer) {
|
clearTimeout(this.powerCheckTimer);
|
this.powerCheckTimer = null;
|
}
|
console.log('[RFIDScanner] ✓ RFID资源已清理');
|
}
|
}
|
|
// 创建单例实例
|
const rfidScanner = new RFIDScanner();
|
|
export default rfidScanner;
|