fengshang_yangzhou/dev_wms_client/src/layout/goodsOut.vue
2025-10-18 21:10:09 +08:00

637 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-config-provider :locale="zhCn">
<el-container class="content">
<div class="work-area">
<fieldset class="search-area">
<el-form ref="outTaskRef" :model="outTaskEntity" :label-position="labelPosition" label-width="158px"
style="max-width: 100%" :rules="requestRules" status-icon>
<div style="display: flex; justify-content: space-between;">
<el-row>
<!-- <el-form-item label="出库类型" prop="outType">
<el-select-v2 style="width: 196px" v-model="outTaskEntity.outType" placeholder="请选择入库类型"
:options="outTypeOptions"></el-select-v2>
</el-form-item> -->
<el-form-item label="料号" prop="goodsId">
<el-input v-model="outTaskEntity.goodsId" @blur="getLackQty()" clearable/>
</el-form-item>
<el-form-item label="数量" prop="needNum">
<el-input-number style="width: 196px" v-model.number="outTaskEntity.needNum"
controls-position="right" :min="1" clearable/>
</el-form-item>
<el-form-item label="箱号" prop="vehicleId">
<el-input v-model="outTaskEntity.vehicleId" clearable/>
</el-form-item>
<el-form-item label="特殊库存" prop="specialStock">
<el-input v-model="outTaskEntity.specialStock" ref="specialStock" clearable/>
</el-form-item>
<el-form-item label="特殊库存号" prop="specialStockNo">
<el-input v-model="outTaskEntity.specialStockNo" ref="specialStockNo" clearable/>
</el-form-item>
<el-form-item label="特殊库存item号" prop="specialStockItemNo">
<el-input v-model="outTaskEntity.specialStockItemNo" ref="specialStockItemNo" clearable/>
</el-form-item>
<el-form-item label="批次号" prop="batchNo">
<el-input v-model="outTaskEntity.batchNo" ref="batchNo" clearable/>
</el-form-item>
<!-- <el-form-item label="原因" prop="reason" v-if="outTaskEntity.outType === 9">
<el-select-v2 style="width: 196px" v-model="outTaskEntity.reason" placeholder="请选择紧急出库原因"
:options="reasonOptions"></el-select-v2>
</el-form-item> -->
<el-form-item label="工单" prop="workOrder" v-if="outTaskEntity.reason === '缺料'">
<el-input v-model="outTaskEntity.workOrder" @blur="getLackQty()" clearable/>
</el-form-item>
</el-row>
<el-row>
<el-button type="primary"
style="height: 50px; width: 100px; margin: auto 5px auto 5px; font-size: large; color: black;"
@click="confirmOut()">确认出库
</el-button>
<el-button type="warning"
style="height: 50px; width: 100px; margin: auto 5px auto 5px; font-size: large; color: black;"
@click="clearInput()">清除输入
</el-button>
</el-row>
</div>
</el-form>
</fieldset>
<!-- 修改confirm-area为竖直布局表单项两两一排 -->
<!-- 修改confirm-area为竖直布局表单项两两一排 -->
<div style="display: flex; margin-top: 10px;">
<div v-for="(entity, index) in confirmEntities" :key="index" style="width: 32%; margin: 0 10px;">
<fieldset class="confirm-area">
<!-- 在这里添加站台ID显示 -->
<div style="text-align: center; font-size: 18px; font-weight: bold; margin-bottom: 0; color: #333;">
{{ getChildStandIdByIndex(index) }}
</div>
<el-form ref="confirmRef" :model="entity" :label-position="labelPosition" label-width="158px" style="max-width: 100%" :rules="confirmRules" status-icon>
<div style="display: flex; flex-wrap: wrap;">
<div style="width: 50%; display: flex; flex-direction: column;">
<el-form-item label="出库类型" prop="outType">
<el-select-v2 style="width: 196px" v-model="entity.outType" placeholder=" "
:options="outTypeOptions" disabled></el-select-v2>
</el-form-item>
<el-form-item label="特殊库存" prop="totalNeed" class="special-inventory-item">
<el-input v-model="entity.specialStock" disabled/>
</el-form-item>
<el-form-item label="特殊库存号" prop="totalNeed" class="special-inventory-item">
<el-input v-model="entity.specialStockNo" disabled/>
</el-form-item>
<el-form-item label="总需求" prop="totalNeed">
<el-input v-model="entity.totalNeed" disabled/>
</el-form-item>
<el-form-item label="本次计划拣选" prop="planPickQty">
<el-input v-model="entity.planPickQty" disabled/>
</el-form-item>
<el-form-item label="计划剩余数量" prop="planRemainQty">
<el-input v-model="entity.planRemainQty" disabled/>
</el-form-item>
<el-form-item label="箱号" prop="vehicleId">
<el-input v-model="entity.vehicleId" disabled/>
</el-form-item>
</div>
<div style="width: 50%; display: flex; flex-direction: column;">
<el-form-item label="物料号" prop="goodsId" class="special-inventory-item">
<el-input v-model="entity.goodsId" disabled/>
</el-form-item>
<el-form-item label="批次号" prop="remainNeed" class="special-inventory-item">
<el-input v-model="entity.batchNo" disabled/>
</el-form-item>
<el-form-item label="特殊库存item号" prop="remainNeed" class="special-inventory-item">
<el-input v-model="entity.specialStockItemNo" disabled/>
</el-form-item>
<el-form-item label="剩余需求" prop="remainNeed">
<el-input v-model="entity.remainNeed" disabled/>
</el-form-item>
<el-form-item label="本次实际拣选" prop="realPickQty">
<el-input-number style="width: 196px" v-model.number="entity.realPickQty"
controls-position="right" :min="0" clearable @change="() => changePlanQty(index)"/>
</el-form-item>
<el-form-item label="实际剩余数量" prop="realRemainQty">
<el-input-number style="width: 196px" v-model.number="entity.realRemainQty"
controls-position="right" :min="0" clearable/>
</el-form-item>
<el-form-item label="目标箱号" prop="vehicleId">
<el-input v-model="entity.containerNo"/>
</el-form-item>
</div>
<br>
</div>
<div style="display: flex; justify-content: center; gap: 80px; margin-top: 20px;">
<el-button type="success" style="height: 50px; width: 100px; margin: auto 5px auto 5px; font-size: large; color: black;"
@click="confirmOrRelease(index)">确认/放行
</el-button>
<!-- <el-button type="warning" style="height: 50px; width: 100px; margin: auto 5px auto 5px; font-size: large; color: black;"-->
<!-- @click="clearBox(index)">箱子置空-->
<!-- </el-button>-->
</div>
</el-form>
</fieldset>
</div>
</div>
</div>
</el-container>
</el-config-provider>
</template>
<script setup>
import store from '@/store'
import {requireStockOut, getCurrentTask, confirmCurrentTask, getGoodsLackQty} from '@/api/task.js'
import {errorBox, warningBox} from '@/utils/myMessageBox.js'
import {ElMessage} from 'element-plus'
import {nextTick, onBeforeUnmount, onMounted, reactive, ref, watch} from 'vue'
import {loading} from '@/utils/loading'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import {useRoute} from "vue-router";
import {labelPosition} from '@/constant/form'
const STAND_ID = store.getters.getStandId
const USER_NAME = store.getters.getUserName
let timer = ref()
let outTaskRef = ref()
let outTaskEntity = reactive({
outType: 9,
goodsId: '',
vehicleId: '',
reason: '',
workOrder: '',
needNum: null,
specialStock: '',
specialStockNo: '',
specialStockItemNo: '',
batchNo: ''
})
const requestRules = reactive({
outType: [
{required: true, message: '请选择入库类型'}
],
needNum: [
{required: true, message: '请输入数量'},
{type: 'number', message: '请输入数字值'}
],
})
const outTypeOptions = [
{
label: '空箱出库',
value: 1
},
{
label: '紧急出库',
value: 9
}
]
let confirmRef = ref()
let confirmEntities = reactive([
{
taskId: '',
outType: null,
goodsId: '',
totalNeed: null,
remainNeed: null,
planPickQty: null,
realPickQty: null,
stockId: '',
vehicleId: '',
planRemainQty: null,
realRemainQty: null,
isOut: null,
putArea: '',
warningQty: null,
containerNo: '',
specialStock: '',
specialStockNo: '',
batchNo: '',
specialStockItemNo: ''
},
{
taskId: '',
outType: null,
goodsId: '',
totalNeed: null,
remainNeed: null,
planPickQty: null,
realPickQty: null,
stockId: '',
vehicleId: '',
planRemainQty: null,
realRemainQty: null,
isOut: null,
putArea: '',
warningQty: null,
containerNo: '',
specialStock: '',
specialStockNo: '',
batchNo: '',
specialStockItemNo: ''
},
{
taskId: '',
outType: null,
goodsId: '',
totalNeed: null,
remainNeed: null,
planPickQty: null,
realPickQty: null,
stockId: '',
vehicleId: '',
planRemainQty: null,
realRemainQty: null,
isOut: null,
putArea: '',
warningQty: null,
containerNo: '',
specialStock: '',
specialStockNo: '',
batchNo: '',
specialStockItemNo: ''
}
])
const confirmRules = reactive({})
//let pauseGetPickFlag = ref(false)
let hasDataTaskResult = ref(false) // 记录上次请求是否有数据
const route = useRoute()// 路由
// 系统
onMounted(() => {
nextTick(() => {
startTimer() // 调用启动定时器函数
})
})
onBeforeUnmount(() => {
clearInterval(timer.value)
})
// 新增启动定时器的函数
const startTimer = () => {
clearInterval(timer.value) // 先清除已存在的定时器
timer.value = setInterval(() => {
timerTask_1()
}, 2000) // 默认2秒间隔
}
// 监视路由
// 修改 watch 中的定时器设置
watch(() => route.path, (newVal, oldVal) => {
if (newVal === '/goodsOut') {
startTimer() // 调用启动定时器函数
} else {
clearInterval(timer.value)
}
})
// 定时器任务1
const timerTask_1 = () => {
getTask()
}
// 获取拣选信息
const getTask = () => {
// if (pauseGetPickFlag.value) {
// return
// }
const request = {
standId: STAND_ID,
userName: USER_NAME
}
// 获取当前拣选信息
getCurrentTask(request).then(res => {
const response = res.data
console.log(response)
if (response.code === 0) {
// 有数据的情况
if (!hasDataTaskResult.value) {
// 从无数据切换到有数据,更改定时器频率
hasDataTaskResult.value = true
clearInterval(timer.value)
timer.value = setInterval(() => {
timerTask_1()
}, 10000) // 10秒间隔
}
const confirmVos = response.data
// 根据主站台ID确定需要显示的子站台顺序
let childStandOrder = []
if (STAND_ID === 'P1') {
childStandOrder = ['P13', 'P12', 'P11']
} else if (STAND_ID === 'P2') {
childStandOrder = ['P16', 'P15', 'P14']
} else if (STAND_ID === 'P3') {
childStandOrder = ['P19', 'P18', 'P17']
}
// 清空所有实体数据
confirmEntities.forEach(entity => {
clearEntityData(entity)
})
// 根据指定顺序将数据放在对应位置
childStandOrder.forEach((standId, index) => {
const found = confirmVos.find(item => item.childStandId === standId)
console.log("found=" + found)
// 如果没有找到匹配的数据,跳过当前循环
if (!found || index >= 3) { // 最多更新3个
return // 相当于continue
}
// 添加对taskConfirm和stockConfirm的检查
if (!found.taskConfirm || !found.stockConfirm) {
return // 如果taskConfirm或stockConfirm为null跳过当前循环
}
const entity = confirmEntities[index]
entity.taskId = found.taskConfirm.taskId || ''
entity.outType = found.taskConfirm.outType
entity.goodsId = found.taskConfirm.goodsId || ''
entity.totalNeed = found.taskConfirm.totalNeed
entity.remainNeed = found.taskConfirm.remainNeed
entity.planPickQty = found.taskConfirm.planPickQty
entity.realPickQty = found.taskConfirm.realPickQty
entity.stockId = found.stockConfirm.stockId || ''
entity.vehicleId = found.stockConfirm.vehicleId || ''
entity.planRemainQty = found.stockConfirm.planRemainQty
entity.realRemainQty = found.stockConfirm.realRemainQty
entity.isOut = found.stockConfirm.isOut
entity.putArea = found.stockConfirm.putArea || ''
entity.warningQty = found.stockConfirm.warningQty
entity.specialStock = found.stockConfirm.specialStock || ''
entity.specialStockNo = found.stockConfirm.specialStockNo || ''
entity.batchNo = found.stockConfirm.batchNo || ''
entity.specialStockItemNo = found.stockConfirm.specialStockItemNo || ''
// 如果剩余数量低于预警值,弹框报警
if (entity.isOut === 0 && entity.planRemainQty <= entity.warningQty) {
warningBox(`请注意!${found.childStandId}站台,剩余数量小于预警值,请检查并核对数量。`)
}
})
} else if (response.code === 400) {
// 无数据的情况
if (hasDataTaskResult.value) {
// 从有数据切换到无数据,更改定时器频率
hasDataTaskResult.value = false
clearInterval(timer.value)
timer.value = setInterval(() => {
timerTask_1()
}, 2000) // 2秒间隔
}
warningBox(response.message)
}
}).catch(err => {
console.log(err)
// 请求错误视为无数据情况
if (hasDataTaskResult.value) {
hasDataTaskResult.value = false
clearInterval(timer.value)
timer.value = setInterval(() => {
timerTask_1()
}, 2000) // 2秒间隔
}
errorBox('请求错误,请检查完原因后刷新界面。')
})
}
// 添加一个辅助函数来清空实体数据
const clearEntityData = (entity) => {
entity.taskId = ''
entity.outType = null
entity.goodsId = ''
entity.totalNeed = null
entity.remainNeed = null
entity.planPickQty = null
entity.realPickQty = null
entity.stockId = ''
entity.vehicleId = ''
entity.planRemainQty = null
entity.realRemainQty = null
entity.isOut = null
entity.putArea = ''
entity.warningQty = null
entity.containerNo = ''
}
// 清除输入
const clearInput = () => {
outTaskEntity.outType = 9
outTaskEntity.goodsId = ''
outTaskEntity.vehicleId = ''
outTaskEntity.needNum = null
outTaskEntity.specialStock = ''
outTaskEntity.specialStockNo = ''
outTaskEntity.batchNo = ''
outTaskEntity.specialStockItemNo = ''
}
// 确认出库
// 确认出库
const confirmOut = () => {
if (outTaskEntity.needNum == null) {
errorBox('请输入正确的数量。')
return
}
if (outTaskEntity.goodsId === '') {
errorBox('请输入料号。')
return
}
const request = {
// outType: outTaskEntity.outType,
goodsId: outTaskEntity.goodsId ? outTaskEntity.goodsId.toUpperCase().trim() : '',
vehicleId: outTaskEntity.vehicleId ? outTaskEntity.vehicleId.toUpperCase().trim() : '',
needNum: outTaskEntity.needNum,
// reason: outTaskEntity.reason,
workOrder: outTaskEntity.workOrder ? outTaskEntity.workOrder.trim() : '',
destination: STAND_ID,
userName: USER_NAME,
standId: STAND_ID,
specialStock: outTaskEntity.specialStock ? outTaskEntity.specialStock.toUpperCase().trim() : '',
specialStockNo: outTaskEntity.specialStockNo ? outTaskEntity.specialStockNo.toUpperCase().trim() : '',
specialStockItemNo: outTaskEntity.specialStockItemNo ? outTaskEntity.specialStockItemNo.toUpperCase().trim() : '',
batchNo: outTaskEntity.batchNo ? outTaskEntity.batchNo.toUpperCase().trim() : '',
}
loading.open('处理中...')
requireStockOut(request).then(res => {
const response = res.data
if (response.code === 0) {
// 成功
ElMessage.success(response.message)
clearInput()
} else {
errorBox(response.message)
}
}).catch(err => {
console.log(err)
errorBox('请求错误。')
}).finally(() => {
loading.close()
})
}
// 确认/放行
// 修改confirmOrRelease方法以支持索引
const confirmOrRelease = (index) => {
const entity = confirmEntities[index]
if (entity.containerNo === ""){
warningBox('目标箱号必填!')
return
}
// 确认放行---与配料工作区分开来
const request = {
taskConfirm: {
taskId: entity.taskId,
outType: entity.outType,
goodsId: entity.goodsId,
totalNeed: entity.totalNeed,
remainNeed: entity.remainNeed,
planPickQty: entity.planPickQty,
realPickQty: entity.realPickQty,
containerNo: entity.containerNo,
},
stockConfirm: {
stockId: entity.stockId,
vehicleId: entity.vehicleId,
goodsId: entity.goodsId,
planRemainQty: entity.planRemainQty,
realRemainQty: entity.realRemainQty,
isOut: entity.isOut,
putArea: entity.putArea,
},
standId: getChildStandIdByIndex(index),
userName: USER_NAME
}
loading.open('确认中...')
confirmCurrentTask(request, { timeout: 5000 }).then(res => {
const response = res.data
if (response.code === 0) {
clearConfirmEntity(index)
ElMessage.success(response.message)
// 确认后检查是否还有其他数据如果没有则切换回2秒间隔
setTimeout(() => {
// 这里可以触发一次检查,但不强制改变频率
getTask()
}, 100)
} else if (response.code === 400) {
warningBox(response.message)
} else {
// 错误,弹框
errorBox(response.message)
}
}).catch(err => {
console.log(err)
errorBox('请求错误,请检查完原因后刷新界面。')
}).finally(() => {
loading.close()
})
}
// 添加 clearConfirmEntity 方法来清空指定索引的实体数据
const clearConfirmEntity = (index) => {
if (index >= 0 && index < confirmEntities.length) {
clearEntityData(confirmEntities[index]); // 使用已有的 clearEntityData 方法
}
}
// 当拣选数量修改时,要对应的修改
// 修改changePlanQty方法以支持索引
const changePlanQty = (index) => {
const entity = confirmEntities[index]
if (entity.isOut === 0 && entity.realPickQty !== entity.planPickQty) {
// 修正实际剩余数量
entity.realRemainQty = entity.planRemainQty - entity.realPickQty + entity.planPickQty
}
}
// 获取对应工单对应物料号的缺料数量
const getLackQty = () => {
if (outTaskEntity.outType !== 9 || outTaskEntity.reason !== '缺料') {
// 非紧急出库且非缺料,则不处理
return;
}
if (outTaskEntity.workOrder === '' || outTaskEntity.goodsId === '') {
// 缺少工单号或者料号
return
}
// 设置请求参数,添加安全检查
const request = {
workOrder: outTaskEntity.workOrder ? outTaskEntity.workOrder.trim() : '',
goodsId: outTaskEntity.goodsId ? outTaskEntity.goodsId.toUpperCase().trim() : ''
}
loading.open('查询缺料缺料数量中...')
getGoodsLackQty(request).then(res => {
outTaskEntity.needNum = res.data
}).catch(err => {
// 异常,清空数量
outTaskEntity.needNum = null
console.log('获取缺料数量异常:' + err)
}).finally(() => {
loading.close()
})
}
// 根据索引获取子站台ID
const getChildStandIdByIndex = (index) => {
// 根据主站台ID确定需要显示的子站台顺序
let childStandOrder = []
if (STAND_ID === 'P1') {
childStandOrder = ['P13', 'P12', 'P11']
} else if (STAND_ID === 'P2') {
childStandOrder = ['P16', 'P15', 'P14']
} else if (STAND_ID === 'P3') {
childStandOrder = ['P19', 'P18', 'P17']
}
return childStandOrder[index] || ''
}
// 添加箱子置空方法
const clearBox = (index) => {
// 实现箱子置空逻辑
clearConfirmEntity(index)
}
</script>
<style scoped>
.content {
display: flex;
width: 100%;
}
.work-area {
width: 100%;
/* padding: 5px; */
}
.special-inventory-item :deep(.el-form-item__label) {
color: #ff8888;
font-weight: bold;
}
.search-area {
margin: auto;
min-height: fit-content;
max-height: 90%;
margin-bottom: 10px;
min-width: inherit;
border: solid 1px;
border-radius: 10px;
box-shadow: 0px 15px 10px -15px #000;
overflow: auto;
padding: 10px;
}
.confirm-area {
margin: auto;
min-height: fit-content;
max-height: 100%;
margin-bottom: 10px;
min-width: inherit;
border: solid 1px;
border-radius: 10px;
box-shadow: 0px 15px 10px -15px #000;
overflow: auto;
padding: 10px;
}
.el-form-item {
margin: 10px 5px 10px 5px;
}
.el-form-item .el-input {
width: 196px;
}
.table-class {
margin: 5px 5px 5px 5px;
width: inherit;
}
</style>