瀏覽代碼

宝德安全监控-预警历史,风门同控修改-提交

lxh 5 月之前
父節點
當前提交
74cdf57a79

+ 6 - 6
src/views/vent/monitorManager/airDoor/airdoor.api.ts

@@ -7,13 +7,15 @@ enum Api {
   getDevice = '/monitor/device',
   getDevice = '/monitor/device',
   getCameraUrl = '/monitor/camera/queryByCameraCode',
   getCameraUrl = '/monitor/camera/queryByCameraCode',
   devicecontrol = '/safety/ventanalyMonitorData/devicecontrol_ssl',
   devicecontrol = '/safety/ventanalyMonitorData/devicecontrol_ssl',
-  insertSyncRule = '/ventanaly-device/synccontrol/upcoming/saveOrUpdateRule',
+  //insertSyncRule = '/ventanaly-device/synccontrol/upcoming/saveOrUpdateRule',
+  insertSyncRule = '/ventanaly-device/monitor/timeSync/insertSyncRule',
   upcoming = '/ventanaly-device/synccontrol/upcoming',
   upcoming = '/ventanaly-device/synccontrol/upcoming',
   GetSyncRule='/ventanaly-device/synccontrol/upcoming/GetSyncRule',
   GetSyncRule='/ventanaly-device/synccontrol/upcoming/GetSyncRule',
   GetSyncRuleOperationLog='/ventanaly-device/synccontrol/upcoming/GetSyncRuleOperationLog',
   GetSyncRuleOperationLog='/ventanaly-device/synccontrol/upcoming/GetSyncRuleOperationLog',
   GetSyncRuleExecLog='/ventanaly-device/synccontrol/upcoming/GetSyncRuleExecLog',
   GetSyncRuleExecLog='/ventanaly-device/synccontrol/upcoming/GetSyncRuleExecLog',
   list='/safety/ventanalyDeviceInfo/list',
   list='/safety/ventanalyDeviceInfo/list',
-  edit='/ventanaly-device/safety/ventanalyDeviceInfo/batchEdit'
+  edit='/ventanaly-device/safety/ventanalyDeviceInfo/batchEdit',
+  manualTimeSync='/ventanaly-device/monitor/timeSync/manualTimeSync'
 }
 }
 
 
 
 
@@ -47,9 +49,6 @@ export const GetSyncRule = (params) => defHttp.post({ url: Api.GetSyncRule, para
 * @param params
 * @param params
 */
 */
 export const insertSyncRule = (params) => {
 export const insertSyncRule = (params) => {
-  // 加密password
-  //const encryption = new AesEncryption({ key: loginCipher.key, iv: loginCipher.iv });
-  //params.password = encryption.encryptByAES(params.password);
   return defHttp.post({ url: Api.insertSyncRule, params });
   return defHttp.post({ url: Api.insertSyncRule, params });
 };
 };
 
 
@@ -65,4 +64,5 @@ export const GetSyncRuleExecLog = (params) => defHttp.get({ url: Api.GetSyncRule
 export const controlList = (params) => defHttp.get({ url: Api.list, params });
 export const controlList = (params) => defHttp.get({ url: Api.list, params });
 //集控风门-确认选中
 //集控风门-确认选中
 export const confirmChoice = (params) => defHttp.put({ url: Api.edit, params });
 export const confirmChoice = (params) => defHttp.put({ url: Api.edit, params });
-
+//同步PLC时钟
+export const manualTimeSync = () => defHttp.post({ url: Api.manualTimeSync });

+ 49 - 35
src/views/vent/monitorManager/airDoor/components/door-content-r.vue

@@ -14,6 +14,7 @@
         定时设置
         定时设置
       </a-button>
       </a-button>
       <a-button style="margin: 0px 10px" type="primary" @click="handlerOperation">操作日志</a-button>
       <a-button style="margin: 0px 10px" type="primary" @click="handlerOperation">操作日志</a-button>
+      <a-button type="primary" @click="handlerClock">同步PLC时钟</a-button>
       <a-button class="device-control-btn" type="primary" @click="handlerDeviceChoice">集控设备选择</a-button>
       <a-button class="device-control-btn" type="primary" @click="handlerDeviceChoice">集控设备选择</a-button>
     </div>
     </div>
     <div class="content-r-container">
     <div class="content-r-container">
@@ -25,7 +26,9 @@
         <div class="box-content">
         <div class="box-content">
           <!-- plc时钟显示 -->
           <!-- plc时钟显示 -->
           <!-- <div class="timePlcNow">2025-12-4 13:23:24</div> -->
           <!-- <div class="timePlcNow">2025-12-4 13:23:24</div> -->
-            <div class="timePlcNow">{{item.readData.PLCyear ?  `${item.readData.PLCyear}-${item.readData.PLCmonth}-${item.readData.PLCday} ${item.readData.PLChour}:${item.readData.PLCminute}:${item.readData.PLCsecond}` : '' }}</div>
+          <div class="timePlcNow">{{ item.readData.PLCyear ?
+            `${item.readData.PLCyear}-${item.readData.PLCmonth}-${item.readData.PLCday}
+            ${item.readData.PLChour}:${item.readData.PLCminute}:${item.readData.PLCsecond}` : '' }}</div>
           <!-- 二三维信息 -->
           <!-- 二三维信息 -->
           <gateSVG v-if="item.gateStyle == 'fm_fc_ssl'" :ref="(el) => setChildRef(el, index)" :identify="index">
           <gateSVG v-if="item.gateStyle == 'fm_fc_ssl'" :ref="(el) => setChildRef(el, index)" :identify="index">
           </gateSVG>
           </gateSVG>
@@ -37,23 +40,26 @@
           <div>
           <div>
             <span>定时开启时间:</span>
             <span>定时开启时间:</span>
             <!-- <span class="set-time">13:23:24</span> -->
             <!-- <span class="set-time">13:23:24</span> -->
-             <span class="set-time">{{ item.readData.time_on_hour ? `${item.readData.time_on_hour}:${item.readData.time_on_min}` : '--' }}</span>
+            <span class="set-time">{{ item.readData.time_on_hour ?
+              `${item.readData.time_on_hour}:${item.readData.time_on_min}` : '--' }}</span>
           </div>
           </div>
           <div>
           <div>
             <span>启用状态:</span>
             <span>启用状态:</span>
-            <span class="set-time">{{ item.readData.timerSwitch=='0' ? '启用' : '未启用' }}</span>
+            <span class="set-time">{{ item.readData.timerSwitch == '0' ? '启用' : '未启用' }}</span>
           </div>
           </div>
           <div>
           <div>
             <span>定时关闭时间:</span>
             <span>定时关闭时间:</span>
             <!-- <span class="set-time">13:23:24</span> -->
             <!-- <span class="set-time">13:23:24</span> -->
-              <span class="set-time">{{ item.readData.time_off_hour ? `${item.readData.time_off_hour}:${item.readData.time_off_min}` : '--' }}</span>
+            <span class="set-time">{{ item.readData.time_off_hour ?
+              `${item.readData.time_off_hour}:${item.readData.time_off_min}` : '--' }}</span>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
 
 
     </div>
     </div>
     <!-- 同步开启/关闭弹窗 -->
     <!-- 同步开启/关闭弹窗 -->
-    <syncModal :visible="visible" @handleCancel="handleCancel" @handleOk="handleOk"></syncModal>
+    <syncModal :visible="visible" :tooltipText="tooltipText" @handleCancel="handleCancel" @handleOk="handleOk">
+    </syncModal>
     <!-- 定时设置弹窗 -->
     <!-- 定时设置弹窗 -->
     <timeSetModal :visibleTime="visibleTime" @handleCancelTime="handleCancelTime" @handleOk="handleOkTime">
     <timeSetModal :visibleTime="visibleTime" @handleCancelTime="handleCancelTime" @handleOk="handleOkTime">
     </timeSetModal>
     </timeSetModal>
@@ -84,7 +90,7 @@ import gateSVG from './gateSVG.ssl.vue'
 import operationModal from './operationModal.vue'
 import operationModal from './operationModal.vue'
 import DeviceControl from './deviceControl.vue'
 import DeviceControl from './deviceControl.vue'
 import { useRouter } from 'vue-router';
 import { useRouter } from 'vue-router';
-import { devicecontrol, insertSyncRule, GetSyncRule, controlList, confirmChoice } from '../airdoor.api'
+import { devicecontrol, insertSyncRule, GetSyncRule, controlList, confirmChoice, manualTimeSync } from '../airdoor.api'
 import { doorStatus } from '../airdoor.data'
 import { doorStatus } from '../airdoor.data'
 // import { getModelComponent } from '../airdoor.data'
 // import { getModelComponent } from '../airdoor.data'
 import { useMessage } from '/@/hooks/web/useMessage';
 import { useMessage } from '/@/hooks/web/useMessage';
@@ -102,6 +108,8 @@ let props = defineProps({
 const { createMessage } = useMessage();
 const { createMessage } = useMessage();
 const globalConfig = inject<any>('globalConfig');
 const globalConfig = inject<any>('globalConfig');
 let router = useRouter();
 let router = useRouter();
+//判断当前开启的是同步/集控密码弹窗
+let isTbOrJk = ref('')
 let infoDatas = ref<any[]>([])
 let infoDatas = ref<any[]>([])
 //同步开启/关闭弹窗-控制显示与隐藏
 //同步开启/关闭弹窗-控制显示与隐藏
 let visible = ref(false);
 let visible = ref(false);
@@ -119,6 +127,7 @@ const childRefs = ref<any[]>([])
 let gateControlData = ref<any[]>([])
 let gateControlData = ref<any[]>([])
 //集控设备弹窗显示
 //集控设备弹窗显示
 let visibleDeviceControl = ref(false)
 let visibleDeviceControl = ref(false)
+let tooltipText = ref('')
 
 
 const setChildRef = (el, index) => {
 const setChildRef = (el, index) => {
   childRefs.value[index] = el
   childRefs.value[index] = el
@@ -127,27 +136,37 @@ const setChildRef = (el, index) => {
 function handlerOpenOrClose(data) {
 function handlerOpenOrClose(data) {
   visible.value = true;
   visible.value = true;
   visibleStatus.value = data
   visibleStatus.value = data
+  isTbOrJk.value = 'Tb'
+  tooltipText.value = '您正在执行 “开启/关闭” 全部风门的操作,请输入密码执行。'
 }
 }
 //确定
 //确定
 async function handleOk(param) {
 async function handleOk(param) {
-  let deviceStr = infoDatas.value.map(v => v.deviceID).join(',')
-  let paramcode = visibleStatus.value == 'open' ? 'sameTimeOpen' : 'sameTimeClose'
-  let res = await devicecontrol({ deviceids: deviceStr, paramcode: paramcode, password: param.pass || globalConfig?.simulatedPassword })
-  if (res) {
+  if (isTbOrJk.value == 'Tb') {
+    let deviceStr = infoDatas.value.map(v => v.deviceID).join(',')
+    let paramcode = visibleStatus.value == 'open' ? 'sameTimeOpen' : 'sameTimeClose'
+    let res = await devicecontrol({ deviceids: deviceStr, paramcode: paramcode, password: param.pass || globalConfig?.simulatedPassword })
+    if (res) {
+      visible.value = param.visib
+      // visibleStatus.value = ''
+      doorStatus.openOrclose = true
+      doorStatus.statusCode = visibleStatus.value
+      setTimeout(() => {
+        doorStatus.openOrclose = false
+        doorStatus.statusCode = ''
+      }, 60000 * 5)
+    }
+  } else {
     visible.value = param.visib
     visible.value = param.visib
-    // visibleStatus.value = ''
-    doorStatus.openOrclose = true
-    doorStatus.statusCode = visibleStatus.value
-    setTimeout(() => {
-      doorStatus.openOrclose = false
-      doorStatus.statusCode = ''
-    }, 60000 * 5)
+    visibleDeviceControl.value = true
   }
   }
+
 }
 }
 //取消
 //取消
 function handleCancel(param) {
 function handleCancel(param) {
   visible.value = param;
   visible.value = param;
   visibleStatus.value = ''
   visibleStatus.value = ''
+  isTbOrJk.value = ''
+  tooltipText.value = ''
 }
 }
 
 
 //定时设置
 //定时设置
@@ -159,14 +178,8 @@ async function handlerTimeSet() {
 }
 }
 //确定
 //确定
 async function handleOkTime(param) {
 async function handleOkTime(param) {
-  console.log(param, '定时参数---')
-  // let start_time = `${param.formState.hourS}:${param.formState.minuteS}:${param.formState.secondS}`
-  // let end_time = `${param.formState.hourE}:${param.formState.minuteE}:${param.formState.secondE}`
-   let start_time = `${param.formState.hourS}:${param.formState.minuteS}`
-  let end_time = `${param.formState.hourE}:${param.formState.minuteE}`
-  let enabled = param.formState.checked ? '1' : '0'
-  let res = await insertSyncRule({ startTime: start_time, endTime: end_time, enabled: enabled, id: Ids.value, password: param.formState.passWord })
-  console.log(res, '设置定时---')
+  let timerSwitch = param.formState.checked ? '1' : '0'
+  let res = await insertSyncRule({ timerSwitch: timerSwitch, settimeOnHour: param.formState.hourS, settimeOnMin: param.formState.minuteS, settimeOffHour: param.formState.hourE, settimeOffMin: param.formState.minuteE, password: param.formState.passWord })
   if (res) {
   if (res) {
     visibleTime.value = param.visib
     visibleTime.value = param.visib
     Ids.value = ''
     Ids.value = ''
@@ -211,29 +224,30 @@ async function getControlList() {
 }
 }
 //集控设备选择点击
 //集控设备选择点击
 function handlerDeviceChoice() {
 function handlerDeviceChoice() {
-  visibleDeviceControl.value = true
+  isTbOrJk.value = 'Jk'
+  visible.value = true;
+  tooltipText.value = '您正在执行 “集控” 全部风门的操作,请输入密码执行。'
 }
 }
 //集控设备确定选择
 //集控设备确定选择
 async function handlerChoice(param) {
 async function handlerChoice(param) {
-  console.log(param, '选中')
   let data: any[] = []
   let data: any[] = []
   param.forEach(el => {
   param.forEach(el => {
     let list = gateControlData.value.find(v => v.id == el)
     let list = gateControlData.value.find(v => v.id == el)
-    list.isAutosync='1'
+    list.isAutosync = '1'
     data.push(list)
     data.push(list)
   })
   })
-  console.log(data, 'data---')
   let res = await confirmChoice({ obj: data })
   let res = await confirmChoice({ obj: data })
   if (res) {
   if (res) {
     visibleDeviceControl.value = false
     visibleDeviceControl.value = false
   }
   }
 }
 }
-// function getInitSvg(param) {
-//   // const dictCodes = getDictItemsByCode('gateStyle');
-//   // console.log(dictCodes, 'dictCodes---')
-// }
-
-
+//同步PLC时钟
+async function handlerClock() {
+  let res = await manualTimeSync()
+  if (res) {
+    createMessage.success('PLC时钟同步成功!');
+  }
+}
 watch(() => props.infoData, (newV, oldV) => {
 watch(() => props.infoData, (newV, oldV) => {
   infoDatas.value = newV
   infoDatas.value = newV
   if (newV.length) {
   if (newV.length) {

+ 5 - 1
src/views/vent/monitorManager/airDoor/components/syncModal.vue

@@ -2,7 +2,7 @@
   <div class="sync-modal">
   <div class="sync-modal">
     <a-modal v-model:visible="Visible" width="450px" :title="Title" centered destroyOnClose @ok="handleOk"
     <a-modal v-model:visible="Visible" width="450px" :title="Title" centered destroyOnClose @ok="handleOk"
       @cancel="handleCancel">
       @cancel="handleCancel">
-      <p>您正在执行 “开启/关闭” 全部风门的操作,请输入密码执行。</p>
+      <p>{{ tooltipText }}</p>
       <a-form :model="formState" name="basic" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }" autocomplete="off">
       <a-form :model="formState" name="basic" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }" autocomplete="off">
         <a-form-item label="输入密码" name="passWord" :rules="[{ required: true, message: '请输入密码!' }]">
         <a-form-item label="输入密码" name="passWord" :rules="[{ required: true, message: '请输入密码!' }]">
           <a-input-password style="width:220px" v-model:value="formState.passWord" />
           <a-input-password style="width:220px" v-model:value="formState.passWord" />
@@ -24,6 +24,10 @@ let props = defineProps({
   Title: {
   Title: {
     type: String,
     type: String,
     default: '操作确认'
     default: '操作确认'
+  },
+  tooltipText:{
+    type:String,
+    default:''
   }
   }
 })
 })
 
 

+ 100 - 0
src/views/vent/monitorManager/safetyMonitor/WarnHistoryTable.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="warn-history">
+    <a-form :model="formState" layout="inline" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off">
+      <a-form-item label="安装地点">
+        <a-input v-model:value="formState.installLocation" placeholder="请输入" style="width: 220px;" />
+      </a-form-item>
+      <a-form-item label="报警类型">
+        <a-select v-model:value="formState.exceptionType" style="width: 220px">
+          <a-select-option v-for="(item, index) in exceptionTypeList" :key="index" :value="item.value">{{
+            item.label
+          }}</a-select-option>
+        </a-select>
+      </a-form-item>
+
+      <a-form-item label="是否完成">
+        <a-select v-model:value="formState.isCompleted" style="width: 220px">
+          <a-select-option v-for="(item, index) in isCompletedList" :key="index" :value="item.value">{{
+            item.label
+          }}</a-select-option>
+        </a-select>
+      </a-form-item>
+      <a-button type="primary" preIcon="ant-design:search-outlined" style="margin-left:30px;"
+        @click="getSearch">查询</a-button>
+      <a-button type="primary" preIcon="ant-design:sync-outlined" style="margin-left: 20px;"
+        @click="getReset">重置</a-button>
+    </a-form>
+    <a-table size="small" :dataSource="dataSource" :columns="warnHistoryColumns" :scroll="{ y: 620 }"
+      :pagination="pagination" @change="pageChange">
+      <template #actionSp="{ record }">
+
+      </template>
+    </a-table>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue'
+import { warnHistoryColumns, exceptionTypeList, isCompletedList,pagination} from './safety.data'
+import { warnList } from './safety.api'
+
+let dataSource = ref<any[]>([])
+let formState = reactive({
+  installLocation: '',
+  exceptionType: '',
+  isCompleted: ""
+})
+
+async function getTableList() {
+  let res = await warnList({ pageNo: pagination.current, pageSize: pagination.pageSize, ...formState })
+  dataSource.value = res.records.map(el => {
+    return {
+      ...el,
+      isCompletedC: el.isCompleted == 1 ? '是' : el.isCompleted == 0 ? '否' : '',
+      exceptionTypeC: el.exceptionType == '001' ? '超限报警' : el.exceptionType == '002' ? '断电报警' : el.exceptionType == '003' ? '馈电异常' : el.exceptionType == '004' ? '传感器断线' : el.exceptionType == '005' ? '基站断电' : el.exceptionType == '006' ? '基站不通' : el.exceptionType == '007' ? '标校' : el.exceptionType == '008' ? '超量程' : ''
+    }
+  }) || []
+  pagination.total = res.total
+}
+//分页
+function pageChange(val) {
+  pagination.current = val.current;
+  pagination.pageSize = val.pageSize;
+  getTableList()
+}
+//查询
+function getSearch() {
+  pagination.current = 1
+  getTableList()
+}
+//重置
+function getReset() {
+  formState.exceptionType = ''
+  formState.installLocation = ''
+  formState.isCompleted = ''
+  pagination.current = 1
+  getTableList()
+}
+
+onMounted(() => {
+  getTableList()
+})
+</script>
+
+<style lang="less" scoped>
+.zxm-form {
+  height: 70px;
+  display: flex;
+  align-items: center;
+
+}
+
+::v-deep .zxm-form-item-label>label {
+  color: #fff !important;
+}
+
+::v-deep .zxm-input {
+  background: #00000017 !important;
+  border: 1px solid var(--vent-form-item-border) !important;
+}
+</style>

+ 437 - 465
src/views/vent/monitorManager/safetyMonitor/index.vue

@@ -1,26 +1,18 @@
 <template>
 <template>
   <div class="device-box" id="monitorBox">
   <div class="device-box" id="monitorBox">
-    <a-tabs class="tabs-box" type="card" v-model:activeKey="activeKey" @change="tabChange" id="tabsBox" v-if="isRefresh">
+    <a-tabs class="tabs-box" type="card" v-model:activeKey="activeKey" @change="tabChange" id="tabsBox"
+      v-if="isRefresh">
       <a-tab-pane key="1" tab="实时监测">
       <a-tab-pane key="1" tab="实时监测">
         <template v-if="deviceType == 'fan' && activeKey == '1'">
         <template v-if="deviceType == 'fan' && activeKey == '1'">
           <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
           <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
         </template>
         </template>
         <template v-else-if="activeKey == '1' && deviceType">
         <template v-else-if="activeKey == '1' && deviceType">
           <template v-if="hasPermission('btn:noGb') && deviceType.startsWith('safetymonitor')">
           <template v-if="hasPermission('btn:noGb') && deviceType.startsWith('safetymonitor')">
-            <MonitorTable
-              ref="monitorTable"
-              :columnsType="`${deviceType}_monitor`"
-              :dataSource="dataSource"
-              design-scope="device_monitor"
-              :isShowPagination="false"
-              :isShowActionColumn="false"
+            <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :dataSource="dataSource"
+              design-scope="device_monitor" :isShowPagination="false" :isShowActionColumn="false"
               :is-show-select="false"
               :is-show-select="false"
               :form-config="deviceType == 'safetymonitor' && sysOrgCode != 'zjtzqctmk' ? formConfig : undefined"
               :form-config="deviceType == 'safetymonitor' && sysOrgCode != 'zjtzqctmk' ? formConfig : undefined"
-              title="设备监测"
-              :scroll="{ y: 650 }"
-              :defSort="defSort"
-              sortDataIndex="strinstallpos"
-            >
+              title="设备监测" :scroll="{ y: 650 }" :defSort="defSort" sortDataIndex="strinstallpos">
               <template #filterCell="{ column, record }">
               <template #filterCell="{ column, record }">
                 <template v-if="deviceType.startsWith('safetymonitor')">
                 <template v-if="deviceType.startsWith('safetymonitor')">
                   <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
                   <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
@@ -30,9 +22,9 @@
                   <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
                   <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
                   <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
                   <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
                 </template>
                 </template>
-                <a-tag v-if="column.dataIndex === 'exceptionType_str'" :color="record.exceptionType_str == '正常' ? 'green' : '#f00'">
-                  {{ record.exceptionType_str == '正常' ? '正常' : '异常' }}</a-tag
-                >
+                <a-tag v-if="column.dataIndex === 'exceptionType_str'"
+                  :color="record.exceptionType_str == '正常' ? 'green' : '#f00'">
+                  {{ record.exceptionType_str == '正常' ? '正常' : '异常' }}</a-tag>
                 <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '1' ? 'green' : '#f00'">{{
                 <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '1' ? 'green' : '#f00'">{{
                   record.netStatus == '1' ? '正常' : '异常'
                   record.netStatus == '1' ? '正常' : '异常'
                 }}</a-tag>
                 }}</a-tag>
@@ -43,20 +35,11 @@
             </MonitorTable>
             </MonitorTable>
           </template>
           </template>
           <template v-else>
           <template v-else>
-            <MonitorTable
-              ref="monitorTable"
-              :columnsType="`${deviceType}_monitor`"
-              :dataSource="dataSource"
-              design-scope="device_monitor"
-              :isShowPagination="false"
-              :isShowActionColumn="false"
+            <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :dataSource="dataSource"
+              design-scope="device_monitor" :isShowPagination="false" :isShowActionColumn="false"
               :is-show-select="false"
               :is-show-select="false"
               :form-config="deviceType == 'safetymonitor' && sysOrgCode != 'zjtzqctmk' ? formConfig : undefined"
               :form-config="deviceType == 'safetymonitor' && sysOrgCode != 'zjtzqctmk' ? formConfig : undefined"
-              title="设备监测"
-              :scroll="{ y: 650 }"
-              :defSort="defSort"
-              sortDataIndex="strinstallpos"
-            >
+              title="设备监测" :scroll="{ y: 650 }" :defSort="defSort" sortDataIndex="strinstallpos">
               <template #filterCell="{ column, record }">
               <template #filterCell="{ column, record }">
                 <template v-if="deviceType.startsWith('safetymonitor')">
                 <template v-if="deviceType.startsWith('safetymonitor')">
                   <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
                   <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
@@ -66,9 +49,9 @@
                   <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
                   <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
                   <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
                   <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
                 </template>
                 </template>
-                <a-tag v-if="column.dataIndex === 'exceptionType_str'" :color="record.exceptionType_str == '正常' ? 'green' : '#f00'">
-                  {{ record.exceptionType_str == '正常' ? '正常' : '异常' }}</a-tag
-                >
+                <a-tag v-if="column.dataIndex === 'exceptionType_str'"
+                  :color="record.exceptionType_str == '正常' ? 'green' : '#f00'">
+                  {{ record.exceptionType_str == '正常' ? '正常' : '异常' }}</a-tag>
                 <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '1' ? 'green' : '#f00'">{{
                 <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '1' ? 'green' : '#f00'">{{
                   record.netStatus == '1' ? '正常' : '异常'
                   record.netStatus == '1' ? '正常' : '异常'
                 }}</a-tag>
                 }}</a-tag>
@@ -111,13 +94,8 @@
       </a-tab-pane>
       </a-tab-pane>
       <a-tab-pane key="2" tab="历史数据">
       <a-tab-pane key="2" tab="历史数据">
         <div class="tab-item">
         <div class="tab-item">
-          <HistoryTable
-            ref="historyTable"
-            v-if="activeKey == '2'"
-            :columns-type="`${deviceType}`"
-            :device-type="deviceType"
-            designScope="device-history"
-          />
+          <HistoryTable ref="historyTable" v-if="activeKey == '2'" :columns-type="`${deviceType}`"
+            :device-type="deviceType" designScope="device-history" />
         </div>
         </div>
         <!-- 图表 -->
         <!-- 图表 -->
         <!-- <div v-if="alive" style="width:100%;height:280px;margin: 20px 0px;">
         <!-- <div v-if="alive" style="width:100%;height:280px;margin: 20px 0px;">
@@ -141,41 +119,28 @@
       <template v-if="!hasPermission('safety:hideWarning')">
       <template v-if="!hasPermission('safety:hideWarning')">
         <a-tab-pane key="3" tab="报警历史">
         <a-tab-pane key="3" tab="报警历史">
           <div class="tab-item">
           <div class="tab-item">
-            <AlarmHistoryTable
-              ref="alarmHistoryTable"
-              v-if="activeKey == '3' && deviceType == 'safetymonitor'"
-              columns-type="alarm"
-              :list="safetyList"
-              :device-type="deviceType"
+            <AlarmHistoryTable ref="alarmHistoryTable" v-if="activeKey == '3' && deviceType == 'safetymonitor'"
+              columns-type="alarm" :list="safetyList" :device-type="deviceType"
               :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, pageSize: 10000 })"
               :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, pageSize: 10000 })"
-              designScope="alarm-history"
-            />
+              designScope="alarm-history" />
           </div>
           </div>
         </a-tab-pane>
         </a-tab-pane>
       </template>
       </template>
       <template v-else-if="deviceType != 'safetymonitor'">
       <template v-else-if="deviceType != 'safetymonitor'">
         <a-tab-pane key="3" tab="报警历史">
         <a-tab-pane key="3" tab="报警历史">
           <div class="tab-item">
           <div class="tab-item">
-            <AlarmHistoryCommentTable
-              v-if="activeKey == '3'"
-              columns-type="alarm"
-              :device-type="deviceType"
+            <AlarmHistoryCommentTable v-if="activeKey == '3'" columns-type="alarm" :device-type="deviceType"
               :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, pageSize: 10000 })"
               :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, pageSize: 10000 })"
-              designScope="alarm-history"
-            />
+              designScope="alarm-history" />
           </div>
           </div>
         </a-tab-pane>
         </a-tab-pane>
       </template>
       </template>
       <a-tab-pane key="4" tab="操作历史" v-if="deviceType !== 'safetymonitor' && deviceType !== 'wasichoufang'">
       <a-tab-pane key="4" tab="操作历史" v-if="deviceType !== 'safetymonitor' && deviceType !== 'wasichoufang'">
         <div class="tab-item">
         <div class="tab-item">
-          <HandlerHistoryTable
-            ref="handlerHistoryTable"
-            v-if="activeKey == '4'"
-            columns-type="operator_history"
+          <HandlerHistoryTable ref="handlerHistoryTable" v-if="activeKey == '4'" columns-type="operator_history"
             :device-type="deviceType"
             :device-type="deviceType"
             :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, pageSize: 10000 })"
             :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, pageSize: 10000 })"
-            designScope="operator-history"
-          />
+            designScope="operator-history" />
         </div>
         </div>
       </a-tab-pane>
       </a-tab-pane>
       <a-tab-pane key="5" tab="报警分析" v-if="!hasPermission('safety:hideWarning') && deviceType == 'safetymonitor'">
       <a-tab-pane key="5" tab="报警分析" v-if="!hasPermission('safety:hideWarning') && deviceType == 'safetymonitor'">
@@ -183,506 +148,513 @@
           <safetyWarnAnalysis :device-type="deviceType" />
           <safetyWarnAnalysis :device-type="deviceType" />
         </div>
         </div>
       </a-tab-pane>
       </a-tab-pane>
+       <a-tab-pane key="6" tab="预警历史" v-if="sysOrgCode == 'sdmtjtbdmk'">
+          <div class="tab-item">
+            <WarnHistory></WarnHistory>
+          </div>
+        </a-tab-pane>
     </a-tabs>
     </a-tabs>
     <div class="right-btn-group" v-if="deviceType.startsWith('safetymonitor')">
     <div class="right-btn-group" v-if="deviceType.startsWith('safetymonitor')">
       <div class="update-btn">
       <div class="update-btn">
         <span>同步分站:</span>
         <span>同步分站:</span>
-        <a-select
-          v-model:value="subStation"
-          :options="subStationOptions"
-          placeholder="同步分站"
-          size="large"
-          :fieldNames="{ label: 'strinstallpos', value: 'id' }"
-          style="width: 150px"
-        />
+        <a-select v-model:value="subStation" :options="subStationOptions" placeholder="同步分站" size="large"
+          :fieldNames="{ label: 'strinstallpos', value: 'id' }" style="width: 150px" />
         <div class="btn btn1" @click="updateSubstation">确定</div>
         <div class="btn btn1" @click="updateSubstation">确定</div>
       </div>
       </div>
-      <div class="export-btn"><div class="btn btn1" @click="exportData" v-if="!hasPermission('safety:hideWarning')">一键导出</div></div>
-      <div class="export-btn m-l-20px" v-if="!hasPermission('safety:hideWarning')"
-        ><div class="btn btn2" @click="goSystem"><send-outlined />安全监控系统</div></div
-      >
+      <div class="export-btn">
+        <div class="btn btn1" @click="exportData" v-if="!hasPermission('safety:hideWarning')">一键导出</div>
+      </div>
+      <div class="export-btn m-l-20px" v-if="!hasPermission('safety:hideWarning')">
+        <div class="btn btn2" @click="goSystem"><send-outlined />安全监控系统</div>
+      </div>
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-  import { ref, onMounted, onUnmounted, shallowRef, defineProps, watch, inject, unref } from 'vue';
-  import { list, getDeviceList, safetyList, getExportUrl, subStationList, initSubStation } from './safety.api';
-  import AlarmHistoryCommentTable from '../comment/AlarmHistoryTable.vue';
-  import safetyWarnAnalysis from '../comment/safetyWarnAnalysis.vue';
-  import AlarmHistoryTable from './AlarmHistoryTable.vue';
-  import HistoryTable from './HistoryTable.vue';
-  import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
-  import MonitorTable from '../comment/MonitorTable.vue';
-  import GroupMonitorTable from '../comment/GroupMonitorTable.vue';
-  import { useRouter } from 'vue-router';
-  import { formConfig, isHaveNoAction } from './safety.data';
-  import { getDictItemsByCode } from '/@/utils/dict';
-  import { usePermission } from '/@/hooks/web/usePermission';
-  import { useGlobSetting } from '/@/hooks/setting';
-  import { useMethods } from '/@/hooks/system/useMethods';
-  import { message } from 'ant-design-vue';
-  import { SendOutlined } from '@ant-design/icons-vue';
-  import { template } from 'lodash-es';
-
-  const { sysOrgCode } = useGlobSetting();
-  const { hasPermission } = usePermission();
-  const globalConfig = inject('globalConfig');
-
-  const { handleExportXls } = useMethods();
-
-  // import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
-
-  // const echartsOption = {
-  //   grid: {
-  //     top: '60px',
-  //     left: '10px',
-  //     right: '25px',
-  //     bottom: '5%',
-  //     containLabel: true,
-  //   },
-  //   toolbox: {
-  //     feature: {},
-  //   },
-  // };
-  // let alive = ref(true)
-
-  type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
-
-  const props = defineProps({
-    pageData: {
-      type: Object,
-      default: () => {},
-    },
-  });
-
-  const scroll = {
-    y: 360,
-  };
-  const defSort = {
-    column: 'strinstallpos',
-    order: 'desc',
-  };
-  const monitorTable = ref();
-  const historyTable = ref();
-  const alarmHistoryTable = ref();
-  const handlerHistoryTable = ref();
-
-  const isRefresh = ref(true);
-
-  const activeKey = ref('1'); // tab key
-  const dataSource = shallowRef([]); // 实时监测数据
-  const deviceType = ref(''); // 监测设备类型
-  const subStation = ref('');
-  const subStationOptions = ref([]);
-  // let dataSourceHis = shallowRef([])//历史数据
-
-  //历史数据
-  async function changeHis(data) {
-    // alive.value = false
-    // nextTick(() => {
-    //   dataSourceHis = data
-    //   alive.value = true
-    // })
-  }
-
-  async function tabChange(activeKeyVal) {
-    activeKey.value = activeKeyVal;
-    if (activeKey.value != '1') {
-      if (timer != undefined) {
-        clearTimeout(timer);
-        timer = undefined;
-      }
-    } else {
-      timer = null;
-      await getMonitor(true);
+import { ref, onMounted, onUnmounted, shallowRef, defineProps, watch, inject, unref } from 'vue';
+import { list, getDeviceList, safetyList, getExportUrl, subStationList, initSubStation } from './safety.api';
+import AlarmHistoryCommentTable from '../comment/AlarmHistoryTable.vue';
+import safetyWarnAnalysis from '../comment/safetyWarnAnalysis.vue';
+import AlarmHistoryTable from './AlarmHistoryTable.vue';
+import HistoryTable from './HistoryTable.vue';
+import WarnHistory from './WarnHistoryTable.vue'
+import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
+import MonitorTable from '../comment/MonitorTable.vue';
+import GroupMonitorTable from '../comment/GroupMonitorTable.vue';
+import { useRouter } from 'vue-router';
+import { formConfig, isHaveNoAction } from './safety.data';
+import { getDictItemsByCode } from '/@/utils/dict';
+import { usePermission } from '/@/hooks/web/usePermission';
+import { useGlobSetting } from '/@/hooks/setting';
+import { useMethods } from '/@/hooks/system/useMethods';
+import { message } from 'ant-design-vue';
+import { SendOutlined } from '@ant-design/icons-vue';
+import { template } from 'lodash-es';
+
+const { sysOrgCode } = useGlobSetting();
+const { hasPermission } = usePermission();
+const globalConfig = inject('globalConfig');
+
+const { handleExportXls } = useMethods();
+
+// import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
+
+// const echartsOption = {
+//   grid: {
+//     top: '60px',
+//     left: '10px',
+//     right: '25px',
+//     bottom: '5%',
+//     containLabel: true,
+//   },
+//   toolbox: {
+//     feature: {},
+//   },
+// };
+// let alive = ref(true)
+
+type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+
+const props = defineProps({
+  pageData: {
+    type: Object,
+    default: () => { },
+  },
+});
+
+const scroll = {
+  y: 360,
+};
+const defSort = {
+  column: 'strinstallpos',
+  order: 'desc',
+};
+const monitorTable = ref();
+const historyTable = ref();
+const alarmHistoryTable = ref();
+const handlerHistoryTable = ref();
+
+const isRefresh = ref(true);
+
+const activeKey = ref('1'); // tab key
+const dataSource = shallowRef([]); // 实时监测数据
+const deviceType = ref(''); // 监测设备类型
+const subStation = ref('');
+const subStationOptions = ref([]);
+// let dataSourceHis = shallowRef([])//历史数据
+
+//历史数据
+async function changeHis(data) {
+  // alive.value = false
+  // nextTick(() => {
+  //   dataSourceHis = data
+  //   alive.value = true
+  // })
+}
+
+async function tabChange(activeKeyVal) {
+  activeKey.value = activeKeyVal;
+  if (activeKey.value != '1') {
+    if (timer != undefined) {
+      clearTimeout(timer);
+      timer = undefined;
     }
     }
+  } else {
+    timer = null;
+    await getMonitor(true);
   }
   }
-
-  // https获取监测数据
-  let timer: null | NodeJS.Timeout = null;
-  function getMonitor(flag?) {
-    if (deviceType.value) {
-      if (timer) timer = null;
-      if (Object.prototype.toString.call(timer) === '[object Null]') {
-        timer = setTimeout(
-          async () => {
-            await getDataSource();
-            if (timer) {
-              getMonitor();
-            }
-          },
-          flag ? 0 : 1000
-        );
-      }
+}
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor(flag?) {
+  if (deviceType.value) {
+    if (timer) timer = null;
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = setTimeout(
+        async () => {
+          await getDataSource();
+          if (timer) {
+            getMonitor();
+          }
+        },
+        flag ? 0 : 1000
+      );
     }
     }
   }
   }
-
-  async function getDataSource() {
-    const formData = monitorTable.value.getForm();
-    const res = await list({ devicetype: deviceType.value, filterParams: { ...formData.getFieldsValue() } });
-    if (res.msgTxt.length > 0) {
-      dataSource.value = [];
-      let dataArr = res.msgTxt[0].datalist || [];
-      dataArr.filter((data: any) => {
-        const readData = data.readData;
-        return Object.assign(data, readData);
-      });
-      if (deviceType.value == 'safetymonitor') {
-        // 如果是安全监控的数据时需要过滤常见设备数据,根据设定的常用安全监控字典去匹配
-        let dictCodes = getDictItemsByCode('safetynormal');
-        const searchForm = formData.getFieldsValue();
-
-        if (searchForm && searchForm['dataTypeName'] && dictCodes && dictCodes.length > 0) {
-          const tempData = [];
-          const tempData1 = [];
-          for (let i = 0; i < dataArr.length; i++) {
-            const item = dataArr[i];
-            let flag = false;
-            for (let i = 0; i < dictCodes.length; i++) {
-              const dict = dictCodes[i];
-              if (dict['value'] == item['dataTypeName']) {
-                flag = true;
-              }
-            }
-            if (flag) {
-              tempData.push(item);
-            } else {
-              tempData1.push(item);
+}
+
+async function getDataSource() {
+  const formData = monitorTable.value.getForm();
+  const res = await list({ devicetype: deviceType.value, filterParams: { ...formData.getFieldsValue() } });
+  if (res.msgTxt.length > 0) {
+    dataSource.value = [];
+    let dataArr = res.msgTxt[0].datalist || [];
+    dataArr.filter((data: any) => {
+      const readData = data.readData;
+      return Object.assign(data, readData);
+    });
+    if (deviceType.value == 'safetymonitor') {
+      // 如果是安全监控的数据时需要过滤常见设备数据,根据设定的常用安全监控字典去匹配
+      let dictCodes = getDictItemsByCode('safetynormal');
+      const searchForm = formData.getFieldsValue();
+
+      if (searchForm && searchForm['dataTypeName'] && dictCodes && dictCodes.length > 0) {
+        const tempData = [];
+        const tempData1 = [];
+        for (let i = 0; i < dataArr.length; i++) {
+          const item = dataArr[i];
+          let flag = false;
+          for (let i = 0; i < dictCodes.length; i++) {
+            const dict = dictCodes[i];
+            if (dict['value'] == item['dataTypeName']) {
+              flag = true;
             }
             }
           }
           }
-          if (sysOrgCode == 'zjtzqctmk' || hasPermission('btn:noGb')) {
-            dataSource.value = [...tempData, ...tempData1];
+          if (flag) {
+            tempData.push(item);
           } else {
           } else {
-            dataSource.value = [...tempData];
+            tempData1.push(item);
           }
           }
+        }
+        if (sysOrgCode == 'zjtzqctmk' || hasPermission('btn:noGb')) {
+          dataSource.value = [...tempData, ...tempData1];
         } else {
         } else {
-          dataSource.value = dataArr;
+          dataSource.value = [...tempData];
         }
         }
       } else {
       } else {
         dataSource.value = dataArr;
         dataSource.value = dataArr;
       }
       }
     } else {
     } else {
-      dataSource.value = [];
+      dataSource.value = dataArr;
     }
     }
+  } else {
+    dataSource.value = [];
   }
   }
+}
 
 
-  async function getSubstation() {
-    const list: [] = await subStationList({ monitorparam: 'safetymonitor*' });
-    subStationOptions.value = list;
-    if (list.length > 0) {
-      subStation.value = list[0]['id'];
-    }
+async function getSubstation() {
+  const list: [] = await subStationList({ monitorparam: 'safetymonitor*' });
+  subStationOptions.value = list;
+  if (list.length > 0) {
+    subStation.value = list[0]['id'];
   }
   }
-
-  function exportData() {
-    handleExportXls('安全监控导出', getExportUrl);
+}
+
+function exportData() {
+  handleExportXls('安全监控导出', getExportUrl);
+}
+function goSystem() {
+  if (VENT_PARAM['safetyCrlPlatformUrl']) {
+    window.open(VENT_PARAM['safetyCrlPlatformUrl'], '_blank');
+    return;
   }
   }
-  function goSystem() {
-    if (VENT_PARAM['safetyCrlPlatformUrl']) {
-      window.open(VENT_PARAM['safetyCrlPlatformUrl'], '_blank');
-      return;
-    }
+}
+
+function updateSubstation() {
+  if (subStation.value) {
+    initSubStation({ substationID: subStation.value }).then(() => {
+      message.success('分站同步完成!');
+    });
+  } else {
+    message.warning('请选择分站!');
   }
   }
-
-  function updateSubstation() {
-    if (subStation.value) {
-      initSubStation({ substationID: subStation.value }).then(() => {
-        message.success('分站同步完成!');
-      });
-    } else {
-      message.warning('请选择分站!');
+}
+
+onMounted(async () => {
+  const { currentRoute } = useRouter();
+  if (unref(currentRoute)) {
+    const path = unref(currentRoute).path;
+    if (path) {
+      deviceType.value = path.substring(path.lastIndexOf('/') + 1);
     }
     }
+    await getMonitor(true);
+    await getSubstation();
   }
   }
+});
 
 
-  onMounted(async () => {
-    const { currentRoute } = useRouter();
-    if (unref(currentRoute)) {
-      const path = unref(currentRoute).path;
-      if (path) {
-        deviceType.value = path.substring(path.lastIndexOf('/') + 1);
-      }
-      await getMonitor(true);
-      await getSubstation();
-    }
-  });
-
-  onUnmounted(() => {
-    if (timer) {
-      clearTimeout(timer);
-    }
-    timer = undefined;
-  });
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+  }
+  timer = undefined;
+});
 </script>
 </script>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>
-  @import '/@/design/theme.less';
-  @import '/@/design/vent/modal.less';
-  @ventSpace: zxm;
+@import '/@/design/theme.less';
+@import '/@/design/vent/modal.less';
+@ventSpace: zxm;
+
+.device-box {
+  width: 100%;
+  height: calc(100% - 100px);
+  padding-bottom: 10px;
+  margin-top: 20px;
+  display: flex;
+  justify-content: center;
+
+  .tabs-box {
+    width: calc(100% - 12px) !important;
+    height: 100% !important;
+    bottom: 3px !important;
+  }
 
 
-  .device-box {
-    width: 100%;
-    height: calc(100% - 100px);
-    padding-bottom: 10px;
-    margin-top: 20px;
+  .device-button-group {
+    position: absolute;
+    top: -30px;
     display: flex;
     display: flex;
-    justify-content: center;
-
-    .tabs-box {
-      width: calc(100% - 12px) !important;
-      height: 100% !important;
-      bottom: 3px !important;
-    }
+    width: 100%;
 
 
-    .device-button-group {
-      position: absolute;
-      top: -30px;
+    .device-button {
+      height: 26px;
+      padding: 0 20px;
+      background: linear-gradient(45deg, #04e6fb55, #0c5cab55);
+      clip-path: polygon(10px 0, 0 50%, 10px 100%, 100% 100%, calc(100% - 10px) 50%, 100% 0);
       display: flex;
       display: flex;
-      width: 100%;
-
-      .device-button {
-        height: 26px;
-        padding: 0 20px;
-        background: linear-gradient(45deg, #04e6fb55, #0c5cab55);
-        clip-path: polygon(10px 0, 0 50%, 10px 100%, 100% 100%, calc(100% - 10px) 50%, 100% 0);
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        color: #fff;
-        position: relative;
-        cursor: pointer;
-
-        &:nth-child(1) {
-          left: calc(-6px * 1);
-        }
-
-        &:nth-child(2) {
-          left: calc(-6px * 2);
-        }
+      justify-content: center;
+      align-items: center;
+      color: #fff;
+      position: relative;
+      cursor: pointer;
 
 
-        &:nth-child(3) {
-          left: calc(-6px * 3);
-        }
+      &:nth-child(1) {
+        left: calc(-6px * 1);
+      }
 
 
-        &:nth-child(4) {
-          left: calc(-6px * 4);
-        }
+      &:nth-child(2) {
+        left: calc(-6px * 2);
+      }
 
 
-        &:nth-child(5) {
-          left: calc(-6px * 5);
-        }
+      &:nth-child(3) {
+        left: calc(-6px * 3);
+      }
 
 
-        &:nth-child(6) {
-          left: calc(-6px * 6);
-        }
+      &:nth-child(4) {
+        left: calc(-6px * 4);
+      }
 
 
-        &:nth-child(7) {
-          left: calc(-6px * 7);
-        }
+      &:nth-child(5) {
+        left: calc(-6px * 5);
+      }
 
 
-        &:nth-child(8) {
-          left: calc(-6px * 8);
-        }
+      &:nth-child(6) {
+        left: calc(-6px * 6);
+      }
 
 
-        &:nth-child(9) {
-          left: calc(-6px * 9);
-        }
+      &:nth-child(7) {
+        left: calc(-6px * 7);
+      }
 
 
-        &:nth-child(10) {
-          left: calc(-6px * 10);
-        }
+      &:nth-child(8) {
+        left: calc(-6px * 8);
+      }
 
 
-        &:nth-child(11) {
-          left: calc(-6px * 11);
-        }
+      &:nth-child(9) {
+        left: calc(-6px * 9);
+      }
 
 
-        &:nth-child(12) {
-          left: calc(-6px * 12);
-        }
+      &:nth-child(10) {
+        left: calc(-6px * 10);
+      }
 
 
-        &:nth-child(13) {
-          left: calc(-6px * 13);
-        }
+      &:nth-child(11) {
+        left: calc(-6px * 11);
+      }
 
 
-        &:nth-child(14) {
-          left: calc(-6px * 14);
-        }
+      &:nth-child(12) {
+        left: calc(-6px * 12);
+      }
 
 
-        &:nth-child(15) {
-          left: calc(-6px * 15);
-        }
+      &:nth-child(13) {
+        left: calc(-6px * 13);
+      }
 
 
-        &:first-child {
-          clip-path: polygon(0 0, 10px 50%, 0 100%, 100% 100%, calc(100% - 10px) 50%, 100% 0);
-        }
+      &:nth-child(14) {
+        left: calc(-6px * 14);
       }
       }
 
 
-      .device-active {
-        background: linear-gradient(45deg, #04e6fb, #0c5cab);
+      &:nth-child(15) {
+        left: calc(-6px * 15);
+      }
 
 
-        &::before {
-          border-color: #0efcff;
-          box-shadow: 1px 1px 3px 1px #0efcff inset;
-        }
+      &:first-child {
+        clip-path: polygon(0 0, 10px 50%, 0 100%, 100% 100%, calc(100% - 10px) 50%, 100% 0);
       }
       }
     }
     }
 
 
-    .enter-detail {
-      color: #fff;
-      cursor: pointer;
-      position: absolute;
-      right: 120px;
-      top: -6px;
-      padding: 5px;
-      border-radius: 5px;
-      margin-left: 8px;
-      margin-right: 8px;
-      width: auto;
-      height: 33px !important;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      color: #fff;
-      padding: 5px 15px 5px 15px;
-      cursor: pointer;
-
-      &:hover {
-        background: var(--vent-modal-bg2);
-      }
+    .device-active {
+      background: linear-gradient(45deg, #04e6fb, #0c5cab);
 
 
       &::before {
       &::before {
-        width: calc(100% - 6px);
-        height: 27px;
-        content: '';
-        position: absolute;
-        top: 3px;
-        right: 0;
-        left: 3px;
-        bottom: 0;
-        z-index: -1;
-        border-radius: inherit;
-        /*important*/
-        background: linear-gradient(#1fa6cb, #127cb5);
+        border-color: #0efcff;
+        box-shadow: 1px 1px 3px 1px #0efcff inset;
       }
       }
     }
     }
   }
   }
-  .right-btn-group {
-    position: absolute;
+
+  .enter-detail {
     color: #fff;
     color: #fff;
-    right: 20px;
+    cursor: pointer;
+    position: absolute;
+    right: 120px;
+    top: -6px;
+    padding: 5px;
+    border-radius: 5px;
+    margin-left: 8px;
+    margin-right: 8px;
+    width: auto;
+    height: 33px !important;
     display: flex;
     display: flex;
-    .export-btn {
-    }
-    .update-btn {
-      margin-right: 10px;
-      display: flex;
-      align-items: center;
-      .btn {
-        background: var(--vent-modal-bg2);
-      }
-    }
-    .btn {
-      padding: 8px 20px;
-      position: relative;
-      border-radius: 2px;
-      color: #fff;
-      width: fit-content;
-      cursor: pointer;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    padding: 5px 15px 5px 15px;
+    cursor: pointer;
 
 
-      &::before {
-        position: absolute;
-        display: block;
-        content: '';
-        width: calc(100% - 4px);
-        height: calc(100% - 4px);
-        top: 2px;
-        left: 2px;
-        border-radius: 2px;
-        z-index: -1;
-      }
+    &:hover {
+      background: var(--vent-modal-bg2);
     }
     }
 
 
-    .btn1 {
-      border: 1px solid var(--vent-btn-primary-border-color);
+    &::before {
+      width: calc(100% - 6px);
+      height: 27px;
+      content: '';
+      position: absolute;
+      top: 3px;
+      right: 0;
+      left: 3px;
+      bottom: 0;
+      z-index: -1;
+      border-radius: inherit;
+      /*important*/
+      background: linear-gradient(#1fa6cb, #127cb5);
+    }
+  }
+}
 
 
-      &::before {
-        background-image: linear-gradient(#2effee92, #0cb1d592);
-      }
+.right-btn-group {
+  position: absolute;
+  color: #fff;
+  right: 20px;
+  display: flex;
 
 
-      &:hover {
-        border: 1px solid #5cfaffaa;
+  .export-btn {}
 
 
-        &::before {
-          background-image: linear-gradient(#2effee72, #0cb1d572);
-        }
-      }
-    }
-    .btn2 {
-      border: 1px solid var(--vent-btn-primary-border-color);
-      background-image: linear-gradient(#2effee92, #0cb1d592);
+  .update-btn {
+    margin-right: 10px;
+    display: flex;
+    align-items: center;
 
 
-      &:hover {
-        border: 1px solid var(--vent-btn-primary-focus-color);
-        background-image: linear-gradient(#0cb0d554, rgba(46, 255, 238, 0.342));
-      }
+    .btn {
+      background: var(--vent-modal-bg2);
     }
     }
   }
   }
 
 
-  :deep(.@{ventSpace}-tabs-tabpane-active) {
-    height: 100%;
-    border: 1px solid var(--vent-device-manager-box-border);
+  .btn {
+    padding: 8px 20px;
+    position: relative;
     border-radius: 2px;
     border-radius: 2px;
-    -webkit-backdrop-filter: blur(8px);
-    box-shadow: 0 0 20px #44b4ff33 inset;
-    background-color: var(--vent-device-manager-box-bg);
-    overflow-y: auto;
+    color: #fff;
+    width: fit-content;
+    cursor: pointer;
+
+    &::before {
+      position: absolute;
+      display: block;
+      content: '';
+      width: calc(100% - 4px);
+      height: calc(100% - 4px);
+      top: 2px;
+      left: 2px;
+      border-radius: 2px;
+      z-index: -1;
+    }
   }
   }
 
 
-  :deep(.@{ventSpace}-tabs-card) {
-    .@{ventSpace}-tabs-tab {
-      background: var(--vent-modal-bg2);
-      border-color: var(--vent-btn-primary-border-color);
-      border-radius: 0%;
+  .btn1 {
+    border: 1px solid var(--vent-btn-primary-border-color);
 
 
-      &:hover {
-        color: #64d5ff;
-      }
+    &::before {
+      background-image: linear-gradient(#2effee92, #0cb1d592);
     }
     }
 
 
-    .@{ventSpace}-tabs-content {
-      height: 100% !important;
-    }
+    &:hover {
+      border: 1px solid #5cfaffaa;
 
 
-    .@{ventSpace}-tabs-tab.@{ventSpace}-tabs-tab-active .@{ventSpace}-tabs-tab-btn {
-      color: var(--vent-font-action-link);
+      &::before {
+        background-image: linear-gradient(#2effee72, #0cb1d572);
+      }
     }
     }
+  }
+
+  .btn2 {
+    border: 1px solid var(--vent-btn-primary-border-color);
+    background-image: linear-gradient(#2effee92, #0cb1d592);
 
 
-    .@{ventSpace}-tabs-nav::before {
-      border-color: var(--vent-btn-primary-border-color);
+    &:hover {
+      border: 1px solid var(--vent-btn-primary-focus-color);
+      background-image: linear-gradient(#0cb0d554, rgba(46, 255, 238, 0.342));
     }
     }
+  }
+}
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  height: 100%;
+  border: 1px solid var(--vent-device-manager-box-border);
+  border-radius: 2px;
+  -webkit-backdrop-filter: blur(8px);
+  box-shadow: 0 0 20px #44b4ff33 inset;
+  background-color: var(--vent-device-manager-box-bg);
+  overflow-y: auto;
+}
+
+:deep(.@{ventSpace}-tabs-card) {
+  .@{ventSpace}-tabs-tab {
+    background: var(--vent-modal-bg2);
+    border-color: var(--vent-btn-primary-border-color);
+    border-radius: 0%;
+
+    &:hover {
+      color: #64d5ff;
+    }
+  }
 
 
-    .@{ventSpace}-picker,
-    .@{ventSpace}-select-selector {
-      width: 100%;
-      background: #00000017 !important;
-      border: 1px solid @vent-form-item-border !important;
+  .@{ventSpace}-tabs-content {
+    height: 100% !important;
+  }
 
 
-      input,
-      .@{ventSpace}-select-selection-item,
-      .@{ventSpace}-picker-suffix {
-        color: #fff !important;
-      }
+  .@{ventSpace}-tabs-tab.@{ventSpace}-tabs-tab-active .@{ventSpace}-tabs-tab-btn {
+    color: var(--vent-font-action-link);
+  }
 
 
-      .@{ventSpace}-select-selection-placeholder {
-        color: #b7b7b7 !important;
-      }
-    }
+  .@{ventSpace}-tabs-nav::before {
+    border-color: var(--vent-btn-primary-border-color);
+  }
+
+  .@{ventSpace}-picker,
+  .@{ventSpace}-select-selector {
+    width: 100%;
+    background: #00000017 !important;
+    border: 1px solid @vent-form-item-border !important;
 
 
-    .@{ventSpace}-pagination-next,
-    .action,
-    .@{ventSpace}-select-arrow,
-    .@{ventSpace}-picker-separator {
+    input,
+    .@{ventSpace}-select-selection-item,
+    .@{ventSpace}-picker-suffix {
       color: #fff !important;
       color: #fff !important;
     }
     }
+
+    .@{ventSpace}-select-selection-placeholder {
+      color: #b7b7b7 !important;
+    }
+  }
+
+  .@{ventSpace}-pagination-next,
+  .action,
+  .@{ventSpace}-select-arrow,
+  .@{ventSpace}-picker-separator {
+    color: #fff !important;
   }
   }
+}
 </style>
 </style>

+ 7 - 0
src/views/vent/monitorManager/safetyMonitor/safety.api.ts

@@ -10,6 +10,7 @@ enum Api {
   export = '/safety/reportInfo/expComReport?tempName=aqjk',
   export = '/safety/reportInfo/expComReport?tempName=aqjk',
   subStationList = '/safety/ventanalySubStation/alllist',
   subStationList = '/safety/ventanalySubStation/alllist',
   initSubStation = '/monitor/initKafkaDeviceInfo',
   initSubStation = '/monitor/initKafkaDeviceInfo',
+  warnList='/ventanaly-device/monitor/securityWarning/list'
 }
 }
 /**
 /**
  * 列表接口
  * 列表接口
@@ -37,3 +38,9 @@ export const getDeviceTypeList = (params) => defHttp.get({ url: Api.deviceTypeLi
 export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
 export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
 
 
 export const getExportUrl = Api.export;
 export const getExportUrl = Api.export;
+/**
+ * 预警历史
+ * @param params
+ */
+export const warnList = (params) => defHttp.get({ url: Api.warnList, params });
+

+ 80 - 0
src/views/vent/monitorManager/safetyMonitor/safety.data.ts

@@ -1,4 +1,84 @@
 import { safetyDeviceList } from './safety.api';
 import { safetyDeviceList } from './safety.api';
+import { BasicColumn } from '/@/components/Table';
+import {reactive} from 'vue'
+
+export const warnHistoryColumns: BasicColumn[] = [
+  {
+    title: '序号',
+    width: 60,
+    align: 'center',
+    customRender: ({ index }: { index: number }) => `${index + 1}`
+  },
+  {
+    title: '安装位置',
+    dataIndex: 'installLocation',
+    key: 'installLocation',
+    align: 'center',
+    ellipsis: true,
+  },
+  {
+    title: '报警类型',
+    dataIndex: 'exceptionTypeC',
+    key: 'exceptionTypeC',
+    align: 'center',
+    ellipsis: true,
+  },
+  {
+    title: '报警原因',
+    dataIndex: 'exceptionReason',
+    key: 'exceptionReason',
+    align: 'center',
+    ellipsis: true,
+  },
+  {
+    title: '开始报警时间',
+    dataIndex: 'exceptionStartTime',
+    key: 'exceptionStartTime',
+    align: 'center',
+    ellipsis: true,
+  },
+  {
+    title: '结束报警时间',
+    dataIndex: 'exceptionEndTime',
+    key: 'exceptionEndTime',
+    align: 'center',
+    ellipsis: true,
+  },
+  {
+    title: '是否完成',
+    dataIndex: 'isCompletedC',
+    key: 'isCompletedC',
+    align: 'center',
+    ellipsis: true,
+  },
+
+]
+
+export let exceptionTypeList = [
+  { label: '超限报警', value: '001' },
+  { label: '断电报警', value: '002' },
+  { label: '馈电异常', value: '003' },
+  { label: '传感器断线', value: '004' },
+  { label: '基站断电', value: '005' },
+  { label: '基站不通', value: '006' },
+  { label: '标校', value: '007' },
+  { label: '超量程', value: '008' },
+]
+export let isCompletedList = [
+  { label: '是', value: 1 },
+  { label: '否', value: 0 },
+]
+
+//分页参数配置
+export let pagination = reactive({
+  current: 1, // 当前页码
+  pageSize: 10, // 每页显示条数
+  total: 0, // 总条目数,后端返回
+  // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
+  showSizeChanger: true, // 是否可改变每页显示条数
+  pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
+})
+
 
 
 export const chartsColumns = (deviceType) => {
 export const chartsColumns = (deviceType) => {
   if (deviceType === '') {
   if (deviceType === '') {

+ 1 - 1
src/views/vent/performance/approvalPend/index.vue

@@ -19,7 +19,7 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-  import { ref, reactive, watch, nextTick, defineProps, onMounted, provide, toRaw } from 'vue';
+  import { ref, reactive, watch, nextTick, onMounted, provide, toRaw } from 'vue';
   import HistorySp from '../comment/HistorySp.vue';
   import HistorySp from '../comment/HistorySp.vue';
   import DeviceModal from '../comment/DeviceModal.vue';
   import DeviceModal from '../comment/DeviceModal.vue';
   import CADModal from '../comment/CADModal.vue';
   import CADModal from '../comment/CADModal.vue';