Explorar o código

feat(hnyzConfiguratePage):固液分离组态页面
feat(controlPage):固液分离控制页面
refactor(WebSocketPushTask):组态页面数据推送更新

HMY hai 8 meses
pai
achega
cb3ecd37a6

+ 1 - 1
admin/src/main/java/com/dcs/equipment/task/ModbusTcpTask.java

@@ -62,7 +62,7 @@ public class ModbusTcpTask {
         return broadCastEquipmentParamFormVOList;
     }
 
-    private void updateDataToEquipmentParamFormVOList() {
+    public void updateDataToEquipmentParamFormVOList() {
         // 获取设备响应数据
         Map<String, List<DeviceResponse>> deviceResponseMap = deviceService.getResponseMapByDeviceRequests(deviceRequestList);
 

+ 2 - 0
admin/src/main/java/com/dcs/hnyz/service/impl/PageControlServiceImpl.java

@@ -7,6 +7,7 @@ import java.util.Map;
 import java.util.stream.Collectors;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.dcs.common.enums.GeneralStatus;
 import com.dcs.common.utils.DateUtils;
 import com.dcs.hnyz.domain.Equipment;
 import com.dcs.hnyz.service.IEquipmentService;
@@ -114,6 +115,7 @@ public class PageControlServiceImpl implements IPageControlService
     @Override
     public List<PageControl> getPageList(Long equipmentId) {
         LambdaQueryWrapper<PageControl> wrapper=new LambdaQueryWrapper<>();
+        wrapper.eq(PageControl::getStatus, GeneralStatus.ENABLE.getCode());
         if(equipmentId==null){//不传设备id时默认查全部
             return pageControlMapper.selectList(wrapper);
         }

+ 6 - 7
admin/src/main/java/com/dcs/hnyz/task/WebSocketPushTask.java

@@ -2,6 +2,7 @@ package com.dcs.hnyz.task;
 
 import com.alibaba.fastjson2.JSON;
 import com.dcs.equipment.server.EquipmentListWebSocketServer;
+import com.dcs.equipment.task.ModbusTcpTask;
 import com.dcs.hnyz.cache.CacheCenter;
 import com.dcs.hnyz.domain.AlarmEvent;
 import com.dcs.hnyz.domain.dto.AlarmBroadcastPayload;
@@ -37,11 +38,14 @@ public class WebSocketPushTask {
 
     @Autowired
     private AlarmConfigServiceImpl alarmConfigService;
+
+    @Autowired
+    private ModbusTcpTask modbusTcpTask;
     /**
-     * 每3秒推送一次组态页面所需实时数据
+     * 每1秒推送一次组态页面所需实时数据
      */
-//     @Scheduled(fixedRate = 3000)
     public void pushData() {
+        modbusTcpTask.updateDataToEquipmentParamFormVOList();
         CacheCenter.pageDeviceGroupMap.forEach((pageCode, deviceGroupMap) -> {
             Map<String, List<PageDeviceRealtimeVO>> data = deviceDataService.buildRealtimeData(deviceGroupMap);
             messagingTemplate.convertAndSend("/topic/page/" + pageCode, data);
@@ -52,12 +56,7 @@ public class WebSocketPushTask {
     /**
      * 告警信息信息检测推送
      */
-//    @Scheduled(fixedRate = 1000)
     public void pushAlarmInfo(){
-        //测试数据
-//        CacheCenter.registerNowDataMap.put("S1wdsj", create("S1wdsj", 130));
-
-//        System.out.println("告警检测");
         List<AlarmEvent> alarms = alarmConfigService.checkAlarms();
         if (!alarms.isEmpty()) {
 //            System.out.println("有告警信息");

+ 1 - 0
ui/src/config.js

@@ -8,6 +8,7 @@ export const wsConfig = {
   equipmentTree: `ws://${BASE_URL}/webSocket/equipment/tree`,
   stompEndpoint: `http://${BASE_URL}/ws/configurationPage`, 
 };
+//TODO :导航栏配置改为数据库配置
 // 硫酸钠控制页面导航栏配置
 export const navItems_Na2SO4=[
   { label: 'MGM控制', code: 'MGM_Control', path: '/controlPage/flowSelect/mgm' },

+ 10 - 0
ui/src/router/index.js

@@ -157,6 +157,11 @@ export const constantRoutes = [
     component: () => import('@/views/controlPage/flowSelect/reaction/index'),
     name: 'Reaction_Control',//反应控制页面
   },
+  {
+    path: '/controlPage/flowSelect/solidLiquidSeparation',
+    component: () => import('@/views/controlPage/flowSelect/solidLiquidSeparation/index'),
+    name: 'SolidLiquidSeparation_Control',//一次固液分离控制页面
+  },
   //上海组态页面
   {
     path: '/m1sj',//水解:m1Hydrolyze
@@ -225,6 +230,11 @@ export const constantRoutes = [
     component: () => import('@/views/hnyzConfiguratePage/Na2SO4_FY/index'),
     name: 'Na2SO4_FY',
   },
+  {
+    path:'/Na2SO4_GYFL',//硫酸钠-固液分离
+    component: () => import('@/views/hnyzConfiguratePage/Na2SO4_GYFL/index'),
+    name: 'Na2SO4_GYFL',
+  },
   { // 页面设计器
     path: '/deviceState',
     hidden: false,

+ 9 - 6
ui/src/views/controlPage/flowSelect/reaction/index.vue

@@ -2,7 +2,7 @@
 <template>
     <div class="dcs">
         <!-- 顶部返回标题 -->
-        <HeaderComponent title="MGM控制页面" backTo="/controlPage/flowSelect" />
+        <HeaderComponent :title="title" backTo="/controlPage/flowSelect" />
 
         <!-- 顶部导航栏 -->
         <PageNav :items="navItems_Na2SO4" :currentCode="flowCode" />
@@ -12,16 +12,15 @@
             <h2 class="block-title">传感器</h2>
             <div class="group-row">
                 <SensorControl v-for="item in deviceConfigGroup.SENSORS" :key="item.code"
-                    :sensorArr="sensorHelper.getDataArrByCode(item.code)" :title="item.title"
-                    :code="item.code" />
+                    :sensorArr="sensorHelper.getDataArrByCode(item.code)" :title="item.title" :code="item.code" />
             </div>
         </div>
 
         <div v-if="deviceConfigGroup.PUMPS" class="block">
             <h2 class="block-title">泵</h2>
             <div class="group-row">
-                <PumpControlComponent v-for="item in deviceConfigGroup.PUMPS" :key="item.code"
-                    :title="item.title" :pumpArr="pumpHelper.getDataArrByCode(item.code)" :code="item.code" />
+                <PumpControlComponent v-for="item in deviceConfigGroup.PUMPS" :key="item.code" :title="item.title"
+                    :pumpArr="pumpHelper.getDataArrByCode(item.code)" :code="item.code" />
             </div>
         </div>
 
@@ -48,7 +47,11 @@ import { updateZTPageConfig } from '@/api/dcs/configurePage';
 import { getEquipmentGroup } from '@/api/hnyz/equipment'
 import { useEquipmentLayout } from '@/hooks/useEquipmentLayout';
 import { navItems_Na2SO4 } from '@/config';
-const flowCode = 'Reaction_Control'
+import { useRoute } from 'vue-router'
+const route = useRoute()
+const flowCode = route.name
+const title = navItems_Na2SO4.find(item => item.code === flowCode).label
+
 const { generatePageParams } = useEquipmentLayout()
 const deviceConfigGroup = ref({})
 const pageParams = ref({})

+ 147 - 0
ui/src/views/controlPage/flowSelect/solidLiquidSeparation/index.vue

@@ -0,0 +1,147 @@
+<!-- src/views/control/MGMControlPage.vue -->
+<template>
+    <div class="dcs">
+        <!-- 顶部返回标题 -->
+        <HeaderComponent :title="title" backTo="/controlPage/flowSelect" />
+
+        <!-- 顶部导航栏 -->
+        <PageNav :items="navItems_Na2SO4" :currentCode="flowCode" />
+
+        <!-- 控制组件区域 -->
+        <div v-if="deviceConfigGroup.SENSORS" class="block">
+            <h2 class="block-title">传感器</h2>
+            <div class="group-row">
+                <SensorControl v-for="item in deviceConfigGroup.SENSORS" :key="item.code"
+                    :sensorArr="sensorHelper.getDataArrByCode(item.code)" :title="item.title" :code="item.code" />
+            </div>
+        </div>
+
+        <div v-if="deviceConfigGroup.PUMPS" class="block">
+            <h2 class="block-title">泵</h2>
+            <div class="group-row">
+                <PumpControlComponent v-for="item in deviceConfigGroup.PUMPS" :key="item.code" :title="item.title"
+                    :pumpArr="pumpHelper.getDataArrByCode(item.code)" :code="item.code" />
+            </div>
+        </div>
+
+        <div v-if="deviceConfigGroup.VALVES" class="block">
+            <h2 class="block-title">阀门</h2>
+            <div class="group-row">
+                <ValveControlComponent v-for="item in deviceConfigGroup.VALVES" :key="item.code"
+                    :title="item.equipmentName" :valveArr="valveHelper.getDataArrByCode(item.code)" :code="item.code" />
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import PageNav from '@/components/GeneralComponents/control/PageNavComponent.vue';
+import SensorControl from '@/components/GeneralComponents/control/SensorControlComponent.vue';
+import PumpControlComponent from '@/components/GeneralComponents/control/PumpControlComponent.vue';
+import ValveControlComponent from '@/components/GeneralComponents/control/ValveControlComponent.vue';
+import HeaderComponent from '@/components/DCS/HeaderComponent.vue';
+import { useValveHelper } from '@/hooks/useValveHelper'
+import { computed, onMounted, onBeforeUnmount, reactive, ref } from 'vue';
+import { stompClient } from '@/utils/ws/stompClient';
+import { updateZTPageConfig } from '@/api/dcs/configurePage';
+import { getEquipmentGroup } from '@/api/hnyz/equipment'
+import { useEquipmentLayout } from '@/hooks/useEquipmentLayout';
+import { navItems_Na2SO4 } from '@/config';
+import { useRoute } from 'vue-router'
+const route = useRoute()
+const flowCode = route.name
+const title = navItems_Na2SO4.find(item => item.code === flowCode).label
+
+const { generatePageParams } = useEquipmentLayout()
+const deviceConfigGroup = ref({})
+const pageParams = ref({})
+
+const valveArr = []
+const pumpArr = []
+const sensorArr = []
+
+const deviceDataGroup = reactive({
+    VALVES: valveArr,
+    PUMPS: pumpArr,
+    SENSORS: sensorArr,
+})
+
+onMounted(() => {
+    getEquipmentGroup(flowCode).then(res => {
+        deviceConfigGroup.value = res.data
+        pageParams.value = generatePageParams(res.data)
+        updatePageConfig()
+    })
+})
+
+onBeforeUnmount(() => {
+    stompClient.unsubscribeFromPage(flowCode)
+})
+
+function updatePageConfig() {
+    updateZTPageConfig(flowCode, pageParams.value)
+        .then(() => {
+            stompClient.subscribeToPage(flowCode, (data) => {
+                // console.log('收到页面数据:', data)
+                deviceDataGroup.VALVES = Object.values(data.VALVES || {})
+                deviceDataGroup.PUMPS = Object.values(data.PUMPS || {})
+                deviceDataGroup.SENSORS = Object.values(data.SENSORS || {})
+            })
+        })
+        .catch(err => {
+            console.log('页面配置失败:', err)
+        });
+}
+
+const pumpHelper = useValveHelper(computed(() => deviceDataGroup.PUMPS))
+const valveHelper = useValveHelper(computed(() => deviceDataGroup.VALVES))
+const sensorHelper = useValveHelper(computed(() => deviceDataGroup.SENSORS))
+</script>
+
+<style scoped lang="scss">
+.dcs {
+    width: 100%;
+    min-height: 100vh;
+    padding: 24px 32px;
+    background-color: #141414;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.block {
+    margin-bottom: 32px;
+    background: #1a1a1a;
+    padding: 16px;
+    border: 1px solid #333;
+    border-radius: 12px;
+    max-width: 1200px;
+    width: 100%;
+    animation: fadeInUp 0.4s ease;
+}
+
+.block-title {
+    font-size: 20px;
+    color: #fff;
+    margin-bottom: 12px;
+}
+
+.group-row {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12px 20px;
+    justify-content: flex-start;
+}
+
+@keyframes fadeInUp {
+    from {
+        opacity: 0;
+        transform: translateY(20px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translateY(0);
+    }
+}
+</style>

+ 5 - 5
ui/src/views/hnyzConfiguratePage/Na2SO4_FY/index.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="page">
-        <HeaderComponent title="反应流程"></HeaderComponent>
+        <HeaderComponent :title="title"></HeaderComponent>
         <div class="content_page">
             <PageDrawer :pages="pageItems_Na2SO4" class="page_drawer" />
             <!-- 阀门 -->
@@ -27,9 +27,9 @@
             <!-- 传感器 -->
             <div class="sensors">
                 <component v-for="item in deviceConfigGroup.SENSORS" :key="item.id" :is="getComponentName(item.modelId)"
-                    :title="getEquipmentTitle(item.equipmentName)"
+                    :title="getEquipmentTitle(item.equipmentName)" :sensorSize="item.size"
                     :sensorValue="sensorHelper.getDataArrByCode(item.code)" :sensorWidth="item.width"
-                    :sensorHeight="item.height" :sensorSize="item.size" :style="getComponentStyle(item)" />
+                    :sensorHeight="item.height" :style="getComponentStyle(item)" />
             </div>
 
             <!-- 其他设备 -->
@@ -60,16 +60,16 @@
 <script setup>
 import PageDrawer from '@/components/GeneralComponents/PageDrawerComponent.vue';
 import { computed, onMounted, onBeforeUnmount, reactive } from 'vue';
-import { useRoute } from 'vue-router'
 import { useValveHelper } from '@/hooks/useValveHelper'
 import { stompClient } from '@/utils/ws/stompClient';
 import { useEquipmentLayout } from '@/hooks/useEquipmentLayout'
 import { useComponentHelper } from '@/hooks/useComponentHelper'
 import { updateZTPageConfig } from '@/api/dcs/configurePage';
 import { pageItems_Na2SO4 } from "@/config"
+import { useRoute } from 'vue-router'
 const route = useRoute()
 const pageCode = route.name
-
+const title = pageItems_Na2SO4.find(item => item.code === pageCode).label
 // 获取设备布局 & 数据订阅
 const {
     pipeConfig,//管道配置信息

+ 165 - 0
ui/src/views/hnyzConfiguratePage/Na2SO4_GYFL/index.vue

@@ -0,0 +1,165 @@
+<template>
+    <div class="page">
+        <HeaderComponent :title="title"></HeaderComponent>
+        <div class="content_page">
+            <PageDrawer :pages="pageItems_Na2SO4" class="page_drawer" />
+            <!-- 阀门 -->
+            <div class="valves">
+                <component v-for="item in deviceConfigGroup.VALVES" :key="item.id" :is="getComponentName(item.modelId)"
+                    :title="getEquipmentTitle(item.equipmentName)" :valveStatusArr="getDataArrByCode(item.code)"
+                    :rotateAngle="item.rotate || 0" :iconSize="item.size" :style="getComponentStyle(item)" />
+            </div>
+
+            <!-- 泵 -->
+            <div class="pumps">
+                <component v-for="item in deviceConfigGroup.PUMPS" :key="item.id" :is="getComponentName(item.modelId)"
+                    :title="getEquipmentTitle(item.title)" :pumpDataArr="pumpHelper.getDataArrByCode(item.code)"
+                    :isReverse="item.isReverse" :iconSize="item.size" :style="getComponentStyle(item)" />
+            </div>
+
+            <!-- 罐体 -->
+            <div class="tanks">
+                <component v-for="item in deviceConfigGroup.TANKS" :key="item.id" :is="getComponentName(item.modelId)"
+                    :title="getEquipmentTitle(item.equipmentName)" :iconSize="item.size" :iconWidth="item.width"
+                    :iconHeight="item.height" :style="getComponentStyle(item)" />
+            </div>
+
+            <!-- 传感器 -->
+            <div class="sensors">
+                <component v-for="item in deviceConfigGroup.SENSORS" :key="item.id" :is="getComponentName(item.modelId)"
+                    :title="getEquipmentTitle(item.equipmentName)" :sensorSize="item.size"
+                    :sensorValue="sensorHelper.getDataArrByCode(item.code)" :sensorWidth="item.width"
+                    :sensorHeight="item.height" :style="getComponentStyle(item)" />
+            </div>
+
+            <!-- 其他设备 -->
+            <div class="icon_others">
+                <component v-for="item in deviceConfigGroup.ICONS" :key="item.id" :is="getComponentName(item.modelId)"
+                    :iconSize="item.size" :iconClass="getIconClass(item.modelId)" :style="getComponentStyle(item)"
+                    :title="getEquipmentTitle(item.equipmentName)" />
+            </div>
+
+            <!-- 管道  -->
+            <div class="pipelines">
+                <component v-for="item in pipeConfig" :key="item.id" :is="getComponentName(item.modelId)"
+                    :pipeStatus="evaluateCondition(item.flowCondition, true)" :strokeWidth="item.pipeWidth"
+                    :style="getPipelineStyle(item, evaluateCondition(item.reverseCondition))"
+                    :class="getPipelineClass(item.pipeClass, getPipeType(item.dynamicPipelineCondition))" />
+            </div>
+
+            <!-- 大箭头指向 -->
+            <div class="arrows">
+                <component v-for="item in deviceConfigGroup.ARROWS" :key="item.id" :is="getComponentName(item.modelId)"
+                    :arrowText="getEquipmentTitle(item.equipmentName)" :iconSize="item.size"
+                    :specialCondition="JSON.parse(item.specialCondition)" :style="getComponentStyle(item)" />
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import PageDrawer from '@/components/GeneralComponents/PageDrawerComponent.vue';
+import { computed, onMounted, onBeforeUnmount, reactive } from 'vue';
+import { useValveHelper } from '@/hooks/useValveHelper'
+import { stompClient } from '@/utils/ws/stompClient';
+import { useEquipmentLayout } from '@/hooks/useEquipmentLayout'
+import { useComponentHelper } from '@/hooks/useComponentHelper'
+import { updateZTPageConfig } from '@/api/dcs/configurePage';
+import { pageItems_Na2SO4 } from "@/config"
+import { useRoute } from 'vue-router'
+const route = useRoute()
+const pageCode = route.name
+const title = pageItems_Na2SO4.find(item => item.code === pageCode).label
+// 获取设备布局 & 数据订阅
+const {
+    pipeConfig,//管道配置信息
+    deviceConfigGroup,//设备配置分组
+    modelMap,//设备模型映射
+    pageParams,//页面参数
+    fetchPageConfig,//获取页面配置
+} = useEquipmentLayout(pageCode)
+
+// 组件渲染辅助方法
+const {
+    getComponentName,
+    getComponentStyle,
+    getIconClass,
+    getEquipmentTitle,
+    getPipelineClass,
+    getPipelineStyle,
+} = useComponentHelper(modelMap)
+
+
+onMounted(async () => {
+    await fetchPageConfig(pageCode).then(res => {
+        updatePageConfig()
+    })
+})
+
+onBeforeUnmount(() => {
+    // 页面销毁时取消订阅
+    stompClient.unsubscribeFromPage(pageCode);
+});
+
+//阀门数据初始化
+const valveArr = [
+]
+//传感器数据初始化
+const sensorArr = [
+]
+//泵数据初始化
+const pumpArr = [
+]
+
+//设备数据分组
+const deviceDataGroup = reactive({
+    VALVES: valveArr,
+    PUMPS: pumpArr,
+    SENSORS: sensorArr,
+})
+
+//更新页面配置
+function updatePageConfig() {
+    updateZTPageConfig(pageCode, pageParams.value)
+        .then(res => {
+            stompClient.subscribeToPage(pageCode, (data) => {
+                deviceDataGroup.VALVES = Object.values(data?.VALVES || {});
+                deviceDataGroup.PUMPS = Object.values(data?.PUMPS || {});
+                deviceDataGroup.SENSORS = Object.values(data?.SENSORS || {});
+            });
+        })
+        .catch(err => {
+            console.log('页面配置失败:', err);
+        });
+}
+const pumpHelper = useValveHelper(computed(() => deviceDataGroup.PUMPS))
+const { getDataArrByCode } = useValveHelper(computed(() => deviceDataGroup.VALVES))
+const sensorHelper = useValveHelper(computed(() => deviceDataGroup.SENSORS))
+const {
+    evaluateCondition, getPipeType
+} = useValveHelper(computed(() => [...deviceDataGroup.VALVES, ...deviceDataGroup.PUMPS]))
+
+
+</script>
+
+<style lang="scss" scoped>
+.page {
+    // width: 100%;
+    // height: 100%;
+    width: 1920px;
+    height: 1080px;
+    background-color: #0b172c;
+
+    .content_page {
+        position: relative;
+        width: 100%;
+        height: 1000px;
+
+        .page_drawer {
+            position: absolute;
+            right: 2%;
+            top: -1%;
+        }
+    }
+}
+</style>