|
@@ -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>
|