| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- // 注册 Vant 组件
- Vue.use(vant.NavBar);
- Vue.use(vant.Steps);
- Vue.use(vant.Step);
- Vue.use(vant.Tabs);
- Vue.use(vant.Tab);
- Vue.use(vant.List);
- Vue.use(vant.Icon);
- Vue.use(vant.Toast);
- Vue.use(vant.Dialog);
- var app = new Vue({
- el: "#app",
- data: {
- // 盘点单信息
- inventoryInfo: {
- id: null,
- checkVouchId: null,
- name: '',
- documentNo: '',
- inventoryStartDate: '',
- inventoryEndDate: ''
- },
- // 当前激活的Tab
- activeTab: 0,
- // 待盘明细相关
- allPendingList: [], // 所有待盘数据(cfCheckVouchsResponses)
- displayedPendingList: [], // 当前显示的待盘数据
- pendingPage: 0, // 当前页
- pendingLoading: false, // 是否正在加载
- pendingFinished: false, // 是否加载完毕
- pendingTotal: 0, // 待盘总数
- // 已盘相关
- allCheckedList: [], // 所有已盘数据
- displayedCheckedList: [], // 当前显示的已盘数据
- checkedPage: 0, // 当前页
- checkedLoading: false, // 是否正在加载
- checkedFinished: false, // 是否加载完毕
- checkedTotal: 0, // 已盘总数
- // 每页显示数量
- pageSize: 10,
- // IndexDB 数据库实例
- checkVouchDb: null,
- // RFID 扫描状态
- isScanning: false,
- // === 扫描优化相关 ===
- // EPC扫描缓冲区(用于批量处理)
- scanBuffer: [],
- // 批量处理定时器
- batchProcessTimer: null,
- // 批量处理间隔(毫秒)
- batchProcessInterval: 500,
- // UI更新定时器
- uiUpdateTimer: null,
- // UI更新间隔(毫秒)
- uiUpdateInterval: 1000,
- // 待盘数据Map索引(key: epc, value: item)
- pendingMap: {},
- // 已盘数据Map索引(key: checkVouchsId, value: true)
- checkedMap: {},
- // 待更新UI标记
- needsUIUpdate: false,
- // 新增已盘数量(用于实时显示)
- newCheckedCount: 0,
- },
- methods: {
- /**
- * 返回上一页
- */
- goBack: function () {
- history.go(-1);
- },
- /**
- * 去同步页面 - 确保数据已保存
- */
- goToSync: function () {
- var _self = this;
-
- // 停止扫描
- if (_self.isScanning) {
- _self.stopRfidScan();
- }
-
- // 确保最新数据已保存
- _self.saveToUploadQueue();
-
- // 显示提示并跳转
- if (_self.allCheckedList && _self.allCheckedList.length > 0) {
- vant.Toast.success('已盘数据已保存,即将跳转到同步页面');
- } else {
- vant.Toast('当前没有已盘数据');
- }
-
- setTimeout(function () {
- window.location.href = './DataSync.html';
- }, 800);
- },
- /**
- * 初始化盘点单信息并加载待盘数据
- */
- initInventoryInfo: function () {
- var _self = this;
- // 从localStorage获取选中的盘点单
- var selectedInventory = localStorage.getItem('selectedInventory');
- if (!selectedInventory) {
- vant.Toast.fail('请先选择盘点单');
- setTimeout(function () {
- _self.goBack();
- }, 1500);
- return;
- }
- var inventory = JSON.parse(selectedInventory);
- _self.inventoryInfo = {
- id: inventory.id,
- checkVouchId: inventory.checkVouchId,
- name: inventory.name,
- documentNo: inventory.documentNo,
- inventoryStartDate: inventory.inventoryStartDate || '',
- inventoryEndDate: inventory.inventoryEndDate || ''
- };
- // 从 IndexDB 加载完整的盘点单数据
- if (_self.checkVouchDb) {
- _self.checkVouchDb.get('checkVouchList', inventory.checkVouchId, function (data) {
- if (data && data.cfCheckVouchsResponses) {
- // 根据 checkVouchDate 区分已盘数据和待盘数据
- var pendingList = [];
- var checkedList = [];
-
- data.cfCheckVouchsResponses.forEach(function (item) {
- var itemData = {
- id: item.checkVouchsId,
- checkVouchsId: item.checkVouchsId,
- assetName: item.inventoryName,
- no: item.inventoryNo,
- epc: item.inventoryEpc,
- positionId: item.positionId,
- positionName: item.positionName,
- positionNo: item.positionNo,
- warehouseId: item.warehouseId,
- warehouseName: item.warehouseName,
- warehouseNo: item.warehouseNo,
- inventoryId: item.inventoryId
- };
-
- // 根据 checkVouchDate 判断是已盘还是待盘
- if (item.checkVouchDate) {
- // 有 checkVouchDate,是已盘数据
- itemData.checkTime = item.checkVouchDate;
- itemData.userName = item.userName || '';
- checkedList.push(itemData);
- // 构建已盘Map索引
- _self.checkedMap[item.checkVouchsId] = true;
- } else {
- // 没有 checkVouchDate,是待盘数据
- pendingList.push(itemData);
- // 构建待盘Map索引
- if (itemData.epc) {
- _self.pendingMap[itemData.epc] = itemData;
- }
- }
- });
-
- _self.allPendingList = pendingList;
- _self.allCheckedList = checkedList;
- _self.pendingTotal = pendingList.length;
- _self.checkedTotal = checkedList.length;
-
- console.log('数据加载完成 - 待盘:', pendingList.length, '条,已盘:', checkedList.length, '条');
- }
-
- // 加载本地新盘的数据(如果有的话,需要与服务器已盘数据合并)
- _self.loadLocalCheckedData(inventory.checkVouchId);
- }, function (error) {
- console.error('加载盘点单数据失败:', error);
- });
- }
- },
- /**
- * 加载本地新盘的数据(如果有的话,需要与服务器已盘数据合并)
- */
- loadLocalCheckedData: function (checkVouchId) {
- var _self = this;
-
- _self.checkVouchDb.get('uploadQueue', checkVouchId, function (uploadData) {
- if (uploadData && uploadData.cfCheckVouchsRequests && uploadData.cfCheckVouchsRequests.length > 0) {
- console.log('发现本地新盘数据:', uploadData.cfCheckVouchsRequests.length, '条(需要与服务器已盘数据合并)');
-
- // 将本地新盘数据与服务器已盘数据合并
- // 使用 checkVouchsId 去重
- var existingIds = {};
- _self.allCheckedList.forEach(function (item) {
- existingIds[item.checkVouchsId] = true;
- });
-
- // 添加本地新盘的数据(不在服务器已盘列表中的)
- uploadData.cfCheckVouchsRequests.forEach(function (item) {
- if (!existingIds[item.checkVouchsId]) {
- // 从待盘列表中查找完整信息
- var foundPending = null;
- for (var i = 0; i < _self.allPendingList.length; i++) {
- if (_self.allPendingList[i].checkVouchsId === item.checkVouchsId) {
- foundPending = _self.allPendingList[i];
- break;
- }
- }
-
- var checkedItem = {
- id: item.checkVouchsId,
- checkVouchsId: item.checkVouchsId,
- checkTime: item.checkVouchTime
- };
-
- // 补充完整信息
- if (foundPending) {
- checkedItem.assetName = foundPending.assetName;
- checkedItem.no = foundPending.no;
- checkedItem.epc = foundPending.epc;
- checkedItem.positionId = foundPending.positionId;
- checkedItem.positionName = foundPending.positionName;
- checkedItem.inventoryId = foundPending.inventoryId;
- }
-
- // 添加到已盘列表
- _self.allCheckedList.push(checkedItem);
- // 构建已盘Map索引
- _self.checkedMap[item.checkVouchsId] = true;
- existingIds[item.checkVouchsId] = true;
- }
- });
-
- _self.checkedTotal = _self.allCheckedList.length;
- console.log('合并后的已盘数据总数:', _self.checkedTotal, '条');
- } else {
- console.log('没有本地新盘数据');
- }
- }, function (error) {
- console.log('加载本地新盘数据失败(可能是首次盘点):', error);
- });
- },
- /**
- * 处理 RFID 扫描到的 EPC
- * @param {String} epc - 扫描到的 EPC
- */
- addEpc: function (epc) {
- var _self = this;
-
- // 将EPC添加到缓冲区
- _self.scanBuffer.push(epc);
-
- // 如果定时器未启动,启动批量处理定时器
- if (!_self.batchProcessTimer) {
- _self.batchProcessTimer = setInterval(function () {
- _self.processScanBuffer();
- }, _self.batchProcessInterval);
- }
- },
- /**
- * 批量处理扫描缓冲区中的EPC数据
- */
- processScanBuffer: function () {
- var _self = this;
-
- // 如果缓冲区为空,直接返回
- if (_self.scanBuffer.length === 0) {
- return;
- }
- var processStartTime = Date.now();
- var batchSize = _self.scanBuffer.length;
- console.log('开始批量处理 ' + batchSize + ' 条扫描数据');
- // 临时存储本次批量处理的新增已盘项
- var newCheckedItems = [];
- var duplicateCount = 0;
- var notFoundCount = 0;
- // 批量处理缓冲区中的所有EPC
- for (var i = 0; i < batchSize; i++) {
- var epc = _self.scanBuffer[i];
-
- // 使用Map快速查找待盘数据
- var foundItem = _self.pendingMap[epc];
-
- if (foundItem) {
- // 使用Map快速检查是否已经盘点过
- if (!_self.checkedMap[foundItem.checkVouchsId]) {
- // 添加到已盘列表
- var checkedItem = {
- id: foundItem.checkVouchsId,
- checkVouchsId: foundItem.checkVouchsId,
- assetName: foundItem.assetName,
- no: foundItem.no,
- epc: foundItem.epc,
- checkTime: _self.formatDateTime(new Date()),
- positionId: foundItem.positionId,
- positionName: foundItem.positionName,
- inventoryId: foundItem.inventoryId
- };
-
- // 添加到已盘列表
- _self.allCheckedList.push(checkedItem);
- // 更新已盘Map索引
- _self.checkedMap[foundItem.checkVouchsId] = true;
- // 添加到本次批量新增列表
- newCheckedItems.push(checkedItem);
- } else {
- duplicateCount++;
- }
- } else {
- notFoundCount++;
- }
- }
- // 清空缓冲区
- _self.scanBuffer = [];
- // 更新已盘总数
- _self.checkedTotal = _self.allCheckedList.length;
- _self.newCheckedCount += newCheckedItems.length;
- var processEndTime = Date.now();
- console.log('批量处理完成: 新增 ' + newCheckedItems.length + ' 条, 重复 ' + duplicateCount + ' 条, 未找到 ' + notFoundCount + ' 条, 耗时 ' + (processEndTime - processStartTime) + 'ms');
- // 标记需要更新UI
- if (newCheckedItems.length > 0) {
- _self.needsUIUpdate = true;
- _self.scheduleUIUpdate();
-
- // 实时保存已盘数据到 IndexDB
- _self.saveToUploadQueue();
- }
- },
- /**
- * 实时保存已盘数据到 IndexDB 的 uploadQueue
- * 注意:新盘数据会与服务器已盘数据合并,不会覆盖服务器数据
- */
- saveToUploadQueue: function () {
- var _self = this;
-
- // 如果没有数据库实例或没有已盘数据,不保存
- if (!_self.checkVouchDb || !_self.allCheckedList || _self.allCheckedList.length === 0) {
- return;
- }
- // 构建上传数据结构(allCheckedList已经包含了服务器已盘数据和新盘数据)
- var uploadData = {
- checkVouchId: _self.inventoryInfo.checkVouchId,
- cfCheckVouchsRequests: _self.allCheckedList.map(function (item) {
- return {
- checkVouchsId: item.checkVouchsId,
- checkVouchTime: item.checkTime
- };
- })
- };
- // 保存到 IndexDB 的上传队列(使用 put 会覆盖同一 checkVouchId 的旧数据)
- _self.checkVouchDb.put('uploadQueue', uploadData, function () {
- console.log('已盘数据已实时保存到上传队列,数量: ' + _self.allCheckedList.length);
- }, function (error) {
- console.error('保存已盘数据失败:', error);
- });
- },
- /**
- * 安排UI更新(节流)
- */
- scheduleUIUpdate: function () {
- var _self = this;
-
- // 如果已经有UI更新定时器,不重复创建
- if (_self.uiUpdateTimer) {
- return;
- }
-
- // 设置UI更新定时器
- _self.uiUpdateTimer = setTimeout(function () {
- _self.performUIUpdate();
- _self.uiUpdateTimer = null;
- }, _self.uiUpdateInterval);
- },
- /**
- * 执行UI更新
- */
- performUIUpdate: function () {
- var _self = this;
-
- if (!_self.needsUIUpdate) {
- return;
- }
-
- // 只有当前在已盘tab时才更新显示列表
- if (_self.activeTab === 1) {
- _self.refreshCheckedList();
- }
-
- _self.needsUIUpdate = false;
- console.log('UI更新完成,当前已盘总数: ' + _self.checkedTotal);
- },
- /**
- * 格式化日期时间
- */
- formatDateTime: function (date) {
- var year = date.getFullYear();
- var month = String(date.getMonth() + 1).padStart(2, '0');
- var day = String(date.getDate()).padStart(2, '0');
- var hours = String(date.getHours()).padStart(2, '0');
- var minutes = String(date.getMinutes()).padStart(2, '0');
- var seconds = String(date.getSeconds()).padStart(2, '0');
- return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
- },
- /**
- * Tab切换
- */
- onTabChange: function (name) {
- var _self = this;
- console.log('切换到Tab:', name);
- // 如果切换到已盘tab
- if (name === 1) {
- // 如果有待更新的数据,立即更新UI
- if (_self.needsUIUpdate) {
- // 取消定时器,立即更新
- if (_self.uiUpdateTimer) {
- clearTimeout(_self.uiUpdateTimer);
- _self.uiUpdateTimer = null;
- }
- _self.performUIUpdate();
- } else if (_self.displayedCheckedList.length < _self.allCheckedList.length) {
- // 检查是否有新数据需要刷新
- _self.refreshCheckedList();
- }
- }
- },
-
- /**
- * 刷新已盘列表(重新加载所有数据)
- */
- refreshCheckedList: function () {
- var _self = this;
- // 重置分页
- _self.checkedPage = 0;
- _self.displayedCheckedList = [];
- _self.checkedFinished = false;
- // 触发加载
- _self.checkedLoading = true;
- _self.onLoadChecked();
- },
- /**
- * 加载待盘数据
- */
- onLoadPending: function () {
- var _self = this;
- // 模拟加载延迟
- setTimeout(function () {
- var startIndex = _self.pendingPage * _self.pageSize;
- var endIndex = startIndex + _self.pageSize;
- // 获取当前页的数据
- var pageData = _self.allPendingList.slice(startIndex, endIndex);
- if (pageData.length > 0) {
- // 追加到显示列表
- _self.displayedPendingList = _self.displayedPendingList.concat(pageData);
- _self.pendingPage++;
- _self.pendingLoading = false;
- // 判断是否加载完毕
- if (_self.displayedPendingList.length >= _self.allPendingList.length) {
- _self.pendingFinished = true;
- }
- } else {
- // 没有更多数据了
- _self.pendingFinished = true;
- _self.pendingLoading = false;
- }
- }, 300);
- },
- /**
- * 加载已盘数据
- */
- onLoadChecked: function () {
- var _self = this;
- // 模拟加载延迟
- setTimeout(function () {
- var startIndex = _self.checkedPage * _self.pageSize;
- var endIndex = startIndex + _self.pageSize;
- // 获取当前页的数据(倒序显示,最新的在前面)
- var reversedList = _self.allCheckedList.slice().reverse();
- var pageData = reversedList.slice(startIndex, endIndex);
- if (pageData.length > 0) {
- // 追加到显示列表
- _self.displayedCheckedList = _self.displayedCheckedList.concat(pageData);
- _self.checkedPage++;
- _self.checkedLoading = false;
- // 判断是否加载完毕
- if (_self.displayedCheckedList.length >= _self.allCheckedList.length) {
- _self.checkedFinished = true;
- }
- } else {
- // 没有更多数据了
- _self.checkedFinished = true;
- _self.checkedLoading = false;
- }
- }, 300);
- },
- /**
- * 重置待盘分页
- */
- resetPendingPagination: function () {
- var _self = this;
- _self.pendingPage = 0;
- _self.displayedPendingList = [];
- _self.pendingFinished = false;
- _self.pendingLoading = true;
- },
- /**
- * 重置已盘分页
- */
- resetCheckedPagination: function () {
- var _self = this;
- _self.checkedPage = 0;
- _self.displayedCheckedList = [];
- _self.checkedFinished = false;
- _self.checkedLoading = false; // 不自动触发加载,等待van-list组件触发
- },
- /**
- * 启动 RFID 扫描
- */
- startRfidScan: function () {
- var _self = this;
- if (!plugin || !plugin.rfidMiddleware) {
- console.error('RFID 插件未加载');
- return;
- }
- // 重置计数器和缓冲区
- _self.newCheckedCount = 0;
- _self.scanBuffer = [];
-
- _self.isScanning = true;
- plugin.rfidMiddleware.start();
- plugin.rfidMiddleware.readEvent = function (epc) {
- _self.addEpc(epc);
- return "success";
- };
- console.log('RFID 扫描已启动');
- },
- /**
- * 停止 RFID 扫描
- */
- stopRfidScan: function () {
- var _self = this;
- if (!plugin || !plugin.rfidMiddleware) {
- return;
- }
- _self.isScanning = false;
- plugin.rfidMiddleware.stop();
- plugin.rfidMiddleware.stopInventory();
-
- // 清理批量处理定时器
- if (_self.batchProcessTimer) {
- clearInterval(_self.batchProcessTimer);
- _self.batchProcessTimer = null;
- }
-
- // 处理剩余缓冲区数据
- if (_self.scanBuffer.length > 0) {
- console.log('处理剩余缓冲区数据: ' + _self.scanBuffer.length + ' 条');
- _self.processScanBuffer();
- }
-
- // 清理UI更新定时器
- if (_self.uiUpdateTimer) {
- clearTimeout(_self.uiUpdateTimer);
- _self.uiUpdateTimer = null;
- }
-
- // 如果有待更新的UI,立即更新
- if (_self.needsUIUpdate) {
- _self.performUIUpdate();
- }
-
- console.log('RFID 扫描已停止,总计扫描: ' + _self.newCheckedCount + ' 条新数据');
- },
- /**
- * 清理所有定时器
- */
- cleanupTimers: function () {
- var _self = this;
-
- if (_self.batchProcessTimer) {
- clearInterval(_self.batchProcessTimer);
- _self.batchProcessTimer = null;
- }
-
- if (_self.uiUpdateTimer) {
- clearTimeout(_self.uiUpdateTimer);
- _self.uiUpdateTimer = null;
- }
- },
- /**
- * 获取扫描统计信息
- */
- getScanStats: function () {
- var _self = this;
- return {
- pendingTotal: _self.pendingTotal,
- checkedTotal: _self.checkedTotal,
- newCheckedCount: _self.newCheckedCount,
- bufferSize: _self.scanBuffer.length,
- scanProgress: _self.pendingTotal > 0 ?
- ((_self.checkedTotal / _self.pendingTotal) * 100).toFixed(2) : '0.00'
- };
- },
- /**
- * 保存盘点数据到 IndexDB(兼容旧版调用,实际调用 saveToUploadQueue)
- * @param {Function} callback - 保存成功后的回调
- */
- saveInventoryData: function (callback) {
- var _self = this;
-
- // 调用实时保存方法
- _self.saveToUploadQueue();
-
- // 执行回调
- if (callback) {
- callback();
- }
- },
- /**
- * 初始化
- */
- init: function () {
- var _self = this;
- // 初始化 IndexDB 数据库
- var objectStoreDefines = [
- {
- name: 'checkVouchList',
- defineOption: { keyPath: 'checkVouchId' },
- indexDefineList: null
- },
- {
- name: 'uploadQueue',
- defineOption: { keyPath: 'checkVouchId' },
- indexDefineList: null
- }
- ];
- _self.checkVouchDb = new IndexDbFactory('checkVouchDB', objectStoreDefines, 1);
- _self.checkVouchDb.open(function () {
- console.log('盘点数据库初始化成功');
- // 数据库初始化成功后,初始化盘点单信息
- _self.initInventoryInfo();
- // 启动 RFID 扫描
- _self.startRfidScan();
- }, function () {
- console.error('盘点数据库初始化失败');
- vant.Dialog.alert({
- title: '错误',
- message: '数据库初始化失败,请先进行数据同步。',
- theme: 'round-button',
- });
- });
- }
- },
- created: function () {
- console.log('AssetInventoryCheck Vue实例创建完成');
- },
- mounted: function () {
- var _self = this;
- _self.init();
- console.log('AssetInventoryCheck页面加载完成');
-
- // 隐藏页面加载指示器
- setTimeout(function() {
- var loadingElement = document.getElementById('pageLoading');
- if (loadingElement) {
- loadingElement.style.display = 'none';
- }
- }, 100);
- },
- beforeDestroy: function () {
- var _self = this;
- // 停止 RFID 扫描(会自动清理定时器)
- _self.stopRfidScan();
- // 保存盘点数据
- _self.saveInventoryData();
- },
- destroyed: function () {
- var _self = this;
- // 确保停止 RFID 扫描
- _self.stopRfidScan();
- // 清理所有定时器
- _self.cleanupTimers();
- }
- });
|