Przeglądaj źródła

修改若干BUG、首页报警功能接口联调、弹窗问题修复、报警配置页面重构、原始报警分析页面接口更换、字段修改与其他细小修改

Koishi 1 rok temu
rodzic
commit
7a0cea3888

+ 3 - 3
README.md

@@ -7,12 +7,12 @@
     - 实时报警
         - 重构页面由原来的三个报警区域改为六个报警区域,新增功能每个报警区域点击后显示弹出层以便更详尽显示报警列表信息。
     - 报警记录
-        - 
+        - 更换页面所用接口、调整表格所用字段。
     - 数据查询
         - 无
 - 状态检修
     - 原始报警分析
-        - 
+        - 替换了部分字段、修改了部分BUG。
 - 预警配置
     - 自定义预警
         - 无
@@ -22,7 +22,7 @@
         - 无
 - 基础数据
     - 字典维护
-        - 修改部分页面样式与BUG
+        - 页面重构、现五个级别可以分别设置自己独立的规则并保存了。
 - 其他
     - 全局报警提醒
         - 新增全局窗口提醒功能,实时监听 WS 获取报警状态并于系统右下角排列展示,其中危险等级达到要求的部分报警会以播放声音的形式告知用户。

+ 29 - 8
src/api/api.js

@@ -1,6 +1,6 @@
 import request from "./axios.js";
 export const baseURL = "http://10.81.3.154:6015/";
-// export const baseURL = "http://192.168.1.109:6015/";
+// export const baseURL = "http://192.168.1.104:6015/";
 import JSONBIG from "json-bigint";
 
 // 获取场站数据
@@ -151,7 +151,7 @@ export const getAdapterLatest = (stationId, AIlist) => {
         },
         timeout: 1000,
         transformResponse: [
-            function(data) {
+            function (data) {
                 const json = JSONBIG({
                     storeAsString: true,
                 });
@@ -202,7 +202,7 @@ export const alarm_history = (params) => {
 // 列表接口
 export const getAlarmCountList = (params) => {
     return request({
-        url: `alarm/history/findWtFeatureStat?timeType=${params.timeType}&begin=${params.begin}&end=${params.end}&stationid=${params.stationid}&components=${params.components}&modelId=${params.modelId}&alarmIds=${params.alarmIds}`,
+        url: `alarm/history/findWtFeatureStat?m=${params.timeType}&begin=${params.begin}&end=${params.end}&stationid=${params.stationid}&components=${params.components}&modelId=${params.modelId}&alarmIds=${params.alarmIds}`,
         baseURL,
         method: "get",
     });
@@ -479,7 +479,7 @@ export const alarm_fault_recent = (params) => {
             statu: false,
         },
         transformResponse: [
-            function(data) {
+            function (data) {
                 const json = JSONBIG({
                     storeAsString: true,
                 });
@@ -527,7 +527,7 @@ export function tree(params) {
         url: "device/structure/tree/windturbine",
         method: "get",
         transformResponse: [
-            function(data) {
+            function (data) {
                 const json = JSONBIG({
                     storeAsString: true,
                 });
@@ -689,7 +689,7 @@ export const scadabj_fetchTableData = (query) => {
         timeout: 20000,
         transformResponse: [
             // 处理17位数字精度问题
-            function(data) {
+            function (data) {
                 const json = JSONBIG({
                     storeAsString: true,
                 });
@@ -802,8 +802,14 @@ export const getReportDetail = (id) => {
 
 
 export const getAlarmConfig = () => {
-    return request.get(`/alertrule/queryalarmtypellist`);
+    // return request.get(`/alertrule/queryalarmtypellist`);
+    return request({
+        method: "get",
+        baseURL,
+        url: "/alertrule/queryalarmtypellist",
+    });
 };
+
 export const confirmAlart = (data) => {
     return request({
         method: "post",
@@ -811,5 +817,20 @@ export const confirmAlart = (data) => {
         data,
         timeout: 60000
     });
-    // return request.post("/alarm/history/updateAlarms", data)
+};
+
+export const getAlartConfig = () => {
+    return request({
+        method: "get",
+        baseURL,
+        url: "/alarmswitch/queryAll",
+    });
+};
+
+export const saveAlartConfig = (data) => {
+    return request({
+        method: "post",
+        url: "/alarmswitch/save",
+        data
+    });
 };

+ 24 - 10
src/components/Sidebar.vue

@@ -10,46 +10,60 @@
       unique-opened
       router
     >
-    
       <template v-for="item in router.options.routes[1].children">
         <template v-if="item.children">
-          <el-submenu :index="item.path" :key="item.name"  v-if="item.isshow?.includes(identity) || !item.isshow">
+          <el-submenu
+            :index="replaceRoute(item.path)"
+            :key="item.name"
+            v-if="item.isshow?.includes(identity) || !item.isshow"
+          >
             <template #title>
-              <i :class="item.icon" style="margin-right:10px"></i>
+              <i :class="item.icon" style="margin-right: 10px"></i>
               <span>{{ item.meta.title }}</span>
             </template>
 
             <template v-for="subItem in item.children" :key="subItem.name">
-              <el-menu-item :index="subItem.path">
+              <el-menu-item :index="replaceRoute(subItem.path)">
                 {{ subItem.meta.title }}
               </el-menu-item>
             </template>
           </el-submenu>
         </template>
 
-        <template v-else >
-          <el-menu-item :index="item.path" :key="item.path"  v-if="(item.isshow?.includes(identity) || !item.isshow) &&item.path!=='/check'">
-            <i :class="item.icon" style="margin-right:10px"></i>
+        <template v-else>
+          <el-menu-item
+            :index="item.path"
+            :key="item.path"
+            v-if="
+              (item.isshow?.includes(identity) || !item.isshow) &&
+              item.path !== '/check'
+            "
+          >
+            <i :class="item.icon" style="margin-right: 10px"></i>
             <template #title>{{ item.meta.title }}</template>
           </el-menu-item>
         </template>
-        
       </template>
     </el-menu>
   </div>
 </template>
 
 <script setup>
-import { computed, warn } from "vue";
+import { computed } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import { useStore } from "vuex";
-const identity = sessionStorage.getItem("identity")
+const identity = sessionStorage.getItem("identity");
 
 const route = useRoute();
 const store = useStore();
 const router = useRouter();
 let onRoutes = computed(() => route.path.replace("/", ""));
 let collapse = computed(() => store.state.collapse);
+
+const replaceRoute = (route) => {
+  const regex = /\/:[^?]+?\?/g;
+  return route.replace(regex, "");
+};
 </script>
 
 <style scoped>

+ 109 - 18
src/components/alarmPopupa/index.vue

@@ -8,7 +8,10 @@
       <template v-if="index < 6">
         <div class="alarmTitle">{{ item.alarmName }}</div>
         <div class="alarmContent">
-          <div class="contentItem">报警描述: {{ item.description }}</div>
+          <div class="contentItem" @click="goToAlertDescPage(item)">
+            报警描述:
+            <span class="alertDescCursor">{{ item.description }}</span>
+          </div>
           <div class="contentItem">报警时间: {{ item.tsName }}</div>
         </div>
         <div class="btnBox" :class="`lv${item.lv}BdColor`">
@@ -36,10 +39,11 @@
   </div>
 </template>
 <script>
-import { confirmAlart } from "@api/api.js";
+import { confirmAlart, getAlartConfig } from "@api/api.js";
 export default {
   data() {
     return {
+      alarmConfigArray: [],
       alarmList: [],
       seriousWarning: false,
       audioElement: null,
@@ -50,9 +54,18 @@ export default {
   },
 
   created() {
-    this.webSocketInit(
-      `ws://10.81.3.154:6014/websocket/${this.$store.state.user.authToken}`
-    );
+    getAlartConfig()
+      .then((res) => {
+        this.alarmConfigArray = res.data;
+        this.webSocketInit(
+          `ws://10.81.3.154:6014/websocket/${this.$store.state.user.userId}`
+        );
+      })
+      .catch(() => {
+        this.BASE.showMsg({
+          msg: "报警配置获取失败,请重试",
+        });
+      });
   },
 
   unmounted() {
@@ -142,6 +155,7 @@ export default {
               type: "success",
               msg: "全部确认成功",
             });
+            this.alarmList = [];
             this.$store.commit("emptyWarning");
             this.playAudioEffect();
           }
@@ -150,26 +164,57 @@ export default {
       });
     },
 
-    getRandomNumber(min, max) {
-      return Math.floor(Math.random() * (max - min + 1)) + min;
-    },
-
     playAudioEffect() {
-      const fiveLvWarning = this.alarmList.some((ele) => {
-        return ele.lv === 5 && !ele.confirm;
-      });
+      const lv1Config = this.getConfigItem(1);
+      let lv1Play = false;
+      if (lv1Config.isAlarmSound) {
+        lv1Play = this.alarmList.some((ele) => {
+          return ele.lv === 1 && !ele.confirm;
+        });
+      }
 
-      const fourLvWarning = this.alarmList.some((ele) => {
-        return ele.lv === 4 && !ele.confirm;
-      });
+      const lv2Config = this.getConfigItem(2);
+      let lv2Play = false;
+      if (lv2Config.isAlarmSound) {
+        lv2Play = this.alarmList.some((ele) => {
+          return ele.lv === 2 && !ele.confirm;
+        });
+      }
+
+      const lv3Config = this.getConfigItem(3);
+      let lv3Play = false;
+      if (lv3Config.isAlarmSound) {
+        lv3Play = this.alarmList.some((ele) => {
+          return ele.lv === 3 && !ele.confirm;
+        });
+      }
+
+      const lv4Config = this.getConfigItem(4);
+      let lv4Play = false;
+      if (lv4Config.isAlarmSound) {
+        lv4Play = this.alarmList.some((ele) => {
+          return ele.lv === 4 && !ele.confirm;
+        });
+      }
 
-      if (fiveLvWarning && !this.seriousWarning) {
+      const lv5Config = this.getConfigItem(5);
+      let lv5Play = false;
+      if (lv5Config.isAlarmSound) {
+        lv5Play = this.alarmList.some((ele) => {
+          return ele.lv === 5 && !ele.confirm;
+        });
+      }
+
+      if (lv5Play && !this.seriousWarning) {
         this.seriousWarning = true;
         this.audioElement = new Audio();
         this.audioElement.src = "./static/sound/lv5.mp3";
         this.audioElement.loop = true;
         this.audioElement?.play();
-      } else if (fourLvWarning && !this.seriousWarning) {
+      } else if (
+        (lv1Play || lv2Play || lv3Play || lv4Play) &&
+        !this.seriousWarning
+      ) {
         this.audioElement = new Audio();
         this.audioElement.src = "./static/sound/lv4.mp3";
         this.audioElement.addEventListener("ended", () => {
@@ -202,6 +247,7 @@ export default {
         this.ws.onmessage = (res) => {
           let alarmItem = JSON.parse(res.data);
           if (alarmItem) {
+            const configItem = this.getConfigItem(alarmItem.rank);
             const alarmOption = {
               id: alarmItem.id,
               lv: alarmItem.rank,
@@ -210,6 +256,7 @@ export default {
               class: `animate__bounceInRight lv${alarmItem.rank}`,
               isClose: alarmItem.isClose,
               isCloseName: alarmItem.isClose ? "是" : "否",
+              alarmId: alarmItem.alarmId,
               alarmType: alarmItem.alarmType,
               alarmName: this.getAlarmName(alarmItem),
               description: alarmItem.description,
@@ -225,7 +272,14 @@ export default {
               characteristic: alarmItem.characteristic,
               code: alarmItem.code,
             };
-            this.alarmList.push(alarmOption);
+            if (
+              configItem.isAlarmSound ||
+              configItem.isAlart ||
+              configItem.isContinuousAlarm
+            ) {
+              this.alarmList.push(alarmOption);
+            }
+
             this.$store.commit("setWarning", alarmOption);
             this.alarmList.sort((a, b) => {
               return b.lv - a.lv;
@@ -269,6 +323,32 @@ export default {
         this.ws?.close();
       }
     },
+
+    goToAlertDescPage({ deviceId, alarmId }) {
+      this.$router.push(`/safe/historywaring/${deviceId}/${alarmId}`);
+    },
+
+    getConfigItem(lv) {
+      return (
+        this.alarmConfigArray.find((ele) => {
+          return ele.alarmLevel === lv;
+        }) || {}
+      );
+    },
+  },
+
+  watch: {
+    "$store.state.alarmResetFlg"() {
+      getAlartConfig()
+        .then((res) => {
+          this.alarmConfigArray = res.data;
+        })
+        .catch(() => {
+          this.BASE.showMsg({
+            msg: "报警配置获取失败,请重试",
+          });
+        });
+    },
   },
 };
 </script>
@@ -330,6 +410,17 @@ export default {
         margin-bottom: 2px;
         word-wrap: break-word;
 
+        .alertDescCursor {
+          cursor: pointer;
+          transition: 0.2s;
+
+          &:hover {
+            color: var(--el-color-primary);
+            text-decoration: underline;
+            transition: 0.2s;
+          }
+        }
+
         &:last-child {
           margin-bottom: 0;
         }

+ 26 - 6
src/pages/alarmConfig/bj_windturbine/windturbine.vue

@@ -54,12 +54,13 @@
           popper-class="select"
           @change="categorychanged"
         >
-          <el-option key="1" label="设备报警" value="windturbine"></el-option>
+          <el-option key="1" label="风机报警" value="windturbine"></el-option>
           <el-option
             key="2"
             label="升压站报警"
             value="booststation"
           ></el-option>
+          <el-option key="3" label="逆变器报警" value="inverter"></el-option>
         </el-select>
         <el-select
           v-model="query.wpId"
@@ -275,19 +276,19 @@ const state = reactive({
   form: {},
   tableHeader: [
     { title: "编码", code: "id" },
-    { title: "场站", code: "stationId", width: "100" },
-    { title: "设备", code: "deviceId", width: "100" },
+    { title: "场站", code: "stationName", width: "100" },
+    // { title: "设备", code: "deviceId", width: "100" },
     { title: "机型", code: "modelId" },
     { title: "部件", code: "components" },
     { title: "报警描述", code: "description", width: "150" },
-    { title: "设备部件", code: "components" },
-    { title: "级别", code: "rank" },
+    { title: "设备部件", code: "componentsName" },
+    { title: "级别", code: "rankName" },
     { title: "特性", code: "characteristic" },
     { title: "设备类型", code: "deviceType" },
     { title: "报警类型", code: "alarmType" },
     { title: "报警类别", code: "triggerType" },
     { title: "是否启用", code: "enable" },
-    { title: "是否可复位", code: "resetTable" },
+    { title: "是否可复位", code: "resetTableName" },
   ],
   tableHeader1: [
     { title: "编码", code: "id" },
@@ -340,9 +341,27 @@ const isStation = computed(() => store.getters.isStation);
 let total = ref(0);
 const getData = async () => {
   const { data: res } = await windturbinebj_fetchTableData(query);
+  res.records.forEach((ele) => {
+    ele.rankName = getRankName(ele.rank);
+    ele.resetTableName = ele.resetTable ? "是" : "否";
+  });
   state.tableData = res.records;
   total.value = res.total;
 };
+
+const getRankName = (rank) => {
+  if (rank === 1) {
+    return "低级";
+  } else if (rank === 2) {
+    return "低中极";
+  } else if (rank === 3) {
+    return "中极";
+  } else if (rank === 4) {
+    return "中高级";
+  } else if (rank === 5) {
+    return "高极";
+  }
+};
 //changeStation
 const changeStation = async () => {
   query.modelId = "";
@@ -359,6 +378,7 @@ const handleInsert = () => {
 const handleEditClick = (row) => {
   let obj = Object.assign({}, row);
   obj && (obj.manufacturerCode = "");
+  console.log(123123, obj);
   state.form = obj;
   state.visible = true;
 };

+ 36 - 24
src/pages/alarmConfig/bj_windturbine/windturbine_components.vue

@@ -44,7 +44,7 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="风机测点" prop="uniformCode">
+          <el-form-item label="统一编码" prop="uniformCode">
             <el-select
               v-model="form.uniformCode"
               class="width-100"
@@ -68,7 +68,7 @@
       </el-row>
       <el-row :gutter="50">
         <el-col :span="12">
-          <el-form-item label="停机类型" prop="characteristic">
+          <el-form-item label="特性" prop="characteristic">
             <el-select class="width-100" v-model="form.characteristic">
               <el-option
                 v-for="item in state.CHARACTERISTIC"
@@ -136,13 +136,19 @@
       <el-row :gutter="50">
         <el-col :span="12">
           <el-form-item label="关联部件" prop="relatedParts">
-            <el-select class="width-100" v-model="form.relatedParts">
-              <el-option
-                v-for="item in state.relatePartList"
-                :key="item.id"
-                :value="item.id"
-                :label="item.name"
-              />
+            <el-select class="width-100" v-model="form.relatedParts" filterable>
+              <el-option-group
+                v-for="group in state.relatePartList"
+                :key="group.label"
+                :label="group.label"
+              >
+                <el-option
+                  v-for="item in group.options"
+                  :key="item.nemCode"
+                  :label="item.name"
+                  :value="item.nemCode"
+                />
+              </el-option-group>
             </el-select>
           </el-form-item>
         </el-col>
@@ -257,8 +263,12 @@ const state = reactive({
   modelList: [],
   pointList: [],
   fetchListAll: [],
-//   relatePartList: [],
-  warningClassifyList: [],
+  relatePartList: [],
+  warningClassifyList: [
+    { id: "windturbine", name: "风机报警" },
+    { id: "booststation", name: "升压站报警" },
+    { id: "inverter", name: "逆变器报警" },
+  ],
   creator: [
     {
       id: "HFYG_CS",
@@ -309,18 +319,6 @@ const rules = reactive({
     trigger: "change",
   },
 });
-//部件列表
-const relatePartList = computed(() => {
-//   if (query.wpId == "") {
-//     return [];
-//   } else {
-//     if (query.wpId.includes("FDC")) {
-//       return state.fetchListAll?.fjbj;
-//     } else {
-//       return state.fetchListAll?.gfbj;
-//     }
-//   }
-});
 const modelChange = async () => {
   const { data } = await getDIPointList(form.value?.modelId);
   state.pointList = data;
@@ -337,7 +335,21 @@ const getdatadictionaryList = async () => {
 //所属部件
 const getfetchRelatePart = async () => {
   const res = await fetchRelatePartAndAlarmType();
-  state.relatePartList = res;
+  const keyMap = {
+    fjbj: "风机部件",
+    gfbj: "逆变器部件",
+  };
+
+  let relatePartList = [];
+
+  for (let key in keyMap) {
+    relatePartList.push({
+      id: key,
+      label: keyMap[key],
+      options: res.data[key] || [],
+    });
+  }
+  state.relatePartList = relatePartList;
 };
 const getfetchWarningClassify = async () => {
   const res = await fetchWarningClassify();

+ 31 - 2
src/pages/safe/historywaring.vue

@@ -182,6 +182,7 @@
 
 <script setup>
 import { watch, reactive, nextTick, computed, onMounted } from "vue";
+import { useRouter, useRoute } from "vue-router";
 import dayjs from "dayjs";
 import {
   alarm_history,
@@ -197,6 +198,7 @@ import { useStore } from "vuex";
 
 const store = useStore();
 const isStation = computed(() => store.getters.isStation);
+const route = useRoute();
 
 onMounted(() => {
   getequipmentmodel_list();
@@ -205,6 +207,8 @@ onMounted(() => {
     dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
     dayjs().format("YYYY-MM-DD HH:mm:ss"),
   ];
+  state.deviceId = route.params.deviceId || "";
+  state.alarmId = route.params.alarmId || "";
 });
 // 机型
 const getequipmentmodel_list = async () => {
@@ -230,9 +234,14 @@ const state = reactive({
       label: "风机",
       value: "windturbine",
     },
+    {
+      label: "逆变器",
+      value: "inverter",
+    },
   ],
   typeVal: "windturbine",
   stationId: "",
+  alarmId: "",
   windturbineList: [],
   windturbineId: "",
   modelListAll: {},
@@ -249,6 +258,9 @@ const state = reactive({
     { title: "时间", code: "ts", width: "180" },
     { title: "场站", code: "stationname", width: "180" },
     { title: "机组", code: "devicename", width: "180" },
+    { title: "故障编码", code: "nemCode" },
+    { title: "故障原因", code: "faultCause" },
+    { title: "故障解决方法", code: "resolvent" },
     { title: "报警信息", code: "description" },
     { title: "级别", code: "rank", width: "80" },
     { title: "类型", code: "alarmtype", width: "80" },
@@ -284,6 +296,20 @@ watch(
     immediate: true,
   }
 );
+watch(
+  () => route,
+  (val, old) => {
+    state.deviceId = route.params.deviceId || "";
+    state.alarmId = route.params.alarmId || "";
+    nextTick(async () => {
+      await getAlarmHistoryt();
+    });
+  },
+  {
+    deep: true,
+    immediate: true,
+  }
+);
 //型号列表
 const modelList = computed(() => {
   if (state.typeVal == "windturbine") {
@@ -330,9 +356,12 @@ const getAlarmHistoryt = async () => {
   let params = {
     pageNum: query.page,
     pageSize: query.limit,
+    alarmId: state.alarmId,
     alarmType: state.typeVal,
-    stationid: state.stationId,
-    deviceid: state.typeVal == "booststation" ? "" : state.windturbineId,
+    // stationid: state.stationId,
+    deviceid:
+      state.deviceId ||
+      (state.typeVal == "booststation" ? "" : state.windturbineId),
     modelId: state.modelId,
     components: state.components,
     description: state.description,

+ 2 - 0
src/pages/safe/realwaring.vue

@@ -125,6 +125,7 @@
 <script setup>
 import {
   ref,
+  onBeforeMount,
   onMounted,
   reactive,
   nextTick,
@@ -162,6 +163,7 @@ onMounted(async () => {
     await init();
   }
 });
+
 const init = async () => {
   await fearch(formatTime(new Date(new Date() - 12 * 60 * 60 * 1000)));
   let Interval = window.setInterval(async () => {

+ 34 - 10
src/pages/safe/safecomponent.vue

@@ -23,8 +23,8 @@
       />
       <el-table-column prop="lvName" label="报警等级" show-overflow-tooltip />
       <el-table-column
-        prop="alarmName"
-        label="报警类型"
+        prop="description"
+        label="报警描述"
         show-overflow-tooltip
       />
       <el-table-column
@@ -62,15 +62,19 @@
           />
           <el-table-column prop="code" label="报警设备" show-overflow-tooltip />
           <el-table-column
-            prop="alarmName"
-            label="报警类型"
-            show-overflow-tooltip
-          />
-          <el-table-column
             prop="characteristic"
             label="报警特征"
             show-overflow-tooltip
           />
+          <el-table-column label="报警描述">
+            <template #default="scope">
+              <span
+                class="alertDescCursor"
+                @click="goToAlertDescPage(scope.row)"
+                >{{ scope.row.description }}</span
+              >
+            </template>
+          </el-table-column>
           <el-table-column
             prop="isCloseName"
             label="报警是否解除"
@@ -95,7 +99,12 @@
           </el-table-column>
         </el-table>
       </el-card>
-      <el-button class="confirmAllBtn" type="info" plain @click="confirmAll" :disabled="!dialogTableData.length"
+      <el-button
+        class="confirmAllBtn"
+        type="info"
+        plain
+        @click="confirmAll"
+        :disabled="!dialogTableData.length"
         >确认所有报警</el-button
       >
     </el-dialog>
@@ -201,7 +210,6 @@ export default {
                 msg: `${this.title}确认成功`,
               });
               this.$store.commit("removeWarning", alarmItem);
-              this.playAudioEffect();
             }
             this.stopUpdate = false;
           });
@@ -226,7 +234,6 @@ export default {
                 msg: `全部${this.title}确认成功`,
               });
               this.$store.commit("removeWarning", this.dialogTableData);
-              this.playAudioEffect();
             }
             this.stopUpdate = false;
           });
@@ -235,6 +242,12 @@ export default {
           this.stopUpdate = false;
         });
     },
+
+    goToAlertDescPage(alertItem) {
+      this.$router.push(
+        `/safe/historywaring/${alertItem.deviceId}/${alertItem.alarmId}`
+      );
+    },
   },
 
   watch: {
@@ -282,6 +295,17 @@ export default {
       width: calc(100% - 40px);
       height: calc(100% - 40px);
       margin: 20px;
+
+      .alertDescCursor {
+        cursor: pointer;
+        transition: 0.2s;
+
+        &:hover {
+          color: var(--el-color-primary);
+          text-decoration: underline;
+          transition: 0.2s;
+        }
+      }
     }
 
     .confirmAllBtn {

+ 130 - 54
src/pages/systemManage/systemManage.vue

@@ -2,66 +2,142 @@
   <el-card class="box-card">
     <template #header>
       <div class="card-header">
-        <span>系统配置</span>
+        <span>报警配置</span>
       </div>
     </template>
-    <el-form label-width="140px">
-      <el-form-item label="实时报警弹窗开关:">
-        <el-switch v-model="state.warnSwitch" active-color="#13ce66" inactive-color="#ff4949" />
-      </el-form-item>
-      <el-form-item label="实时报警声音开关:">
-        <el-switch v-model="state.speakSwitch" active-color="#13ce66" inactive-color="#ff4949" />
-      </el-form-item>
-      <el-form-item label="报警弹窗时间:">
-        <el-input v-model="state.inputVal" placeholder="请输入" style="width: 140px">
-          <template #append>秒</template>
-        </el-input>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" @click="storeF">保存</el-button>
-        <el-button type="primary" @click="restart">清理预警服务缓存</el-button>
-      </el-form-item>
-    </el-form>
+    <el-tabs type="border-card" v-model="activeTab">
+      <el-tab-pane
+        v-for="(item, index) in alarmConfigArray"
+        :key="index"
+        :name="item.id"
+      >
+        <template #label>
+          <div class="alartPaneLabel">
+            <span>{{ item.alarmLevel }}级报警</span>
+            <div class="alartBadge" :class="getAlartStatus(item)"></div>
+          </div>
+        </template>
+        <el-form label-width="120px">
+          <el-form-item label="报警弹窗:">
+            <el-switch
+              v-model="item.isAlart"
+              active-text="弹出"
+              inactive-text="不弹出"
+            />
+          </el-form-item>
+          <el-form-item label="播放声音:">
+            <el-switch
+              v-model="item.isAlarmSound"
+              active-text="播放"
+              inactive-text="不播放"
+            />
+          </el-form-item>
+          <el-form-item label="必须确认:">
+            <el-switch
+              v-model="item.isContinuousAlarm"
+              active-text="是"
+              inactive-text="否"
+            />
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+    </el-tabs>
+    <div class="btnBox">
+      <el-button type="primary" @click="save">保存规则</el-button>
+    </div>
   </el-card>
 </template>
-<script setup>
-import { ref, onMounted, reactive, nextTick, watch, computed, h } from "vue";
-import { registerRequest, getRestart, getRestart2, getRestart3 } from "/@/api/api.js";
-import { ElMessage, ElMessageBox } from "element-plus";
-import { initWebSocket } from "/@/websocket/indextest";
-import { common } from "/@/composables/common";
-import { useStore } from "vuex";
-const store = useStore();
-const { setenableWarn, getenableWarn, system } = common();
-const warnTime = computed(() => store.state.warnTime);
-const state = reactive({
-  warnSwitch: false,
-  speakSwitch: false,
-  inputVal: warnTime.value,
-});
-onMounted(async () => {
-  await getenableWarn()
-  await init()
-});
-const init = async () => {
-  const { enableWarn, enableSpeak } = system.value
-  state.warnSwitch = enableWarn
-  state.speakSwitch = enableSpeak
-}
-const storeF = () => {
-  // store.commit("setEnableWarn", state.warnSwitch);
-  setenableWarn(state.warnSwitch, state.speakSwitch)
-  store.commit("setWarnTime", state.inputVal);
+<script>
+import { getAlartConfig, saveAlartConfig } from "@api/api.js";
+export default {
+  data() {
+    return {
+      activeTab: "",
+      alarmConfigArray: [],
+    };
+  },
+
+  created() {
+    this.getConfigArray();
+  },
+  methods: {
+    getConfigArray() {
+      this.alarmConfigArray = [];
+      getAlartConfig().then((res) => {
+        res.data.forEach((ele) => {
+          for (let key in ele) {
+            if (
+              this.BASE.getType(ele[key]) === "number" &&
+              key !== "alarmLevel"
+            ) {
+              ele[key] = !!ele[key];
+            }
+          }
+        });
+        this.alarmConfigArray = res.data;
+        this.activeTab = this.activeTab || res?.data?.[0]?.id;
+      });
+    },
+    getAlartStatus(alartItem) {
+      if (
+        alartItem.isAlart ||
+        alartItem.isAlarmSound ||
+        alartItem.isContinuousAlarm
+      ) {
+        return "badgeWork";
+      } else {
+        return "badgeNotworK";
+      }
+    },
+
+    save() {
+      let configArray = this.BASE.deepCopy(this.alarmConfigArray);
+      let promiseArray = [];
+      configArray.forEach((ele) => {
+        for (let key in ele) {
+          if (ele[key] == true) {
+            ele[key] = 1;
+          } else if (ele[key] == false) {
+            ele[key] = 0;
+          }
+        }
+        promiseArray.push(saveAlartConfig(ele));
+      });
+
+      Promise.all(promiseArray).then(() => {
+        this.BASE.showMsg({
+          type: "success",
+          msg: "修改成功",
+        });
+        this.$store.commit("changeAlarmResetFlg");
+        this.getConfigArray();
+      });
+    },
+  },
 };
-const restart = () => {
-  const res = getRestart()
-  const res2 = getRestart2()
-  const res3 = getRestart3()
-  ElMessage.success("清理成功!");
-}
 </script>
 <style lang="scss" scoped>
-.systemBox {
-  display: flex;
+.alartPaneLabel {
+  position: relative;
+  .alartBadge {
+    position: absolute;
+    right: -10px;
+    top: 8px;
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    overflow: hidden;
+  }
+}
+
+.badgeWork {
+  background: var(--el-color-success);
+}
+.badgeNotworK {
+  background: var(--el-color-error);
+}
+
+.btnBox {
+  margin-top: 12px;
 }
 </style>

+ 1 - 1
src/router/index.js

@@ -63,7 +63,7 @@ const routes = [
                             ),
                     },
                     {
-                        path: "/safe/historywaring",
+                        path: "/safe/historywaring/:deviceId?/:alarmId?",
                         name: "safehistorywaring",
                         meta: {
                             title: "报警记录",

+ 29 - 2
src/store/index.js

@@ -20,13 +20,34 @@ export default createStore({
         enableWarn: false,
         //报警弹窗持续时间
         warnTime: 5,
+        alarmResetFlg: 1,
+        replaceRouteName: ["safehistorywaring"]
     },
     mutations: {
         delTagsItem(state, data) {
             state.tagsList.splice(data.index, 1);
         },
         setTagsItem(state, data) {
-            state.tagsList.push(data);
+            const needReplace = state.replaceRouteName.some(routeName => {
+                return routeName === data.name;
+            });
+            if (needReplace) {
+                let someIndex = 0;
+                const someRes = state.tagsList.some((ele, index) => {
+                    if (ele.name === data.name) {
+                        someIndex = index;
+                        return ele.name === data.name;
+                    }
+                });
+                if (someRes) {
+                    state.tagsList.splice(someIndex, 1, data);
+                } else {
+                    state.tagsList.push(data);
+                }
+
+            } else {
+                state.tagsList.push(data);
+            }
         },
         clearTags(state) {
             state.tagsList = [];
@@ -76,7 +97,7 @@ export default createStore({
             if (Array.isArray(data)) {
                 data.forEach(ele => {
                     for (let i = 0; i < state.warningList.length; i++) {
-                        if (`${ele.id}${ele.ts}` === `${data.id}${data.ts}`) {
+                        if (`${ele.id}${ele.ts}` === `${state.warningList[i].id}${state.warningList[i].ts}`) {
                             setTimeout(() => {
                                 state.warningList.splice(i, 1);
                             }, 0);
@@ -109,6 +130,9 @@ export default createStore({
         setWarnTime(state, data) {
             state.warnTime = data;
         },
+        changeAlarmResetFlg(state, data) {
+            state.alarmResetFlg += 1;
+        }
     },
     actions: {
         actionsWarning(context, newData) {
@@ -134,6 +158,9 @@ export default createStore({
         actionsWarnInterval(context, newData) {
             context.commit("setWarnInterval", newData);
         },
+        changeAlarmResetFlg(context) {
+            context.commit("changeAlarmResetFlg");
+        },
     },
     modules: { user, },
     getters: getter,

+ 1 - 1
vite.config.js

@@ -31,7 +31,7 @@ export default defineConfig({
             "^/sharding": {
                 // target: 'http://wanghs.nat300.top',
                 target: "http://10.81.3.154:6015",
-                // target: "http://192.168.1.108:6015",
+                // target: "http://192.168.1.104:6015",
                 changeOrigin: true, //开启代理
                 rewrite: (path) => path.replace(/^\/sharding/, ""),
             },