<template>
|
<div class="app-container">
|
<!-- 优化效果统计 -->
|
<el-row :gutter="20" class="stat-row">
|
<el-col :span="6">
|
<el-statistic title="已过滤无效报警" :value="optimizationStats.filteredCount" />
|
</el-col>
|
<el-col :span="6">
|
<el-statistic title="有效报警率(%)" :value="optimizationStats.validRate" />
|
</el-col>
|
<el-col :span="6">
|
<el-statistic title="平均响应时间(秒)" :value="optimizationStats.responseTime" />
|
</el-col>
|
<el-col :span="6">
|
<el-statistic title="治理评分" :value="optimizationStats.score" />
|
</el-col>
|
</el-row>
|
|
<!-- 滋扰报警治理策略 -->
|
<el-card class="box-card">
|
<template #header>
|
<div class="card-header">
|
<span>滋扰报警治理策略</span>
|
<el-button type="primary" size="small" icon="Plus" @click="handleAddStrategy">新增策略</el-button>
|
</div>
|
</template>
|
|
<el-table :data="strategyList" v-loading="loading" border>
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column prop="strategyName" label="策略名称" min-width="150" />
|
<el-table-column prop="strategyType" label="策略类型" width="120" align="center">
|
<template #default="{ row }">
|
<el-tag size="small">{{ row.strategyType }}</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="description" label="策略说明" min-width="200" />
|
<el-table-column prop="filteredCount" label="已过滤数" width="100" align="center" />
|
<el-table-column prop="status" label="状态" width="80" align="center">
|
<template #default="{ row }">
|
<el-tag :type="row.status === 1 ? 'success' : 'info'" size="small">
|
{{ row.status === 1 ? '启用' : '停用' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="150" align="center">
|
<template #default="{ row }">
|
<el-button type="primary" link size="small" @click="handleEditStrategy(row)">编辑</el-button>
|
<el-button type="danger" link size="small" @click="handleDeleteStrategy(row)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-card>
|
|
<!-- 历史报警数据分析 -->
|
<el-row :gutter="20" style="margin-top: 20px;">
|
<el-col :span="12">
|
<el-card class="box-card">
|
<template #header>
|
<span>治理前后对比</span>
|
</template>
|
<Echarts :xAxis="compareXAxis" :yAxis="compareYAxis" :series="compareSeries" :legend="compareLegend" :tooltip="compareTooltip" :chartStyle="{ height: '280px', width: '100%' }" />
|
</el-card>
|
</el-col>
|
<el-col :span="12">
|
<el-card class="box-card">
|
<template #header>
|
<div class="card-header">
|
<span>高频报警点位TOP5</span>
|
</div>
|
</template>
|
<el-table :data="highFreqList" size="small" border>
|
<el-table-column type="index" label="排名" width="60" align="center" />
|
<el-table-column prop="pointName" label="点位名称" min-width="150" />
|
<el-table-column prop="deviceType" label="设备类型" width="120" align="center" />
|
<el-table-column prop="alarmLevel" label="报警级别" width="100" align="center">
|
<template #default="{ row }">
|
<el-tag :type="row.alarmLevel === '紧急' ? 'danger' : row.alarmLevel === '重要' ? 'warning' : 'info'" size="small">
|
{{ row.alarmLevel }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-card>
|
</el-col>
|
</el-row>
|
|
<!-- 报警剔除审批 -->
|
<el-card class="box-card" style="margin-top: 20px;">
|
<template #header>
|
<div class="card-header">
|
<span>报警剔除审批</span>
|
<el-button type="primary" size="small" icon="Plus" @click="handleApplyRemove">申请剔除</el-button>
|
</div>
|
</template>
|
|
<el-form :inline="true" :model="approvalQuery">
|
<el-form-item label="审批状态">
|
<el-select v-model="approvalQuery.status" placeholder="请选择" clearable style="width: 120px">
|
<el-option label="待审批" value="pending" />
|
<el-option label="已通过" value="approved" />
|
<el-option label="已驳回" value="rejected" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" icon="Search" @click="getApprovalList">查询</el-button>
|
<el-button icon="Refresh" @click="resetApprovalQuery">重置</el-button>
|
</el-form-item>
|
</el-form>
|
|
<el-table :data="approvalList" border>
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column prop="applyNo" label="申请编号" width="120" align="center" />
|
<el-table-column prop="pointName" label="报警点位" min-width="150" />
|
<el-table-column prop="removeReason" label="剔除原因" min-width="180" />
|
<el-table-column prop="applicant" label="申请人" width="100" align="center" />
|
<el-table-column prop="applyTime" label="申请时间" width="160" align="center" />
|
<el-table-column prop="status" label="审批状态" width="100" align="center">
|
<template #default="{ row }">
|
<el-tag :type="row.status === 'pending' ? 'warning' : row.status === 'approved' ? 'success' : 'danger'" size="small">
|
{{ row.status === 'pending' ? '待审批' : row.status === 'approved' ? '已通过' : '已驳回' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="150" align="center">
|
<template #default="{ row }">
|
<template v-if="row.status === 'pending'">
|
<el-button type="success" link size="small" @click="handleApprove(row)">通过</el-button>
|
<el-button type="danger" link size="small" @click="handleReject(row)">驳回</el-button>
|
</template>
|
<span v-else>-</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<pagination v-show="approvalTotal > 0" :total="approvalTotal" v-model:page="approvalQuery.pageNum" v-model:limit="approvalQuery.pageSize" @pagination="getApprovalList" />
|
</el-card>
|
|
<!-- 新增/编辑策略弹窗 -->
|
<el-dialog :title="strategyDialogTitle" v-model="strategyDialogVisible" width="500px" append-to-body>
|
<el-form ref="strategyFormRef" :model="strategyForm" :rules="strategyRules" label-width="100px">
|
<el-form-item label="策略名称" prop="strategyName">
|
<el-input v-model="strategyForm.strategyName" placeholder="请输入策略名称" />
|
</el-form-item>
|
<el-form-item label="策略类型" prop="strategyType">
|
<el-select v-model="strategyForm.strategyType" placeholder="请选择" style="width: 100%">
|
<el-option label="重复报警过滤" value="重复报警过滤" />
|
<el-option label="抖动报警过滤" value="抖动报警过滤" />
|
<el-option label="瞬态报警过滤" value="瞬态报警过滤" />
|
<el-option label="无效报警屏蔽" value="无效报警屏蔽" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="策略说明" prop="description">
|
<el-input v-model="strategyForm.description" type="textarea" :rows="3" placeholder="请输入策略说明" />
|
</el-form-item>
|
<el-form-item label="规则配置" prop="ruleConfig">
|
<el-input v-model="strategyForm.ruleConfig" type="textarea" :rows="3" placeholder="请输入规则配置JSON" />
|
</el-form-item>
|
<el-form-item label="状态" prop="status">
|
<el-radio-group v-model="strategyForm.status">
|
<el-radio :label="1">启用</el-radio>
|
<el-radio :label="0">停用</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="strategyDialogVisible = false">取消</el-button>
|
<el-button type="primary" @click="submitStrategyForm">确定</el-button>
|
</template>
|
</el-dialog>
|
|
<!-- 申请剔除弹窗 -->
|
<el-dialog title="申请报警剔除" v-model="applyDialogVisible" width="500px" append-to-body>
|
<el-form ref="applyFormRef" :model="applyForm" :rules="applyRules" label-width="100px">
|
<el-form-item label="报警点位" prop="pointId">
|
<el-select v-model="applyForm.pointId" placeholder="请选择报警点位" style="width: 100%">
|
<el-option v-for="item in pointOptions" :key="item.pointId" :label="item.pointName" :value="item.pointId" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="剔除原因" prop="removeReason">
|
<el-select v-model="applyForm.removeReason" placeholder="请选择剔除原因" style="width: 100%">
|
<el-option label="误报警" value="误报警" />
|
<el-option label="设备故障已修复" value="设备故障已修复" />
|
<el-option label="工艺调整" value="工艺调整" />
|
<el-option label="其他原因" value="其他原因" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="详细说明" prop="description">
|
<el-input v-model="applyForm.description" type="textarea" :rows="3" placeholder="请详细说明剔除原因" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="applyDialogVisible = false">取消</el-button>
|
<el-button type="primary" @click="submitApplyForm">提交申请</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted } from 'vue';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
import Echarts from '@/components/Echarts/echarts.vue';
|
import Pagination from '@/components/Pagination/index.vue';
|
import {
|
getOptimizationStatistics,
|
listNuisanceStrategies,
|
addNuisanceStrategy,
|
updateNuisanceStrategy,
|
delNuisanceStrategy,
|
changeStrategyStatus,
|
getOptimizationCompareData,
|
listRemoveApprovals,
|
submitRemoveApply,
|
approveRemoveApply,
|
rejectRemoveApply
|
} from '@/api/alarmManagement/alarmOptimization';
|
import { listAlarmPointLedger } from '@/api/alarmManagement/dataCollection';
|
|
// 优化统计
|
const optimizationStats = reactive({
|
filteredCount: 0,
|
validRate: 0,
|
responseTime: 0,
|
score: 0
|
});
|
|
// 策略列表
|
const loading = ref(false);
|
const strategyList = ref([]);
|
|
// 审批列表
|
const approvalList = ref([]);
|
const approvalTotal = ref(0);
|
const approvalQuery = reactive({
|
pageNum: 1,
|
pageSize: 10,
|
status: ''
|
});
|
|
// 高频报警列表
|
const highFreqList = ref([]);
|
|
// 策略弹窗
|
const strategyDialogVisible = ref(false);
|
const strategyDialogTitle = ref('');
|
const strategyFormRef = ref(null);
|
const strategyForm = reactive({
|
strategyId: undefined,
|
strategyName: '',
|
strategyType: '',
|
description: '',
|
ruleConfig: '',
|
status: 1
|
});
|
const strategyRules = {
|
strategyName: [{ required: true, message: '策略名称不能为空', trigger: 'blur' }],
|
strategyType: [{ required: true, message: '策略类型不能为空', trigger: 'change' }],
|
description: [{ required: true, message: '策略说明不能为空', trigger: 'blur' }]
|
};
|
|
// 申请弹窗
|
const applyDialogVisible = ref(false);
|
const applyFormRef = ref(null);
|
const applyForm = reactive({
|
pointId: '',
|
removeReason: '',
|
description: ''
|
});
|
const applyRules = {
|
pointId: [{ required: true, message: '请选择报警点位', trigger: 'change' }],
|
removeReason: [{ required: true, message: '请选择剔除原因', trigger: 'change' }],
|
description: [{ required: true, message: '请填写详细说明', trigger: 'blur' }]
|
};
|
const pointOptions = ref([]);
|
|
// 图表配置
|
const compareXAxis = ref([{ type: 'category', data: [] }])
|
const compareYAxis = ref([{ type: 'value' }])
|
const compareSeries = ref([
|
{ name: '治理前', type: 'bar', data: [], itemStyle: { color: '#f56c6c' } },
|
{ name: '治理后', type: 'bar', data: [], itemStyle: { color: '#67c23a' } },
|
])
|
const compareLegend = reactive({ data: ['治理前', '治理后'] })
|
const compareTooltip = reactive({ trigger: 'axis', axisPointer: { type: 'shadow' } })
|
|
// 获取优化统计
|
async function getStatistics() {
|
const res = await getOptimizationStatistics();
|
if (res.code === 200) {
|
Object.assign(optimizationStats, res.data);
|
}
|
}
|
|
// 获取策略列表
|
async function getStrategyList() {
|
loading.value = true;
|
const res = await listNuisanceStrategies();
|
if (res.code === 200) {
|
strategyList.value = res.data;
|
}
|
loading.value = false;
|
}
|
|
// 获取审批列表
|
async function getApprovalList() {
|
const res = await listRemoveApprovals(approvalQuery);
|
if (res.code === 200) {
|
approvalList.value = res.data.records;
|
approvalTotal.value = res.data.total;
|
}
|
}
|
|
// 获取高频报警列表(调用数据采集模块的查询接口)
|
async function getHighFreqList() {
|
const res = await listAlarmPointLedger({ current: 1, size: 5 });
|
if (res.code === 200) {
|
highFreqList.value = res.data.records || res.data || [];
|
}
|
}
|
|
// 获取对比数据
|
async function getCompareData() {
|
const res = await getOptimizationCompareData();
|
if (res.code === 200) {
|
const data = res.data;
|
compareXAxis.value[0].data = data.categories
|
compareSeries.value[0].data = data.before
|
compareSeries.value[1].data = data.after
|
}
|
}
|
|
// 获取点位选项(调用数据采集模块的查询接口)
|
async function getPointOptions() {
|
const res = await listAlarmPointLedger({ current: 1, size: 1000 });
|
if (res.code === 200) {
|
pointOptions.value = res.data.records || res.data || [];
|
}
|
}
|
|
function handleAddStrategy() {
|
strategyDialogTitle.value = '新增策略';
|
Object.keys(strategyForm).forEach(key => strategyForm[key] = key === 'strategyId' ? undefined : '');
|
strategyDialogVisible.value = true;
|
}
|
|
function handleEditStrategy(row) {
|
strategyDialogTitle.value = '编辑策略';
|
Object.assign(strategyForm, row);
|
strategyDialogVisible.value = true;
|
}
|
|
async function submitStrategyForm() {
|
strategyFormRef.value.validate(async (valid) => {
|
if (valid) {
|
const api = strategyForm.strategyId ? updateNuisanceStrategy : addNuisanceStrategy;
|
const res = await api(strategyForm);
|
if (res.code === 200) {
|
ElMessage.success(strategyForm.strategyId ? '修改成功' : '新增成功');
|
strategyDialogVisible.value = false;
|
getStrategyList();
|
}
|
}
|
});
|
}
|
|
async function handleDeleteStrategy(row) {
|
await ElMessageBox.confirm('确认删除该策略吗?', '提示', { type: 'warning' });
|
const res = await delNuisanceStrategy(row.strategyId);
|
if (res.code === 200) {
|
ElMessage.success('删除成功');
|
getStrategyList();
|
}
|
}
|
|
async function handleStrategyStatusChange(row) {
|
const res = await changeStrategyStatus(row.strategyId, row.status);
|
if (res.code === 200) {
|
ElMessage.success('状态修改成功');
|
}
|
}
|
|
function handleViewMore() {
|
ElMessage.info('查看更多高频报警点位');
|
}
|
|
function handleApplyRemove() {
|
Object.keys(applyForm).forEach(key => applyForm[key] = '');
|
applyDialogVisible.value = true;
|
}
|
|
async function submitApplyForm() {
|
applyFormRef.value.validate(async (valid) => {
|
if (valid) {
|
const res = await submitRemoveApply(applyForm);
|
if (res.code === 200) {
|
ElMessage.success('申请提交成功');
|
applyDialogVisible.value = false;
|
getApprovalList();
|
}
|
}
|
});
|
}
|
|
async function handleApprove(row) {
|
const res = await approveRemoveApply(row.applyNo);
|
if (res.code === 200) {
|
ElMessage.success('审批通过');
|
getApprovalList();
|
}
|
}
|
|
async function handleReject(row) {
|
const res = await rejectRemoveApply(row.applyNo);
|
if (res.code === 200) {
|
ElMessage.success('已驳回');
|
getApprovalList();
|
}
|
}
|
|
function viewDetail(row) {
|
ElMessage.info('查看详情: ' + row.applyNo);
|
}
|
|
function resetApprovalQuery() {
|
approvalQuery.status = '';
|
getApprovalList();
|
}
|
|
onMounted(() => {
|
getStatistics();
|
getStrategyList();
|
getApprovalList();
|
getHighFreqList();
|
getCompareData();
|
getPointOptions();
|
});
|
</script>
|
|
<style scoped>
|
.stat-row {
|
margin-bottom: 20px;
|
}
|
.stat-row :deep(.el-statistic__content) {
|
font-size: 28px;
|
font-weight: 600;
|
color: #303133;
|
}
|
.stat-row :deep(.el-statistic__title) {
|
font-size: 14px;
|
color: #606266;
|
margin-bottom: 8px;
|
}
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
</style>
|