6 changed files with 733 additions and 20 deletions
-
6src/api/haianAutoWarehouse/palletChangeStation.js
-
1src/router/index.js
-
6src/views/main.vue
-
561src/views/modules/haianAutoWarehouse/haianPalletChangeStation.vue
-
98src/views/modules/haianAutoWarehouse/haianPalletPacking.vue
-
81src/views/modules/haianAutoWarehouse/haianPalletSorting.vue
@ -1,7 +1,13 @@ |
|||||
import { createAPI } from "@/utils/httpRequest.js"; |
import { createAPI } from "@/utils/httpRequest.js"; |
||||
|
|
||||
|
// 海安-检查栈板是否可执行换站(含calling_flag与当前站点)- rqrq
|
||||
|
export const checkPalletForChangeStation = data => createAPI(`/haiAnWcsIntegration/checkPalletForChangeStation`, 'post', data) |
||||
|
|
||||
// 海安-获取可选区域(choose_able=Y)- rqrq
|
// 海安-获取可选区域(choose_able=Y)- rqrq
|
||||
export const getAreaOptionsForChange = data => createAPI(`/haiAnWcsIntegration/getAreaOptionsForChange`, 'post', data) |
export const getAreaOptionsForChange = data => createAPI(`/haiAnWcsIntegration/getAreaOptionsForChange`, 'post', data) |
||||
|
|
||||
// 海安-按区域获取站点清单(locationCode/status)- rqrq
|
// 海安-按区域获取站点清单(locationCode/status)- rqrq
|
||||
export const getStationsByArea = data => createAPI(`/haiAnWcsIntegration/getStationsByArea`, 'post', data) |
export const getStationsByArea = data => createAPI(`/haiAnWcsIntegration/getStationsByArea`, 'post', data) |
||||
|
|
||||
|
// 海安-提交托盘运输任务(写haian_wms_order_task并调用立库搬运接口)- rqrq
|
||||
|
export const submitChangeStationTask = data => createAPI(`/haiAnWcsIntegration/submitChangeStationTask`, 'post', data) |
||||
@ -0,0 +1,561 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div class="pda-container"> |
||||
|
<!-- 头部栏 - rqrq --> |
||||
|
<div class="header-bar"> |
||||
|
<div class="header-left" @click="handleBack"> |
||||
|
<i class="el-icon-arrow-left"></i> |
||||
|
<span>栈板换站</span> |
||||
|
</div> |
||||
|
<div class="header-right" @click="$router.push({ path: '/' })"> |
||||
|
首页 |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="table-body" style="max-height: 600px; overflow-y: auto;"> |
||||
|
<div class="main-content form-section"> |
||||
|
<!-- 栈板扫描 - rqrq --> |
||||
|
<div class="input-group"> |
||||
|
<label class="input-label">托盘编码</label> |
||||
|
<el-input |
||||
|
v-model="palletCode" |
||||
|
placeholder="请扫描栈板编码" |
||||
|
class="form-input" |
||||
|
clearable |
||||
|
@keyup.enter.native="handlePalletScan" |
||||
|
inputmode="none" |
||||
|
autocomplete="off" |
||||
|
autocorrect="off" |
||||
|
spellcheck="false" |
||||
|
ref="palletInput" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 栈板信息显示(扫描栈板后显示)- rqrq --> |
||||
|
<div v-if="palletScanned" class="pallet-info-section"> |
||||
|
<!-- 当前站点信息 - rqrq --> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">当前站点ID:</label> |
||||
|
<span class="info-value">{{ palletInfo.currentStationId || '-' }}</span> |
||||
|
</div> |
||||
|
|
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">当前站点编码:</label> |
||||
|
<span class="info-value">{{ palletInfo.currentStationCode || '-' }}</span> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 浏览明细按钮 - rqrq --> |
||||
|
<div class="button-row"> |
||||
|
<button class="action-btn primary" @click="showDetailModal" style="width: 100%;"> |
||||
|
浏览明细 ({{ detailList.length }}条) |
||||
|
</button> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 选择区域和站点(只有栈板未被调用时才显示)- rqrq --> |
||||
|
<div v-if="palletInfo.callingFlag !== 'Y'" style="margin-top: 8px"> |
||||
|
<!-- 选择区域 - rqrq --> |
||||
|
<div class="input-group"> |
||||
|
<label class="input-label">选择区域</label> |
||||
|
<el-select |
||||
|
v-model="selectedArea" |
||||
|
placeholder="请选择区域" |
||||
|
style="width: 100%;" |
||||
|
@change="handleAreaChange" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="area in areaOptions" |
||||
|
:key="area.areaId" |
||||
|
:label="area.areaDesc" |
||||
|
:value="area.areaId" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 选择站点 - rqrq --> |
||||
|
<div class="input-group"> |
||||
|
<label class="input-label">选择站点</label> |
||||
|
<el-select |
||||
|
v-model="selectedStation" |
||||
|
placeholder="请选择站点" |
||||
|
style="width: 100%;" |
||||
|
:disabled="!selectedArea" |
||||
|
> |
||||
|
<el-option label="自动分配" value=""></el-option> |
||||
|
<el-option |
||||
|
v-for="station in stationOptions" |
||||
|
:key="station.stationId" |
||||
|
:label="`${station.stationId} (${station.stationCode})`" |
||||
|
:value="station.stationCode" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 操作按钮 - rqrq --> |
||||
|
<div class="button-row" style="display: flex; gap: 8px;"> |
||||
|
<button class="action-btn secondary" @click="handleReset" style="flex: 1;"> |
||||
|
重置 |
||||
|
</button> |
||||
|
<button |
||||
|
class="action-btn primary" |
||||
|
@click="handleSubmitTask" |
||||
|
:disabled="submitLoading" |
||||
|
style="flex: 1;"> |
||||
|
{{ submitLoading ? '下达中...' : '下达任务' }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 浏览明细弹窗 - rqrq --> |
||||
|
<el-dialog |
||||
|
:title="'栈板明细 (共' + detailList.length + '条)'" |
||||
|
:visible.sync="detailModalVisible" |
||||
|
width="90%" |
||||
|
:close-on-click-modal="false" |
||||
|
:show-close="false" |
||||
|
:modal="true" |
||||
|
:modal-append-to-body="true" |
||||
|
:append-to-body="true" |
||||
|
> |
||||
|
<div class="table-body" style="max-height: 400px; overflow-y: auto;"> |
||||
|
<div class="detail-table"> |
||||
|
<div class="table-header"> |
||||
|
<div class="col-position">位置</div> |
||||
|
<div class="col-layer">层数</div> |
||||
|
<div class="col-serial">标签号</div> |
||||
|
</div> |
||||
|
<div |
||||
|
v-for="(detail, index) in detailList" |
||||
|
:key="index" |
||||
|
class="table-row" |
||||
|
> |
||||
|
<div class="col-position">{{ detail.position }}</div> |
||||
|
<div class="col-layer">{{ detail.layer }}</div> |
||||
|
<div class="col-serial">{{ detail.serialNo }}</div> |
||||
|
</div> |
||||
|
<div v-if="detailList.length === 0" class="table-row empty-row"> |
||||
|
<div class="empty-hint">暂无栈板明细数据</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<button class="action-btn secondary" @click="detailModalVisible = false">关闭</button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { getPalletDetails } from '../../../api/haianAutoWarehouse/palletPacking' |
||||
|
import { |
||||
|
checkPalletForChangeStation, |
||||
|
getAreaOptionsForChange, |
||||
|
getStationsByArea, |
||||
|
submitChangeStationTask |
||||
|
} from '../../../api/haianAutoWarehouse/palletChangeStation' |
||||
|
|
||||
|
export default { |
||||
|
name: 'haianPalletChangeStation', |
||||
|
data() { |
||||
|
return { |
||||
|
// 栈板信息 - rqrq |
||||
|
palletCode: '', |
||||
|
palletScanned: false, |
||||
|
palletInfo: { |
||||
|
palletId: '', |
||||
|
callingFlag: '', |
||||
|
currentStationId: '', |
||||
|
currentStationCode: '' |
||||
|
}, |
||||
|
|
||||
|
// 区域和站点 - rqrq |
||||
|
selectedArea: '', |
||||
|
selectedStation: '', |
||||
|
areaOptions: [], |
||||
|
stationOptions: [], |
||||
|
|
||||
|
// 栈板明细 - rqrq |
||||
|
detailList: [], |
||||
|
detailModalVisible: false, |
||||
|
|
||||
|
// 加载状态 - rqrq |
||||
|
submitLoading: false |
||||
|
}; |
||||
|
}, |
||||
|
computed: { |
||||
|
// 海安页面site统一从store读取,保证和后端“site唯一来源”规则一致 - rqrq |
||||
|
site() { |
||||
|
const storeSite = this.$store.state.user.site |
||||
|
if (storeSite !== null && storeSite !== undefined && String(storeSite).trim() !== '') { |
||||
|
return String(storeSite).trim() |
||||
|
} |
||||
|
return (localStorage.getItem('site') || '').trim() |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
// 返回上一页 - rqrq |
||||
|
handleBack() { |
||||
|
this.resetPage(false); |
||||
|
this.$router.back(); |
||||
|
}, |
||||
|
|
||||
|
// 页面统一重置:退出/重进/手工重置都走同一逻辑,避免keep-alive残留状态 - rqrq |
||||
|
resetPage(needFocus = true) { |
||||
|
this.palletCode = ''; |
||||
|
this.palletScanned = false; |
||||
|
this.palletInfo = { |
||||
|
palletId: '', |
||||
|
callingFlag: '', |
||||
|
currentStationId: '', |
||||
|
currentStationCode: '' |
||||
|
}; |
||||
|
this.selectedArea = ''; |
||||
|
this.selectedStation = ''; |
||||
|
this.areaOptions = []; |
||||
|
this.stationOptions = []; |
||||
|
this.detailList = []; |
||||
|
this.detailModalVisible = false; |
||||
|
this.submitLoading = false; |
||||
|
if (needFocus) { |
||||
|
this.$nextTick(() => { |
||||
|
if (this.$refs.palletInput) { |
||||
|
this.$refs.palletInput.focus(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 扫描栈板 - rqrq |
||||
|
handlePalletScan() { |
||||
|
if (!this.site) { |
||||
|
this.$alert('当前用户缺少site,无法执行海安操作', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
if (!this.palletCode.trim()) { |
||||
|
this.$alert('请输入栈板编码', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
checkPalletForChangeStation({ |
||||
|
site: this.site, |
||||
|
palletId: this.palletCode |
||||
|
}).then(({ data }) => { |
||||
|
if (data && data.code === 0 && data.row) { |
||||
|
// 后端返回标准化后的栈板码,回填输入框避免R/L后缀重复扫描 - rqrq |
||||
|
this.palletCode = data.row.palletId; |
||||
|
|
||||
|
// 如果栈板被调用,提示并清空 - rqrq |
||||
|
if (data.row.callingFlag === 'Y') { |
||||
|
this.$alert('栈板被调用,请选择其他栈板', '提示', { |
||||
|
confirmButtonText: '确定', |
||||
|
callback: () => { |
||||
|
this.resetPage(true); |
||||
|
} |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 栈板未被调用,显示信息并加载区域选项 - rqrq |
||||
|
this.palletInfo = data.row; |
||||
|
this.palletScanned = true; |
||||
|
|
||||
|
// 加载栈板明细 - rqrq |
||||
|
this.loadPalletDetails(); |
||||
|
|
||||
|
// 加载区域选项 - rqrq |
||||
|
this.loadAreaOptions(); |
||||
|
} else { |
||||
|
this.$alert((data && data.msg) || '栈板不存在', '错误', { |
||||
|
confirmButtonText: '确定', |
||||
|
callback: () => { |
||||
|
this.resetPage(true); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('查询栈板失败:', error); |
||||
|
this.$alert((error && error.message) || '查询栈板失败', '错误', { |
||||
|
confirmButtonText: '确定', |
||||
|
callback: () => { |
||||
|
this.resetPage(true); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 加载栈板明细 - rqrq |
||||
|
loadPalletDetails() { |
||||
|
getPalletDetails({ |
||||
|
site: this.site, |
||||
|
palletId: this.palletCode, |
||||
|
position: '', |
||||
|
layer: '' |
||||
|
}).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
this.detailList = data.details || []; |
||||
|
} else { |
||||
|
this.detailList = []; |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('获取栈板明细失败:', error); |
||||
|
this.detailList = []; |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 显示明细弹窗 - rqrq |
||||
|
showDetailModal() { |
||||
|
this.detailModalVisible = true; |
||||
|
}, |
||||
|
|
||||
|
// 加载区域选项 - rqrq |
||||
|
loadAreaOptions() { |
||||
|
getAreaOptionsForChange({ |
||||
|
site: this.site |
||||
|
}).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
// 与老页面保持一致:过滤Z199,避免误投特殊区域 - rqrq |
||||
|
const allOptions = data.rows || []; |
||||
|
this.areaOptions = allOptions.filter(area => area.areaId !== 'Z199'); |
||||
|
} else { |
||||
|
this.areaOptions = []; |
||||
|
this.$alert('获取区域选项失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('获取区域选项失败:', error); |
||||
|
this.areaOptions = []; |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 区域变化 - rqrq |
||||
|
handleAreaChange(areaId) { |
||||
|
this.selectedStation = ''; |
||||
|
this.stationOptions = []; |
||||
|
|
||||
|
if (!areaId) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 选择区域后调用海安站点接口,返回locationCode/status结构 - rqrq |
||||
|
getStationsByArea({ |
||||
|
site: this.site, |
||||
|
areaId: areaId |
||||
|
}).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
this.stationOptions = data.rows || []; |
||||
|
} else { |
||||
|
this.stationOptions = []; |
||||
|
this.$alert('获取站点选项失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('获取站点选项失败:', error); |
||||
|
this.stationOptions = []; |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 重置 - rqrq |
||||
|
handleReset() { |
||||
|
this.resetPage(true); |
||||
|
}, |
||||
|
|
||||
|
// 下达任务 - rqrq |
||||
|
handleSubmitTask() { |
||||
|
if (!this.site) { |
||||
|
this.$alert('当前用户缺少site,无法下达任务', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
if (!this.palletInfo.currentStationCode) { |
||||
|
this.$alert('当前站点编码不能为空', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
if (!this.selectedArea) { |
||||
|
this.$alert('请选择目标区域', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const params = { |
||||
|
site: this.site, |
||||
|
palletId: this.palletCode, |
||||
|
startStation: this.palletInfo.currentStationCode, |
||||
|
targetArea: this.selectedArea, |
||||
|
targetStation: this.selectedStation || '' // 空表示自动分配 - rqrq |
||||
|
}; |
||||
|
|
||||
|
this.$confirm('确定下达任务?', '提示', { |
||||
|
confirmButtonText: '确认', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning' |
||||
|
}).then(() => { |
||||
|
this.submitLoading = true; |
||||
|
submitChangeStationTask(params).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
this.$message.success('任务下达成功'); |
||||
|
this.resetPage(true); |
||||
|
} else { |
||||
|
this.$alert((data && data.msg) || '任务下达失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('任务下达失败:', error); |
||||
|
this.$alert((error && error.message) || '任务下达失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
}).finally(() => { |
||||
|
this.submitLoading = false; |
||||
|
}); |
||||
|
}).catch(() => { |
||||
|
// 用户取消下达时不做额外动作,保持当前选择便于复核 - rqrq |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
// keep-alive重进统一清理,避免历史扫描数据残留 - rqrq |
||||
|
activated() { |
||||
|
this.resetPage(true); |
||||
|
}, |
||||
|
// 离开页面时清理内存态,确保再次进入是干净页面 - rqrq |
||||
|
beforeRouteLeave(to, from, next) { |
||||
|
this.resetPage(false); |
||||
|
next(); |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.resetPage(true); |
||||
|
} |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 栈板信息区域 - rqrq */ |
||||
|
.pallet-info-section { |
||||
|
margin-top: 16px; |
||||
|
padding: 12px; |
||||
|
background: #f5f7fa; |
||||
|
border-radius: 6px; |
||||
|
} |
||||
|
|
||||
|
.info-row { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 8px 0; |
||||
|
border-bottom: 1px solid #e4e7ed; |
||||
|
} |
||||
|
|
||||
|
.info-row:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
.info-label { |
||||
|
font-weight: bold; |
||||
|
color: #606266; |
||||
|
width: 120px; |
||||
|
flex-shrink: 0; |
||||
|
} |
||||
|
|
||||
|
.info-value { |
||||
|
color: #303133; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.button-row { |
||||
|
margin-top: 12px; |
||||
|
} |
||||
|
|
||||
|
/* 表格样式 - rqrq */ |
||||
|
.detail-table { |
||||
|
background: white; |
||||
|
border-radius: 6px; |
||||
|
overflow: hidden; |
||||
|
border: 1px solid #e0e0e0; |
||||
|
} |
||||
|
|
||||
|
.table-header, |
||||
|
.table-row { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 8px; |
||||
|
border-bottom: 1px solid #e0e0e0; |
||||
|
} |
||||
|
|
||||
|
.table-header { |
||||
|
background: #f5f5f5; |
||||
|
font-weight: bold; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.table-row { |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
.table-row:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
.col-position { |
||||
|
flex: 1; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.col-layer { |
||||
|
flex: 1; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.col-serial { |
||||
|
flex: 4; |
||||
|
text-align: center; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
|
||||
|
/* 空数据提示 - rqrq */ |
||||
|
.empty-hint { |
||||
|
text-align: center; |
||||
|
color: #999; |
||||
|
padding: 20px; |
||||
|
background: white; |
||||
|
border-radius: 6px; |
||||
|
} |
||||
|
|
||||
|
.dialog-footer { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
/* 修复模态框层级问题 - rqrq */ |
||||
|
::v-deep .el-dialog__wrapper { |
||||
|
z-index: 2000 !important; |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-overlay { |
||||
|
z-index: 2000 !important; |
||||
|
} |
||||
|
|
||||
|
/* 空数据行样式 - rqrq */ |
||||
|
.empty-row { |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
padding: 20px; |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
.empty-row .empty-hint { |
||||
|
text-align: center; |
||||
|
color: #999; |
||||
|
width: 100%; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue