Преглед изворни кода

Merge remote-tracking branch 'origin/master'

wuhb пре 8 месеци
родитељ
комит
76bc1fab9f

+ 4 - 2
admin/src/main/java/com/dcs/hnyz/service/impl/ActionConfigServiceImpl.java

@@ -352,9 +352,11 @@ public class ActionConfigServiceImpl implements IActionConfigService {
                     //针对泵类数据
                     if(Objects.equals(equipment.getEquipmentType(), DeviceTypeEnum.PUMP.getCode())){
                         List<EquipmentParam> allSetParam = equipmentParamService.getAllSetParam(equipment.getCode());
-                        EquipmentParam slaveSetParam = allSetParam.get(1);
                         ModbusUtil.setRegisterValues(hort, port, slaveId, address, new int[]{1});
-                        ModbusUtil.setRegisterValues(slaveSetParam.getIpAddress(), slaveSetParam.getPort(), slaveSetParam.getUnitId(), slaveSetParam.getAddress(),new int[]{0});
+                        if(allSetParam.size()>1){//部分泵只有状态设置
+                            EquipmentParam slaveSetParam = allSetParam.get(1);
+                            ModbusUtil.setRegisterValues(slaveSetParam.getIpAddress(), slaveSetParam.getPort(), slaveSetParam.getUnitId(), slaveSetParam.getAddress(),new int[]{0});
+                        }
                     }else{//阀门类型
                         ModbusUtil.setCoilValue(hort, port, slaveId, address, false);
                     }

+ 11 - 2
ui/src/components/GeneralComponents/MTypeHollowTankComponent.vue

@@ -3,7 +3,9 @@
     <div class="tank_body" :style="getTankBodyStyle">
         <i class="icon iconfont-colour icon-tank1 tank_icon" :style="getTankStyle">
             <!-- 标题 -->
-            <div class="tank_title" v-if="title">{{ title }}</div>
+            <div class="tank_title" v-if="title" :style="{ fontSize: titleFontSize }">
+                {{ title }}
+            </div>
         </i>
     </div>
 </template>
@@ -53,7 +55,14 @@ const getTankStyle = computed(() => {
 
     return style
 })
-
+// 根据标题长度动态设置字体大小
+const titleFontSize = computed(() => {
+    const len = props.title.length
+    if (len <= 4) return iconSize.value *0.15 + 'px'
+    if (len <= 8) return iconSize.value *0.1 + 'px'
+    if (len <= 12) return iconSize.value *0.08 + 'px'
+    return iconSize.value *0.06 + 'px'
+})
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
ui/src/components/GeneralComponents/PhSliderComponent.vue

@@ -62,7 +62,7 @@ const marks = computed(() => {
 
 // 动态样式
 const sliderStyle = computed(() => ({
-    '--marks-font-size': `${props.sensorWidth * 0.9}px`,
+    '--marks-font-size': `${Math.max(props.sensorWidth * 0.9, 18)}px`,
     '--runway-width': `${props.sensorWidth}px`,
     '--slider-height': props.sensorHeight ? `${props.sensorHeight}px` : '0.5em',
 }))

+ 46 - 10
ui/src/components/GeneralComponents/STypeHollowTankComponent.vue

@@ -1,14 +1,17 @@
 <template>
-    <div class="tank" :style="{ width: `${iconSize}px`, height: `${iconSize}px` }">
-        <!-- S镂空罐体 -->
-        <i class="icon iconfont-colour icon-tank3 tank_s" :style="{ fontSize: iconSize + 'px' }">
-            <div class="tank_title" v-if="title">{{ title }}</div>
+    <div class="tank">
+        <!-- 方形镂空罐体图标 -->
+        <i class="icon iconfont-colour icon-tank3 tank_s" :style="getTankStyle">
+            <div class="tank_title" v-if="title" :style="{ fontSize: titleFontSize }">
+                {{ title }}
+            </div>
         </i>
+
     </div>
 </template>
 
 <script setup>
-import { defineProps } from 'vue'
+import { defineProps, computed } from 'vue'
 
 const props = defineProps({
     title: {
@@ -19,13 +22,46 @@ const props = defineProps({
         type: Number,
         default: 400
     },
+    iconWidth: {
+        type: Number,
+    },
+    iconHeight: {
+        type: Number,
+    },
+})
+
+// 根据标题长度动态设置字体大小
+const titleFontSize = computed(() => {
+    const len = props.title.length
+    if (len <= 4) return '24px'
+    if (len <= 8) return '16px'
+    if (len <= 12) return '14px'
+    return '12px'
 })
 
+const fontSize = computed(() => props.iconSize ?? 200)
+
+// 罐子样式
+const getTankStyle = computed(() => {
+    const style = {
+        fontSize: fontSize.value + 'px',
+        display: 'inline-block'
+    }
+    const scaleX = props.iconWidth ? props.iconWidth / fontSize.value : 1
+    const scaleY = props.iconHeight ? props.iconHeight / fontSize.value : 1
+
+    if (scaleX !== 1 || scaleY !== 1) {
+        style.transform = `scale(${scaleX}, ${scaleY})`
+        style['--scale-x'] = scaleX
+        style['--scale-y'] = scaleY
+    }
+
+    return style
+})
 </script>
 
 <style lang="scss" scoped>
 .tank {
-    // margin: 200px;
     position: relative;
     z-index: 10;
 
@@ -33,16 +69,16 @@ const props = defineProps({
         position: relative;
         z-index: 10;
 
-        //罐子名称
         .tank_title {
             position: absolute;
             top: 6%;
             left: 50%;
-            transform: translate(-50%, -50%);
-            font-size: 24px;
+            transform: translate(-50%, -50%) scale(calc(1 / var(--scale-x, 1)), calc(1 / var(--scale-y, 1)));
             color: #e65100;
             font-weight: bold;
+            z-index: 20;
+            pointer-events: none;
         }
     }
 }
-</style>
+</style>

+ 1 - 1
ui/src/components/GeneralComponents/control/PageNavComponent.vue

@@ -40,7 +40,7 @@ const goToPage = (item) => {
     padding: 12px 24px;
     border-radius: 12px;
     width: 100%;
-    max-width: 800px;
+    max-width: 1100px;
     margin: 16px auto;
     box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
 }

+ 5 - 8
ui/src/components/GeneralComponents/control/PumpControlComponent.vue

@@ -37,7 +37,7 @@
                             <div class="body_show_value">
                                 {{ (pumpDataArr[1] / 50) || 0 }}
                             </div>
-                            <div class="body_show_unit">%</div>
+                            <div class="body_show_unit">{{ pumpSetArr[1].unitType || '%' }}</div>
                         </div>
                     </div>
                     <div class="show_detail">
@@ -50,7 +50,7 @@
                                 <el-input v-model="speedValue" style="width: 75px" size="small" type="number" :min="0"
                                     :max="100" />
                             </div>
-                            <div class="body_show_unit">%</div>
+                            <div class="body_show_unit">{{ pumpSetArr[1].unitType || '%' }}</div>
                         </div>
                     </div>
                 </div>
@@ -120,7 +120,7 @@ function setPump(registerData, value) {
     const setValue = value ? frequencyOptions[open].value : frequencyOptions[close].value;
     setPumpVaule(registerData, setValue);
     //如果是关闭,则同步设置转速为0
-    if(!value){
+    if (!value) {
         setPumpVaule(pumpSetArr.value[1], 0);
     }
 }
@@ -170,7 +170,7 @@ function setPumpVaule(registerData, value) {
         gap: 10px;
         align-self: stretch;
         color: #76E1FF;
-        font-size: 21px;
+        font-size: 20px;
         font-weight: bold;
         border-radius: 0px 0px 5px 5px;
         background: #192846;
@@ -193,6 +193,7 @@ function setPumpVaule(registerData, value) {
             .show_body_left {
                 width: 50px;
                 text-align: center;
+                padding: 7px 0;
                 font-size: large;
                 background: #0e2b60;
                 border-radius: 5px;
@@ -253,10 +254,6 @@ function setPumpVaule(registerData, value) {
                                 }
                             }
                         }
-
-                        .body_show_unit {
-                            margin-left: 10px;
-                        }
                     }
                 }
             }

+ 4 - 0
ui/src/components/GeneralComponents/control/ValveControlComponent.vue

@@ -40,6 +40,10 @@ const props = defineProps({
 
 // 计算 pointer 的 class
 const pointerClass = computed(() => {
+    //未传阀门状态数组时,默认为关状态
+    if (props.valveArr.length === 0) {
+        return 'pointer_close'
+    }
     // 未传入阀门信号状态时,该阀门为N阀门
     if (props.valveArr.length === 1) {
         // console.log('未传入阀门信号状态')

+ 11 - 3
ui/src/config.js

@@ -15,11 +15,19 @@ export const navItems_Na2SO4=[
   { label: '反应', code: 'Reaction_Control', path: '/controlPage/flowSelect/reaction' },
   { label: '一次固液分离', code: 'SolidLiquidSeparation_Control', path: '/controlPage/flowSelect/solidLiquidSeparation' },
   { label: '24平带式过滤', code: 'FlatBeltFiltration_Control', path: '/controlPage/flowSelect/flatBeltFiltration' },
+  { label: 'G1分解', code: 'G1Decomposition_Control', path: '/controlPage/flowSelect/G1Decomposition' },
+  { label: 'G1附属分离器', code: 'G1AccessorySeparator_Control', path: '/controlPage/flowSelect/G1AccessorySeparator' },
+  { label: '溶晶', code: 'DissolvedCrystal_Control', path: '/controlPage/flowSelect/DissolvedCrystal' },
+  { label: 'G3分解', code: 'G3Decomposition_Control', path: '/controlPage/flowSelect/G3Decomposition' },
 ]
 
 // 硫酸钠组态页面导航栏配置
 export const pageItems_Na2SO4=[
-  { label: '反应', code: 'Na2SO4_FY', path: '/Na2SO4_FY' },
-  { label: '一次固液分离', code: 'Na2SO4_GYFL', path: '/Na2SO4_GYFL' },
-  { label: '24平带式过滤', code: 'Na2SO4_24PDSGL', path: '/Na2SO4_24PDSGL' },
+  { label: '反应', code: 'Na2SO4_FY', path: '/configuratePage/Na2SO4_FY' },
+  { label: '一次固液分离', code: 'Na2SO4_GYFL', path: '/configuratePage/Na2SO4_GYFL' },
+  { label: '24平带式过滤', code: 'Na2SO4_24PDSGL', path: '/configuratePage/Na2SO4_24PDSGL' },
+  { label: 'G1分解', code: 'Na2SO4_G1FJ', path: '/configuratePage/Na2SO4_G1FJ' },
+  { label: 'G1附属分离器', code: 'Na2SO4_G1FSFLQ', path: '/configuratePage/Na2SO4_G1FSFLQ' },
+  { label: '溶晶', code: 'Na2SO4_RJ', path: '/configuratePage/Na2SO4_RJ' },
+  { label: 'G3分解', code: 'Na2SO4_G3FJ', path: '/configuratePage/Na2SO4_G3FJ' },
 ]

+ 28 - 3
ui/src/router/index.js

@@ -162,6 +162,16 @@ export const constantRoutes = [
     component: () => import('@/views/controlPage/flowSelect/solidLiquidSeparation/index'),
     name: 'SolidLiquidSeparation_Control',//一次固液分离控制页面
   },
+  {
+    path: '/controlPage/flowSelect/flatBeltFiltration',
+    component: () => import('@/views/controlPage/flowSelect/flatBeltFiltration/index'),
+    name: 'FlatBeltFiltration_Control',//24平带式过滤控制页面
+  },
+  {
+    path: '/controlPage/flowSelect/G1Decomposition',
+    component: () => import('@/views/controlPage/flowSelect/G1Decomposition/index'),
+    name: 'G1Decomposition_Control',//G1分解控制页面
+  },
   //上海组态页面
   {
     path: '/m1sj',//水解:m1Hydrolyze
@@ -226,15 +236,30 @@ export const constantRoutes = [
   },
   //湖南硫酸钠组态页面
   {
-    path:'/Na2SO4_FY',//硫酸钠-反应
+    path:'/configuratePage/Na2SO4_FY',//硫酸钠-反应
     component: () => import('@/views/hnyzConfiguratePage/Na2SO4_FY/index'),
     name: 'Na2SO4_FY',
   },
   {
-    path:'/Na2SO4_GYFL',//硫酸钠-固液分离
+    path:'/configuratePage/Na2SO4_GYFL',//硫酸钠-固液分离
     component: () => import('@/views/hnyzConfiguratePage/Na2SO4_GYFL/index'),
     name: 'Na2SO4_GYFL',
   },
+  {
+    path:'/configuratePage/Na2SO4_24PDSGL',//硫酸钠-24平带式过滤
+    component: () => import('@/views/hnyzConfiguratePage/Na2SO4_24PDSGL/index'),
+    name: 'Na2SO4_24PDSGL',
+  },
+  {
+    path:'/configuratePage/Na2SO4_G1FJ',//硫酸钠-G1分解
+    component: () => import('@/views/hnyzConfiguratePage/Na2SO4_G1FJ/index'),
+    name: 'Na2SO4_G1FJ',
+  },
+  {
+    path:'/configuratePage/Na2SO4_RJ',//硫酸钠-G1分解
+    component: () => import('@/views/hnyzConfiguratePage/Na2SO4_RJ/index'),
+    name: 'Na2SO4_RJ',
+  },
   { // 页面设计器
     path: '/deviceState',
     hidden: false,
@@ -245,7 +270,7 @@ export const constantRoutes = [
   { // 页面设计器
     path: '/pageDesigner',
     component: Layout,
-    hidden: false,
+    hidden: true,
     name: 'PageDesigner',
     meta: { title: '页面设计器', icon: 'edit' },
     children: [

+ 147 - 0
ui/src/views/controlPage/flowSelect/G1Decomposition/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>

+ 147 - 0
ui/src/views/controlPage/flowSelect/flatBeltFiltration/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>

+ 172 - 0
ui/src/views/hnyzConfiguratePage/Na2SO4_24PDSGL/index.vue

@@ -0,0 +1,172 @@
+<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.equipmentName)" :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>
+
+            <!-- 单纯ICON设备 -->
+            <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)"
+                    :specialCondition="JSON.parse(item.specialCondition)" />
+            </div>
+
+            <!-- 其他组件 -->
+            <div class="other_components">
+                <component v-for="item in deviceConfigGroup.OTHERS" :key="item.id" :is="getComponentName(item.modelId)"
+                    :iconSize="item.size" :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) => {
+                // 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 { 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: 1920px;
+    height: 1080px;
+    background-color: #0b172c;
+
+    .content_page {
+        position: relative;
+        width: 100%;
+        height: 1000px;
+
+        .page_drawer {
+            position: absolute;
+            right: 2%;
+            top: -1%;
+        }
+    }
+}
+</style>

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

@@ -20,7 +20,7 @@
             <!-- 罐体 -->
             <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"
+                    :title="getEquipmentTitle(item.title)" :iconSize="item.size" :iconWidth="item.width"
                     :iconHeight="item.height" :style="getComponentStyle(item)" />
             </div>
 

+ 163 - 0
ui/src/views/hnyzConfiguratePage/Na2SO4_G1FJ/index.vue

@@ -0,0 +1,163 @@
+<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.equipmentName)" :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: 1920px;
+    height: 1080px;
+    background-color: #0b172c;
+
+    .content_page {
+        position: relative;
+        width: 100%;
+        height: 1000px;
+
+        .page_drawer {
+            position: absolute;
+            right: 2%;
+            top: -1%;
+        }
+    }
+}
+</style>

+ 1 - 3
ui/src/views/hnyzConfiguratePage/Na2SO4_GYFL/index.vue

@@ -20,7 +20,7 @@
             <!-- 罐体 -->
             <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"
+                    :title="getEquipmentTitle(item.title)" :iconSize="item.size" :iconWidth="item.width"
                     :iconHeight="item.height" :style="getComponentStyle(item)" />
             </div>
 
@@ -144,8 +144,6 @@ const {
 
 <style lang="scss" scoped>
 .page {
-    // width: 100%;
-    // height: 100%;
     width: 1920px;
     height: 1080px;
     background-color: #0b172c;

+ 163 - 0
ui/src/views/hnyzConfiguratePage/Na2SO4_RJ/index.vue

@@ -0,0 +1,163 @@
+<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.title)" :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: 1920px;
+    height: 1080px;
+    background-color: #0b172c;
+
+    .content_page {
+        position: relative;
+        width: 100%;
+        height: 1000px;
+
+        .page_drawer {
+            position: absolute;
+            right: 2%;
+            top: -1%;
+        }
+    }
+}
+</style>

+ 1 - 1
ui/src/views/index.vue

@@ -217,7 +217,7 @@ function toConfig() {
 }
 function toHnyzConfig() {
   // 跳转湖南组态页面
-  router.push('/Na2SO4_FY')
+  router.push('/configuratePage/Na2SO4_FY')
 }
 function toSimulatorPage() {
   // 跳转模拟器页面