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

[Feat 0000]喷淋管控系统左侧配置内容功能实现及样式修改

wangkeyi пре 1 месец
родитељ
комит
6ea99d437e

+ 68 - 8
src/views/vent/home/configurable/belt/configurable.data.ts

@@ -1002,11 +1002,11 @@ export const testSpary: Config[] = [
     pageType: 'beltYjkf1',
     moduleData: {
       header: {
-        show: false,
+        show: true,
         readFrom: '',
         selector: {
-          show: false,
-          value: '',
+          show: true,
+          value: '${beltName}',
         },
         slot: {
           show: false,
@@ -1037,7 +1037,7 @@ export const testSpary: Config[] = [
       complex_list: [],
       preset: [
         {
-          readFrom: 'sprayData',
+          readFrom: 'plmhInfo',
           type: 'C',
           config: [
             {
@@ -1058,7 +1058,7 @@ export const testSpary: Config[] = [
                   code: 'netStatus',
                   trans: {
                     0: '断开',
-                    1: '连接',
+                    1: '正常',
                   },
                 },
                 {
@@ -1066,12 +1066,12 @@ export const testSpary: Config[] = [
                   code: 'runStatus',
                   trans: {
                     0: '断开',
-                    1: '连接',
+                    1: '正常',
                   },
                 },
                 {
                   label: '水量',
-                  code: '${waterVolume}',
+                  code: 'waterVolume',
                 },
                 {
                   label: '水压',
@@ -1082,7 +1082,67 @@ export const testSpary: Config[] = [
           ],
         },
       ],
-      // mock: doorMock,
+      mock: {
+        plmhInfo: [
+          {
+            id: '1',
+            beltName: '1#皮带区域',
+            beltData: [
+              {
+                sid: '1',
+                beltArea: '1#皮带区域',
+                devicePosition: '1#皮带-50m处',
+                netStatus: '1',
+                runStatus: '1',
+                waterVolume: '0.0',
+                waterPressure: '0.0 Mpa',
+              },
+              {
+                sid: '2',
+                beltArea: '1#皮带区域',
+                devicePosition: '1#皮带-100m处',
+                netStatus: '1',
+                runStatus: '1',
+                waterVolume: '0.0',
+                waterPressure: '0.0 Mpa',
+              },
+              {
+                sid: '3',
+                beltArea: '1#皮带区域',
+                devicePosition: '1#皮带-150m处',
+                netStatus: '1',
+                runStatus: '1',
+                waterVolume: '0.0',
+                waterPressure: '0.0 Mpa',
+              },
+            ],
+          },
+          {
+            id: '2',
+            beltName: '2#皮带区域',
+            beltData: [
+              {
+                sid: '4',
+                beltArea: '2#皮带区域',
+                devicePosition: '2#皮带-50m处',
+                netStatus: '1',
+                runStatus: '1',
+                waterVolume: '0.0',
+                waterPressure: '0.0 Mpa',
+              },
+              {
+                sid: '5',
+                beltArea: '2#皮带区域',
+                devicePosition: '2#皮带-100m处',
+                netStatus: '1',
+                runStatus: '1',
+                waterVolume: '0.0',
+                waterPressure: '0.0 Mpa',
+              },
+            ],
+          },
+        ],
+      },
     },
     showStyle: {
       size: 'width:440px;height:825px;',

+ 294 - 227
src/views/vent/home/configurable/components/belt/SprayControl.vue

@@ -4,28 +4,43 @@
     <div class="sensor-list">
       <!-- 按钮 -->
       <div class="control-bar">
-        <a-button class="control-btn">启动喷淋</a-button>
-        <a-button class="control-btn">停止喷淋</a-button>
+        <a-button class="control-btn" @click="handleSpary(true)">启动喷淋</a-button>
+        <a-button class="control-btn" @click="handleSpary(false)">停止喷淋</a-button>
         <a-button class="control-btn">手动控制</a-button>
         <a-button class="control-btn">自动控制</a-button>
       </div>
       <!-- 循环渲染分组 -->
-      <div v-for="(group, index) in config.config" :key="index" class="sensor-group">
-        <!-- 组标题 -->
-        <div class="group-title"> <a-checkbox class="check-btn">控制勾选</a-checkbox> </div>
-        <!-- 循环渲染组内项 -->
-        <div v-for="(item, itemIndex) in group.contentTop" :key="itemIndex" class="sensor-item" :class="getBgClass(itemIndex)">
-          <div class="item-icon" :class="getBgClass(itemIndex)"></div>
-          <div class="item-status">
-            <div class="item-label">{{ item.label }}</div>
-            <div class="item-code">{{ getFormattedText(data, item.code) }}</div>
+      <div v-for="(beltData, index) in data.beltData" :key="index" class="block-item">
+        <!-- {{ beltData }} -->
+        <!-- 这里应该由data渲染,因为data数量是动态不固定的,config.config是静态的 -->
+        <div v-for="(group, index) in config.config" :key="index" class="sensor-group">
+          <!-- 组标题 -->
+          <div class="group-title">
+            <a-checkbox
+              class="check-btn"
+              :checked="selectedSids.includes(beltData.sid)"
+              @change="(e) => handleCheckChange(e.target.checked, beltData.sid)"
+            >
+              控制勾选
+            </a-checkbox>
           </div>
-        </div>
-        <div class="container">
-          <div v-for="(item, itemIndex) in group.contents" :key="itemIndex" class="dataInfo-item" :class="getBgClass(itemIndex)">
+          <!-- 循环渲染组内项 -->
+          <div v-for="(item, itemIndex) in group.contentTop" :key="itemIndex" class="sensor-item" :class="getBgClass(itemIndex)">
+            <div class="item-icon" :class="getBgClass(itemIndex)"></div>
             <div class="item-status">
               <div class="item-label">{{ item.label }}</div>
-              <div class="item-code"><span class="status-dot" v-if="item.trans"> </span>{{ getFormattedText(data, item.code, item.trans) }}</div>
+              <div class="item-code">{{ getItemText(beltData, item) }}</div>
+            </div>
+          </div>
+          <div class="container">
+            <div v-for="(item, itemIndex) in group.contents" :key="itemIndex" class="dataInfo-item" :class="getBgClass(itemIndex)">
+              <div class="item-status">
+                <div class="item-label">{{ item.label }}</div>
+                <div class="item-code">
+                  <span class="status-dot" v-if="item.trans" :class="getStatusClass(beltData, item)"> </span>
+                  {{ getItemText(beltData, item) }}
+                </div>
+              </div>
             </div>
           </div>
         </div>
@@ -35,246 +50,298 @@
 </template>
 
 <script setup lang="ts">
-import { computed, onMounted, ref } from 'vue';
-import { getFormattedText } from '../../hooks/helper';
+  import { computed, onMounted, ref } from 'vue';
+  import { getFormattedText } from '../../hooks/helper';
 
-const props = defineProps<{
-  config: Array<{
-    readFrom: string;
-    contentTop: Array<{
-      label: string;
-      code: string;
-      status?: string;
-      info?: string;
+  const props = defineProps<{
+    config: Array<{
+      readFrom: string;
+      contentTop: Array<{
+        label: string;
+        code: string;
+        status?: string;
+        info?: string;
+      }>;
+      contents: Array<{
+        label: string;
+        code: string;
+        trans?: any;
+      }>;
     }>;
-    contents: Array<{
-      label: string;
-      code: string;
-      trans?: any;
-    }>;
-  }>;
-  data: {
-    [key: string]: any;
+    data: {
+      [key: string]: any;
+    };
+  }>();
+
+  // --- 存储选中的 sid ---
+  const selectedSids = ref<string[]>([]);
+
+  // --- 处理勾选变化 ---
+  const handleCheckChange = (checked: boolean, sid: string) => {
+    if (checked) {
+      // 勾选:如果不存在则加入数组
+      if (!selectedSids.value.includes(sid)) {
+        selectedSids.value.push(sid);
+      }
+    } else {
+      // 取消勾选:从数组中移除
+      const index = selectedSids.value.indexOf(sid);
+      if (index > -1) {
+        selectedSids.value.splice(index, 1);
+      }
+    }
+    console.log('当前选中的 SID 列表:', selectedSids.value);
   };
-}>();
-const getBgClass = (index) => {
-  return index % 2 === 0 ? 'bg-1' : 'bg-2';
-};
-onMounted(() => {
-  console.log(props.config, '123');
-});
-</script>
+  const getBgClass = (index) => {
+    return index % 2 === 0 ? 'bg-1' : 'bg-2';
+  };
+  /**
+   * 根据配置项从当前皮带数据中获取对应的值
+   * @param currentItem 当前循环到的单条皮带数据 (beltData)
+   * @param configItem 配置项 (包含 code 和 trans)
+   */
+  const getItemText = (currentItem: any, configItem: { code: string; trans?: any }) => {
+    // 1. 获取原始值: 通过 code 字段从 currentItem 中取值
+    const rawValue = currentItem[configItem.code];
 
-<style scoped lang="less">
-/* 全局面板样式 */
-.fire-safety-panel {
-  border-radius: 8px;
-  padding: 3px;
-  color: #fff;
-  font-family: 'Microsoft YaHei', sans-serif;
-  padding-top: 10px;
-}
-/* 列表容器 */
-.sensor-list {
-  display: flex;
-  flex-direction: column;
-  gap: 15px; /* 组间距 */
-}
-/** 按钮 **/
-.control-bar {
-  background: url('@/assets/images/beltFire/yjkf/1-2title.png');
-  background-size: 100% 100%;
-  display: flex;
-  justify-content: space-around;
-  height: 50px;
-}
-.control-btn {
-  background: linear-gradient(180deg, #34b7f1 0%, #1890ff 100%);
-  border: 1px solid #40c4ff;
-  color: #fff;
-  font-size: 12px;
-  padding: 2px 8px;
-  height: 24px;
-  margin: auto;
-  box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-}
+    // 2. 如果有翻译映射 (trans),则进行翻译
+    if (configItem.trans && configItem.trans[rawValue] !== undefined) {
+      return configItem.trans[rawValue];
+    }
 
-/* 分组卡片 */
-.sensor-group {
-  background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
-  background-size: 100% 100%;
-  padding: 10px;
-}
+    // 3. 没有翻译则直接返回原始值
+    return rawValue;
+  };
+  const handleSpary = (state: boolean) => {
+    if (state) {
+      console.log('启动喷淋');
+    } else {
+      console.log('停止喷淋');
+    }
+  };
+  const getStatusClass = (beltData: any, item: any) => {
+    const val = getItemText(beltData, item);
+    // 根据翻译后的值判断颜色(连接=绿,断开=红)
+    if (val === '正常') return 'status-normal';
+    if (val === '断开') return 'status-danger';
+    return '';
+  };
+  onMounted(() => {
+    console.log(props.config, '123');
+    console.log(props.data, 'data');
+  });
+</script>
 
-/* 组标题 */
-.group-title {
-  background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
-  background-size: 35% 100%;
-  color: #fff;
-  font-size: 12px;
-  font-weight: bold;
-  font-style: italic;
-  margin-bottom: 8px;
-  padding-bottom: 5px;
-  padding-left: 10px;
-  .check-btn {
+<style scoped lang="less">
+  /* 全局面板样式 */
+  .fire-safety-panel {
+    border-radius: 8px;
+    padding: 3px;
+    color: #fff;
+    font-family: 'Microsoft YaHei', sans-serif;
+    padding-top: 10px;
+  }
+  /* 列表容器 */
+  .sensor-list {
+    display: flex;
+    flex-direction: column;
+    gap: 15px; /* 组间距 */
+  }
+  /** 按钮 **/
+  .control-bar {
+    background: url('@/assets/images/beltFire/yjkf/1-2title.png');
+    background-size: 100% 100%;
+    display: flex;
+    justify-content: space-around;
+    height: 50px;
+  }
+  .control-btn {
+    background: linear-gradient(180deg, #34b7f1 0%, #1890ff 100%);
+    border: 1px solid #40c4ff;
     color: #fff;
     font-size: 12px;
+    padding: 2px 8px;
+    height: 24px;
+    margin: auto;
+    box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
   }
-}
-
-/* 列表项 */
-.sensor-item {
-  height: 30px;
-  background-size: 100% 100%;
-  display: flex;
-  align-items: center;
-  margin-bottom: 5px;
-  font-size: 13px;
-  color: #c0d0e0;
-  overflow-y: auto;
-  background-repeat: no-repeat;
-}
-.sensor-item.bg-1 {
-  background-image: url('@/assets/images/beltFire/yjkf/1-5.png');
-}
-.sensor-item.bg-2 {
-  background-image: url('@/assets/images/beltFire/yjkf/1-6.png');
-}
-.item-icon {
-  background-size: 100% 100%;
-  width: 20px;
-  height: 20px;
-  margin-left: 10px;
-}
-.item-icon.bg-1 {
-  background: url('@/assets/images/beltFire/yjkf/1-3area.svg') no-repeat;
-}
-
-.item-icon.bg-2 {
-  background: url('@/assets/images/beltFire/yjkf/1-4wz.svg') no-repeat;
-}
-.container {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 10px;
-}
-.dataInfo-item {
-  display: flex;
-  justify-content: space-around;
-  margin-bottom: 5px;
-  font-size: 13px;
-  width: calc(50% - 5px);
-  color: #c0d0e0;
-}
 
-.dataInfo-item:nth-child(1),
-.dataInfo-item:nth-child(4) {
-  background: url('@/assets/images/beltFire/yjkf/1-7.png') no-repeat;
-  background-size: 100% 100%;
-}
-
-.dataInfo-item:nth-child(2),
-.dataInfo-item:nth-child(3) {
-  background: url('@/assets/images/beltFire/yjkf/1-8.png') no-repeat;
-  background-size: 100% 100%;
-}
+  /* 分组卡片 */
+  .sensor-group {
+    background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
+    background-size: 100% 100%;
+    padding: 10px;
+  }
 
-.item-status {
-  width: 100%;
-  display: flex;
-  flex-direction: row;
-  justify-content: space-between;
-  margin-left: 20px;
-  font-weight: bold;
-  .item-label {
+  /* 组标题 */
+  .group-title {
+    background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
+    background-size: 35% 100%;
     color: #fff;
-    height: 30px;
-    line-height: 30px;
+    font-size: 12px;
+    font-weight: bold;
+    font-style: italic;
+    margin-bottom: 8px;
+    padding-bottom: 5px;
+    padding-left: 10px;
+    .check-btn {
+      color: #fff;
+      font-size: 12px;
+    }
   }
-  .item-code {
+
+  /* 列表项 */
+  .sensor-item {
     height: 30px;
-    line-height: 30px;
-    text-align: right;
-    color: #91faff;
-    font-size: 12px;
+    background-size: 100% 100%;
+    display: flex;
+    align-items: center;
+    margin-bottom: 5px;
+    font-size: 13px;
+    color: #c0d0e0;
+    overflow-y: auto;
+    background-repeat: no-repeat;
+  }
+  .sensor-item.bg-1 {
+    background-image: url('@/assets/images/beltFire/yjkf/1-5.png');
+  }
+  .sensor-item.bg-2 {
+    background-image: url('@/assets/images/beltFire/yjkf/1-6.png');
+  }
+  .item-icon {
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    margin-left: 10px;
+  }
+  .item-icon.bg-1 {
+    background: url('@/assets/images/beltFire/yjkf/1-3area.svg') no-repeat;
   }
-}
 
-.item-content {
-  flex: 1;
-  display: flex;
-  align-items: center;
-  .label {
-    color: #fff;
+  .item-icon.bg-2 {
+    background: url('@/assets/images/beltFire/yjkf/1-4wz.svg') no-repeat;
+  }
+  .container {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+  .dataInfo-item {
+    display: flex;
+    justify-content: space-around;
+    margin-bottom: 5px;
+    font-size: 13px;
+    width: calc(50% - 5px);
+    color: #c0d0e0;
   }
-}
 
-.item-value {
-  margin-right: 10px;
-  font-size: 12px;
-  color: #36dae7;
-}
-.item-info {
-  color: #ffff;
-  font-size: 11px;
-}
+  .dataInfo-item:nth-child(1),
+  .dataInfo-item:nth-child(4) {
+    background: url('@/assets/images/beltFire/yjkf/1-7.png') no-repeat;
+    background-size: 100% 100%;
+  }
 
-/* 状态指示灯 */
-.status-dot {
-  display: inline-block;
-  width: 10px;
-  height: 10px;
-  border-radius: 50%;
-  margin-left: 5px;
-  margin-top: 10px;
-  animation: pulse 2s infinite;
-  background: #3a3a3a;
-  position: absolute;
-  left: 0;
-  top: 50%;
-  transform: translateY(-50%);
-  box-shadow: 0 0 6px 2px rgba(90, 90, 90, 0.6);
-  &.status-normal {
-    background-color: #00ff00;
-    box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
+  .dataInfo-item:nth-child(2),
+  .dataInfo-item:nth-child(3) {
+    background: url('@/assets/images/beltFire/yjkf/1-8.png') no-repeat;
+    background-size: 100% 100%;
   }
 
-  &.status-danger {
-    background-color: #ff4d4d;
-    box-shadow: 0 0 6px 2px rgba(255, 48, 48, 0.6);
-    animation: flash 1s infinite;
+  .item-status {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    margin: 0 15px 0 20px;
+    .item-label {
+      color: #fff;
+      height: 30px;
+      line-height: 30px;
+    }
+    .item-code {
+      height: 30px;
+      line-height: 30px;
+      text-align: right;
+      color: #91faff;
+      font-size: 12px;
+      font-family: 'douyuFont';
+    }
   }
-}
 
-/* 动画效果 */
-@keyframes pulse {
-  0% {
-    transform: scale(1);
-    opacity: 1;
+  .item-content {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    .label {
+      color: #fff;
+    }
   }
-  50% {
-    transform: scale(1.2);
-    opacity: 0.8;
+
+  .item-value {
+    margin-right: 10px;
+    font-size: 12px;
+    color: #36dae7;
   }
-  100% {
-    transform: scale(1);
-    opacity: 1;
+  .item-info {
+    color: #ffff;
+    font-size: 11px;
   }
-}
 
-@keyframes flash {
-  0% {
-    opacity: 1;
+  /* 状态指示灯 */
+  .status-dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    margin-left: 5px;
+    margin-top: 10px;
+    animation: pulse 2s infinite;
+    background: #3a3a3a;
+    // position: absolute;
+    // left: 0;
+    // top: 50%;
+    transform: translateY(-50%);
+    box-shadow: 0 0 6px 2px rgba(90, 90, 90, 0.6);
+    &.status-normal {
+      background-color: #00ff00;
+      box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
+    }
+
+    &.status-danger {
+      background-color: #ff4d4d;
+      box-shadow: 0 0 6px 2px rgba(255, 48, 48, 0.6);
+      animation: flash 1s infinite;
+    }
   }
-  50% {
-    opacity: 0.5;
+
+  /* 动画效果 */
+  @keyframes pulse {
+    0% {
+      transform: scale(1);
+      opacity: 1;
+    }
+    50% {
+      transform: scale(1.2);
+      opacity: 0.8;
+    }
+    100% {
+      transform: scale(1);
+      opacity: 1;
+    }
   }
-  100% {
-    opacity: 1;
+
+  @keyframes flash {
+    0% {
+      opacity: 1;
+    }
+    50% {
+      opacity: 0.5;
+    }
+    100% {
+      opacity: 1;
+    }
   }
-}
 </style>

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

@@ -199,7 +199,7 @@
         </template>
         <!-- 3. 火灾监测设备分析 -->
         <template v-if="config.name === 'sprayCtrl'">
-          <SprayControl class="content__module" :config="config.config" :data="config.data" />
+          <SprayControl class="content__module" :config="config.config" :data="data" />
         </template>
         <template v-if="config.name === 'cameraList'">
           <CameraList class="content__module" :config="config.config" :data="config.data" />