feat: 增加AGV任务管理并完善磨合管理
This commit is contained in:
@@ -1,18 +0,0 @@
|
|||||||
模块介绍
|
|
||||||
用于 处理各工位生产过程中 出现的异常情况(如 进站失败重试 出站失败重试) 开放功能重试按钮、查看工位产品信息、加工状态、可以看工位当前产品 过站情况 等
|
|
||||||
|
|
||||||
功能需求
|
|
||||||
1.首先进入页面仍然需要刷卡弹窗进行登陆 登陆后 首先拉出工位当前在位产品信息 然后是 显示三个重试按钮
|
|
||||||
2.三个重试按钮 分别是 (进站重试、出站重试、申请条码) 分别对应后端三个接口 (接口地址 仍然是 window.g.API_MES_Controller_URL + /url)
|
|
||||||
4.显示一块区域 或者 点按钮显示一个弹窗(看情况和UI自由发挥) 就可以拉出 该产品 各工位接口执行情况Moby数据 用户可以查看前面各工位接口执行情况
|
|
||||||
5.存储过程相关你需要先调用 SqlServerMCP 去查看存储过程定义以及参数 还有返回结果后再进行开发
|
|
||||||
6.界面要适配 竖屏PAD 因为会在竖屏Pad上进行使用 要界面友好
|
|
||||||
7.我发现 刷卡登陆弹窗在竖屏Pad上会出现 弹窗宽度不宽 但是 输入框超出了弹窗范围
|
|
||||||
|
|
||||||
|
|
||||||
资源位置
|
|
||||||
1.这个页面文件是 (D:\项目文件\52.智柔PDC线\前端\MES_ApiFailRetry\src\views\OpStatus.vue)
|
|
||||||
2.重试接口程序位置 可查看重试接口参数 (D:\项目文件\52.智柔PDC线\程序\MesProject_2025.09.161105\MisDataFun\MisDataFun\webApi\WebSendServer.cs 的 ApiFailRetry 方法)
|
|
||||||
3.刷卡登陆功能参考 和 工位列表获取参考 (D:\项目文件\52.智柔PDC线\前端\MES_ApiFailRetry\src\views\index.vue)
|
|
||||||
4.工位状态存储过程 PAD_工位状态_查询 切换选择工位时调用 进入页面默认选择第一个工位 其中 状态 1 已进站 2 已完成 其他都是未进站
|
|
||||||
5.工位产品 接口调用情况查询存储过程 PAD_工位状态_产品接口Moby_查询 其中请求内容列是个多行文本 这个如果要看可以是单独弹窗或者单独区域显示(你看怎么合适怎么来)
|
|
||||||
1808
src/components/AgvTaskManagement.vue
Normal file
1808
src/components/AgvTaskManagement.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ import {ElMessage} from 'element-plus' // 引入Element Plus的消息提示组
|
|||||||
const name_config = `OP8888`
|
const name_config = `OP8888`
|
||||||
// import.meta.env.VITE_BASE_URL
|
// import.meta.env.VITE_BASE_URL
|
||||||
console.log(window.g)
|
console.log(window.g)
|
||||||
const request_config = window.g.API_WEB_URL + `/submit/MESCommonBase.ashx`
|
const request_config = window.g.API_WEB_URL
|
||||||
export const name = name_config
|
export const name = name_config
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: request_config,
|
baseURL: request_config,
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="running-in-page">
|
<div class="management-page">
|
||||||
|
<el-tabs v-model="activeTab" class="management-tabs">
|
||||||
|
<el-tab-pane label="AGV任务" name="agv">
|
||||||
|
<AgvTaskManagement v-if="activeTab === 'agv'" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="库位监控" name="slots">
|
||||||
|
<div class="running-in-page">
|
||||||
<!-- 顶部标题栏 -->
|
<!-- 顶部标题栏 -->
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>磨合转序管理</h1>
|
<h1>磨合转序管理</h1>
|
||||||
@@ -151,6 +157,22 @@
|
|||||||
>
|
>
|
||||||
AGV离开
|
AGV离开
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
size="large"
|
||||||
|
:loading="toggleCallLoading"
|
||||||
|
@click="handleToggleCall"
|
||||||
|
>
|
||||||
|
{{ selectedSlot?.是否呼叫 ? '取消呼叫' : '设为呼叫' }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="large"
|
||||||
|
:loading="clearSlotLoading"
|
||||||
|
@click="handleClearSlot"
|
||||||
|
>
|
||||||
|
清空库位数据
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@@ -221,16 +243,21 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted, getCurrentInstance, inject } from 'vue'
|
import { ref, computed, onMounted, onUnmounted, getCurrentInstance, inject, watch } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { Refresh, Right } from '@element-plus/icons-vue'
|
import { Refresh, Right } from '@element-plus/icons-vue'
|
||||||
|
import AgvTaskManagement from '@/components/AgvTaskManagement.vue'
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
const ExecHttpRequest = inject('ExecHttpRequest')
|
const ExecHttpRequest = inject('ExecHttpRequest')
|
||||||
|
const activeTab = ref('agv')
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -249,6 +276,11 @@ const confirmTransferLoading = ref(false)
|
|||||||
const agvArriveLoading = ref(false)
|
const agvArriveLoading = ref(false)
|
||||||
const agvLeaveLoading = ref(false)
|
const agvLeaveLoading = ref(false)
|
||||||
|
|
||||||
|
// 库位运维操作
|
||||||
|
const toggleCallLoading = ref(false)
|
||||||
|
const clearSlotLoading = ref(false)
|
||||||
|
const OPERATOR = '磨合系统'
|
||||||
|
|
||||||
// PLC相关
|
// PLC相关
|
||||||
const plcConfigList = window.g.showPosList || []
|
const plcConfigList = window.g.showPosList || []
|
||||||
const plcValues = ref({}) // 存储点位值 Key=TagCode, Value=0/1
|
const plcValues = ref({}) // 存储点位值 Key=TagCode, Value=0/1
|
||||||
@@ -326,7 +358,6 @@ const handleSlotClick = (slot) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 监听弹窗打开关闭,控制PLC轮询
|
// 监听弹窗打开关闭,控制PLC轮询
|
||||||
import { watch } from 'vue'
|
|
||||||
watch(dialogVisible, (val) => {
|
watch(dialogVisible, (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
fetchPLCValues()
|
fetchPLCValues()
|
||||||
@@ -621,9 +652,100 @@ const handleAGVLeave = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换是否呼叫
|
||||||
|
const handleToggleCall = async () => {
|
||||||
|
if (!selectedSlot.value) return
|
||||||
|
|
||||||
|
const targetText = selectedSlot.value.是否呼叫 ? '取消呼叫' : '设为呼叫'
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确认将库位 ${selectedSlot.value.库位号} ${targetText}?此操作会写入系统日志。`,
|
||||||
|
'确认',
|
||||||
|
{ confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning' }
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCallLoading.value = true
|
||||||
|
try {
|
||||||
|
const param = [
|
||||||
|
['库位号', selectedSlot.value.库位号],
|
||||||
|
['操作人', OPERATOR]
|
||||||
|
]
|
||||||
|
const data = proxy.CreateData('11', 'XD_磨合_状态_是否呼叫_切换', param)
|
||||||
|
const res = await proxy.ExecDatabase(data)
|
||||||
|
const row = res.data && res.data[0] ? res.data[0] : {}
|
||||||
|
|
||||||
|
if (row.result === 1) {
|
||||||
|
ElMessage.success(`${targetText}成功`)
|
||||||
|
selectedSlot.value.是否呼叫 = Number(row.是否呼叫) || 0
|
||||||
|
loadData(false)
|
||||||
|
} else {
|
||||||
|
ElMessage.error(row.msg || `${targetText}失败`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('切换呼叫状态失败:', err)
|
||||||
|
ElMessage.error('切换呼叫状态异常')
|
||||||
|
} finally {
|
||||||
|
toggleCallLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空库位数据
|
||||||
|
const handleClearSlot = async () => {
|
||||||
|
if (!selectedSlot.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确认清空库位 ${selectedSlot.value.库位号} 的产品/工序/状态数据?此操作会写入系统日志,且不可撤销。`,
|
||||||
|
'危险操作',
|
||||||
|
{ confirmButtonText: '确认清空', cancelButtonText: '取消', type: 'error' }
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSlotLoading.value = true
|
||||||
|
try {
|
||||||
|
const param = [
|
||||||
|
['库位号', selectedSlot.value.库位号],
|
||||||
|
['操作人', OPERATOR]
|
||||||
|
]
|
||||||
|
const data = proxy.CreateData('11', 'XD_磨合_状态_清空', param)
|
||||||
|
const res = await proxy.ExecDatabase(data)
|
||||||
|
const row = res.data && res.data[0] ? res.data[0] : {}
|
||||||
|
|
||||||
|
if (row.result === 1) {
|
||||||
|
ElMessage.success('库位数据已清空')
|
||||||
|
dialogVisible.value = false
|
||||||
|
loadData()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(row.msg || '清空库位数据失败')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('清空库位数据失败:', err)
|
||||||
|
ElMessage.error('清空库位数据异常')
|
||||||
|
} finally {
|
||||||
|
clearSlotLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadData()
|
if (activeTab.value === 'slots') {
|
||||||
startAutoRefresh()
|
loadData()
|
||||||
|
startAutoRefresh()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(activeTab, value => {
|
||||||
|
if (value === 'slots') {
|
||||||
|
loadData()
|
||||||
|
startAutoRefresh()
|
||||||
|
} else {
|
||||||
|
dialogVisible.value = false
|
||||||
|
stopAutoRefresh()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -632,9 +754,33 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.running-in-page {
|
.management-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #e8eaed;
|
background: #e8eaed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-tabs {
|
||||||
|
:deep(.el-tabs__header) {
|
||||||
|
padding: 0 18px;
|
||||||
|
margin: 0;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
height: 52px;
|
||||||
|
font-size: 15px;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tabs__content) {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.running-in-page {
|
||||||
|
min-height: calc(100vh - 52px);
|
||||||
|
background: #e8eaed;
|
||||||
color: #1a1a1a;
|
color: #1a1a1a;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
Reference in New Issue
Block a user