feat: 调整报警管理-厂界在线页面

调整报警管理-厂界在线页面,解决选择部门后页面无数据的问题,修改页面后端接口。
This commit is contained in:
LokerL 2024-10-11 21:16:39 +08:00
parent 627e8fd07e
commit 72b2ace017
7 changed files with 440 additions and 289 deletions

View File

@ -0,0 +1,31 @@
package com.ruoyi.project.oil.controller;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.oil.service.IOilThDeviceReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/analysis")
public class OilAnalysisController extends BaseController {
@Autowired
private IOilThDeviceReportService oilThDeviceReportService;
@GetMapping("/factoryBoundaryOnline")
public AjaxResult getDeviceReport(Long deptId, String beginDate, String endDate) {
List<Map<String, Object>> alarmCount = oilThDeviceReportService.selectAlarmCountByDeptIdAndDateRange(deptId, beginDate, endDate);
List<Map<String, Object>> alarmCountDesc = oilThDeviceReportService.selectAlarmCountByDeptIdAndDateRangeDesc(deptId, beginDate, endDate);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("alarmCount", alarmCount);
resultMap.put("alarmCountDesc", alarmCountDesc);
return AjaxResult.success(resultMap);
}
}

View File

@ -71,4 +71,11 @@ public interface ThDeviceReportMapper {
*/ */
@MapKey("day") @MapKey("day")
List<Map<String, Object>> dailyReportDataOverview(@Param("day") String day); List<Map<String, Object>> dailyReportDataOverview(@Param("day") String day);
@MapKey("day")
List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRange(@Param("deptId") Long deptId, @Param("beginDate") String beginDate, @Param("endDate") String endDate);
@MapKey("sn")
List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRangeDesc(@Param("deptId") Long deptId, @Param("beginDate") String beginDate, @Param("endDate") String endDate);
} }

View File

@ -9,4 +9,8 @@ public interface IOilThDeviceReportService {
List<Map<String, Object>> monthReportDataOverviewDeviceDs(Long deptId, String month); List<Map<String, Object>> monthReportDataOverviewDeviceDs(Long deptId, String month);
List<Map<String, Object>> dailyReportDataOverview(String day); List<Map<String, Object>> dailyReportDataOverview(String day);
List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRange(Long deptId, String beginDate, String endDate);
List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRangeDesc(Long deptId, String beginDate, String endDate);
} }

View File

@ -31,4 +31,14 @@ public class OilThDeviceReportService implements IOilThDeviceReportService {
return camelCaseMapListKey(thDeviceReportMapper.dailyReportDataOverview(day)); return camelCaseMapListKey(thDeviceReportMapper.dailyReportDataOverview(day));
} }
@Override
public List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRange(Long deptId, String beginDate, String endDate) {
return camelCaseMapListKey(thDeviceReportMapper.selectAlarmCountByDeptIdAndDateRange(deptId, beginDate, endDate));
}
@Override
public List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRangeDesc(Long deptId, String beginDate, String endDate) {
return camelCaseMapListKey(thDeviceReportMapper.selectAlarmCountByDeptIdAndDateRangeDesc(deptId, beginDate, endDate));
}
} }

View File

@ -177,4 +177,52 @@
GROUP BY TO_CHAR(d.report_time, 'YYYY-MM-DD'), ppp.dept_name, pp.dept_name, p.dept_name, d.sn GROUP BY TO_CHAR(d.report_time, 'YYYY-MM-DD'), ppp.dept_name, pp.dept_name, p.dept_name, d.sn
ORDER BY ppp.dept_name, pp.dept_name, p.dept_name ORDER BY ppp.dept_name, pp.dept_name, p.dept_name
</select> </select>
<!-- 选择日期范围内 某个部门id下的所有子部门的所有设备的报警每日数量统计(d.zt = '一级报警' OR d.zt = '二级报警')的alarm_count 统计当天全部的数量count -->
<select id="selectAlarmCountByDeptIdAndDateRange" parameterType="map" resultType="map">
SELECT TO_CHAR(d.report_time, 'YYYY-MM-DD') AS day,
COUNT(CASE WHEN d.zt = '一级报警' OR d.zt = '二级报警' THEN 1 END) AS alarm_count,
COUNT(1) AS count
FROM th_device_report d
LEFT JOIN th_device td ON d.sn = td.sn
LEFT JOIN sys_dept p ON td.dept_id = p.dept_id
WHERE d.sn IN (SELECT d.sn
FROM th_device d
LEFT JOIN sys_dept p ON d.dept_id = p.dept_id
WHERE d.dept_id IN (SELECT dept_id
FROM sys_dept START WITH dept_id = #{deptId}
CONNECT BY PRIOR dept_id = parent_id))
AND d.report_time &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND d.report_time &lt;= TO_DATE(#{endDate}, 'YYYY-MM-DD')
GROUP BY TO_CHAR(d.report_time, 'YYYY-MM-DD')
ORDER BY day
</select>
<!-- 选择日期范围内 某个部门id下的所有子部门的所有设备的报警数量 降序排列 -->
<select id="selectAlarmCountByDeptIdAndDateRangeDesc" parameterType="map" resultType="map">
SELECT d.sn,
COUNT(d.id) AS count,
p.dept_name as "p",
pp.dept_name as "pp",
ppp.dept_name as "ppp",
td.address,
td.name,
d.zt
FROM th_device_report d
LEFT JOIN th_device td ON d.sn = td.sn
LEFT JOIN sys_dept p ON td.dept_id = p.dept_id
LEFT JOIN sys_dept pp ON p.parent_id = pp.dept_id
LEFT JOIN sys_dept ppp ON pp.parent_id = ppp.dept_id
WHERE d.sn IN (SELECT d.sn
FROM th_device d
LEFT JOIN sys_dept p ON d.dept_id = p.dept_id
WHERE d.dept_id IN (SELECT dept_id
FROM sys_dept START WITH dept_id = #{deptId}
CONNECT BY PRIOR dept_id = parent_id))
AND d.report_time &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND d.report_time &lt;= TO_DATE(#{endDate}, 'YYYY-MM-DD')
AND (d.zt = '一级报警' OR d.zt = '二级报警')
GROUP BY d.sn, p.dept_name, pp.dept_name, ppp.dept_name, td.address, td.name, d.zt
ORDER BY count DESC
</select>
</mapper> </mapper>

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function factoryBoundaryOnline(params) {
return request({
url: '/analysis/factoryBoundaryOnline',
params: params,
method: 'get',
})
}

View File

@ -1,302 +1,344 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" :model="queryParams" ref="form"> <el-row :gutter="10">
<el-col :span="6">
<el-form-item> <dept-tree @deptChange="handleDeptChange" :showQuickGroup="true" />
<span style="margin-right: 10px;">日期</span> </el-col>
<el-date-picker v-model="dateList" type="daterange" range-separator="" start-placeholder="开始日期" <el-col :span="6">
end-placeholder="结束日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd" :picker-options="pickerOptions"> <el-date-picker
</el-date-picker> v-model="dateList"
</el-form-item> type="daterange"
<el-form-item> range-separator="至"
<el-button type="primary" icon="el-icon-search" size="mini" @click="queryChart">搜索</el-button> start-placeholder="开始日期"
</el-form-item> end-placeholder="结束日期"
</el-form> format="yyyy-MM-dd"
<div style="display: flex;height: 780px;"> value-format="yyyy-MM-dd"
<div style="width: 50%;background: #e0e1e2;padding:10px"> :picker-options="pickerOptions"
<div class="title">厂界在线监测设备报警情况分析</div> @change="dateChange"
<div style="width:100%;height:700px;" ref="qdCityMap1"></div> >
</el-date-picker>
</div> </el-col>
<div style="width: 50%;background: #e0e1e2;padding:10px"> </el-row>
结合最近14天的数据分析报警最多的监测设备列表如下请在未来加强管控
<el-table v-loading="loading" :data="monitorList" style="height: 800px;">
<el-table-column label="企业名称" align="center" prop="a" />
<el-table-column label="设备编号" align="center" prop="d" />
<el-table-column label="放置区域" align="center" prop="b" />
<el-table-column label="报警次数" align="center" prop="e" >
<template slot-scope="scope">
<span :style="{ color: 'red' }">{{ scope.row.e }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">下发通知</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!--发送通知-->
<send-msg :deviceInfo="deviceInfo" v-if="isOpenMsg" :isOpenMsg="isOpenMsg" @closeMsg="closeMsg"></send-msg>
</div>
</template>
<script>
import { queryAlarmChart} from "@/api/demostrate/monitor";
import { queryMonitorPrediction} from "@/api/demostrate/monitor";
import sendMsg from "@/views/demostrate/alarm/sendMsg.vue";
const echarts = require("echarts");
export default {
name: "alarm",
components: {sendMsg},
dicts: [],
data() {
return {
monitorList:[{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:2},{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},
{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:4},
{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3}
,{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},
{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:6},{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},
{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},
{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},{'a':'***有限公司',b:'泄压装置',c:'阀门',d:'000SSD-001-001-0002',e:3},
],
loading:false,
pickerOptions: {
// disabledDate(time) {
// //
// const diff = Math.abs(time.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24);
// // 30
// return diff > 30;
// },
shortcuts: [
{
text: '最近30天',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 29); // 30
picker.$emit('pick', [start, end]);
}
}]},
dateList: [],//
total:0,
isOpenMsg:false,
deviceInfo: {},
//
queryParams: {
startTime: null,
endTime: null,
},
<div style="display: flex; height: 700px; margin-top: 10px;">
}; <div style="width: 50%; background: #e0e1e2; padding: 10px">
<div class="title">厂界在线监测设备报警情况分析</div>
<div style="width: 100%; height: 650px" ref="qdCityMap1"></div>
</div>
<div style="width: 50%; background: #e0e1e2; padding: 10px">
结合{{days}}天的数据分析报警最多的监测设备列表如下请在未来加强管控
<el-table v-loading="loading" :data="alarmCountDesc" max-height="650">
<el-table-column label="企业名称" align="center" prop="p" />
<el-table-column label="设备编号" align="center" prop="sn" />
<el-table-column label="放置区域" align="center" prop="address" />
<el-table-column label="报警次数" align="center" prop="count">
<template slot-scope="scope">
<span :style="{ color: 'red' }">{{ scope.row.count }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>下发通知</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!--发送通知-->
<send-msg
:deviceInfo="deviceInfo"
v-if="isOpenMsg"
:isOpenMsg="isOpenMsg"
@closeMsg="closeMsg"
></send-msg>
</div>
</template>
<script>
import { queryAlarmChart } from "@/api/demostrate/monitor";
import { queryMonitorPrediction } from "@/api/demostrate/monitor";
import sendMsg from "@/views/demostrate/alarm/sendMsg.vue";
const echarts = require("echarts");
import { factoryBoundaryOnline } from "@/api/analysis"
import to from '@/utils/await-to.js';
import moment from 'moment';
import { debounce } from '@/utils';
export default {
name: "alarm",
components: { sendMsg },
dicts: [],
data() {
return {
dept: null,
queryDebounce: null,
alarmCount: [],
alarmCountDesc: [],
days: 0,
loading: false,
pickerOptions: {
// disabledDate(time) {
// //
// const diff = Math.abs(time.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24);
// // 30
// return diff > 30;
// },
shortcuts: [
{
text: "最近30天",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 29); // 30
picker.$emit("pick", [start, end]);
},
},
],
},
dateList: [], //
total: 0,
isOpenMsg: false,
deviceInfo: {},
//
queryParams: {
deptId: null,
beginDate: null,
endDate: null,
},
};
},
mounted() {
this.queryDebounce = debounce(this.query, 100);
setTimeout(() => {
let dsiab_com = this.$refs.qdCityMap1;
dsiab_com.removeAttribute("_echarts_instance_");
this.getDefaultDateRange();
});
},
watch: {
dateList: {
handler: function () {
//
const diff = Math.abs(
new Date(this.dateList[1]).getTime() -
new Date(this.dateList[0]).getTime()
);
this.days = diff / (1000 * 60 * 60 * 24);
},
deep: true,
}, },
created() { },
methods: {
dateChange() {
this.queryDebounce();
}, },
mounted() { handleDeptChange(dept) {
this.dept = dept;
setTimeout(() => { this.queryDebounce();
let dsiab_com = this.$refs.qdCityMap1
dsiab_com.removeAttribute('_echarts_instance_')
this.getDefaultDateRange()
// this.getList();
})
}, },
methods: { async query() {
// if (this.dept && this.dateList.length > 0) {
handleUpdate(row) { this.queryParams.deptId = this.dept.deptId;
this.deviceInfo = row this.queryParams.beginDate = this.dateList[0];
this.isOpenMsg = true this.queryParams.endDate = this.dateList[1];
}, console.log(this.queryParams);
const [err, res] = await to(factoryBoundaryOnline(this.queryParams));
queryChart() { if (err) {
if (this.dateList && this.dateList.length > 0) { console.error(err);
this.queryParams.startTime = this.dateList[0] this.$message.error("查询失败");
this.queryParams.endTime = this.dateList[1] return;
} else {
this.queryParams.startTime = null
this.queryParams.endTime = null
} }
// queryAlarmChart(this.queryParams).then(response => { if (res.code !== 200) {
// if(response.data && response.data.length>0){ this.$message.error(res.msg);
// let xData=[]// return;
// let yData1=[]// }
// let yData2=[]// console.log(res);
// let yData3=[]// this.alarmCount = res.data.alarmCount;
// response.data.forEach(map=>{ this.alarmCountDesc = res.data.alarmCountDesc;
// xData.push(map.reportTime) this.queryChart();
// yData1.push(map.level1)
// yData2.push(map.level2) }
// yData3.push(map.progress) },
// }) //
// this.init(xData,yData1,yData2,yData3) handleUpdate(row) {
// } this.deviceInfo = row;
// }); this.isOpenMsg = true;
let xData = ['2024-05-03','2024-05-06','2024-05-08','2024-05-11','2024-05-15','2024-05-20']// },
let yData1 = [10,12,32,12,5,6,9]//
let yData2 = [5,1,3,5,9,2,1]// queryChart() {
let yData3 = [15,23,3,12,20,3,2]// const xData = [];
const yData1 = [];
this.init(xData, yData1, yData2, yData3) const yData2 = [];
}, const yData3 = [];
getDefaultDateRange() { this.alarmCount.forEach((item) => {
const endDate = new Date(); // xData.push(item.day);
const startDate = new Date(); yData1.push(item.alarmCount);
startDate.setDate(startDate.getDate() - 7); // 7 yData3.push(((item.alarmCount / item.count) * 100).toFixed(2));
this.dateList = [startDate, endDate] });
this.queryChart() this.init(xData, yData1, yData2, yData3);
}, },
init(xData,yData1,yData2,yData3) { getDefaultDateRange() {
const yData2GradientColor = [ const endDate = new Date(); //
const startDate = new Date();
startDate.setDate(startDate.getDate() - 7); // 7
// YYYY-MM-DD
this.dateList = [
moment(startDate).format("YYYY-MM-DD"),
moment(endDate).format("YYYY-MM-DD"),
];
this.queryChart();
},
init(xData, yData1, yData2, yData3) {
const yData2GradientColor = [
{
offset: 0,
color: "#0058e1",
},
{
offset: 1,
color: "#3BA1E3",
},
];
const yData3GradientColor = [
{
offset: 0,
color: "#32E8D4",
},
{
offset: 1,
color: "#4BA1E3",
},
];
const option = {
tooltip: {
trigger: "axis", // x
formatter: function (params) {
let list = [];
let listItem = "";
params.forEach((item) => {
// 线 %
let unitValue =
item.seriesType == "bar" ? item.value + "个" : item.value + "%";
list.push(item.marker + "" + item.seriesName + ": " + unitValue);
});
listItem = list.join("<br/>");
return "<div>" + listItem + "</div>";
},
},
legend: {
orient: "horizontal", //
x: "center", //
y: "top", //
padding: 6, // []
},
xAxis: {
type: "category",
data: xData,
},
yAxis: [
{ {
offset: 0, type: "value",
color: '#0058e1' name: "报警数",
}, yAxisIndex: 0,
{ axisLabel: {
offset: 1, //y
color: '#3BA1E3' formatter: "{value}个",
}
]
const yData3GradientColor = [
{
offset: 0,
color: '#32E8D4'
},
{
offset: 1,
color: '#4BA1E3'
}
]
const option = {
tooltip: {
trigger: 'axis', // x
formatter: function (params) {
let list = []
let listItem = ''
params.forEach((item) => {
// 线 %
let unitValue = item.seriesType == 'bar' ? item.value + '个' : item.value + '%'
list.push(item.marker + '' + item.seriesName + ': ' + unitValue)
})
listItem = list.join('<br/>')
return '<div>' + listItem + '</div>'
}
},
legend: {
orient: 'horizontal', //
x: 'center', //
y: 'top', //
padding: 6, // []
},
xAxis: {
type: 'category',
data: xData
},
yAxis: [
{
type: 'value',
name: '报警数',
yAxisIndex: 0,
axisLabel: {
//y
formatter: "{value}个",
},
}, },
{ },
type: 'value', {
name: "报警率(%)", type: "value",
min: 0, // 0 name: "报警率(%)",
max: 100, // 100 min: 0, // 0
interval: 25, // 25 max: 100, // 100
axisLabel: { interval: 25, // 25
//y axisLabel: {
formatter: "{value}%", //y
}, formatter: "{value}%",
}, },
], },
series: [ ],
{ series: [
type: 'bar', {
stack: 'x', type: "bar",
name: "报警数", stack: "x",
data: yData1, name: "报警数",
label: { data: yData1,
show: true, label: {
color: '#eee' show: true,
}, color: "#eee",
barGap: "-100%", // 使
// stack:'',
itemStyle: {
// borderRadius: [20, 20, 6, 6],
color: '#15C1AF',
}
}, },
// { barGap: "-100%", // 使
// type: 'bar', // stack:'',
// stack: 'x', itemStyle: {
// name: "", // borderRadius: [20, 20, 6, 6],
// data: yData2, color: "#15C1AF",
// label: { },
// show: true, },
// color: '#eee' // {
// }, // type: 'bar',
// barGap: "-100%", // 使 // stack: 'x',
// // stack:'', // name: "",
// itemStyle: { // data: yData2,
// // borderRadius: [20, 20, 6, 6], // label: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, yData3GradientColor), // show: true,
// } // color: '#eee'
// }, // },
{ // barGap: "-100%", // 使
type: 'line', // // stack:'',
name: '报警率(%)', // itemStyle: {
data: yData3, // // borderRadius: [20, 20, 6, 6],
yAxisIndex: 1, // 1Y 0Y // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, yData3GradientColor),
symbolSize: 10, // // }
// },
{
type: "line",
name: "报警率(%)",
data: yData3,
yAxisIndex: 1, // 1Y 0Y
symbolSize: 10, //
// itemStyle: { // itemStyle: {
// color: '#74DER1', // 线 // color: '#74DER1', // 线
// }, // },
lineStyle: { lineStyle: {
color: '#DE390F', color: "#DE390F",
}, },
label: { label: {
show: true, show: true,
color: '#ddd', color: "#ddd",
formatter: '{c}%' // {c} formatter: "{c}%", // {c}
}, },
} },
] ],
}; };
this.myChart = echarts.init(this.$refs.qdCityMap1) this.myChart = echarts.init(this.$refs.qdCityMap1);
this.myChart.setOption(option); this.myChart.setOption(option);
}, },
},
};
} </script>
}; <style>
</script> .title {
<style> padding-left: 10px;
.title { color: #212121;
padding-left: 10px; font-size: 20px;
color: #212121; margin-bottom: 10px;
font-size: 20px; margin-top: 10px;
margin-bottom: 10px;
margin-top: 10px; background-position-y: 7px;
}
background-position-y: 7px; </style>
}
</style>