Browse Source

feat(告警历史): 实现告警历史页面功能并优化设备统计抽屉

- 新增告警历史页面,包含搜索、表格展示和分页功能
- 将设备统计抽屉中的冗余代码注释掉以简化界面
- 添加告警历史相关的常量定义和类型
- 修改路由配置使告警历史页面可见
liujia 1 month ago
parent
commit
4844560d6b

+ 1 - 1
src/router/modules/alarm.ts

@@ -28,7 +28,7 @@ export default [
         path: '/alarm/history',
         name: 'alarmHistory',
         component: () => import('@/views/alarm/history/index.vue'),
-        meta: { title: '告警历史', sort: 3, isFullScreen: false, keepAlive: true, hidden: true },
+        meta: { title: '告警历史', sort: 3, isFullScreen: false, keepAlive: true, hidden: false },
       },
     ],
   },

+ 28 - 0
src/views/alarm/history/const.ts

@@ -0,0 +1,28 @@
+export const columns = [
+  {
+    title: '发生时间',
+    dataIndex: 'createTime',
+    key: 'createTime',
+    align: 'center',
+    // width: 200,
+  },
+  {
+    title: '事件类型',
+    dataIndex: 'eventType',
+    key: 'eventType',
+    align: 'center',
+    // width: 200,
+  },
+  {
+    title: '事件内容',
+    dataIndex: 'info',
+    key: 'info',
+    align: 'center',
+  },
+  {
+    title: '备注',
+    key: 'remark',
+    dataIndex: 'remark',
+    align: 'center',
+  },
+]

+ 279 - 2
src/views/alarm/history/index.vue

@@ -1,11 +1,288 @@
 <template>
-  <div> 告警历史 </div>
+  <div class="alarmHistoryPage">
+    <div class="searchBar">
+      <a-form layout="inline" @keydown.enter="searchHandler">
+        <a-form-item label="创建时间">
+          <range-picker
+            v-model:start="searchState.createTimeStart"
+            v-model:end="searchState.createTimeEnd"
+            @change="searchHandler"
+          />
+        </a-form-item>
+
+        <a-form-item label="事件类型">
+          <a-select
+            v-model:value="searchState.eventType"
+            placeholder="请选择"
+            style="width: 150px"
+            :options="eventTypeList"
+            @change="searchHandler"
+          />
+        </a-form-item>
+
+        <a-form-item>
+          <a-space>
+            <a-button type="primary" @click="searchHandler"> 搜索 </a-button>
+            <a-button @click="resetHandler"> 重置 </a-button>
+          </a-space>
+        </a-form-item>
+      </a-form>
+    </div>
+
+    <div class="tableCard">
+      <div class="tableCard-header">
+        <div class="tableCard-header-title">告警历史列表</div>
+      </div>
+
+      <a-table :columns="columns" :data-source="tableList" :loading="loading" :pagination="false">
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'pose'">
+            {{ record.poseName }}
+          </template>
+          <template v-if="column.key === 'eventType'">
+            {{ record.eventTypeName }}
+          </template>
+          <template v-if="column.key === 'info'">
+            <div v-if="record.info?.start_time">开始时间:{{ record.info?.start_time }}</div>
+            <div v-if="record.info?.end_time">结束时间:{{ record.info?.end_time }}</div>
+            <div v-if="record.info?.stay_time">停留时长:{{ record.info?.stay_time }}(秒)</div>
+            <div v-if="record.info?.count">次数{{ record.info?.count }}</div>
+            <template v-if="record.info?.event_list">
+              事件列表:
+              <div v-for="(event, index) in record.info?.event_list" :key="index">
+                <div>开始时间{{ event.start_time }}</div>
+                <div>结束时间{{ event.end_time }}</div>
+                <div>停留时长{{ event.stay_time }}(秒)</div>
+                <div>消失时长{{ event.absence_time }}(秒)</div>
+              </div>
+            </template>
+          </template>
+        </template>
+      </a-table>
+
+      <base-pagination
+        v-if="tableTotal > 0"
+        v-model:current="current"
+        v-model:pageSize="pageSize"
+        :total="tableTotal"
+        @change="paginationChange"
+        @showSizeChange="paginationSizeChange"
+      ></base-pagination>
+    </div>
+
+    <alarmPlanModal
+      v-if="alarmPlanVisible"
+      v-model:open="alarmPlanVisible"
+      :title="alarmPlanTitle"
+      type="template"
+      :alarm-plan-id="alarmPlanId"
+      :data="alarmPlanDataWithType"
+      :area="{
+        width: 400,
+        height: 400,
+        ranges: [-200, 200, -200, 200],
+      }"
+      @success="fetchList"
+    ></alarmPlanModal>
+  </div>
 </template>
 
 <script setup lang="ts">
+import { ref, onActivated, computed } from 'vue'
+import { columns } from './const'
+import { useSearch } from '@/hooks/useSearch'
+// import { useRouter } from 'vue-router'
+import * as alarmApi from '@/api/alarm'
+import alarmPlanModal from '@/views/device/detail/components/alarmPlanModal/index.vue'
+// import { message } from 'ant-design-vue'
+import { useDictName } from '@/hooks/useDictName'
+import * as statsApi from '@/api/stats'
+import type { StatsAlarmQueryDataRow } from '@/api/stats/types'
+
+// const router = useRouter()
+
 defineOptions({
   name: 'AlarmHistoryIndex',
 })
+
+interface SearchData {
+  createTimeStart: string // 创建时间开始
+  createTimeEnd: string // 创建时间结束
+  type?: ID // 事件类型 一般滞留
+  eventType?: ID // 事件类型 异常滞留
+}
+
+const defaultSearch: SearchData = {
+  createTimeStart: '',
+  createTimeEnd: '',
+  type: null,
+  eventType: null,
+}
+
+const [searchState, resetHandler] = useSearch(defaultSearch, { afterReset: () => searchHandler() })
+
+const tableList = ref<StatsAlarmQueryDataRow[]>([])
+const tableTotal = ref<number>(0)
+const current = ref<number>(1)
+const pageSize = ref<number>(10)
+
+const alarmList = ref<StatsAlarmQueryDataRow[]>([])
+
+// 分页变化
+const paginationChange = (current: number, pageSize: number) => {
+  console.log('change', current, pageSize)
+  fetchList()
+}
+// 分页大小变化
+const paginationSizeChange = (current: number, pageSize: number) => {
+  console.log('showSizeChange', current, pageSize)
+}
+
+const eventTypeList = ref<{ label: string; value: string }[]>([])
+// 获取事件类型下拉列表
+const fetchEventTypeList = async () => {
+  try {
+    const res = await alarmApi.getAlarmEventTypeList()
+    console.log('获取事件类型下拉列表成功✅', res)
+    const data = res.data
+    eventTypeList.value =
+      (Array.isArray(data) &&
+        data.map((item) => ({
+          label: item.eventDesc,
+          value: item.eventVal,
+        }))) ||
+      []
+  } catch (err) {
+    console.log('获取事件类型下拉列表失败❌', err)
+  }
+}
+
+const { dictNameMap: alarmEventTypeName } = useDictName(eventTypeList)
+
+const loading = ref(false)
+// 获取列表
+const fetchList = async () => {
+  console.log('fetchList')
+  try {
+    loading.value = true
+    const res = await statsApi.statsAlarmQuery({
+      pageNo: current.value,
+      pageSize: pageSize.value,
+      createTimeStart: searchState.createTimeStart,
+      createTimeEnd: searchState.createTimeEnd,
+      eventType: searchState.eventType as ID,
+    })
+    console.log('✅ 获取告警统计数据成功', res)
+    const { rows, total } = res.data
+    alarmList.value = rows as StatsAlarmQueryDataRow[]
+    alarmList.value.forEach((item) => {
+      item.eventTypeName = alarmEventTypeName(item.eventType)
+      try {
+        item.info = item.info && JSON.parse(item.info)
+      } catch (error) {
+        item.info = ''
+        console.log('❌ 解析info失败', error)
+      }
+    })
+    tableList.value = alarmList.value
+    tableTotal.value = Number(total)
+    loading.value = false
+  } catch (error) {
+    console.error('❌ 获取告警统计数据失败', error)
+    loading.value = false
+  }
+}
+
+// 搜索
+const searchHandler = async () => {
+  console.log('searchState', searchState)
+  current.value = 1
+  pageSize.value = 10
+  await fetchList()
+}
+
+const alarmPlanVisible = ref(false) // 告警计划弹窗
+const alarmPlanId = ref<number | null>(null) // 当前编辑的告警计划id
+const alarmPlanTitle = ref<string>('添加告警计划')
+
+type AlarmPlan = {
+  id: number
+  uuid: ID
+  name: string
+  clientId: string
+  enable: SwitchType
+  region: string
+  eventVal: number
+  alarmTimePlanId: ID
+  thresholdTime: ID
+  mergeTime: ID
+  param: string
+  createTime: string
+  updateTime: string
+  remark: string | null
+  alarmTimePlan: {
+    createId: ID
+    updateId: ID
+    createTime: ID
+    updateTime: ID
+    isDeleted: SwitchType | null
+    remark: ID
+    id: ID
+    startDate: string
+    stopDate: string
+    timeRange: string
+    monthDays: string
+    weekdays: string
+  }
+}
+
+interface AlarmPlanItem {
+  id?: number
+  loading?: boolean
+  [key: string]: unknown
+}
+const alarmPlanData = ref<AlarmPlanItem | undefined>(undefined)
+const alarmPlanDataWithType = computed(() => alarmPlanData.value as AlarmPlan)
+
+onActivated(async () => {
+  await fetchEventTypeList().catch((err) => {
+    console.error('fetchEventTypeList 失败', err)
+  })
+
+  await fetchList().catch((err) => {
+    console.error('fetchList 失败', err)
+  })
+})
 </script>
 
-<style scoped lang="less"></style>
+<style scoped lang="less">
+.alarmHistoryPage {
+  .searchBar {
+    padding: 20px;
+    background-color: #fff;
+    margin-bottom: 20px;
+    display: flex;
+    justify-content: space-between;
+    .ant-form {
+      flex-grow: 1;
+    }
+    :deep(.ant-form-inline .ant-form-item) {
+      margin-bottom: 16px !important;
+    }
+  }
+
+  .tableCard {
+    background-color: #fff;
+
+    &-header {
+      display: flex;
+      justify-content: space-between;
+      padding: 20px;
+      &-title {
+        font-size: 18px;
+        font-weight: 600;
+      }
+    }
+  }
+}
+</style>

+ 16 - 16
src/views/device/detail/components/deviceStatsDrawer/const.ts

@@ -7,13 +7,13 @@ export const fallColumns = [
     align: 'center',
     width: 150,
   },
-  {
-    title: '姿态',
-    dataIndex: 'pose',
-    key: 'pose',
-    align: 'center',
-    width: 150,
-  },
+  // {
+  //   title: '姿态',
+  //   dataIndex: 'pose',
+  //   key: 'pose',
+  //   align: 'center',
+  //   width: 150,
+  // },
   {
     title: '处理状态',
     key: 'isHandle',
@@ -37,14 +37,14 @@ export const alarmColumns = [
     dataIndex: 'createTime',
     key: 'createTime',
     align: 'center',
-    width: 150,
+    // width: 150,
   },
   {
     title: '事件类型',
     dataIndex: 'eventType',
     key: 'eventType',
     align: 'center',
-    width: 150,
+    // width: 150,
   },
   {
     title: '事件内容',
@@ -53,13 +53,13 @@ export const alarmColumns = [
     align: 'center',
     // width: 200,
   },
-  {
-    title: '处理状态',
-    key: 'isHandle',
-    dataIndex: 'isHandle',
-    align: 'center',
-    width: 150,
-  },
+  // {
+  //   title: '处理状态',
+  //   key: 'isHandle',
+  //   dataIndex: 'isHandle',
+  //   align: 'center',
+  //   width: 150,
+  // },
   {
     title: '备注',
     key: 'remark',

+ 4 - 4
src/views/device/detail/components/deviceStatsDrawer/index.vue

@@ -47,13 +47,13 @@
     <div class="tableCard">
       <a-table :columns="columns" :data-source="tableList" :loading="loading" :pagination="false">
         <template #bodyCell="{ column, record }">
-          <template v-if="column.key === 'pose'">
+          <!-- <template v-if="column.key === 'pose'">
             {{ record.poseName }}
-          </template>
-          <template v-if="column.key === 'isHandle'">
+          </template> -->
+          <!-- <template v-if="column.key === 'isHandle'">
             <a-tag v-if="record.isHandle === 0" :bordered="false" color="red">未处理</a-tag>
             <a-tag v-if="record.isHandle === 1" :bordered="false" color="green">已处理</a-tag>
-          </template>
+          </template> -->
           <template v-if="column.key === 'eventType'">
             {{ record.eventTypeName }}
           </template>