New file |
| | |
| | | <!DOCTYPE html> |
| | | <html lang="zh-CN"> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | | <title>提升机监控系统</title> |
| | | <link rel="stylesheet" href="../static/vue/element/element.css"> |
| | | <link rel="stylesheet" href="../static/css/shuttle_page.min.css"> |
| | | <script src="../static/js/shuttle_page.js"></script> |
| | | <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../static/js/common.js"></script> |
| | | <script type="text/javascript" src="../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../static/vue/element/element.js"></script> |
| | | <style> |
| | | body { |
| | | font-family: 'Noto Sans SC', sans-serif; |
| | | background-color: #0f172a; |
| | | color: #e2e8f0; |
| | | } |
| | | .card { |
| | | background-color: #1e293b; |
| | | border-radius: 0.75rem; |
| | | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| | | transition: all 0.3s ease; |
| | | } |
| | | /*.card:hover {*/ |
| | | /* transform: translateY(-2px);*/ |
| | | /* box-shadow: 0 10px 15px rgba(0, 0, 0, 0.2);*/ |
| | | /*}*/ |
| | | .btn { |
| | | background-color: #3b82f6; |
| | | color: white; |
| | | border-radius: 0.5rem; |
| | | padding: 0.5rem 1rem; |
| | | transition: all 0.3s ease; |
| | | } |
| | | .btn:hover { |
| | | background-color: #2563eb; |
| | | transform: translateY(-1px); |
| | | } |
| | | .status-active { |
| | | color: #4ade80; |
| | | } |
| | | .status-inactive { |
| | | color: #f87171; |
| | | } |
| | | .progress-bar { |
| | | height: 0.75rem; |
| | | border-radius: 0.375rem; |
| | | background-color: #334155; |
| | | } |
| | | .progress-fill { |
| | | height: 100%; |
| | | border-radius: 0.375rem; |
| | | background-color: #4ade80; |
| | | transition: width 0.5s ease; |
| | | } |
| | | .table-striped tbody tr:nth-child(odd) { |
| | | background-color: #1e293b; |
| | | } |
| | | .table-striped tbody tr:nth-child(even) { |
| | | background-color: #1a2537; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body class="min-h-screen"> |
| | | <div id="app"> |
| | | <div class="container mx-auto px-4 py-8"> |
| | | <!-- 顶部标题和状态栏 --> |
| | | <div class="flex flex-col md:flex-row justify-between items-center mb-8"> |
| | | <h1 class="text-3xl font-bold text-blue-400 mb-4 md:mb-0"> |
| | | <i class="fas fa-robot mr-2"></i>提升机监控系统 |
| | | </h1> |
| | | <div class="flex items-center space-x-4"> |
| | | <div class="flex items-center"> |
| | | <div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div> |
| | | <span>在线: {{ deviceStatusCountMap.online }}</span> |
| | | </div> |
| | | <div class="flex items-center"> |
| | | <div class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></div> |
| | | <span>故障: {{ deviceStatusCountMap.error }}</span> |
| | | </div> |
| | | <div class="flex items-center"> |
| | | <div class="w-3 h-3 rounded-full bg-red-500 mr-2"></div> |
| | | <span>离线: {{ deviceStatusCountMap.offline }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 主要监控区域 --> |
| | | <div class="card p-6 mb-8"> |
| | | <!-- 提升机状态表格 --> |
| | | <div class="card p-6"> |
| | | <div class="flex justify-between items-center mb-4"> |
| | | <h2 class="text-xl font-semibold text-blue-300"> |
| | | <i class="fas fa-list-alt mr-2"></i>提升机状态 |
| | | </h2> |
| | | <div class="relative"> |
| | | <select v-model="selectListStatus" class="bg-slate-700 text-white rounded px-3 py-1 pr-8"> |
| | | <option value="all">全部状态</option> |
| | | <option value="online">在线</option> |
| | | <option value="idle">空闲</option> |
| | | <option value="running">运行中</option> |
| | | <option value="offline">离线</option> |
| | | <option value="error">故障</option> |
| | | </select> |
| | | </div> |
| | | </div> |
| | | <div class="overflow-auto" style="height: 500px;"> |
| | | <table class="w-full table-striped"> |
| | | <thead> |
| | | <tr class="text-left text-slate-300 border-b border-slate-600 bg-slate-800 sticky top-0 z-10"> |
| | | <th class="py-3 px-4">编号</th> |
| | | <th class="py-3 px-4">工作号</th> |
| | | <th class="py-3 px-4">PLC工作号</th> |
| | | <th class="py-3 px-4">设备模式</th> |
| | | <th class="py-3 px-4">任务状态</th> |
| | | <th class="py-3 px-4">任务模式</th> |
| | | <th class="py-3 px-4">取货数据</th> |
| | | <th class="py-3 px-4">放货数据</th> |
| | | <th class="py-3 px-4">出入库模式</th> |
| | | <th class="py-3 px-4">托盘</th> |
| | | <th class="py-3 px-4">小车</th> |
| | | <th class="py-3 px-4">故障码</th> |
| | | <th class="py-3 px-4">层</th> |
| | | <th class="py-3 px-4">站点信息</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr v-for="(item,idx) in liftList" :key="idx" class="hover:bg-slate-700"> |
| | | <td class="py-3 px-4">{{ item.liftNo }}</td> |
| | | <td class="py-3 px-4">{{ item.taskNo }}</td> |
| | | <td class="py-3 px-4">{{ item.plcTaskNo }}</td> |
| | | <td class="py-3 px-4">{{ item.model$ }}</td> |
| | | <td class="py-3 px-4">{{ item.protocolStatus$ }}</td> |
| | | <td class="py-3 px-4">{{ item.taskMode$ }}</td> |
| | | <td class="py-3 px-4">{{ item.pick }}</td> |
| | | <td class="py-3 px-4">{{ item.put }}</td> |
| | | <td class="py-3 px-4">{{ item.iOMode$ }}</td> |
| | | <td class="py-3 px-4">{{ item.hasTray ? '有':'无' }}</td> |
| | | <td class="py-3 px-4">{{ item.hasCar ? '有':'无' }}</td> |
| | | <td class="py-3 px-4">{{ item.errorCode }}</td> |
| | | <td class="py-3 px-4">{{ item.lev }}</td> |
| | | <td class="py-3 px-4"> |
| | | <div v-for="(sta,id) in item.liftStaProtocols" :key="id"> |
| | | {{ sta.lev }}层,托盘:{{ sta.hasTray ? 'Y':'N' }},小车:{{ sta.hasCar ? 'Y':'N' }} |
| | | </div> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 操作控制区域 --> |
| | | <div class="card p-6 mb-8"> |
| | | <h2 class="text-xl font-semibold text-blue-300 mb-4"> |
| | | <i class="fas fa-sliders-h mr-2"></i>控制面板 |
| | | </h2> |
| | | <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-2"> |
| | | <div class="bg-slate-700 p-4 rounded-lg"> |
| | | <h3 class="text-lg font-medium mb-2">设备控制</h3> |
| | | <div class="flex flex-wrap gap-2" style="display: flex;justify-content: center;"> |
| | | <div> |
| | | <el-input @change="changeControlLiftNo" v-model="controlData.liftNo" style="width: 150px;" placeholder="编号"></el-input> |
| | | </div> |
| | | <div> |
| | | <el-input v-model="controlData.sourceStaNo" style="width: 200px;" placeholder="源站"></el-input> |
| | | </div> |
| | | <div> |
| | | <el-input v-model="controlData.staNo" style="width: 200px;" placeholder="目标站"></el-input> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="bg-slate-700 p-4 rounded-lg"> |
| | | <h3 class="text-lg font-medium mb-2">设备指令</h3> |
| | | <div class="flex flex-wrap gap-2" style="display: flex;justify-content: center;"> |
| | | <button class="btn bg-slate-600 hover:bg-slate-500" @click="liftOperator('movePallet')"> |
| | | <i class="fas fa-level-up mr-1"></i>移动托盘 |
| | | </button> |
| | | <button class="btn bg-slate-600 hover:bg-slate-500" @click="liftOperator('switchShuttle')"> |
| | | <i class="fas fa-level-down mr-1"></i>小车换层 |
| | | </button> |
| | | <button class="btn bg-slate-600 hover:bg-slate-500" @click="liftOperator('move')"> |
| | | <i class="fas fa-battery-three-quarters mr-1"></i>移动 |
| | | </button> |
| | | <button class="btn bg-slate-600 hover:bg-slate-500" @click="liftOperator('reset')"> |
| | | <i class="fas fa-home mr-1"></i>复位 |
| | | </button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | </body> |
| | | |
| | | <script> |
| | | var app = new Vue({ |
| | | el: '#app', |
| | | data: { |
| | | ws: null, |
| | | liftList: [], //提升机集合 |
| | | liftAllList: [], |
| | | selectListStatus: "all", |
| | | deviceStatusCountMap: {}, |
| | | controlData: { |
| | | liftNo: "", |
| | | taskNo: "", |
| | | sourceLocNo: "", |
| | | targetLocNo: "" |
| | | }, |
| | | controlLiftInfo: null, |
| | | }, |
| | | created() { |
| | | this.init() |
| | | }, |
| | | watch: { |
| | | |
| | | }, |
| | | methods: { |
| | | init() { |
| | | this.consoleInterval = setInterval(() => { |
| | | this.websocketConnect(); |
| | | |
| | | this.getLiftStateInfo() //获取提升机信息 |
| | | }, 1000) |
| | | }, |
| | | getLiftStateInfo() { |
| | | this.sendWs(JSON.stringify({ |
| | | "url": "/lift/table/lift/state", |
| | | "data": {} |
| | | })) |
| | | }, |
| | | setLiftStateInfo(res) { |
| | | // 提升机信息表获取 |
| | | if (res.code == 200) { |
| | | let list = res.data; |
| | | |
| | | let allList = [] |
| | | let runningList = [] |
| | | let idleList = [] |
| | | let errorList = [] |
| | | let offlineList = [] |
| | | let onlineList = [] |
| | | |
| | | list.forEach((item) => { |
| | | allList.push(item) |
| | | |
| | | if(item.protocolStatusType == "WORKING") { |
| | | runningList.push(item) |
| | | } |
| | | |
| | | if(item.protocolStatusType == "IDLE") { |
| | | idleList.push(item) |
| | | } |
| | | |
| | | if(item.errorCode > 0) { |
| | | errorList.push(item) |
| | | } |
| | | |
| | | if (item.protocolStatusType == "NONE") { |
| | | offlineList.push(item) |
| | | }else { |
| | | onlineList.push(item) |
| | | } |
| | | }) |
| | | |
| | | if (this.selectListStatus == "all") { |
| | | this.liftList = allList; |
| | | }else if (this.selectListStatus == "running") { |
| | | this.liftList = runningList; |
| | | }else if (this.selectListStatus == "idle") { |
| | | this.liftList = idleList; |
| | | }else if (this.selectListStatus == "error") { |
| | | this.liftList = errorList; |
| | | }else if (this.selectListStatus == "offline") { |
| | | this.liftList = offlineList; |
| | | }else if (this.selectListStatus == "online") { |
| | | this.liftList = onlineList; |
| | | } |
| | | |
| | | let tmpMap = { |
| | | idle: idleList.length, |
| | | running: runningList.length, |
| | | error: errorList.length, |
| | | offline: offlineList.length, |
| | | online: idleList.length + runningList.length, |
| | | } |
| | | this.deviceStatusCountMap = tmpMap; |
| | | |
| | | this.liftAllList = allList; |
| | | if (this.controlLiftInfo != null) { |
| | | allList.forEach((item) => { |
| | | if(item.liftNo == this.controlLiftInfo.liftNo) { |
| | | this.controlLiftInfo = item; |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }, |
| | | liftOperator(type) { |
| | | let that = this; |
| | | if (this.controlData.liftNo == null || this.controlData.liftNo == "") { |
| | | this.$message({ |
| | | message: '请输入设备编号', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | let requestParam = { |
| | | liftNo: this.controlData.liftNo |
| | | }; |
| | | |
| | | if (type == 'movePallet') { |
| | | if (this.controlData.sourceStaNo == null || this.controlData.sourceStaNo == "") { |
| | | this.$message({ |
| | | message: '请输入源站', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | if (this.controlData.staNo == null || this.controlData.staNo == "") { |
| | | this.$message({ |
| | | message: '请输入目标站', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | requestParam.liftTaskMode = 1; |
| | | requestParam.sourceStaNo = this.controlData.sourceStaNo; |
| | | requestParam.staNo = this.controlData.staNo; |
| | | }else if (type == 'switchShuttle') { |
| | | if (this.controlData.sourceStaNo == null || this.controlData.sourceStaNo == "") { |
| | | this.$message({ |
| | | message: '请输入源站', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | if (this.controlData.staNo == null || this.controlData.staNo == "") { |
| | | this.$message({ |
| | | message: '请输入目标站', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | requestParam.liftTaskMode = 2; |
| | | requestParam.sourceStaNo = this.controlData.sourceStaNo; |
| | | requestParam.staNo = this.controlData.staNo; |
| | | }else if (type == 'move') { |
| | | if (this.controlData.sourceStaNo == null || this.controlData.sourceStaNo == "") { |
| | | this.$message({ |
| | | message: '请输入源站', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | if (this.controlData.staNo == null || this.controlData.staNo == "") { |
| | | this.$message({ |
| | | message: '请输入目标站', |
| | | type: 'warning' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | requestParam.liftTaskMode = 3; |
| | | requestParam.sourceStaNo = this.controlData.sourceStaNo; |
| | | requestParam.staNo = this.controlData.staNo; |
| | | }else if (type == 'reset') { |
| | | requestParam.liftTaskMode = 9996; |
| | | } |
| | | |
| | | $.ajax({ |
| | | url: baseUrl + "/lift/operator/lift", |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | method: 'POST', |
| | | data: requestParam, |
| | | success: function (res) { |
| | | if (res.code === 200) { |
| | | that.$message({ |
| | | message: res.msg, |
| | | type: 'success' |
| | | }); |
| | | } else if (res.code === 403) { |
| | | window.location.href = baseUrl + "/login"; |
| | | } else { |
| | | that.$message({ |
| | | message: res.msg, |
| | | type: 'warning' |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | changeControlLiftNo() { |
| | | let liftNo = this.controlData.liftNo; |
| | | if (liftNo == null || liftNo == "") { |
| | | this.controlLiftInfo = null |
| | | } |
| | | |
| | | this.liftAllList.forEach((item) => { |
| | | if (item.liftNo == liftNo) { |
| | | this.controlLiftInfo = item; |
| | | } |
| | | }); |
| | | }, |
| | | websocketConnect() { |
| | | if (this.ws == null) { |
| | | this.ws = new WebSocket("ws://" + window.location.host + baseUrl + "/console/websocket"); |
| | | this.ws.onopen = this.webSocketOnOpen |
| | | this.ws.onerror = this.webSocketOnError |
| | | this.ws.onmessage = this.webSocketOnMessage |
| | | this.ws.onclose = this.webSocketClose |
| | | } |
| | | }, |
| | | webSocketOnOpen(e) { |
| | | console.log("open"); |
| | | }, |
| | | webSocketOnError(e) { |
| | | this.ws = null; |
| | | console.log(e); |
| | | }, |
| | | webSocketOnMessage(e) { |
| | | const result = JSON.parse(e.data); |
| | | if (result.url == "/lift/table/lift/state") { |
| | | this.setLiftStateInfo(JSON.parse(result.data)) |
| | | } |
| | | }, |
| | | webSocketClose(e) { |
| | | this.ws = null; |
| | | console.log("close"); |
| | | }, |
| | | sendWs(message) { |
| | | if (this.ws == null) { |
| | | return; |
| | | } |
| | | |
| | | if (this.ws.readyState == WebSocket.OPEN) { |
| | | this.ws.send(message); |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | </script> |
| | | </html> |