chen.llin
8 天以前 3f63164b824fd996273a2533e9d27b98f87c56c5
rfid初版
10个文件已添加
12个文件已修改
4336 ■■■■■ 已修改文件
.hbuilderx/launch.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/misc.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
App.vue 318 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/idata-rfid.js 501 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/rfid-input-helper.js 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/rfid-scanner.js 565 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
nativeplugins/iData-UHFPlugin/android/uhflib-release.aar 补丁 | 查看 | 原始文档 | blame | 历史
nativeplugins/iData-UHFPlugin/license.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
nativeplugins/iData-UHFPlugin/package.json 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/AGV/agv_back.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/AGV/agv_empty.vue 598 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/AGV/agv_start.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/order/orderPakin2.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/pakin/pakin.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/rfid/settings.vue 800 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/rfid/uhftest.vue 509 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/rfid/uhftest2.vue 400 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stock/stockQuery.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/uni-popup.vue 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.hbuilderx/launch.json
@@ -2,7 +2,7 @@
    "version" : "1.0",
    "configurations" : [
        {
            "playground" : "standard",
            "playground" : "custom",
            "type" : "uni-app:app-android"
        }
    ]
.idea/misc.xml
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
    <output url="file://$PROJECT_DIR$/out" />
App.vue
@@ -1,33 +1,264 @@
<script>
    import Vue from 'vue'
    // #ifdef APP-PLUS
    import { startRFIDInputHelper, stopRFIDInputHelper } from '@/common/rfid-input-helper.js'
    // #endif
    export default {
        onLaunch: function() {
            console.log('App Launch')
            // #ifdef APP-PLUS
            // 全局初始化RFID模块(应用启动时初始化,关闭app时关闭)
            console.log('[App] 初始化RFID模块...');
            const uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule");
            const globalEvent = uni.requireNativePlugin('globalEvent');
            const modal = uni.requireNativePlugin('modal');
            if (!uhfModel) {
                console.error('[App] RFID插件未找到');
            } else {
                // 监听上电事件
                let isPowerOn = false;
                globalEvent.addEventListener('POWEREvent', function(e) {
                    console.log('[App] POWEREvent:', JSON.stringify(e));
                    if (e && e.status === 'connected') {
                        isPowerOn = true;
                        console.log('[App] ✓✓✓ RFID模块已上电成功!');
                    } else {
                        isPowerOn = false;
                        console.log('[App] ✗ RFID模块未上电');
                    }
                });
                // 初始化RFID模块(使用SLR模块,与测试页面一致)
                uhfModel.initUHF(1, (ret) => {
                    console.log('[App] initUHF result:', ret);
                    if (ret && typeof ret === 'string' && ret.includes('success')) {
                        console.log('[App] ✓ RFID模块初始化成功');
                    } else {
                        console.warn('[App] ⚠ RFID模块初始化失败:', ret);
                    }
                });
                // 保存引用,用于onExit时关闭
                this.uhfModel = uhfModel;
                this.globalEvent = globalEvent;
            }
            // 启动全局RFID输入助手(用于自动填入输入框)
            startRFIDInputHelper();
            // #endif
            // 注意:以下代码已废弃,改为上面的全局初始化方式
            // #ifdef APP-PLUS
            /*
            console.log('[App] 初始化RFID模块...');
            const uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule");
            const globalEvent = uni.requireNativePlugin('globalEvent');
            const modal = uni.requireNativePlugin('modal');
            // 监听上电事件
            let isPowerOn = false;
            let moduleTypeIndex = 0; // 当前尝试的模块类型索引:0=UM, 1=SLR, 2=GX
            const moduleTypes = [0, 1, 2]; // 模块类型列表
            const moduleTypeNames = ['UM模块', 'SLR模块', 'GX模块'];
            let initRetryCount = 0;
            const maxRetryCount = 3; // 每种模块类型最多尝试3次
            globalEvent.addEventListener('POWEREvent', function(e) {
                console.log('[App] POWEREvent:', JSON.stringify(e));
                if (e && e.status === 'connected') {
                    isPowerOn = true;
                    console.log('[App] ✓✓✓ 模块已上电成功!模块类型:', moduleTypeNames[moduleTypeIndex]);
                } else {
                    isPowerOn = false;
                    console.log('[App] ✗ 模块未上电:', e ? e.msg : '未知错误');
                    // 如果上电失败,尝试下一个模块类型
                    if (e && e.msg && e.msg.includes('上电失败')) {
                        setTimeout(() => {
                            tryNextModuleType();
                        }, 2000);
                    }
                }
            });
            // 尝试下一个模块类型
            const tryNextModuleType = () => {
                initRetryCount++;
                if (initRetryCount >= maxRetryCount) {
                    // 当前模块类型尝试次数用完,切换到下一个
                    moduleTypeIndex++;
                    initRetryCount = 0;
                    if (moduleTypeIndex >= moduleTypes.length) {
                        // 所有模块类型都尝试过了
                        console.log('[App] ⚠ 所有模块类型都尝试失败,停止初始化');
                        modal.toast({
                            message: 'RFID模块初始化失败,请检查设备',
                            duration: 2
                        });
                        return;
                    }
                }
                // 先清除配置信息
                if (uhfModel.clearConfigInfo) {
                    console.log('[App] 清除配置信息...');
                    uhfModel.clearConfigInfo();
                }
                // 延迟后尝试初始化
                setTimeout(() => {
                    const moduleType = moduleTypes[moduleTypeIndex];
                    console.log(`[App] 尝试初始化 ${moduleTypeNames[moduleTypeIndex]} (类型${moduleType}),第${initRetryCount + 1}次...`);
                    uhfModel.initUHF(moduleType, (ret) => {
                        console.log('[App] initUHF result:', ret);
                        if (ret && ret.code === 'success') {
                            // 初始化成功,等待上电事件
                            console.log('[App] initUHF调用成功,等待上电事件...');
                        } else {
                            // 初始化失败,重试
                            setTimeout(() => {
                                tryNextModuleType();
                            }, 2000);
                        }
                    });
                }, 100);
            };
            // 开始尝试初始化
            tryNextModuleType();
            // 全局监听扫码按键(189、190、191),触发RFID扫描
            let scanKeyDebounceTimer = null; // 防抖定时器
            const handleScanKey = (e) => {
                const keyCode = e.keyCode;
                // 扫码按键:189、190、191
                if (keyCode === 189 || keyCode === 190 || keyCode === 191) {
                    // 防抖处理,避免快速按键
                    if (scanKeyDebounceTimer) {
                        clearTimeout(scanKeyDebounceTimer);
                    }
                    scanKeyDebounceTimer = setTimeout(() => {
                        console.log('[App] 扫码按键按下(键值' + keyCode + '),触发RFID扫描');
                        if (isPowerOn) {
                            // 触发扫描
                            uhfModel.startOrStopRFID((ret) => {
                                console.log('[App] startOrStopRFID result:', JSON.stringify(ret));
                                if (ret && ret.code === 'success') {
                                    if (ret.msg === 'start') {
                                        modal.toast({
                                            message: 'RFID扫描已启动',
                                            duration: 1.5
                                        });
                                    } else {
                                        modal.toast({
                                            message: 'RFID扫描已停止',
                                            duration: 1.5
                                        });
                                    }
                                }
                            });
                        } else {
                            modal.toast({
                                message: 'RFID正在上电,请稍候...',
                                duration: 1.5
                            });
                        }
                    }, 300); // 300ms防抖
                }
            };
            // 确保plus对象存在后再添加按键监听
            if (typeof plus !== 'undefined' && plus.key) {
                plus.key.addEventListener('keydown', handleScanKey);
                // 保存按键监听器引用,用于清理
                this.scanKeyHandler = handleScanKey;
                this.scanKeyDebounceTimer = scanKeyDebounceTimer;
            } else {
                console.warn('[App] plus对象未初始化,无法添加按键监听');
            }
            */
            // 注意:RFID初始化已注释,由各个页面自己管理(参考iDataUHFDemo)
            // #endif
            // 全局监听扫码按键(189、190、191),触发单标签读无过滤
            // #ifdef APP-PLUS
            let scanKeyDebounceTimer = null; // 防抖定时器
            const handleScanKey = (e) => {
                const keyCode = e.keyCode;
                // 扫码按键:189、190、191
                if (keyCode === 189 || keyCode === 190 || keyCode === 191) {
                    // 防抖处理,避免快速按键
                    if (scanKeyDebounceTimer) {
                        clearTimeout(scanKeyDebounceTimer);
                    }
                    scanKeyDebounceTimer = setTimeout(() => {
                        console.log('[App] 扫码按键按下(键值' + keyCode + '),触发单标签读无过滤');
                        // 调用单标签读无过滤功能,自动填入当前焦点输入框
                        rfidScanner.readSingleTagWithoutFilter(null, (tagData) => {
                            if (tagData && tagData.epc) {
                                console.log('[App] 单标签读成功,EPC:', tagData.epc);
                            }
                        });
                    }, 300); // 300ms防抖
                }
            };
            // 确保plus对象存在后再添加按键监听
            if (typeof plus !== 'undefined' && plus.key) {
                plus.key.addEventListener('keydown', handleScanKey);
                console.log('[App] 已添加扫码按键监听(189、190、191)');
            } else {
                console.warn('[App] plus对象未初始化,无法添加按键监听');
            }
            // #endif
            uni.getSystemInfo({
                success: function(e) {
                    // 安全地处理系统信息,避免访问不存在的属性
                    if (!e) {
                        console.warn('[App] getSystemInfo 返回空数据');
                        return;
                    }
                    // #ifndef MP
                    Vue.prototype.StatusBar = e.statusBarHeight;
                    if (e.platform == 'android') {
                        Vue.prototype.CustomBar = e.statusBarHeight + 50;
                    } else {
                        Vue.prototype.CustomBar = e.statusBarHeight + 45;
                    };
                    if (e.statusBarHeight !== undefined) {
                        Vue.prototype.StatusBar = e.statusBarHeight;
                        if (e.platform == 'android') {
                            Vue.prototype.CustomBar = e.statusBarHeight + 50;
                        } else {
                            Vue.prototype.CustomBar = e.statusBarHeight + 45;
                        }
                    }
                    // #endif
                    // #ifdef MP-WEIXIN
                    Vue.prototype.StatusBar = e.statusBarHeight;
                    let custom = wx.getMenuButtonBoundingClientRect();
                    Vue.prototype.Custom = custom;
                    Vue.prototype.CustomBar = custom.bottom + custom.top - e.statusBarHeight;
                    if (e.statusBarHeight !== undefined) {
                        Vue.prototype.StatusBar = e.statusBarHeight;
                        if (typeof wx !== 'undefined' && wx.getMenuButtonBoundingClientRect) {
                            let custom = wx.getMenuButtonBoundingClientRect();
                            if (custom) {
                                Vue.prototype.Custom = custom;
                                Vue.prototype.CustomBar = custom.bottom + custom.top - e.statusBarHeight;
                            }
                        }
                    }
                    // #endif        
                    // #ifdef MP-ALIPAY
                    Vue.prototype.StatusBar = e.statusBarHeight;
                    Vue.prototype.CustomBar = e.statusBarHeight + e.titleBarHeight;
                    if (e.statusBarHeight !== undefined && e.titleBarHeight !== undefined) {
                        Vue.prototype.StatusBar = e.statusBarHeight;
                        Vue.prototype.CustomBar = e.statusBarHeight + e.titleBarHeight;
                    }
                    // #endif
                },
                fail: function(err) {
                    console.warn('[App] getSystemInfo 失败:', err);
                }
            })
            Vue.prototype.ColorList = [{
                    title: '嫣红',
                    name: 'red',
@@ -110,18 +341,39 @@
        },
        onHide: function() {
            console.log('App Hide')
        },
        onError: function(err) {
            console.log('App Error:', err)
        },
        onExit: function() {
            console.log('App Exit')
            // #ifdef APP-PLUS
            // 停止全局RFID输入助手
            stopRFIDInputHelper();
            // 关闭RFID模块
            if (this.uhfModel && this.uhfModel.closeUHF) {
                this.uhfModel.closeUHF();
                console.log('[App] ✓ RFID模块已关闭');
            }
            if (this.globalEvent) {
                this.globalEvent.removeEventListener('POWEREvent');
            }
            // #endif
        }
    }
</script>
<style>
    @import "static/css/colorUi/icon.css";
    /*每个页面公共css */
    body {
        background-color: #f1f1f1;
        color: #606266;
        font-family: Helvetica Neue, Helvetica, sans-serif;
    }
    .nav-list {
        display: flex;
        flex-wrap: wrap;
@@ -129,7 +381,7 @@
        justify-content: space-between;
        margin-top: 20px;
    }
    .nav-li {
        padding: 30upx;
        border-radius: 12upx;
@@ -141,7 +393,7 @@
        position: relative;
        z-index: 1;
    }
    .nav-li::after {
        content: "";
        position: absolute;
@@ -155,30 +407,30 @@
        opacity: 0.2;
        transform: scale(0.9, 0.9);
    }
    .nav-li.cur {
        color: #fff;
        background: rgb(94, 185, 94);
        box-shadow: 4upx 4upx 6upx rgba(94, 185, 94, 0.4);
    }
    .nav-title {
        font-size: 32upx;
        font-weight: 300;
    }
    .nav-title::first-letter {
        font-size: 40upx;
        margin-right: 4upx;
    }
    .nav-name {
        font-size: 28upx;
        text-transform: Capitalize;
        margin-top: 20upx;
        position: relative;
    }
    .nav-name::before {
        content: "";
        position: absolute;
@@ -190,7 +442,7 @@
        right: 0;
        opacity: 0.5;
    }
    .nav-name::after {
        content: "";
        position: absolute;
@@ -202,13 +454,13 @@
        right: 40upx;
        opacity: 0.3;
    }
    .nav-name::first-letter {
        font-weight: bold;
        font-size: 36upx;
        margin-right: 1px;
    }
    .nav-li text {
        position: absolute;
        right: 30upx;
@@ -219,36 +471,36 @@
        text-align: center;
        line-height: 60upx;
    }
    .text-light {
        font-weight: 300;
    }
    @keyframes show {
        0% {
            transform: translateY(-50px);
        }
        60% {
            transform: translateY(40upx);
        }
        100% {
            transform: translateY(0px);
        }
    }
    @-webkit-keyframes show {
        0% {
            transform: translateY(-50px);
        }
        60% {
            transform: translateY(40upx);
        }
        100% {
            transform: translateY(0px);
        }
    }
</style>
</style>
common/idata-rfid.js
New file
@@ -0,0 +1,501 @@
/**
 * iData UHF RFID 工具类
 * 封装 iData-UHFPlugin 插件的所有功能
 */
// #ifdef APP-PLUS
const uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule");
const globalEvent = uni.requireNativePlugin('globalEvent');
const modal = uni.requireNativePlugin('modal');
// #endif
class iDataRFID {
    constructor() {
        this.isInitialized = false;
        this.isScanning = false;
        this.powerStatus = 'disconnected'; // connected/disconnected
        this.scanCallback = null;
        this.powerCallback = null;
    }
    /**
     * 清除配置信息(在初始化前调用,避免"Please use the 'clearConfigInfo' function to clear the current instance first"错误)
     */
    clearConfigInfo() {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            console.error('[iDataRFID] 插件未找到');
            return;
        }
        console.log('[iDataRFID] 清除配置信息...');
        if (uhfModel.clearConfigInfo) {
            uhfModel.clearConfigInfo();
        }
        // #endif
    }
    /**
     * 初始化UHF模块
     * @param {Number} mode - 1为SLR模块,0为UM模块,2为GX模块
     * @param {Function} callback - 回调函数
     */
    initUHF(mode, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            console.error('[iDataRFID] 插件未找到');
            if (callback) callback({ code: 'error', msg: '插件未找到' });
            return;
        }
        // 先清除配置信息,避免"Please use the 'clearConfigInfo' function to clear the current instance first"错误
        this.clearConfigInfo();
        // 延迟一下再初始化,确保清除操作完成
        setTimeout(() => {
            console.log('[iDataRFID] initUHF mode:', mode);
            uhfModel.initUHF(mode, (ret) => {
                console.log('[iDataRFID] initUHF result:', ret);
                if (typeof ret === 'string' && ret.includes('success')) {
                    this.isInitialized = true;
                }
                if (callback) callback(ret);
            });
        }, 100);
        // #endif
        // #ifndef APP-PLUS
        if (callback) callback({ code: 'error', msg: '仅支持APP环境' });
        // #endif
    }
    /**
     * 监听模块上电结果
     * @param {Function} callback - 回调函数 (e) => {}
     */
    onPowerEvent(callback) {
        // #ifdef APP-PLUS
        if (!globalEvent) {
            console.error('[iDataRFID] globalEvent未找到');
            return;
        }
        this.powerCallback = callback;
        globalEvent.addEventListener('POWEREvent', (e) => {
            console.log('[iDataRFID] POWEREvent:', JSON.stringify(e));
            if (e && e.status === 'connected') {
                this.powerStatus = 'connected';
            } else {
                this.powerStatus = 'disconnected';
            }
            if (callback) callback(e);
        });
        // #endif
    }
    /**
     * 监听UHF盘点扫描结果
     * @param {Function} callback - 回调函数 (e) => {}
     */
    onScanEvent(callback) {
        // #ifdef APP-PLUS
        if (!globalEvent) {
            console.error('[iDataRFID] globalEvent未找到');
            return;
        }
        this.scanCallback = callback;
        globalEvent.addEventListener('iDataUHFEvent', (e) => {
            console.log('[iDataRFID] ========== 扫描到标签 ==========');
            console.log('[iDataRFID] iDataUHFEvent:', JSON.stringify(e));
            console.log('[iDataRFID] EPC:', e ? e.epc : 'undefined');
            console.log('[iDataRFID] TID:', e ? e.tid : 'undefined');
            console.log('[iDataRFID] ====================================');
            if (callback) callback(e);
        });
        // #endif
    }
    /**
     * 开始/结束扫描
     * @param {Function} callback - 回调函数
     */
    startOrStopRFID(callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback({ code: 'error', msg: '插件未找到' });
            return;
        }
        console.log('[iDataRFID] ========== 开始/停止扫描 ==========');
        console.log('[iDataRFID] 当前扫描状态:', this.isScanning);
        console.log('[iDataRFID] 当前上电状态:', this.powerStatus);
        uhfModel.startOrStopRFID((ret) => {
            console.log('[iDataRFID] startOrStopRFID result:', JSON.stringify(ret));
            if (ret && ret.code === 'success') {
                if (ret.msg === 'start') {
                    this.isScanning = true;
                    console.log('[iDataRFID] ✓ 扫描已启动');
                    console.log('[iDataRFID] 【提示】请将标签放在读取范围内(建议5-10cm)');
                    console.log('[iDataRFID] 【提示】如果扫描不到标签,请检查:');
                    console.log('[iDataRFID]   1. 功率设置是否足够(建议20-30)');
                    console.log('[iDataRFID]   2. 标签是否在读取范围内');
                    console.log('[iDataRFID]   3. 频率设置是否正确');
                } else {
                    this.isScanning = false;
                    console.log('[iDataRFID] ✓ 扫描已停止');
                }
            } else {
                console.error('[iDataRFID] ✗ 扫描操作失败:', ret ? ret.msg : '未知错误');
            }
            console.log('[iDataRFID] ====================================');
            if (callback) callback(ret);
        });
        // #endif
        // #ifndef APP-PLUS
        if (callback) callback({ code: 'error', msg: '仅支持APP环境' });
        // #endif
    }
    /**
     * 设置盘点标签返回的数据内容模式
     * @param {Number} mode - 0只读取EPC, 1读取EPC和TID
     * @param {Function} callback - 回调函数
     */
    readTagModeSet(mode, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.readTagModeSet(mode, (ret) => {
            console.log('[iDataRFID] readTagModeSet result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 获取盘点标签返回的数据内容模式
     * @param {Function} callback - 回调函数
     */
    readTagModeGet(callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.readTagModeGet((ret) => {
            console.log('[iDataRFID] readTagModeGet result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 移除事件监听器(参考示例项目)
     */
    removeEventListeners() {
        // #ifdef APP-PLUS
        if (globalEvent) {
            globalEvent.removeEventListener('POWEREvent');
            globalEvent.removeEventListener('iDataUHFEvent');
            console.log('[iDataRFID] 事件监听器已移除');
        }
        this.powerCallback = null;
        this.scanCallback = null;
        // #endif
    }
    /**
     * 模块下电
     */
    closeUHF() {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            console.error('[iDataRFID] 插件未找到');
            return;
        }
        uhfModel.closeUHF();
        this.isInitialized = false;
        this.isScanning = false;
        this.powerStatus = 'disconnected';
        // 移除事件监听
        this.removeEventListeners();
        // #endif
    }
    /**
     * 单标签读取,无过滤条件
     * @param {Number} readBank - 0->RESERVED,1->EPC,2->TID,3->USR
     * @param {Number} startBlock - 起始地址(Word类型)
     * @param {Number} len - 数据长度(Word类型)
     * @param {String} pwd - 访问密码,默认00000000
     * @param {Function} callback - 回调函数
     */
    readTagWithoutFilter(readBank, startBlock, len, pwd, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            console.error('[iDataRFID] readTagWithoutFilter: 插件未找到');
            if (callback) callback({ code: 'error', msg: '插件未找到' });
            return;
        }
        console.log('[iDataRFID] readTagWithoutFilter 调用参数:');
        console.log('[iDataRFID]   readBank:', readBank, '(' + ['RESERVED', 'EPC', 'TID', 'USR'][readBank] + ')');
        console.log('[iDataRFID]   startBlock:', startBlock);
        console.log('[iDataRFID]   len:', len);
        console.log('[iDataRFID]   pwd:', pwd || '00000000');
        uhfModel.readTagWithoutFilter(readBank, startBlock, len, pwd || '00000000', (ret) => {
            console.log('[iDataRFID] readTagWithoutFilter 返回结果:');
            console.log('[iDataRFID]   完整结果:', JSON.stringify(ret));
            console.log('[iDataRFID]   code:', ret ? ret.code : 'undefined');
            console.log('[iDataRFID]   msg:', ret ? ret.msg : 'undefined');
            console.log('[iDataRFID]   data:', ret ? ret.data : 'undefined');
            if (ret && ret.code === 'fail') {
                console.error('[iDataRFID] 读取标签失败!');
                console.error('[iDataRFID]   失败原因:', ret.msg || '未知错误');
                console.error('[iDataRFID]   错误详情:', JSON.stringify(ret));
            }
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 单标签写入,无过滤条件
     * @param {Number} writeBank - 0->RESERVED,1->EPC,2->TID,3->USR
     * @param {Number} startBlock - 起始地址(Word类型)
     * @param {String} writeData - 写入的数据
     * @param {String} pwd - 访问密码,默认00000000
     * @param {Function} callback - 回调函数
     */
    writeTagWithoutFilter(writeBank, startBlock, writeData, pwd, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback({ code: 'error', msg: '插件未找到' });
            return;
        }
        uhfModel.writeTagWithoutFilter(writeBank, startBlock, writeData, pwd || '00000000', (ret) => {
            console.log('[iDataRFID] writeTagWithoutFilter result:', JSON.stringify(ret));
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 单标签读取,有过滤条件
     * @param {Object} options - 参数对象
     * @param {Function} callback - 回调函数
     */
    readTagWithFilter(options, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback({ code: 'error', msg: '插件未找到' });
            return;
        }
        const {
            fBank, fStartBlock, fLen, fData,
            readBank, startBlock, len, pwd
        } = options;
        uhfModel.readTagWithFilter(fBank, fStartBlock, fLen, fData, readBank, startBlock, len, pwd || '00000000', (ret) => {
            console.log('[iDataRFID] readTagWithFilter result:', JSON.stringify(ret));
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 单标签写入,有过滤条件
     * @param {Object} options - 参数对象
     * @param {Function} callback - 回调函数
     */
    writeTagWithFilter(options, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback({ code: 'error', msg: '插件未找到' });
            return;
        }
        const {
            fBank, fStartBlock, fLen, fData,
            writeBank, startBlock, writeData, pwd
        } = options;
        uhfModel.writeTagWithFilter(fBank, fStartBlock, fLen, fData, writeBank, startBlock, writeData, pwd || '00000000', (ret) => {
            console.log('[iDataRFID] writeTagWithFilter result:', JSON.stringify(ret));
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 盘点模式设置
     * @param {Number} mode - UM:0多标签模式,1快盘模式,2低功耗模式 | SLR:0异步模式,2智能控温,3新快速模式,4普通模式
     * @param {Function} callback - 回调函数
     */
    inventoryModeSet(mode, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.inventoryModeSet(mode, (ret) => {
            console.log('[iDataRFID] inventoryModeSet result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 盘点模式获取
     * @param {Function} callback - 回调函数
     */
    inventoryModeGet(callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.inventoryModeGet((ret) => {
            console.log('[iDataRFID] inventoryModeGet result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 占空比参数设置
     * @param {Number} scanTime - 盘点时间
     * @param {Number} waitTime - 休眠时间
     * @param {Boolean} save - 是否断电保存配置
     * @param {Function} callback - 回调函数
     */
    inventoryWaitTimeSet(scanTime, waitTime, save, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.inventoryWaitTimeSet(scanTime, waitTime, save, (ret) => {
            console.log('[iDataRFID] inventoryWaitTimeSet result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 占空比参数获取
     * @param {Function} callback - 回调函数
     */
    inventoryWaitTimeGet(callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.inventoryWaitTimeGet((ret) => {
            console.log('[iDataRFID] inventoryWaitTimeGet result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 天线功率参数设置
     * @param {Number} power - 0-33
     * @param {Function} callback - 回调函数
     */
    setPower(power, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.setPower(power, (ret) => {
            console.log('[iDataRFID] setPower result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 天线功率参数获取
     * @param {Function} callback - 回调函数
     */
    getPower(callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.getPower((ret) => {
            console.log('[iDataRFID] getPower result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 频率设置
     * @param {Number} mode - 0:中国(840-845MHz),1:中国(920-925MHz),2:欧洲(865-868MHz),3:美国(902-928MHz)
     * @param {Function} callback - 回调函数
     */
    setFrequencyMode(mode, callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.setFrequencyMode(mode, (ret) => {
            console.log('[iDataRFID] setFrequencyMode result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 频率获取
     * @param {Function} callback - 回调函数
     */
    getFrequencyMode(callback) {
        // #ifdef APP-PLUS
        if (!uhfModel) {
            if (callback) callback('插件未找到');
            return;
        }
        uhfModel.getFrequencyMode((ret) => {
            console.log('[iDataRFID] getFrequencyMode result:', ret);
            if (callback) callback(ret);
        });
        // #endif
    }
    /**
     * 显示Toast消息
     * @param {String} message - 消息内容
     * @param {Number} duration - 持续时间(秒)
     */
    showToast(message, duration = 1.5) {
        // #ifdef APP-PLUS
        if (modal) {
            modal.toast({
                message: message,
                duration: duration
            });
        } else {
            uni.showToast({
                title: message,
                icon: 'none',
                duration: duration * 1000
            });
        }
        // #endif
        // #ifndef APP-PLUS
        uni.showToast({
            title: message,
            icon: 'none',
            duration: duration * 1000
        });
        // #endif
    }
}
// 创建单例实例
const idataRFID = new iDataRFID();
export default idataRFID;
common/rfid-input-helper.js
New file
@@ -0,0 +1,354 @@
/**
 * 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插件未找到');
            return false;
        }
        // 监听上电事件(监听全局上电状态,RFID模块由App.vue初始化)
        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模块未上电');
            }
        });
        // 注意:RFID模块由App.vue在onLaunch时全局初始化
        // 这里只负责监听按键和读取标签,不初始化RFID模块
        return true;
    } catch (error) {
        console.error('[RFIDInputHelper] 初始化失败:', error);
        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;
    }
}
/**
 * 读取RFID标签(单标签读,无过滤)
 */
function readRFIDTag() {
    if (!uhfModel) {
        // 如果模块未初始化,尝试初始化
        uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule");
        if (!uhfModel) {
            console.warn('[RFIDInputHelper] RFID模块未找到');
            modal.toast({
                message: 'RFID模块未找到',
                duration: 1.5
            });
            return;
        }
    }
    // 检查RFID是否已上电(RFID模块由App.vue全局初始化)
    if (!isPowerOn) {
        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位字符
     */
    uhfModel.readTagWithoutFilter(1, 2, 6, "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值
                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]{16,})/i);
                    if (hexMatch && hexMatch[1]) {
                        epc = hexMatch[1];
                    }
                }
            }
            if (epc) {
                console.log('[RFIDInputHelper] ✓ 读取到标签EPC:', epc);
                // 自动填入当前焦点输入框
                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();
                    if (cleanRet.length >= 8) {
                        fillCurrentInput(cleanRet);
                        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) {
                const epc = ret.data.epc || ret.data;
                if (epc) {
                    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 inputFieldMap = [
            { field: 'barcode', focusField: 'barcodeFocus' },
            { field: 'matnr', focusField: 'matFocus' },
            { field: 'sourceSite', focusField: 'sourceSiteFocus' },
            { field: 'orderNo', focusField: 'orderNoFocus' },
            { field: 'targetSite', focusField: 'targetSiteFocus' },
            { field: 'locNo', focusField: 'locNoFocus' }
        ];
        // 只查找有焦点的输入框(光标所在的输入框)
        let focusedField = null;
        for (let item of inputFieldMap) {
            if (vm[item.field] !== undefined) {
                // 检查是否有焦点状态字段,并且焦点为true
                if (vm[item.focusField] === true) {
                    focusedField = item.field;
                    console.log(`[RFIDInputHelper] ✓ 找到有焦点的输入框: ${item.field}`);
                    break;
                }
            }
        }
        // 只填入有焦点的输入框,如果没有焦点则不填入
        if (focusedField) {
            console.log(`[RFIDInputHelper] 填入有焦点的输入框 ${focusedField}:`, epc);
            vm[focusedField] = epc;
            // 触发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] 未找到有焦点的输入框,不填入任何输入框');
            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
common/rfid-scanner.js
New file
@@ -0,0 +1,565 @@
/**
 * 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;
manifest.json
@@ -3,7 +3,7 @@
    "appid" : "__UNI__DA5854D",
    "description" : "",
    "versionName" : "20240420",
    "versionCode" : "100",
    "versionCode" : 100,
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
@@ -24,6 +24,7 @@
        "distribute" : {
            /* android打包配置 */
            "android" : {
                "packageName" : "uni.UNIDA5854D",
                "permissions" : [
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
@@ -97,6 +98,17 @@
                    "pid" : "2731",
                    "parameters" : {}
                }
            },
            "iData-UHFPlugin" : {
                "__plugin_info__" : {
                    "name" : "iData UHF扫描插件",
                    "description" : "实现了APP接收iData品牌扫描的UHF标签数据,适配iData品牌所有安卓PDA设备",
                    "platforms" : "Android",
                    "android_package_name" : "uni.UNIDA5854D",
                    "ios_bundle_id" : "",
                    "isCloud" : false,
                    "parameters" : {}
                }
            }
        }
    },
nativeplugins/iData-UHFPlugin/android/uhflib-release.aar
Binary files differ
nativeplugins/iData-UHFPlugin/license.md
New file
@@ -0,0 +1,7 @@
#iData Copyright (c) 2021 Lzy
###Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
###The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
###THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
nativeplugins/iData-UHFPlugin/package.json
New file
@@ -0,0 +1,26 @@
{
    "name": "iData UHF插件",
    "id": "iData-UHFPlugin",
    "version": "1.7",
    "description": "实现了APP接收iData品牌UHF标签读取。",
    "_dp_type": "nativeplugin",
    "_dp_nativeplugin": {
        "android": {
            "minSdkVersion": 23,
            "plugins": [{
                "type": "module",
                "name": "iData-UHFPlugin-UHFModule",
                "class": "com.idata.uhflib.UHFModule"
            }],
            "integrateType": "aar",
            "abis": [
                "arm64-v8a", "armeabi-v7a"
            ],
            "compileOptions": {
                "sourceCompatibility": "1.8",
                "targetCompatibility": "1.8"
            },
            "useAndroidX": true
        }
    }
}
pages.json
@@ -65,12 +65,37 @@
            }
        },
        {
            "path": "pages/AGV/agv_empty",
            "style": {
                "navigationBarTitleText": "AGV空托入库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stock/stockQuery",
            "style": {
                "navigationBarTitleText": "库存查询"
            }
        },
        {
            "path": "pages/rfid/settings",
            "style": {
                "navigationBarTitleText": "RFID设置"
            }
        },
        {
            "path": "pages/rfid/uhftest",
            "style": {
                "navigationBarTitleText": "UHF测试"
            }
        },
        {
            "path": "pages/rfid/uhftest2",
            "style": {
                "navigationBarTitleText": "UHF测试2"
            }
        },
        {
            "path": "pages/login/logOut",
            "style": {
                "navigationBarTitleText": "退出登录"
pages/AGV/agv_back.vue
@@ -9,7 +9,7 @@
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入托盘码" v-model="barcode" 
                        :focus="barcodeFocus" @input="barcodeInput()" />
                        :focus="barcodeFocus" @input="barcodeInput()" @focus="onBarcodeFocus()" />
                    <uni-icons v-if="barcode" type="clear" size="18" color="#c0c4cc" @click="clearBarcode"></uni-icons>
                </view>
            </view>
@@ -19,7 +19,7 @@
                    <text class="label-text">暂存位</text>
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入暂存位" v-model="sourceSite" />
                    <input class="form-input" type="text" placeholder="扫码 / 输入暂存位" v-model="sourceSite" @focus="onSourceSiteFocus()" />
                    <uni-icons v-if="sourceSite" type="clear" size="18" color="#c0c4cc" @click="sourceSite=''"></uni-icons>
                </view>
            </view>
@@ -181,6 +181,7 @@
</template>
<script>
    import rfidScanner from '@/common/rfid-scanner.js';
    export default {
        data() {
            return {
@@ -202,6 +203,7 @@
                content: '',
                barcodeFocus: true,
                matFocus: false,
                sourceSiteFocus: false,
                matData: '',
                removeNum: 0,
                ck1: true,
@@ -223,8 +225,33 @@
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // RFID已在App.vue中全局初始化,这里不需要再初始化
            // 设置当前页面实例,用于全局扫描时自动填入
            rfidScanner.setCurrentPageInstance(this);
        },
        methods: {
            // 托盘码输入框获得焦点(保留方法,但不自动触发扫描)
            onBarcodeFocus() {
                console.log('[agv_back] 托盘码输入框获得焦点');
                // 设置托盘码输入框为焦点,其他输入框失去焦点
                this.barcodeFocus = true;
                this.matFocus = false;
                if (this.sourceSiteFocus !== undefined) {
                    this.sourceSiteFocus = false;
                }
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            // 暂存位输入框获得焦点(保留方法,但不自动触发扫描)
            onSourceSiteFocus() {
                console.log('[agv_back] 暂存位输入框获得焦点');
                // 设置暂存位输入框为焦点,其他输入框失去焦点
                if (this.sourceSiteFocus !== undefined) {
                    this.sourceSiteFocus = true;
                }
                this.barcodeFocus = false;
                this.matFocus = false;
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            onTargetSiteChange(e) {
                const index = e.detail.value;
                this.selectedTargetSite = this.targetSiteList[index];
pages/AGV/agv_empty.vue
New file
@@ -0,0 +1,598 @@
<template>
    <view class="page-container">
        <!-- 表单区域 -->
        <view class="form-section">
            <view class="form-item">
                <view class="form-label">
                    <uni-icons type="scan" size="18" color="#667eea"></uni-icons>
                    <text class="label-text">托盘码</text>
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入托盘码" v-model="barcode"
                        :focus="barcodeFocus" @input="barcodeInput()" @focus="onBarcodeFocus()" @blur="onBarcodeBlur()" />
                    <uni-icons v-if="barcode" type="clear" size="18" color="#c0c4cc" @click="clearBarcode"></uni-icons>
                </view>
            </view>
            <view class="form-item">
                <view class="form-label">
                    <uni-icons type="location" size="18" color="#667eea"></uni-icons>
                    <text class="label-text">暂存位</text>
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入暂存位" v-model="sourceSite" @focus="onSourceSiteFocus()" />
                    <uni-icons v-if="sourceSite" type="clear" size="18" color="#c0c4cc" @click="sourceSite=''"></uni-icons>
                </view>
            </view>
        </view>
        <!-- 列表头部 -->
        <view class="list-header" v-if="showDetl">
            <view class="header-left">
                <text class="header-title">商品列表</text>
                <view class="count-badge" v-if="dataList.length > 0">
                    <text class="count-text">{{dataList.length}}</text>
                </view>
            </view>
        </view>
        <!-- 商品列表 -->
        <view class="list-container" v-if="showDetl">
            <view class="mat-card" v-for="(item, i) in dataList" :key="i">
                <!-- 卡片头部 -->
                <view class="card-top">
                    <view class="card-index">{{i + 1}}</view>
                    <view class="mat-code-wrap">
                        <text class="mat-code">{{item.matnr}}</text>
                    </view>
                </view>
                <!-- 卡片内容 -->
                <view class="card-content">
                    <view class="info-row">
                        <view class="info-col">
                            <text class="info-label">品名</text>
                            <text class="info-value">{{item.maktx || '-'}}</text>
                        </view>
                    </view>
                    <view class="info-row">
                        <view class="info-col half">
                            <text class="info-label">规格</text>
                            <text class="info-value">{{item.specs || '-'}}</text>
                        </view>
                        <view class="info-col half">
                            <text class="info-label">批号</text>
                            <text class="info-value highlight">{{item.batch || '-'}}</text>
                        </view>
                    </view>
                    <view class="info-row">
                        <view class="info-col half">
                            <text class="info-label">数量</text>
                            <text class="info-value qty">{{item.anfme}}</text>
                        </view>
                    </view>
                </view>
                <!-- 卡片操作 -->
                <view class="card-actions">
                    <view class="action-btn edit-btn" @click="revise(item, i)">
                        <uni-icons type="compose" size="18" color="#667eea"></uni-icons>
                        <text class="action-text">修改</text>
                    </view>
                    <view class="action-btn delete-btn" @click="remove(item, i, 'warn')">
                        <uni-icons type="trash" size="18" color="#f56c6c"></uni-icons>
                        <text class="action-text delete-text">移除</text>
                    </view>
                </view>
            </view>
            <!-- 空状态 -->
            <view class="empty-state" v-if="dataList.length === 0">
                <uni-icons type="cart" size="60" color="#CCCCCC"></uni-icons>
                <text class="empty-text">暂无商品</text>
                <text class="empty-hint">请扫描物料码添加商品</text>
            </view>
            <!-- 底部占位 -->
            <view class="bottom-placeholder"></view>
        </view>
        <!-- 底部操作按钮 -->
        <view class="bottom-bar">
            <view class="btn-reset" @click="reset('warn')">
                <uni-icons type="refresh" size="18" color="#909399"></uni-icons>
                <text class="btn-text">重置</text>
            </view>
            <view class="btn-submit" :class="{'btn-disabled': isSubmitting || barcode === ''}" @click="combConfirm('warn')">
                <uni-icons type="checkbox" size="18" color="#ffffff"></uni-icons>
                <text class="btn-text">确认呼叫</text>
            </view>
        </view>
        <!-- 弹窗区域 -->
        <!-- 修改数量 -->
        <uni-popup ref="revise" type="dialog">
            <view class="popup-card">
                <view class="popup-header">
                    <text class="popup-title">修改信息</text>
                </view>
                <view class="popup-body">
                    <view class="popup-row">
                        <text class="popup-label">编码</text>
                        <view class="popup-value disabled">{{editMatnr}}</view>
                    </view>
                    <view class="popup-row">
                        <text class="popup-label">批号</text>
                        <input class="popup-value input" type="text" v-model="batch" placeholder="输入批号" />
                    </view>
                    <view class="popup-row">
                        <text class="popup-label">数量</text>
                        <view class="popup-value number">
                            <uni-number-box :value="count" :step='0.01' :max="9999999" color="#747474" @change="changeValue" />
                        </view>
                    </view>
                </view>
                <view class="popup-footer">
                    <view class="popup-btn cancel" @click="reviseClose">取消</view>
                    <view class="popup-btn confirm" @click="reviseConfirm()">确认</view>
                </view>
            </view>
        </uni-popup>
        <!-- 移除确认 -->
        <uni-popup ref="alertDialog" type="dialog">
            <uni-popup-dialog :type="msgType" confirmText="移除" :title="title" :content="content"
                @confirm="removeConfirm()" @close="removeClose"></uni-popup-dialog>
        </uni-popup>
        <!-- 提示信息弹窗 -->
        <uni-popup ref="message" type="message">
            <uni-popup-message :type="msgType1" :message="messageText" :duration="2000"></uni-popup-message>
        </uni-popup>
        <!-- 确认组托 -->
        <uni-popup ref="combConfirm" type="dialog">
            <uni-popup-dialog :type="msgType" cancelText="取消" confirmText="确认" :title="title" :content="content"
                @confirm="comb" @close="combClose"></uni-popup-dialog>
        </uni-popup>
        <!-- 确认重置 -->
        <uni-popup ref="resetConfirm" type="dialog">
            <uni-popup-dialog :type="msgType" cancelText="取消" confirmText="确认" :title="title" :content="content"
                @confirm="resetConfirm" @close="resetClose"></uni-popup-dialog>
        </uni-popup>
    </view>
</template>
<script>
    // #ifdef APP-PLUS
    import rfidScanner from '@/common/rfid-scanner.js';
    // #endif
    export default {
        data() {
            return {
                showDetl:false,
                baseUrl: '',
                token: '',
                barcode: '',
                dataList: [],
                count: 0,
                rowNum: '',
                matnr: '',
                editMatnr: '',
                batch: '',
                weight: '',
                msgType1: 'success',
                msgType: 'success',
                messageText: '',
                title: '',
                content: '',
                barcodeFocus: true,
                matFocus: false,
                sourceSiteFocus: false,
                matData: '',
                removeNum: 0,
                ck1: true,
                ck2: false,
                isFull: true,
                isSubmitting: false,
                sourceSite:'',
                targetSiteList: [
                    { label: '101', value: '101' },
                    { label: '102', value: '102' }
                ],
                selectedTargetSite: { label: '101', value: '101' },
                type : 3
            }
        },
        onLoad() {
        },
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // #ifdef APP-PLUS
            // RFID已在App.vue中全局初始化,这里不需要再初始化
            // 设置当前页面实例,用于全局扫描时自动填入
            try {
                if (typeof rfidScanner !== 'undefined' && rfidScanner && typeof rfidScanner.setCurrentPageInstance === 'function') {
                    rfidScanner.setCurrentPageInstance(this);
                }
            } catch (e) {
                console.warn('[agv_empty] RFID模块初始化失败:', e);
            }
            // #endif
        },
        onHide() {
            // #ifdef APP-PLUS
            // 页面隐藏时停止RFID扫描(但不下电)
            // 注意:不再自动停止扫描,因为全局扫描模式支持跨页面扫描
            // 如果需要页面隐藏时停止扫描,可以取消下面的注释
            // try {
            //     if (typeof rfidScanner !== 'undefined' && rfidScanner && typeof rfidScanner.stopScan === 'function') {
            //         rfidScanner.stopScan();
            //     }
            // } catch (e) {
            //     console.warn('[agv_empty] RFID模块停止失败:', e);
            // }
            // #endif
        },
        methods: {
            // 托盘码输入框获得焦点(保留方法,但不自动触发扫描)
            onBarcodeFocus() {
                console.log('[agv_empty] 托盘码输入框获得焦点');
                // 设置托盘码输入框为焦点,其他输入框失去焦点
                this.barcodeFocus = true;
                this.matFocus = false;
                if (this.sourceSiteFocus !== undefined) {
                    this.sourceSiteFocus = false;
                }
                // #ifdef APP-PLUS
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
                // #endif
            },
            // 托盘码输入框失去焦点时停止RFID扫描(可选)
            onBarcodeBlur() {
                console.log('[agv_empty] 托盘码输入框失去焦点');
                // #ifdef APP-PLUS
                // 注意:不再自动停止扫描,因为全局扫描模式支持持续扫描
                // 如果需要失去焦点时停止扫描,可以取消下面的注释
                // setTimeout(() => {
                //     try {
                //         if (typeof rfidScanner !== 'undefined' && rfidScanner && typeof rfidScanner.stopScan === 'function') {
                //             rfidScanner.stopScan();
                //         }
                //     } catch (e) {
                //         console.warn('[agv_empty] RFID模块停止失败:', e);
                //     }
                // }, 1000);
                // #endif
            },
            // 暂存位输入框获得焦点(保留方法,但不自动触发扫描)
            onSourceSiteFocus() {
                console.log('[agv_empty] 暂存位输入框获得焦点');
                // 设置暂存位输入框为焦点,其他输入框失去焦点
                if (this.sourceSiteFocus !== undefined) {
                    this.sourceSiteFocus = true;
                }
                this.barcodeFocus = false;
                this.matFocus = false;
                // #ifdef APP-PLUS
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
                // #endif
            },
            onTargetSiteChange(e) {
                const index = e.detail.value;
                this.selectedTargetSite = this.targetSiteList[index];
            },
            clearBarcode() {
                this.barcode = '';
                this.barcodeFocus = false;
                setTimeout(() => {
                    this.barcodeFocus = true;
                }, 100);
            },
            clearMatnr() {
                this.matnr = '';
                this.matFocus = false;
                setTimeout(() => {
                    this.matFocus = true;
                }, 100);
            },
            isFrozen() {
                this.isFull = !this.isFull
                console.log(this.isFull);
            },
            messageToggle(type) {
                this.msgType1 = type
                this.$refs.message.open()
            },
            // barcode input 事件
            barcodeInput() {
                // #ifdef APP-PLUS
                // 注意:不再自动停止扫描,因为全局扫描模式支持持续扫描
                // 如果需要输入完成后停止扫描,可以取消下面的注释
                // setTimeout(() => {
                //     try {
                //         if (typeof rfidScanner !== 'undefined' && rfidScanner && typeof rfidScanner.stopScan === 'function') {
                //             rfidScanner.stopScan();
                //         }
                //     } catch (e) {
                //         console.warn('[agv_empty] RFID模块停止失败:', e);
                //     }
                // }, 500);
                // #endif
                // 不设置定时器 会出现扫入的字符串不全
                setTimeout(() => {
                    var len = this.barcode.length
                    if (len >= 9 && len <=8) {
                        uni.showToast({
                            title: '托盘码有误请重试',
                            icon: "none",
                            position: 'top'
                        });
                        this.barcodeFocuss()
                        return;
                    }
                    this.focuss()
                }, 200)
            },
            // 托盘码有误重置
            barcodeFocuss() {
                let that = this;
                that.barcodeFocus = false;
                setTimeout(() => {
                    that.barcode = '';
                    that.barcodeFocus = true;
                }, 100);
            },
            // 商品光标清空重置
            focuss() {
                this.focus = false;
                setTimeout(() => {
                    this.matnr = '';
                    this.matFocus = true;
                }, 100);
            },
            // 搜索物料
            findMat() {
                let that = this
                uni.request({
                    url: that.baseUrl + '/mat/auth',
                    data: {
                        matnr: that.matnr
                    },
                    header: {
                        'token': uni.getStorageSync('token')
                    },
                    success(result) {
                        result = result.data
                        if (result.code === 200 && result.data) {
                            that.matData = result.data
                            that.matnr = ''
                            that.matData['batch'] = ''
                            uni.navigateTo({
                                url: "../mat/matSelected",
                                // 通过eventChannel向被打开页面传送数据
                                success: function(res) {
                                    res.eventChannel.emit('mat', {
                                        data: result.data
                                    })
                                },
                                // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
                                events: {
                                    matList: function(data) {
                                        that.checkMat(data.data)
                                        that.focuss()
                                    },
                                },
                            });
                        } else if (result.code == 403) {
                            uni.showToast({
                                title: result.msg,
                                icon: "none",
                                position: 'top'
                            })
                            setTimeout(() => {
                                uni.reLaunch({
                                    url: '../login/login'
                                });
                            }, 1000);
                        } else {
                            uni.showToast({
                                title: result.msg,
                                icon: "none",
                                position: 'top'
                            })
                        }
                    }
                });
            },
            selectMat() {
                let that = this
                uni.navigateTo({
                    url: "../mat/matQuery",
                    success: function(res) {
                        // 通过eventChannel向被打开页面传送数据   向另外一个页面传递值的
                        res.eventChannel.emit('commonUrl', {
                            commonUrl: ''
                        })
                    },
                    events: {
                        // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据  另外一个页面传过来的
                        acceptDataFromOpenedPage: function(data) {
                            that.matnr = data.data
                            that.findMat(that.matnr)
                        },
                    },
                });
                that.matnr = ''
            },
            checkMat(mat) {
                var len = this.dataList.length
                var add = true ,sameItem = false
                for (var i = 0; i < len; i++) {
                    if (mat.matnr == this.dataList[i].matnr) {
                        for (var j = 0; j < len; j++) {
                            if (mat.batch == this.dataList[j].batch) {
                                sameItem = true
                            }
                        }
                        // 相同物料 不同批号  新加列表
                        if (mat.batch != this.dataList[i].batch) {
                            this.$forceUpdate() // 强制刷新
                            if (sameItem) {
                                add = false
                            } else {
                                add = true
                            }
                        } else {
                            // 相同物料相同批号 数量累加
                            this.dataList[i].anfme += mat.anfme
                            this.$forceUpdate() // 强制刷新
                            add = false
                        }
                    }
                }
                if (add) {
                    this.dataList.unshift(mat)
                }
            },
            // 修改批号
            revise(item, i) {
                this.editMatnr = this.dataList[i].matnr
                this.count = this.dataList[i].anfme
                this.batch = this.dataList[i].batch
                this.weight = this.dataList[i].weight
                this.rowNum = i
                this.eject()
            },
            eject(type) {
                this.type = type
                this.$refs.revise.open(type)
            },
            // 列表移除按钮
            remove(item, i, type) {
                this.removeNum  = i
                this.msgType = type
                this.title = '确认移除'
                this.content = '是否移除该商品?'
                this.$refs.alertDialog.open(i)
            },
            // 确认移除
            removeConfirm() {
                this.messageText = "移除成功"
                this.messageToggle('success')
                this.dataList.splice(this.removeNum, 1)
            },
            // 取消移除
            removeClose() {
                this.$refs.alertDialog.close()
            },
            reviseConfirm() {
                this.dataList[this.rowNum].anfme = this.count
                this.dataList[this.rowNum].batch = this.batch
                this.dataList[this.rowNum].weight = this.weight
                this.editMatnr = ''
                this.messageText = "修改成功"
                this.messageToggle('success')
                this.$refs.revise.close()
            },
            reviseClose() {
                this.$refs.revise.close()
            },
            changeValue(value) {
                this.count = value
            },
            combConfirm(type) {
                if (this.isSubmitting || this.barcode === '' || this.sourceSite === '') return;
                this.msgType = type
                this.title = '确认呼叫'
                this.content = '确认呼叫?'
                this.$refs.combConfirm.open()
            },
            combClose() {
                this.$refs.combConfirm.close()
            },
            comb() {
                uni.vibrateShort();
                let that = this;
                that.isSubmitting = true;
                uni.request({
                    url: that.baseUrl + '/mobile/agv/start',
                    data: JSON.stringify({
                        type : that.type,
                        barcode: that.barcode,
                        sourceSite:that.sourceSite
                    }),
                    method: 'POST',
                    header: {
                        'token': uni.getStorageSync('token')
                    },
                    success(result) {
                        var res = result.data
                        if (res.code === 200) {
                            that.resst();
                            that.messageText = "呼叫成功"
                            that.messageToggle('success')
                        } else if (res.code == 403) {
                            that.messageText = res.msg
                            that.messageToggle('error')
                            setTimeout(() => {
                                uni.reLaunch({
                                    url: '../login/login'
                                });
                            }, 1000);
                        } else {
                            that.messageText = res.msg
                            that.messageToggle('error')
                        }
                    },
                    fail: () => {
                        that.messageText = "网络请求超时"
                        that.messageToggle('error')
                    },
                    complete: () => {
                        that.isSubmitting = false;
                    }
                });
            },
            reset(type) {
                this.msgType = type
                this.title = '确认重置'
                this.content = '是否清空所有数据?'
                this.$refs.resetConfirm.open()
            },
            // 确认重置
            resetConfirm() {
                this.dataList = []
                this.barcode = ''
                this.messageText = "重置完成"
                this.messageToggle('success')
            },
            // 取消重置
            resetClose() {
            },
            // 清空
            resst() {
                // this.dataList = []
                this.barcode = ''
                this.sourceSite = ''
                this.barcodeFocuss()
            },
        }
    }
</script>
<style>
    /* 引入公共样式 */
    @import url('../../static/css/common.css');
    /* @import url('../../static/css/wms.css/wms.css'); */
</style>
pages/AGV/agv_start.vue
@@ -9,7 +9,7 @@
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入托盘码" v-model="barcode" 
                        :focus="barcodeFocus" @input="barcodeInput()" />
                        :focus="barcodeFocus" @input="barcodeInput()" @focus="onBarcodeFocus()" @blur="onBarcodeBlur()" />
                    <uni-icons v-if="barcode" type="clear" size="18" color="#c0c4cc" @click="clearBarcode"></uni-icons>
                </view>
            </view>
@@ -19,7 +19,7 @@
                    <text class="label-text">暂存位</text>
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入暂存位" v-model="sourceSite" />
                    <input class="form-input" type="text" placeholder="扫码 / 输入暂存位" v-model="sourceSite" @focus="onSourceSiteFocus()" />
                    <uni-icons v-if="sourceSite" type="clear" size="18" color="#c0c4cc" @click="sourceSite=''"></uni-icons>
                </view>
            </view>
@@ -181,6 +181,7 @@
</template>
<script>
    import rfidScanner from '@/common/rfid-scanner.js';
    export default {
        data() {
            return {
@@ -223,8 +224,36 @@
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // RFID已在App.vue中全局初始化,这里不需要再初始化
            // 设置当前页面实例,用于全局扫描时自动填入
            rfidScanner.setCurrentPageInstance(this);
        },
        onHide() {
            // 页面隐藏时停止RFID扫描(但不下电)
            // 注意:不再自动停止扫描,因为全局扫描模式支持跨页面扫描
            // 如果需要页面隐藏时停止扫描,可以取消下面的注释
            // rfidScanner.stopScan();
        },
        methods: {
            // 托盘码输入框获得焦点(保留方法,但不自动触发扫描)
            onBarcodeFocus() {
                console.log('[agv_start] 托盘码输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            // 托盘码输入框失去焦点时停止RFID扫描(可选)
            onBarcodeBlur() {
                console.log('[agv_start] 托盘码输入框失去焦点');
                // 注意:不再自动停止扫描,因为全局扫描模式支持持续扫描
                // 如果需要失去焦点时停止扫描,可以取消下面的注释
                // setTimeout(() => {
                //     rfidScanner.stopScan();
                // }, 1000);
            },
            // 暂存位输入框获得焦点(保留方法,但不自动触发扫描)
            onSourceSiteFocus() {
                console.log('[agv_start] 暂存位输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            onTargetSiteChange(e) {
                const index = e.detail.value;
                this.selectedTargetSite = this.targetSiteList[index];
@@ -253,6 +282,12 @@
            },
            // barcode input 事件
            barcodeInput() {
                // 注意:不再自动停止扫描,因为全局扫描模式支持持续扫描
                // 如果需要输入完成后停止扫描,可以取消下面的注释
                // setTimeout(() => {
                //     rfidScanner.stopScan();
                // }, 500);
                // 不设置定时器 会出现扫入的字符串不全
                setTimeout(() => {
                    var len = this.barcode.length
pages/home/home.vue
@@ -151,11 +151,32 @@
                        url: '/AGV/agv_back'
                    },
                    {
                        title: 'AGV空托入库',
                        name: 'agv_empty',
                        color: 'pink',
                        cuIcon: '',
                        url: '/AGV/agv_empty'
                    },
                    {
                        title: '库存查询',
                        name: 'stockQuery',
                        color: 'green',
                        cuIcon: '',
                        url: '/stock/stockQuery'
                    },
                    {
                        title: 'RFID设置',
                        name: 'rfidSettings',
                        color: 'mauve',
                        cuIcon: 'scan',
                        url: '/rfid/settings'
                    },
                    {
                        title: 'UHF测试',
                        name: 'uhftest',
                        color: 'red',
                        cuIcon: 'scan',
                        url: '/rfid/uhftest'
                    },
                    {
                        title: '退出登录',
@@ -178,6 +199,9 @@
                    'stockCheck': 'checkbox',
                    'agv_start': 'navigate',
                    'agv_back': 'refresh',
                    'agv_empty': 'upload',
                    'rfidSettings': 'scan',
                    'uhftest': 'scan',
                },
                // 菜单分类配置(仅分类模式使用)
                // key: 分类唯一标识
@@ -198,7 +222,7 @@
                        name: 'AGV管理',
                        color: 'blue',
                        icon: 'navigate',
                        menuNames: ['agv_start', 'agv_back']
                        menuNames: ['agv_start', 'agv_back', 'agv_empty']
                    },
                    {
                        key: 'stock_category',
@@ -206,6 +230,13 @@
                        color: 'green',
                        icon: 'search',
                        menuNames: ['stockQuery']
                    },
                    {
                        key: 'device_category',
                        name: '设备设置',
                        color: 'mauve',
                        icon: 'settings',
                        menuNames: ['rfidSettings', 'uhftest']
                    }
                ],
                // 不参与分类的菜单项(如退出登录,始终单独显示)
pages/order/orderPakin2.vue
@@ -22,7 +22,7 @@
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入托盘码" v-model="barcode" 
                        :focus="barcodeFocus" @input="barcodeInput()" />
                        :focus="barcodeFocus" @input="barcodeInput()" @focus="onBarcodeFocus()" />
                    <uni-icons v-if="barcode" type="clear" size="20" color="#c0c4cc" @click="clearBarcode"></uni-icons>
                </view>
            </view>
@@ -35,7 +35,7 @@
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码复核物料" v-model="matnr" 
                        :focus="matFocus" @input="findMat()" />
                        :focus="matFocus" @input="findMat()" @focus="onMatnrFocus()" />
                </view>
            </view>
        </view>
@@ -186,6 +186,7 @@
</template>
<script>
    import rfidScanner from '@/common/rfid-scanner.js';
    export default {
        data() {
            return {
@@ -231,8 +232,21 @@
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // RFID已在App.vue中全局初始化,这里不需要再初始化
            // 设置当前页面实例,用于全局扫描时自动填入
            rfidScanner.setCurrentPageInstance(this);
        },
        methods: {
            // 托盘码输入框获得焦点(保留方法,但不自动触发扫描)
            onBarcodeFocus() {
                console.log('[orderPakin2] 托盘码输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            // 物料码输入框获得焦点(保留方法,但不自动触发扫描)
            onMatnrFocus() {
                console.log('[orderPakin2] 物料码输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            messageToggle(type) {
                this.msgType1 = type;
                this.$refs.message.open();
pages/pakin/pakin.vue
@@ -9,7 +9,7 @@
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入托盘码" v-model="barcode" 
                        :focus="barcodeFocus" @input="barcodeInput()" />
                        :focus="barcodeFocus" @input="barcodeInput()" @focus="onBarcodeFocus()" @blur="onBarcodeBlur()" />
                    <uni-icons v-if="barcode" type="clear" size="18" color="#c0c4cc" @click="clearBarcode"></uni-icons>
                </view>
            </view>
@@ -20,7 +20,7 @@
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入物料码" v-model="matnr" 
                        :focus="matFocus" @input="findMat()" />
                        :focus="matFocus" @input="findMat()" @focus="onMatnrFocus()" />
                    <uni-icons v-if="matnr" type="clear" size="18" color="#c0c4cc" @click="clearMatnr"></uni-icons>
                </view>
            </view>
@@ -168,6 +168,8 @@
</template>
<script>
    import rfidScanner from '@/common/rfid-scanner.js';
    export default {
        data() {
            return {
@@ -202,8 +204,36 @@
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // RFID已在App.vue中全局初始化,这里不需要再初始化
            // 设置当前页面实例,用于全局扫描时自动填入
            rfidScanner.setCurrentPageInstance(this);
        },
        onHide() {
            // 页面隐藏时停止RFID扫描(但不下电)
            // 注意:不再自动停止扫描,因为全局扫描模式支持跨页面扫描
            // 如果需要页面隐藏时停止扫描,可以取消下面的注释
            // rfidScanner.stopScan();
        },
        methods: {
            // 托盘码输入框获得焦点(保留方法,但不自动触发扫描)
            onBarcodeFocus() {
                console.log('[pakin] 托盘码输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            // 托盘码输入框失去焦点时停止RFID扫描(可选)
            onBarcodeBlur() {
                console.log('[pakin] 托盘码输入框失去焦点');
                // 注意:不再自动停止扫描,因为全局扫描模式支持持续扫描
                // 如果需要失去焦点时停止扫描,可以取消下面的注释
                // setTimeout(() => {
                //     rfidScanner.stopScan();
                // }, 1000);
            },
            // 物料码输入框获得焦点(保留方法,但不自动触发扫描)
            onMatnrFocus() {
                console.log('[pakin] 物料码输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            clearBarcode() {
                this.barcode = '';
                this.barcodeFocus = false;
@@ -228,6 +258,12 @@
            },
            // barcode input 事件
            barcodeInput() {
                // 注意:不再自动停止扫描,因为全局扫描模式支持持续扫描
                // 如果需要输入完成后停止扫描,可以取消下面的注释
                // setTimeout(() => {
                //     rfidScanner.stopScan();
                // }, 500);
                // 不设置定时器 会出现扫入的字符串不全
                setTimeout(() => {
                    var len = this.barcode.length
pages/rfid/settings.vue
New file
@@ -0,0 +1,800 @@
<template>
    <view class="page-container">
        <!-- 状态栏 -->
        <view class="status-section">
            <view class="status-card">
                <view class="status-item">
                    <text class="status-label">上电状态</text>
                    <text class="status-value" :class="{'success': powerStatus === 'connected', 'error': powerStatus !== 'connected'}">
                        {{ powerStatus === 'connected' ? '已连接' : '未连接' }}
                    </text>
                </view>
                <view class="status-item">
                    <text class="status-label">扫描状态</text>
                    <text class="status-value" :class="{'success': isScanning, 'error': !isScanning}">
                        {{ isScanning ? '扫描中' : '未扫描' }}
                    </text>
                </view>
            </view>
        </view>
        <!-- 扫描结果显示 -->
        <view class="scan-result-section">
            <view class="section-header">
                <text class="section-title">扫描结果 ({{ scanResults.length }})</text>
                <view class="btn-clear" @click="clearResults">
                    <uni-icons type="trash" size="16" color="#f56c6c"></uni-icons>
                    <text class="btn-clear-text">清空</text>
                </view>
            </view>
            <scroll-view class="result-list" scroll-y>
                <view class="result-item" v-for="(item, index) in scanResults" :key="index">
                    <view class="result-header">
                        <text class="result-index">#{{ index + 1 }}</text>
                        <text class="result-time">{{ item.time }}</text>
                    </view>
                    <view class="result-content">
                        <view class="result-row" v-if="item.epc">
                            <text class="result-label">EPC:</text>
                            <text class="result-value">{{ item.epc }}</text>
                        </view>
                        <view class="result-row" v-if="item.tid">
                            <text class="result-label">TID:</text>
                            <text class="result-value">{{ item.tid }}</text>
                        </view>
                    </view>
                </view>
                <view class="empty-result" v-if="scanResults.length === 0">
                    <text class="empty-text">暂无扫描结果</text>
                    <text class="empty-hint">请将标签放在读取范围内</text>
                </view>
            </scroll-view>
        </view>
        <!-- 控制按钮 -->
        <view class="control-section">
            <button class="btn-control" :class="{'btn-scanning': isScanning}" @click.stop="handleStartStopScan" @tap.stop="handleStartStopScan">
                {{ isScanning ? '停止扫描' : '开始扫描' }}
            </button>
        </view>
    </view>
</template>
<script>
    import idataRFID from '@/common/idata-rfid.js';
    export default {
        data() {
            return {
                isScanning: false,
                powerStatus: 'disconnected',
                scanResults: [],
                moduleTypeIndex: 0, // 0=UM模块, 1=SLR模块, 2=GX模块
                initRetryCount: 0,
                maxRetryCount: 3,
                readTagTimer: null, // 单标签读取定时器
                readTagInterval: 300, // 读取间隔(毫秒)- 缩短到300ms,更快轮换
                currentMethod: 0, // 当前使用的方法索引
                methodNames: ['连续扫描', '单标签读取EPC', '单标签读取TID', '单标签读取EPC(地址0)', '单标签读取EPC(地址1)'],
                methodCounter: 0, // 方法调用计数器
                methodMaxRetries: 5, // 每种方法最多尝试5次(约1.5秒)就切换到下一个
                methodSwitchTimer: null // 方法切换定时器
            }
        },
        onShow() {
            // 参考示例项目:在 onShow() 中初始化
            console.log('[RFID] ========== onShow() 页面显示 ==========');
            // 监听上电事件(参考示例项目:在 onShow() 中监听)
            idataRFID.onPowerEvent((e) => {
                console.log('[RFID] POWEREvent:', JSON.stringify(e));
                if (e && e.status === 'connected') {
                    this.powerStatus = 'connected';
                    console.log('[RFID] ✓ 模块已上电');
                    // 上电成功后,先设置参数,再开启扫描
                    this.setupAndStartScan();
                } else {
                    this.powerStatus = 'disconnected';
                    console.log('[RFID] ✗ 模块未上电');
                }
            });
            // 监听扫描事件(连续扫描模式 - 方法1使用)
            idataRFID.onScanEvent((e) => {
                console.log('[RFID] ========== 【方法1】iDataUHFEvent 事件触发 ==========');
                console.log('[RFID] 【方法1】事件数据:', JSON.stringify(e));
                if (e) {
                    const result = {
                        epc: e.epc || '',
                        tid: e.tid || '',
                        time: new Date().toLocaleTimeString()
                    };
                    console.log('[RFID] 【方法1】✓✓✓✓✓ 成功扫描到标签,EPC:', result.epc, 'TID:', result.tid);
                    // 如果方法1成功,清除切换定时器,停止轮换
                    if (this.methodSwitchTimer) {
                        clearTimeout(this.methodSwitchTimer);
                        this.methodSwitchTimer = null;
                        console.log('[RFID] 【方法1】成功!停止轮换,继续使用连续扫描模式');
                    }
                    // 检查是否已存在(避免重复)
                    const exists = this.scanResults.some(item =>
                        (item.epc && item.epc === result.epc) ||
                        (item.tid && item.tid === result.tid)
                    );
                    if (!exists) {
                        this.scanResults.unshift(result);
                        // 限制最多保存100条
                        if (this.scanResults.length > 100) {
                            this.scanResults = this.scanResults.slice(0, 100);
                        }
                        idataRFID.showToast('扫描到标签');
                    }
                } else {
                    console.warn('[RFID] 【方法1】扫描事件数据为空');
                }
                console.log('[RFID] ====================================');
            });
            // 自动初始化(参考示例项目:在 onShow() 中初始化)
            this.autoInit();
        },
        onHide() {
            // 参考示例项目:在 onHide() 中清理
            console.log('[RFID] ========== onHide() 页面隐藏 ==========');
            this.stopReadTag();
            idataRFID.closeUHF();
            idataRFID.removeEventListeners();
        },
        onLoad() {
            // 页面加载时不做任何操作,等待 onShow() 触发
            console.log('[RFID] ========== onLoad() 页面加载 ==========');
        },
        onUnload() {
            // 参考示例项目:在 onUnload() 中清理
            console.log('[RFID] ========== onUnload() 页面卸载 ==========');
            this.stopReadTag();
            idataRFID.closeUHF();
            idataRFID.removeEventListeners();
        },
        methods: {
            // 自动初始化
            autoInit() {
                console.log('[RFID] ========== 自动初始化模块 ==========');
                console.log('[RFID] 模块类型:', ['UM模块', 'SLR模块', 'GX模块'][this.moduleTypeIndex]);
                idataRFID.initUHF(this.moduleTypeIndex, (ret) => {
                    console.log('[RFID] initUHF result:', JSON.stringify(ret));
                    if (ret && (ret.code === 'success' || (typeof ret === 'string' && ret.includes('success')))) {
                        console.log('[RFID] ✓ 初始化成功,等待上电...');
                    } else {
                        // 如果失败,尝试其他模块类型
                        this.initRetryCount++;
                        if (this.initRetryCount < this.maxRetryCount) {
                            console.log('[RFID] 初始化失败,尝试其他模块类型...');
                            this.moduleTypeIndex = (this.moduleTypeIndex + 1) % 3;
                            setTimeout(() => {
                                this.autoInit();
                            }, 2000);
                        } else {
                            console.error('[RFID] ✗ 初始化失败,已尝试所有模块类型');
                            console.error('[RFID] 请手动选择正确的模块类型');
                        }
                    }
                });
            },
            // 设置参数并开启扫描
            setupAndStartScan() {
                if (this.powerStatus !== 'connected') {
                    console.log('[RFID] 模块未上电,无法设置参数');
                    return;
                }
                console.log('[RFID] ========== 设置参数并开启扫描 ==========');
                // 步骤1:设置功率(25,如果失败也不影响)
                console.log('[RFID] 步骤1: 设置功率为25...');
                idataRFID.setPower(25, (ret) => {
                    console.log('[RFID] setPower result:', JSON.stringify(ret));
                    if (ret && ret.code === 'success') {
                        console.log('[RFID] ✓ 功率设置成功');
                    } else {
                        console.log('[RFID] ⚠ 功率设置失败(可能不支持或已设置):', ret ? ret.msg : '未知错误');
                    }
                    // 步骤2:设置频率(1=中国920-925MHz)
                    setTimeout(() => {
                        console.log('[RFID] 步骤2: 设置频率为中国(920-925MHz)...');
                        idataRFID.setFrequencyMode(1, (ret) => {
                            console.log('[RFID] setFrequencyMode result:', JSON.stringify(ret));
                            if (ret && ret.code === 'success') {
                                console.log('[RFID] ✓ 频率设置成功');
                            } else {
                                console.log('[RFID] ⚠ 频率设置失败(可能不支持或已设置):', ret ? ret.msg : '未知错误');
                            }
                                    // 步骤3:设置读取模式(参考UHFDemo:先设置读取模式,再开启扫描)
                                    setTimeout(() => {
                                        console.log('[RFID] 步骤3: 设置读取模式为EPC(参考UHFDemo流程)...');
                                        idataRFID.readTagModeSet(0, (ret) => {
                                            console.log('[RFID] readTagModeSet result:', JSON.stringify(ret));
                                            if (ret && (ret.code === 'success' || (typeof ret === 'string' && ret.includes('success')))) {
                                                console.log('[RFID] ✓ 读取模式设置成功');
                                            } else {
                                                console.log('[RFID] ⚠ 读取模式设置失败(可能不支持):', ret);
                                            }
                                            // 步骤4:延迟1秒后开启连续扫描(参考UHFDemo:startInventoryTag后立即开始读取)
                                            setTimeout(() => {
                                                console.log('[RFID] ========== 参考UHFDemo流程开启扫描 ==========');
                                                console.log('[RFID] UHFDemo流程: powerOn() → startInventoryTag() → readTagFromBuffer()循环');
                                                console.log('[RFID] iData流程: initUHF() → POWEREvent → readTagModeSet() → startOrStopRFID() → iDataUHFEvent');
                                                this.startReadTagLoop();
                                            }, 1000);
                                        });
                                    }, 500);
                        });
                    }, 500);
                });
            },
            // 开启读取(轮换尝试不同方法)
            startReadTagLoop() {
                if (this.powerStatus !== 'connected') {
                    console.log('[RFID] 模块未上电,无法开启读取');
                    idataRFID.showToast('模块未上电');
                    return;
                }
                if (this.isScanning) {
                    console.log('[RFID] 读取已在进行中');
                    return;
                }
                console.log('[RFID] ========== 开始轮换尝试不同方法 ==========');
                console.log('[RFID] 当前方法:', this.methodNames[this.currentMethod]);
                console.log('[RFID] 【提示】请将标签放在读取范围内(5-10cm)');
                this.isScanning = true;
                this.methodCounter = 0;
                // 根据当前方法索引选择不同的读取方式
                this.tryCurrentMethod();
            },
            // 尝试当前方法
            tryCurrentMethod() {
                if (!this.isScanning || this.powerStatus !== 'connected') {
                    console.log('[RFID] tryCurrentMethod: 已停止或未上电,退出');
                    return;
                }
                // 方法1特殊处理:只执行一次,等待事件
                if (this.currentMethod === 0) {
                    if (this.methodCounter === 0) {
                        this.methodCounter = 1;
                        console.log(`[RFID] ========== 方法1: 连续扫描 (开始,等待3秒) ==========`);
                        this.methodContinuousScan();
                        // 设置超时,3秒后切换到下一个方法
                        this.methodSwitchTimer = setTimeout(() => {
                            if (this.isScanning && this.scanResults.length === 0) {
                                console.log(`[RFID] 【方法1】3秒未扫描到标签,切换到下一个方法`);
                                this.switchToNextMethod();
                            }
                        }, 3000);
                    }
                    return; // 方法1只执行一次,直接返回
                }
                // 方法2-5:循环尝试
                this.methodCounter++;
                const elapsedTime = (this.methodCounter * this.readTagInterval / 1000).toFixed(1);
                console.log(`[RFID] ========== 方法${this.currentMethod + 1}: ${this.methodNames[this.currentMethod]} (第${this.methodCounter}次,已用时${elapsedTime}秒) ==========`);
                switch(this.currentMethod) {
                    case 1:
                        // 方法2: 单标签读取EPC(地址2)
                        this.methodReadEPC(2);
                        break;
                    case 2:
                        // 方法3: 单标签读取TID(地址0)
                        this.methodReadTID(0);
                        break;
                    case 3:
                        // 方法4: 单标签读取EPC(地址0)
                        this.methodReadEPC(0);
                        break;
                    case 4:
                        // 方法5: 单标签读取EPC(地址1)
                        this.methodReadEPC(1);
                        break;
                }
                // 如果当前方法尝试次数达到上限,切换到下一个方法
                if (this.methodCounter >= this.methodMaxRetries) {
                    console.log(`[RFID] 【方法${this.currentMethod + 1}】已尝试${this.methodCounter}次,切换到下一个方法`);
                    this.switchToNextMethod();
                } else {
                    // 继续尝试当前方法
                    setTimeout(() => {
                        if (this.isScanning && this.powerStatus === 'connected' && this.currentMethod !== 0) {
                            this.tryCurrentMethod();
                        }
                    }, this.readTagInterval);
                }
            },
            // 方法1: 连续扫描模式(参考UHFDemo:startInventoryTag + readTagFromBuffer循环)
            methodContinuousScan() {
                console.log('[RFID] 【方法1】连续扫描模式 - startOrStopRFID(对应UHFDemo的startInventoryTag)');
                console.log('[RFID] 【方法1】参考UHFDemo: startInventoryTag() → readTagFromBuffer()循环');
                console.log('[RFID] 【方法1】iData对应: startOrStopRFID() → iDataUHFEvent事件');
                console.log('[RFID] 【方法1】将等待3秒,如果有iDataUHFEvent事件则成功,否则切换到下一个方法');
                idataRFID.startOrStopRFID((ret) => {
                    console.log('[RFID] 【方法1】startOrStopRFID result:', JSON.stringify(ret));
                    if (ret && ret.code === 'success' && ret.msg === 'start') {
                        console.log('[RFID] 【方法1】✓ 连续扫描已启动(相当于UHFDemo的startInventoryTag成功)');
                        console.log('[RFID] 【方法1】等待 iDataUHFEvent 事件(相当于UHFDemo的readTagFromBuffer返回数据)...');
                        console.log('[RFID] 【方法1】如果3秒内没有事件,将自动切换到下一个方法');
                    } else {
                        console.error('[RFID] 【方法1】✗ 开启扫描失败:', ret ? ret.msg : '未知错误');
                        // 如果启动失败,立即切换到下一个方法
                        setTimeout(() => {
                            this.switchToNextMethod();
                        }, 500);
                    }
                });
            },
            // 方法2-5: 单标签读取EPC
            methodReadEPC(startBlock) {
                // 确保当前方法不是方法1
                if (this.currentMethod === 0) {
                    console.error('[RFID] 错误:方法1不应该调用 methodReadEPC');
                    return;
                }
                console.log(`[RFID] 【方法${this.currentMethod + 1}】单标签读取EPC,起始地址: ${startBlock}`);
                console.log(`[RFID] 【方法${this.currentMethod + 1}】当前状态 - isScanning: ${this.isScanning}, powerStatus: ${this.powerStatus}, currentMethod: ${this.currentMethod}`);
                idataRFID.readTagWithoutFilter(
                    1, // EPC区域
                    startBlock, // 起始地址
                    6, // 数据长度
                    '00000000',
                    (ret) => {
                        // 检查是否还在使用当前方法(可能已经切换了)
                        if (this.currentMethod === 0) {
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】回调时方法已切换,忽略结果`);
                            return;
                        }
                        console.log(`[RFID] 【方法${this.currentMethod + 1}】readTagWithoutFilter result:`, JSON.stringify(ret));
                        if (ret && ret.code === 'success' && ret.data) {
                            const epc = ret.data.trim();
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】✓✓✓✓✓ 成功读取到标签 EPC:`, epc);
                            this.addScanResult({ epc: epc, tid: '' });
                            idataRFID.showToast('读取成功: ' + epc.substring(0, 16));
                            // 成功读取后,停止轮换,继续使用当前方法
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】成功!停止轮换,继续使用此方法`);
                            // 继续循环读取
                            setTimeout(() => {
                                if (this.isScanning && this.powerStatus === 'connected' && this.currentMethod !== 0) {
                                    this.methodReadEPC(startBlock);
                                }
                            }, this.readTagInterval);
                        } else {
                            // 失败时继续尝试(由tryCurrentMethod控制)
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】读取失败 (code: ${ret ? ret.code : 'undefined'}, msg: ${ret ? ret.msg : 'undefined'})`);
                        }
                    }
                );
            },
            // 方法3: 单标签读取TID
            methodReadTID(startBlock) {
                // 确保当前方法不是方法1
                if (this.currentMethod === 0) {
                    console.error('[RFID] 错误:方法1不应该调用 methodReadTID');
                    return;
                }
                console.log(`[RFID] 【方法${this.currentMethod + 1}】单标签读取TID,起始地址: ${startBlock}`);
                console.log(`[RFID] 【方法${this.currentMethod + 1}】当前状态 - isScanning: ${this.isScanning}, powerStatus: ${this.powerStatus}, currentMethod: ${this.currentMethod}`);
                idataRFID.readTagWithoutFilter(
                    2, // TID区域
                    startBlock, // 起始地址
                    6, // 数据长度
                    '00000000',
                    (ret) => {
                        // 检查是否还在使用当前方法(可能已经切换了)
                        if (this.currentMethod === 0) {
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】回调时方法已切换,忽略结果`);
                            return;
                        }
                        console.log(`[RFID] 【方法${this.currentMethod + 1}】readTagWithoutFilter result:`, JSON.stringify(ret));
                        if (ret && ret.code === 'success' && ret.data) {
                            const tid = ret.data.trim();
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】✓✓✓✓✓ 成功读取到标签 TID:`, tid);
                            this.addScanResult({ epc: '', tid: tid });
                            idataRFID.showToast('读取成功: ' + tid.substring(0, 16));
                            // 成功读取后,停止轮换,继续使用当前方法
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】成功!停止轮换,继续使用此方法`);
                            // 继续循环读取
                            setTimeout(() => {
                                if (this.isScanning && this.powerStatus === 'connected' && this.currentMethod !== 0) {
                                    this.methodReadTID(startBlock);
                                }
                            }, this.readTagInterval);
                        } else {
                            // 失败时继续尝试(由tryCurrentMethod控制)
                            console.log(`[RFID] 【方法${this.currentMethod + 1}】读取失败 (code: ${ret ? ret.code : 'undefined'}, msg: ${ret ? ret.msg : 'undefined'})`);
                        }
                    }
                );
            },
            // 切换到下一个方法
            switchToNextMethod() {
                // 清除方法1的超时定时器
                if (this.methodSwitchTimer) {
                    clearTimeout(this.methodSwitchTimer);
                    this.methodSwitchTimer = null;
                }
                // 如果方法1正在运行,先停止它
                if (this.currentMethod === 0 && this.isScanning) {
                    idataRFID.startOrStopRFID((ret) => {
                        console.log('[RFID] 停止方法1的扫描:', JSON.stringify(ret));
                        this.doSwitchToNextMethod();
                    });
                } else {
                    this.doSwitchToNextMethod();
                }
            },
            // 执行切换到下一个方法
            doSwitchToNextMethod() {
                this.currentMethod = (this.currentMethod + 1) % this.methodNames.length;
                this.methodCounter = 0;
                console.log(`[RFID] ========== 切换到方法${this.currentMethod + 1}: ${this.methodNames[this.currentMethod]} ==========`);
                console.log(`[RFID] 每种方法将尝试${this.methodMaxRetries}次(约${(this.methodMaxRetries * this.readTagInterval / 1000).toFixed(1)}秒)`);
                setTimeout(() => {
                    if (this.isScanning && this.powerStatus === 'connected') {
                        this.tryCurrentMethod();
                    }
                }, 300);
            },
            // 添加扫描结果
            addScanResult(result) {
                const exists = this.scanResults.some(item =>
                    (item.epc && item.epc === result.epc) ||
                    (item.tid && item.tid === result.tid)
                );
                if (!exists) {
                    result.time = new Date().toLocaleTimeString();
                    this.scanResults.unshift(result);
                    if (this.scanResults.length > 100) {
                        this.scanResults = this.scanResults.slice(0, 100);
                    }
                }
            },
            // 读取单个标签
            readSingleTag() {
                if (this.powerStatus !== 'connected') {
                    return;
                }
                // 尝试多种读取方式
                // 方式1:读取EPC区域(起始地址2,长度6)
                idataRFID.readTagWithoutFilter(
                    1, // EPC区域
                    2, // 起始地址(Word)
                    6, // 数据长度(Word)
                    '00000000', // 访问密码
                    (ret) => {
                        if (ret && ret.code === 'success' && ret.data) {
                            // 检查是否已存在(避免重复)
                            const epc = ret.data.trim();
                            const exists = this.scanResults.some(item => item.epc === epc);
                            if (!exists) {
                                const result = {
                                    epc: epc,
                                    tid: '',
                                    time: new Date().toLocaleTimeString()
                                };
                                this.scanResults.unshift(result);
                                // 限制最多保存100条
                                if (this.scanResults.length > 100) {
                                    this.scanResults = this.scanResults.slice(0, 100);
                                }
                                console.log('[RFID] ✓ 读取到标签 EPC:', epc);
                                idataRFID.showToast('读取成功: ' + epc.substring(0, 16));
                            }
                        } else if (ret && ret.code === 'fail') {
                            // 如果EPC读取失败,尝试读取TID
                            this.readSingleTagTID();
                        }
                    }
                );
            },
            // 读取TID区域(备用方案)
            readSingleTagTID() {
                if (this.powerStatus !== 'connected') {
                    return;
                }
                // 读取TID区域(起始地址0,长度6)
                idataRFID.readTagWithoutFilter(
                    2, // TID区域
                    0, // 起始地址(Word)
                    6, // 数据长度(Word)
                    '00000000', // 访问密码
                    (ret) => {
                        if (ret && ret.code === 'success' && ret.data) {
                            const tid = ret.data.trim();
                            const exists = this.scanResults.some(item => item.tid === tid);
                            if (!exists) {
                                const result = {
                                    epc: '',
                                    tid: tid,
                                    time: new Date().toLocaleTimeString()
                                };
                                this.scanResults.unshift(result);
                                if (this.scanResults.length > 100) {
                                    this.scanResults = this.scanResults.slice(0, 100);
                                }
                                console.log('[RFID] ✓ 读取到标签 TID:', tid);
                                idataRFID.showToast('读取成功: ' + tid.substring(0, 16));
                            }
                        }
                    }
                );
            },
            // 停止读取
            stopReadTag() {
                console.log('[RFID] stopReadTag 被调用');
                if (this.readTagTimer) {
                    clearInterval(this.readTagTimer);
                    this.readTagTimer = null;
                    console.log('[RFID] 定时器已清除');
                }
                if (this.methodSwitchTimer) {
                    clearTimeout(this.methodSwitchTimer);
                    this.methodSwitchTimer = null;
                    console.log('[RFID] 方法切换定时器已清除');
                }
                this.isScanning = false;
                // 停止连续扫描(如果正在使用方法1)
                if (this.currentMethod === 0) {
                    idataRFID.startOrStopRFID((ret) => {
                        console.log('[RFID] stop scan result:', JSON.stringify(ret));
                        console.log('[RFID] 连续扫描已停止');
                    });
                }
                console.log('[RFID] 所有读取方法已停止');
            },
            // 开始/停止读取
            handleStartStopScan() {
                console.log('[RFID] ========== 按钮点击 ==========');
                console.log('[RFID] 当前状态 - isScanning:', this.isScanning, 'powerStatus:', this.powerStatus);
                if (this.powerStatus !== 'connected') {
                    console.log('[RFID] 模块未上电,无法操作');
                    idataRFID.showToast('请先等待模块上电成功');
                    return;
                }
                if (this.isScanning) {
                    console.log('[RFID] 停止读取...');
                    this.stopReadTag();
                    idataRFID.showToast('已停止读取');
                } else {
                    console.log('[RFID] 开始读取...');
                    this.startReadTagLoop();
                    idataRFID.showToast('已开始读取');
                }
            },
            // 清空结果
            clearResults() {
                this.scanResults = [];
            }
        }
    }
</script>
<style>
    .page-container {
        min-height: 100vh;
        background: #f5f5f5;
        padding-bottom: 20px;
    }
    .status-section {
        padding: 15px;
        background: #fff;
        margin-bottom: 10px;
    }
    .status-card {
        display: flex;
        justify-content: space-around;
        padding: 15px 0;
    }
    .status-item {
        display: flex;
        flex-direction: column;
        align-items: center;
    }
    .status-label {
        font-size: 12px;
        color: #909399;
        margin-bottom: 5px;
    }
    .status-value {
        font-size: 14px;
        font-weight: 500;
    }
    .status-value.success {
        color: #67c23a;
    }
    .status-value.error {
        color: #f56c6c;
    }
    .scan-result-section {
        background: #fff;
        margin-bottom: 10px;
        padding: 15px;
        flex: 1;
    }
    .section-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 10px;
    }
    .section-title {
        font-size: 16px;
        font-weight: 500;
        color: #303133;
    }
    .btn-clear {
        display: flex;
        align-items: center;
        padding: 5px 10px;
    }
    .btn-clear-text {
        font-size: 12px;
        color: #f56c6c;
        margin-left: 3px;
    }
    .result-list {
        max-height: calc(100vh - 300px);
        min-height: 200px;
    }
    .result-item {
        padding: 10px;
        border-bottom: 1px solid #ebeef5;
    }
    .result-header {
        display: flex;
        justify-content: space-between;
        margin-bottom: 5px;
    }
    .result-index {
        font-size: 12px;
        color: #909399;
    }
    .result-time {
        font-size: 12px;
        color: #909399;
    }
    .result-content {
        margin-top: 5px;
    }
    .result-row {
        display: flex;
        margin-top: 3px;
    }
    .result-label {
        font-size: 13px;
        color: #606266;
        margin-right: 8px;
        min-width: 40px;
    }
    .result-value {
        font-size: 13px;
        color: #303133;
        font-family: monospace;
        word-break: break-all;
    }
    .empty-result {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 40px 0;
    }
    .empty-text {
        font-size: 14px;
        color: #909399;
        margin-bottom: 5px;
    }
    .empty-hint {
        font-size: 12px;
        color: #c0c4cc;
    }
    .control-section {
        padding: 15px;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        background: #fff;
        border-top: 1px solid #ebeef5;
        z-index: 999;
    }
    .btn-control {
        width: 100%;
        padding: 15px;
        background: #667eea;
        color: #fff;
        border-radius: 8px;
        font-size: 16px;
        font-weight: 500;
        border: none;
        position: relative;
        z-index: 1000;
    }
    .btn-control.btn-scanning {
        background: #f56c6c;
    }
    .btn-control:active {
        opacity: 0.8;
    }
</style>
pages/rfid/uhftest.vue
New file
@@ -0,0 +1,509 @@
<template>
    <div>
        <button type="primary" @click="scanStartOrStopFunc()">开启/关闭盘点</button>
        <br />
        <button type="primary" @click="readTagWithoutFilterFunc()">单标签读,无过滤</button>
        <br />
        <button type="primary" @click="writeTagWithoutFilterFunc()">单标签写,无过滤</button>
        <br />
        <button type="primary" @click="readTagWithFilterFunc()">单标签读,有过滤</button>
        <br />
        <button type="primary" @click="writeTagWithFilterFunc()">单标签写,有过滤</button>
        <br />
        <button type="primary" @click="inventoryModeSetFunc()">盘点模式设置</button>
        <br />
        <button type="primary" @click="inventoryModeGetFunc()">盘点模式获取</button>
        <br />
        <button type="primary" @click="inventoryWaitTimeSetFunc()">占空比设置(50,50)</button>
        <br />
        <button type="primary" @click="inventoryWaitTimeGetFunc()">占空比获取</button>
        <br />
        <button type="primary" @click="readTagModeSetFunc()">盘点标签数据返回模式设置</button>
        <br />
        <button type="primary" @click="readTagModeGetFunc()">盘点标签数据返回模式获取</button>
        <br />
        <button type="primary" @click="setPowerFunc()">设置天线功率20</button>
        <br />
        <button type="primary" @click="getPowerFunc()">获取天线功率</button>
        <br />
        <button type="primary" @click="getFrequencyMode()">获取频率</button>
        <br />
        <button type="primary" @click="openSound()">打开声音</button>
        <br />
        <button type="primary" @click="closeSound()">关闭声音</button>
        <br />
        <button type="primary" @click="startOrStop6BAnd6CFunc()">盘点/停止盘点6B和6C标签</button>
        <br />
        <button type="primary" @click="read6BFunc()">读6B标签</button>
        <br />
        <button type="primary" @click="FilterFunc()">过滤标签</button>
        <br />
        <button type="primary" @click="goTestFunc()">跳转</button>
        <br />
    </div>
</template>
<script>
    //获取module
    var uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule")
    const modal = uni.requireNativePlugin('modal');
    var globalEvent = uni.requireNativePlugin('globalEvent');
    var globalEvent2 = uni.requireNativePlugin('globalEvent');
    var isPowerOn = false;
    const handleKeydown = (e) => {
      const keyCode = e.keyCode;
      console.log(keyCode);
      switch (keyCode) {
        case 181:
          console.log('键值为181的按键被按下');
          break;
        case 191:
          console.log('其他键值的按键被按下');
          break;
      }
    };
    const that = this;
    export default {
        data() {
            return {
            }
        },
        onShow() {
            globalEvent.addEventListener('POWEREvent', function(e) {
                console.log(JSON.stringify(e));
                if (e["status"] == "connected") {
                    isPowerOn = true;
                }else{
                    isPowerOn = false;
                }
                console.log("isPowerOn=" + isPowerOn);
            });
            //globalEvent2.addEventListener('iDataUHFEvent', function(e) {
                //console.log(JSON.stringify(e));
                // modal.toast({
                //     message: JSON.stringify(e),
                //     duration: 1
                // });
            //});
            // 注意:RFID模块已由App.vue全局初始化,测试页面不再初始化,避免冲突
            // 整个app只使用一个RFID初始化(App.vue的onLaunch)
            // 如果需要在测试页面独立初始化,可以取消下面的注释
            /*
            uhfModel.initUHF(1, (ret) => {
                console.log(ret);
                modal.toast({
                    message: ret,
                    duration: 1.5
                });
            });
            */
            plus.key.addEventListener('keydown', handleKeydown);
        },
        onHide() {
            //页面进入后台时调用,通常在屏幕锁屏或者跳转到其他页面时
            // 注意:RFID模块由App.vue全局管理,测试页面不关闭RFID模块,避免影响其他页面
            // 如果需要在测试页面独立管理RFID,可以取消下面的注释
            // uhfModel.closeUHF();
            globalEvent.removeEventListener('POWEREvent');
            globalEvent.removeEventListener('iDataUHFEvent');
            plus.key.removeEventListener('keydown', handleKeydown);
        },
        onUnload() {
            //返回上一个页面时调用
            // 注意:RFID模块由App.vue全局管理,测试页面不关闭RFID模块,避免影响其他页面
            // 如果需要在测试页面独立管理RFID,可以取消下面的注释
            // uhfModel.closeUHF();
            globalEvent.removeEventListener('POWEREvent');
            globalEvent.removeEventListener('iDataUHFEvent');
            plus.key.removeEventListener('keydown', handleKeydown);
        },
        onLoad() {},
        methods: {
            openSound() {
                uhfModel.setRFIDSound(true,(ret) => {
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            closeSound() {
                uhfModel.setRFIDSound(false,(ret) => {
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            FilterFunc(){
                console.log("FilterFunc");
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.filterSet(1,0,16,'0000',(ret) => {
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            read6BFunc(){
                console.log("read6BFunc");
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.read6BTag(0,0,6,null,(ret) => {
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            startOrStop6BAnd6CFunc(){
                console.log("startOrStop6BAnd6CFunc");
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.startOrStop6BAnd6CRFID(true,0,10,(ret) => {
                    console.log(JSON.stringify(ret));
                });
            },
            scanStartOrStopFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.startOrStopRFID((ret) => {
                    console.log(JSON.stringify(ret));
                });
            },
            readTagWithoutFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * readBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * len:读取的数据长度(Word类型,大于0)
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.readTagWithoutFilter(1, 2, 6, "00000000", (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            writeTagWithoutFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * writeBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * writeData:写入的数据
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.writeTagWithoutFilter(1, 2, "1234567890ABCDEF", "00000000", (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            readTagWithFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 过滤条件
                 * fBank:操作区域 0->RESERVED,1->EPC,2->TID,3->USR
                 * fStartBlock:起始地址
                 * fLen:数据长度
                 * fData:过滤数据
                 * 读标签条件
                 * readBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * len:读取长度
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.readTagWithFilter(1, 32, 32, "12345678", 1, 2, 6, "00000000", (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            writeTagWithFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 过滤条件
                 * fBank:操作区域 0->RESERVED,1->EPC,2->TID,3->USR
                 * fStartBlock:起始地址
                 * fLen:数据长度
                 * fData:过滤数据
                 * 写标签条件
                 * writeBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * writeData:写入的数据
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.writeTagWithFilter(1, 32, 32, "12345678", 1, 2, "1234567890ABCDE1", "00000000", (
                    ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryModeSetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 0:多标签模式,侧重读全标签 ,1:快盘模式,侧重快速读取标签 ,2.低功耗模式
                 */
                uhfModel.inventoryModeSet(0, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryModeGetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 0:多标签模式,侧重读全标签 ,1:快盘模式,侧重快速读取标签 ,2.低功耗模式
                 */
                uhfModel.inventoryModeGet((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryWaitTimeSetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 占空比接口,用于解决长时间盘点标签,导致模块发热并降低性能
                 * scanTime:盘点时间
                 * waitTime:休眠时间
                 * save:是否断电保存配置
                 */
                uhfModel.inventoryWaitTimeSet(50, 50, false, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryWaitTimeGetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 占空比接口,用于解决长时间盘点标签,导致模块发热并降低性能
                 * scanTime:盘点时间
                 * waitTime:休眠时间
                 * save:是否断电保存配置
                 */
                uhfModel.inventoryWaitTimeGet((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            readTagModeSetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * mode - 设置0只读取标签EPC,1读取标签EPC和TID
                 */
                uhfModel.readTagModeSet(1, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            readTagModeGetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.readTagModeGet((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            setPowerFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * power:0-33
                 * 不同模块支持的功率值不同,如果返回失败通常是不支持
                 */
                uhfModel.setPower(20, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            getPowerFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.getPower((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            getFrequencyMode() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.getFrequencyMode((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            goTestFunc(){
                console.log("goTestFunc");
                globalEvent.removeEventListener('iDataUHFEvent');
                globalEvent.removeEventListener('POWEREvent');
                uni.navigateTo({
                    url: './uhftest2'
                });
            },
        }
    }
</script>
<style>
</style>
pages/rfid/uhftest2.vue
New file
@@ -0,0 +1,400 @@
<template>
    <div>
        <button type="primary" @click="scanStartOrStopFunc()">开启/关闭盘点</button>
        <br />
        <button type="primary" @click="readTagWithoutFilterFunc()">单标签读,无过滤</button>
        <br />
        <button type="primary" @click="writeTagWithoutFilterFunc()">单标签写,无过滤</button>
        <br />
        <button type="primary" @click="readTagWithFilterFunc()">单标签读,有过滤</button>
        <br />
        <button type="primary" @click="writeTagWithFilterFunc()">单标签写,有过滤</button>
        <br />
        <button type="primary" @click="inventoryModeSetFunc()">盘点模式设置</button>
        <br />
        <button type="primary" @click="inventoryModeGetFunc()">盘点模式获取</button>
        <br />
        <button type="primary" @click="inventoryWaitTimeSetFunc()">占空比设置(50,50)</button>
        <br />
        <button type="primary" @click="inventoryWaitTimeGetFunc()">占空比获取</button>
        <br />
        <button type="primary" @click="readTagModeSetFunc()">盘点标签数据返回模式设置</button>
        <br />
        <button type="primary" @click="readTagModeGetFunc()">盘点标签数据返回模式获取</button>
        <br />
        <button type="primary" @click="setPowerFunc()">设置天线功率20</button>
        <br />
        <button type="primary" @click="getPowerFunc()">获取天线功率</button>
        <button type="primary" @click="getFrequencyMode()">获取频率</button>
        <button type="primary" @click="goTestFunc()">打开新页面</button>
    </div>
</template>
<script>
    //获取module
    var uhfModel = uni.requireNativePlugin("iData-UHFPlugin-UHFModule")
    const modal = uni.requireNativePlugin('modal');
    var globalEvent = uni.requireNativePlugin('globalEvent');
    var globalEvent2 = uni.requireNativePlugin('globalEvent');
    var isPowerOn = true;
    export default {
        onShow() {
            globalEvent.addEventListener('POWEREvent', function(e) {
                console.log(JSON.stringify(e));
                if (e["status"] == "connected") {
                    isPowerOn = true;
                }else{
                    isPowerOn = false;
                }
                console.log("isPowerOn=" + isPowerOn);
            });
            globalEvent2.addEventListener('iDataUHFEvent', function(e) {
                console.log(JSON.stringify(e));
            });
            uhfModel.initUHF(1, (ret) => {
                console.log(ret);
                modal.toast({
                    message: ret,
                    duration: 1.5
                });
            });
            // uhfModel.setRFIDListener((ret) => {
            //     console.log(ret);
            //     modal.toast({
            //         message: ret,
            //         duration: 1.5
            //     });
            // });
        },
        onHide() {
            //页面进入后台时调用,通常在屏幕锁屏或者跳转到其他页面时
            uhfModel.closeUHF();
            globalEvent.removeEventListener('POWEREvent');
            globalEvent.removeEventListener('iDataUHFEvent');
        },
        onUnload() {
            //返回上一个页面时调用
            uhfModel.closeUHF();
            globalEvent.removeEventListener('POWEREvent');
            globalEvent.removeEventListener('iDataUHFEvent');
        },
        data() {
            return {}
        },
        onLoad() {},
        methods: {
            goTestFunc(){
                console.log("goTestFunc");
                globalEvent.removeEventListener('iDataUHFEvent');
                globalEvent.removeEventListener('POWEREvent');
                uni.navigateTo({
                    url: './uhftest'
                });
            },
            scanStartOrStopFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.startOrStopRFID((ret) => {
                    console.log(JSON.stringify(ret));
                });
            },
            readTagWithoutFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * readBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * len:读取的数据长度(Word类型,大于0)
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.readTagWithoutFilter(1, 2, 6, "00000000", (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            writeTagWithoutFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * writeBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * writeData:写入的数据
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.writeTagWithoutFilter(1, 2, "1234567890ABCDEF", "00000000", (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            readTagWithFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 过滤条件
                 * fBank:操作区域 0->RESERVED,1->EPC,2->TID,3->USR
                 * fStartBlock:起始地址
                 * fLen:数据长度
                 * fData:过滤数据
                 * 读标签条件
                 * readBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * len:读取长度
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.readTagWithFilter(1, 32, 32, "12345678", 1, 2, 6, "00000000", (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            writeTagWithFilterFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 过滤条件
                 * fBank:操作区域 0->RESERVED,1->EPC,2->TID,3->USR
                 * fStartBlock:起始地址
                 * fLen:数据长度
                 * fData:过滤数据
                 * 写标签条件
                 * writeBank:0->RESERVED,1->EPC,2->TID,3->USR
                 * startBlock:读取的起始地址(Word类型)
                 * writeData:写入的数据
                 * pwd:访问密码,默认密码为:00000000
                 * 注意:Word类型,一个长度表示标签存储4位字符
                 */
                uhfModel.writeTagWithFilter(1, 32, 32, "12345678", 1, 2, "1234567890ABCDE1", "00000000", (
                    ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryModeSetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 0:多标签模式,侧重读全标签 ,1:快盘模式,侧重快速读取标签 ,2.低功耗模式
                 */
                uhfModel.inventoryModeSet(0, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryModeGetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 0:多标签模式,侧重读全标签 ,1:快盘模式,侧重快速读取标签 ,2.低功耗模式
                 */
                uhfModel.inventoryModeGet((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryWaitTimeSetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 占空比接口,用于解决长时间盘点标签,导致模块发热并降低性能
                 * scanTime:盘点时间
                 * waitTime:休眠时间
                 * save:是否断电保存配置
                 */
                uhfModel.inventoryWaitTimeSet(50, 50, false, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            inventoryWaitTimeGetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * 占空比接口,用于解决长时间盘点标签,导致模块发热并降低性能
                 * scanTime:盘点时间
                 * waitTime:休眠时间
                 * save:是否断电保存配置
                 */
                uhfModel.inventoryWaitTimeGet((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            readTagModeSetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * mode - 设置0只读取标签EPC,1读取标签EPC和TID
                 */
                uhfModel.readTagModeSet(1, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            readTagModeGetFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.readTagModeGet((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            setPowerFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                /**
                 * power:0-33
                 * 不同模块支持的功率值不同,如果返回失败通常是不支持
                 */
                uhfModel.setPower(20, (ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            getPowerFunc() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.getPower((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
            getFrequencyMode() {
                if (!isPowerOn) {
                    modal.toast({
                        message: "正在上电 ,请稍后重试!",
                        duration: 1.5
                    });
                    return;
                }
                uhfModel.getFrequencyMode((ret) => {
                    //
                    modal.toast({
                        message: ret,
                        duration: 1.5
                    });
                });
            },
        }
    }
</script>
<style>
</style>
pages/stock/stockQuery.vue
@@ -8,7 +8,7 @@
                    <text class="label-text">库位号</text>
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入库位号" v-model="locNo" />
                    <input class="form-input" type="text" placeholder="扫码 / 输入库位号" v-model="locNo" @focus="onLocNoFocus()" />
                    <uni-icons v-if="locNo" type="clear" size="18" color="#c0c4cc" @click="locNo=''"></uni-icons>
                </view>
            </view>
@@ -18,7 +18,7 @@
                    <text class="label-text">物料号</text>
                </view>
                <view class="form-input-wrap">
                    <input class="form-input" type="text" placeholder="扫码 / 输入物料号" v-model="matnr" @input="findMat()" />
                    <input class="form-input" type="text" placeholder="扫码 / 输入物料号" v-model="matnr" @input="findMat()" @focus="onMatnrFocus()" />
                    <uni-icons v-if="matnr" type="clear" size="18" color="#c0c4cc" @click="matnr=''"></uni-icons>
                </view>
            </view>
@@ -114,6 +114,7 @@
</template>
<script>
    import rfidScanner from '@/common/rfid-scanner.js';
    export default {
        data() {
            return {
@@ -133,8 +134,21 @@
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // RFID已在App.vue中全局初始化,这里不需要再初始化
            // 设置当前页面实例,用于全局扫描时自动填入
            rfidScanner.setCurrentPageInstance(this);
        },
        methods: {
            // 库位号输入框获得焦点(保留方法,但不自动触发扫描)
            onLocNoFocus() {
                console.log('[stockQuery] 库位号输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            // 物料号输入框获得焦点(保留方法,但不自动触发扫描)
            onMatnrFocus() {
                console.log('[stockQuery] 物料号输入框获得焦点');
                // 注意:单标签读无过滤功能已改为按键触发(191、189、190),不再在焦点时自动触发
            },
            // 搜索物料
            findMat() {
                let that = this;
uni_modules/uni-popup/components/uni-popup/uni-popup.vue
@@ -175,18 +175,31 @@
    },
    mounted() {
        const fixSize = () => {
            const { windowWidth, windowHeight, windowTop, safeArea,screenHeight ,safeAreaInsets } = uni.getSystemInfoSync()
            this.popupWidth = windowWidth
            this.popupHeight = windowHeight + windowTop
            // TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异,需要框架修复
            if(safeArea){
                // #ifdef MP-WEIXIN
                this.safeAreaInsets = screenHeight - safeArea.bottom
                // #endif
                // #ifndef MP-WEIXIN
                this.safeAreaInsets = safeAreaInsets.bottom
                // #endif
            }else{
            try {
                const systemInfo = uni.getSystemInfoSync()
                if (!systemInfo) {
                    console.warn('[uni-popup] getSystemInfoSync 返回空数据')
                    return
                }
                const { windowWidth = 0, windowHeight = 0, windowTop = 0, safeArea, screenHeight = 0, safeAreaInsets } = systemInfo
                this.popupWidth = windowWidth || 0
                this.popupHeight = (windowHeight || 0) + (windowTop || 0)
                // TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异,需要框架修复
                if(safeArea){
                    // #ifdef MP-WEIXIN
                    this.safeAreaInsets = screenHeight - (safeArea && safeArea.bottom ? safeArea.bottom : 0)
                    // #endif
                    // #ifndef MP-WEIXIN
                    this.safeAreaInsets = safeAreaInsets && safeAreaInsets.bottom ? safeAreaInsets.bottom : 0
                    // #endif
                }else{
                    this.safeAreaInsets = 0
                }
            } catch (error) {
                console.error('[uni-popup] fixSize 错误:', error)
                // 设置默认值
                this.popupWidth = 0
                this.popupHeight = 0
                this.safeAreaInsets = 0
            }
        }