797 lines
26 KiB
Vue
797 lines
26 KiB
Vue
<template>
|
||
<div class="card modern-card">
|
||
<div style="display: flex; justify-content: flex-end; margin-bottom: 12px;position: relative;">
|
||
<div v-if="currentPartitionName"
|
||
style="position: absolute; left: 10px; top: 10px; font-size: .8rem; color: #409EFF; font-weight: bold; letter-spacing: 1px;">
|
||
{{ currentPartitionName }}
|
||
</div>
|
||
<el-button type="primary" @click="onReturnPalletClick">退空托盘</el-button>
|
||
</div>
|
||
<div class="storList">
|
||
<div class="storList-item modern-item" v-for="item in opStoreData" :key="item.StockCode"
|
||
@click="handleClick(item)">
|
||
<div class="storList-header">
|
||
<span class="storList-title">{{ item.StockName }}</span>
|
||
<div class="storList-tags">
|
||
<van-tag type="danger" v-if="item.TaskId != null">任务中</van-tag>
|
||
<van-tag type="primary" v-if="item.StockStatus == false && !item.TrayNo">空库位</van-tag>
|
||
<van-tag type="warning" v-if="item.StockStatus == false && item.TrayNo">空托盘</van-tag>
|
||
<van-tag type="success" v-if="item.StockStatus == true">满料</van-tag>
|
||
</div>
|
||
</div>
|
||
<div class="storList-info">
|
||
<span><i class="iconfont icon-project"></i> 项目名称:<b>{{ item.ProjectNo }}</b></span>
|
||
<span><i class="iconfont icon-product"></i> 间隔编号:<b>{{ item.IntervalNo }}</b></span>
|
||
<span><i class="iconfont icon-model"></i> 部件位置:<b>{{ item.ComponentLocation }}</b></span>
|
||
<span><i class="iconfont icon-tuopan"></i> 托盘编号:<b>{{ item.TrayNo }}</b></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<el-dialog v-model="showStockDialog" :title="stockDialogTitle" width="400px" :close-on-click-modal="false"
|
||
@close="onStockDialogClose">
|
||
<div v-if="stockList.length > 0">
|
||
<div v-for="item in stockList" :key="item.code" @click="onStockSelect(item)"
|
||
style="cursor:pointer; border-bottom:1px solid #eee; padding:12px 0;">
|
||
<div style="display:flex;flex-direction:column;">
|
||
<span><b>库位名称:</b>{{ item.name }}</span>
|
||
<span><b>项目名称:</b>{{ item.ProjectNo }}</span>
|
||
<span><b>间隔编号:</b>{{ item.IntervalNo }}</span>
|
||
<span><b>部件位置:</b>{{ item.ComponentLocation }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-else style="text-align:center;color:#888;">暂无可用库位</div>
|
||
</el-dialog>
|
||
<van-action-sheet v-model:show="showActionSheet" :actions="actionList" @select="onActionSelect" title="请选择操作" />
|
||
<van-action-sheet v-model:show="showCallMaterialSheet" :actions="callMaterialActions" @select="onCallMaterialSelect"
|
||
title="请选择操作" />
|
||
<van-action-sheet v-model:show="showReturnMaterialSheet" :actions="returnMaterialActions"
|
||
@select="onReturnMaterialSelect" title="请选择操作" />
|
||
<el-dialog v-model="showInputDialog" title="物料验证" width="320px" :close-on-click-modal="false"
|
||
@close="onInputCancel">
|
||
<el-form @submit.prevent>
|
||
<el-form-item label="产品图号">
|
||
<el-input v-model="MaterialData.SortNo" disabled clearable autofocus @keyup.enter="onInputConfirm" />
|
||
</el-form-item>
|
||
<el-form-item label="产品编号">
|
||
<el-input v-model="inputValue" placeholder="请扫描物料编号" clearable autofocus @input="onInputChange"
|
||
@keyup.enter="onInputConfirm" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="onInputCancel">取消</el-button>
|
||
<el-button type="primary" @click="onInputConfirm">校验</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
<el-dialog v-model="showReturnPalletDialog" title="退空托盘" width="320px" :close-on-click-modal="false"
|
||
@close="onReturnPalletCancel">
|
||
<el-form @submit.prevent>
|
||
<el-form-item label="托盘码">
|
||
<el-input v-model="returnPalletCode" placeholder="请扫描托盘码" clearable autofocus
|
||
@keyup.enter="onReturnPalletConfirm" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="onReturnPalletCancel">取消</el-button>
|
||
<el-button type="primary" @click="onReturnPalletConfirm">校验</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { v4 as uuidv4 } from 'uuid'
|
||
import { inject, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||
import { storeToRefs } from 'pinia'
|
||
import { useAppStore } from '@/store/app.js'
|
||
import { Dialog, ActionSheet, Toast } from 'vant'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
const store = useAppStore()
|
||
const { user } = storeToRefs(store)
|
||
|
||
const ExecDatabaseByParam = inject('ExecDatabaseByParam')
|
||
const ExecAgvApi = inject('ExecAgvApi')
|
||
|
||
const opStoreCode = ref(-1)
|
||
|
||
// 补充定义 stockList
|
||
const stockList = ref([])
|
||
|
||
// 添加 selectedStock 定义
|
||
const selectedStock = ref(null)
|
||
|
||
// StockCode 库位编号
|
||
// StockName 库位名称
|
||
// StockStatus 满料状态 bool
|
||
// TrayNo 托盘号
|
||
// IntervalNo 间隔号
|
||
// ComponentLocation 组件位置
|
||
// TaskId 任务号
|
||
const opStoreData = reactive([])
|
||
// 库区列表
|
||
const partitionList = reactive([])
|
||
|
||
// 物料验证相关数据
|
||
const MaterialData = reactive({})
|
||
|
||
// 目标库区数据
|
||
const targetPartition = reactive({
|
||
callMaterial: null, // 叫料库区
|
||
returnMaterial: null, // 退料库区
|
||
returnPallet: null // 退空托库区
|
||
})
|
||
|
||
// 库位选择数据
|
||
const showStockDialog = ref(false)
|
||
const stockDialogTitle = ref('')
|
||
|
||
const showActionSheet = ref(false)
|
||
const actionList = [
|
||
{ name: '退料' }
|
||
]
|
||
const currentItem = ref(null)
|
||
|
||
const showInputDialog = ref(false)
|
||
const inputValue = ref('')
|
||
|
||
const showReturnPalletDialog = ref(false)
|
||
const returnPalletCode = ref('')
|
||
const returnPalletStock = ref(null)
|
||
|
||
// 叫料相关数据
|
||
const showCallMaterialSheet = ref(false)
|
||
const callMaterialActions = [
|
||
{ name: '叫料' }
|
||
]
|
||
|
||
// 叫料选择处理
|
||
const onCallMaterialSelect = async (action) => {
|
||
showCallMaterialSheet.value = false
|
||
if (action.name === '叫料') {
|
||
// 获取叫料目标库区
|
||
const routes = await getRoutePartitions(currentItem.value.StockCode)
|
||
if (!routes || !routes.callMaterial) {
|
||
ElMessage.warning('未配置叫料路线,请联系管理员')
|
||
return
|
||
}
|
||
|
||
// 记录目标库区
|
||
targetPartition.callMaterial = routes.callMaterial
|
||
|
||
// 根据目标库区获取库位列表
|
||
const stockRes = await ExecAgvApi('getStockList', { PartitionCode: targetPartition.callMaterial })
|
||
if (!stockRes.Result) {
|
||
ElMessage.error(stockRes.ErrMsg || '获取库位失败')
|
||
return
|
||
}
|
||
|
||
// 叫料流程:只显示满料库位,排除"无库位"
|
||
stockList.value = (stockRes.Data || [])
|
||
.filter(i => i.StockStatus === true && i.StockName !== '无库位')
|
||
.map(i => ({ name: i.StockName, code: i.StockCode, ...i }))
|
||
|
||
if (stockList.value.length === 0) {
|
||
ElMessage.warning('目标库区没有满料库位')
|
||
return
|
||
}
|
||
|
||
// 设置叫料流程标识
|
||
isCallMaterialFlow.value = true
|
||
stockDialogTitle.value = await getPartitionName(targetPartition.callMaterial)
|
||
showStockDialog.value = true
|
||
}
|
||
}
|
||
|
||
const isCallMaterialFlow = ref(false)
|
||
const currentPartitionName = ref('')
|
||
|
||
// 退料相关数据
|
||
const showReturnMaterialSheet = ref(false)
|
||
const returnMaterialActions = [
|
||
{ name: '物料验证' },
|
||
{ name: '退料' }
|
||
]
|
||
|
||
// 退料选择处理
|
||
const onReturnMaterialSelect = async (action) => {
|
||
showReturnMaterialSheet.value = false
|
||
if (action.name === '物料验证') {
|
||
inputValue.value = ''
|
||
showInputDialog.value = true
|
||
// 将当前物料信息赋值到验证数据
|
||
Object.assign(MaterialData, currentItem.value)
|
||
return
|
||
}
|
||
|
||
if (action.name === '退料') {
|
||
// 获取退料目标库区
|
||
const routes = await getRoutePartitions(currentItem.value.StockCode)
|
||
if (!routes || !routes.returnMaterial) {
|
||
ElMessage.warning('未配置退料路线,请联系管理员')
|
||
return
|
||
}
|
||
|
||
// 记录目标库区
|
||
targetPartition.returnMaterial = routes.returnMaterial
|
||
|
||
// 根据目标库区获取库位列表
|
||
const stockRes = await ExecAgvApi('getStockList', { PartitionCode: targetPartition.returnMaterial })
|
||
if (!stockRes.Result) {
|
||
ElMessage.error(stockRes.ErrMsg || '获取库位失败')
|
||
return
|
||
}
|
||
|
||
// 退料流程:只显示空库位(无托盘且状态为空)
|
||
stockList.value = stockRes.Data
|
||
.filter(i => !i.PalletCode && i.StockStatus === false)
|
||
.map(i => ({ name: i.StockName, code: i.StockCode, ...i }))
|
||
|
||
if (stockList.value.length === 0) {
|
||
ElMessage.warning('目标库区没有可用空库位')
|
||
return
|
||
}
|
||
|
||
// 设置退料流程标识
|
||
isReturnMaterialFlow.value = true
|
||
stockDialogTitle.value = await getPartitionName(targetPartition.returnMaterial)
|
||
showStockDialog.value = true
|
||
}
|
||
}
|
||
|
||
const isReturnMaterialFlow = ref(false)
|
||
|
||
// 获取预设路线库区信息
|
||
const getRoutePartitions = async (stockCode) => {
|
||
try {
|
||
const res = await ExecDatabaseByParam('11', 'PTCHV_AGV_送料路线_PDA查询_初始化', [['库位号', stockCode]])
|
||
if (res.data && res.data.length > 0) {
|
||
return {
|
||
callMaterial: res.data[0].叫料库区,
|
||
returnMaterial: res.data[0].退料库区,
|
||
returnPallet: res.data[0].退空托库区
|
||
}
|
||
} else {
|
||
ElMessage.warning('未找到预设的路线信息')
|
||
return null
|
||
}
|
||
} catch (error) {
|
||
console.error('获取路线信息失败:', error)
|
||
ElMessage.error('获取路线信息失败')
|
||
return null
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await getPartitionList()
|
||
await getOpStoreCode()
|
||
})
|
||
const getPartitionList = async () => {
|
||
let res = await ExecDatabaseByParam('11', 'MES_计划BOM_工位与名称_库位编号_查询', [['工位号', user.value.opName]])
|
||
if (res.data.length > 0) {
|
||
// 处理库区编号,可能会返回多个库区,如 "7,14"
|
||
const partitionCodes = res.data[0].库位编号.toString().split(',').map(code => code.trim())
|
||
opStoreCode.value = partitionCodes[0] // 保存第一个库区编号作为主库区
|
||
|
||
// 查找库区名称
|
||
partitionList.length = 0
|
||
const partitionRes = await ExecAgvApi('getPartitionList', {})
|
||
if (partitionRes.Result) {
|
||
partitionList.push(...partitionRes.Data)
|
||
currentPartitionName.value = await getPartitionName(opStoreCode.value)
|
||
}
|
||
} else {
|
||
ElMessage.warning('此工位无对应库位!')
|
||
}
|
||
}
|
||
|
||
// 获取对应库位编号名称
|
||
const getPartitionName = async (partitionCode) => {
|
||
const found = partitionList.find(i => i.PartitionCode == partitionCode)
|
||
return found ? found.PartitionName : ''
|
||
}
|
||
|
||
const getOpStoreCode = async () => {
|
||
// 获取MES_计划BOM_工位与名称_库位编号_查询返回的所有库区编号
|
||
const res = await ExecDatabaseByParam('11', 'MES_计划BOM_工位与名称_库位编号_查询', [['工位号', user.value.opName]])
|
||
if (res.data.length === 0) {
|
||
ElMessage.warning('此工位无对应库位!')
|
||
return
|
||
}
|
||
|
||
// 清空现有数据
|
||
opStoreData.length = 0
|
||
|
||
// 处理可能有多个库区编号的情况(如 "7,14")
|
||
const partitionCodes = res.data[0].库位编号.toString().split(',').map(code => code.trim())
|
||
|
||
// 依次查询每个库区的库位信息并合并
|
||
for (const partitionCode of partitionCodes) {
|
||
const agvPar = {
|
||
"PartitionCode": partitionCode
|
||
}
|
||
const agvRes = await ExecAgvApi('getStockList', agvPar)
|
||
|
||
if (agvRes.Result) {
|
||
// 将查询到的库位信息添加到列表中,过滤"无库位"
|
||
const filteredData = (agvRes.Data || []).filter(item => item.StockName !== '无库位')
|
||
opStoreData.push(...filteredData)
|
||
} else {
|
||
ElMessage.error(`获取库区${partitionCode}信息失败: ${agvRes.ErrMsg}`)
|
||
}
|
||
}
|
||
|
||
// 如果没有任何库位信息
|
||
if (opStoreData.length === 0) {
|
||
ElMessage.error('未获取到任何库位信息')
|
||
}
|
||
}
|
||
|
||
const handleClick = async (item) => {
|
||
if (item.TaskId != null) {
|
||
Dialog.alert({
|
||
title: '提示',
|
||
message: '该库位存在任务,不可操作',
|
||
})
|
||
return
|
||
}
|
||
// 满料库位:退料流程
|
||
if (item.StockStatus === true) {
|
||
currentItem.value = item
|
||
showReturnMaterialSheet.value = true
|
||
return
|
||
}
|
||
// 空托盘:退空托盘流程
|
||
if (item.StockStatus === false && item.TrayNo) {
|
||
currentItem.value = item
|
||
showActionSheet.value = true
|
||
return
|
||
}
|
||
// 空库位:叫料流程
|
||
if (item.StockStatus === false && !item.TrayNo) {
|
||
currentItem.value = item
|
||
showCallMaterialSheet.value = true
|
||
return
|
||
}
|
||
}
|
||
|
||
// 选择库位后的处理
|
||
const onStockItemClick = (item) => {
|
||
// 二次确认
|
||
|
||
}
|
||
|
||
const onStockDialogClose = () => {
|
||
showStockDialog.value = false
|
||
}
|
||
|
||
const onStockSelect = async (stock) => {
|
||
selectedStock.value = stock
|
||
showStockDialog.value = false
|
||
|
||
if (isCallMaterialFlow.value) {
|
||
// 获取目标库区名称
|
||
const partitionName = await getPartitionName(targetPartition.callMaterial)
|
||
|
||
// 叫料流程确认
|
||
ElMessageBox.confirm(`是否将物料 从库位【${stock.name}】送至库位【${currentItem.value.StockName}】?`, '确认叫料', {
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(async () => {
|
||
const taskId = uuidv4()
|
||
const res = await ExecAgvApi('createTask', {
|
||
taskId,
|
||
pickPosition: stock.code,
|
||
dropPosition: currentItem.value.StockCode,
|
||
})
|
||
if (res.Result) {
|
||
await ExecDatabaseByParam('12', 'PTCHV_AGV_送料记录_增加', [
|
||
['任务号', taskId],
|
||
['取料库位', stock.code],
|
||
['取料库位名称', stock.name],
|
||
['取料项目名称', stock.ProjectNo || ''],
|
||
['取料间隔编号', stock.IntervalNo || ''],
|
||
['取料部件位置', stock.ComponentLocation || ''],
|
||
['取料托盘编号', stock.TrayNo || ''],
|
||
['送料库位', currentItem.value.StockCode],
|
||
['送料库位名称', currentItem.value.StockName],
|
||
['操作人', user.value.name],
|
||
['type', 1],
|
||
])
|
||
ElMessage.success('叫料任务创建成功')
|
||
getOpStoreCode()
|
||
} else {
|
||
ElMessage.error(res.ErrMsg || '叫料任务创建失败')
|
||
}
|
||
isCallMaterialFlow.value = false
|
||
})
|
||
} else if (isReturnMaterialFlow.value) {
|
||
// 获取目标库区名称
|
||
const partitionName = await getPartitionName(targetPartition.returnMaterial)
|
||
|
||
// 退料流程确认
|
||
Dialog.confirm({
|
||
title: '确认退料',
|
||
message: `是否将物料退至库位【${stock.name}】?`,
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
}).then(async () => {
|
||
const taskId = uuidv4()
|
||
const res = await ExecAgvApi('createTask', {
|
||
taskId,
|
||
pickPosition: currentItem.value.StockCode,
|
||
dropPosition: stock.code,
|
||
})
|
||
if (res.Result) {
|
||
await ExecDatabaseByParam('12', 'PTCHV_AGV_送料记录_增加', [
|
||
['任务号', taskId],
|
||
['取料库位', currentItem.value.StockCode],
|
||
['取料库位名称', currentItem.value.StockName],
|
||
['取料项目名称', currentItem.value.ProjectNo || ''],
|
||
['取料间隔编号', currentItem.value.IntervalNo || ''],
|
||
['取料部件位置', currentItem.value.ComponentLocation || ''],
|
||
['取料托盘编号', currentItem.value.TrayNo || ''],
|
||
['送料库位', stock.code],
|
||
['送料库位名称', stock.name],
|
||
['操作人', user.value.name],
|
||
['type', 2],
|
||
])
|
||
ElMessage.success('退料任务创建成功')
|
||
getOpStoreCode()
|
||
} else {
|
||
ElMessage.error(res.ErrMsg || '退料任务创建失败')
|
||
}
|
||
isReturnMaterialFlow.value = false
|
||
}).catch(() => {
|
||
isReturnMaterialFlow.value = false
|
||
})
|
||
} else if (isReturnPalletFlow.value) {
|
||
// 获取目标库区名称
|
||
const partitionName = await getPartitionName(targetPartition.returnPallet)
|
||
|
||
// 退空托盘流程确认
|
||
Dialog.confirm({
|
||
title: '确认退空托盘',
|
||
message: `是否将空托盘退至 库位【${stock.name}】?`,
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
}).then(async () => {
|
||
// 先更新库位信息
|
||
const oldTrayNo = returnPalletStock.value.TrayNo || ''
|
||
const oldIntervalNo = returnPalletStock.value.IntervalNo || ''
|
||
const oldComponentLocation = returnPalletStock.value.ComponentLocation || ''
|
||
const stockName = returnPalletStock.value.StockName || ''
|
||
|
||
const updateRes = await ExecAgvApi('updateStockInfo', {
|
||
StockCode: returnPalletStock.value.StockCode,
|
||
StockStatus: false,
|
||
TrayNo: oldTrayNo,
|
||
ProjectNo: null,
|
||
IntervalNo: null,
|
||
ComponentLocation: null,
|
||
TaskId: returnPalletStock.value.TaskId
|
||
})
|
||
|
||
if (!updateRes.Result) {
|
||
ElMessage.error(updateRes.ErrMsg || '库位信息更新失败')
|
||
return
|
||
}
|
||
|
||
await ExecDatabaseByParam('12', 'PTCHV_AGV_库位更新记录_增加', [
|
||
['库位号', returnPalletStock.value.StockCode],
|
||
['库位名称', stockName],
|
||
['项目', ''],
|
||
['间隔号', ''],
|
||
['组件位置', ''],
|
||
['托盘号', oldTrayNo],
|
||
['项目_old', ''],
|
||
['间隔号_old', oldIntervalNo],
|
||
['组件位置_old', oldComponentLocation],
|
||
['托盘号_old', oldTrayNo],
|
||
['操作人', user.value.name],
|
||
['type', 2],
|
||
])
|
||
|
||
// 创建退空托盘任务
|
||
const taskId = uuidv4()
|
||
const res = await ExecAgvApi('createTask', {
|
||
taskId,
|
||
pickPosition: returnPalletStock.value.StockCode,
|
||
dropPosition: stock.code,
|
||
})
|
||
|
||
if (res.Result) {
|
||
await ExecDatabaseByParam('12', 'PTCHV_AGV_送料记录_增加', [
|
||
['任务号', taskId],
|
||
['取料库位', returnPalletStock.value.StockCode],
|
||
['取料库位名称', stockName],
|
||
['项目', ''],
|
||
['间隔号', ''],
|
||
['组件位置', ''],
|
||
['托盘号', oldTrayNo],
|
||
['送料库位', stock.code],
|
||
['送料库位名称', stock.name],
|
||
['操作人', user.value.name],
|
||
['type', 3],
|
||
])
|
||
ElMessage.success('退空托盘任务创建成功')
|
||
getOpStoreCode()
|
||
} else {
|
||
ElMessage.error(res.ErrMsg || '退空托盘任务创建失败')
|
||
}
|
||
isReturnPalletFlow.value = false
|
||
}).catch(() => {
|
||
isReturnPalletFlow.value = false
|
||
})
|
||
}
|
||
}
|
||
|
||
const onInputChange = (val) => {
|
||
if (val.length > 10) {
|
||
// 如果 出现 &符号说明是扫描了二维码 解析出来是 <物料编号&物料图号> 只把物料编号赋值给inputValue
|
||
if (val.split('&').length === 2) {
|
||
const [EngineNo, SortNo] = val.split('&')
|
||
inputValue.value = EngineNo
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
const onActionSelect = async (action) => {
|
||
showActionSheet.value = false
|
||
if (action.name === '退料') {
|
||
// 获取退空托盘目标库区
|
||
const routes = await getRoutePartitions(currentItem.value.StockCode)
|
||
if (!routes || !routes.returnPallet) {
|
||
ElMessage.warning('未配置退空托盘路线,请联系管理员')
|
||
return
|
||
}
|
||
|
||
// 记录目标库区
|
||
targetPartition.returnPallet = routes.returnPallet
|
||
|
||
// 根据目标库区获取库位列表
|
||
const stockRes = await ExecAgvApi('getStockList', { PartitionCode: targetPartition.returnPallet })
|
||
if (!stockRes.Result) {
|
||
ElMessage.error(stockRes.ErrMsg || '获取库位失败')
|
||
return
|
||
}
|
||
|
||
// 退空托盘流程:只显示无托盘库位
|
||
stockList.value = stockRes.Data
|
||
.filter(i => !i.PalletCode || i.PalletCode === '')
|
||
.map(i => ({ name: i.StockName, code: i.StockCode, ...i }))
|
||
|
||
if (stockList.value.length === 0) {
|
||
ElMessage.warning('目标库区没有可用库位')
|
||
return
|
||
}
|
||
|
||
// 设置退空托盘流程标识和数据
|
||
isReturnPalletFlow.value = true
|
||
returnPalletStock.value = currentItem.value
|
||
stockDialogTitle.value = await getPartitionName(targetPartition.returnPallet)
|
||
showStockDialog.value = true
|
||
}
|
||
}
|
||
|
||
const onInputConfirm = async () => {
|
||
if (!inputValue.value) {
|
||
ElMessage.warning('请输入物料码')
|
||
return
|
||
}
|
||
|
||
// 如果 出现 &符号说明是扫描了二维码 解析出来是 <物料编号&物料图号> 只把物料编号赋值给inputValue
|
||
if (inputValue.value.split('&').length === 2) {
|
||
const [EngineNo, SortNo] = inputValue.value.split('&')
|
||
inputValue.value = EngineNo
|
||
}
|
||
|
||
if (MaterialData.EngineNo != inputValue.value) {
|
||
ElMessage.warning(`库位物料编号【${MaterialData.EngineNo}】与扫描物料编号【${inputValue.value}】不匹配`)
|
||
return
|
||
}
|
||
const res = await ExecDatabaseByParam('11', 'PTCHV_物料验证记录_增加', [["工位号", user.value.opName], ["物料编号", inputValue.value], ["物料图号", MaterialData.SortNo]])
|
||
if (res.data[0].result === 1) {
|
||
ElMessage.success('物料校验成功')
|
||
showInputDialog.value = false
|
||
|
||
if (user.value.opName == 'OP010') {
|
||
// 1. 调用 PTCHV_AGV_上线绑定 存储过程
|
||
const resBind = await ExecDatabaseByParam('11', 'PTCHV_AGV_上线绑定', [['工位号', user.value.opName]])
|
||
if (resBind.data && resBind.data[0].result === 1) {
|
||
try {
|
||
const item = resBind.data[0]
|
||
const agvReq = {
|
||
taskId: uuidv4(),
|
||
EngineNo: item.工件编号,
|
||
SortNo: item.产品型号,
|
||
RouteCode: item.工艺路线编号
|
||
}
|
||
// 2. 调用 AGV API 生产上线绑定
|
||
const agvRes = await ExecAgvApi('productionLaunchBind', agvReq)
|
||
if (agvRes.Result) {
|
||
// 3. 调用 PTCHV_AGV_工位放行次数_记录 存储过程
|
||
const resPass = await ExecDatabaseByParam('12', 'PTCHV_AGV_工位放行次数_记录', [
|
||
['工件编号', item.工件编号],
|
||
['OP10', agvRes.Data.OP010PassCount],
|
||
['OP20', agvRes.Data.OP020PassCount],
|
||
['OP30', agvRes.Data.OP030PassCount]
|
||
])
|
||
if (resPass.data && resPass.data[0].result === '1') {
|
||
// 4. 调用 PTCHV_AGV_进离站 存储过程
|
||
const param = [
|
||
['工位号', user.value.opName],
|
||
['工件编号', item.工件编号],
|
||
['type', 1],
|
||
['任务编号', agvReq.taskId]
|
||
]
|
||
const resInOut = await ExecDatabaseByParam('12', 'PTCHV_AGV_进离站', param)
|
||
if (resInOut.data && resInOut.data[0].result === '1') {
|
||
ElMessage.success('产品上线绑定AGV成功!')
|
||
} else {
|
||
ElMessage.error('产品上线绑定AGV失败')
|
||
}
|
||
} else {
|
||
ElMessage.error('放行次数记录失败')
|
||
}
|
||
} else {
|
||
ElMessage.error(agvRes.ErrMsg)
|
||
}
|
||
} catch (e) {
|
||
ElMessage.error('调度任务出错' + e.message)
|
||
console.log(e)
|
||
}
|
||
} else {
|
||
ElMessage.error('调度任务出错' + (resBind.data && resBind.data[0] && resBind.data[0].msg ? resBind.data[0].msg : ''))
|
||
}
|
||
}
|
||
} else {
|
||
ElMessage.error(res.data[0].msg)
|
||
}
|
||
}
|
||
|
||
const onInputCancel = () => {
|
||
showInputDialog.value = false
|
||
}
|
||
|
||
const onReturnPalletClick = () => {
|
||
returnPalletCode.value = ''
|
||
returnPalletStock.value = null
|
||
showReturnPalletDialog.value = true
|
||
}
|
||
|
||
const onReturnPalletCancel = () => {
|
||
showReturnPalletDialog.value = false
|
||
}
|
||
|
||
const onReturnPalletConfirm = async () => {
|
||
if (!returnPalletCode.value) {
|
||
ElMessage.warning('请输入托盘码')
|
||
return
|
||
}
|
||
|
||
// 校验托盘码是否属于本库区
|
||
const stock = opStoreData.find(i => i.TrayNo === returnPalletCode.value)
|
||
if (!stock) {
|
||
ElMessage.error('该托盘码不属于本库区')
|
||
return
|
||
}
|
||
|
||
returnPalletStock.value = stock
|
||
showReturnPalletDialog.value = false
|
||
|
||
// 获取退空托盘目标库区
|
||
const routes = await getRoutePartitions(stock.StockCode)
|
||
if (!routes || !routes.returnPallet) {
|
||
ElMessage.warning('未配置退空托盘路线,请联系管理员')
|
||
return
|
||
}
|
||
|
||
// 记录目标库区
|
||
targetPartition.returnPallet = routes.returnPallet
|
||
|
||
// 根据目标库区获取库位列表
|
||
const stockRes = await ExecAgvApi('getStockList', { PartitionCode: targetPartition.returnPallet })
|
||
if (!stockRes.Result) {
|
||
ElMessage.error(stockRes.ErrMsg || '获取库位失败')
|
||
return
|
||
}
|
||
|
||
// 退空托盘流程:只显示无托盘库位,排除"无库位"
|
||
stockList.value = (stockRes.Data || [])
|
||
.filter(i => (!i.TrayNo || i.TrayNo === '') && i.StockName !== '无库位')
|
||
.map(i => ({ name: i.StockName, code: i.StockCode, ...i }))
|
||
|
||
if (stockList.value.length === 0) {
|
||
ElMessage.warning('目标库区没有可用库位')
|
||
return
|
||
}
|
||
|
||
// 设置退空托盘流程标识并显示库位选择
|
||
isReturnPalletFlow.value = true
|
||
showStockDialog.value = true
|
||
}
|
||
|
||
// 标记当前流程类型
|
||
const isReturnPalletFlow = ref(false)
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.card.modern-card {
|
||
background: #fff;
|
||
border-radius: 18px;
|
||
box-shadow: 0 4px 24px 0 rgba(0, 0, 0, 0.08);
|
||
padding: 10px 14px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.storList {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 24px;
|
||
}
|
||
|
||
.storList-item.modern-item {
|
||
background: linear-gradient(135deg, #f8fafc 60%, #e0e7ef 100%);
|
||
border-radius: 14px;
|
||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
|
||
padding: 20px 18px 16px 18px;
|
||
min-width: 260px;
|
||
max-width: 320px;
|
||
flex: 1 1 260px;
|
||
transition: box-shadow 0.2s, transform 0.2s;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.12);
|
||
transform: translateY(-2px) scale(1.02);
|
||
}
|
||
}
|
||
|
||
.storList-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.storList-title {
|
||
font-size: 1.18rem;
|
||
font-weight: 600;
|
||
color: #222;
|
||
}
|
||
|
||
.storList-tags {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.storList-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
font-size: 0.98rem;
|
||
color: #555;
|
||
|
||
span {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
|
||
i {
|
||
font-size: 1.1em;
|
||
color: #8bb4f8;
|
||
}
|
||
|
||
b {
|
||
color: #222;
|
||
font-weight: 500;
|
||
margin-left: 2px;
|
||
}
|
||
}
|
||
}
|
||
</style> |