|
|
@@ -1,75 +1,74 @@
|
|
|
<template>
|
|
|
- <div class="dcs_tanks">
|
|
|
- <!-- 顶部固定头部 -->
|
|
|
- <div class="fixed-header" ref="fixedHeader">
|
|
|
- <HeaderComponent title="碳酸钠-流程控制" backTo="/controlPage/flowSelect" />
|
|
|
- <PageNav :items="navItems" :currentCode="flowCode" @navClick="onNavClick"/>
|
|
|
- </div>
|
|
|
+ <div class="dcs_tanks">
|
|
|
+ <!-- 固定头部 -->
|
|
|
+ <div class="fixed-header" ref="fixedHeader">
|
|
|
+ <HeaderComponent title="硫酸钠-参数配置" backTo="/controlPage/flowSelect" />
|
|
|
+ <PageNav :items="navItems" :currentCode="flowCode" />
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- 主内容区 -->
|
|
|
- <div class="main-container">
|
|
|
- <div class="main-content">
|
|
|
- <div class="content-area">
|
|
|
- <div v-if="isLoading" class="loading">正在加载设备数据...</div>
|
|
|
- <div v-if="hasError" class="error">
|
|
|
- <p>加载数据失败: {{ errorMessage }}</p>
|
|
|
- <button @click="loadInitialData">重试</button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div v-else class="tanks_container">
|
|
|
- <div v-for="(equipments, tankName) in deviceConfigGroup" :key="tankName"
|
|
|
- class="tank_section" :id="`tank-${tankName}`">
|
|
|
- <h2 class="tank_title">{{ tankName }}</h2>
|
|
|
- <div class="equipment_grid">
|
|
|
- <component v-for="equipment in equipments" :key="equipment.code"
|
|
|
- :is="getComponentByType(equipment.equipmentType)"
|
|
|
- :title="equipment.title + '-' + equipment.equipmentName"
|
|
|
- :code="equipment.code"
|
|
|
- :dataArr="getValueByCode(tankName, equipment.code)"
|
|
|
- class="equipment_item" />
|
|
|
- </div>
|
|
|
+ <!-- 主内容区 -->
|
|
|
+ <div class="main-container">
|
|
|
+ <div class="main-content">
|
|
|
+ <!-- 设备区域 -->
|
|
|
+ <div class="content-area">
|
|
|
+ <div v-if="isLoading" class="loading">正在加载设备数据...</div>
|
|
|
+ <div v-if="hasError" class="error">
|
|
|
+ <p>加载数据失败: {{ errorMessage }}</p>
|
|
|
+ <button @click="loadInitialData">重试</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else class="tanks_container">
|
|
|
+ <div v-for="(equipments, tankName) in deviceConfigGroup" :key="tankName" class="tank_section"
|
|
|
+ :id="`tank-${tankName}`">
|
|
|
+ <h2 class="tank_title">{{ tankName }}</h2>
|
|
|
+ <div class="equipment_grid">
|
|
|
+ <PumpControlComponent v-if="tankName === '1#反应釜-C3001'" title="原矿进料"
|
|
|
+ :dataArr="[5, 100, 100]" id="equipment-special-pump" class="equipment_item" />
|
|
|
+ <WorkModeControl v-if="tankName === '兑卤器低位槽-V3001'" class="equipment_item" />
|
|
|
+ <component v-for="equipment in equipments" :key="equipment.code"
|
|
|
+ :is="getComponentByType(equipment.equipmentType)"
|
|
|
+ :title="equipment.title + '-' + equipment.equipmentName" :code="equipment.code"
|
|
|
+ :dataArr="getValueByCode(tankName, equipment.code)"
|
|
|
+ :id="`equipment-${equipment.code}`" class="equipment_item" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="isEmptyData" class="no_data">未获取到设备数据</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧导航 -->
|
|
|
+ <TankNavigation :tanks="allTanks" :current-index="currentNavIndex" :header-height="headerHeight"
|
|
|
+ @tankClick="scrollToTank" @scrollPositionChange="handleScrollPositionChange" />
|
|
|
</div>
|
|
|
-
|
|
|
- <div v-if="isEmptyData" class="no_data">未获取到设备数据</div>
|
|
|
- </div>
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- 右侧导航 -->
|
|
|
- <TankNavigation :tanks="allTanks"
|
|
|
- :current-index="currentNavIndex"
|
|
|
- :header-height="headerHeight"
|
|
|
- @tankClick="scrollToTank"
|
|
|
- @scrollPositionChange="handleScrollPositionChange" />
|
|
|
- </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, computed, onMounted, onBeforeUnmount, watchEffect } from 'vue';
|
|
|
-import { useRoute, useRouter } from 'vue-router';
|
|
|
+import { ref, onMounted, onBeforeUnmount, watch, watchEffect, computed } from 'vue';
|
|
|
+import { useRoute } from 'vue-router';
|
|
|
import HeaderComponent from '@/components/DCS/HeaderComponent.vue';
|
|
|
import PageNav from '@/components/GeneralComponents/control/PageNavComponent.vue';
|
|
|
-import TankNavigation from '@/components/GeneralComponents/control/TankNavigationComponent.vue';
|
|
|
import SensorControl from '@/components/GeneralComponents/control/SensorControl2Component.vue';
|
|
|
import PumpControlComponent from '@/components/GeneralComponents/control/PumpControl2Component.vue';
|
|
|
import ValveControlComponent from '@/components/GeneralComponents/control/ValveControl2Component.vue';
|
|
|
-import { navItems_Na2SO4 } from '@/config';
|
|
|
-import { stompClient } from '@/utils/ws/stompClient';
|
|
|
-import { getPageEquipmentGroupByTankByFlowCode } from '@/api/hnyz/equipment';
|
|
|
+import WorkModeControl from '@/components/GeneralComponents/control/WorkModeControl2Component.vue';
|
|
|
+import TankNavigation from '@/components/GeneralComponents/control/TankNavigationComponent.vue';
|
|
|
|
|
|
+import { getPageEquipmentGroupByTankByFlowCode } from '@/api/hnyz/equipment';
|
|
|
+import { useEquipmentLayout } from '@/hooks/useEquipmentLayout';
|
|
|
+import { stompClient } from '@/utils/ws/stompClient';
|
|
|
+import { updateZTPageConfig } from '@/api/dcs/configurePage';
|
|
|
+import { getFlowNav } from '@/api/hnyz/flow';
|
|
|
const route = useRoute();
|
|
|
-const router = useRouter();
|
|
|
-
|
|
|
-const navItems = navItems_Na2SO4; // 暂时前端常量
|
|
|
const flowCode = computed(() => route.params.flowCode);
|
|
|
-const title = computed(() => navItems.find(i => i.code === flowCode.value)?.label || '');
|
|
|
+const navItems = ref();
|
|
|
|
|
|
const isLoading = ref(true);
|
|
|
const hasError = ref(false);
|
|
|
const errorMessage = ref('');
|
|
|
const isEmptyData = ref(false);
|
|
|
-
|
|
|
const fixedHeader = ref(null);
|
|
|
const headerHeight = ref(0);
|
|
|
const allTanks = ref([]);
|
|
|
@@ -77,82 +76,103 @@ const currentNavIndex = ref(-1);
|
|
|
|
|
|
const deviceConfigGroup = ref({});
|
|
|
const deviceDataGroup = ref({});
|
|
|
+const pageParams = ref({});
|
|
|
|
|
|
-function getComponentByType(type) {
|
|
|
- if ([1,5].includes(Number(type))) return ValveControlComponent;
|
|
|
- if (Number(type) === 2) return PumpControlComponent;
|
|
|
- if (Number(type) === 4) return SensorControl;
|
|
|
- return 'div';
|
|
|
-}
|
|
|
+const { generatePageParams } = useEquipmentLayout();
|
|
|
|
|
|
-function getValueByCode(tankName, code) {
|
|
|
- const dataArr = deviceDataGroup.value[tankName] || [];
|
|
|
- const target = dataArr.find(item => item.code === code);
|
|
|
- return target?.value || [];
|
|
|
-}
|
|
|
-
|
|
|
-async function loadInitialData() {
|
|
|
- isLoading.value = true;
|
|
|
- hasError.value = false;
|
|
|
- errorMessage.value = '';
|
|
|
- try {
|
|
|
- const res = await getPageEquipmentGroupByTankByFlowCode(flowCode.value);
|
|
|
- deviceConfigGroup.value = Object.fromEntries(
|
|
|
- Object.entries(res.data || {}).filter(([_, e]) => e?.length)
|
|
|
- );
|
|
|
- isEmptyData.value = Object.keys(deviceConfigGroup.value).length === 0;
|
|
|
-
|
|
|
- // WebSocket 订阅
|
|
|
- stompClient.unsubscribeFromPage(flowCode.value);
|
|
|
- stompClient.subscribeToPage(flowCode.value, data => {
|
|
|
- if (data) {
|
|
|
- for (const key in data) deviceDataGroup.value[key] = data[key] || [];
|
|
|
- }
|
|
|
- });
|
|
|
- } catch (err) {
|
|
|
- hasError.value = true;
|
|
|
- errorMessage.value = err.message || '加载失败';
|
|
|
- } finally {
|
|
|
- isLoading.value = false;
|
|
|
- }
|
|
|
-}
|
|
|
+// 监控路由变化
|
|
|
+watch(() => route.params.flowCode, loadInitialData);
|
|
|
|
|
|
+// 生成导航罐体列表
|
|
|
watchEffect(() => {
|
|
|
- allTanks.value = Object.keys(deviceConfigGroup.value).map(name => ({
|
|
|
- uniqueId: `tank-${name}`,
|
|
|
- tankName: name,
|
|
|
- shortName: name.length > 18 ? name.slice(0,16)+'...' : name
|
|
|
- }));
|
|
|
+ allTanks.value = Object.keys(deviceConfigGroup.value).map(tankName => ({
|
|
|
+ uniqueId: `tank-${tankName}`,
|
|
|
+ tankName,
|
|
|
+ shortName: tankName.length > 18 ? tankName.slice(0, 16) + '...' : tankName
|
|
|
+ }));
|
|
|
+ currentNavIndex.value = -1;
|
|
|
});
|
|
|
|
|
|
-function calculateHeaderHeight() { headerHeight.value = fixedHeader.value?.offsetHeight || 0; }
|
|
|
+// 计算固定头部高度
|
|
|
+const calculateHeaderHeight = () => { headerHeight.value = fixedHeader.value?.offsetHeight || 0; }
|
|
|
|
|
|
-function scrollToTank(tank,index) {
|
|
|
- currentNavIndex.value = index;
|
|
|
- const el = document.getElementById(`tank-${tank.tankName}`);
|
|
|
- if(el) window.scrollTo({top: el.offsetTop - headerHeight.value - 20, behavior:'smooth'});
|
|
|
+// 加载初始数据
|
|
|
+async function loadInitialData() {
|
|
|
+ try {
|
|
|
+ isLoading.value = true; hasError.value = false; errorMessage.value = '';
|
|
|
+
|
|
|
+ const res = await getPageEquipmentGroupByTankByFlowCode(flowCode.value);
|
|
|
+ deviceConfigGroup.value = Object.fromEntries(
|
|
|
+ Object.entries(res.data || {}).filter(([_, eqs]) => eqs?.length)
|
|
|
+ );
|
|
|
+ isEmptyData.value = !Object.keys(deviceConfigGroup.value).length;
|
|
|
+
|
|
|
+ pageParams.value = generatePageParams(deviceConfigGroup.value);
|
|
|
+ await updatePageConfig();
|
|
|
+ } catch (err) {
|
|
|
+ hasError.value = true;
|
|
|
+ errorMessage.value = err.message || '加载设备分组失败';
|
|
|
+ } finally {
|
|
|
+ isLoading.value = false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-function handleScrollPositionChange(index){ currentNavIndex.value = index; }
|
|
|
+// 更新页面配置并订阅 WebSocket
|
|
|
+async function updatePageConfig() {
|
|
|
+ try {
|
|
|
+ await updateZTPageConfig(flowCode.value, pageParams.value);
|
|
|
+
|
|
|
+ stompClient.unsubscribeFromPage(flowCode.value);
|
|
|
+ stompClient.subscribeToPage(flowCode.value, data => {
|
|
|
+ if (!data) return;
|
|
|
+ try {
|
|
|
+ for (const key in data) { deviceDataGroup.value[key] = data[key] || []; }
|
|
|
+ } catch (err) {
|
|
|
+ console.error('更新设备数据失败:', err);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (err) { console.error('页面配置失败:', err); }
|
|
|
+}
|
|
|
|
|
|
-// 点击导航栏跳转页面
|
|
|
-function onNavClick(item) {
|
|
|
- router.push(item.path)
|
|
|
+// 根据设备类型返回组件
|
|
|
+function getComponentByType(equipmentType) {
|
|
|
+ const type = Number(equipmentType);
|
|
|
+ if ([1, 5].includes(type)) return ValveControlComponent;
|
|
|
+ if (type === 2) return PumpControlComponent;
|
|
|
+ if (type === 4) return SensorControl;
|
|
|
+ return 'div';
|
|
|
}
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- calculateHeaderHeight();
|
|
|
- window.addEventListener('resize', calculateHeaderHeight);
|
|
|
- loadInitialData();
|
|
|
+// 根据罐体名和 code 获取设备数据
|
|
|
+function getValueByCode(tankName, code) {
|
|
|
+ const arr = deviceDataGroup.value[tankName] || [];
|
|
|
+ const item = arr.find(i => i.code === code);
|
|
|
+ return item ? item.value : [];
|
|
|
+}
|
|
|
+
|
|
|
+// 导航滚动
|
|
|
+function scrollToTank(tank, index) {
|
|
|
+ currentNavIndex.value = index;
|
|
|
+ const el = document.getElementById(`tank-${tank.tankName}`);
|
|
|
+ if (!el) return;
|
|
|
+ window.scrollTo({ top: el.offsetTop - headerHeight.value - 20, behavior: 'smooth' });
|
|
|
+}
|
|
|
+
|
|
|
+function handleScrollPositionChange(index) { currentNavIndex.value = index; }
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ const res = await getFlowNav('Na2SO4', 'flowSelect');
|
|
|
+ navItems.value = res.data;
|
|
|
+ calculateHeaderHeight();
|
|
|
+ window.addEventListener('resize', calculateHeaderHeight);
|
|
|
+ loadInitialData();
|
|
|
});
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
- stompClient.unsubscribeFromPage(flowCode.value);
|
|
|
- window.removeEventListener('resize', calculateHeaderHeight);
|
|
|
+ stompClient.unsubscribeFromPage(flowCode.value);
|
|
|
+ window.removeEventListener('resize', calculateHeaderHeight);
|
|
|
});
|
|
|
</script>
|
|
|
-
|
|
|
-
|
|
|
<style scoped lang="scss">
|
|
|
.dcs_tanks {
|
|
|
width: 100%;
|