Explorar o código

Merge branch 'master' of http://39.97.59.228:8013/hrx/goaf-monitoring-system

hongrunxia hai 3 meses
pai
achega
db924aee27

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/js/shanxi.geo.json


+ 80 - 0
src/api/sys/map.ts

@@ -0,0 +1,80 @@
+import { defHttp } from '/@/utils/http/axios';
+import { omitBy, isNil } from 'lodash-es';
+
+enum Api {
+  list = '/province/mineData/getMineData',
+  getGoafAlarmLevel = '/province/homeData/getGoafAlarmLevel',
+}
+/**
+ * 列表接口
+ * @param params
+ */
+export function getMarkers(params: any): Promise<any> {
+  return defHttp.post({ url: Api.list, params: omitBy(params, isNil) }, { joinParamsToUrl: true }).then(({ records }) => {
+    // const presets = [
+    //   ['36.644181586865905', '109.48980355362514', '1566106'],
+    //   ['36.644181586865905', '109.48980355362514', '1566106'],
+    //   // [33.063924198120645, 107.01782226562501, '1566101'],
+    //   // [34.34116826510752, 108.93468369998695, '1566103'],
+    //   ['34.361576287484176', '107.23571011212084', '1566107'],
+    //   ['34.361576287484176', '107.23571011212084', '1566107'],
+    // ];
+    // const presets2 = [
+    //   ['36.534181586865905', '109.39980355362514', '1566106'],
+    //   ['36.434181586865905', '109.29980355362514', '1566106'],
+    //   ['34.461576287484176', '107.33571011212084', '1566107'],
+    //   ['34.561576287484176', '107.43571011212084', '1566107'],
+    // ];
+    const presets = {
+      '810321182c6a40fa92d5acccdba34ce3': [
+        ['36.534181586865905', '109.39980355362514', '1566106'],
+        ['36.434181586865905', '109.29980355362514', '1566106'],
+        ['36.644181586865905', '109.48980355362514', '1566106'],
+      ],
+      '63afd272d0e24c7e9c1475c6498f0c80': [
+        ['34.461576287484176', '107.33571011212084', '1566103'],
+        ['34.561576287484176', '107.43571011212084', '1566103'],
+        ['34.361576287484176', '107.23571011212084', '1566103'],
+      ],
+    };
+
+    const results: any = {};
+
+    records.forEach((ele) => {
+      const temp = {
+        name: ele.mineName,
+        radius: 10,
+        ...ele,
+      };
+      if (results[ele.managementId]) {
+        results[ele.managementId].children.push(temp);
+      } else {
+        results[ele.managementId] = {
+          ...temp,
+          children: [temp],
+        };
+      }
+    });
+
+    return Object.values(results).map((ele: any) => {
+      return {
+        ...ele,
+        lat: presets[ele.managementId][2][0],
+        lng: presets[ele.managementId][2][1],
+        gb: presets[ele.managementId][2][2],
+        children: ele.children.map((ele2: any, index) => {
+          return {
+            ...ele2,
+            lat: presets[ele.managementId][index][0],
+            lng: presets[ele.managementId][index][1],
+            gb: presets[ele.managementId][index][2],
+          };
+        }),
+      };
+    });
+  });
+}
+
+export function getGoafAlarmLevel(params: any): Promise<any> {
+  return defHttp.post({ url: Api.getGoafAlarmLevel, params: omitBy(params, isNil) }, { joinParamsToUrl: true });
+}

+ 269 - 96
src/layouts/default/feature/SimpleMap.vue

@@ -1,25 +1,72 @@
 <template>
   <div ref="mapContainer" class="map-container"></div>
+  <div class="map-reset-btn">
+    <Button type="primary" @click="reset"> 重置 </Button>
+  </div>
 </template>
 
-<script setup>
+<script lang="ts" setup>
   import { ref, onMounted, onUnmounted } from 'vue';
   // 引入 Leaflet
   import L from 'leaflet';
   import 'leaflet/dist/leaflet.css';
+  import { getGoafAlarmLevel, getMarkers } from '/@/api/sys/map';
+  import { StatusColorEnum } from '/@/enums/jeecgEnum';
+  import { Button } from 'ant-design-vue';
   // Ant Design Vue 图标
-
   // --- 1. 组件引用和状态定义 ---
   const mapContainer = ref(null);
-  let map = null; // Leaflet 地图实例
 
-  // --- 2. 瓦片图层配置 ---
-  const tileLayers = {
-    custom: {
+  const DEFAULT_LAYER_ID = 'default';
+  // 邮政编码,GeoJSON中存有完整编码,下面是去掉了后两位00的编码
+  const layerMap = new Map<string, L.Layer>([
+    [DEFAULT_LAYER_ID, L.featureGroup()],
+    // 西安
+    ['1566101', L.featureGroup()],
+    // 铜川
+    ['1566102', L.featureGroup()],
+    // 宝鸡
+    ['1566103', L.featureGroup()],
+    // 咸阳
+    ['1566104', L.featureGroup()],
+    // 渭南
+    ['1566105', L.featureGroup()],
+    // 延安
+    ['1566106', L.featureGroup()],
+    // 汉中
+    ['1566107', L.featureGroup()],
+    // 榆林
+    ['1566108', L.featureGroup()],
+    // 安康
+    ['1566109', L.featureGroup()],
+    // 商洛
+    ['1566111', L.featureGroup()],
+  ]);
+  const colorMap = new Map<string, string>([
+    ['1566101', '#14baff'],
+    ['1566102', '#14baff'],
+    ['1566103', '#ffff12'],
+    ['1566104', '#ffff12'],
+    ['1566105', '#ffab12'],
+    ['1566106', '#ffab12'],
+    ['1566107', '#fe1414'],
+    ['1566108', '#fe1414'],
+    ['1566109', '#fe1414'],
+    ['1566111', '#fe1414'],
+    ['810321182c6a40fa92d5acccdba34ce3', '#ffff12'],
+    ['63afd272d0e24c7e9c1475c6498f0c80', '#ffab12'],
+  ]);
+
+  let map: typeof L = null; // Leaflet 地图实例
+
+  // --- 2. 配置项声明 ---
+  const tileLayers: any[] = [
+    {
       name: '基准瓦片',
       layer: null,
       url: 'https://shaanxizhxx.chinamine-safety.gov.cn/zh1/8/33/17.png',
       // url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
+      addByDefault: false,
       options: {
         maxZoom: 18,
         // attribution: '',
@@ -27,19 +74,21 @@
         // crossOrigin: true,
       },
     },
-    satellite: {
+    {
       name: '卫星图',
       layer: null,
       url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
+      addByDefault: false,
       options: {
         maxZoom: 18,
         attribution: '© Esri',
       },
     },
-    gaode: {
+    {
       name: '高德地图',
       layer: null,
       url: 'https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
+      addByDefault: true,
       options: {
         className: 'light-blue-theme',
         maxZoom: 18,
@@ -47,26 +96,13 @@
         attribution: '© 高德地图', // 版权声明(必填,遵守使用规范)
       },
     },
-  };
-
-  // 添加一个风险点示例(类似第一张图的红色气泡)
+  ];
 
   // --- 3. 地图初始化 ---
   onMounted(() => {
-    initMap();
-  });
-
-  onUnmounted(() => {
-    if (map) {
-      map.remove();
-    }
-  });
-
-  // 初始化地图
-  function initMap() {
     if (!mapContainer.value) return;
 
-    // 创建地图实例,设置太原市中心和初始缩放级别
+    // 创建地图实例,设置中心和初始缩放级别
     map = L.map(mapContainer.value, {
       center: [35.841, 108.94], // 西安市中心坐标 [纬度, 经度]
       zoom: 7, // 初始缩放级别,适合城市级别查看
@@ -76,94 +112,218 @@
 
     // 初始化所有瓦片图层
     initTileLayers();
+    // 请求矿区数据并初始化标记点图层
+    initMarkers();
+    // 初始化陕西省GeoJSON图层
+    initGeoJSON();
 
-    // 默认显示自定义底图
-    tileLayers.gaode.layer.addTo(map);
-    // tileLayers.custom.layer.addTo(map);
-    // tileLayers.satellite.layer.addTo(map);
+    layerMap.get(DEFAULT_LAYER_ID).addTo(map);
+  });
 
-    // initMarkers();
-    initGeoJSON();
-  }
+  onUnmounted(() => {
+    map && map.remove();
+  });
 
   // 初始化瓦片图层
   function initTileLayers() {
-    Object.keys(tileLayers).forEach((key) => {
-      const config = tileLayers[key];
+    tileLayers.forEach((config) => {
       config.layer = L.tileLayer(config.url, config.options);
+
+      if (config.addByDefault) {
+        config.layer.addTo(map);
+      }
     });
   }
 
   async function initGeoJSON() {
     const response = await fetch('/js/shanxi.geo.json');
     const ShanXiGeoJSON = await response.json();
-    L.geoJSON(ShanXiGeoJSON, {
-      style: function () {
-        return { color: '#ff9100' };
-      },
-    }).addTo(map);
+
+    layerMap.forEach((group, code) => {
+      const features = ShanXiGeoJSON.features.filter((feature) => {
+        if (code === DEFAULT_LAYER_ID) return true;
+        return feature.properties.gb.startsWith(code);
+      });
+
+      const GeoJSON = L.geoJSON(features, {
+        style(feature) {
+          const gb = feature.properties.gb.slice(0, -2);
+          return {
+            fillColor: colorMap.get(gb) || '#14baff',
+            fillOpacity: 0.2,
+            weight: 2,
+            opacity: 1,
+            color: '#ff9100',
+          };
+        },
+        onEachFeature(__, layer) {
+          layer.on({
+            mouseover: (e) => {
+              const layer = e.target;
+
+              layer.setStyle({
+                weight: 2,
+                fillOpacity: 0.6,
+              });
+
+              layer.bringToFront();
+            },
+            mouseout: (e) => {
+              GeoJSON.resetStyle(e.target);
+            },
+            // click: zoomToFeature,
+          });
+        },
+      });
+
+      // layerMap.set(code, GeoJSON);
+      GeoJSON.addTo(group);
+    });
+  }
+
+  /** 生成一个标准的标记点,通过传入的数据,请求详情信息并生成监测详情框 */
+  async function generateStandardMarker(marker: any, options: any) {
+    const linkArr = ['断线', '正常', '标校'];
+    const statusArr = ['暂无信息', '低风险', '一般风险', '较高风险', '高风险'];
+    const colorArr = [StatusColorEnum.red, StatusColorEnum.blue, StatusColorEnum.gold, StatusColorEnum.purple, StatusColorEnum.red];
+
+    const tbodyInnerHtml = await getGoafAlarmLevel({ mineCode: marker.mineCode }).then(({ goafDataList, alarmLevel, goafNum }) => {
+      marker.alarmLevel = alarmLevel;
+      marker.goafNum = goafNum;
+
+      return goafDataList.reduce((htmlstr, item, index) => {
+        htmlstr += `
+          <tr>
+            <td>${index + 1}</td>
+            <td>${item.devicePos}</td>
+            <td style="color: ${colorArr[item.alarmLevel || 0]}">${statusArr[item.alarmLevel || 0]}</td>
+            <td style="color: ${colorArr[item.linkStatus || 0]}">${linkArr[item.linkStatus || 0]}</td>
+          </tr>
+        `;
+
+        return htmlstr;
+      }, ``);
+    });
+
+    return L.marker([marker.lat, marker.lng], options).bindPopup(
+      `
+        <div class="leaflet-popup-content__title">${marker.mineName}</div>
+        <div class="leaflet-popup-content__divider"></div>
+        <div class="leaflet-popup-content__board mb-5px">
+          <div class="mr-5px">所属执法处</div>
+          <div>${marker.managementName}</div>
+        </div>
+        <div class="leaflet-popup-content__board mb-5px">
+          <div class="mr-5px">采空区密闭数量</div>
+          <div>${marker.goafNum}</div>
+        </div>
+        <div class="leaflet-popup-content__board">
+          <div class="mr-5px">密闭整体风险等级</div>
+          <div style="color: ${colorArr[marker.alarmLevel]}">${statusArr[marker.alarmLevel]}</div>
+        </div>
+        <div class="leaflet-popup-content__divider"></div>
+        <table id="${marker.id}" class="leaflet-popup-content__table w-full mt-10px">
+          <thead>
+            <tr>
+              <th>序号</th>
+              <th>采空区名称</th>
+              <th>风险等级</th>
+              <th>通讯状态</th>
+            </tr>
+          </thead>
+          <tbody>
+            ${tbodyInnerHtml.length ? tbodyInnerHtml : `<tr><td colspan="4">暂无数据</td></tr>`}
+          </tbody>
+        </table>
+      `
+    );
+  }
+
+  function generateRootMarker(marker: any, options: any) {
+    const size = 40;
+    const icon = L.divIcon({
+      className: 'numbered-marker',
+      html: `
+        <svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" style="overflow: visible;">
+          <!-- 圆形背景 -->
+          <circle
+            cx="${size / 2}"
+            cy="${size / 2}"
+            r="${size / 2 - 2}"
+            fill="${colorMap.get(marker.gb)}"
+          />
+          <!-- 数字文本 -->
+          <text
+            x="${size / 2}"
+            y="${size / 2}"
+            text-anchor="middle"
+            dominant-baseline="middle"
+            fill="gray"
+            font-size="16"
+            font-weight="bold"
+            font-family="Arial, sans-serif"
+          >${marker.children.length}</text>
+        </svg>
+      `,
+      iconSize: [size, size],
+      iconAnchor: [size / 2, size / 2],
+      popupAnchor: [0, -size / 2],
+    });
+
+    return L.marker([marker.lat, marker.lng], {
+      icon,
+      color: colorMap.get(marker.gb),
+      fillColor: colorMap.get(marker.gb),
+      ...options,
+    }).on('click', () => {
+      layerMap.forEach((group, code) => {
+        map.removeLayer(group);
+
+        if (code === marker.gb) {
+          map.addLayer(group);
+          console.log('debug bounds', group, marker);
+          map.flyToBounds(group.getBounds());
+        }
+      });
+    });
   }
 
-  // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
+  /** 请求矿区数据并初始化标记点 */
   async function initMarkers() {
-    const markers = await Promise.resolve([
-      {
-        name: '太原',
-        lat: 37.857014,
-        lng: 112.549248,
-        value: 35,
-        color: 'red',
-        radius: 10,
-        type: 'marker',
-      },
-    ]);
-    // const circles = await Promise.resolve([
-    //   {
-    //     name: '西安',
-    //     lat: 34.343161,
-    //     lng: 108.915024,
-    //     value: 35,
-    //     color: 'red',
-    //     radius: 10,
-    //     type: 'circle',
-    //   },
-    // ]);
-    // circles.forEach((circle) => {
-    //   L.circleMarker([circle.lat, circle.lng], { radius: circle.radius, color: circle.color, fillColor: circle.color, fillOpacity: 0.5 })
-    //     .addTo(map)
-    //     .bindPopup(`${circle.name}: ${circle.value}`);
-    // });
-    markers.forEach((marker) => {
-      L.marker([marker.lat, marker.lng], { title: marker.name })
-        .addTo(map)
-        .bindPopup(
-          `
-            <div class="leaflet-popup-content__title">${marker.name}: ${marker.value}</div>
-            <div class="leaflet-popup-content__divider"></div>
-            <div class="leaflet-popup-content__board w-200px">
-              <div>测试字体</div>
-              <div>测试数值</div>
-            </div>
-            <table class="leaflet-popup-content__table w-full mt-10px">
-              <thead>
-                <tr>
-                  <th>name</th>
-                  <th>value</th>
-                </tr>
-              </thead>
-              <tbody>
-                <tr>
-                  <td>测试数据1</td>
-                  <td>100</td>
-                </tr>
-                <tr>
-                  <td>测试数据2</td>
-                  <td>200</td>
-                </tr>
-              </tbody>
-            </table>
-          `
+    const records = await getMarkers({ pageNo: 0, paseSize: 9999 });
+    const details: Promise<any>[] = [];
+    records.forEach((item) => {
+      generateRootMarker(item, {
+        riseOnHover: true,
+      }).addTo(layerMap.get(DEFAULT_LAYER_ID));
+
+      if (!item.children.length) return;
+
+      item.children.forEach((child) => {
+        details.push(
+          generateStandardMarker(child, {
+            riseOnHover: false,
+          }).then((marker) => {
+            if (layerMap.has(child.gb)) {
+              marker.addTo(layerMap.get(child.gb));
+            }
+          })
         );
+      });
+    });
+
+    await Promise.all(details);
+  }
+
+  function reset() {
+    layerMap.forEach((layer, code) => {
+      map.removeLayer(layer);
+
+      if (code === DEFAULT_LAYER_ID) {
+        map.addLayer(layer);
+
+        map.flyToBounds(layer.getBounds());
+      }
     });
   }
 </script>
@@ -196,6 +356,8 @@
     }
 
     .leaflet-popup-content {
+      margin: 13px 20px;
+      min-width: 280px;
       // &__popup {
       // }
 
@@ -227,14 +389,25 @@
         }
         tbody {
           tr {
-            padding: 5px;
             background-color: @map-popup-table-th-bg;
           }
           tr:nth-child(even) {
             background-color: @map-popup-table-theven-bg;
           }
+          td {
+            padding: 5px;
+          }
         }
       }
     }
   }
+
+  .map-reset-btn {
+    position: absolute;
+    right: 30%; /* 距离右边 20px */
+    z-index: 2; /* 确保在地图控件之上 */
+    top: @header-height;
+    // padding: 10px 15px;
+    margin: 10px 0;
+  }
 </style>

+ 8 - 1
src/layouts/default/plain.vue

@@ -3,7 +3,7 @@
   <Layout :class="prefixCls" v-bind="lockEvents">
     <LayoutFeatures />
     <LayoutHeader />
-    <SystemSelect :style="{ position: 'fixed', top: '60px', left: '0', zIndex: '100' }" />
+    <SystemSelect class="system-select-for-plain-layout" />
     <SimpleMap />
     <LayoutContent />
   </Layout>
@@ -91,6 +91,13 @@
       // 代码逻辑说明:【issues/8709】LayoutContent样式多出1px
       // margin-left: 1px;
     }
+
+    .system-select-for-plain-layout {
+      z-index: @layout-header-fixed-z-index;
+      position: fixed;
+      top: @header-height;
+      left: 0;
+    }
   }
 
   :deep(.jeecg-system-select) {

+ 9 - 9
src/views/dashboard/SealedGoaf/index.vue

@@ -36,12 +36,12 @@
     totalNum: {
       productionNum: 0, // 原有生产状态总计
       alarmNum: {
-        alarm1Total: 0,   // alarm1 总计
-        alarm2Total: 0,   // alarm2 总计
-        alarm3Total: 0,   // alarm3 总计
-        alarm4Total: 0,   // alarm4 总计
-        alarmTotal: 0     // 所有alarm总计
-      }
+        alarm1Total: 0, // alarm1 总计
+        alarm2Total: 0, // alarm2 总计
+        alarm3Total: 0, // alarm3 总计
+        alarm4Total: 0, // alarm4 总计
+        alarmTotal: 0, // 所有alarm总计
+      },
     },
   }); // 所有数据汇总
 
@@ -68,7 +68,7 @@
 
       // 遍历数组累加(边界处理:确保是数组,字段非数字则取0)
       if (Array.isArray(goafAlarmData)) {
-        goafAlarmData.forEach(item => {
+        goafAlarmData.forEach((item) => {
           alarm1Total += Number(item.alarm1) || 0;
           alarm2Total += Number(item.alarm2) || 0;
           alarm3Total += Number(item.alarm3) || 0;
@@ -81,7 +81,7 @@
       // console.log('所有alarm的总合计:', alarmTotal);
       const totalNum = { productionNum: totalProductionNum, alarmNum: { alarm1Total, alarm2Total, alarm3Total, alarm4Total, alarmTotal } };
 
-            // 3. 把接口数据赋值给响应式变量(备用)
+      // 3. 把接口数据赋值给响应式变量(备用)
       mineData.value = { coalSeamFireData, productionStatusData, overLimitData, goafAlarmData, goafAlarmLevel, totalNum };
       // 4. 赋值更新后的配置到configs(触发组件重新渲染)
       if (configs.value.length === 0) {
@@ -111,7 +111,7 @@
     width: 100%;
     height: 100%;
     color: @white;
-    background-image: linear-gradient(90deg, @map-bg 0%, @map-bg 14%, transparent 50%, @map-bg 86%, @map-bg 100%);
+    background-image: linear-gradient(90deg, @map-bg 0%, @map-bg 20%, transparent 30%, transparent 70%, @map-bg 80%, @map-bg 100%);
     background-repeat: no-repeat;
     background-size: 100% 100%;
     z-index: @layout-basic-z-index;

+ 19 - 0
src/views/monitor/sealedMonitor/monitor.data.ts

@@ -13,6 +13,11 @@ const riskMap = {
   '3': '较高风险',
   '4': '高风险',
 };
+const linkMap = {
+  '0': '断线',
+  '1': '正常',
+  '2': '标校',
+};
 
 const dictMap = getDictItemsByCode('mineProStatus');
 
@@ -139,6 +144,18 @@ export const columns: BasicColumn[] = [
       return alarmCellRender(record.unsealAlarm);
     },
   },
+  {
+    title: '设备状态',
+    dataIndex: 'linkStatus',
+    width: 100,
+    customRender({ record }) {
+      return alarmCellRender(
+        record.linkStatus,
+        (r) => linkMap[r],
+        (r) => String(r)
+      );
+    },
+  },
   // {
   //   title: '爆炸危险性',
   //   dataIndex: 'explosionHazard',
@@ -550,6 +567,8 @@ function getTagColor(level: string) {
       return StatusColorEnum.gold;
     case '1':
       return StatusColorEnum.blue;
+    case '0':
+      return StatusColorEnum.red;
     default:
       return 'inhert';
   }

+ 16 - 22
src/views/system/algorithm/algorithm.data.ts

@@ -207,21 +207,9 @@ export const schemasCoalAlarm: FormSchema[] = [
     slot: 'InputGreaterNumber',
     /** 借用 */
     groupName: '  T-μT(℃) <',
-    colProps: { span: 12 },
+    colProps: { span: 12, style: 'margin-right: 1px' },
   },
   // { field: 'fireWarn1T', label: '', show: false, component: 'Input' },
-  {
-    field: 'fireWarn1Co2',
-    label: ' ',
-    suffix: '',
-    labelWidth: 118,
-    component: 'Input',
-    slot: 'InputGreaterNumber',
-    /** 借用 */
-    groupName: '  CO2(%) <=',
-    colProps: { span: 12 },
-  },
-  // { field: 'fireWarn1Co2', label: '', show: false, component: 'Input' },
   {
     field: 'fireWarn2CoRzl',
     label: '预警等级(Ⅱ):',
@@ -274,16 +262,18 @@ export const schemasCoalAlarm: FormSchema[] = [
   { field: 'fireWarn2TStart', label: '', show: false, component: 'Input' },
   { field: 'fireWarn2TEnd', label: '', show: false, component: 'Input' },
   {
-    field: 'fireWarn2Co2',
+    field: 'fireWarn2CoO2Ratio',
     label: ' ',
     suffix: '',
     labelWidth: 118,
     component: 'Input',
-    slot: 'InputGreaterNumber',
+    slot: 'InputRangeNumber',
     /** 借用 */
-    groupName: '  CO2(%) <',
+    groupName: '<  100 x ΔCO / ΔO2  =',
     colProps: { span: 12, style: 'margin-right: 1px' },
   },
+  { field: 'fireWarn2CoO2RatioStart', label: '', show: false, component: 'Input' },
+  { field: 'fireWarn2CoO2RatioEnd', label: '', show: false, component: 'Input' },
   {
     field: 'fireWarn3CoRzl',
     label: '预警等级(Ⅲ):',
@@ -336,16 +326,18 @@ export const schemasCoalAlarm: FormSchema[] = [
   { field: 'fireWarn3TStart', label: '', show: false, component: 'Input' },
   { field: 'fireWarn3TEnd', label: '', show: false, component: 'Input' },
   {
-    field: 'fireWarn3Co2',
+    field: 'fireWarn3CoO2Ratio',
     label: ' ',
     suffix: '',
     labelWidth: 118,
     component: 'Input',
-    slot: 'InputGreaterNumber',
+    slot: 'InputRangeNumber',
     /** 借用 */
-    groupName: '  CO2(%) <',
+    groupName: '<  100 x ΔCO / ΔO2  =',
     colProps: { span: 12 },
   },
+  { field: 'fireWarn3CoO2RatioStart', label: '', show: false, component: 'Input' },
+  { field: 'fireWarn3CoO2RatioEnd', label: '', show: false, component: 'Input' },
   {
     field: 'fireWarn3C2h4',
     label: ' ',
@@ -405,16 +397,18 @@ export const schemasCoalAlarm: FormSchema[] = [
   },
   // { field: 'fireWarn4T', label: '', show: false, component: 'Input' },
   {
-    field: 'fireWarn4Co2',
+    field: 'fireWarn4CoO2Ratio',
     label: ' ',
     suffix: '',
     labelWidth: 118,
     component: 'Input',
-    slot: 'InputLowerNumber',
+    slot: 'InputRangeNumber',
     /** 借用 */
-    groupName: '<= CO2(%)  ',
+    groupName: '<  100 x ΔCO / ΔO2  =',
     colProps: { span: 12 },
   },
+  { field: 'fireWarn4CoO2RatioStart', label: '', show: false, component: 'Input' },
+  { field: 'fireWarn4CoO2RatioEnd', label: '', show: false, component: 'Input' },
   {
     field: 'fireWarn4C2h4',
     label: ' ',

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio