楼宇能效监测控制系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

779 lines
23 KiB

<template>
<div class="big-machine" v-loading="listLoading">
<div class="condition">
<div class="condition-left">
<el-select
style="margin-right: 0.1rem"
v-model="building"
placeholder="请选择楼栋"
clearable
>
<el-option
v-for="(item, index) in builds"
:key="index"
:label="item.label"
:value="item.id"
/>
</el-select>
<el-date-picker
v-model="dayDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期"
>
</el-date-picker>
<div class="success-btn" style="margin: 0 0.12rem">
<el-button type="success" @click="findData">查询</el-button>
</div>
<div class="warning-btn">
<el-button type="warning" @click="exportData">导出</el-button>
</div>
</div>
</div>
<div class="charts" ref="chart_ref"></div>
<el-table
:data="postList"
stripe
:cell-style="tableRowStyle"
@row-click="handlerow"
highlight-current-row
height="500"
>
<el-table-column label="楼栋名称" align="center" prop="dateAndWeek" />
<el-table-column label="0点" align="center" prop="maxTemp" />
<el-table-column label="2点" align="center" prop="minTemp" />
<el-table-column label="6点" align="center" prop="minTemp" />
<el-table-column label="8点" align="center" prop="minTemp" />
<el-table-column label="11点" align="center" prop="minTemp" />
<el-table-column label="13点" align="center" prop="minTemp" />
<el-table-column label="14点" align="center" prop="minTemp" />
<el-table-column label="15点" align="center" prop="minTemp" />
<el-table-column label="16点" align="center" prop="minTemp" />
<el-table-column label="17点" align="center" prop="minTemp" />
<el-table-column label="18点" align="center" prop="minTemp" />
<el-table-column label="19点" align="center" prop="minTemp" />
<el-table-column label="20点" align="center" prop="minTemp" />
<el-table-column label="21点" align="center" prop="minTemp" />
<el-table-column label="22点" align="center" prop="minTemp" />
<el-table-column label="23点" align="center" prop="minTemp" />
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script>
import { formatDay } from "@/utils/datetime";
import { energyAnalyze, analyzeExport } from "@/api/centerairC/energyManage";
import { spaceTree } from "@/api/region";
import * as echarts from "echarts";
export default {
data() {
return {
listLoading: false,
dayDate: [], //日值
dialogVisible: false,
building: "", //选中的楼栋
builds: [], //楼栋列表
// 遮罩层
loading: false,
// 总条数
total: 0,
// 表格数据
postList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
startTime: "",
endTime: "",
},
brokenInstanc: null,
brokenOption: {},
brokenData1: [],
brokenTime: [],
};
},
created() {
// 在组件创建完成后,设置默认值
},
mounted() {
this.initializeTimeDate();
this.getBuildList();
this.getList();
this.initChart();
window.addEventListener("resize", this.screenAdapter);
this.screenAdapter();
this.getChartData();
},
destroyed() {
//取消监听器
window.removeEventListener("resize", this.screenAdapter);
},
methods: {
/** 查询楼栋 */
getBuildList() {
spaceTree().then((res) => {
if (res.code == 200) {
// 只需要保留热水的系统
console.log("楼栋返回值", res);
let newRes = { ...res };
if (newRes.data && newRes.data[0] && newRes.data[0].children) {
newRes.data[0].children = newRes.data[0].children.filter((item) => {
// 假设子项有一个 label属性,用于检查是否包含 "热水"
return item.label && item.label.includes("热水");
});
}
// 指定要保留的最大层级(从 1 开始计数),这里假设指定为第 4 级
const targetLevel = 4;
// 从 data[0] 开始处理,当前层级为 1
if (newRes.data[0]) {
this.removeChildrenAfterLevel(newRes.data[0], 1, targetLevel);
}
this.builds = newRes.data[0].children[0].children[0].children;
// console.log("筛选后的新结果", this.builds);
this.building = this.builds[0].id;
this.getList();
}
});
},
// 递归函数,用于去除指定层级往后的 children 数据
removeChildrenAfterLevel(obj, currentLevel, targetLevel) {
if (currentLevel >= targetLevel) {
// 当达到指定层级时,将 children 属性置为空数组
obj.children = [];
return;
}
if (obj.children && obj.children.length > 0) {
// 若存在 children 数组,则递归处理每个子项
for (let i = 0; i < obj.children.length; i++) {
this.removeChildrenAfterLevel(
obj.children[i],
currentLevel + 1,
targetLevel
);
}
}
},
// 初始化时间
initializeTimeDate() {
this.dayDate = formatDay(new Date()); // 更新
},
// 查询
findData() {
this.getList();
},
// 显示消息的函数
showMessage(message, type) {
this.$message({
message: message,
type: type,
});
},
//请求数据
getList() {
let data = {
startTime: this.dayDate,
endTime: this.dayDate,
building: this.building,
};
console.log("查询数据参数", data);
this.listLoading = true;
// 请求数据
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false;
}, 1.0 * 1000);
},
//
getChartData() {
this.queryParams.pageNum = 0;
console.log("图表参数", this.queryParams);
this.brokenData1 = [30, 40, 29];
this.brokenTime = ["3", "4", "5"];
this.brokenOption.series[0].data = this.brokenData1;
this.brokenOption.series[0].itemStyle.color = "#1f8dee";
this.brokenOption.series[0].areaStyle.color.colorStops = [
{
offset: 0,
color: "rgba(31, 141, 238, 0.3)", // 0% 处的颜色
},
{
offset: 0.8,
color: "rgba(31, 141, 238,0)", // 100% 处的颜色
},
];
// 动态设置 tooltip 格式化函数
this.brokenOption.tooltip = {
trigger: "axis",
formatter: function (params) {
// 获取当前数据点信息
const data = params[0];
const month = data.name;
const value = data.value;
return `${month}<br/>温度: ${value} ℃`;
},
};
this.brokenOption.xAxis.data = this.brokenTime;
this.brokenInstanc.setOption(this.brokenOption);
// weatherTempData(this.queryParams).then((response) => {
// console.log("处理值然后渲染");
// if (response.rows.length > 0) {
// let data = response.rows;
// let timeValue = [];
// let hightValue = [];
// let lowValue = [];
// data.forEach((element) => {
// timeValue.push(element.weatherDate);
// hightValue.push(element.maxTemp);
// lowValue.push(element.minTemp);
// });
// let adapterOption = {};
// adapterOption = {
// xAxis: {
// data: timeValue,
// },
// series: [
// {
// data: hightValue,
// //折线颜色
// itemStyle: {
// color: "rgb(18, 126, 226)", //折线的颜色
// },
// lineStyle: {
// color: "rgb(18, 126, 226)", //折线点的颜色
// },
// },
// {
// data: lowValue,
// //折线颜色
// itemStyle: {
// color: "rgb(250, 169, 19)", //折线的颜色
// },
// lineStyle: {
// color: "rgb(250, 169, 19)", //折线点的颜色
// },
// },
// ],
// };
// //记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关
// this.brokenInstanc.setOption(adapterOption);
// //手动的调用图标对象的resize才能产生效果
// this.brokenInstanc.resize();
// } else {
// let adapterOption = {};
// adapterOption = {
// xAxis: {
// data: [],
// },
// series: [
// {
// data: [],
// },
// {
// data: [],
// },
// ],
// };
// //记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关
// this.brokenInstanc.setOption(adapterOption);
// //手动的调用图标对象的resize才能产生效果
// this.brokenInstanc.resize();
// }
// });
},
//查询单个热泵状态 点击表格的某一行
handlerow(row, event, column) {
// console.log("点击的行数据----", row)
if (row) {
const obj = Object.assign({}, row);
// 先截取掉不需要的对象属性和值
delete obj.buildingID;
delete obj.curDate;
delete obj.pumpID;
delete obj.pumpName;
delete obj.buildingName;
//定义一个新数组
let newObj = {};
for (let key in obj) {
if (obj[key]) {
newObj[key] = obj[key];
}
}
// console.log("不含空的数组对象", newObj);
// 在返回的新的对象中,取出对象的所有key值返回新数组
// Object.setPrototypeOf(this.newObj);
// let data7 = Object.keys(newObj);
// console.log("不含空的x轴数据", data7);
const keysArr = Object.keys(newObj); // 获取对象所有属性名的数组
this.brokenTime = [];
keysArr.forEach((item) => {
if (item) {
this.brokenTime.push(item.split("temp").join("") + ":00");
}
});
const valuesArr = keysArr.map((key) => newObj[key]); // 将属性名对应的值提取出来存入一个新的数组中
// console.log("", valuesArr);
// console.log("坐标", this.brokenTime);
this.brokenData1 = valuesArr;
const adapterOption = {
xAxis: {
data: this.brokenTime,
},
series: [
{
name: "温度",
data: this.brokenData1,
itemStyle: {
color: "#1f8dee",
},
areaStyle: {
color: {
colorStops: [
{
offset: 0,
color: "rgba(31, 141, 238, 0.3)", // 0% 处的颜色
},
{
offset: 0.8,
color: "rgba(31, 141, 238,0)", // 100% 处的颜色
},
],
},
},
},
],
};
//记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关
this.brokenInstanc.setOption(adapterOption);
//手动的调用图标对象的resize才能产生效果
this.brokenInstanc.resize();
} else {
const adapterOption = {
xAxis: {
data: [],
},
series: [
{
name: "温度",
data: [],
},
],
};
//记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关
this.brokenInstanc.setOption(adapterOption);
//手动的调用图标对象的resize才能产生效果
this.brokenInstanc.resize();
}
},
// 导出
exportData() {
let data = {
timeType: this.dateType,
startTime: this.queryParams.startTime,
endTime: this.endTime,
building: this.building,
};
console.log("导出数据参数", data);
analyzeExport(data).then((res) => {
console.log("导出返回", res);
if (res) {
// 请求的结果就是文件
// 创建一个blob URL,用于生成下载链接
const url = window.URL.createObjectURL(new Blob([res]));
// 创建一个<a>元素,并设置其href和download属性
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "机房能耗报表.xls"); // 设置下载的文件名
// 模拟点击下载链接
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 释放blob URL资源
window.URL.revokeObjectURL(url);
this.$message({
type: "success",
message: "导出成功!",
});
} else {
this.$message.error("导出失败!");
}
});
// .catch((err) => {
// this.$message.error('导出失败!');
// })
},
tableRowStyle({ row, column, rowIndex, columnIndex }) {
// 修改颜色
if (columnIndex === 1) {
return "color: #fd1e00;!important;text-align:center";
}
if (columnIndex === 2) {
return "color: #3390ff;!important;text-align:center";
}
if (columnIndex === 4) {
return "color: #75d148;!important;text-align:center";
}
// return "text-align:center";
},
// 折线图自适应+ 根据按钮切换图例仅限一条且不可点击+ 折线图数据
screenAdapter() {
//自己定义的比较合适的适配大小,2.6 mes_ref是图表盒子
const titleFontSize = this.$refs.chart_ref.offsetWidth / 130;
//因为option可以多次配置的,所以这里的option只需要写 需要配置大小的相关数据
const adapterOption = {};
//记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关
this.brokenInstanc.setOption(adapterOption);
//手动的调用图标对象的resize才能产生效果
this.brokenInstanc.resize();
},
//初始化chartInstance对象
initChart() {
this.brokenInstanc = echarts.init(this.$refs.chart_ref);
this.brokenOption = {
tooltip: {
trigger: "axis",
},
legend: {
show: false,
selectedMode: false, // 是否允许图例进行点击
icon: "cricle", //图例样式,可以自行查看样式选择
//图例文字颜色
textStyle: {
color: "#ffff",
fontSize: 16, //这里改字体大小
},
// left: "73%",
left: "66%",
top: "0",
//图例距离饼图的距离
itemGap: 5,
itemWidth: 10,
itemHeight: 5,
},
grid: {
top: "4%",
left: "3%",
right: "4%",
bottom: "5%",
containLabel: true,
},
xAxis: {
type: "category",
//设置为true代表离零刻度间隔一段距离
boundaryGap: true,
// 修饰刻度标签的颜色即x坐标数据
axisLabel: {
// interval: 0, //强制显示所有x轴数据
// rotate: 30, //x轴坐标字体倾斜30度
color: "rgba(255, 255, 255, 1)",
fontSize: 14, // 设置字体大小,可根据需要调整
},
axisTick: {
show: false, // 不显示坐标轴刻度线
},
// x坐标轴的颜色
axisLine: {
show: true,
lineStyle: {
color: "#365576",
},
},
splitLine: {
lineStyle: {
color: "#e2e6f0",
},
}, //x轴分割线
data: this.brokenTime,
},
yAxis: {
min: 0,
// max:20,
// // // min:'dataMin',
// // // max:'dataMax',
// name: "kwh", // 第一个 y 轴的单位描述
// 设置 name 的样式
nameTextStyle: {
color: "rgba(255, 255, 255, 1)",
fontSize: 12,
},
miniInterval: 5,
type: "value",
// 修饰刻度标签的颜色即y坐标数据
axisLabel: {
color: "rgba(255, 255, 255, 1)",
},
// 显示y坐标轴
axisLine: {
show: true,
lineStyle: {
color: "#365576", // 设置 y 轴线的颜色
},
fontSize: 14, // 设置字体大小,可根据需要调整
},
//y轴分割线段数
// splitNumber: 10,
// 修改y轴分割线的颜色
splitLine: {
lineStyle: {
color: "#1a3d62", // 设置分割线的颜色
type: "dashed", // 设置分割线为虚线
},
},
},
series: [
{
type: "line",
// 拐点大小
symbolSize: 8,
smooth: true,
showSymbol: false,
data: this.brokenData1,
//折线颜色
itemStyle: {
color: "#d48e17", //折线点的颜色
lineStyle: {
color: "#d48e17", //折线的颜色
},
},
areaStyle: {
color: {
//线性渐变
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [],
},
},
},
],
};
//把配置项给实例对象
this.brokenInstanc.setOption(this.brokenOption, true);
},
},
};
</script>
<style lang="scss" scoped>
.condition {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
margin-bottom: 0.24rem;
.condition-left {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
.years-div {
display: flex;
flex-direction: row;
align-items: center;
.years-word {
font-size: 14px;
margin: 0 5px;
color: #388ff3;
}
}
.time-label {
font-size: 16px;
line-height: 7px;
margin-right: 12px;
white-space: nowrap;
}
}
}
.data-content {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
width: 100%;
margin-top: 23px;
.data-li {
background-color: transparent;
border-radius: 8px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0.3rem;
width: 31%;
justify-content: space-between;
margin-bottom: 0.24rem;
font-family: SourceHanSansCN-Regular;
font-size: 0.16rem;
position: relative;
overflow: hidden;
.use-icon {
width: 0.6rem;
height: 0.6rem;
}
.use-text {
width: 33%;
display: flex;
flex-direction: column;
align-items: flex-start;
color: #dbdbdb;
.data-text {
z-index: 11 !important;
font-family: DIN-Bold;
font-size: 0.24rem;
margin-top: 0.05rem;
color: #ffffff;
}
.downText {
color: #ff4027;
z-index: 11 !important;
font-family: DIN-Bold;
font-size: 0.24rem;
margin-top: 0.05rem;
.el-icon-bottom {
margin-right: 0.08rem;
}
}
.upText {
color: #2ff016;
z-index: 11 !important;
font-family: DIN-Bold;
font-size: 0.24rem;
margin-top: 0.05rem;
.el-icon-bottom,
.el-icon-top {
margin-right: 0.08rem;
}
}
}
}
.type-img {
position: absolute;
bottom: 0;
width: 3.17rem;
height: 0.52rem;
z-index: 10;
}
.type1 {
border: 1px solid #e8aa13;
border-radius: 10px;
/* 设置渐变背景 */
background: linear-gradient(rgba(26, 56, 65, 0.5), rgba(184, 196, 51, 0.5));
}
.type1::after {
content: "";
width: 100%;
height: 90%;
box-shadow: 0 0 30px 40px rgba(243, 166, 23, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: -100% !important;
z-index: 1;
}
.type2 {
border: 1px solid #27a0f2;
border-radius: 10px;
/* 设置渐变背景 */
background: linear-gradient(rgba(2, 43, 88, 0.5), rgba(8, 96, 179, 0.5));
}
.type2::after {
content: "";
width: 100%;
height: 90%;
box-shadow: 0 0 30px 40px rgba(28, 128, 241, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: -100% !important;
z-index: 1;
}
.type3 {
border: 1px solid #1ad3ef;
border-radius: 10px;
/* 设置渐变背景 */
background: linear-gradient(rgba(2, 50, 89, 0.5), rgba(17, 145, 151, 0.5));
}
.type3::after {
content: "";
width: 100%;
height: 90%;
box-shadow: 0 0 30px 40px rgba(117, 242, 248, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: -100% !important;
z-index: 1;
}
.type4 {
border: 1px solid #11d47b;
border-radius: 10px;
/* 设置渐变背景 */
background: linear-gradient(rgba(2, 57, 82, 0.5), rgba(5, 91, 90, 0.5));
}
.type4::after {
content: "";
width: 100%;
height: 90%;
box-shadow: 0 0 30px 40px rgba(115, 245, 176, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: -100% !important;
z-index: 1;
}
}
.choice {
margin: 20px;
.mr20 {
padding: 0.05rem 0.2rem;
white-space: nowrap;
width: auto;
}
}
.charts {
width: 100%;
height: 300px;
margin-bottom: 0.1rem;
}
// 媒体查询,适配大于2000px分辨率的大屏样式
@media (min-width: 2000px) {
.condition {
.condition-left {
.years-div {
.years-word {
font-size: 0.14rem !important;
margin: 0 0.05rem !important;
}
}
.time-label {
font-size: 0.16rem !important;
line-height: 0.07rem !important;
margin-right: 0.12rem !important;
}
}
}
}
</style>