From 1ef2ffaa5bd537ce36f3f26690409f4c198383ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B8=B8=E7=86=9F=E5=90=B4=E5=BD=A6=E7=A5=96?= Date: Wed, 1 Oct 2025 13:46:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=A0=88=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/automatedWarehouse/palletPacking.js | 12 + .../automatedWarehouse/palletPacking.vue | 408 ++++++++++++++---- 2 files changed, 345 insertions(+), 75 deletions(-) diff --git a/src/api/automatedWarehouse/palletPacking.js b/src/api/automatedWarehouse/palletPacking.js index c8e89fd..0de9025 100644 --- a/src/api/automatedWarehouse/palletPacking.js +++ b/src/api/automatedWarehouse/palletPacking.js @@ -41,3 +41,15 @@ export const callPalletToStation = data => createAPI(`/wcsIntegration/callPallet // Call栈板到指定站点(包含组盘处理) - AI制作 export const callPalletToStationWithUpdateZuPan = data => createAPI(`/wcsIntegration/callPalletToStationWithUpdateZuPan`,'post',data) + +// 获取栈板详细信息(包含palletType和autoSort) - AI制作 +export const getPalletInfo = data => createAPI(`/wcsIntegration/getPalletInfo`,'post',data) + +// 获取托盘类型列表(根据palletFamily过滤) - AI制作 +export const getPalletTypeList = data => createAPI(`/base/palletType/list`,'post',data) + +// 获取托盘类型的区域列表 - AI制作 +export const getPalletTypeAreas = data => createAPI(`/base/palletTypeArea/list`,'post',data) + +// 更新栈板类型和自动分拣标志 - AI制作 +export const updatePalletTypeAndAutoSort = data => createAPI(`/wcsIntegration/updatePalletTypeAndAutoSort`,'post',data) diff --git a/src/views/modules/automatedWarehouse/palletPacking.vue b/src/views/modules/automatedWarehouse/palletPacking.vue index 8cc12bd..0e33ed4 100644 --- a/src/views/modules/automatedWarehouse/palletPacking.vue +++ b/src/views/modules/automatedWarehouse/palletPacking.vue @@ -36,45 +36,62 @@ - +
-
- +
+ -
-
- +
+ - - + +
+
+
+ + +
+ +
+ + + +
- +
-
-
- +
+
+ 扫进 扫出
@@ -104,16 +121,15 @@
-
-
栈板明细
- +
+
栈板明细
+
位置
层数
标签号
-
物料编码
{{ detail.position }}
{{ detail.layer }}
{{ detail.serialNo }}
-
{{ detail.partNo }}
@@ -261,8 +276,10 @@
@@ -300,27 +317,29 @@ />
- +
- +
@@ -368,8 +387,10 @@
@@ -388,7 +409,11 @@ import { updatePalletDetailPosition, getAgvStations, callPalletToStation, - callPalletToStationWithUpdateZuPan + callPalletToStationWithUpdateZuPan, + getPalletInfo, + getPalletTypeList, + getPalletTypeAreas, + updatePalletTypeAndAutoSort } from '../../../api/automatedWarehouse/palletPacking' export default { @@ -399,6 +424,16 @@ export default { palletScanned: false, operationType: 'in', // 'in' 或 'out' + // 栈板类型和自动分拣 + currentPalletFamily: '', // 当前栈板大分类(固定不可改) + currentPalletType: '', // 当前栈板类型 + currentAutoSort: '', // 当前是否自动分拣 Y/N + palletTypeOptions: [], // 托盘类型选项列表 + palletTypeDisabled: false, // 栈板类型下拉框是否禁用(有明细数据时禁用) + autoSortDisabled: false, // 自动分拣下拉框是否禁用 + currentWcsAutoSort: '', // 当前托盘类型的wcsAutoSort值 + currentMaxLayer: 0, // 当前托盘类型的最大层数,0=无限 + // 筛选条件 selectedPosition: '', selectedLayer: '', @@ -418,9 +453,9 @@ export default { // 运输任务模态框 transportModalVisible: false, - transportStationOptions: [], + transportAreaOptions: [], // 目标区域选项(从空闲站点中提取并去重) currentPalletStation: '', - selectedTargetStation: '', + selectedTargetArea: '', // 选择的目标区域 // Call栈板模态框 callPalletModalVisible: false, @@ -437,6 +472,11 @@ export default { editLayerOptions: [], editOriginalPosition: '', editOriginalLayer: '', + + // 按钮loading状态(防止重复点击) + editPositionLoading: false, // 修改位置按钮 + transportTaskLoading: false, // 创建运输任务按钮 + callPalletLoading: false, // Call栈板按钮 }; }, methods: { @@ -458,6 +498,10 @@ export default { if (data.code === 0) { this.palletScanned = true; this.positionOptions = data.positions || []; + + // 获取栈板详细信息(包括palletType和autoSort) + this.loadPalletInfo(); + this.refreshTable(); } else { this.$message.error(data.msg || '栈板不存在'); @@ -468,6 +512,137 @@ export default { }); }, + // 加载栈板信息 + loadPalletInfo() { + getPalletInfo({ + site: this.site, + palletId: this.palletCode + }).then(({ data }) => { + if (data.code === 0) { + const palletInfo = data.row || {}; + this.currentPalletFamily = palletInfo.palletFamily || ''; + this.currentPalletType = palletInfo.palletType || ''; + this.currentAutoSort = palletInfo.autoSort || 'N'; + + // 加载托盘类型列表(根据palletFamily过滤) + this.loadPalletTypeList(); + } else { + this.$message.error(data.msg || '获取栈板信息失败'); + } + }).catch(error => { + console.error('获取栈板信息失败:', error); + this.$message.error('获取栈板信息失败'); + }); + }, + + // 加载托盘类型列表 + loadPalletTypeList() { + getPalletTypeList({ + site: this.site, + palletFamily: this.currentPalletFamily, + active: 'Y' + }).then(({ data }) => { + if (data.code === 0) { + this.palletTypeOptions = data.rows || []; + + // 设置当前托盘类型的wcsAutoSort值和maxLayer + const currentType = this.palletTypeOptions.find(t => t.palletType === this.currentPalletType); + if (currentType) { + this.currentWcsAutoSort = currentType.wcsAutoSort || 'N'; + this.currentMaxLayer = currentType.maxLayer || 0; + this.updateAutoSortControl(); + + // 加载当前托盘类型的区域列表 + this.loadPalletTypeAreas(); + } + } else { + this.palletTypeOptions = []; + } + }).catch(error => { + console.error('获取托盘类型列表失败:', error); + this.palletTypeOptions = []; + }); + }, + + // 加载托盘类型的区域列表 + loadPalletTypeAreas() { + getPalletTypeAreas({ + site: this.site, + palletType: this.currentPalletType + }).then(({ data }) => { + if (data.code === 0) { + // 从pallet_type_area获取position列表 + const areas = data.rows || []; + this.positionOptions = areas.map(area => area.position); + } else { + this.positionOptions = []; + } + }).catch(error => { + console.error('获取托盘区域列表失败:', error); + this.positionOptions = []; + }); + }, + + // 托盘类型变更事件 + handlePalletTypeChange() { + // 查找选中的托盘类型 + const selectedType = this.palletTypeOptions.find(t => t.palletType === this.currentPalletType); + + if (selectedType) { + this.currentWcsAutoSort = selectedType.wcsAutoSort || 'N'; + this.currentMaxLayer = selectedType.maxLayer || 0; + + // 默认值:从托盘类型表取 + this.currentAutoSort = this.currentWcsAutoSort; + + // 更新自动分拣控制 + this.updateAutoSortControl(); + + // 重新查询pallet_type_area,更新位置下拉框 + this.loadPalletTypeAreas(); + + // 保存到数据库 + this.savePalletTypeAndAutoSort(); + } + }, + + // 更新自动分拣控制逻辑 + updateAutoSortControl() { + if (this.currentWcsAutoSort === 'N') { + // 不支持自动分拣,锁定为N,禁用选择 + this.currentAutoSort = 'N'; + this.autoSortDisabled = true; + } else { + // 支持自动分拣,可以选择Y或N + this.autoSortDisabled = false; + } + }, + + // 是否自动分拣变更事件 + handleAutoSortChange() { + // 保存到数据库 + this.savePalletTypeAndAutoSort(); + }, + + // 保存栈板类型和自动分拣标志 + savePalletTypeAndAutoSort() { + updatePalletTypeAndAutoSort({ + site: this.site, + palletId: this.palletCode, + palletType: this.currentPalletType, + autoSort: this.currentAutoSort + }).then(({ data }) => { + if (data.code === 0) { + this.$message.success('更新成功'); + } else { + this.$message.error(data.msg || '更新失败'); + } + }).catch(error => { + console.error('更新失败:', error); + this.$message.error('更新失败'); + }); + }, + // Call栈板 - 调用空托盘 handleCallPallet() { this.callPalletModalVisible = true; @@ -530,12 +705,27 @@ export default { }).then(({ data }) => { if (data.code === 0) { this.detailList = data.details || []; + + // 如果栈板有明细数据,禁用栈板类型和自动分拣的修改 + const hasDetails = this.detailList.length > 0; + this.palletTypeDisabled = hasDetails; + + // 如果有明细数据,自动分拣也要禁用;否则根据wcsAutoSort判断 + if (hasDetails) { + this.autoSortDisabled = true; + } else { + this.updateAutoSortControl(); + } } else { this.detailList = []; + this.palletTypeDisabled = false; + this.updateAutoSortControl(); } }).catch(error => { console.error('获取栈板明细失败:', error); this.detailList = []; + this.palletTypeDisabled = false; + this.updateAutoSortControl(); }); }, @@ -574,17 +764,29 @@ export default { // 扫码模态框中位置变化 handleScanPositionChange() { if (this.scanPosition) { + // maxLayer=0表示混装托盘,只能选第1层 + if (this.currentMaxLayer === 0) { + this.scanLayerOptions = [1]; + this.scanLayer = 1; // 自动选中第1层 + this.moveFocusToScanInput(); + return; + } + + // maxLayer>0,根据已有层数和maxLayer计算可选层数 getLayersByPosition({ site: this.site, palletId: this.palletCode, position: this.scanPosition }).then(({ data }) => { if (data.code === 0) { - const maxLayer = data.layers && data.layers.length > 0 + const existingMaxLayer = data.layers && data.layers.length > 0 ? Math.max(...data.layers) : 0; - this.scanLayerOptions = Array.from({ length: maxLayer+1 }, (_, i) => i + 1) + // 有maxLayer限制,取已有最大层+1和maxLayer的较小值 + const layerCount = Math.min(existingMaxLayer + 1, this.currentMaxLayer); + + this.scanLayerOptions = Array.from({ length: layerCount }, (_, i) => i + 1); } }).catch(error => { console.error('获取层数失败:', error); @@ -673,6 +875,14 @@ export default { // 编辑位置选择变化 handleEditPositionChange() { if (this.editPosition) { + // maxLayer=0表示混装托盘,只能选第1层 + if (this.currentMaxLayer === 0) { + this.editLayerOptions = [1]; + this.editLayer = 1; // 自动选中第1层 + return; + } + + // maxLayer>0,根据已有层数和maxLayer计算可选层数 getLayersForEdit({ site: this.site, palletId: this.palletCode, @@ -680,7 +890,15 @@ export default { excludeSerialNo: this.editSerialNo }).then(({ data }) => { if (data.code === 0) { - this.editLayerOptions = data.layers || []; + let layerOptions = data.layers || []; + + // 根据maxLayer限制层数选项 + if (this.currentMaxLayer > 0) { + // 过滤掉超过maxLayer的层数 + layerOptions = layerOptions.filter(layer => layer <= this.currentMaxLayer); + } + + this.editLayerOptions = layerOptions; // 如果当前选择的层数不在新的选项中,清空选择 // if (!this.editLayerOptions.includes(this.editLayer)) { // this.editLayer = ''; @@ -713,6 +931,9 @@ export default { return; } + // 设置loading状态,防止重复点击 + this.editPositionLoading = true; + updatePalletDetailPosition({ site: this.site, palletId: this.palletCode, @@ -730,6 +951,9 @@ export default { }).catch(error => { console.error('位置修改失败:', error); this.$message.error('位置修改失败'); + }).finally(() => { + // 无论成功或失败,都要恢复按钮状态 + this.editPositionLoading = false; }); }, @@ -765,14 +989,38 @@ export default { } this.transportModalVisible = true; - this.selectedTargetStation = ''; - this.transportStationOptions = []; + this.selectedTargetArea = ''; + this.transportAreaOptions = []; - // 获取所有AGV站点列表,只显示空闲站点(statusDb = 0) + // 获取所有AGV站点列表,只显示空闲站点(statusDb = 0)的区域 getAgvStations({}).then(({ data }) => { if (data.code === 0) { // 过滤出statusDb为0(空闲)的站点 - this.transportStationOptions = (data.stations || []).filter(station => station.statusDb === '0'); + const freeStations = (data.stations || []).filter(station => station.statusDb === 0); + + console.log('空闲站点数量:', freeStations.length); + + // 提取station_area并去重(只提取有stationArea的站点) + const areaMap = new Map(); + freeStations.forEach(station => { + if (station.stationArea && station.stationArea.trim() !== '') { + if (!areaMap.has(station.stationArea)) { + areaMap.set(station.stationArea, { + stationArea: station.stationArea, + areaType: station.areaType + }); + } + } + }); + + this.transportAreaOptions = Array.from(areaMap.values()); + + console.log('可用目标区域数量:', this.transportAreaOptions.length); + + // 如果没有可用区域,给出友好提示 + if (this.transportAreaOptions.length === 0) { + this.$message.warning('当前没有可用的目标区域,所有站点可能都已被占用'); + } } else { this.$message.error(data.msg || '获取站点列表失败'); } @@ -795,22 +1043,19 @@ export default { this.$message.error('无法获取当前栈板位置'); return; } - if (!this.selectedTargetStation) { - this.$message.error('请选择目标站点'); + if (!this.selectedTargetArea) { + this.$message.error('请选择目标区域'); return; } - // 前端验证:起始站点和目标站点不能一样 - if (this.currentPalletStation === this.selectedTargetStation) { - this.$message.error('起始站点和目标站点不能相同'); - return; - } + // 设置loading状态,防止重复点击 + this.transportTaskLoading = true; - // 调用包含组盘处理的接口 + // 调用包含组盘处理的接口(后端会根据区域自动查找空闲站点) callPalletToStationWithUpdateZuPan({ site: this.site, startStation: this.currentPalletStation, - targetStation: this.selectedTargetStation + targetArea: this.selectedTargetArea }).then(({ data }) => { if (data.code === 0) { this.$message.success('栈板运输任务创建成功'); @@ -823,6 +1068,9 @@ export default { }).catch(error => { console.error('创建运输任务失败:', error); this.$message.error('创建运输任务失败'); + }).finally(() => { + // 无论成功或失败,都要恢复按钮状态 + this.transportTaskLoading = false; }); }, @@ -830,8 +1078,8 @@ export default { closeTransportModal() { this.transportModalVisible = false; this.currentPalletStation = ''; - this.selectedTargetStation = ''; - this.transportStationOptions = []; + this.selectedTargetArea = ''; + this.transportAreaOptions = []; }, // 确认Call栈板 @@ -851,6 +1099,9 @@ export default { return; } + // 设置loading状态,防止重复点击 + this.callPalletLoading = true; + callPalletToStation({ site: this.site, startStation: this.selectedCallStartStation, @@ -865,6 +1116,9 @@ export default { }).catch(error => { console.error('调用空托盘失败:', error); this.$message.error('异常:'+error); + }).finally(() => { + // 无论成功或失败,都要恢复按钮状态 + this.callPalletLoading = false; }); }, @@ -930,13 +1184,9 @@ export default { } .col-serial { - flex: 2; - text-align: center; -} - -.col-part { - flex: 2; + flex: 4; text-align: center; + word-break: break-all; } /* 空数据提示 */ @@ -1006,4 +1256,12 @@ export default { color: #999; width: 100%; } + +/* 按钮禁用状态样式 */ +.action-btn:disabled { + opacity: 0.6; + cursor: not-allowed; + background-color: #ccc !important; + border-color: #ccc !important; +}