|
|
@ -36,45 +36,62 @@ |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 第二行:筛选条件 (扫描栈板后显示) --> |
|
|
|
|
|
|
|
|
<!-- 第二行:栈板类型和自动分拣 (扫描栈板后显示) --> |
|
|
<div v-if="palletScanned" class="input-group"> |
|
|
<div v-if="palletScanned" class="input-group"> |
|
|
<div style="display: flex; gap: 8px; align-items: end;"> |
|
|
<div style="display: flex; gap: 8px; align-items: end;"> |
|
|
<div style="flex: 1;"> |
|
|
|
|
|
<label class="input-label">位置</label> |
|
|
|
|
|
|
|
|
<div style="flex: 0.65;"> |
|
|
|
|
|
<label class="input-label">栈板类型</label> |
|
|
<el-select |
|
|
<el-select |
|
|
v-model="selectedPosition" |
|
|
|
|
|
placeholder="请选择位置" |
|
|
|
|
|
|
|
|
v-model="currentPalletType" |
|
|
|
|
|
placeholder="请选择栈板类型" |
|
|
style="width: 100%;" |
|
|
style="width: 100%;" |
|
|
@change="handlePositionChange" |
|
|
|
|
|
|
|
|
:disabled="palletTypeDisabled" |
|
|
|
|
|
@change="handlePalletTypeChange" |
|
|
> |
|
|
> |
|
|
<el-option label="ALL" value=""></el-option> |
|
|
|
|
|
<el-option |
|
|
<el-option |
|
|
v-for="position in positionOptions" |
|
|
|
|
|
:key="position" |
|
|
|
|
|
:label="position" |
|
|
|
|
|
:value="position" |
|
|
|
|
|
|
|
|
v-for="type in palletTypeOptions" |
|
|
|
|
|
:key="type.palletType" |
|
|
|
|
|
:label="`${type.palletType} - ${type.typeDesc}`" |
|
|
|
|
|
:value="type.palletType" |
|
|
/> |
|
|
/> |
|
|
</el-select> |
|
|
</el-select> |
|
|
</div> |
|
|
</div> |
|
|
<div style="flex: 1;"> |
|
|
|
|
|
<label class="input-label">层数</label> |
|
|
|
|
|
|
|
|
<div style="flex: 0.35;"> |
|
|
|
|
|
<label class="input-label">自动分拣</label> |
|
|
<el-select |
|
|
<el-select |
|
|
v-model="selectedLayer" |
|
|
|
|
|
placeholder="请选择层数" |
|
|
|
|
|
|
|
|
v-model="currentAutoSort" |
|
|
|
|
|
placeholder="请选择" |
|
|
style="width: 100%;" |
|
|
style="width: 100%;" |
|
|
|
|
|
:disabled="autoSortDisabled" |
|
|
|
|
|
@change="handleAutoSortChange" |
|
|
|
|
|
> |
|
|
|
|
|
<el-option label="是" value="Y"></el-option> |
|
|
|
|
|
<el-option label="否" value="N"></el-option> |
|
|
|
|
|
</el-select> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 第三行:筛选条件 (扫描栈板后显示) --> |
|
|
|
|
|
<div v-if="palletScanned" class="input-group"> |
|
|
|
|
|
<label class="input-label">位置</label> |
|
|
|
|
|
<div style="display: flex; gap: 8px;"> |
|
|
|
|
|
<el-select |
|
|
|
|
|
v-model="selectedPosition" |
|
|
|
|
|
placeholder="请选择位置" |
|
|
|
|
|
style="flex: 0.75;" |
|
|
> |
|
|
> |
|
|
<el-option label="ALL" value=""></el-option> |
|
|
<el-option label="ALL" value=""></el-option> |
|
|
<el-option |
|
|
<el-option |
|
|
v-for="layer in layerOptions" |
|
|
|
|
|
:key="layer" |
|
|
|
|
|
:label="`第${layer}层`" |
|
|
|
|
|
:value="layer" |
|
|
|
|
|
|
|
|
v-for="position in positionOptions" |
|
|
|
|
|
:key="position" |
|
|
|
|
|
:label="position" |
|
|
|
|
|
:value="position" |
|
|
/> |
|
|
/> |
|
|
</el-select> |
|
|
</el-select> |
|
|
</div> |
|
|
|
|
|
<button |
|
|
<button |
|
|
class="action-btn secondary" |
|
|
class="action-btn secondary" |
|
|
style="margin: 0; white-space: nowrap;" |
|
|
|
|
|
|
|
|
style="flex: 0.25; margin: 0; white-space: nowrap;" |
|
|
@click="refreshTable" |
|
|
@click="refreshTable" |
|
|
> |
|
|
> |
|
|
刷新 |
|
|
刷新 |
|
|
@ -82,21 +99,21 @@ |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 第三行:扫进/扫出选择 (扫描栈板后显示) --> |
|
|
|
|
|
|
|
|
<!-- 第四行:扫进/扫出选择 (扫描栈板后显示) --> |
|
|
<div v-if="palletScanned" class="input-group"> |
|
|
<div v-if="palletScanned" class="input-group"> |
|
|
<div style="display: flex; gap: 8px; align-items: center; flex-wrap: nowrap;"> |
|
|
|
|
|
<div style="flex: 1; min-width: 0;"> |
|
|
|
|
|
<el-radio-group v-model="operationType" style="display: flex; flex-wrap: nowrap;"> |
|
|
|
|
|
|
|
|
<div style="display: flex; gap: 8px; align-items: center;"> |
|
|
|
|
|
<div style="flex: 0.75;"> |
|
|
|
|
|
<el-radio-group v-model="operationType" style="display: flex;"> |
|
|
<el-radio label="in" style="margin-right: 0px; white-space: nowrap;">扫进</el-radio> |
|
|
<el-radio label="in" style="margin-right: 0px; white-space: nowrap;">扫进</el-radio> |
|
|
<el-radio label="out" style="white-space: nowrap;">扫出</el-radio> |
|
|
<el-radio label="out" style="white-space: nowrap;">扫出</el-radio> |
|
|
</el-radio-group> |
|
|
</el-radio-group> |
|
|
</div> |
|
|
</div> |
|
|
<button |
|
|
<button |
|
|
class="action-btn secondary" |
|
|
class="action-btn secondary" |
|
|
style="margin: 0; white-space: nowrap; flex-shrink: 0;" |
|
|
|
|
|
|
|
|
style="flex: 0.25; margin: 0; white-space: nowrap;" |
|
|
@click="showScanModal" |
|
|
@click="showScanModal" |
|
|
> |
|
|
> |
|
|
扫描二维码 |
|
|
|
|
|
|
|
|
扫描条码 |
|
|
</button> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
@ -104,16 +121,15 @@ |
|
|
|
|
|
|
|
|
<!-- 栈板明细表格 (扫描栈板后显示) --> |
|
|
<!-- 栈板明细表格 (扫描栈板后显示) --> |
|
|
<div v-if="palletScanned" class="rma-list"> |
|
|
<div v-if="palletScanned" class="rma-list"> |
|
|
<div class="list-title-row"> |
|
|
|
|
|
<div class="list-title">栈板明细</div> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="handleTransportOrder">运输指令</button> |
|
|
|
|
|
|
|
|
<div class="list-title-row" style="display: flex; gap: 8px; align-items: center; padding: 0;"> |
|
|
|
|
|
<div class="list-title" style="flex: 0.75; margin: 0;">栈板明细</div> |
|
|
|
|
|
<button class="action-btn secondary" style="flex: 0.25; margin: 0;" @click="handleTransportOrder">运输指令</button> |
|
|
</div> |
|
|
</div> |
|
|
<div class="detail-table"> |
|
|
<div class="detail-table"> |
|
|
<div class="table-header"> |
|
|
<div class="table-header"> |
|
|
<div class="col-position">位置</div> |
|
|
<div class="col-position">位置</div> |
|
|
<div class="col-layer">层数</div> |
|
|
<div class="col-layer">层数</div> |
|
|
<div class="col-serial">标签号</div> |
|
|
<div class="col-serial">标签号</div> |
|
|
<div class="col-part">物料编码</div> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
<div |
|
|
<div |
|
|
v-for="(detail, index) in detailList" |
|
|
v-for="(detail, index) in detailList" |
|
|
@ -124,7 +140,6 @@ |
|
|
<div class="col-position">{{ detail.position }}</div> |
|
|
<div class="col-position">{{ detail.position }}</div> |
|
|
<div class="col-layer">{{ detail.layer }}</div> |
|
|
<div class="col-layer">{{ detail.layer }}</div> |
|
|
<div class="col-serial">{{ detail.serialNo }}</div> |
|
|
<div class="col-serial">{{ detail.serialNo }}</div> |
|
|
<div class="col-part">{{ detail.partNo }}</div> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
<!-- 暂无数据提示 --> |
|
|
<!-- 暂无数据提示 --> |
|
|
<div v-if="detailList.length === 0" class="table-row empty-row"> |
|
|
<div v-if="detailList.length === 0" class="table-row empty-row"> |
|
|
@ -261,8 +276,10 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div slot="footer" class="dialog-footer"> |
|
|
<div slot="footer" class="dialog-footer"> |
|
|
<button class="action-btn primary" @click="confirmEditPosition">确定</button> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeEditPositionModal">取消</button> |
|
|
|
|
|
|
|
|
<button class="action-btn primary" @click="confirmEditPosition" :disabled="editPositionLoading"> |
|
|
|
|
|
{{ editPositionLoading ? '处理中...' : '确定' }} |
|
|
|
|
|
</button> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeEditPositionModal" :disabled="editPositionLoading">取消</button> |
|
|
</div> |
|
|
</div> |
|
|
</el-dialog> |
|
|
</el-dialog> |
|
|
|
|
|
|
|
|
@ -300,27 +317,29 @@ |
|
|
/> |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 目标站点选择 --> |
|
|
|
|
|
|
|
|
<!-- 目标区域选择 --> |
|
|
<div class="input-group"> |
|
|
<div class="input-group"> |
|
|
<label class="input-label">目标站点</label> |
|
|
|
|
|
|
|
|
<label class="input-label">目标区域</label> |
|
|
<el-select |
|
|
<el-select |
|
|
v-model="selectedTargetStation" |
|
|
|
|
|
placeholder="请选择目标站点" |
|
|
|
|
|
|
|
|
v-model="selectedTargetArea" |
|
|
|
|
|
placeholder="请选择目标区域" |
|
|
style="width: 100%;" |
|
|
style="width: 100%;" |
|
|
> |
|
|
> |
|
|
<el-option |
|
|
<el-option |
|
|
v-for="station in transportStationOptions" |
|
|
|
|
|
:key="station.stationCode" |
|
|
|
|
|
:label="`${station.stationCode} - ${station.stationName}`" |
|
|
|
|
|
:value="station.stationCode" |
|
|
|
|
|
|
|
|
v-for="area in transportAreaOptions" |
|
|
|
|
|
:key="area.stationArea" |
|
|
|
|
|
:label="area.stationArea" |
|
|
|
|
|
:value="area.stationArea" |
|
|
/> |
|
|
/> |
|
|
</el-select> |
|
|
</el-select> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div slot="footer" class="dialog-footer"> |
|
|
<div slot="footer" class="dialog-footer"> |
|
|
<button class="action-btn primary" @click="confirmTransportTask">确定</button> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeTransportModal">取消</button> |
|
|
|
|
|
|
|
|
<button class="action-btn primary" @click="confirmTransportTask" :disabled="transportTaskLoading"> |
|
|
|
|
|
{{ transportTaskLoading ? '创建中...' : '确定' }} |
|
|
|
|
|
</button> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeTransportModal" :disabled="transportTaskLoading">取消</button> |
|
|
</div> |
|
|
</div> |
|
|
</el-dialog> |
|
|
</el-dialog> |
|
|
|
|
|
|
|
|
@ -368,8 +387,10 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div slot="footer" class="dialog-footer"> |
|
|
<div slot="footer" class="dialog-footer"> |
|
|
<button class="action-btn primary" @click="confirmCallPallet">确定</button> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeCallPalletModal">取消</button> |
|
|
|
|
|
|
|
|
<button class="action-btn primary" @click="confirmCallPallet" :disabled="callPalletLoading"> |
|
|
|
|
|
{{ callPalletLoading ? '调用中...' : '确定' }} |
|
|
|
|
|
</button> |
|
|
|
|
|
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeCallPalletModal" :disabled="callPalletLoading">取消</button> |
|
|
</div> |
|
|
</div> |
|
|
</el-dialog> |
|
|
</el-dialog> |
|
|
</div> |
|
|
</div> |
|
|
@ -388,7 +409,11 @@ import { |
|
|
updatePalletDetailPosition, |
|
|
updatePalletDetailPosition, |
|
|
getAgvStations, |
|
|
getAgvStations, |
|
|
callPalletToStation, |
|
|
callPalletToStation, |
|
|
callPalletToStationWithUpdateZuPan |
|
|
|
|
|
|
|
|
callPalletToStationWithUpdateZuPan, |
|
|
|
|
|
getPalletInfo, |
|
|
|
|
|
getPalletTypeList, |
|
|
|
|
|
getPalletTypeAreas, |
|
|
|
|
|
updatePalletTypeAndAutoSort |
|
|
} from '../../../api/automatedWarehouse/palletPacking' |
|
|
} from '../../../api/automatedWarehouse/palletPacking' |
|
|
|
|
|
|
|
|
export default { |
|
|
export default { |
|
|
@ -399,6 +424,16 @@ export default { |
|
|
palletScanned: false, |
|
|
palletScanned: false, |
|
|
operationType: 'in', // 'in' 或 'out' |
|
|
operationType: 'in', // 'in' 或 'out' |
|
|
|
|
|
|
|
|
|
|
|
// 栈板类型和自动分拣 |
|
|
|
|
|
currentPalletFamily: '', // 当前栈板大分类(固定不可改) |
|
|
|
|
|
currentPalletType: '', // 当前栈板类型 |
|
|
|
|
|
currentAutoSort: '', // 当前是否自动分拣 Y/N |
|
|
|
|
|
palletTypeOptions: [], // 托盘类型选项列表 |
|
|
|
|
|
palletTypeDisabled: false, // 栈板类型下拉框是否禁用(有明细数据时禁用) |
|
|
|
|
|
autoSortDisabled: false, // 自动分拣下拉框是否禁用 |
|
|
|
|
|
currentWcsAutoSort: '', // 当前托盘类型的wcsAutoSort值 |
|
|
|
|
|
currentMaxLayer: 0, // 当前托盘类型的最大层数,0=无限 |
|
|
|
|
|
|
|
|
// 筛选条件 |
|
|
// 筛选条件 |
|
|
selectedPosition: '', |
|
|
selectedPosition: '', |
|
|
selectedLayer: '', |
|
|
selectedLayer: '', |
|
|
@ -418,9 +453,9 @@ export default { |
|
|
|
|
|
|
|
|
// 运输任务模态框 |
|
|
// 运输任务模态框 |
|
|
transportModalVisible: false, |
|
|
transportModalVisible: false, |
|
|
transportStationOptions: [], |
|
|
|
|
|
|
|
|
transportAreaOptions: [], // 目标区域选项(从空闲站点中提取并去重) |
|
|
currentPalletStation: '', |
|
|
currentPalletStation: '', |
|
|
selectedTargetStation: '', |
|
|
|
|
|
|
|
|
selectedTargetArea: '', // 选择的目标区域 |
|
|
|
|
|
|
|
|
// Call栈板模态框 |
|
|
// Call栈板模态框 |
|
|
callPalletModalVisible: false, |
|
|
callPalletModalVisible: false, |
|
|
@ -437,6 +472,11 @@ export default { |
|
|
editLayerOptions: [], |
|
|
editLayerOptions: [], |
|
|
editOriginalPosition: '', |
|
|
editOriginalPosition: '', |
|
|
editOriginalLayer: '', |
|
|
editOriginalLayer: '', |
|
|
|
|
|
|
|
|
|
|
|
// 按钮loading状态(防止重复点击) |
|
|
|
|
|
editPositionLoading: false, // 修改位置按钮 |
|
|
|
|
|
transportTaskLoading: false, // 创建运输任务按钮 |
|
|
|
|
|
callPalletLoading: false, // Call栈板按钮 |
|
|
}; |
|
|
}; |
|
|
}, |
|
|
}, |
|
|
methods: { |
|
|
methods: { |
|
|
@ -458,6 +498,10 @@ export default { |
|
|
if (data.code === 0) { |
|
|
if (data.code === 0) { |
|
|
this.palletScanned = true; |
|
|
this.palletScanned = true; |
|
|
this.positionOptions = data.positions || []; |
|
|
this.positionOptions = data.positions || []; |
|
|
|
|
|
|
|
|
|
|
|
// 获取栈板详细信息(包括palletType和autoSort) |
|
|
|
|
|
this.loadPalletInfo(); |
|
|
|
|
|
|
|
|
this.refreshTable(); |
|
|
this.refreshTable(); |
|
|
} else { |
|
|
} else { |
|
|
this.$message.error(data.msg || '栈板不存在'); |
|
|
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栈板 - 调用空托盘 |
|
|
// Call栈板 - 调用空托盘 |
|
|
handleCallPallet() { |
|
|
handleCallPallet() { |
|
|
this.callPalletModalVisible = true; |
|
|
this.callPalletModalVisible = true; |
|
|
@ -530,12 +705,27 @@ export default { |
|
|
}).then(({ data }) => { |
|
|
}).then(({ data }) => { |
|
|
if (data.code === 0) { |
|
|
if (data.code === 0) { |
|
|
this.detailList = data.details || []; |
|
|
this.detailList = data.details || []; |
|
|
|
|
|
|
|
|
|
|
|
// 如果栈板有明细数据,禁用栈板类型和自动分拣的修改 |
|
|
|
|
|
const hasDetails = this.detailList.length > 0; |
|
|
|
|
|
this.palletTypeDisabled = hasDetails; |
|
|
|
|
|
|
|
|
|
|
|
// 如果有明细数据,自动分拣也要禁用;否则根据wcsAutoSort判断 |
|
|
|
|
|
if (hasDetails) { |
|
|
|
|
|
this.autoSortDisabled = true; |
|
|
|
|
|
} else { |
|
|
|
|
|
this.updateAutoSortControl(); |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
this.detailList = []; |
|
|
this.detailList = []; |
|
|
|
|
|
this.palletTypeDisabled = false; |
|
|
|
|
|
this.updateAutoSortControl(); |
|
|
} |
|
|
} |
|
|
}).catch(error => { |
|
|
}).catch(error => { |
|
|
console.error('获取栈板明细失败:', error); |
|
|
console.error('获取栈板明细失败:', error); |
|
|
this.detailList = []; |
|
|
this.detailList = []; |
|
|
|
|
|
this.palletTypeDisabled = false; |
|
|
|
|
|
this.updateAutoSortControl(); |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
@ -574,17 +764,29 @@ export default { |
|
|
// 扫码模态框中位置变化 |
|
|
// 扫码模态框中位置变化 |
|
|
handleScanPositionChange() { |
|
|
handleScanPositionChange() { |
|
|
if (this.scanPosition) { |
|
|
if (this.scanPosition) { |
|
|
|
|
|
// maxLayer=0表示混装托盘,只能选第1层 |
|
|
|
|
|
if (this.currentMaxLayer === 0) { |
|
|
|
|
|
this.scanLayerOptions = [1]; |
|
|
|
|
|
this.scanLayer = 1; // 自动选中第1层 |
|
|
|
|
|
this.moveFocusToScanInput(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// maxLayer>0,根据已有层数和maxLayer计算可选层数 |
|
|
getLayersByPosition({ |
|
|
getLayersByPosition({ |
|
|
site: this.site, |
|
|
site: this.site, |
|
|
palletId: this.palletCode, |
|
|
palletId: this.palletCode, |
|
|
position: this.scanPosition |
|
|
position: this.scanPosition |
|
|
}).then(({ data }) => { |
|
|
}).then(({ data }) => { |
|
|
if (data.code === 0) { |
|
|
if (data.code === 0) { |
|
|
const maxLayer = data.layers && data.layers.length > 0 |
|
|
|
|
|
|
|
|
const existingMaxLayer = data.layers && data.layers.length > 0 |
|
|
? Math.max(...data.layers) |
|
|
? Math.max(...data.layers) |
|
|
: 0; |
|
|
: 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 => { |
|
|
}).catch(error => { |
|
|
console.error('获取层数失败:', error); |
|
|
console.error('获取层数失败:', error); |
|
|
@ -673,6 +875,14 @@ export default { |
|
|
// 编辑位置选择变化 |
|
|
// 编辑位置选择变化 |
|
|
handleEditPositionChange() { |
|
|
handleEditPositionChange() { |
|
|
if (this.editPosition) { |
|
|
if (this.editPosition) { |
|
|
|
|
|
// maxLayer=0表示混装托盘,只能选第1层 |
|
|
|
|
|
if (this.currentMaxLayer === 0) { |
|
|
|
|
|
this.editLayerOptions = [1]; |
|
|
|
|
|
this.editLayer = 1; // 自动选中第1层 |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// maxLayer>0,根据已有层数和maxLayer计算可选层数 |
|
|
getLayersForEdit({ |
|
|
getLayersForEdit({ |
|
|
site: this.site, |
|
|
site: this.site, |
|
|
palletId: this.palletCode, |
|
|
palletId: this.palletCode, |
|
|
@ -680,7 +890,15 @@ export default { |
|
|
excludeSerialNo: this.editSerialNo |
|
|
excludeSerialNo: this.editSerialNo |
|
|
}).then(({ data }) => { |
|
|
}).then(({ data }) => { |
|
|
if (data.code === 0) { |
|
|
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)) { |
|
|
// if (!this.editLayerOptions.includes(this.editLayer)) { |
|
|
// this.editLayer = ''; |
|
|
// this.editLayer = ''; |
|
|
@ -713,6 +931,9 @@ export default { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 设置loading状态,防止重复点击 |
|
|
|
|
|
this.editPositionLoading = true; |
|
|
|
|
|
|
|
|
updatePalletDetailPosition({ |
|
|
updatePalletDetailPosition({ |
|
|
site: this.site, |
|
|
site: this.site, |
|
|
palletId: this.palletCode, |
|
|
palletId: this.palletCode, |
|
|
@ -730,6 +951,9 @@ export default { |
|
|
}).catch(error => { |
|
|
}).catch(error => { |
|
|
console.error('位置修改失败:', error); |
|
|
console.error('位置修改失败:', error); |
|
|
this.$message.error('位置修改失败'); |
|
|
this.$message.error('位置修改失败'); |
|
|
|
|
|
}).finally(() => { |
|
|
|
|
|
// 无论成功或失败,都要恢复按钮状态 |
|
|
|
|
|
this.editPositionLoading = false; |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
@ -765,14 +989,38 @@ export default { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.transportModalVisible = true; |
|
|
this.transportModalVisible = true; |
|
|
this.selectedTargetStation = ''; |
|
|
|
|
|
this.transportStationOptions = []; |
|
|
|
|
|
|
|
|
this.selectedTargetArea = ''; |
|
|
|
|
|
this.transportAreaOptions = []; |
|
|
|
|
|
|
|
|
// 获取所有AGV站点列表,只显示空闲站点(statusDb = 0) |
|
|
|
|
|
|
|
|
// 获取所有AGV站点列表,只显示空闲站点(statusDb = 0)的区域 |
|
|
getAgvStations({}).then(({ data }) => { |
|
|
getAgvStations({}).then(({ data }) => { |
|
|
if (data.code === 0) { |
|
|
if (data.code === 0) { |
|
|
// 过滤出statusDb为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 { |
|
|
} else { |
|
|
this.$message.error(data.msg || '获取站点列表失败'); |
|
|
this.$message.error(data.msg || '获取站点列表失败'); |
|
|
} |
|
|
} |
|
|
@ -795,22 +1043,19 @@ export default { |
|
|
this.$message.error('无法获取当前栈板位置'); |
|
|
this.$message.error('无法获取当前栈板位置'); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
if (!this.selectedTargetStation) { |
|
|
|
|
|
this.$message.error('请选择目标站点'); |
|
|
|
|
|
|
|
|
if (!this.selectedTargetArea) { |
|
|
|
|
|
this.$message.error('请选择目标区域'); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 前端验证:起始站点和目标站点不能一样 |
|
|
|
|
|
if (this.currentPalletStation === this.selectedTargetStation) { |
|
|
|
|
|
this.$message.error('起始站点和目标站点不能相同'); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 设置loading状态,防止重复点击 |
|
|
|
|
|
this.transportTaskLoading = true; |
|
|
|
|
|
|
|
|
// 调用包含组盘处理的接口 |
|
|
|
|
|
|
|
|
// 调用包含组盘处理的接口(后端会根据区域自动查找空闲站点) |
|
|
callPalletToStationWithUpdateZuPan({ |
|
|
callPalletToStationWithUpdateZuPan({ |
|
|
site: this.site, |
|
|
site: this.site, |
|
|
startStation: this.currentPalletStation, |
|
|
startStation: this.currentPalletStation, |
|
|
targetStation: this.selectedTargetStation |
|
|
|
|
|
|
|
|
targetArea: this.selectedTargetArea |
|
|
}).then(({ data }) => { |
|
|
}).then(({ data }) => { |
|
|
if (data.code === 0) { |
|
|
if (data.code === 0) { |
|
|
this.$message.success('栈板运输任务创建成功'); |
|
|
this.$message.success('栈板运输任务创建成功'); |
|
|
@ -823,6 +1068,9 @@ export default { |
|
|
}).catch(error => { |
|
|
}).catch(error => { |
|
|
console.error('创建运输任务失败:', error); |
|
|
console.error('创建运输任务失败:', error); |
|
|
this.$message.error('创建运输任务失败'); |
|
|
this.$message.error('创建运输任务失败'); |
|
|
|
|
|
}).finally(() => { |
|
|
|
|
|
// 无论成功或失败,都要恢复按钮状态 |
|
|
|
|
|
this.transportTaskLoading = false; |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
@ -830,8 +1078,8 @@ export default { |
|
|
closeTransportModal() { |
|
|
closeTransportModal() { |
|
|
this.transportModalVisible = false; |
|
|
this.transportModalVisible = false; |
|
|
this.currentPalletStation = ''; |
|
|
this.currentPalletStation = ''; |
|
|
this.selectedTargetStation = ''; |
|
|
|
|
|
this.transportStationOptions = []; |
|
|
|
|
|
|
|
|
this.selectedTargetArea = ''; |
|
|
|
|
|
this.transportAreaOptions = []; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
// 确认Call栈板 |
|
|
// 确认Call栈板 |
|
|
@ -851,6 +1099,9 @@ export default { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 设置loading状态,防止重复点击 |
|
|
|
|
|
this.callPalletLoading = true; |
|
|
|
|
|
|
|
|
callPalletToStation({ |
|
|
callPalletToStation({ |
|
|
site: this.site, |
|
|
site: this.site, |
|
|
startStation: this.selectedCallStartStation, |
|
|
startStation: this.selectedCallStartStation, |
|
|
@ -865,6 +1116,9 @@ export default { |
|
|
}).catch(error => { |
|
|
}).catch(error => { |
|
|
console.error('调用空托盘失败:', error); |
|
|
console.error('调用空托盘失败:', error); |
|
|
this.$message.error('异常:'+error); |
|
|
this.$message.error('异常:'+error); |
|
|
|
|
|
}).finally(() => { |
|
|
|
|
|
// 无论成功或失败,都要恢复按钮状态 |
|
|
|
|
|
this.callPalletLoading = false; |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
@ -930,13 +1184,9 @@ export default { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.col-serial { |
|
|
.col-serial { |
|
|
flex: 2; |
|
|
|
|
|
text-align: center; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.col-part { |
|
|
|
|
|
flex: 2; |
|
|
|
|
|
|
|
|
flex: 4; |
|
|
text-align: center; |
|
|
text-align: center; |
|
|
|
|
|
word-break: break-all; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* 空数据提示 */ |
|
|
/* 空数据提示 */ |
|
|
@ -1006,4 +1256,12 @@ export default { |
|
|
color: #999; |
|
|
color: #999; |
|
|
width: 100%; |
|
|
width: 100%; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 按钮禁用状态样式 */ |
|
|
|
|
|
.action-btn:disabled { |
|
|
|
|
|
opacity: 0.6; |
|
|
|
|
|
cursor: not-allowed; |
|
|
|
|
|
background-color: #ccc !important; |
|
|
|
|
|
border-color: #ccc !important; |
|
|
|
|
|
} |
|
|
</style> |
|
|
</style> |