<script setup name="earlyWarningAnalysis">
|
import { ref, reactive, onMounted, computed, nextTick, watch, onActivated } from "vue";
|
import { storeToRefs } from "pinia";
|
import { Search, Plus } from "@element-plus/icons-vue";
|
import ycCard from "@/components/ycCard/index.vue";
|
// import addEdit from "./addEdit.vue";
|
import { ElMessage } from "element-plus";
|
import useElement from "@/hooks/useElement.js";
|
import { useUserStore } from '@/store/user';
|
import getQueryString from "@/utils/getQueryString";
|
|
import alarmParams from '@/components/pwrAlarmParams.vue';
|
import lineChart from '@/components/echarts/line-yj.vue';
|
import treeTransfer from 'tree-transfer-vue3';
|
|
|
import useStation from "@/hooks/useStationList.js";
|
const { provice, city, country, stationName, stationId, powerId,
|
proviceList, cityList, countryList, stationList, powerList, isManual,
|
getPowerList,
|
whenLoaded,
|
} = useStation();
|
|
import powerTypes from '@/utils/const/const_powerType.js';
|
import { ExportFile } from '@/utils/exportFile.js';
|
import { useRouter } from "vue-router";
|
const router = useRouter();
|
|
const userStore = useUserStore();
|
const { uid, uname } = storeToRefs(userStore);
|
import moment from 'moment';
|
|
|
import {
|
getPwrtAlmAnalyse,
|
getDevAlmAnalyse,
|
getBattAlmAnalyse,
|
getHisRealInAlm,
|
getAlmSummaryParam,
|
getHisRealWithChage,
|
getAlarmAnalysisCycle,
|
updateAlarmAnalysisCycle,
|
} from "@/api/alarm.js";
|
|
import {
|
getPowerAlmIdType,
|
} from "@/api/station.js";
|
|
|
const { $loading, $message, $confirm } = useElement();
|
const flag = ref(Math.random());
|
const chart0 = ref(null);
|
|
|
const headers0 = [
|
{
|
prop: "fullName",
|
label: "机房名称",
|
width: "220",
|
},
|
{
|
prop: "powerName",
|
label: "电源名称",
|
width: "80",
|
},
|
{
|
prop: "almName",
|
label: "告警名称",
|
width: "160",
|
},
|
{
|
prop: "almLevelStr",
|
label: "告警等级",
|
width: "120",
|
},
|
{
|
prop: "almStartTime",
|
label: "告警开始时间",
|
width: "120",
|
},
|
];
|
|
const headers1 = [
|
{
|
prop: "fullName",
|
label: "机房名称",
|
width: "220",
|
},
|
{
|
prop: "devName",
|
label: "设备名称",
|
width: "80",
|
},
|
{
|
prop: "almName",
|
label: "告警名称",
|
width: "160",
|
},
|
{
|
prop: "almLevelStr",
|
label: "告警等级",
|
width: "120",
|
},
|
{
|
prop: "almStartTime",
|
label: "告警开始时间",
|
width: "120",
|
},
|
];
|
|
const headers2 = [
|
{
|
prop: "fullName",
|
label: "机房名称",
|
width: "220",
|
},
|
{
|
prop: "battgroupName",
|
label: "电池组名称",
|
width: "80",
|
},
|
{
|
prop: "almName",
|
label: "告警名称",
|
width: "160",
|
},
|
{
|
prop: "almLevelStr",
|
label: "告警等级",
|
width: "120",
|
},
|
{
|
prop: "almStartTime",
|
label: "告警开始时间",
|
width: "120",
|
},
|
];
|
|
const pageNum0 = ref(1);
|
const pageSize0 = ref(10);
|
const total0 = ref(0);
|
const timeVisible = ref(false);
|
const dialogTitle = ref("");
|
const datas0 = reactive({
|
tableData: [],
|
rowData: {},
|
});
|
|
const pageNum1 = ref(1);
|
const pageSize1 = ref(10);
|
const total1 = ref(0);
|
const datas1 = reactive({
|
tableData: [],
|
rowData: {},
|
});
|
|
const pageNum2 = ref(1);
|
const pageSize2 = ref(10);
|
const total2 = ref(0);
|
const datas2 = reactive({
|
tableData: [],
|
rowData: {},
|
});
|
|
const currentRow = ref({});
|
|
const alarmTypeList = ref([]);
|
|
const alarmId = ref('');
|
|
|
|
// 电源告警列表
|
function getList0() {
|
let params = {
|
almIdList: alarmId.value ? [alarmId.value] : undefined,
|
provice: provice.value || undefined,
|
city: city.value || undefined,
|
country: country.value || undefined,
|
stationId: stationId.value || undefined,
|
powerId: powerId.value || undefined,
|
almLevel: alarmLevel.value,
|
pageNum: pageNum0.value,
|
pageSize: pageSize0.value,
|
};
|
|
let loading = $loading();
|
getPwrtAlmAnalyse(params).then((res) => {
|
let { code, data, data2 } = res;
|
let list = [];
|
let _total0 = 0;
|
loading.close();
|
if (code && data) {
|
// console.log(data);
|
list = data2.list.map(v => ({
|
...v,
|
almLevelStr: ['', '一级告警', '二级告警', '三级告警', '四级告警'][v.almLevel],
|
|
}));
|
_total0 = data2.total;
|
}
|
datas0.tableData = list;
|
total0.value = _total0;
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
}
|
|
// 设备告警列表
|
function getList1() {
|
let params = {
|
almIdList: alarmId.value ? [alarmId.value] : undefined,
|
provice: provice.value || undefined,
|
city: city.value || undefined,
|
country: country.value || undefined,
|
stationId: stationId.value || undefined,
|
powerId: powerId.value || undefined,
|
almLevel: alarmLevel.value,
|
pageNum: pageNum1.value,
|
pageSize: pageSize1.value,
|
};
|
|
let loading = $loading();
|
getDevAlmAnalyse(params).then((res) => {
|
let { code, data, data2 } = res;
|
let list = [];
|
let _total0 = 0;
|
loading.close();
|
if (code && data) {
|
// console.log(data);
|
list = data2.list.map(v => ({
|
...v,
|
almLevelStr: ['', '一级告警', '二级告警', '三级告警', '四级告警'][v.almLevel],
|
|
}));
|
_total0 = data2.total;
|
}
|
datas1.tableData = list;
|
console.log('list', list, '=============');
|
|
total1.value = _total0;
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
}
|
|
// 电池告警列表
|
function getList2() {
|
let params = {
|
almIdList: alarmId.value ? [alarmId.value] : undefined,
|
provice: provice.value || undefined,
|
city: city.value || undefined,
|
country: country.value || undefined,
|
stationId: stationId.value || undefined,
|
powerId: powerId.value || undefined,
|
almLevel: alarmLevel.value,
|
pageNum: pageNum2.value,
|
pageSize: pageSize2.value,
|
};
|
|
let loading = $loading();
|
getBattAlmAnalyse(params).then((res) => {
|
let { code, data, data2 } = res;
|
let list = [];
|
let _total0 = 0;
|
loading.close();
|
if (code && data) {
|
// console.log(data);
|
list = data2.list.map(v => ({
|
...v,
|
almLevelStr: ['', '一级告警', '二级告警', '三级告警', '四级告警'][v.almLevel],
|
|
}));
|
_total0 = data2.total;
|
}
|
datas2.tableData = list;
|
console.log('list', list, '=============');
|
|
total2.value = _total0;
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
}
|
|
|
async function acTabChange() {
|
await nextTick();
|
|
switch (acTab.value) {
|
case 'power':
|
getList0();
|
break;
|
case 'dev':
|
getList1();
|
break;
|
case 'batt':
|
getList2();
|
break;
|
}
|
}
|
|
const allProps = ref([]);
|
// 查询属性对应关系
|
async function getAllProps() {
|
let res = await getAlmSummaryParam();
|
let { code, data, data2 } = res;
|
let list = [];
|
if (code && data) {
|
list = data2;
|
}
|
allProps.value = list;
|
formatProp(list);
|
}
|
|
// 查询告警类型
|
async function getAlarmType() {
|
let res = await getPowerAlmIdType();
|
let { code, data, data2 } = res;
|
let list = [];
|
if (code && data) {
|
Object.keys(data2).map((key) => {
|
Object.keys(data2[key]).map((key2) => {
|
list.push({
|
value: key2,
|
label: data2[key][key2]
|
});
|
})
|
});
|
}
|
alarmTypeList.value = list;
|
}
|
|
|
const chartRefs = ref({});
|
|
function setComponentRef (prop, el) {
|
if (el) {
|
chartRefs.value[prop] = el;
|
} else {
|
// 组件卸载时移除引用
|
delete chartRefs.value[prop];
|
}
|
};
|
|
const alarmType = ref(0);
|
const acTab = ref('power');
|
const alarmLevel = ref(1);
|
const currAlm = ref({});
|
// 当前告警的告警开始时间
|
const startTime = ref('');
|
const battList = ref([]);
|
const battId = ref('');
|
|
async function view(record) {
|
currAlm.value = record;
|
battList.value = record.binfList;
|
battId.value = acTab.value == 'batt'
|
? record.battgroupId
|
: record.binfList.length
|
? record.binfList[0].battgroupId
|
: 0;
|
|
getRtData();
|
}
|
|
const propInfo = ref({});
|
async function getRtData() {
|
let params = {
|
powerId: currAlm.value.powerId,
|
almId: currAlm.value.almId,
|
startTime: currAlm.value.almStartTime,
|
battgroupId: battId.value,
|
}
|
let res = await getHisRealInAlm(params);
|
let { code, data, data2, data3, data4 } = res;
|
let list = [];
|
let mainProps = '主属性曲线';
|
let subs = [];
|
if (code && data) {
|
let { batt, pwr } = data2;
|
// 取出主属性 和 副属性 及对应的中文名称
|
mainProps = data2[data3.main][0].dataName1;
|
if (data3.main == 'pwr') {
|
// batt 个数表示全部的副属性
|
// pwr 要去掉第一个主属性 剩下的为副属性
|
for(let i = 0, len = data3.batt; i < len; i++) {
|
let idx = i + 1;
|
let prop = batt[0][`dataName${idx}`];
|
subs.push({prop, name: getPropName(prop), data: [], xLabels: [], valueProp: `dataValue${idx}`, from: 'batt'});
|
}
|
for (let j = 0, len = data3.pwr - 1; j < len; j++) {
|
let idx = j + 2;
|
let prop = pwr[0][`dataName${idx}`];
|
subs.push({prop, name: getPropName(prop), data: [], xLabels: [], valueProp: `dataValue${idx}`, from: 'pwr'});
|
}
|
} else {
|
for(let i = 0, len = data3.batt - 1; i < len; i++) {
|
let idx = i + 2;
|
let prop = batt[0][`dataName${idx}`];
|
subs.push({prop, name: getPropName(prop), data: [], xLabels: [], valueProp: `dataValue${idx}`, from: 'batt'});
|
}
|
for (let j = 0, len = data3.pwr; j < len; j++) {
|
let idx = j + 1;
|
let prop = pwr[0][`dataName${idx}`];
|
subs.push({prop, name: getPropName(prop), data: [], xLabels: [], valueProp: `dataValue${idx}`, from: 'pwr'});
|
}
|
}
|
|
// 格式化数据
|
formatData(data2, data3, subs);
|
propInfo.value = data4;
|
|
}
|
|
subProp.value = subs;
|
|
|
startTime.value = currAlm.value.almStartTime;
|
name0.value = getPropName(mainProps);
|
|
nextTick(() => {
|
// 更新图表
|
updateChart();
|
});
|
|
}
|
|
|
function findClosestTime(timeArray, targetTime, format = 'YYYY-MM-DD HH:mm:ss') {
|
if (!timeArray || timeArray.length === 0) return '';
|
|
// 将目标时间转换为Moment对象
|
const targetMoment = moment(targetTime, format);
|
|
|
// 找出所有大于或等于目标时间的元素
|
const timesAfterTarget = timeArray.filter(time =>
|
moment(time, format).isSameOrAfter(targetMoment)
|
);
|
|
// 如果存在这样的元素,返回第一个
|
if (timesAfterTarget.length > 0) {
|
return timesAfterTarget[0];
|
}
|
|
// 若没有找到大于或等于目标时间的元素,则返回整个数组中的最后一个元素(即最接近但小于目标时间的元素)
|
return timeArray[timeArray.length - 1];
|
}
|
|
const mainData = ref([]);
|
// const xLabels0 = ref([]);
|
// const xLabels1 = ref([]);
|
|
function formatData(data2, data3, subs) {
|
let _mainData = [];
|
let recordTimes = [];
|
for (let i = 0, len = data2[data3.main].length; i < len; i++) {
|
let item = data2[data3.main][i];
|
let recordTime = item.recordTime;
|
_mainData.push(item.dataValue1);
|
recordTimes.push(recordTime);
|
|
for (let j = 0, len = subs.length; j < len; j++) {
|
let sub = subs[j];
|
// 取属性对应的index
|
let { prop, from, valueProp } = sub;
|
|
sub.data.push(data2[from][i][valueProp]);
|
sub.xLabels.push(data2[from][i].recordTime);
|
}
|
}
|
mainData.value = {labels: recordTimes, data: _mainData};
|
// xlabels.value = recordTimes;
|
}
|
|
function updateChart() {
|
console.log('xlabels.value, mainData.value', mainData.value, '=============');
|
|
chart0.value.updateChart(mainData.value.labels, mainData.value.data, findClosestTime(mainData.value.labels, startTime.value));
|
subProp.value.forEach((v, i) => {
|
chartRefs.value[v.prop].updateChart(v.xLabels, v.data, findClosestTime(v.xLabels, startTime.value));
|
});
|
}
|
|
|
function exportExcel() {
|
let _headers = headers0.map(v => {
|
let prop = v.prop;
|
let label = v.label;
|
if (prop == 'almIsConfirmed') {
|
prop = 'almIsConfirmedStr';
|
}
|
return {
|
prop,
|
label
|
};
|
});
|
ExportFile(_headers, datas0.tableData, "电源告警");
|
}
|
|
// 展示数据数量
|
function handleSizeChange0(val) {
|
pageSize0.value = val;
|
getList0();
|
}
|
// 翻页
|
function handleCurrentChange0(val) {
|
pageNum0.value = val;
|
getList0();
|
}
|
|
// 展示数据数量
|
function handleSizeChange1(val) {
|
pageSize1.value = val;
|
getList1();
|
}
|
// 翻页
|
function handleCurrentChange1(val) {
|
pageNum1.value = val;
|
getList1();
|
}
|
|
// 展示数据数量
|
function handleSizeChange2(val) {
|
pageSize2.value = val;
|
getList2();
|
}
|
// 翻页
|
function handleCurrentChange2(val) {
|
pageNum2.value = val;
|
getList2();
|
}
|
|
async function exportExcelAll() {
|
// let res = await getPwrAllAlmParam();
|
// let { code, data, data2 } = res;
|
// let list = [];
|
// if (code && data) {
|
// list = data2.map(v => ({
|
// ...v,
|
// almLevelStr: ['', '一级告警', '二级告警', '三级告警', '四级告警'][v.almLevel],
|
// }));
|
// }
|
// let _headers = headers0.map(v => {
|
// let prop = v.prop;
|
// let label = v.label;
|
// return {
|
// prop,
|
// label
|
// };
|
// });
|
// ExportFile(_headers, list, "电源告警-全部");
|
}
|
|
|
// 获取属性对应的中文名称
|
function getPropName(prop) {
|
let name = '';
|
let obj = allProps.value.filter(v => v.fieldName == prop);
|
if (obj.length) {
|
name = obj[0].fieldNameZh;
|
}
|
return name;
|
}
|
|
// 获取类型名称
|
function getTypeName(type) {
|
let name = '';
|
let obj = allTypes.value.filter(v => v.id == type);
|
if (obj.length) {
|
name = obj[0].label;
|
}
|
return name;
|
}
|
|
const name0 = ref('主属性曲线');
|
|
const subProp = ref([]);
|
const timeLong = ref(0);
|
async function getTimeSettings() {
|
let res = await getAlarmAnalysisCycle();
|
let { code, data, data2 } = res;
|
let _time = 30;
|
if (code && data) {
|
_time = data2.paramValue;
|
}
|
timeLong.value = _time;
|
}
|
|
const layout = {
|
gutter: 20,
|
span: 24,
|
};
|
|
const form1 = reactive({
|
time: 0,
|
});
|
|
const validatorTime = (rule, value, callback) => {
|
const reg = /^\d+$/;
|
|
if (reg.test(value)) {
|
if (value < 1 || value > 1440) {
|
callback(new Error('范围1~1440'));
|
} else {
|
callback();
|
}
|
} else {
|
callback(new Error('请输入整数'));
|
}
|
}
|
|
const rules = reactive({
|
time: [{ required: true, message: "不能为空", trigger: ["blur", "change"] },
|
{ validator: validatorTime, trigger: ["blur", "change"] },
|
],
|
});
|
|
|
function setTime() {
|
form1.time = timeLong.value;
|
dialogTitle.value = '设置时间周期';
|
timeVisible.value = true;
|
}
|
|
|
const formRef = ref();
|
async function timeSetOk() {
|
let valid = await formRef.value.validate(() => { });
|
// console.log('valid', valid, '=============');
|
if (!valid) {
|
$message.error("表单验证失败");
|
return false;
|
}
|
|
let loading = $loading();
|
let res = await updateAlarmAnalysisCycle(form1.time);
|
let { code, data } = res;
|
loading.close();
|
if (code && data) {
|
$message.success("设置成功");
|
timeLong.value = form1.time;
|
timeVisible.value = false;
|
} else {
|
$message.error("设置失败");
|
}
|
}
|
|
const transferRef = ref();
|
const fromData = ref([]);
|
const propVisible = ref(false);
|
const toData = ref([]);
|
|
function setProp () {
|
dialogTitle.value = '设置关注属性';
|
propVisible.value = true;
|
nextTick(() => {
|
initSubProp(propInfo.value);
|
});
|
}
|
|
function initSubProp (data) {
|
let {
|
almId,
|
minorField1,
|
minorField1Type,
|
minorField2,
|
minorField2Type,
|
minorField3,
|
minorField3Type,
|
minorField4,
|
minorField4Type,
|
} = data;
|
let arr = [];
|
let obj = {};
|
[1, 2, 3, 4].forEach((v) => {
|
let prop = `minorField${v}`;
|
let type = `${prop}Type`;
|
if (data[prop]) {
|
obj[data[type]] = obj[data[type]] || [];
|
obj[data[type]].push({
|
pid: data[type] + '',
|
id: data[prop],
|
label: getPropName(data[prop]),
|
prop: data[prop],
|
type: data[type],
|
});
|
// arr.push({
|
// pid: data[type] + '',
|
// id: data[prop],
|
// label: getPropName(data[prop]),
|
// prop: data[prop],
|
// type: data[type],
|
// });
|
}
|
});
|
|
Object.keys(obj).forEach((key) => {
|
arr.push({
|
pid: 0,
|
id: key,
|
label: getTypeName(key),
|
children: obj[key],
|
});
|
});
|
|
transferRef.value.removeToSource(false);
|
transferRef.value.addToAims(false);
|
toData.value = arr;
|
}
|
|
function propSetOk() {
|
|
}
|
|
async function add (_fromData,_toData,{ checkedKeys, checkedNodes, harfKeys, harfNodes }) {
|
console.log('fromData,toData,obj', _fromData,_toData, checkedKeys, checkedNodes, harfKeys, harfNodes , '=============');
|
let params = {
|
battgroupId: battId.value,
|
powerId: currAlm.value.powerId,
|
startTime: currAlm.value.almStartTime,
|
}
|
let arr = [];
|
_toData.forEach((v) => {
|
arr.push(...v.children);
|
});
|
let len = arr.length;
|
|
if (len > 4) {
|
$message.error('最多设置4个属性');
|
console.log('toData', _toData, toData, '=============');
|
toData.value = toData.value.map(v => ({
|
...v,
|
children: v.children.filter(vv => !checkedKeys.includes(vv.id))
|
}));
|
return false;
|
}
|
let i = 0;
|
_toData.forEach((item) => {
|
item.children.forEach((v) => {
|
i++;
|
params[`dataName${i}`] = v.id;
|
params[`dataType${i}`] = v.pid;
|
|
});
|
});
|
console.log('params', params, '=============');
|
|
let res = await getHisRealWithChage(params);
|
|
|
}
|
|
function remove(fromData,toData,obj) {
|
console.log('fromData,toData,obj', fromData,toData,obj, '=============');
|
|
}
|
|
const allTypes = ref([]);
|
|
function formatProp(data) {
|
let obj = {};
|
let res = [];
|
let types = [];
|
data.forEach((v) => {
|
obj[v.fieldType] = obj[v.fieldType] || [];
|
obj[v.fieldType].push(v);
|
|
});
|
Object.keys(obj).forEach((key) => {
|
types.push({
|
id: key,
|
label: obj[key][0].fieldTypeName
|
});
|
res.push({
|
id: key,
|
pid: 0,
|
label: obj[key][0].fieldTypeName,
|
children: obj[key].map(vv => {
|
return {
|
...vv,
|
id: vv.fieldName,
|
label: vv.fieldNameZh,
|
pid: key,
|
}
|
})
|
})
|
});
|
fromData.value = res;
|
allTypes.value = types;
|
return res;
|
}
|
|
onMounted(async () => {
|
await getAlarmType();
|
getAllProps();
|
getTimeSettings();
|
getList0();
|
|
});
|
|
// onActivated(async () => {
|
// let pageFlag = getQueryString("pageFlag");
|
// // console.log('pageFlag', pageFlag, flag.value, '=============');
|
// await nextTick();
|
// await whenLoaded();
|
|
// if (pageFlag && pageFlag != flag.value) {
|
// // let provice, city, country, stationName, battId;
|
|
// if (getQueryString('stationId')) {
|
// let statId = getQueryString('stationId');
|
// let stat = stationList.value.find(v => v.stationId == statId);
|
// if (stat) {
|
// isManual.value = true;
|
// stationName.value = stat.stationName;
|
// await getPowerList();
|
// }
|
// }
|
// if (getQueryString('powerId')) {
|
// powerId.value = getQueryString('powerId') * 1;
|
// // console.log('battId', battId.value, battList.value, '=============');
|
// }
|
// getList();
|
// flag.value = pageFlag;
|
// }
|
// });
|
</script>
|
|
<template>
|
<div class="page-wrapper">
|
<!-- <div class="page-header">
|
</div> -->
|
<div class="page-content">
|
<el-tabs
|
tab-position="left"
|
v-model="acTab"
|
@tab-change="acTabChange"
|
type="card"
|
class="main-tabs"
|
>
|
<el-tab-pane name="power" class="tab-pane" label="电源告警">
|
<div class="page-content-wrapper">
|
<div class="page-content-tools page-filter">
|
<div class="grid-container" :style="{'--counter': 9}">
|
<div class="grid-item">
|
<div class="label">省</div>
|
<div class="value">
|
<el-select
|
v-model="provice"
|
size="small"
|
clearable
|
placeholder="请选择省"
|
>
|
<el-option
|
v-for="item in proviceList"
|
:key="'l0_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">市</div>
|
<div class="value">
|
<el-select
|
v-model="city"
|
size="small"
|
clearable
|
placeholder="请选择市"
|
>
|
<el-option
|
v-for="item in cityList"
|
:key="'l1_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">区县</div>
|
<div class="value">
|
<el-select
|
v-model="country"
|
clearable
|
size="small"
|
placeholder="请选择区县"
|
>
|
<el-option
|
v-for="item in countryList"
|
:key="'l2_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">站点</div>
|
<div class="value">
|
<el-select
|
v-model="stationName"
|
clearable
|
size="small"
|
placeholder="请选择站点"
|
>
|
<el-option
|
v-for="item in stationList"
|
:key="'l3_' + item.stationId"
|
:label="item.stationName"
|
:value="item.stationName"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">电源名称</div>
|
<div class="value">
|
<el-select
|
v-model="powerId"
|
clearable
|
size="small"
|
placeholder="请选择电源"
|
>
|
<el-option
|
v-for="item in powerList"
|
:key="'l4_' + item.powerId"
|
:label="`${item.stationName}-${item.powerName}`"
|
:value="item.powerId"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">告警名称</div>
|
<div class="value">
|
<el-select
|
v-model="alarmId"
|
size="small"
|
clearable
|
filterable
|
placeholder="请选择告警名称"
|
>
|
<el-option
|
v-for="item in alarmTypeList"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<el-radio-group
|
v-model="alarmLevel"
|
size="small"
|
style="grid-column: span 6;"
|
>
|
<el-radio-button :value="1">一级告警</el-radio-button>
|
<el-radio-button :value="2">二级告警</el-radio-button>
|
<el-radio-button :value="3">三级告警</el-radio-button>
|
<el-radio-button :value="4">四级告警</el-radio-button>
|
</el-radio-group>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-table">
|
<div class="pos-rel">
|
<div class="pos-abs">
|
<el-table
|
class="yc-table"
|
stripe
|
height="100%"
|
size="small"
|
:data="datas0.tableData"
|
style="width: 100%"
|
>
|
<el-table-column
|
type="index"
|
fixed="left"
|
label="序号"
|
width="60"
|
></el-table-column>
|
<el-table-column
|
v-for="header in headers0"
|
:key="header.prop"
|
:prop="header.prop"
|
:label="header.label"
|
:min-width="header.width"
|
align="center"
|
>
|
<template #default="scope">
|
<template v-if="header.prop == 'almIsConfirmed'">
|
<el-checkbox
|
disabled
|
:checked="scope.row[header.prop] == 1"
|
></el-checkbox>
|
</template>
|
<template v-else>
|
{{ scope.row[header.prop] || '--' }}
|
</template>
|
</template>
|
</el-table-column>
|
<el-table-column
|
label="操作"
|
fixed="right"
|
width="120"
|
align="center"
|
>
|
<template #default="scope">
|
<el-button
|
type="warning"
|
size="small"
|
@click="view(scope.row)"
|
>查看详情</el-button
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-page">
|
<div class="page-tool">
|
<el-button
|
type="primary"
|
round
|
size="small"
|
@click="getList0"
|
:icon="Search"
|
>查询</el-button
|
>
|
</div>
|
<div class="el-page-container">
|
<el-pagination
|
v-model:current-page="pageNum0"
|
v-model:page-size="pageSize0"
|
:page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]"
|
size="small"
|
layout="total, sizes, prev, pager, next, jumper"
|
:total="total0"
|
@size-change="handleSizeChange0"
|
@current-change="handleCurrentChange0"
|
/>
|
</div>
|
<div class="page-tool">
|
<!-- <el-button type="primary" round size="small" @click="exportExcel"
|
>导出</el-button
|
>
|
<el-button type="primary" round size="small" @click="exportExcelAll"
|
>导出全部</el-button
|
> -->
|
</div>
|
</div>
|
</div>
|
</el-tab-pane>
|
<el-tab-pane name="dev" class="tab-pane" label="设备告警">
|
<div class="page-content-wrapper">
|
<div class="page-content-tools page-filter">
|
<div class="grid-container" :style="{'--counter': 9}">
|
<div class="grid-item">
|
<div class="label">省</div>
|
<div class="value">
|
<el-select
|
v-model="provice"
|
size="small"
|
clearable
|
placeholder="请选择省"
|
>
|
<el-option
|
v-for="item in proviceList"
|
:key="'l0_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">市</div>
|
<div class="value">
|
<el-select
|
v-model="city"
|
size="small"
|
clearable
|
placeholder="请选择市"
|
>
|
<el-option
|
v-for="item in cityList"
|
:key="'l1_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">区县</div>
|
<div class="value">
|
<el-select
|
v-model="country"
|
clearable
|
size="small"
|
placeholder="请选择区县"
|
>
|
<el-option
|
v-for="item in countryList"
|
:key="'l2_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">站点</div>
|
<div class="value">
|
<el-select
|
v-model="stationName"
|
clearable
|
size="small"
|
placeholder="请选择站点"
|
>
|
<el-option
|
v-for="item in stationList"
|
:key="'l3_' + item.stationId"
|
:label="item.stationName"
|
:value="item.stationName"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">电源名称</div>
|
<div class="value">
|
<el-select
|
v-model="powerId"
|
clearable
|
size="small"
|
placeholder="请选择电源"
|
>
|
<el-option
|
v-for="item in powerList"
|
:key="'l4_' + item.powerId"
|
:label="`${item.stationName}-${item.powerName}`"
|
:value="item.powerId"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">告警名称</div>
|
<div class="value">
|
<el-select
|
v-model="alarmId"
|
size="small"
|
clearable
|
filterable
|
placeholder="请选择告警名称"
|
>
|
<el-option
|
v-for="item in alarmTypeList"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<el-radio-group
|
v-model="alarmLevel"
|
size="small"
|
style="grid-column: span 6;"
|
>
|
<el-radio-button :value="1">一级告警</el-radio-button>
|
<el-radio-button :value="2">二级告警</el-radio-button>
|
<el-radio-button :value="3">三级告警</el-radio-button>
|
<el-radio-button :value="4">四级告警</el-radio-button>
|
</el-radio-group>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-table">
|
<div class="pos-rel">
|
<div class="pos-abs">
|
<el-table
|
class="yc-table"
|
stripe
|
height="100%"
|
size="small"
|
:data="datas1.tableData"
|
style="width: 100%"
|
>
|
<el-table-column
|
type="index"
|
fixed="left"
|
label="序号"
|
width="60"
|
></el-table-column>
|
<el-table-column
|
v-for="header in headers1"
|
:key="header.prop"
|
:prop="header.prop"
|
:label="header.label"
|
:min-width="header.width"
|
align="center"
|
>
|
<template #default="scope">
|
<template v-if="header.prop == 'almIsConfirmed'">
|
<el-checkbox
|
disabled
|
:checked="scope.row[header.prop] == 1"
|
></el-checkbox>
|
</template>
|
<template v-else>
|
{{ scope.row[header.prop] || '--' }}
|
</template>
|
</template>
|
</el-table-column>
|
<el-table-column
|
label="操作"
|
fixed="right"
|
width="120"
|
align="center"
|
>
|
<template #default="scope">
|
<el-button
|
type="warning"
|
size="small"
|
@click="view(scope.row)"
|
>查看详情</el-button
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-page">
|
<div class="page-tool">
|
<el-button
|
type="primary"
|
round
|
size="small"
|
@click="getList1"
|
:icon="Search"
|
>查询</el-button
|
>
|
</div>
|
<div class="el-page-container">
|
<el-pagination
|
v-model:current-page="pageNum1"
|
v-model:page-size="pageSize1"
|
:page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]"
|
size="small"
|
layout="total, sizes, prev, pager, next, jumper"
|
:total="total1"
|
@size-change="handleSizeChange1"
|
@current-change="handleCurrentChange1"
|
/>
|
</div>
|
<div class="page-tool">
|
<!-- <el-button type="primary" round size="small" @click="exportExcel"
|
>导出</el-button
|
>
|
<el-button type="primary" round size="small" @click="exportExcelAll"
|
>导出全部</el-button
|
> -->
|
</div>
|
</div>
|
</div>
|
</el-tab-pane>
|
<el-tab-pane name="batt" class="tab-pane" label="电池告警">
|
<div class="page-content-wrapper">
|
<div class="page-content-tools page-filter">
|
<div class="grid-container" :style="{'--counter': 9}">
|
<div class="grid-item">
|
<div class="label">省</div>
|
<div class="value">
|
<el-select
|
v-model="provice"
|
size="small"
|
clearable
|
placeholder="请选择省"
|
>
|
<el-option
|
v-for="item in proviceList"
|
:key="'l0_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">市</div>
|
<div class="value">
|
<el-select
|
v-model="city"
|
size="small"
|
clearable
|
placeholder="请选择市"
|
>
|
<el-option
|
v-for="item in cityList"
|
:key="'l1_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">区县</div>
|
<div class="value">
|
<el-select
|
v-model="country"
|
clearable
|
size="small"
|
placeholder="请选择区县"
|
>
|
<el-option
|
v-for="item in countryList"
|
:key="'l2_' + item"
|
:label="item"
|
:value="item"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">站点</div>
|
<div class="value">
|
<el-select
|
v-model="stationName"
|
clearable
|
size="small"
|
placeholder="请选择站点"
|
>
|
<el-option
|
v-for="item in stationList"
|
:key="'l3_' + item.stationId"
|
:label="item.stationName"
|
:value="item.stationName"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">电源名称</div>
|
<div class="value">
|
<el-select
|
v-model="powerId"
|
clearable
|
size="small"
|
placeholder="请选择电源"
|
>
|
<el-option
|
v-for="item in powerList"
|
:key="'l4_' + item.powerId"
|
:label="`${item.stationName}-${item.powerName}`"
|
:value="item.powerId"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<div class="label">告警名称</div>
|
<div class="value">
|
<el-select
|
v-model="alarmId"
|
size="small"
|
clearable
|
filterable
|
placeholder="请选择告警名称"
|
>
|
<el-option
|
v-for="item in alarmTypeList"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="grid-item">
|
<el-radio-group
|
v-model="alarmLevel"
|
size="small"
|
style="grid-column: span 6;"
|
>
|
<el-radio-button :value="1">一级告警</el-radio-button>
|
<el-radio-button :value="2">二级告警</el-radio-button>
|
<el-radio-button :value="3">三级告警</el-radio-button>
|
<el-radio-button :value="4">四级告警</el-radio-button>
|
</el-radio-group>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-table">
|
<div class="pos-rel">
|
<div class="pos-abs">
|
<el-table
|
class="yc-table"
|
stripe
|
height="100%"
|
size="small"
|
:data="datas2.tableData"
|
style="width: 100%"
|
>
|
<el-table-column
|
type="index"
|
fixed="left"
|
label="序号"
|
width="60"
|
></el-table-column>
|
<el-table-column
|
v-for="header in headers2"
|
:key="header.prop"
|
:prop="header.prop"
|
:label="header.label"
|
:min-width="header.width"
|
align="center"
|
>
|
<template #default="scope">
|
<template v-if="header.prop == 'almIsConfirmed'">
|
<el-checkbox
|
disabled
|
:checked="scope.row[header.prop] == 1"
|
></el-checkbox>
|
</template>
|
<template v-else>
|
{{ scope.row[header.prop] || '--' }}
|
</template>
|
</template>
|
</el-table-column>
|
<el-table-column
|
label="操作"
|
fixed="right"
|
width="120"
|
align="center"
|
>
|
<template #default="scope">
|
<el-button
|
type="warning"
|
size="small"
|
@click="view(scope.row)"
|
>查看详情</el-button
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-page">
|
<div class="page-tool">
|
<el-button
|
type="primary"
|
round
|
size="small"
|
@click="getList2"
|
:icon="Search"
|
>查询</el-button
|
>
|
</div>
|
<div class="el-page-container">
|
<el-pagination
|
v-model:current-page="pageNum2"
|
v-model:page-size="pageSize2"
|
:page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]"
|
size="small"
|
layout="total, sizes, prev, pager, next, jumper"
|
:total="total2"
|
@size-change="handleSizeChange2"
|
@current-change="handleCurrentChange2"
|
/>
|
</div>
|
<div class="page-tool">
|
<!-- <el-button type="primary" round size="small" @click="exportExcel"
|
>导出</el-button
|
>
|
<el-button type="primary" round size="small" @click="exportExcelAll"
|
>导出全部</el-button
|
> -->
|
</div>
|
</div>
|
</div>
|
</el-tab-pane>
|
</el-tabs>
|
</div>
|
<div class="page-footer">
|
<div class="left">
|
<card :title="name0">
|
<line-chart ref="chart0"></line-chart>
|
</card>
|
</div>
|
<div class="right">
|
<div class="btn-grp">
|
<div class="item">
|
<div class="label">选择电池组</div>
|
<div class="value">
|
<el-select
|
v-model="battId"
|
size="small"
|
clearable
|
@change="getRtData"
|
placeholder="请选择电池组"
|
>
|
<el-option
|
v-for="item in battList"
|
:key="'l5_' + item.battgroupId"
|
:label="`${item.devName}-${item.battgroupName}`"
|
:value="item.battgroupId"
|
>
|
</el-option>
|
</el-select>
|
</div>
|
</div>
|
<div class="item">
|
<div class="label">设置时间周期(分钟)</div>
|
<div class="value">
|
<div class="input">{{ timeLong }}</div>
|
</div>
|
<el-button type="primary" size="small" @click="setTime"
|
>设置</el-button
|
>
|
</div>
|
<div class="item">
|
<el-button type="primary" size="small" @click="setProp"
|
>关注属性</el-button
|
>
|
</div>
|
</div>
|
<!-- 一个就分一块 两个就分两列一行 两个以上就两列两行 -->
|
<div
|
:class="['contain', { 'grid1': subProp.length == 1, 'grid2': subProp.length == 2, 'grid3': subProp.length > 2}]"
|
>
|
<template v-for="(sub, idx) in subProp" :key="'sub_' + idx">
|
<card :title="sub.name">
|
<line-chart
|
:ref="(el) => setComponentRef(sub.prop, el)"
|
></line-chart>
|
</card>
|
</template>
|
</div>
|
</div>
|
</div>
|
<!-- 弹窗 -->
|
<el-dialog
|
:title="dialogTitle"
|
v-model="timeVisible"
|
top="0"
|
draggable
|
:close-on-click-modal="false"
|
class="dialog-center"
|
width="460px"
|
center
|
>
|
<el-form ref="formRef" :model="form1" :rules="rules" label-width="10em">
|
<el-row :gutter="layout.gutter">
|
<el-col :span="layout.span">
|
<el-form-item label="时间周期(分钟)" prop="time">
|
<el-input v-model="form1.time"></el-input>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="timeVisible = false">取 消</el-button>
|
<el-button type="primary" @click="timeSetOk">确 定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<!-- 弹窗 -->
|
<el-dialog
|
:title="dialogTitle"
|
v-model="propVisible"
|
top="0"
|
draggable
|
:close-on-click-modal="false"
|
class="dialog-center transfer-dialog"
|
width="940px"
|
center
|
>
|
<tree-transfer
|
v-model:fromData="fromData"
|
:titleList="['未关注属性', '已关注属性']"
|
ref="transferRef"
|
:showBtnTxt="true"
|
:btnTitleList="['添加', '移除']"
|
rootPid="0"
|
v-model:toData="toData"
|
:defaultProps="{label:'label', id: 'id', parentId: 'pid', children: 'children'}"
|
@add="add"
|
@remove="remove"
|
>
|
</tree-transfer>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="propVisible = false">取 消</el-button>
|
<el-button type="primary" @click="propSetOk">确 定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<style scoped lang="less">
|
.page-wrapper {
|
display: flex;
|
flex-direction: column;
|
padding: 8px;
|
height: 100%;
|
|
.page-content {
|
flex: 1;
|
.main-tabs {
|
height: 100%;
|
:deep(.el-tabs__header) {
|
|
border-bottom: 0 none;
|
}
|
:deep(.el-tabs__header) {
|
.el-tabs__nav {
|
border: 0 none;
|
}
|
.el-tabs__item {
|
background: #21487e;
|
color: #fff;
|
border: 0 none;
|
&.is-active {
|
background: #409EFF;
|
}
|
}
|
}
|
}
|
}
|
.page-footer {
|
flex: 2;
|
display: flex;
|
.left {
|
flex: 1;
|
}
|
.right {
|
flex: 1.6;
|
margin-left: 10px;
|
display: flex;
|
flex-direction: column;
|
.btn-grp {
|
display: flex;
|
justify-content: flex-end;
|
padding: 8px;
|
}
|
.contain {
|
flex: 1;
|
display: grid;
|
grid-column-gap: 8px;
|
grid-row-gap: 8px;
|
&.grid1 {
|
grid-template-columns: repeat(1, 1fr);
|
}
|
&.grid2 {
|
grid-template-columns: repeat(2, 1fr);
|
grid-template-rows: repeat(1, 1fr);
|
}
|
&.grid3 {
|
grid-template-columns: repeat(2, 1fr);
|
grid-template-rows: repeat(2, 1fr);
|
}
|
}
|
}
|
}
|
.tab-pane {
|
height: 100%;
|
}
|
}
|
|
.page-content-wrapper {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
|
.page-content-tools {
|
padding-bottom: 8px;
|
|
.flex-row {
|
display: flex;
|
align-items: center;
|
|
:deep(.el-checkbox) {
|
color: #fff;
|
}
|
|
.group {
|
margin-left: 30px;
|
}
|
}
|
}
|
|
.page-content-table {
|
// border-top: 1px solid var(--border-light-color);
|
box-sizing: border-box;
|
flex: 1;
|
margin-left: 26px;
|
margin-right: 26px;
|
}
|
|
.page-content-page {
|
padding: 8px 8px 0 8px;
|
text-align: center;
|
|
.el-page-container {
|
display: inline-block;
|
padding: 0 16px;
|
}
|
|
.page-tool {
|
display: inline-block;
|
}
|
}
|
}
|
|
.hdw-card-container {
|
width: 240px;
|
padding-right: 8px;
|
height: 100%;
|
}
|
|
.pos-rel {
|
position: relative;
|
width: 100%;
|
height: 100%;
|
|
.pos-abs {
|
position: absolute;
|
top: 0;
|
bottom: 0;
|
left: 0;
|
right: 0;
|
width: 100%;
|
height: 100%;
|
}
|
}
|
.btn-grp {
|
.item {
|
font-size: 14px;
|
color: #439bc4;
|
margin-left: 12px;
|
display: flex;
|
align-items: center;
|
.label {
|
&::after {
|
content: ':';
|
}
|
}
|
.value {
|
margin-left: 8px;
|
margin-right: 8px;
|
:deep(.el-select) {
|
width: 120px;
|
}
|
}
|
.input {
|
display: flex;
|
align-items: center;
|
padding-left: 6px;
|
color: #fff;
|
background: #439bc4;
|
border-radius: 4px;
|
min-width: 86px;
|
height: 28px;
|
}
|
}
|
}
|
|
.item-setting {
|
display: flex;
|
align-items: center;
|
.label {
|
&::after {
|
content: ':';
|
}
|
}
|
.value {
|
margin-left: 8px;
|
}
|
}
|
.dialog-footer {
|
display: flex;
|
justify-content: flex-end;
|
}
|
|
.tools-filter {
|
display: inline-block;
|
font-size: 14px;
|
|
.tools-filter-item {
|
display: inline-block;
|
margin-right: 8px;
|
|
.filter-label {
|
display: inline-block;
|
}
|
|
.filter-content {
|
display: inline-block;
|
}
|
}
|
}
|
:deep(.transfer-dialog) {
|
.el-tree {
|
max-height: 500px;
|
overflow-y: auto;
|
}
|
}
|
</style>
|