2025-05-28 16:53:52 +08:00

444 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="bigdata-alarm-info">
<BCard title="报警信息" @edit="handleEdit" style="height: 100%">
<div class="info-content" :style="{ maxHeight: contentMaxHeight }">
<a-scrollbar :maxHeight="contentMaxHeight">
<div class="info-list">
<div class="info-list-item" v-for="item in alarmInfo" :key="item.title">
<div class="info-list-item-title">
{{ item.title }}
</div>
<div class="info-list-item-content">
<div class="info-list-item-text">
<span class="value">{{ item.value }}</span>
<span class="label">设备数量</span>
</div>
<div class="info-list-item-text">
<span class="value">{{ item.num }}</span>
<span class="label">离线</span>
</div>
</div>
</div>
</div>
<div class="alarm-list">
<div
class="alarm-list-item"
v-for="item in alarmTabList"
:key="item.name"
:class="{ active: item.value === alarmTabValue }"
@click="handleAlarmTabClick(item.value)"
>
{{ item.name }}({{ item.num }})
</div>
</div>
<a-table
v-if="alarmTabValue === 1"
size="small"
:dataSource="alarmInfoList"
:columns="columns"
rowKey="id"
:pagination="false"
:showSorterTooltip="false"
>
<template #bodyCell="{ column, record }">
<span v-if="column.dataIndex === 'type'" :style="record[column.dataIndex] === 1 ? { color: '#EDA200' } : { color: '#ff0000' }">
{{ record[column.dataIndex] === 1 ? '预警' : '报警' }}
</span>
</template>
</a-table>
<a-table
v-if="alarmTabValue === 2"
size="small"
:dataSource="eventAlarmInfoList"
:columns="eventColumns"
rowKey="id"
:pagination="false"
:showSorterTooltip="false"
>
<template #bodyCell="{ column, record, text }">
<template v-if="column.dataIndex === 'state'">
<a-tag :bordered="false" :color="stateMap[text].color">{{ stateMap[text].label }}</a-tag>
</template>
<template v-if="column.dataIndex === 'image'">
<template v-if="JSON.parse(record.image).length > 0">
<a-image :width="40" :src="JSON.parse(record.image)[0].fileUrl" />
</template>
<template v-else>
<span></span>
</template>
</template>
</template>
</a-table>
<a-table
v-if="alarmTabValue === 3"
size="small"
:dataSource="aiAlarmInfoList"
:columns="aiColumns"
rowKey="id"
:pagination="false"
:showSorterTooltip="false"
>
<template #bodyCell="{ column, record }">
<span v-if="column.dataIndex === 'imageUrl'">
<a-image :src="record[column.dataIndex]" :width="40" :height="24" />
</span>
</template>
</a-table>
</a-scrollbar>
</div>
</BCard>
<AlarmInfoDialog ref="alarmInfoDialogRef" @refresh="queryConfigPage" />
</div>
</template>
<script setup>
import BCard from './b-card.vue';
import AlarmInfoDialog from './alarm-info-dialog.vue';
import { ref, onMounted, nextTick, watch } from 'vue';
import { bigdataApi } from '/@/api/business/bigdata/bigdata-api';
import { monitorApi } from '/@/api/business/monitor/monitor-api';
import { eventApi } from '/@/api/business/event/event-api';
import { weatherStationApi } from '/@/api/business/weather-station/weather-station-api';
import { useUserStore } from '/@/store/modules/system/user';
watch(
() => useUserStore().getCurrentVillageId,
(value) => {
getTableList();
queryConfigPage();
},
);
const alarmInfo = ref([]);
const alarmInfoList = ref([]);
const aiAlarmInfoList = ref([]);
const eventAlarmInfoList = ref([]);
const alarmInfoDialogRef = ref();
const contentMaxHeight = ref(0);
const isEdit = ref(false);
const isCustom = ref(false);
const alarmInfoData = ref({});
const alarmTabList = ref([
{
name: '设备预警',
value: 1,
num: 0,
},
{
name: '事件预警',
value: 2,
num: 0,
},
{
name: 'AI预警',
value: 3,
num: 0,
},
]);
const alarmTabValue = ref(1);
const columns = ref([
{
title: '名称',
dataIndex: 'deviceName',
},
{
title: '报警类型',
dataIndex: 'type',
},
{
title: '报警项',
dataIndex: 'alarmTypeName',
},
{
title: '报警值',
dataIndex: 'alarmValue',
},
{
title: '阈值',
dataIndex: 'exceed',
},
{
title: '推送人',
dataIndex: 'pushUser',
},
]);
const aiColumns = ref([
{
title: '名称',
dataIndex: 'hardwareName',
},
{
title: '编号',
dataIndex: 'hardwareId',
ellipsis: true,
},
{
title: '预警类型',
dataIndex: 'alarmTypeName',
},
{
title: '图片',
dataIndex: 'imageUrl',
},
]);
const eventColumns = ref([
{
title: '事件名称',
dataIndex: 'eventDesc',
},
{
title: '图片',
dataIndex: 'image',
},
{
title: '上报人',
dataIndex: 'createByName',
},
{
title: '处理人',
dataIndex: 'solveUserName',
},
{
title: '状态',
dataIndex: 'state',
},
]);
// 状态(0已发起待处理1已处理2:已驳回)
const stateMap = [
{
label: '待处理',
value: 0,
color: 'blue',
},
{
label: '待审核',
value: 1,
color: 'orange',
},
{
label: '驳回',
value: 2,
color: 'red',
},
{
label: '通过',
value: 3,
color: 'green',
},
];
const getAlarmInfo = async () => {
const res = await bigdataApi.getDeviceOnline();
const { environmentOffLine, environmentTotal, insectPestSituationOffLine, insectPestSituationTotal, videoOffLine, videoTotal } = res.data;
alarmInfo.value = [
{
title: '监控摄像',
value: videoTotal,
num: videoOffLine,
},
{
title: '虫情灯',
value: insectPestSituationTotal,
num: insectPestSituationOffLine,
},
{
title: '气象站',
value: environmentTotal,
num: environmentOffLine,
},
];
};
const queryConfigPage = async () => {
const res = await bigdataApi.queryLargeScreenConfigPage({
configKey: 'alarmInfo',
pageNum: 1,
pageSize: 1,
});
isEdit.value = res.data.list.length > 0 ? true : false;
if (res.ok && res.data.list.length > 0) {
alarmInfoData.value = res.data.list[0];
const { configValue } = alarmInfoData.value;
const { isCustom: isCustom1, list } = JSON.parse(configValue);
isCustom.value = isCustom1;
if (isCustom.value) {
alarmInfo.value = list;
} else {
await getAlarmInfo();
}
} else {
await getAlarmInfo();
}
};
const getTableList = async () => {
// 设备预警
const deviceListRes = await weatherStationApi.queryAlarmWarningPage({ pageNum: 1, pageSize: 500 });
const deviceList = deviceListRes.data.list || [];
alarmTabList.value[0].num = deviceListRes.data.total;
alarmInfoList.value = deviceList;
// AI预警
const aiListRes = await monitorApi.queryAiAlarmRecordPage({ pageNum: 1, pageSize: 500 });
const aiList = aiListRes.data.list || [];
alarmTabList.value[2].num = aiListRes.data.total;
aiAlarmInfoList.value = aiList;
// 事件预警
const eventListRes = await eventApi.queryPage({ pageNum: 1, pageSize: 500 });
const eventList = eventListRes.data.list || [];
alarmTabList.value[1].num = eventListRes.data.total;
eventAlarmInfoList.value = eventList;
};
const handleAlarmTabClick = (value) => {
alarmTabValue.value = value;
};
const initHeight = () => {
let height = document.querySelector('.bigdata-right').clientHeight;
let height1 = document.querySelector('.bigdata-right-1').clientHeight;
let height3 = document.querySelector('.bigdata-right-3').clientHeight;
let otherHeight = 76;
let gapHeight = 40;
contentMaxHeight.value = `${height - otherHeight - gapHeight - height1 - height3}px`;
};
onMounted(async () => {
await getTableList();
await queryConfigPage();
initHeight();
window.addEventListener('resize', initHeight);
});
const handleEdit = () => {
alarmInfoDialogRef.value.showModal(isEdit.value ? alarmInfoData.value : null);
};
</script>
<style lang="less" scoped>
.bigdata-alarm-info {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
// overflow: hidden;
.info-content {
width: 100%;
height: 100%;
.info-list {
display: flex;
flex-wrap: wrap;
gap: 14px;
position: relative;
.info-list-item {
display: flex;
flex-direction: column;
// align-items: center;
// justify-content: space-between;
width: calc(33.33% - 9.33px);
height: 86px;
gap: 6px;
background-image: url('/@/assets/images/bigdata/alarm-bg.png');
background-size: 100% 100%;
background-repeat: no-repeat;
// padding: 10px;
.info-list-item-title {
padding: 8px 28px;
font-family:
Alibaba PuHuiTi,
Alibaba PuHuiTi;
font-weight: 400;
font-size: 14px;
color: #ffffff;
line-height: 20px;
}
.info-list-item-content {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
gap: 12px;
.info-list-item-text {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.label {
font-weight: 500;
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
line-height: 18px;
}
.value {
font-family:
PingFang SC,
PingFang SC;
font-weight: 800;
font-size: 18px;
color: #ffffff;
line-height: 22px;
}
}
}
}
}
:deep(.ant-table) {
background: transparent;
color: #fff;
border: none;
.ant-table-thead > tr > th {
background: transparent;
color: #fff;
border: none;
&::before {
display: none;
}
}
.ant-table-tbody > tr {
background: rgba(124, 222, 135, 0.05);
& > td {
background: transparent;
color: #fff;
border: none;
}
}
}
}
}
.alarm-list {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin: 10px;
.alarm-list-item {
font-family:
PingFang SC,
PingFang SC;
font-weight: 500;
font-size: 12px;
height: 20px;
color: rgba(255, 255, 255, 0.7);
background: linear-gradient(360deg, #19926c 0%, rgba(25, 146, 108, 0) 100%);
border-radius: 20px;
padding: 0px 10px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&.active {
background: linear-gradient(360deg, #4fe87d 0%, rgba(80, 237, 114, 0) 100%);
}
}
}
</style>