瀏覽代碼

新增websocket操作

pm 11 月之前
父節點
當前提交
1c135a42b6

+ 3 - 2
package.json

@@ -21,7 +21,7 @@
       "eslint --fix",
       "git add"
     ]
-  },
+  },                                          
   "keywords": [
     "vue",
     "admin",
@@ -67,7 +67,8 @@
     "vue-plugin-hiprint": "^0.0.54-fix",
     "vue-router": "3.4.9",
     "vuedraggable": "2.24.3",
-    "vuex": "3.6.0"
+    "vuex": "3.6.0",
+    "websocket": "^1.0.35"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "4.4.6",

+ 1 - 0
src/App.vue

@@ -21,3 +21,4 @@ export default  {
     }
 }
 </script>
+

+ 220 - 0
src/utils/websocket.js

@@ -0,0 +1,220 @@
+// websocket实例
+let wsObj = null;
+// ws连接地址
+let wsUrl = null;
+// let userId = null;
+// 是否执行重连 true/不执行 ; false/执行
+let lockReconnect = false;
+// 重连定时器
+let wsCreateHandler = null;
+// 连接成功,执行回调函数
+let messageCallback = null;
+// 连接失败,执行回调函数
+let errorCallback = null;
+// 发送给后台的数据
+let sendDatas = {};
+
+/**
+ * 发起websocket请求函数
+ * @param {string} url ws连接地址
+ * @param {Object} agentData 传给后台的参数
+ * @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数
+ * @param {function} errCallback ws连接错误的回调函数
+ */
+export const connectWebsocket = (url, agentData, successCallback, errCallback) => {
+  wsUrl = url;
+  createWebSoket();
+  messageCallback = successCallback;
+  errorCallback = errCallback;
+  sendDatas = agentData;
+};
+
+// 手动关闭websocket (这里手动关闭会执行onclose事件)
+export const closeWebsocket = () => {
+  if (wsObj) {
+    writeToScreen("手动关闭websocket");
+    wsObj.close(); // 关闭websocket
+    // wsObj.onclose() // 关闭websocket(如果上面的关闭不生效就加上这一条)
+    // 关闭重连
+    lockReconnect = true;
+    wsCreateHandler && clearTimeout(wsCreateHandler);
+    // 关闭心跳检查
+    heartCheck.stop();
+  }
+};
+
+//向服务器端发送消息
+export const sendMsg = value => {
+  wsObj.send(JSON.stringify(value));
+};
+
+// 创建ws函数
+const createWebSoket = () => {
+  //判断浏览器是否支持websocket
+  if (typeof WebSocket === "undefined") {
+    writeToScreen("您的浏览器不支持WebSocket,无法获取数据");
+    return false;
+  }
+
+  // const host = window.location.host; //获取端口
+  // userId = GetQueryString("userId");
+  // wsUrl = "ws://" + host + "/websoket" + userId;
+
+  try {
+    wsObj = new WebSocket(wsUrl);
+    initWsEventHandle();
+  } catch (e) {
+    writeToScreen("连接异常,开始重连");
+    reconnect();
+  }
+};
+
+
+const initWsEventHandle = () => {
+  try {
+    // 连接成功
+    wsObj.onopen = event => {
+      heartCheck.start(); //开启心跳
+      onWsOpen(event); //客户端与服务器端通信
+    };
+
+    // 监听服务器端返回的信息
+    wsObj.onmessage = event => {
+      onWsMessage(event); //接收数据,抛出
+      heartCheck.reset(); //重置心跳
+    };
+
+    wsObj.onclose = event => {
+      writeToScreen("onclose执行关闭事件");
+      onWsClose(event); //关闭事件
+    };
+
+    wsObj.onerror = event => {
+      writeToScreen("onerror执行error事件,开始重连");
+      onWsError(event); //error事件
+      reconnect(); //重连
+    };
+  } catch (err) {
+    writeToScreen("绑定事件没有成功,开始重连");
+    reconnect();
+  }
+};
+
+//open事件 WebSocket连接成功时触发
+const onWsOpen = event => {
+  //  客户端与服务器端通信
+  // wsObj.send('我发送消息给服务端');
+  // 添加状态判断,当为OPEN时,发送消息
+  if (wsObj.readyState === wsObj.OPEN) {
+    // wsObj.OPEN = 1
+    // 发给后端的数据需要字符串化
+    wsObj.send(JSON.stringify(sendDatas));
+  }
+  if (wsObj.readyState === wsObj.CLOSED) {
+    // wsObj.CLOSED = 3
+    writeToScreen("wsObj.readyState=3, ws连接异常,开始重连");
+    reconnect();
+    errorCallback(event);
+  }
+};
+
+//message事件  接收到WebSocket服务器发送的消息时触发
+const onWsMessage = event => {
+  const jsonStr = event.data;
+  // writeToScreen("onWsMessage接收到服务器的数据: ", jsonStr);
+  messageCallback(jsonStr);
+};
+
+//close事件 WebSocket连接关闭时触发
+const onWsClose = event => {
+  writeToScreen("DISCONNECT");
+  // e.code === 1000  表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。
+  // e.code !== 1000  表示非正常关闭。
+  console.log("onclose event: ", event);
+  if (event && event.code !== 1000) {
+    writeToScreen("非正常关闭");
+    errorCallback(event);
+    // 如果不是手动关闭,这里的重连会执行;如果调用了手动关闭函数,这里重连不会执行
+    reconnect();
+  }
+};
+
+//error事件 WebSocket连接出错时触发
+const onWsError = event => {
+  writeToScreen("onWsError: ", event.data);
+  errorCallback(event);//抛出错误
+};
+
+//封装console.log()
+const writeToScreen = massage => {
+  console.log(massage);
+};
+
+// 重连函数
+const reconnect = () => {
+  if (lockReconnect) {
+    return;
+  }
+  writeToScreen("1分钟秒后重连");
+  lockReconnect = true;
+  // 没连接上会一直重连,设置延迟避免请求过多
+  wsCreateHandler && clearTimeout(wsCreateHandler);
+  wsCreateHandler = setTimeout(() => {
+    writeToScreen("重连..." + wsUrl);
+    createWebSoket();
+    lockReconnect = false;
+    writeToScreen("重连完成");
+  }, 60000);//一分钟之后重新链接
+};
+
+// 从浏览器地址中获取对应参数
+const GetQueryString = name => {
+  let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+  // 获取url中 ? 符后的字符串并正则匹配
+  let r = window.location.search.substr(1).match(reg);
+  let context = "";
+  r && (context = r[2]);
+  reg = null;
+  r = null;
+  return context;
+};
+
+// 心跳检查(看看websocket是否还在正常连接中)
+let heartCheck = {
+  timeout: 15 * 1000,
+  timeoutObj: null,
+  serverTimeoutObj: null,
+  // 重启
+  reset() {
+    clearTimeout(this.timeoutObj);
+    clearTimeout(this.serverTimeoutObj);
+    this.start();
+  },
+  // 停止
+  stop() {
+    clearTimeout(this.timeoutObj);
+    clearTimeout(this.serverTimeoutObj);
+  },
+  // 开启定时器
+  start() {
+    this.timeoutObj && clearTimeout(this.timeoutObj);
+    this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
+    // 15s之内如果没有收到后台的消息,则认为是连接断开了,需要重连
+    this.timeoutObj = setTimeout(() => {
+      writeToScreen("心跳检查,发送ping到后台");
+      try {
+        const datas = { content: "心跳检测" };
+        wsObj.send(JSON.stringify(datas));
+      } catch (err) {
+        writeToScreen("发送ping异常,重连");
+        reconnect();
+      }
+      // console.log("内嵌定时器this.serverTimeoutObj: ", this.serverTimeoutObj);
+      // 内嵌定时器
+      this.serverTimeoutObj = setTimeout(() => {
+        writeToScreen("没有收到后台的数据,重新连接");
+        reconnect();
+      }, this.timeout);
+    }, this.timeout);
+  },
+};

+ 1 - 0
src/views/mes/job/jobm/NewOperations.vue

@@ -1184,6 +1184,7 @@ export default {
     addOutside() {
       this.open = true
       this.title = '添加外部人员'
+      this.OutSideUserTableData=[]
       this.insideMumber = false
       this.outsideMumber = true
       this.dialogForm.username = null

+ 26 - 6
src/views/mes/job/jobplay/jobPlayDetail.vue

@@ -164,7 +164,7 @@
 
 <script>
 import { getJobPlayTicketInfo } from "@/api/mes/jobplay/jobplay";
-
+import { connectWebsocket, closeWebsocket, sendMsg } from "@/utils/websocket";
 export default {
   name: "jobPlayDetail",
   dicts: ["ticket_type", "ticket_status"],
@@ -177,10 +177,7 @@ export default {
       ticketId:null
     };
   },
-  // mounted() {
-  //   localStorage.setItem('ticketId',this.$route.query.ticketId);
-  //   this.getJobPlayInfo();
-  // },
+
   created() {
     // 检查路由参数
     if (this.$route.query.ticketId) {
@@ -191,8 +188,13 @@ export default {
       // 从 localStorage 获取 ticketId
       this.ticketId = localStorage.getItem('ticketId');
     }
-  },
+    // this.initWebSocket();
 
+  },
+  // 页面销毁就停止webStocket
+  destroyed() {
+    // this.destory()
+  },
   mounted() {
     this.getJobPlayInfo();
     setInterval(() => {
@@ -200,6 +202,24 @@ export default {
     }, 5000);
   },
   methods: {
+    // initWebSocket(){
+    //   connectWebsocket('ws://192.168.1.127:9090/websocket/iot/127',{w:'S',},(res)=>{
+    //     console.log(res,'websocket接收服务器的数据');
+    //     if(res){
+    //
+    //     }
+    //   },
+    //     (err)=>{
+    //     console.log('断开重连',);
+    //     })
+    // },
+    // destory(){
+    //   closeWebsocket();//断开链接
+    // },
+    // // 发消息
+    // sendMsg(){
+    //   sendMsg('aaa');
+    // },
     getJobPlayInfo() {
       getJobPlayTicketInfo(this.ticketId).then((res) => {
         console.log(res, "作业执行详细信息");

+ 38 - 31
src/views/mes/md/segregationpoint/index.vue

@@ -266,7 +266,7 @@
       </div>
       <el-form ref="form" :model="form" :rules="rules" label-width="110px">
         <el-row>
-          <el-col :span="8">
+          <el-col :span="7">
             <el-form-item label="隔离点编码" prop="pointCode">
               <el-input
                 v-model="form.pointCode"
@@ -287,17 +287,6 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label-width="80" label="锁具名称" prop="lockTypeName">
-              <el-input
-                style="width: 300px"
-                v-model="form.lockTypeName"
-                placeholder="请输入锁具名称"
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="11">
             <el-form-item label="隔离点名称" prop="pointName">
               <el-input
                 style="width: 300px"
@@ -305,8 +294,11 @@
                 placeholder="请输入隔离点名称"
               />
             </el-form-item>
+
           </el-col>
-          <el-col :span="12">
+        </el-row>
+        <el-row>
+          <el-col :span="11">
             <el-form-item label="隔离点类型" prop="pointType">
               <el-select
                 style="width: 300px"
@@ -322,9 +314,33 @@
               </el-select>
             </el-form-item>
           </el-col>
+          <el-col :span="12">
+            <el-form-item label="作业区域" prop="workareaId">
+              <treeselect
+                style="width: 300px"
+                v-model="form.workareaId"
+                :options="deptOptions"
+                :normalizer="normalizer"
+                placeholder="选择作业区域"
+              />
+            </el-form-item>
+
+          </el-col>
         </el-row>
         <el-row>
 
+          <el-col :span="11">
+            <el-form-item label="挂锁类型" prop="lockTypeId">
+              <treeselect
+                style="width: 300px"
+                v-model="form.lockTypeId"
+                :options="padLockTypeOptions"
+                :normalizer="normalizerpadLock"
+                placeholder="选择挂锁类型"
+              />
+            </el-form-item>
+
+          </el-col>
           <el-col :span="11">
             <el-form-item label="危险能量类型" prop="powerType">
               <el-select
@@ -341,20 +357,9 @@
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="11">
-            <el-form-item label="作业区域" prop="workareaId">
-              <treeselect
-                style="width: 300px"
-                v-model="form.workareaId"
-                :options="deptOptions"
-                :normalizer="normalizer"
-                placeholder="选择作业区域"
-              />
-            </el-form-item>
-          </el-col>
         </el-row>
         <el-row>
-          <el-col :span="11">
+          <el-col :span="12">
             <el-form-item label="锁具类型" prop="locksetTypeId">
               <treeselect
                 style="width: 300px"
@@ -366,15 +371,14 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="挂锁类型" prop="lockTypeId">
-              <treeselect
+            <el-form-item label-width="80" label="锁具名称" prop="lockTypeName">
+              <el-input
                 style="width: 300px"
-                v-model="form.lockTypeId"
-                :options="padLockTypeOptions"
-                :normalizer="normalizerpadLock"
-                placeholder="选择挂锁类型"
+                v-model="form.lockTypeName"
+                placeholder="请输入锁具名称"
               />
             </el-form-item>
+
           </el-col>
         </el-row>
 
@@ -534,6 +538,9 @@ export default {
         ],
         pointType: [
           { required: true, message: '隔离点类型不能为空', trigger: 'blur' }
+        ],
+        lockTypeId:[
+          { required: true, message: '挂锁类型不能为空', trigger: 'blur' }
         ]
       }
     }

+ 2 - 1
src/views/mes/sop/sopm/NewSop.vue

@@ -341,7 +341,7 @@
       </div>
     </div>
     <!--    newSop盒子结束-->
-    <!-- 添加或修改设备维修单对话框 -->
+    <!-- 添加或修改外部人员对话框 -->
     <el-dialog
       :visible.sync="open"
       width="450px"
@@ -980,6 +980,7 @@ export default {
     addOutside() {
       this.open = true
       this.title = '添加外部人员'
+      this.OutSideUserTableData=[]
       this.insideMumber = false
       this.outsideMumber = true
       this.dialogForm.username = null