/**
|
* RFID输入框自动填入助手
|
* 全局监听RFID扫描按键(189、190、191),自动读取标签并填入当前焦点输入框
|
*/
|
|
// #ifdef APP-PLUS
|
let uhfModel = null;
|
let globalEvent = null;
|
let modal = null;
|
let isPowerOn = false;
|
let isScanning = false; // 是否正在扫描中
|
let scanKeyHandler = null; // 按键监听器引用
|
|
/**
|
* 初始化RFID助手(只初始化插件引用和事件监听,不初始化RFID模块)
|
* RFID模块由App.vue全局初始化,这里只负责监听按键和读取标签
|
* 注意:即使初始化失败,也不抛出异常,确保不影响页面使用
|
*/
|
function initRFIDForInput() {
|
try {
|
uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule");
|
globalEvent = uni.requireNativePlugin('globalEvent');
|
modal = uni.requireNativePlugin('modal');
|
|
if (!uhfModel) {
|
console.warn('[RFIDInputHelper] ⚠ RFID插件未找到,RFID扫描功能不可用,但页面可正常使用');
|
return false;
|
}
|
|
// 监听上电事件(监听全局上电状态,RFID模块由App.vue初始化)
|
try {
|
globalEvent.addEventListener('POWEREvent', function(e) {
|
console.log('[RFIDInputHelper] POWEREvent:', JSON.stringify(e));
|
if (e && e.status === 'connected') {
|
isPowerOn = true;
|
console.log('[RFIDInputHelper] ✓ RFID模块已上电');
|
} else {
|
isPowerOn = false;
|
console.log('[RFIDInputHelper] ✗ RFID模块未上电');
|
}
|
});
|
} catch (eventError) {
|
console.warn('[RFIDInputHelper] ⚠ 添加POWEREvent监听失败:', eventError);
|
console.warn('[RFIDInputHelper] ⚠ RFID扫描功能可能不可用,但页面可正常使用');
|
}
|
|
// 注意:RFID模块由App.vue在onLaunch时全局初始化
|
// 这里只负责监听按键和读取标签,不初始化RFID模块
|
|
return true;
|
} catch (error) {
|
console.error('[RFIDInputHelper] ⚠ 初始化失败:', error);
|
console.warn('[RFIDInputHelper] ⚠ RFID扫描功能不可用,但页面可正常使用');
|
return false;
|
}
|
}
|
|
/**
|
* 检查当前页面是否是测试页面
|
*/
|
function isTestPage() {
|
try {
|
const pages = getCurrentPages();
|
if (pages.length > 0) {
|
const currentPage = pages[pages.length - 1];
|
const route = currentPage.route || '';
|
// 如果是测试页面,不启用全局RFID扫描
|
return route.includes('rfid/uhftest') || route.includes('rfid/uhftest2');
|
}
|
return false;
|
} catch (error) {
|
console.error('[RFIDInputHelper] 检查页面失败:', error);
|
return false;
|
}
|
}
|
|
/**
|
* 播放提示音
|
* @param {String} type - 提示音类型:'success'=成功(滴1声),'error'=错误(滴2声),'warning'=警告(滴3声),'short'=短促(快速滴1声)
|
*/
|
function playBeepSound(type = 'success') {
|
// #ifdef APP-PLUS
|
try {
|
// 使用设备蜂鸣器播放提示音
|
if (typeof plus !== 'undefined' && plus.device && plus.device.beep) {
|
let beepCount = 1; // 默认播放1次
|
|
// 根据类型设置不同的提示音
|
switch(type) {
|
case 'success':
|
beepCount = 1; // 成功:滴1声
|
break;
|
case 'error':
|
beepCount = 2; // 错误:滴2声
|
break;
|
case 'warning':
|
beepCount = 3; // 警告:滴3声
|
break;
|
case 'short':
|
beepCount = 1; // 短促:快速滴1声
|
break;
|
default:
|
beepCount = 1;
|
}
|
|
plus.device.beep(beepCount); // 播放指定次数
|
|
// 如果是错误或警告,可以添加震动反馈
|
if (type === 'error' || type === 'warning') {
|
if (typeof plus !== 'undefined' && plus.device && plus.device.vibrate) {
|
setTimeout(() => {
|
plus.device.vibrate(200); // 震动200ms
|
}, 100);
|
}
|
}
|
} else {
|
// 如果设备不支持beep,尝试使用vibrate(震动)作为替代
|
if (typeof plus !== 'undefined' && plus.device && plus.device.vibrate) {
|
let vibrateDuration = 100; // 默认震动100ms
|
if (type === 'error') {
|
vibrateDuration = 300; // 错误:震动300ms
|
} else if (type === 'warning') {
|
vibrateDuration = 200; // 警告:震动200ms
|
}
|
plus.device.vibrate(vibrateDuration);
|
}
|
}
|
} catch (error) {
|
console.warn('[RFIDInputHelper] 播放提示音失败:', error);
|
}
|
// #endif
|
}
|
|
/**
|
* 读取RFID标签(单标签读,无过滤)
|
*/
|
function readRFIDTag() {
|
try {
|
if (!uhfModel) {
|
// 如果模块未初始化,尝试初始化
|
try {
|
uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule");
|
} catch (e) {
|
console.warn('[RFIDInputHelper] ⚠ RFID模块未找到:', e);
|
}
|
if (!uhfModel) {
|
console.warn('[RFIDInputHelper] RFID模块未找到');
|
if (modal) {
|
modal.toast({
|
message: 'RFID模块未找到',
|
duration: 1.5
|
});
|
}
|
return;
|
}
|
}
|
|
// 检查RFID是否已上电(RFID模块由App.vue全局初始化)
|
if (!isPowerOn) {
|
console.warn('[RFIDInputHelper] RFID未上电,无法扫描');
|
if (modal) {
|
modal.toast({
|
message: 'RFID正在上电,请稍候...',
|
duration: 1.5
|
});
|
}
|
return;
|
}
|
} catch (error) {
|
console.error('[RFIDInputHelper] ⚠ 读取RFID标签前检查失败:', error);
|
console.warn('[RFIDInputHelper] ⚠ RFID扫描功能不可用,但页面可正常使用');
|
if (modal) {
|
modal.toast({
|
message: 'RFID扫描功能不可用',
|
duration: 1.5
|
});
|
}
|
return;
|
}
|
|
if (isScanning) {
|
console.log('[RFIDInputHelper] 正在扫描中,跳过');
|
return;
|
}
|
|
isScanning = true;
|
console.log('[RFIDInputHelper] 开始读取RFID标签...');
|
|
/**
|
* readBank:0->RESERVED,1->EPC,2->TID,3->USR
|
* startBlock:读取的起始地址(Word类型)
|
* len:读取的数据长度(Word类型,大于0)
|
* pwd:访问密码,默认密码为:00000000
|
* 注意:Word类型,一个长度表示标签存储4位字符
|
* len=1表示读取4位,len=2表示读取8位,len=8表示读取32位
|
* 使用len=1读取4位数据(如果标签是4位)
|
*/
|
const readLen = 8; // 读取长度:1个Word = 4个字符
|
uhfModel.readTagWithoutFilter(1, 2, readLen, "00000000", (ret) => {
|
isScanning = false;
|
console.log('[RFIDInputHelper] readTagWithoutFilter result:', ret);
|
|
if (ret && typeof ret === 'string') {
|
// 解析返回结果,提取EPC(不追加,不截断,使用实际长度)
|
// 返回格式可能是:success EPC:XXXXXXXX 或类似格式
|
let epc = '';
|
if (ret.includes('success') || ret.includes('EPC')) {
|
// 尝试提取EPC值(提取完整的16进制字符串,不限制长度)
|
const epcMatch = ret.match(/EPC[:\s]+([A-F0-9]+)/i);
|
if (epcMatch && epcMatch[1]) {
|
epc = epcMatch[1]; // 使用实际长度,不追加
|
} else {
|
// 如果没有匹配到,尝试提取16进制字符串(不限制最小长度)
|
const hexMatch = ret.match(/([A-F0-9]+)/i);
|
if (hexMatch && hexMatch[1]) {
|
epc = hexMatch[1]; // 使用实际长度,不追加
|
}
|
}
|
}
|
|
if (epc) {
|
// 根据读取长度截取数据(len=1表示4位,len=2表示8位)
|
const maxLength = readLen * 4; // Word长度 × 4 = 字符数
|
if (epc.length > maxLength) {
|
console.log(`[RFIDInputHelper] 数据过长(${epc.length}位),截取前${maxLength}位`);
|
epc = epc.substring(0, maxLength);
|
}
|
|
// 去除前导0(如果插件返回了固定长度的数据,前面可能有0填充)
|
// 但保留至少1位(如果全部是0,保留一个0)
|
const originalLength = epc.length;
|
epc = epc.replace(/^0+/, '') || '0';
|
if (originalLength !== epc.length) {
|
console.log('[RFIDInputHelper] 去除前导0: 原始长度=' + originalLength + ', 去除后长度=' + epc.length);
|
}
|
|
console.log('[RFIDInputHelper] ✓ 读取到标签EPC (长度' + epc.length + '位):', epc);
|
// 播放提示音(滴一声)
|
// playBeepSound(); // 已注释,后续自己决定是否启用
|
// 自动填入当前焦点输入框(不追加,使用实际长度)
|
fillCurrentInput(epc);
|
modal.toast({
|
message: '已读取标签',
|
duration: 1.5
|
});
|
} else {
|
console.warn('[RFIDInputHelper] 无法解析EPC,返回结果:', ret);
|
// 如果返回的是失败消息,直接显示
|
if (ret.includes('fail') || ret.includes('失败')) {
|
modal.toast({
|
message: '读取失败,请重试',
|
duration: 1.5
|
});
|
} else {
|
// 尝试直接使用返回的字符串作为EPC(不限制最小长度)
|
const cleanRet = ret.trim();
|
// 移除可能的"success"等前缀,只保留16进制字符
|
let hexOnly = cleanRet.replace(/[^A-F0-9]/gi, '');
|
if (hexOnly.length > 0) {
|
// 去除前导0(如果插件返回了固定长度的数据,前面可能有0填充)
|
const originalLength = hexOnly.length;
|
hexOnly = hexOnly.replace(/^0+/, '') || '0';
|
if (originalLength !== hexOnly.length) {
|
console.log('[RFIDInputHelper] 去除前导0: 原始长度=' + originalLength + ', 去除后长度=' + hexOnly.length);
|
}
|
// 播放提示音(滴一声)
|
// playBeepSound(); // 已注释,后续自己决定是否启用
|
fillCurrentInput(hexOnly); // 使用实际长度,不追加
|
modal.toast({
|
message: '已读取标签',
|
duration: 1.5
|
});
|
} else {
|
modal.toast({
|
message: '读取失败,请重试',
|
duration: 1.5
|
});
|
}
|
}
|
}
|
} else if (ret && typeof ret === 'object') {
|
// 如果返回的是对象格式
|
if (ret.code === 'success' && ret.data) {
|
let epc = '';
|
if (typeof ret.data === 'string') {
|
// 如果是字符串,提取16进制部分(不追加,不截断)
|
epc = ret.data.trim().replace(/[^A-F0-9]/gi, '');
|
} else if (ret.data.epc) {
|
epc = String(ret.data.epc).trim().replace(/[^A-F0-9]/gi, '');
|
} else {
|
epc = String(ret.data).trim().replace(/[^A-F0-9]/gi, '');
|
}
|
|
// 根据读取长度截取数据(len=1表示4位,len=2表示8位)
|
if (epc) {
|
const maxLength = readLen * 4; // Word长度 × 4 = 字符数
|
if (epc.length > maxLength) {
|
console.log(`[RFIDInputHelper] 数据过长(${epc.length}位),截取前${maxLength}位`);
|
epc = epc.substring(0, maxLength);
|
}
|
|
// 去除前导0(如果插件返回了固定长度的数据,前面可能有0填充)
|
// 但保留至少1位(如果全部是0,保留一个0)
|
const originalLength = epc.length;
|
epc = epc.replace(/^0+/, '') || '0';
|
if (originalLength !== epc.length) {
|
console.log('[RFIDInputHelper] 去除前导0: 原始长度=' + originalLength + ', 去除后长度=' + epc.length);
|
}
|
|
console.log('[RFIDInputHelper] ✓ 读取到标签EPC (长度' + epc.length + '位):', epc);
|
// 播放提示音(滴一声)
|
// playBeepSound(); // 已注释,后续自己决定是否启用
|
fillCurrentInput(epc); // 使用实际长度,不追加
|
modal.toast({
|
message: '已读取标签',
|
duration: 1.5
|
});
|
} else {
|
modal.toast({
|
message: '读取失败,请重试',
|
duration: 1.5
|
});
|
}
|
} else {
|
modal.toast({
|
message: '读取失败,请重试',
|
duration: 1.5
|
});
|
}
|
} else {
|
console.warn('[RFIDInputHelper] 读取失败:', ret);
|
modal.toast({
|
message: '读取失败,请重试',
|
duration: 1.5
|
});
|
}
|
});
|
}
|
|
/**
|
* 自动填入当前焦点输入框
|
*/
|
function fillCurrentInput(epc) {
|
try {
|
console.log('[RFIDInputHelper] 尝试填入EPC到输入框:', epc);
|
|
// 获取当前页面实例
|
const pages = getCurrentPages();
|
if (pages.length === 0) {
|
console.warn('[RFIDInputHelper] 没有页面实例');
|
return;
|
}
|
|
const currentPage = pages[pages.length - 1];
|
if (!currentPage || !currentPage.$vm) {
|
console.warn('[RFIDInputHelper] 页面实例无效');
|
return;
|
}
|
|
const vm = currentPage.$vm;
|
console.log('[RFIDInputHelper] 当前页面:', currentPage.route);
|
|
// 定义输入框字段和对应的焦点状态字段(预定义的常见字段)
|
// 格式:{ 字段名: 焦点状态字段名 }
|
const predefinedFieldMap = [
|
{ field: 'barcode', focusField: 'barcodeFocus' },
|
{ field: 'matnr', focusField: 'matFocus' },
|
{ field: 'sourceSite', focusField: 'sourceSiteFocus' },
|
{ field: 'orderNo', focusField: 'orderNoFocus' },
|
{ field: 'targetSite', focusField: 'targetSiteFocus' },
|
{ field: 'locNo', focusField: 'locNoFocus' },
|
{ field: 'batch', focusField: 'batchFocus' },
|
{ field: 'userName', focusField: 'userNameFocus' },
|
{ field: 'password', focusField: 'passwordFocus' }
|
];
|
|
// 自动检测所有可能的输入框字段(从vm.$data中查找所有字符串类型的属性)
|
const autoDetectedFields = [];
|
if (vm.$data) {
|
for (let key in vm.$data) {
|
// 跳过以$开头的Vue内部属性,跳过函数,跳过focus字段本身
|
if (key.startsWith('$') || typeof vm.$data[key] === 'function' || key.endsWith('Focus')) {
|
continue;
|
}
|
// 如果是字符串类型,认为是可能的输入框字段
|
if (typeof vm.$data[key] === 'string' || vm.$data[key] === null || vm.$data[key] === undefined) {
|
// 检查是否有对应的focusField(字段名 + Focus)
|
const focusFieldName = key + 'Focus';
|
if (vm.$data[focusFieldName] !== undefined) {
|
autoDetectedFields.push({ field: key, focusField: focusFieldName });
|
}
|
}
|
}
|
}
|
|
// 合并预定义字段和自动检测的字段(去重)
|
const allFieldsMap = [...predefinedFieldMap];
|
for (let autoField of autoDetectedFields) {
|
// 检查是否已存在
|
const exists = allFieldsMap.some(item => item.field === autoField.field);
|
if (!exists) {
|
allFieldsMap.push(autoField);
|
}
|
}
|
|
// 调试:打印所有输入框的焦点状态
|
console.log('[RFIDInputHelper] ========== 检查输入框焦点状态 ==========');
|
for (let item of allFieldsMap) {
|
if (vm[item.field] !== undefined) {
|
const focusValue = vm[item.focusField];
|
console.log(`[RFIDInputHelper] ${item.field}: focus=${focusValue}, value="${vm[item.field]}"`);
|
}
|
}
|
|
// 只查找有焦点的输入框(光标所在的输入框)
|
let focusedField = null;
|
for (let item of allFieldsMap) {
|
if (vm[item.field] !== undefined) {
|
// 检查是否有焦点状态字段,并且焦点为true
|
const focusValue = vm[item.focusField];
|
console.log(`[RFIDInputHelper] 检查 ${item.field}: focusField=${item.focusField}, focusValue=${focusValue}, type=${typeof focusValue}`);
|
if (focusValue === true) {
|
focusedField = item.field;
|
console.log(`[RFIDInputHelper] ✓✓✓ 找到有焦点的输入框: ${item.field} (focus=${focusValue})`);
|
break;
|
}
|
}
|
}
|
|
// 只填入有焦点的输入框,如果没有焦点则不填入
|
if (focusedField) {
|
// 根据字段类型截断RFID数据长度
|
let finalEpc = epc;
|
const fieldLengthMap = {
|
'barcode': 8, // 托盘码:保留前8位
|
'matnr': 16, // 物料码/物料号:保留前16位
|
'sourceSite': 9, // 暂存位:保留前9位
|
'locNo': 7 // 库位号:保留前7位
|
};
|
|
if (fieldLengthMap[focusedField]) {
|
const maxLength = fieldLengthMap[focusedField];
|
if (finalEpc.length > maxLength) {
|
console.log(`[RFIDInputHelper] ${focusedField}字段数据长度(${finalEpc.length}位)超过限制(${maxLength}位),截取前${maxLength}位`);
|
finalEpc = finalEpc.substring(0, maxLength);
|
}
|
}
|
|
console.log(`[RFIDInputHelper] 填入有焦点的输入框 ${focusedField}:`, finalEpc);
|
vm[focusedField] = finalEpc;
|
// 触发input事件,确保页面逻辑能响应
|
if (vm.$nextTick) {
|
vm.$nextTick(() => {
|
// 如果页面有对应的input处理方法,可以手动触发
|
if (focusedField === 'barcode' && typeof vm.barcodeInput === 'function') {
|
vm.barcodeInput();
|
} else if (focusedField === 'matnr' && typeof vm.findMat === 'function') {
|
vm.findMat();
|
}
|
});
|
}
|
} else {
|
console.warn('[RFIDInputHelper] ✗ 未找到有焦点的输入框,不填入任何输入框');
|
console.warn('[RFIDInputHelper] 请先点击输入框获得焦点,然后再按扫码按键');
|
modal.toast({
|
message: '请先点击输入框获得焦点',
|
duration: 1.5
|
});
|
}
|
} catch (error) {
|
console.error('[RFIDInputHelper] 自动填入失败:', error);
|
}
|
}
|
|
/**
|
* 监听扫码按键
|
*/
|
function setupScanKeyListener() {
|
if (scanKeyHandler) {
|
console.log('[RFIDInputHelper] 按键监听器已存在');
|
return;
|
}
|
|
if (typeof plus === 'undefined' || !plus.key) {
|
console.warn('[RFIDInputHelper] plus对象未初始化,无法添加按键监听');
|
return;
|
}
|
|
scanKeyHandler = function(e) {
|
const keyCode = e.keyCode;
|
|
// 扫码按键:189、190、191
|
if (keyCode === 189 || keyCode === 190 || keyCode === 191) {
|
// 如果是测试页面,不处理(让测试页面自己处理)
|
if (isTestPage()) {
|
console.log('[RFIDInputHelper] 测试页面,跳过全局RFID扫描');
|
return;
|
}
|
|
console.log('[RFIDInputHelper] 扫码按键按下(键值' + keyCode + '),触发RFID扫描');
|
readRFIDTag();
|
}
|
};
|
|
plus.key.addEventListener('keydown', scanKeyHandler);
|
console.log('[RFIDInputHelper] ✓ 按键监听器已添加');
|
}
|
|
/**
|
* 移除按键监听
|
*/
|
function removeScanKeyListener() {
|
if (scanKeyHandler && typeof plus !== 'undefined' && plus.key) {
|
plus.key.removeEventListener('keydown', scanKeyHandler);
|
scanKeyHandler = null;
|
console.log('[RFIDInputHelper] ✓ 按键监听器已移除');
|
}
|
}
|
|
/**
|
* 关闭RFID模块(注意:RFID模块由App.vue管理,这里不关闭)
|
*/
|
function closeRFID() {
|
// RFID模块由App.vue在onExit时关闭,这里不需要关闭
|
console.log('[RFIDInputHelper] RFID模块由App.vue管理,不在此处关闭');
|
}
|
|
/**
|
* 启动全局RFID输入助手
|
*/
|
export function startRFIDInputHelper() {
|
// #ifdef APP-PLUS
|
console.log('[RFIDInputHelper] 启动RFID输入助手...');
|
|
// 初始化RFID模块
|
if (initRFIDForInput()) {
|
// 延迟添加按键监听,确保初始化完成
|
setTimeout(() => {
|
setupScanKeyListener();
|
}, 500);
|
}
|
// #endif
|
}
|
|
/**
|
* 停止全局RFID输入助手
|
*/
|
export function stopRFIDInputHelper() {
|
// #ifdef APP-PLUS
|
console.log('[RFIDInputHelper] 停止RFID输入助手...');
|
removeScanKeyListener();
|
// 注意:不关闭RFID模块,因为测试页面可能在使用
|
// closeRFID();
|
// #endif
|
}
|
|
// #endif
|