Răsfoiți Sursa

[Feat 0000]防灭火监测子页面接口对接

bobo04052021@163.com 2 luni în urmă
părinte
comite
801bac9f06
21 a modificat fișierele cu 1050 adăugiri și 459 ștergeri
  1. 3 0
      src/assets/images/beltFire/fireMonitor/close.svg
  2. BIN
      src/assets/images/beltFire/fireMonitor/historyTitle.png
  3. BIN
      src/assets/images/beltFire/fireMonitor/modalBorder.png
  4. 16 13
      src/views/vent/home/configurable/belt/belt-new.vue
  5. 51 65
      src/views/vent/home/configurable/belt/belt.vue
  6. 144 80
      src/views/vent/home/configurable/belt/components/BeltNav.vue
  7. 344 0
      src/views/vent/home/configurable/belt/components/confirmModal.vue
  8. 9 94
      src/views/vent/home/configurable/belt/configurable.api.ts
  9. 106 125
      src/views/vent/home/configurable/belt/configurable.data.ts
  10. 3 2
      src/views/vent/home/configurable/components/belt/CameraList.vue
  11. 3 5
      src/views/vent/home/configurable/components/belt/CameraListTest.vue
  12. 2 2
      src/views/vent/home/configurable/components/belt/ComplexListBelt.vue
  13. 2 2
      src/views/vent/home/configurable/components/belt/CustomListBelt.vue
  14. 4 1
      src/views/vent/home/configurable/components/belt/CustomTableBelt.vue
  15. 9 7
      src/views/vent/home/configurable/components/belt/FireSensorAnalysis.vue
  16. 12 11
      src/views/vent/home/configurable/components/belt/SensorStatusPanel.vue
  17. 3 4
      src/views/vent/home/configurable/components/belt/SprayControl.vue
  18. 78 45
      src/views/vent/home/configurable/components/belt/VehicleCOAnalysis.vue
  19. 1 2
      src/views/vent/home/configurable/components/belt/WarningResultList.vue
  20. 259 0
      src/views/vent/home/configurable/components/belt/historyModal.vue
  21. 1 1
      src/views/vent/home/configurable/components/content.vue

+ 3 - 0
src/assets/images/beltFire/fireMonitor/close.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="54.167" height="54.167" viewBox="0 0 54.167 54.167">
+  <path id="取消" d="M27.083,54.167A27.083,27.083,0,1,1,54.167,27.083,27.083,27.083,0,0,1,27.083,54.167Zm0-50.3c-12.109,0-23.214,11.105-23.214,23.214S14.974,50.3,27.083,50.3,50.3,39.192,50.3,27.083,39.192,3.869,27.083,3.869ZM39.221,39.414a2.577,2.577,0,0,1-3.647,0l-8.208-8.206-8.208,8.206a2.579,2.579,0,1,1-3.649-3.647l8.208-8.208L15.51,19.352A2.579,2.579,0,1,1,19.158,15.7l8.208,8.208L35.573,15.7a2.579,2.579,0,1,1,3.647,3.647l-8.208,8.207,8.208,8.208a2.579,2.579,0,0,1,0,3.647Z" fill="#36c7ff" opacity="0.8"/>
+</svg>

BIN
src/assets/images/beltFire/fireMonitor/historyTitle.png


BIN
src/assets/images/beltFire/fireMonitor/modalBorder.png


+ 16 - 13
src/views/vent/home/configurable/belt/belt-new.vue

@@ -13,7 +13,7 @@
     <!-- 主体区域 -->
     <div class="border">
       <!-- 配置模块区 -->
-      <template v-if="pageType == 'fireMonitor'">
+      <template v-if="pageType == 'fire_risk_warn'">
         <ModuleCommon
           v-for="cfg in configs"
           :key="cfg.deviceType"
@@ -68,7 +68,7 @@ import ModuleCommon from './components/ModuleCommon.vue';
 import Three3D from '/@/views/vent/home/configurable/components/three3D.vue';
 import BeltNav from './components/BeltNav.vue';
 import { useRouter, useRoute } from 'vue-router';
-import { getSystem, getDevice } from './configurable.api';
+import { getSystem, getMonitorAndAlertBelt, getDevice } from './configurable.api';
 import { modalAnimate } from './threejs/belt.threejs';
 import History from './components/detail/history.vue';
 // 初始化配置
@@ -232,18 +232,22 @@ function getLevelClass(level: string) {
 }
 // 刷新数据
 function refresh() {
-  fetchConfigs('belt').then(() => {
-    if (pageType.value == 'fireMonitor') {
+  fetchConfigs('').then(() => {
+    if (pageType.value == 'fire_risk_warn') {
       configs.value = testBeltNew;
-      Promise.resolve(readData).then(updateData);
+      const params = {
+        sysId: '1637983899775242242',
+        dataList: 'fire_risk_warn,warn_result,vehicle_co_correlate',
+      };
+      Promise.resolve(getMonitorAndAlertBelt(params)).then(updateData);
     } else if (pageType.value == 'emergencyControl') {
+      configs.value = testYjkf;
       const params = {
         devicetype: 'sys',
         systemID: '1637983899775242242',
         type: 'ventS',
       };
       Promise.resolve(getSystem(params)).then(updateData);
-      configs.value = testYjkf;
     } else if (pageType.value == 'sprayControl') {
       configs.value = testSpary;
       const params = {
@@ -275,11 +279,11 @@ function refresh() {
 }
 
 // // 定时刷新
-// function initInterval() {
-//   setInterval(() => {
-//     refresh();
-//   }, 60000);
-// }
+function initInterval() {
+  setInterval(() => {
+    refresh();
+  }, 60000);
+}
 
 async function changePage(pageTypeStr: string) {
   const finalPageType = pageTypeStr || (route.query.pageType as string) || '';
@@ -317,7 +321,7 @@ watch(
 
 onMounted(() => {
   refresh();
-  // initInterval();
+  initInterval();
 });
 </script>
 
@@ -350,7 +354,6 @@ onMounted(() => {
     background-size: 100% 100%;
     position: relative;
     overflow: hidden;
-    margin-top: 50px;
     .box-container {
       position: relative;
       width: 100%;

+ 51 - 65
src/views/vent/home/configurable/belt/belt.vue

@@ -3,9 +3,9 @@
   <div class="company-home">
     <div class="border">
       <customHeader>皮带巷三级防灭火系统</customHeader>
-      <!-- <div class="test" style="width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 0"> -->
-      <SubApp />
-      <!-- </div> -->
+      <div class="test" style="width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 0">
+        <SubApp />
+      </div>
       <div class="box-container">
         <ModuleCommon
           v-for="cfg in configs"
@@ -37,7 +37,7 @@ const { updateEnhancedConfigs, updateData, data } = useInitPage('皮带巷三级
 const readData = {
   pdhzfxInfo: [
     {
-      beltName: '测试1',
+      beltName: '皮带巷1',
       sysList: [
         {
           beltName: '东翼胶带运输大巷皮带',
@@ -62,24 +62,24 @@ const readData = {
       ],
     },
   ],
-  plmhInfo: [
+  spray_auto: [
     {
-      beltName: '测试1',
+      beltName: '皮带巷1',
       sysList: [
         {
           netstatus: '1',
-          yxzt: '1',
+          deviceStatus: '1',
           plsy: '1#区域 1.4MPa',
           kzms: '手动',
         },
       ],
     },
     {
-      beltName: '测试2',
+      beltName: '皮带巷2',
       sysList: [
         {
           netstatus: '1',
-          yxzt: '1',
+          deviceStatus: '1',
           plqy: '2#区域',
           plsy: '1.6MPa',
           kzms: '自动',
@@ -89,7 +89,7 @@ const readData = {
   ],
   fmhjcInfo: [
     {
-      beltName: '测试1',
+      beltName: '皮带巷1',
       sysList: [
         {
           warnLevel: '一般风险',
@@ -130,7 +130,7 @@ const readData = {
       ],
     },
     {
-      beltName: '测试2',
+      beltName: '皮带巷2',
       sysList: [
         {
           warnLevel: '一般风险',
@@ -173,6 +173,7 @@ const readData = {
   ],
   yjkfArray: [
     {
+      beltName: '皮带巷1',
       aqjkData: [
         {
           deviceName: '风门1',
@@ -230,61 +231,46 @@ const readData = {
         },
       ],
     },
-  ],
-  aqjkData: [
-    {
-      deviceName: '风门1',
-      frontDoorStatus: '关闭',
-      backDoorStatus: '开启',
-      netStatus: '在线',
-    },
     {
-      deviceName: '风门2',
-      frontDoorStatus: '关闭',
-      backDoorStatus: '开启',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门3',
-      frontDoorStatus: '关闭',
-      backDoorStatus: '开启',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门4',
-      frontDoorStatus: '开启',
-      backDoorStatus: '开启',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门5',
-      frontDoorStatus: '开启',
-      backDoorStatus: '开启',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门6',
-      frontDoorStatus: '开启',
-      backDoorStatus: '开启',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门7',
-      frontDoorStatus: '关闭',
-      backDoorStatus: '关闭',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门8',
-      frontDoorStatus: '关闭',
-      backDoorStatus: '关闭',
-      netStatus: '在线',
-    },
-    {
-      deviceName: '风门9',
-      frontDoorStatus: '关闭',
-      backDoorStatus: '关闭',
-      netStatus: '在线',
+      beltName: '皮带巷2',
+      aqjkData: [
+        {
+          deviceName: '1#风门',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '2#风门',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '3#风门',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '4#风门',
+          frontDoorStatus: '开启',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '5#风门',
+          frontDoorStatus: '开启',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '6#风门',
+          frontDoorStatus: '开启',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+      ],
     },
   ],
 };

+ 144 - 80
src/views/vent/home/configurable/belt/components/BeltNav.vue

@@ -3,7 +3,7 @@
     <!-- 左侧圆形图标 -->
     <div class="icon-left">
       <div class="icon-circle">
-        <div class="icon">3D</div>
+        <div class="icon" @click="pathClick">3D</div>
       </div>
     </div>
     <!-- 中间按钮组 -->
@@ -21,67 +21,105 @@
     <!-- 右侧圆形图标 -->
     <div class="icon-right">
       <div class="icon-circle">
-        <span class="icon">应急控制</span>
+        <span class="icon" @click="openModal()">应急控制</span>
       </div>
     </div>
   </div>
+  <ConfirmModal v-model:visible="modalVisible" @handleCancel="handleCancel" @handleConfirm="handleConfirm" class="btn-confirm-modal"> </ConfirmModal>
 </template>
 
 <script setup lang="ts">
-  import { ref, watch, onMounted } from 'vue';
-  import { useRoute } from 'vue-router';
-  const emit = defineEmits(['changePage']);
-  const props = defineProps({
-    pageType: {
-      type: String,
-      default: '',
-    },
-  });
-  const route = useRoute(); // 获取路由实例
-  // 当前激活菜单
-  const activeType = ref('');
+import ConfirmModal from './confirmModal.vue';
+import { InputPassword } from 'ant-design-vue';
+import { ref, watch, onMounted } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
+const emit = defineEmits(['changePage']);
+const props = defineProps({
+  pageType: {
+    type: String,
+    default: '',
+  },
+});
+const router = useRouter(); // 获取路由实例
+const route = useRoute(); // 获取路由实例
+const password = ref('');
+const inputWarn = ref('密码错误请重新输入');
+const modalVisible = ref(false);
+// 当前激活菜单
+const activeType = ref('');
+activeType.value = (route.query.pageType as string) || props.pageType || '';
 
-  // 导航菜单列表
-  const menuList = ref([
-    {
-      name: '防灭火监测与预警',
-      position: 'left',
-      pageType: 'fireMonitor',
-    },
-    {
-      name: '喷淋系统管控',
-      position: 'center',
-      pageType: 'sprayControl',
-    },
-    {
-      name: '应急控风减灾',
-      position: 'right',
-      pageType: 'emergencyControl',
-    },
-  ]);
+// 导航菜单列表
+const menuList = ref([
+  {
+    name: '防灭火监测与预警',
+    position: 'left',
+    pageType: 'fire_risk_warn',
+  },
+  {
+    name: '喷淋系统管控',
+    position: 'center',
+    pageType: 'sprayControl',
+  },
+  {
+    name: '应急控风减灾',
+    position: 'center',
+    pageType: 'emergencyControl',
+  },
+  {
+    name: '历史数据',
+    position: 'right',
+    pageType: 'history',
+  },
+]);
 
-  watch(
-    [() => props.pageType, () => route.query.pageType],
-    ([newProp, newRoute]) => {
-      let currentType = '';
-      if (newProp) {
-        currentType = newProp;
-      } else if (newRoute) {
-        currentType = newRoute as string;
-      }
-      if (currentType) {
-        activeType.value = currentType;
-      }
-    },
-    { immediate: true }
-  );
+watch(
+  [() => props.pageType, () => route.query.pageType],
+  ([newProp, newRoute]) => {
+    if (newProp) {
+      activeType.value = newProp;
+    } else if (newRoute) {
+      activeType.value = newRoute as string;
+    }
+  },
+  { immediate: true }
+);
 
-  // 导航点击
-  function handleNavClick(data) {
-    const pageType = data.item.pageType;
-    activeType.value = pageType; // 点击立刻更新
-    emit('changePage', pageType);
+// 导航点击
+function handleNavClick(data) {
+  const pageType = data.item.pageType;
+  activeType.value = pageType; // 点击立刻更新
+  emit('changePage', pageType);
+}
+function pathClick() {
+  router.push('/micro-vent-2dModal/configurable/belt/fireS/home');
+}
+function openModal() {
+  modalVisible.value = !modalVisible.value;
+}
+const handleConfirm = async (password) => {
+  try {
+    console.log('用户输入的密码:', password);
+    await new Promise((resolve) => setTimeout(resolve, 500));
+    if (password === '123456') {
+      console.log('密码验证成功!');
+    } else {
+      throw new Error('密码错误,请重新输入');
+    }
+  } catch (error) {
+    return false;
   }
+};
+
+/**
+ * 处理弹窗取消回调
+ */
+const handleCancel = () => {
+  console.log('关闭弹窗');
+  password.value = '';
+  inputWarn.value = '';
+  modalVisible.value = false;
+};
 </script>
 
 <style scoped lang="less">
@@ -128,10 +166,14 @@
 .icon-left .icon {
   font-size: 14px;
   font-weight: bold;
+  z-index: 9999;
+  cursor: pointer;
 }
 .icon-right .icon {
   font-size: 14px;
   font-weight: bold;
+  z-index: 9999;
+  cursor: pointer;
 }
 
 /* 中间按钮组容器 - 核心修改区 */
@@ -170,35 +212,57 @@
   transition: all 0.2s ease;
 }
 
-  .nav-menu-item {
-    color: #59acc7;
-  }
-  .nav-menu-item:hover {
-    color: #fff;
-  }
+.nav-menu-item {
+  color: #59acc7;
+}
+.nav-menu-item:hover {
+  color: #fff;
+}
 
-  .nav-menu-active {
-    color: #fff !important;
-    font-weight: 500;
-  }
+.nav-menu-active {
+  color: #fff !important;
+  font-weight: 500;
+}
 
-  /* 按钮背景 */
-  .btn-left {
-    background: url('/@/assets/images/beltFire/yjkf/navBtnLeft-2.png') center / 100% 100% no-repeat;
-  }
-  .btn-center {
-    background: url('/@/assets/images/beltFire/yjkf/navBtnCenter-2.png') center / 100% 100% no-repeat;
-  }
-  .btn-right {
-    background: url('/@/assets/images/beltFire/yjkf/navBtnRight-2.png') center / 100% 100% no-repeat;
-  }
-  .btn-left.nav-menu-active {
-    background-image: url('/@/assets/images/beltFire/yjkf/navBtnLeft-1.png');
-  }
-  .btn-center.nav-menu-active {
-    background-image: url('/@/assets/images/beltFire/yjkf/navBtnCenter-1.png');
-  }
-  .btn-right.nav-menu-active {
-    background-image: url('/@/assets/images/beltFire/yjkf/navBtnRight-1.png');
+/* 按钮背景 */
+.btn-left {
+  background: url('/@/assets/images/beltFire/yjkf/navBtnLeft-2.png') center / 100% 100% no-repeat;
+}
+.btn-center {
+  background: url('/@/assets/images/beltFire/yjkf/navBtnCenter-2.png') center / 100% 100% no-repeat;
+}
+.btn-right {
+  background: url('/@/assets/images/beltFire/yjkf/navBtnRight-2.png') center / 100% 100% no-repeat;
+}
+.btn-left.nav-menu-active {
+  background-image: url('/@/assets/images/beltFire/yjkf/navBtnLeft-1.png');
+}
+.btn-center.nav-menu-active {
+  background-image: url('/@/assets/images/beltFire/yjkf/navBtnCenter-1.png');
+}
+.btn-right.nav-menu-active {
+  background-image: url('/@/assets/images/beltFire/yjkf/navBtnRight-1.png');
+}
+.btn-confirm-modal {
+  .zxm-modal-content {
+    height: 240px !important;
+    background-size: 100% 100%;
+    .zxm-modal-body {
+      height: 187px !important;
+      padding-top: 33px !important;
+    }
+    .zxm-modal-footer {
+      text-align: center;
+    }
   }
+}
+.pswInput {
+  margin-top: 55px;
+  width: 50%;
+  margin-left: 25% !important;
+}
+.warn-text {
+  color: red;
+  font-size: 15px;
+}
 </style>

+ 344 - 0
src/views/vent/home/configurable/belt/components/confirmModal.vue

@@ -0,0 +1,344 @@
+<template>
+  <Teleport to="body">
+    <Transition name="fade">
+      <div v-if="visible" class="password-dialog-overlay" @click.self="handleOverlayClick">
+        <div class="password-dialog">
+          <!-- 标题栏 -->
+          <div class="dialog-header">
+            <h3>应急控制</h3>
+          </div>
+          <div class="close-btn" @click="handleCancel">
+            <img src="@/assets/images/home-container/configurable/close.svg" alt="" />
+          </div>
+
+          <!-- 内容区域 -->
+          <div class="dialog-content">
+            <!-- 密码输入框 -->
+            <div class="input-wrapper" :class="{ error: showError }">
+              <input
+                ref="passwordInput"
+                v-model="password"
+                :type="showPassword ? 'text' : 'password'"
+                :placeholder="placeholder"
+                maxlength="20"
+                @keyup.enter="handleConfirm"
+                @input="clearError"
+              />
+              <!-- 显示/隐藏密码切换 -->
+              <button type="button" class="toggle-password" @click="togglePassword" tabindex="-1">
+                <span v-if="showPassword"> <img src="@/assets/images/home-container/configurable/showPassword.svg" alt="" /></span>
+                <span v-else> <img src="@/assets/images/home-container/configurable/hidePassword.svg" alt="" /></span>
+              </button>
+            </div>
+
+            <!-- 错误提示 -->
+            <Transition name="slide">
+              <p v-if="errorMessage" class="error-message">{{ errorMessage }}</p>
+            </Transition>
+          </div>
+
+          <!-- 按钮区域 -->
+          <div class="dialog-footer">
+            <button class="btn cancel" @click="handleCancel"><span>取消</span></button>
+            <button class="btn confirm" @click="handleConfirm"><span>确认</span></button>
+          </div>
+        </div>
+      </div>
+    </Transition>
+  </Teleport>
+</template>
+
+<script setup>
+import { ref, nextTick, watch } from 'vue';
+
+// Props
+const props = defineProps({
+  // 弹窗显示状态
+  visible: {
+    type: Boolean,
+    default: false,
+  },
+  // 提示消息
+  message: {
+    type: String,
+    default: '',
+  },
+  // 输入框占位符
+  placeholder: {
+    type: String,
+    default: '请输入密码(必填)',
+  },
+  // 点击遮罩层是否关闭
+  closeOnClickOverlay: {
+    type: Boolean,
+    default: true,
+  },
+});
+
+// Emits
+const emit = defineEmits(['update:visible', 'confirm', 'cancel', 'forgot-password', 'error']);
+
+// 状态
+const password = ref('');
+const showPassword = ref(false);
+const errorMessage = ref('');
+const showError = ref(false);
+const passwordInput = ref(null);
+
+// 监听弹窗显示,自动聚焦
+watch(
+  () => props.visible,
+  async (newVal) => {
+    if (newVal) {
+      await nextTick();
+      passwordInput.value?.focus();
+      // 重置状态
+      password.value = '';
+      errorMessage.value = '';
+      showError.value = false;
+    }
+  }
+);
+
+// 清除错误
+const clearError = () => {
+  showError.value = false;
+  errorMessage.value = '';
+};
+
+// 切换密码显示
+const togglePassword = () => {
+  showPassword.value = !showPassword.value;
+};
+
+// 处理取消
+const handleCancel = () => {
+  emit('update:visible', false);
+  emit('cancel');
+  resetState();
+};
+// 处理确认
+const handleConfirm = async () => {
+  if (!password.value) {
+    showError.value = true;
+    errorMessage.value = '请输入密码';
+    return;
+  }
+  showError.value = false;
+  try {
+    // 触发确认事件,返回密码
+    const result = await emit('confirm', password.value);
+    // 如果确认成功(组件外部处理),关闭弹窗
+    if (result !== false) {
+      handleCancel();
+    }
+  } catch (error) {
+    // 密码错误
+    showError.value = true;
+    errorMessage.value = '密码错误';
+
+    // 清空密码输入
+    password.value = '';
+
+    // 重新聚焦
+    await nextTick();
+    passwordInput.value?.focus();
+  } finally {
+  }
+};
+// 点击遮罩层
+const handleOverlayClick = () => {
+  if (props.closeOnClickOverlay) {
+    handleCancel();
+  }
+};
+
+// 重置状态
+const resetState = () => {
+  password.value = '';
+  showPassword.value = false;
+  errorMessage.value = '';
+  showError.value = false;
+};
+
+// 暴露方法给父组件
+defineExpose({
+  resetState,
+  focus: () => passwordInput.value?.focus(),
+});
+</script>
+
+<style scoped>
+@font-face {
+  font-family: 'douyuFont';
+  src: url('../../../../assets/font/douyuFont.otf');
+}
+.password-dialog-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.password-dialog {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  border-radius: 12px;
+  width: 500px; /* 固定宽度 */
+  height: 270px; /* 固定高度 */
+  background: url('/@/assets/images/home-container/configurable/confirmBj.png') no-repeat;
+  background-size: 100% 100%;
+}
+
+/* 调整 close-btn 的位置 */
+.close-btn {
+  width: 30px;
+  position: absolute;
+  top: -6px;
+  right: -23px;
+  cursor: pointer;
+}
+
+/* 调整标题位置 */
+.dialog-header {
+  padding: 20px 24px;
+  text-align: center;
+  color: #fff;
+  background: url('/src/assets/images/home-container/configurable/confirmTitle.png') no-repeat;
+  background-size: 100% 40%;
+  width: 70%;
+  margin: 30px auto 0; /* 改为 margin: 30px auto 0 */
+}
+
+.dialog-header h3 {
+  margin: 5px;
+  font-size: 18px;
+  color: #fff;
+  margin-top: -35px;
+  font-family: 'douyuFont';
+}
+.close-btn :hover {
+  cursor: pointer;
+}
+
+/* 内容区域 */
+.dialog-content {
+  padding: 24px;
+}
+
+.input-wrapper {
+  position: relative;
+  margin-bottom: 8px;
+}
+
+.input-wrapper input {
+  width: 100%;
+  padding: 12px 40px 12px 12px;
+  background: url('/@/assets/images/home-container/configurable/input-success.png') no-repeat;
+  background-size: 100% 100%;
+  border-radius: 8px;
+  border: none;
+  font-size: 16px;
+  transition: all 0.3s;
+  box-sizing: border-box;
+  color: #fff;
+  height: 53px;
+}
+
+.input-wrapper input:focus {
+  outline: none;
+}
+
+.input-wrapper.error input {
+  background: url('/@/assets/images/home-container/configurable/input-error.png') no-repeat;
+  background-size: 100% 100%;
+}
+
+.toggle-password {
+  position: absolute;
+  right: 8px;
+  top: 50%;
+  transform: translateY(-50%);
+  background: none;
+  border: none;
+  cursor: pointer;
+  padding: 4px;
+  color: #999 !important;
+  font-size: 18px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.toggle-password:hover {
+  color: #666;
+}
+
+.error-message {
+  color: #e90203;
+  font-size: 16px;
+  margin: 4px 0 0 0;
+  min-height: 18px;
+  text-align: center;
+}
+
+.forgot-password {
+  display: inline-block;
+  margin-top: 12px;
+  color: #409eff;
+  font-size: 14px;
+  text-decoration: none;
+}
+
+.forgot-password:hover {
+  text-decoration: underline;
+}
+
+/* 底部按钮 */
+/* 调整底部按钮位置 */
+.dialog-footer {
+  position: absolute;
+  bottom: 30px;
+  left: 50%;
+  transform: translateX(-50%);
+  width: auto;
+  display: flex;
+  gap: 10px;
+}
+
+.btn {
+  flex: 1;
+  cursor: pointer;
+  transition: all 0.3s;
+  border-radius: 5px;
+  height: 40px;
+}
+
+.btn.cancel {
+  width: 100px;
+  background: none;
+  color: #fff;
+  border: 2px solid #1b6e96;
+}
+
+.btn.confirm {
+  width: 100px;
+  margin-left: 10px;
+  background-color: #1da2a9;
+  border: 2px solid #2effee;
+  color: #fff;
+}
+
+.btn.confirm:disabled {
+  background-color: #a0cfff;
+  cursor: not-allowed;
+}
+</style>

+ 9 - 94
src/views/vent/home/configurable/belt/configurable.api.ts

@@ -6,101 +6,16 @@ import { reactive } from 'vue';
 import _ from 'lodash';
 
 enum Api {
-  getSystem = '/modelreq/monitor/system',
+  monitorAndAlertBelt = '/ventanaly-device/monitor/disaster/monitorAndAlertBelt',
   getDevice = '/modelreq/monitor/device',
-  getDisHome = '/monitor/disaster/getDisHome',
+  getSystem = '/modelreq/monitor/system',
+  //车辆干扰排除状态查询
+  getStatus = '/ventanaly-device/safety/deviceVehiclePass/switch/status',
+  // 车辆干扰排除控制
+  changeStatus = '/ventanaly-device/safety/deviceVehiclePass/switch/change',
 }
-
 export const getSystem = (params) => defHttp.post({ url: Api.getSystem, params });
+export const getMonitorAndAlertBelt = (params) => defHttp.post({ url: Api.monitorAndAlertBelt, params });
 export const getDevice = (params) => defHttp.post({ url: Api.getDevice, params });
-
-// 搞这个缓存是由于:目前代码上的设计是多个模块发出多次请求,每个模块自己负责消费前者的响应。
-// 这会导致相同的请求被同时发送多次。
-const cache = new Map<string, Promise<any>>();
-export const getDisHome = (params) => {
-  // 生成缓存key,基于接口地址和参数
-  const key = `${Api.getDisHome}?${JSON.stringify(params)}`;
-
-  // 缓存不存在时发起请求
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getDisHome, params }).finally(() => {
-        // 请求完成后删除缓存,保证下次请求能获取最新数据
-        cache.delete(key);
-      })
-    );
-  }
-
-  // 返回缓存中的Promise并处理响应数据
-  return (cache.get(key) as Promise<any>).then((res) => {
-    // 1. 处理 pdArray 中的光纤温度数据(解析JSON字符串)
-    if (res.pdArray && Array.isArray(res.pdArray)) {
-      res.pdArray.forEach((e) => {
-        // 先校验 arrayFiber 是数组,避免forEach报错
-        if (e.arrayFiber && Array.isArray(e.arrayFiber)) {
-          e.arrayFiber.forEach((j) => {
-            // 安全解析 JSON,避免 undefined/无效JSON 导致报错
-            j.fibreTemperatureArr = safeJsonParse(j.fibreTemperature, []);
-          });
-        }
-      });
-    }
-
-    // 2. 处理 sgGxObj 下的设备数据
-    if (res.sgGxObj) {
-      // 2.1 解析 devGxcw 中的光纤温度
-      if (res.sgGxObj.devGxcw && Array.isArray(res.sgGxObj.devGxcw)) {
-        res.sgGxObj.devGxcw.forEach((e) => {
-          e.fibreTemperatureArr = safeJsonParse(e.fibreTemperature, []);
-        });
-      }
-
-      // 2.2 为 devSgjc 中的气体字段设置默认值
-      if (res.sgGxObj.devSgjc && Array.isArray(res.sgGxObj.devSgjc)) {
-        res.sgGxObj.devSgjc.forEach((e) => {
-          e.o2val = e.o2Val || 0;
-          e.coval = e.coVal || 0;
-          e.gasval = e.gasVal || 0;
-          e.ch2val = e.ch2Val || 0;
-          e.chval = e.chVal || 0;
-        });
-      }
-    }
-
-    // 3. 重组 obfObj 为按气体类型分类的结构
-    if (res.obfObj && Array.isArray(res.obfObj.arrayDev)) {
-      res.obfObj.obfObjModded = [
-        { objType: '氧气', arrayDev: mapObfDev(res.obfObj.arrayDev, 'o2Val') },
-        { objType: '甲烷', arrayDev: mapObfDev(res.obfObj.arrayDev, 'ch4Val') },
-        { objType: '一氧化碳', arrayDev: mapObfDev(res.obfObj.arrayDev, 'coVal') },
-        { objType: '乙炔', arrayDev: mapObfDev(res.obfObj.arrayDev, 'c2h2Val') },
-        { objType: '二氧化碳', arrayDev: mapObfDev(res.obfObj.arrayDev, 'co2Val') },
-        { objType: '乙烯', arrayDev: mapObfDev(res.obfObj.arrayDev, 'c2h4Val') },
-        { objType: '压差', arrayDev: mapObfDev(res.obfObj.arrayDev, 'dpVal') },
-        { objType: '温度', arrayDev: mapObfDev(res.obfObj.arrayDev, 'tempVal') },
-      ];
-    }
-
-    return res;
-  });
-};
-/**
- * 安全解析 JSON 字符串的工具函数
- * @param {string} jsonStr - 要解析的JSON字符串
- * @param {any} defaultValue - 解析失败/值无效时的默认值
- * @returns {any} 解析结果或默认值
- */
-function safeJsonParse(jsonStr, defaultValue = null) {
-  // 先校验值是否为有效字符串
-  if (!jsonStr || typeof jsonStr !== 'string') {
-    return defaultValue;
-  }
-  // 捕获解析异常
-  try {
-    return JSON.parse(jsonStr);
-  } catch (err) {
-    console.warn('JSON解析失败', jsonStr, err);
-    return defaultValue;
-  }
-}
+export const getStatus = () => defHttp.get({ url: Api.getStatus });
+export const changeStatus = (params) => defHttp.get({ url: Api.changeStatus, params });

+ 106 - 125
src/views/vent/home/configurable/belt/configurable.data.ts

@@ -59,7 +59,7 @@ export const testBeltLaneFire: Config[] = [
         },
       ],
       preset: [],
-      to: '/belt/fireS/home?pageType=fireMonitor',
+      to: '/belt/fireS/home?pageType=fire_risk_warn',
     },
     showStyle: {
       size: 'width:430px;height:350px;',
@@ -116,7 +116,7 @@ export const testBeltLaneFire: Config[] = [
               contents: [
                 {
                   label: '${deviceType}',
-                  value: '${warnLevel}',
+                  value: '${frontDoorStatus}',
                   info: '',
                 },
               ],
@@ -125,7 +125,7 @@ export const testBeltLaneFire: Config[] = [
         },
       ],
       preset: [],
-      to: '/belt/fireS/home?pageType=fireMonitor',
+      to: '/belt/fireS/home?pageType=fire_risk_warn',
     },
     showStyle: {
       size: 'width:430px;height:430px;',
@@ -197,7 +197,7 @@ export const testBeltLaneFire: Config[] = [
             },
             {
               label: '喷淋水压状态',
-              value: '${[0].MPa}',
+              value: '${[0].plsy}',
               color: 'blue',
               info: '',
             },
@@ -263,7 +263,6 @@ export const testBeltLaneFire: Config[] = [
         {
           type: 'C',
           readFrom: 'aqjkData',
-          pagetype: 'Belt',
           columns: [
             {
               name: '设备位置',
@@ -444,7 +443,7 @@ export const testYjkf: Config[] = [
 export const testBeltNew: Config[] = [
   // ==================== 左侧栏:火灾监测设备状态 ====================
   {
-    deviceType: 'fireMonitor',
+    deviceType: 'fire_risk_warn',
     moduleName: '火灾监测设备报警与分析',
     pageType: 'fireMonitorLeft',
     moduleData: {
@@ -483,31 +482,31 @@ export const testBeltNew: Config[] = [
       list: [],
       preset: [
         {
-          readFrom: 'fmhjcInfo[0]',
+          readFrom: 'fire_risk_warn',
           list: [
             {
-              title: '微震测声传感器',
+              title: '光纤测温传感器',
               contentTop: [
                 {
                   label: '平均值',
-                  code: '${wz.avg}',
+                  code: '${fiber_v1.avg}',
                   color: 'white',
                 },
                 {
                   label: '最大值',
-                  code: 'max',
+                  code: '${fiber_v1.max}',
                   color: 'white',
                 },
                 {
                   label: '最小值',
-                  code: 'min',
+                  code: '${fiber_v1.min}',
                   color: 'white',
                 },
               ],
               contents: [
                 {
                   label: '是否报警',
-                  code: 'alarm',
+                  code: '${fiber_v1.flag}',
                   trans: {
                     true: '报警',
                     false: '正常',
@@ -516,34 +515,37 @@ export const testBeltNew: Config[] = [
                 },
                 {
                   label: '最大值产生于',
-                  code: '${wz.maxTime}',
+                  code: '${fiber_v1.time}',
                   color: 'white',
+                  info: {
+                    code: '${fiber_v1.position}',
+                  },
                 },
               ],
             },
             {
-              title: 'HCl传感器',
+              title: 'CO传感器',
               contentTop: [
                 {
                   label: '平均值',
-                  code: '${avg}',
+                  code: '${modelsensor_co.avg}',
                   color: 'white',
                 },
                 {
                   label: '最大值',
-                  code: 'max',
+                  code: '${modelsensor_co.max}',
                   color: 'white',
                 },
                 {
                   label: '最小值',
-                  code: 'min',
+                  code: '${modelsensor_co.min}',
                   color: 'white',
                 },
               ],
               contents: [
                 {
                   label: '是否报警',
-                  code: 'alarm',
+                  code: '${modelsensor_co.flag}',
                   trans: {
                     true: '报警',
                     false: '正常',
@@ -552,128 +554,77 @@ export const testBeltNew: Config[] = [
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
+                  code: '${modelsensor_co.time}',
                   color: 'white',
                   info: {
-                    code: 'pos',
+                    code: '${modelsensor_co.position}',
                   },
                 },
               ],
             },
             {
-              title: '光纤测温传感器',
+              title: '火焰传感器',
               contentTop: [
-                {
-                  label: '平均值',
-                  code: 'avg',
-                  color: 'white',
-                },
-                {
-                  label: '最大值',
-                  code: 'max',
-                  color: 'white',
-                },
-                {
-                  label: '最小值',
-                  code: 'min',
-                  color: 'white',
-                },
+                { label: '平均值', code: '${modelsensor_fire.avg}', color: 'white' },
+                { label: '最大值', code: '${modelsensor_fire.max}', color: 'white' },
+                { label: '最小值', code: '${modelsensor_fire.min}', color: 'white' },
               ],
               contents: [
                 {
                   label: '是否报警',
-                  code: 'alarm',
-                  trans: {
-                    true: '报警',
-                    false: '正常',
-                  },
+                  code: '${modelsensor_fire.flag}',
+                  trans: { true: '报警', false: '正常' },
                   color: 'green',
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
+                  code: '${modelsensor_fire.time}',
                   color: 'white',
-                  info: {
-                    code: 'pos',
-                  },
+                  info: { code: '${modelsensor_fire.position}' },
                 },
               ],
             },
             {
-              title: 'CO传感器',
+              title: '烟雾传感器',
               contentTop: [
-                {
-                  label: '平均值',
-                  code: 'avg',
-                  color: 'white',
-                },
-                {
-                  label: '最大值',
-                  code: 'max',
-                  color: 'white',
-                },
-                {
-                  label: '最小值',
-                  code: 'min',
-                  color: 'white',
-                },
+                { label: '平均值', code: '${modelsensor_smoke.avg}', color: 'white' },
+                { label: '最大值', code: '${modelsensor_smoke.max}', color: 'white' },
+                { label: '最小值', code: '${modelsensor_smoke.min}', color: 'white' },
               ],
               contents: [
                 {
                   label: '是否报警',
-                  code: 'alarm',
-                  trans: {
-                    true: '报警',
-                    false: '正常',
-                  },
+                  code: '${modelsensor_smoke.flag}',
+                  trans: { true: '报警', false: '正常' },
                   color: 'green',
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
+                  code: '${modelsensor_smoke.time}',
                   color: 'white',
-                  info: {
-                    code: 'pos',
-                  },
+                  info: { code: '${modelsensor_smoke.position}' },
                 },
               ],
             },
             {
               title: '温度传感器',
               contentTop: [
-                {
-                  label: '平均值',
-                  code: 'avg',
-                  color: 'white',
-                },
-                {
-                  label: '最大值',
-                  code: 'max',
-                  color: 'white',
-                },
-                {
-                  label: '最小值',
-                  code: 'min',
-                  color: 'white',
-                },
+                { label: '平均值', code: '${modelsensor_temperature.avg}', color: 'white' },
+                { label: '最大值', code: '${modelsensor_temperature.max}', color: 'white' },
+                { label: '最小值', code: '${modelsensor_temperature.min}', color: 'white' },
               ],
               contents: [
                 {
                   label: '是否报警',
-                  code: 'alarm',
-                  trans: {
-                    true: '报警',
-                    false: '正常',
-                  },
+                  code: '${modelsensor_temperature.flag}',
+                  trans: { true: '报警', false: '正常' },
                   color: 'green',
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
+                  code: '${modelsensor_temperature.time}',
                   color: 'white',
-                  info: {
-                    code: 'pos',
-                  },
+                  info: { code: '${modelsensor_temperature.position}' },
                 },
               ],
             },
@@ -690,7 +641,7 @@ export const testBeltNew: Config[] = [
 
   // ==================== 中央中部:预警结果列表 ====================
   {
-    deviceType: 'fireMonitor',
+    deviceType: 'warn_result',
     moduleName: '预警结果',
     pageType: 'fireMonitorMid',
     moduleData: {
@@ -729,9 +680,9 @@ export const testBeltNew: Config[] = [
       complex_list: [],
       preset: [
         {
-          readFrom: 'pdhzfxInfo[0]',
+          readFrom: '',
           type: 'C',
-          tableReadFrom: 'sysList',
+          tableReadFrom: '',
           columns: [
             {
               name: '时间',
@@ -765,7 +716,7 @@ export const testBeltNew: Config[] = [
           ],
           otherProps: {
             title: '火灾风险预警',
-            prop: 'warningLevel',
+            prop: 'status',
           },
         },
       ],
@@ -778,7 +729,7 @@ export const testBeltNew: Config[] = [
   },
 
   {
-    deviceType: 'fireMonitor',
+    deviceType: 'fire_risk_warn',
     moduleName: '火灾监测设备状态',
     pageType: 'fireMonitor',
     moduleData: {
@@ -817,20 +768,50 @@ export const testBeltNew: Config[] = [
       complex_list: [],
       preset: [
         {
-          readFrom: 'sensorAnalysis',
+          readFrom: 'fire_risk_warn',
           config: [
             {
-              title: '火焰传感器', // 对应 UI 图中的组标题
+              title: '光纤测温传感器',
               items: [
                 {
                   label: '是否报警',
-                  code: '${hy.alarm}', // 占位符
-                  status: '1', // 状态映射逻辑 (0:正常, 1:报警)
+                  code: '${fiber_v1.flag}',
+                  trans: { true: '报警', false: '正常' },
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
-                  info: '1521胶运顺槽600m',
+                  code: '${fiber_v1.time}',
+                  info: { code: '${fiber_v1.position}' },
+                },
+              ],
+            },
+            {
+              title: 'CO传感器',
+              items: [
+                {
+                  label: '是否报警',
+                  code: '${modelsensor_co.flag}',
+                  trans: { true: '报警', false: '正常' },
+                },
+                {
+                  label: '最大值产生于',
+                  code: '${modelsensor_co.time}',
+                  info: { code: '${modelsensor_co.position}' },
+                },
+              ],
+            },
+            {
+              title: '火焰传感器',
+              items: [
+                {
+                  label: '是否报警',
+                  code: '${modelsensor_fire.flag}',
+                  trans: { true: '报警', false: '正常' },
+                },
+                {
+                  label: '最大值产生于',
+                  code: '${modelsensor_fire.time}',
+                  info: { code: '${modelsensor_fire.position}' },
                 },
               ],
             },
@@ -839,13 +820,13 @@ export const testBeltNew: Config[] = [
               items: [
                 {
                   label: '是否报警',
-                  code: 'isAlarm', // 占位符
-                  status: 'isAlarm', // 状态映射逻辑 (0:正常, 1:报警)
+                  code: '${modelsensor_temp.flag}',
+                  trans: { true: '报警', false: '正常' },
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
-                  info: '1521胶运顺槽600m',
+                  code: '${modelsensor_temp.time}',
+                  info: { code: '${modelsensor_temp.position}' },
                 },
               ],
             },
@@ -854,13 +835,13 @@ export const testBeltNew: Config[] = [
               items: [
                 {
                   label: '是否报警',
-                  code: 'isAlarm', // 占位符
-                  status: 'isAlarm', // 状态映射逻辑 (0:正常, 1:报警)
+                  code: '${modelsensor_smoke.flag}',
+                  trans: { true: '报警', false: '正常' },
                 },
                 {
                   label: '最大值产生于',
-                  code: 'maxTime',
-                  info: '1521胶运顺槽600m',
+                  code: '${modelsensor_smoke.time}',
+                  info: { code: '${modelsensor_smoke.position}' },
                 },
               ],
             },
@@ -877,7 +858,7 @@ export const testBeltNew: Config[] = [
 
   // ==================== 右侧下部:车辆定位与CO浓度关联分析 ====================
   {
-    deviceType: 'fireMonitor',
+    deviceType: 'vehicle_co_correlate',
     moduleName: '车辆定位与CO浓度关联分析',
     pageType: 'fireMonitor',
     moduleData: {
@@ -916,12 +897,12 @@ export const testBeltNew: Config[] = [
       complex_list: [],
       preset: [
         {
-          readFrom: 'vehicleCOAnalysis',
+          readFrom: 'vehicle_co_correlate',
           list: [
             {
               type: 'control',
               title: '车辆干扰排除',
-              layout: 'horizontal',
+              layout: '',
               readFrom: '',
               items: [
                 {
@@ -937,34 +918,34 @@ export const testBeltNew: Config[] = [
             {
               type: 'activity',
               title: '最近车辆活动',
-              readFrom: 'activityList',
+              readFrom: '',
               items: [
                 {
                   label: '',
-                  code: 'pos',
+                  code: '${strNmae}',
                 },
                 {
                   label: '',
-                  code: 'vehicle',
+                  code: '${vehicle_id}',
                 },
                 {
                   label: '',
-                  code: 'status', // 状态映射逻辑 (0:已排除, 1:预警)
+                  code: '${result}', // 状态映射逻辑 (0:已排除, 1:预警)
                 },
               ],
             },
             {
               type: 'analysis',
               title: 'CO浓度异常分析',
-              readFrom: 'analysisList',
+              readFrom: '',
               items: [
                 {
                   label: '',
-                  code: 'pos',
+                  code: 'strName',
                 },
                 {
                   label: '',
-                  code: 'analysisText',
+                  code: 'judge',
                 },
               ],
             },
@@ -975,11 +956,11 @@ export const testBeltNew: Config[] = [
               items: [
                 {
                   label: '可能原因',
-                  code: 'possibleCause',
+                  code: 'cause',
                 },
                 {
                   label: '建议',
-                  code: 'recommendation',
+                  code: 'advice',
                 },
               ],
             },

+ 3 - 2
src/views/vent/home/configurable/components/belt/CameraList.vue

@@ -79,13 +79,14 @@ onBeforeUnmount(() => {
   .liveVideo {
     width: 430px !important;
     height: 276px !important;
-    padding: 15px !important;
     align-self: auto !important;
-    margin: 10px 8px !important;
     background-size: 100% 100% !important;
   }
   .video-parent {
     pointer-events: auto !important;
   }
 }
+:deep(#LivePlayerBox .liveVideo) {
+  background: none !important;
+}
 </style>

+ 3 - 5
src/views/vent/home/configurable/components/belt/CameraListTest.vue

@@ -48,21 +48,19 @@ const videoList = ref([
   height: 100%;
   display: flex;
   flex-wrap: wrap;
-  gap: 16px; // 视频间距
   justify-content: flex-start;
 }
 
 // 视频项样式
 .video-item {
   width: 395px;
-  height: 240px;
+  height: 250px;
   display: flex;
   flex-direction: column;
   align-items: center;
   .live-video {
-    width: 90%;
-    height: 86%;
-    margin-top: 15px;
+    width: 100%;
+    height: 100%;
   }
 }
 </style>

+ 2 - 2
src/views/vent/home/configurable/components/belt/ComplexListBelt.vue

@@ -127,12 +127,12 @@ onMounted(() => {
 }
 /* 外层list-item奇数时的图标 */
 .list-item:nth-child(odd) .risk-text {
-  background-image: url('@/assets/images/beltFire/2-3.png');
+  background-image: url('@/assets/images/beltFire/2-6.png');
 }
 
 /* 外层list-item偶数时的图标 */
 .list-item:nth-child(even) .risk-text {
-  background-image: url('@/assets/images/beltFire/2-6.png');
+  background-image: url('@/assets/images/beltFire/2-3.png');
 }
 
 /* 底部:传感器名称 */

+ 2 - 2
src/views/vent/home/configurable/components/belt/CustomListBelt.vue

@@ -41,7 +41,7 @@
 </template>
 
 <script lang="ts" setup>
-withDefaults(
+const props = withDefaults(
   defineProps<{
     listConfig: {
       label: string;
@@ -53,7 +53,7 @@ withDefaults(
   }>(),
   {
     listConfig: () => [],
-    type: 'A',
+    type: 'B',
   }
 );
 const getBgClass = (riskLevel: string) => {

+ 4 - 1
src/views/vent/home/configurable/components/belt/CustomTableBelt.vue

@@ -21,7 +21,7 @@
   </div>
 </template>
 <script lang="ts" setup>
-import { computed, defineProps, ref } from 'vue';
+import { computed, defineProps, onMounted, ref } from 'vue';
 import _ from 'lodash';
 import { useAutoScroll } from '/@/hooks/core/useAutoScroll';
 
@@ -69,6 +69,9 @@ function get(o, p) {
   const d = _.get(o, p);
   return _.isNil(d) ? props.defaultValue : d === '' ? props.defaultValue : d;
 }
+onMounted(() => {
+  console.log(props.data, '-----data');
+});
 </script>
 <style lang="less" scoped>
 @import '/@/design/theme.less';

+ 9 - 7
src/views/vent/home/configurable/components/belt/FireSensorAnalysis.vue

@@ -10,10 +10,13 @@
         <!-- 循环渲染组内项 -->
         <div v-for="(item, itemIndex) in group.items" :key="itemIndex" class="sensor-item">
           <div class="item-icon"></div>
-          <template v-if="item.status !== undefined">
+          <template v-if="!item.info">
             <div class="item-status">
               <div class="item-label">{{ item.label }}:</div>
-              <span v-if="item.status !== undefined" class="status-dot" :class="parseStatus(item.status)"></span>
+              <div>
+                <span class="status-dot" :class="parseStatus(getFormattedText(data, item.code))"></span>
+                <span style="margin-left: 10px; color: #fafafa">{{ getFormattedText(data, item.code, item.trans) }}</span>
+              </div>
             </div>
           </template>
           <template v-else>
@@ -21,7 +24,8 @@
             <div class="item-content">
               <!-- 主要数值/状态 -->
               <span class="item-value"
-                >{{ getFormattedText(data, item.code) }} <span class="label">时刻</span> {{ getFormattedText(data, item.info!) }}
+                >{{ getFormattedText(data, item.code) }} <span class="label">时刻</span>
+                {{ getFormattedText(data, item.info?.code) }}
               </span>
             </div>
           </template>
@@ -42,6 +46,7 @@ const props = defineProps<{
     items: Array<{
       label: string;
       code: string;
+      trans?: String;
       status?: string;
       info?: string;
     }>;
@@ -55,9 +60,7 @@ const props = defineProps<{
  * 解析状态并返回对应的 CSS 类名
  */
 const parseStatus = (statusStr: string) => {
-  const statusVal = getFormattedText(props.data, statusStr);
-  // 假设 0 为正常,1 为报警
-  return statusVal === '1' ? 'status-danger' : 'status-normal';
+  return statusStr === 'true' ? 'status-danger' : 'status-normal';
 };
 </script>
 
@@ -81,7 +84,6 @@ const parseStatus = (statusStr: string) => {
 .sensor-group {
   background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
   background-size: 100% 100%;
-  padding: 10px;
 }
 
 /* 组标题 */

+ 12 - 11
src/views/vent/home/configurable/components/belt/SensorStatusPanel.vue

@@ -44,7 +44,7 @@
               }"
             >
               <span class="status-dot"></span>
-              <span>{{ getAlarmText(getFormattedText(data, sensor.contents[0].code)) }}</span>
+              <span>{{ getFormattedText(data, sensor.contents[0].code, sensor.contents[0].trans) }}</span>
             </div>
           </div>
           <div class="detail-row1">
@@ -52,8 +52,13 @@
               <span class="arrow-icon"></span> <span class="labelInfo">{{ sensor.contents[1].label }}</span></span
             >
             <div class="row-value" :style="{ color: sensor.contents[1].color }">
-              <span class="label">{{ getFormattedText(data, sensor.contents[1].code) }} <span class="text">时刻</span></span>
-              <span v-if="sensor.contents[1].info" class="info">{{ getFormattedText(data, sensor.contents[1].info.code) }}</span>
+              <span class="label" style="margin-left: 10px"
+                >{{ getFormattedText(data, sensor.contents[1].code) }}
+                <span class="text" style="margin-left: 10px">时刻</span>
+              </span>
+              <span v-if="sensor.contents[1].info" class="info" style="margin-left: 10px">{{
+                getFormattedText(data, sensor.contents[1].info.code)
+              }}</span>
             </div>
           </div>
         </div>
@@ -63,7 +68,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import { getFormattedText } from '../../hooks/helper';
 
 const props = defineProps<{
@@ -99,12 +104,9 @@ const getAlarmColor = (value) => {
   if (value === false || value == 0) return 'green';
   return 'white';
 };
-
-const getAlarmText = (value) => {
-  if (value === true) return '报警';
-  if (value === false) return '正常';
-  return value;
-};
+onMounted(() => {
+  console.log(props.data, '---data');
+});
 </script>
 
 <style scoped lang="less">
@@ -127,7 +129,6 @@ const getAlarmText = (value) => {
   background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
   background-size: 100% 100%;
   border-radius: 8px;
-  padding: 10px;
 }
 
 .sensor-header {

+ 3 - 4
src/views/vent/home/configurable/components/belt/SprayControl.vue

@@ -170,7 +170,6 @@ onMounted(() => {
 .sensor-group {
   background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
   background-size: 100% 100%;
-  padding: 10px;
 }
 
 /* 组标题 */
@@ -210,9 +209,9 @@ onMounted(() => {
 }
 .item-icon {
   background-size: 100% 100%;
-  width: 20px;
+  width: 30px;
   height: 20px;
-  margin-left: 10px;
+  margin-left: 8px;
 }
 .item-icon.bg-1 {
   background: url('@/assets/images/beltFire/yjkf/1-3area.svg') no-repeat;
@@ -252,7 +251,7 @@ onMounted(() => {
   display: flex;
   flex-direction: row;
   justify-content: space-between;
-  margin: 0 15px 0 20px;
+  margin: 0 15px 0 15px;
   .item-label {
     color: #fff;
     height: 30px;

+ 78 - 45
src/views/vent/home/configurable/components/belt/VehicleCOAnalysis.vue

@@ -7,13 +7,13 @@
         <div class="tip">
           <div class="icon"></div>
           <span class="label">车辆干扰排除</span>
-          <span class="text">{{ monitData.isRisk ? '开启' : '关闭' }}</span>
+          <span class="text">关闭</span>
           <div class="toggle-switch" :class="{ 'is-on': isOn }" @click="toggleSwitch">
             <div class="slider"></div>
           </div>
-          <span class="text1">{{ monitData.isRisk ? '关闭' : '开启' }}</span>
+          <span class="text1">开启</span>
         </div>
-        <button class="btn-history">历史分析记录</button>
+        <button class="btn-history" @click="visible = true">历史分析记录</button>
       </div>
     </div>
 
@@ -21,14 +21,14 @@
     <div class="section" v-for="item in filteredList('activity')" :key="item.type">
       <div class="section-title">{{ item.title }}</div>
       <div class="activity-list">
-        <div class="activity-item" v-for="(act, idx) in monitData.activityList" :key="idx">
+        <div class="activity-item" v-for="(act, idx) in monitData" :key="idx">
           <div class="info">
-            <span class="pos">{{ act.pos }}</span>
-            <span class="vehicle">{{ act.vehicle }}</span>
+            <span class="pos">{{ act.strName }}</span>
+            <span class="vehicle">{{ act.vehicle_id }}</span>
           </div>
           <div class="warnStatus">
-            <span class="status" :class="getStatusClass(act.status)"> </span>
-            <span class="status-text"> {{ getStatusText(act.status) }}</span>
+            <span class="status" :class="getStatusClass(act.result)"> </span>
+            <span class="status-text"> {{ act.result }}</span>
           </div>
         </div>
       </div>
@@ -39,30 +39,33 @@
       <div v-for="item in filteredList('analysis')" :key="item.type">
         <div class="section-title">{{ item.title }}</div>
         <div class="analysis-list">
-          <div class="analysis-item" v-for="(ana, idx) in monitData.analysisList" :key="idx">
-            <span class="label">{{ ana.pos }}</span>
-            <span class="text">{{ ana.analysisText }}</span>
-          </div>
-        </div>
-        <!-- 4. 可能原因与建议 (Reason Section) -->
-        <div v-for="i in filteredList('reasonAnalysis')" :key="i.type">
-          <div class="reason-item">
-            <span class="label">{{ i.items[0].label }}:</span>
-            <span class="value reason">{{ monitData.possibleCause }}</span>
-          </div>
-          <div class="reason-item">
-            <span class="label">{{ i.items[1].label }}:</span>
-            <span class="value recommendation">{{ monitData.recommendation }}</span>
+          <div v-for="(ana, idx) in monitData" :key="idx">
+            <div class="analysis-item">
+              <span class="label">{{ ana.strName }}</span>
+              <span class="text">{{ ana.judge }}</span>
+            </div>
+            <div v-for="i in filteredList('reasonAnalysis')" :key="i.type">
+              <div class="reason-item">
+                <span class="label">{{ i.items[0].label }}:</span>
+                <span class="value reason">{{ ana.cause }}</span>
+              </div>
+              <div class="reason-item">
+                <span class="label">{{ i.items[1].label }}:</span>
+                <span class="value recommendation">{{ ana.advice }}</span>
+              </div>
+            </div>
           </div>
         </div>
       </div>
     </div>
   </div>
+  <HistoryModal v-model="visible" columns-type="Leather_history" device-type="window" designScope="alarm-history" :scroll="scroll" />
 </template>
 
 <script lang="ts" setup>
-import { computed, ref } from 'vue';
-
+import { computed, onMounted, ref, reactive } from 'vue';
+import { getStatus, changeStatus } from '../../belt/configurable.api';
+import HistoryModal from './historyModal.vue';
 // 定义 Props,接收配置和模拟数据
 interface ConfigItem {
   type: string;
@@ -76,10 +79,10 @@ const props = withDefaults(
     list: ConfigItem[];
     data: {
       isRisk: boolean;
-      activityList: Array<{ pos: string; vehicle: string; status: string }>;
-      analysisList: Array<{ pos: string; analysisText: string }>;
-      possibleCause: string;
-      recommendation: string;
+      activityList: Array<{ strName: string; vehicle_id: string; result: string }>;
+      analysisList: Array<{ strName: string; judge: string }>;
+      cause: string;
+      advice: string;
     };
   }>(),
   {
@@ -88,28 +91,42 @@ const props = withDefaults(
       isRisk: false,
       activityList: [],
       analysisList: [],
-      possibleCause: '',
-      recommendation: '',
+      cause: '',
+      advice: '',
     }),
   }
 );
-
+const statusValue = ref(0);
+const visible = ref(false);
+const scroll = reactive({
+  y: 400,
+});
 const monitData = computed(() => props.data);
 // 自己维护开关状态,不依赖任何外部数据
-const isOn = ref(false);
 // --- 计算属性:根据 type 筛选配置项 ---
 const filteredList = (type: string) => {
   return props.list.filter((item) => item.type === type);
 };
 //滑块滑动
-const toggleSwitch = () => {
-  // const isOn = monitData.isRisk;
-  isOn.value = !isOn.value;
+const isOn = ref(false);
+const toggleSwitch = async () => {
+  const newStatus = statusValue.value === 1 ? 0 : 1;
+  try {
+    // 请求后端修改状态
+    const params = { status: newStatus };
+    await changeStatus(params);
+    statusValue.value = newStatus;
+    // isOn.value = newStatus === 1;
+    getStatusData();
+  } catch (err) {
+    console.error('切换状态失败', err);
+  }
 };
+
 // --- 方法:获取状态类名和文本 ---
 const getStatusClass = (status: string) => {
-  if (status === '0') return 'status-excluded';
-  if (status === '1') return 'status-warning';
+  if (status === '已排除') return 'status-excluded';
+  if (status === '预警') return 'status-warning';
   return '';
 };
 
@@ -118,6 +135,18 @@ const getStatusText = (status: string) => {
   if (status === '1') return '预警';
   return '未知';
 };
+const getStatusData = async () => {
+  try {
+    const res = await getStatus();
+    statusValue.value = res;
+    isOn.value = statusValue.value === 1 ? true : false;
+  } catch (err) {
+    console.error(err);
+  }
+};
+onMounted(async () => {
+  await getStatusData();
+});
 </script>
 
 <style scoped lang="less">
@@ -135,12 +164,10 @@ const getStatusText = (status: string) => {
   border: 1px solid #1a3b5d;
   color: #fafafa;
   font-family: 'Microsoft YaHei', sans-serif;
-  padding: 10px 15px;
+  padding: 10px 5px;
   position: relative;
-  /* overflow: hidden; */
 }
 
-/* 顶部标题样式 (虽然图里有,但数据配置里没单独标题,这里用 CSS 模拟顶部栏) */
 .monitor-container::before {
   content: '';
   position: absolute;
@@ -158,6 +185,11 @@ const getStatusText = (status: string) => {
   background-size: 100% 100%;
 }
 
+.section:first-child {
+  margin: 0;
+  padding: 5px 0 5px 10px;
+}
+
 .section-title {
   background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
   background-size: 35% 100%;
@@ -218,7 +250,7 @@ const getStatusText = (status: string) => {
   align-items: center;
   justify-content: space-between;
   padding: 5px 5px;
-  width: 50px;
+  width: 36px;
   height: 20px;
   border-radius: 15px;
   position: relative;
@@ -279,12 +311,12 @@ const getStatusText = (status: string) => {
   padding: 5px 8px;
   color: #fafafa;
   font-size: 12px;
-
   .info {
     display: flex;
     align-items: center;
     padding: 2px 12px;
-    gap: 60px;
+    gap: 108px;
+    flex: 1;
     color: #fafafa;
     background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
     background-size: 100% 100%;
@@ -295,12 +327,12 @@ const getStatusText = (status: string) => {
   }
 
   .warnStatus {
+    width: 80px;
     display: flex;
     align-items: center;
     justify-content: space-around;
     margin-left: 10px;
     padding: 2px 10px;
-    flex: 1;
     background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
     background-size: 100% 100%;
     .status {
@@ -320,6 +352,7 @@ const getStatusText = (status: string) => {
     }
     .status-text {
       color: #fafafa;
+      margin-left: 10px;
     }
   }
 }
@@ -379,4 +412,4 @@ const getStatusText = (status: string) => {
 .recommendation {
   color: #ff5252;
 }
-</style>
+</style>

+ 1 - 2
src/views/vent/home/configurable/components/belt/WarningResultList.vue

@@ -59,8 +59,7 @@ const props = defineProps<{
     [key: string]: any;
   };
 }>();
-onMounted(() => {
-});
+onMounted(() => {});
 </script>
 
 <style scoped lang="less">

+ 259 - 0
src/views/vent/home/configurable/components/belt/historyModal.vue

@@ -0,0 +1,259 @@
+<template>
+  <!-- 1. 传送到 body → 全屏显示 -->
+  <Teleport to="body">
+    <!-- 2. 全屏遮罩 + 居中 -->
+    <div v-if="modelValue" class="modal-overlay" @click.self="close">
+      <!-- 3. 弹窗容器(带标题、关闭、样式) -->
+      <div class="modal-container">
+        <div class="dialog-header">
+          <h3>应急控制</h3>
+        </div>
+        <div class="close-btn" @click="close">
+          <img src="@/assets/images/beltFire/fireMonitor/close.svg" alt="" />
+        </div>
+        <!-- 4. 你原来的表格组件(直接放这里) -->
+        <div class="table-box">
+          <BasicTable ref="handlerHistory" @register="registerTable" />
+        </div>
+      </div>
+    </div>
+  </Teleport>
+</template>
+
+<script lang="ts" name="HistoryModal" setup>
+import { watch, ref, defineExpose } from 'vue';
+import { BasicTable } from '/@/components/Table';
+import { useListPage } from '/@/hooks/system/useListPage';
+import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
+import { defHttp } from '/@/utils/http/axios';
+import dayjs from 'dayjs';
+import { getAutoScrollContainer } from '/@/utils/common/compUtils';
+
+// 接口
+const list = (params) =>
+  defHttp.get({
+    url: '/ventanaly-device/safety/deviceVehiclePass/getByDeviceAndTime',
+    params,
+  });
+
+// 接收 v-model
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  columnsType: {
+    type: String,
+    required: true,
+  },
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  designScope: { type: String },
+  sysId: { type: String },
+  deviceId: { type: String, default: '' },
+  scroll: { type: Object, default: { y: 0 } },
+});
+
+const emit = defineEmits(['update:modelValue']);
+const close = () => emit('update:modelValue', false);
+
+// 表格
+const handlerHistory = ref();
+const columns = ref([]);
+const tableScroll = props.scroll.y ? ref({ y: props.scroll.y - 100 }) : ref({});
+
+watch(
+  () => props.columnsType,
+  (newVal) => {
+    const column = getTableHeaderColumns(newVal);
+    if (column && column.length < 1) {
+      const arr = newVal.split('_');
+      columns.value = getTableHeaderColumns(arr[0] + '_history');
+    } else {
+      columns.value = column;
+    }
+    if (handlerHistory.value) reload();
+  },
+  { immediate: true }
+);
+
+watch(
+  () => props.scroll.y,
+  (newVal) => {
+    if (newVal) tableScroll.value = { y: newVal - 100 };
+    else tableScroll.value = {};
+  }
+);
+
+const { tableContext } = useListPage({
+  tableProps: {
+    api: list,
+    columns: columns,
+    canResize: true,
+    showTableSetting: false,
+    showActionColumn: false,
+    showIndexColumn: true,
+    bordered: false,
+    size: 'small',
+    scroll: tableScroll,
+    formConfig: {
+      labelAlign: 'left',
+      showAdvancedButton: false,
+      baseColProps: {
+        xs: 24,
+        sm: 24,
+        md: 24,
+        lg: 9,
+        xl: 7,
+        xxl: 4,
+      },
+      schemas: [
+        {
+          field: 'createTime_begin',
+          label: '开始时间',
+          component: 'DatePicker',
+          defaultValue: dayjs().add(-30, 'day').format('YYYY-MM-DD HH:mm:ss'),
+          required: true,
+          componentProps: {
+            showTime: true,
+            valueFormat: 'YYYY-MM-DD HH:mm:ss',
+            getPopupContainer: getAutoScrollContainer,
+          },
+          colProps: { span: 7 },
+        },
+        {
+          field: 'createTime_end',
+          label: '结束时间',
+          component: 'DatePicker',
+          defaultValue: dayjs(),
+          required: true,
+          componentProps: {
+            showTime: true,
+            valueFormat: 'YYYY-MM-DD HH:mm:ss',
+            getPopupContainer: getAutoScrollContainer,
+          },
+          colProps: { span: 7 },
+        },
+      ],
+    },
+    fetchSetting: { listField: 'records' },
+    pagination: {
+      current: 1,
+      pageSize: 10,
+      pageSizeOptions: ['10', '30', '50', '100'],
+    },
+    beforeFetch(params) {
+      params.devicetype = props.deviceType + '*';
+      if (props.sysId) params.sysId = props.sysId;
+      if (props.deviceId) params.deviceid = props.deviceId;
+    },
+  },
+});
+
+const [registerTable, { reload, setLoading }] = tableContext;
+defineExpose({ setLoading });
+</script>
+
+<style scoped lang="less">
+@ventSpace: zxm;
+
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.3);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.modal-container {
+  width: 85%;
+  max-width: 1200px;
+  max-height: 85vh;
+  background: url('/@/assets/images/beltFire/fireMonitor/modalBorder.png') no-repeat;
+  background-size: 100% 100%;
+  border-radius: 6px;
+  color: #fff;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+}
+
+.close-btn {
+  position: absolute;
+  top: -12px;
+  right: -12px;
+  width: 30px;
+  height: 30px;
+  cursor: pointer;
+  z-index: 10;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  img {
+    width: 100%;
+    height: 100%;
+    display: block;
+  }
+}
+.dialog-header {
+  padding: 20px 24px;
+  text-align: center;
+  color: #fff;
+  background: url('/@/assets/images/beltFire/fireMonitor/historyTitle.png') no-repeat;
+  background-size: 100% 40%;
+  width: 100%;
+  margin: 30px auto 0;
+}
+
+.dialog-header h3 {
+  margin: 5px;
+  font-size: 18px;
+  color: #fff;
+  margin-top: -35px;
+  font-family: 'douyuFont';
+}
+.close-btn :hover {
+  cursor: pointer;
+}
+
+.table-box {
+  flex: 1;
+  overflow: auto;
+  padding: 10px;
+}
+
+.table-box {
+  width: 100%;
+  :deep(.jeecg-basic-table-form-container) {
+    .@{ventSpace}-form {
+      padding: 0 !important;
+      border: none !important;
+      margin-bottom: 0 !important;
+      .@{ventSpace}-picker,
+      .@{ventSpace}-select-selector {
+        width: 100% !important;
+        height: 100%;
+        background: #00000017;
+        border: 1px solid #b7b7b7;
+        input,
+        .@{ventSpace}-select-selection-item,
+        .@{ventSpace}-picker-suffix {
+          color: #fff;
+        }
+        .@{ventSpace}-select-selection-placeholder {
+          color: #ffffffaa;
+        }
+      }
+    }
+    .@{ventSpace}-table-title {
+      min-height: 0 !important;
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/vent/home/configurable/components/content.vue

@@ -83,7 +83,7 @@
             <TimelineListNew class="content__module" :list-config="config.items" />
           </template>
           <template v-else-if="config.pagetype === 'Belt'">
-            <CustomListBelt class="content__module" :type="config.type" :list-config="config.items" />
+            <CustomListBelt class="content__module" :type="config.type" :list-config="config.items" :data="data" />
           </template>
           <template v-else>
             <CustomList class="content__module" :type="config.type" :list-config="config.items" />