常熟吴彦祖 5 months ago
parent
commit
8d768c4d84
  1. 3
      src/api/automatedWarehouse/palletPacking.js
  2. 491
      src/views/modules/automatedWarehouse/palletAssembly.vue
  3. 491
      src/views/modules/automatedWarehouse/palletPacking.vue

3
src/api/automatedWarehouse/palletPacking.js

@ -58,3 +58,6 @@ export const getPalletTypeAreas = data => createAPI(`/base/palletTypeArea/list`,
// 更新栈板类型和自动分拣标志 - AI制作 // 更新栈板类型和自动分拣标志 - AI制作
export const updatePalletTypeAndAutoSort = data => createAPI(`/wcsIntegration/updatePalletTypeAndAutoSort`,'post',data) export const updatePalletTypeAndAutoSort = data => createAPI(`/wcsIntegration/updatePalletTypeAndAutoSort`,'post',data)
export const completePalletAssembly = data => createAPI(`/wcsIntegration/completePalletAssembly`,'post',data) export const completePalletAssembly = data => createAPI(`/wcsIntegration/completePalletAssembly`,'post',data)
// 获取指定层数下各位置的可用状态 - rqrq
export const getAvailablePositionsForLayer = data => createAPI(`/wcsIntegration/getAvailablePositionsForLayer`,'post',data)

491
src/views/modules/automatedWarehouse/palletAssembly.vue

@ -24,6 +24,7 @@
style="flex: 0.75;" style="flex: 0.75;"
clearable clearable
@keyup.enter.native="handlePalletScan" @keyup.enter.native="handlePalletScan"
@focus.native="$event.target.setAttribute('inputmode', 'none')"
ref="palletInput" ref="palletInput"
/> />
<button <button
@ -111,6 +112,7 @@
<button <button
class="action-btn secondary" class="action-btn secondary"
style="flex: 0.25; margin: 0; white-space: nowrap;" style="flex: 0.25; margin: 0; white-space: nowrap;"
:disabled="currentPalletType === ''"
@click="showScanModal" @click="showScanModal"
> >
扫描条码 扫描条码
@ -193,7 +195,7 @@
<button class="action-btn secondary" style="margin-left: 10px;" @click="detailModalVisible=false">取消</button> <button class="action-btn secondary" style="margin-left: 10px;" @click="detailModalVisible=false">取消</button>
</div> </div>
</el-dialog> </el-dialog>
<!-- 扫码模态框 -->
<!-- 扫码模态框 - rqrq -->
<el-dialog <el-dialog
title="扫描标签" title="扫描标签"
:visible.sync="scanModalVisible" :visible.sync="scanModalVisible"
@ -205,43 +207,54 @@
:append-to-body="true" :append-to-body="true"
> >
<div class="scan-modal-content"> <div class="scan-modal-content">
<!-- 扫进时显示位置和层数选择 -->
<!-- 扫进时显示层数选择和位置网格 - rqrq -->
<div v-if="operationType === 'in'" class="modal-form"> <div v-if="operationType === 'in'" class="modal-form">
<div class="input-group">
<label class="input-label">位置</label>
<el-select
v-model="scanPosition"
placeholder="请选择位置"
style="width: 100%;"
@change="handleScanPositionChange"
>
<el-option
v-for="position in positionOptions"
:key="position"
:label="position"
:value="position"
/>
</el-select>
</div>
<div class="input-group">
<label class="input-label">层数</label>
<el-select
v-model="scanLayer"
placeholder="请选择层数"
@change="moveFocusToScanInput"
style="width: 100%;"
>
<el-option
<!-- 层数选择混装托盘不显示 - rqrq -->
<div v-if="!currentMixedMode && scanLayerOptions.length > 0" class="input-group">
<label class="input-label">层数当前选择{{ scanLayer }}</label>
<div class="layer-grid">
<div
v-for="layer in scanLayerOptions" v-for="layer in scanLayerOptions"
:key="layer" :key="layer"
:label="`第${layer}层`"
:value="layer"
/>
</el-select>
class="layer-item"
:class="{
'layer-selected': scanLayer === layer
}"
@click="handleLayerClick(layer)"
>
{{ layer }}
</div>
</div>
</div>
<!-- 位置网格选择器 - rqrq -->
<div class="input-group">
<label class="input-label">
位置{{ currentSelectedPosition ? `(当前选择:${currentSelectedPosition}` : '' }}
<span v-if="positionGridLoading" style="color: #909399; font-size: 12px;">加载中...</span>
</label>
<div class="position-grid" :class="[
{'position-grid-loading': positionGridLoading},
positionGrid.length === 4 ? 'position-grid-4' : 'position-grid-9'
]">
<div
v-for="(position, index) in positionGrid"
:key="index"
class="position-item"
:class="{
'position-disabled': positionGridLoading || !availablePositions.includes(position),
'position-selected': currentSelectedPosition === position,
'position-loading': positionGridLoading
}"
@click="handlePositionClick(position)"
>
{{ position }}
</div>
</div>
</div> </div>
</div> </div>
<!-- 标签扫描 -->
<!-- 标签扫描 - rqrq -->
<div class="input-group"> <div class="input-group">
<label class="input-label">标签二维码</label> <label class="input-label">标签二维码</label>
<el-input <el-input
@ -249,7 +262,9 @@
placeholder="请扫描标签二维码" placeholder="请扫描标签二维码"
class="form-input" class="form-input"
clearable clearable
:disabled="operationType === 'in' && !currentSelectedPosition"
@keyup.enter.native="handleLabelScan" @keyup.enter.native="handleLabelScan"
@focus.native="$event.target.setAttribute('inputmode', 'none')"
ref="scanInput" ref="scanInput"
/> />
</div> </div>
@ -397,7 +412,8 @@ import {
getAgvStations, getAgvStations,
getAvailableAgvStations, getAvailableAgvStations,
callPalletToStation, callPalletToStation,
completePalletAssembly
completePalletAssembly,
getAvailablePositionsForLayer
} from '../../../api/automatedWarehouse/palletPacking' } from '../../../api/automatedWarehouse/palletPacking'
export default { export default {
@ -424,14 +440,21 @@ export default {
positionOptions: [], positionOptions: [],
layerOptions: [], layerOptions: [],
//
// - rqrq
scanModalVisible: false, scanModalVisible: false,
scanCode: '', scanCode: '',
scanPosition: '', scanPosition: '',
scanLayer: '',
scanLayer: 1,
scanLayerOptions: [], scanLayerOptions: [],
needRefreshOnClose: false, // needRefreshOnClose: false, //
// - rqrq
positionGrid: [], // 49
availablePositions: [], //
currentSelectedPosition: '', //
currentMixedMode: false, //
positionGridLoading: false, //
// //
detailList: [], detailList: [],
@ -515,7 +538,7 @@ export default {
console.log('页面已重置到初始状态'); console.log('页面已重置到初始状态');
}, },
//
// - rqrq
handlePalletScan() { handlePalletScan() {
if (!this.palletCode.trim()) { if (!this.palletCode.trim()) {
this.$message.error('请输入栈板编码'); this.$message.error('请输入栈板编码');
@ -540,11 +563,41 @@ export default {
this.refreshTable(); this.refreshTable();
}) })
} else { } else {
this.$message.error(data.msg || '栈板不存在');
// 100 - rqrq
let errorMsg = data.msg || '栈板不存在';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.palletCode = '';
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus();
}
});
}
});
} }
}).catch(error => { }).catch(error => {
console.error('验证栈板失败:', error); console.error('验证栈板失败:', error);
this.$message.error('验证栈板失败');
// - rqrq
let errorMsg = error.message || '验证栈板失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.palletCode = '';
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus();
}
});
}
});
}); });
}, },
@ -774,21 +827,141 @@ export default {
}); });
}, },
//
// - rqrq
showScanModal() { showScanModal() {
this.scanModalVisible = true; this.scanModalVisible = true;
this.scanCode = ''; this.scanCode = '';
this.scanPosition = '';
this.scanLayer = '';
this.scanLayerOptions = [];
this.needRefreshOnClose = false; //
this.currentSelectedPosition = '';
this.needRefreshOnClose = false;
// - rqrq
if (this.operationType === 'in') {
this.scanLayer = 1;
// - rqrq
this.loadLayerOptions();
} else {
// - rqrq
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
},
// - rqrq
loadLayerOptions() {
console.log('开始加载层数选项 - rqrq,maxLayer=' + this.currentMaxLayer);
getPalletDetails({
site: this.site,
palletId: this.palletCode,
position: '',
layer: null
}).then(({ data }) => {
if (data && data.code === 0) {
const details = data.details || [];
// - rqrq
let maxExistingLayer = 0;
if (details.length > 0) {
maxExistingLayer = Math.max(...details.map(d => d.layer || 0));
}
// maxLayer - rqrq
if (this.currentMaxLayer === 0) {
// maxLayer=0+1 - rqrq
this.currentMixedMode = false;
this.scanLayerOptions = Array.from({ length: maxExistingLayer + 1 }, (_, i) => i + 1);
console.log('不限高模式 - 已有最大层:' + maxExistingLayer + ',可选层数:' + this.scanLayerOptions.length + ' - rqrq');
} else {
// maxLayer>01~maxLayer - rqrq
this.currentMixedMode = false;
this.scanLayerOptions = Array.from({ length: this.currentMaxLayer }, (_, i) => i + 1);
console.log('限高模式 - maxLayer:' + this.currentMaxLayer + ' - rqrq');
}
// - rqrq
this.loadAvailablePositions();
} else {
this.$message.error(data.msg || '获取栈板信息失败');
}
}).catch(error => {
console.error('获取栈板信息失败:', error);
this.$message.error('获取栈板信息失败');
});
},
// - rqrq
loadAvailablePositions() {
console.log('开始加载位置网格 - rqrq,layer=' + this.scanLayer);
// - rqrq
this.positionGridLoading = true;
this.availablePositions = []; //
getAvailablePositionsForLayer({
site: this.site,
palletId: this.palletCode,
layer: this.scanLayer
}).then(({ data }) => {
if (data && data.code === 0) {
const result = data.data;
this.positionGrid = result.positions || [];
this.availablePositions = result.availablePositions || [];
console.log('位置网格加载完成 - 总位置:' + this.positionGrid.length + ',可用:' + this.availablePositions.length + ' - rqrq');
} else {
this.$message.error(data.msg || '获取位置信息失败');
// - rqrq
this.availablePositions = [];
}
}).catch(error => {
console.error('获取位置信息失败:', error);
this.$message.error('获取位置信息失败');
// - rqrq
this.availablePositions = [];
}).finally(() => {
// - rqrq
this.positionGridLoading = false;
});
},
// - rqrq
handleLayerClick(layer) {
if (this.scanLayer === layer) {
return; //
}
console.log('切换层数 - rqrq,从第' + this.scanLayer + '层切换到第' + layer + '层');
this.scanLayer = layer;
this.currentSelectedPosition = '';
this.loadAvailablePositions();
},
// - rqrq
handlePositionClick(position) {
// - rqrq
if (this.positionGridLoading) {
this.$message.warning('位置信息加载中,请稍候');
return;
}
if (!this.availablePositions.includes(position)) {
this.$message.warning('该位置不可用');
return;
}
this.currentSelectedPosition = position;
this.scanPosition = position;
console.log('选择位置 - rqrq,position=' + position);
// - rqrq
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs.scanInput) { if (this.$refs.scanInput) {
this.$refs.scanInput.focus(); this.$refs.scanInput.focus();
} }
}); });
}, },
moveFocusToScanInput(){ moveFocusToScanInput(){
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs.scanInput) { if (this.$refs.scanInput) {
@ -806,44 +979,9 @@ export default {
} }
}, },
//
handleScanPositionChange() {
if (this.scanPosition) {
// maxLayer=01
if (this.currentMaxLayer === 0) {
this.scanLayerOptions = [1];
this.scanLayer = 1; // 1
this.moveFocusToScanInput();
return;
}
// maxLayer>0maxLayer
getLayersByPosition({
site: this.site,
palletId: this.palletCode,
position: this.scanPosition
}).then(({ data }) => {
if (data.code === 0) {
const existingMaxLayer = data.layers && data.layers.length > 0
? Math.max(...data.layers)
: 0;
// maxLayer+1maxLayer
const layerCount = Math.min(existingMaxLayer + 1, this.currentMaxLayer);
this.scanLayerOptions = Array.from({ length: layerCount }, (_, i) => i + 1);
}
}).catch(error => {
console.error('获取层数失败:', error);
this.scanLayerOptions = [1];
});
} else {
this.scanLayerOptions = [];
}
this.scanLayer = '';
},
//
// - rqrq
handleLabelScan() { handleLabelScan() {
if (!this.scanCode.trim()) { if (!this.scanCode.trim()) {
this.$message.error('请输入标签编码'); this.$message.error('请输入标签编码');
@ -870,16 +1008,50 @@ export default {
}).then(({ data }) => { }).then(({ data }) => {
if (data.code === 0) { if (data.code === 0) {
this.$message.success('扫进成功'); this.$message.success('扫进成功');
this.needRefreshOnClose = true; //
this.scanCode = ''; //
this.handleScanPositionChange()
this.needRefreshOnClose = true;
this.scanCode = '';
// - rqrq
this.loadLayerOptions();
// - rqrq
this.$refs.scanInput.focus(); this.$refs.scanInput.focus();
} else { } else {
this.$message.error(data.msg || '扫进失败');
// 100 - rqrq
let errorMsg = data.msg || '扫进失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
} }
}).catch(error => { }).catch(error => {
console.error('扫进失败:', error); console.error('扫进失败:', error);
this.$message.error('扫进失败');
// - rqrq
let errorMsg = error.message || '扫进失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
}); });
} else { } else {
// //
@ -890,15 +1062,45 @@ export default {
}).then(({ data }) => { }).then(({ data }) => {
if (data.code === 0) { if (data.code === 0) {
this.$message.success('扫出成功'); this.$message.success('扫出成功');
this.needRefreshOnClose = true; //
this.scanCode = ''; //
this.needRefreshOnClose = true;
this.scanCode = '';
this.$refs.scanInput.focus(); this.$refs.scanInput.focus();
} else { } else {
this.$message.error(data.msg || '扫出失败');
// 100 - rqrq
let errorMsg = data.msg || '扫出失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
} }
}).catch(error => { }).catch(error => {
console.error('扫出失败:', error); console.error('扫出失败:', error);
this.$message.error('扫出失败');
// - rqrq
let errorMsg = error.message || '扫出失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
}); });
} }
}, },
@ -1248,4 +1450,117 @@ export default {
background-color: #ccc !important; background-color: #ccc !important;
border-color: #ccc !important; border-color: #ccc !important;
} }
/* 层数网格样式 - rqrq */
.layer-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.layer-item {
display: flex;
align-items: center;
justify-content: center;
min-width: 50px;
height: 45px;
padding: 0 12px;
background-color: #fff;
border: 2px solid #dcdfe6;
border-radius: 6px;
font-size: 15px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
user-select: none;
}
.layer-item:hover {
border-color: #409eff;
background-color: #ecf5ff;
}
.layer-item.layer-selected {
border-color: #409eff;
background-color: #409eff;
color: #fff;
}
/* 位置网格样式 - rqrq */
.position-grid {
display: grid;
gap: 10px;
margin-top: 8px;
position: relative;
}
/* 4宫格:2行2列,按列排列(1,2 | 3,4) - rqrq */
.position-grid.position-grid-4 {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
grid-auto-flow: column;
}
/* 9宫格:3行3列,按列排列(1,2,3 | 4,5,6 | 7,8,9) - rqrq */
.position-grid.position-grid-9 {
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-auto-flow: column;
}
/* 加载中的遮罩效果 - rqrq */
.position-grid.position-grid-loading {
opacity: 0.7;
pointer-events: none;
}
.position-item {
display: flex;
align-items: center;
justify-content: center;
height: 60px;
background-color: #fff;
border: 2px solid #dcdfe6;
border-radius: 6px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
user-select: none;
}
.position-item:hover:not(.position-disabled) {
border-color: #409eff;
background-color: #ecf5ff;
}
.position-item.position-selected {
border-color: #409eff;
background-color: #409eff;
color: #fff;
}
.position-item.position-disabled {
background-color: #f5f7fa;
color: #c0c4cc;
cursor: not-allowed;
opacity: 0.6;
}
/* 加载中的位置项样式 - rqrq */
.position-item.position-loading {
background: linear-gradient(90deg, #f5f7fa 25%, #e4e7ed 50%, #f5f7fa 75%);
background-size: 200% 100%;
animation: loading 1.5s ease-in-out infinite;
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
</style> </style>

491
src/views/modules/automatedWarehouse/palletPacking.vue

@ -23,6 +23,7 @@
class="form-input" class="form-input"
style="flex: 0.75;" style="flex: 0.75;"
clearable clearable
@focus.native="$event.target.setAttribute('inputmode', 'none')"
@keyup.enter.native="handlePalletScan" @keyup.enter.native="handlePalletScan"
ref="palletInput" ref="palletInput"
/> />
@ -111,6 +112,7 @@
<button <button
class="action-btn secondary" class="action-btn secondary"
style="flex: 0.25; margin: 0; white-space: nowrap;" style="flex: 0.25; margin: 0; white-space: nowrap;"
:disabled="currentPalletType === ''"
@click="showScanModal" @click="showScanModal"
> >
扫描条码 扫描条码
@ -191,7 +193,7 @@
<button class="action-btn secondary" style="margin-left: 10px;" @click="detailModalVisible=false">取消</button> <button class="action-btn secondary" style="margin-left: 10px;" @click="detailModalVisible=false">取消</button>
</div> </div>
</el-dialog> </el-dialog>
<!-- 扫码模态框 -->
<!-- 扫码模态框 - rqrq -->
<el-dialog <el-dialog
title="扫描标签" title="扫描标签"
:visible.sync="scanModalVisible" :visible.sync="scanModalVisible"
@ -203,43 +205,54 @@
:append-to-body="true" :append-to-body="true"
> >
<div class="scan-modal-content"> <div class="scan-modal-content">
<!-- 扫进时显示位置和层数选择 -->
<!-- 扫进时显示层数选择和位置网格 - rqrq -->
<div v-if="operationType === 'in'" class="modal-form"> <div v-if="operationType === 'in'" class="modal-form">
<div class="input-group">
<label class="input-label">位置</label>
<el-select
v-model="scanPosition"
placeholder="请选择位置"
style="width: 100%;"
@change="handleScanPositionChange"
>
<el-option
v-for="position in positionOptions"
:key="position"
:label="position"
:value="position"
/>
</el-select>
</div>
<div class="input-group">
<label class="input-label">层数</label>
<el-select
v-model="scanLayer"
placeholder="请选择层数"
@change="moveFocusToScanInput"
style="width: 100%;"
>
<el-option
<!-- 层数选择混装托盘不显示 - rqrq -->
<div v-if="!currentMixedMode && scanLayerOptions.length > 0" class="input-group">
<label class="input-label">层数当前选择{{ scanLayer }}</label>
<div class="layer-grid">
<div
v-for="layer in scanLayerOptions" v-for="layer in scanLayerOptions"
:key="layer" :key="layer"
:label="`第${layer}层`"
:value="layer"
/>
</el-select>
class="layer-item"
:class="{
'layer-selected': scanLayer === layer
}"
@click="handleLayerClick(layer)"
>
{{ layer }}
</div>
</div>
</div>
<!-- 位置网格选择器 - rqrq -->
<div class="input-group">
<label class="input-label">
位置{{ currentSelectedPosition ? `(当前选择:${currentSelectedPosition}` : '' }}
<span v-if="positionGridLoading" style="color: #909399; font-size: 12px;">加载中...</span>
</label>
<div class="position-grid" :class="[
{'position-grid-loading': positionGridLoading},
positionGrid.length === 4 ? 'position-grid-4' : 'position-grid-9'
]">
<div
v-for="(position, index) in positionGrid"
:key="index"
class="position-item"
:class="{
'position-disabled': positionGridLoading || !availablePositions.includes(position),
'position-selected': currentSelectedPosition === position,
'position-loading': positionGridLoading
}"
@click="handlePositionClick(position)"
>
{{ position }}
</div>
</div>
</div> </div>
</div> </div>
<!-- 标签扫描 -->
<!-- 标签扫描 - rqrq -->
<div class="input-group"> <div class="input-group">
<label class="input-label">标签二维码</label> <label class="input-label">标签二维码</label>
<el-input <el-input
@ -247,7 +260,9 @@
placeholder="请扫描标签二维码" placeholder="请扫描标签二维码"
class="form-input" class="form-input"
clearable clearable
:disabled="operationType === 'in' && !currentSelectedPosition"
@keyup.enter.native="handleLabelScan" @keyup.enter.native="handleLabelScan"
@focus.native="$event.target.setAttribute('inputmode', 'none')"
ref="scanInput" ref="scanInput"
/> />
</div> </div>
@ -456,7 +471,8 @@ import {
getPalletInfo, getPalletInfo,
getPalletTypeList, getPalletTypeList,
getPalletTypeAreas, getPalletTypeAreas,
updatePalletTypeAndAutoSort
updatePalletTypeAndAutoSort,
getAvailablePositionsForLayer
} from '../../../api/automatedWarehouse/palletPacking' } from '../../../api/automatedWarehouse/palletPacking'
export default { export default {
@ -483,14 +499,21 @@ export default {
positionOptions: [], positionOptions: [],
layerOptions: [], layerOptions: [],
//
// - rqrq
scanModalVisible: false, scanModalVisible: false,
scanCode: '', scanCode: '',
scanPosition: '', scanPosition: '',
scanLayer: '',
scanLayer: 1,
scanLayerOptions: [], scanLayerOptions: [],
needRefreshOnClose: false, // needRefreshOnClose: false, //
// - rqrq
positionGrid: [], // 49
availablePositions: [], //
currentSelectedPosition: '', //
currentMixedMode: false, //
positionGridLoading: false, //
// //
detailList: [], detailList: [],
@ -586,7 +609,7 @@ export default {
console.log('页面已重置到初始状态'); console.log('页面已重置到初始状态');
}, },
//
// - rqrq
handlePalletScan() { handlePalletScan() {
if (!this.palletCode.trim()) { if (!this.palletCode.trim()) {
this.$message.error('请输入栈板编码'); this.$message.error('请输入栈板编码');
@ -609,11 +632,41 @@ export default {
this.refreshTable(); this.refreshTable();
}) })
} else { } else {
this.$message.error(data.msg || '栈板不存在');
// 100 - rqrq
let errorMsg = data.msg || '栈板不存在';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.palletCode = '';
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus();
}
});
}
});
} }
}).catch(error => { }).catch(error => {
console.error('验证栈板失败:', error); console.error('验证栈板失败:', error);
this.$message.error('验证栈板失败');
// - rqrq
let errorMsg = error.message || '验证栈板失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.palletCode = '';
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus();
}
});
}
});
}); });
}, },
@ -843,15 +896,135 @@ export default {
}); });
}, },
//
// - rqrq
showScanModal() { showScanModal() {
this.scanModalVisible = true; this.scanModalVisible = true;
this.scanCode = ''; this.scanCode = '';
this.scanPosition = '';
this.scanLayer = '';
this.scanLayerOptions = [];
this.needRefreshOnClose = false; //
this.currentSelectedPosition = '';
this.needRefreshOnClose = false;
// - rqrq
if (this.operationType === 'in') {
this.scanLayer = 1;
// - rqrq
this.loadLayerOptions();
} else {
// - rqrq
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
},
// - rqrq
loadLayerOptions() {
console.log('开始加载层数选项 - rqrq,maxLayer=' + this.currentMaxLayer);
getPalletDetails({
site: this.site,
palletId: this.palletCode,
position: '',
layer: null
}).then(({ data }) => {
if (data && data.code === 0) {
const details = data.details || [];
// - rqrq
let maxExistingLayer = 0;
if (details.length > 0) {
maxExistingLayer = Math.max(...details.map(d => d.layer || 0));
}
// maxLayer - rqrq
if (this.currentMaxLayer === 0) {
// maxLayer=0+1 - rqrq
this.currentMixedMode = false;
this.scanLayerOptions = Array.from({ length: maxExistingLayer + 1 }, (_, i) => i + 1);
console.log('不限高模式 - 已有最大层:' + maxExistingLayer + ',可选层数:' + this.scanLayerOptions.length + ' - rqrq');
} else {
// maxLayer>01~maxLayer - rqrq
this.currentMixedMode = false;
this.scanLayerOptions = Array.from({ length: this.currentMaxLayer }, (_, i) => i + 1);
console.log('限高模式 - maxLayer:' + this.currentMaxLayer + ' - rqrq');
}
// - rqrq
this.loadAvailablePositions();
} else {
this.$message.error(data.msg || '获取栈板信息失败');
}
}).catch(error => {
console.error('获取栈板信息失败:', error);
this.$message.error('获取栈板信息失败');
});
},
// - rqrq
loadAvailablePositions() {
console.log('开始加载位置网格 - rqrq,layer=' + this.scanLayer);
// - rqrq
this.positionGridLoading = true;
this.availablePositions = []; //
getAvailablePositionsForLayer({
site: this.site,
palletId: this.palletCode,
layer: this.scanLayer
}).then(({ data }) => {
if (data && data.code === 0) {
const result = data.data;
this.positionGrid = result.positions || [];
this.availablePositions = result.availablePositions || [];
console.log('位置网格加载完成 - 总位置:' + this.positionGrid.length + ',可用:' + this.availablePositions.length + ' - rqrq');
} else {
this.$message.error(data.msg || '获取位置信息失败');
// - rqrq
this.availablePositions = [];
}
}).catch(error => {
console.error('获取位置信息失败:', error);
this.$message.error('获取位置信息失败');
// - rqrq
this.availablePositions = [];
}).finally(() => {
// - rqrq
this.positionGridLoading = false;
});
},
// - rqrq
handleLayerClick(layer) {
if (this.scanLayer === layer) {
return; //
}
console.log('切换层数 - rqrq,从第' + this.scanLayer + '层切换到第' + layer + '层');
this.scanLayer = layer;
this.currentSelectedPosition = '';
this.loadAvailablePositions();
},
// - rqrq
handlePositionClick(position) {
// - rqrq
if (this.positionGridLoading) {
this.$message.warning('位置信息加载中,请稍候');
return;
}
if (!this.availablePositions.includes(position)) {
this.$message.warning('该位置不可用');
return;
}
this.currentSelectedPosition = position;
this.scanPosition = position;
console.log('选择位置 - rqrq,position=' + position);
// - rqrq
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs.scanInput) { if (this.$refs.scanInput) {
this.$refs.scanInput.focus(); this.$refs.scanInput.focus();
@ -875,44 +1048,9 @@ export default {
} }
}, },
//
handleScanPositionChange() {
if (this.scanPosition) {
// maxLayer=01
if (this.currentMaxLayer === 0) {
this.scanLayerOptions = [1];
this.scanLayer = 1; // 1
this.moveFocusToScanInput();
return;
}
// maxLayer>0maxLayer
getLayersByPosition({
site: this.site,
palletId: this.palletCode,
position: this.scanPosition
}).then(({ data }) => {
if (data.code === 0) {
const existingMaxLayer = data.layers && data.layers.length > 0
? Math.max(...data.layers)
: 0;
// maxLayer+1maxLayer
const layerCount = Math.min(existingMaxLayer + 1, this.currentMaxLayer);
this.scanLayerOptions = Array.from({ length: layerCount }, (_, i) => i + 1);
}
}).catch(error => {
console.error('获取层数失败:', error);
this.scanLayerOptions = [1];
});
} else {
this.scanLayerOptions = [];
}
this.scanLayer = '';
},
//
// - rqrq
handleLabelScan() { handleLabelScan() {
if (!this.scanCode.trim()) { if (!this.scanCode.trim()) {
this.$message.error('请输入标签编码'); this.$message.error('请输入标签编码');
@ -939,16 +1077,50 @@ export default {
}).then(({ data }) => { }).then(({ data }) => {
if (data.code === 0) { if (data.code === 0) {
this.$message.success('扫进成功'); this.$message.success('扫进成功');
this.needRefreshOnClose = true; //
this.scanCode = ''; //
this.handleScanPositionChange()
this.needRefreshOnClose = true;
this.scanCode = '';
// - rqrq
this.loadLayerOptions();
// - rqrq
this.$refs.scanInput.focus(); this.$refs.scanInput.focus();
} else { } else {
this.$message.error(data.msg || '扫进失败');
// 100 - rqrq
let errorMsg = data.msg || '扫进失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
} }
}).catch(error => { }).catch(error => {
console.error('扫进失败:', error); console.error('扫进失败:', error);
this.$message.error('扫进失败');
// - rqrq
let errorMsg = error.message || '扫进失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
}); });
} else { } else {
// //
@ -959,15 +1131,45 @@ export default {
}).then(({ data }) => { }).then(({ data }) => {
if (data.code === 0) { if (data.code === 0) {
this.$message.success('扫出成功'); this.$message.success('扫出成功');
this.needRefreshOnClose = true; //
this.scanCode = ''; //
this.needRefreshOnClose = true;
this.scanCode = '';
this.$refs.scanInput.focus(); this.$refs.scanInput.focus();
} else { } else {
this.$message.error(data.msg || '扫出失败');
// 100 - rqrq
let errorMsg = data.msg || '扫出失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
} }
}).catch(error => { }).catch(error => {
console.error('扫出失败:', error); console.error('扫出失败:', error);
this.$message.error('扫出失败');
// - rqrq
let errorMsg = error.message || '扫出失败';
if (errorMsg.length > 100) {
errorMsg = errorMsg.substring(0, 100) + '...';
}
this.$alert(errorMsg, '错误', {
confirmButtonText: '确定',
callback: () => {
this.scanCode = '';
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
});
}); });
} }
}, },
@ -1381,4 +1583,117 @@ export default {
background-color: #ccc !important; background-color: #ccc !important;
border-color: #ccc !important; border-color: #ccc !important;
} }
/* 层数网格样式 - rqrq */
.layer-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.layer-item {
display: flex;
align-items: center;
justify-content: center;
min-width: 50px;
height: 45px;
padding: 0 12px;
background-color: #fff;
border: 2px solid #dcdfe6;
border-radius: 6px;
font-size: 15px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
user-select: none;
}
.layer-item:hover {
border-color: #409eff;
background-color: #ecf5ff;
}
.layer-item.layer-selected {
border-color: #409eff;
background-color: #409eff;
color: #fff;
}
/* 位置网格样式 - rqrq */
.position-grid {
display: grid;
gap: 10px;
margin-top: 8px;
position: relative;
}
/* 4宫格:2行2列,按列排列(1,2 | 3,4) - rqrq */
.position-grid.position-grid-4 {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
grid-auto-flow: column;
}
/* 9宫格:3行3列,按列排列(1,2,3 | 4,5,6 | 7,8,9) - rqrq */
.position-grid.position-grid-9 {
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-auto-flow: column;
}
/* 加载中的遮罩效果 - rqrq */
.position-grid.position-grid-loading {
opacity: 0.7;
pointer-events: none;
}
.position-item {
display: flex;
align-items: center;
justify-content: center;
height: 60px;
background-color: #fff;
border: 2px solid #dcdfe6;
border-radius: 6px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
user-select: none;
}
.position-item:hover:not(.position-disabled) {
border-color: #409eff;
background-color: #ecf5ff;
}
.position-item.position-selected {
border-color: #409eff;
background-color: #409eff;
color: #fff;
}
.position-item.position-disabled {
background-color: #f5f7fa;
color: #c0c4cc;
cursor: not-allowed;
opacity: 0.6;
}
/* 加载中的位置项样式 - rqrq */
.position-item.position-loading {
background: linear-gradient(90deg, #f5f7fa 25%, #e4e7ed 50%, #f5f7fa 75%);
background-size: 200% 100%;
animation: loading 1.5s ease-in-out infinite;
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
</style> </style>
Loading…
Cancel
Save