wenhongquan 2 ani în urmă
părinte
comite
f57236076d

+ 2 - 0
ruoyi-system/src/main/java/com/ruoyi/data/domain/vo/TblRecordVo.java

@@ -42,4 +42,6 @@ public class TblRecordVo implements Serializable {
 
     private Long sensorId;
 
+    private Date createTime;
+
 }

+ 2 - 1
ruoyi-system/src/main/java/com/ruoyi/data/service/impl/MqttServiceImpl.java

@@ -78,6 +78,7 @@ public class MqttServiceImpl implements MqttService {
 
     @Override
     public void pubMqttData(String mqttStr) {
+        websocketService.sendMessageAll(mqttStr);
         if(saveAndForward) {
 
             JSONObject jsonObject = new JSONObject(mqttStr);
@@ -117,7 +118,7 @@ public class MqttServiceImpl implements MqttService {
 //        tblSensorRecord.setUpdateBy("admin");
 //        updateNowRecord(tblSensorRecord);
         CacheUtils.put("sensorData",sensorId,mqttMsg.toString());
-        websocketService.sendMessageAll(mqttStr);
+
 //      tblSensorRecordMapper.insert(tblSensorRecord);
         String protocolType = "";
         List<SysDictData> sysDictTypeList = sysDictTypeService.selectDictDataByType("protocal_type");

+ 6 - 0
ruoyi-system/src/main/java/com/ruoyi/data/service/impl/TblRecordServiceImpl.java

@@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.PageQuery;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.data.domain.TblSensor;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import com.ruoyi.data.domain.bo.TblRecordBo;
@@ -63,6 +64,11 @@ public class TblRecordServiceImpl implements ITblRecordService {
         LambdaQueryWrapper<TblRecord> lqw = Wrappers.lambdaQuery();
         lqw.eq(StringUtils.isNotBlank(bo.getJson()), TblRecord::getJson, bo.getJson());
         lqw.eq(bo.getEquipmentId() != null, TblRecord::getEquipmentId, bo.getEquipmentId());
+        if(bo.getParams()!=null && bo.getParams().get("name")!=null){
+            lqw.like(TblRecord::getJson, "%"+bo.getParams().get("name")+"%");
+        }
+
+
         return lqw;
     }
 

+ 5 - 0
ruoyi-ui-vue3/src/App.vue

@@ -5,11 +5,16 @@
 <script setup>
 import useSettingsStore from '@/store/modules/settings'
 import { handleThemeStyle } from '@/utils/theme'
+import useWSStore from "@/store/modules/websocket";
 
+import {closeWebSocket, dostartWebSocket, initWebSocket} from "@/utils/websocket";
+dostartWebSocket();
 onMounted(() => {
   nextTick(() => {
     // 初始化主题样式
     handleThemeStyle(useSettingsStore().theme)
   })
+
+
 })
 </script>

+ 45 - 0
ruoyi-ui-vue3/src/api/data/record.js

@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+
+// 查询record配置列表
+export function listRecord(query) {
+  return request({
+    url: '/data/record/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询record配置详细
+export function getRecord(id) {
+  return request({
+    url: '/data/record/' + id,
+    method: 'get'
+  })
+}
+
+
+// 新增record配置
+export function addRecord(data) {
+  return request({
+    url: '/data/record',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改record配置
+export function updateRecord(data) {
+  return request({
+    url: '/data/record',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除record配置
+export function delRecord(id) {
+  return request({
+    url: '/data/record/' + id,
+    method: 'delete'
+  })
+}

+ 2 - 0
ruoyi-ui-vue3/src/main.js

@@ -88,3 +88,5 @@ app.use(ElementPlus, {
 app._context.components.ElDialog.props.closeOnClickModal.default = false
 
 app.mount('#app')
+
+

+ 21 - 1
ruoyi-ui-vue3/src/store/modules/websocket.js

@@ -1,11 +1,31 @@
+
+import moment from "moment";
 const useWSStore = defineStore(
   'ws',
   {
     state: () => ({
       isConnected: false,
-      message: '',
+      message: {},
     }),
     actions: {
+      setMessage(message) {
+
+        let data = message;
+        data.data.forEach(i=>{
+          if(!this.message[`${data.sensorId}`]){
+            this.message[`${data.sensorId}`] = {};
+          }
+          this.message[`${data.sensorId}`][i.name] = { value:i.value,unit:i.unitType,time:moment().format('YYYY-MM-DD HH:mm:ss') }
+        })
+      },
+      getMessage() {
+        // 获取 message 状态
+        return this.message
+      },
+      isConnected() {
+        // 返回当前的 isConnected 状态
+        return this.isConnected
+      },
       connect() {
         // 连接成功后,将 isConnected 状态设置为 true
         this.isConnected = true

+ 30 - 66
ruoyi-ui-vue3/src/utils/websocket.ts

@@ -5,19 +5,11 @@ let websocket: WebSocket | null = null; // 用于存储实例化后websocket
 let rec: any; // 断线重连后,延迟5秒重新创建WebSocket连接  rec用来存储延迟请求的代码
 // @ts-ignore
 const baseUrl = import.meta.env.VITE_APP_WS_API;
-const store = useWSStore();
+
 // 创建websocket
 function creatWebSocket(wsUrl: string) {
-  wsUrl = baseUrl+wsUrl;
-  wsUrl = wsUrl.replace("http","ws");
-  wsUrl = wsUrl.replace("https","wss");
-  if(wsUrl.indexOf("ws") == -1){
-    var start =  window.location.href.split("://")[0];
-    start = start.replace("http","ws");
-    start = start.replace("https","wss");
-    wsUrl =start+"://"+ window.location.href.split("://")[1].split("/")[0]+wsUrl
-  }
-  console.log("websocket==================");
+
+  console.log("websocket=================="+wsUrl);
   // 判断当前浏览器是否支持WebSocket
   if ("WebSocket" in window) {
     console.log("当前浏览器支持 WebSocket");
@@ -31,19 +23,27 @@ function creatWebSocket(wsUrl: string) {
   try {
     initWebSocket(wsUrl); // 初始化websocket连接
   } catch (e) {
+    debugger
     console.log("尝试创建连接失败");
     reConnect(wsUrl); // 如果无法连接上 webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
   }
 }
 
 
-
 // 初始化websocket
 function initWebSocket(wsUrl: string) {
-  websocket = new WebSocket(wsUrl);
-  console.log("websocket:", websocket);
-
+  wsUrl = baseUrl+wsUrl;
+  wsUrl = wsUrl.replace("http","ws");
+  wsUrl = wsUrl.replace("https","wss");
 
+  if(wsUrl.indexOf("s://") == -1){
+    var start =  window.location.href.split("://")[0];
+    start = start.replace("http","ws");
+    start = start.replace("https","wss");
+    wsUrl =start+"://"+ window.location.href.split("://")[1].split("/")[0]+wsUrl
+  }
+  websocket = new WebSocket(wsUrl);
+  // console.log("websocket:", websocket);
   websocket.onopen = function () {
     websocketOpen();
   };
@@ -72,9 +72,9 @@ function initWebSocket(wsUrl: string) {
 
 // 定义重连函数
 let reConnect = (wsUrl: string) => {
-
+debugger
   console.log("尝试重新连接");
-  if (store.state.isConnected) return; // 如果已经连上就不在重连了
+  if (useWSStore().isConnected()) return; // 如果已经连上就不在重连了
   rec && clearTimeout(rec);
   rec = setTimeout(function () {
     // 延迟5秒重连  避免过多次过频繁请求重连
@@ -86,57 +86,14 @@ let reConnect = (wsUrl: string) => {
 // 创建连接
 function websocketOpen() {
   console.log("连接成功");
-  store.connect(); // 修改连接状态
+  useWSStore().connect(); // 修改连接状态
 }
 // 数据接收
 function websocketonmessage(e: MessageEvent<any>) {
-  console.log("数据接收", e.data);
+  // console.log("数据接收", e.data);
   const data = JSON.parse(e.data);  // 解析JSON格式的数据
-  store.state.message = data;
-  // 下面的判断则是后台返回的接收到的数据  如何处理自己决定
-  if (data.code === 400) {
-    console.log("数据接收", data.msg);
-    ElMessage({
-      showClose: true,
-      message: data.msg,
-      type: 'warning',
-    })
-
-
-  } else if (data.code === 404) {
-    ElMessage({
-      showClose: true,
-      message: data.msg,
-      type: 'warning',
-    })
-  } else if (data.code === 0) {
-    ElMessage({
-      showClose: true,
-      message: "连接成功",
-
+  useWSStore().setMessage(data); // 存储数据
 
-      type: 'success',
-    })
-  } else if (data.code === 200) {
-    ElMessage({
-      showClose: true,
-      message: data.msg,
-      type: 'success',
-    })
-    // 成功后的相应处理  此处成功后播放音乐
-    const audio = new Audio('./tipMusic.mp3');
-    audio.play();
-  } else {
-    ElMessage({
-      showClose: true,
-      message: data.msg,
-      type: 'error',
-    })
-    // 延时5秒后刷新页面
-    setTimeout(() => {
-      location.reload();
-    }, 1000);
-  }
 
   // let data = JSON.parse(decodeUnicode(e.data))
 }
@@ -146,7 +103,7 @@ function websocketonmessage(e: MessageEvent<any>) {
 // 关闭
 function websocketclose(e: any) {
   console.log(e);
-  store.disconnect(); // 修改连接状态
+  useWSStore().disconnect(); // 修改连接状态
   console.log("connection closed (" + e.code + ")");
 }
 
@@ -155,7 +112,7 @@ function websocketclose(e: any) {
 // 数据发送
 function websocketsend(data: any) {
   console.log("发送的数据", data, JSON.stringify(data));
-  if (websocket && store.state.isConnected) { // 检查连接状态
+  if (websocket && useWSStore().isConnected()) { // 检查连接状态
     websocket.send(JSON.stringify(data));
 
   } else {
@@ -173,7 +130,7 @@ function websocketsend(data: any) {
 // 发送
 function sendWebSocket(data: any) {
   // 如果未保持连接状态 不允许直接发送消息 提示请选择连接设备
-  if (!store.state.isConnected) {
+  if (!useWSStore().isConnected()) {
     ElMessage({
       showClose: true,
       message: "请选择设备连接",
@@ -202,9 +159,16 @@ let closeWebSocket = () => {
 };
 
 
+let dostartWebSocket = () => {
+  if (!websocket) {
+    initWebSocket("/ws/realtimedata/ss");
+  }
+};
+
 export {
   initWebSocket,
   sendWebSocket,
   creatWebSocket,
   closeWebSocket,
+  dostartWebSocket,
 }

+ 103 - 3
ruoyi-ui-vue3/src/views/device/sensordash/index.vue

@@ -250,10 +250,34 @@
     >
       <div>
 <!--        显示测点实时数据-->
+        <el-table @cellClick="doshowhistory" :data="JSON.parse(currentsensor.datapoints)" style="margin-top: 15px" height="150px">
+          <el-table-column label="变量名" prop="name">
+            <template #default="scope">
+              <span>{{scope.row.name}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="数值" prop="name">
+            <template #default="scope">
+              <span>{{ (useWSStore().getMessage()[currentsensor.id])?(useWSStore().getMessage()[currentsensor.id][scope.row.name]?.value):'-' }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="单位" prop="name">
+            <template #default="scope">
+              <span>{{scope.row.unitType}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="时间" prop="name">
+            <template #default="scope">
+              <span>{{ (useWSStore().getMessage()[currentsensor.id])?(useWSStore().getMessage()[currentsensor.id][scope.row.name]?.time):'-' }}</span>
+            </template>
+          </el-table-column>
+        </el-table>
 
       </div>
       <div>
+        <div style="margin-top: 10px" v-if="currentname!=''">变量 {{currentname}} 数值曲线</div>
 <!--        显示历史数据 折线图-->
+        <div ref="chartlinediv" style="height: 400px" v-loading="isloading" ></div>
 
 
       </div>
@@ -262,7 +286,7 @@
 </template>
 
 <script setup>
-import {onMounted, ref} from "vue";
+import {onMounted, ref, watch, watchEffect} from "vue";
 import {LayTree} from "@layui/layui-vue";
 import "@layui/layui-vue/lib/index.css";
 import {useRoute, useRouter} from "vue-router";
@@ -271,9 +295,13 @@ import {listEquipmentSbook} from "@/api/data/equipmentSbook"
 import {listSensor,delSensor,addSensor,updateSensor} from "@/api/data/sensor"
 import {listDatapoint} from "@/api/data/datapoint";
 import {listUnit} from "@/api/data/unit";
+import useWSStore from "@/store/modules/websocket"
+import {listRecord} from "@/api/data/record"
+import * as echarts from 'echarts';
+
 
-import {closeWebSocket,creatWebSocket } from "@/utils/websocket";
 import {ElMessage, ElMessageBox} from "element-plus";
+import moment from "moment";
 
 const {proxy} = getCurrentInstance();
 const {protocal_type, sensor_type, sensor_status} = proxy.useDict("protocal_type", "sensor_type", "sensor_status");
@@ -293,7 +321,6 @@ const cloumdata = ref([
   {label: '类型', prop: 'sensorType', visible: true},
 ])
 
-creatWebSocket("/ws/realtimedata/ss");
 
 const onchangepage = (page) => {
   pagedata.value.current = page;
@@ -491,6 +518,79 @@ const dosave = ()=>{
   })
 }
 
+const historytabledata = ref([]);
+const chartlinediv = ref(null)
+const currentname = ref("")
+const isloading = ref(false);
+watchEffect(()=>{
+  if(currentsensor.value && useWSStore().getMessage()[currentsensor.value.id]  && useWSStore().getMessage()[currentsensor.value.id][currentname.value] ){
+    let data = useWSStore().getMessage()[currentsensor.value.id][currentname.value];
+    historytabledata.value.push([moment(data.time).toDate(),data.value]);
+  }
+  if(historytabledata.value.length>0){
+    const usedmemoryInstance = echarts.init(chartlinediv.value, "macarons");
+    usedmemoryInstance.setOption( {
+      tooltip: {
+        trigger: 'axis',
+        position: function (pt) {
+          return [pt[0], '10%'];
+        }
+      },
+      xAxis: {
+        type: 'time',
+        boundaryGap: false,
+      },
+      yAxis: {
+        type: 'value',
+      },
+      dataZoom: [
+        {
+          type: 'inside',
+          start: 0,
+          end: 20
+        },
+        {
+          start: 0,
+          end: 20
+        }
+      ],
+      series: [
+        {
+          name:currentname.value,
+          data: historytabledata.value,
+          type: 'line',
+          smooth: true
+        }
+      ]
+    });
+    window.addEventListener("resize",()=>{
+      usedmemoryInstance.resize()
+    });
+  }else{
+    if(chartlinediv.value){
+      chartlinediv.value.innerHTML = "请选择监测点";
+    }
+
+  }
+
+
+})
+const doshowhistory = (row)=>{
+  isloading.value = true;
+  currentname.value = row.name;
+  //获取历史数据
+  listRecord({sensorId:currentsensor.value.id,page:1,pageSize:100,orderByColumn:"create_time",isAsc:"desc",params:{name:row.name}}).then(res=>{
+    const {rows,total,page,size} = res;
+    isloading.value = false;
+    historytabledata.value = rows.map(i=>{
+      var j = JSON.parse(i.json);
+      console.log(j.data[0].value)
+      return [moment(i.createTime).toDate(),j.data[0].value]
+    });
+  })
+}
+
+
 </script>
 
 <style lang="scss">

+ 1 - 0
ruoyi-ui-vue3/vite.config.js

@@ -37,6 +37,7 @@ export default defineConfig(({ mode, command }) => {
         '/dev-ws': {
           target: 'ws://localhost:8989',
           changeOrigin: true,
+          ws: true,
           rewrite: (p) => p.replace(/^\/dev-ws/, '')
         }
       }