537 lines
17 KiB
HTML
537 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>节能减排分析</title>
|
||
|
||
<script src="../../js/publics/tailwindcss.min.js"></script>
|
||
<link rel="stylesheet" href="../../css/font.css">
|
||
<link rel="stylesheet" href="../../plugin/layui-v2.9.7/layui/css/layui.css">
|
||
<link rel="stylesheet" href="../../css/dataAnalysis/commonStyle.css">
|
||
<link rel="stylesheet" href="../../css/shuiYin/shuiYin.css">
|
||
<link rel="stylesheet" href="../../css/coreTable.css"/>
|
||
<link href="../../css/all.min.css" rel="stylesheet">
|
||
<script src="../../js/publics/echarts.js"></script>
|
||
<script src="../../js/publics/sm4.js" type="text/javascript"></script>
|
||
<script src="../../js/publics/jquery-3.6.0.min.js" type="text/javascript"></script>
|
||
<script src="../../js/publics/public.js"></script>
|
||
<script src="../../plugin/layui-v2.9.7/layui/layui.js"></script>
|
||
<script src="../../js/publics/aescbc.js"></script>
|
||
<script src="../../js/publics/sm3.js"></script>
|
||
<script src="../../api/commonRequest.js"></script>
|
||
<style>
|
||
html {
|
||
width: 100%;
|
||
height: 90%;
|
||
margin-top: 3%;
|
||
|
||
color: #009B94
|
||
|
||
}
|
||
|
||
.layui-icon-close:before {
|
||
color: #009B94
|
||
}
|
||
|
||
.layui-form-select dl dd {
|
||
cursor: pointer;
|
||
background-color: #008781;
|
||
}
|
||
|
||
/*.shadow {
|
||
background-color: #FFFFFF;
|
||
}*/
|
||
|
||
.layui-laydate {
|
||
background-color: #009B94;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.layui-laydate-content td {
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.layui-laydate-header i {
|
||
color: #FFFFFF;
|
||
|
||
}
|
||
|
||
.shadow {
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(22, 186, 170, 0.1) 0%,
|
||
rgba(22, 186, 170, 0.05) 100%
|
||
);
|
||
|
||
}
|
||
|
||
.layui-layer {
|
||
background-image: url("../../img/video/child-back.png");
|
||
background-size: 100% 100%;
|
||
background-color: transparent;
|
||
}
|
||
|
||
.layui-laydate-footer span {
|
||
background-color: transparent;
|
||
|
||
}
|
||
|
||
.layui-laydate-preview {
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.layui-layer-title {
|
||
border-bottom: 1px solid #008781;
|
||
}
|
||
|
||
.layui-laydate-preview {
|
||
color: #FFFFFF !important;
|
||
}
|
||
|
||
#alarm-container {
|
||
overflow-x: auto; /* 或 overflow-y: auto,根据需要 */
|
||
|
||
/* Firefox */
|
||
scrollbar-width: none;
|
||
|
||
/* IE 10+ */
|
||
-ms-overflow-style: none;
|
||
}
|
||
|
||
/* Chrome, Edge, Safari */
|
||
#alarm-container::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
</style>
|
||
<script>
|
||
tailwind.config = {
|
||
theme: {
|
||
extend: {
|
||
colors: {
|
||
primary: '#009B94',
|
||
secondary: '#009B94'
|
||
},
|
||
borderRadius: {
|
||
'none': '0px',
|
||
'sm': '2px',
|
||
DEFAULT: '4px',
|
||
'md': '8px',
|
||
'lg': '12px',
|
||
'xl': '16px',
|
||
'2xl': '20px',
|
||
'3xl': '24px',
|
||
'full': '9999px',
|
||
'button': '4px'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
</head>
|
||
<body style="width: 100%;height: 100%;color: #FFFFFF">
|
||
<div class="max-w-[1440px] mx-auto px-4">
|
||
<div class="flex items-center justify-between mb-1">
|
||
<form class="layui-form" style="color: #009B94" action="">
|
||
<div class="layui-form-item">
|
||
<div class="layui-inline">
|
||
<div class="layui-inline" id="ID-laydate-range">
|
||
<div class="layui-input-inline">
|
||
<input type="text" autocomplete="off" id="ID-laydate-start-date" class="layui-input"
|
||
placeholder="开始日期">
|
||
</div>
|
||
<div class="layui-form-mid">-</div>
|
||
<div class="layui-input-inline">
|
||
<input type="text" autocomplete="off" id="ID-laydate-end-date" class="layui-input"
|
||
placeholder="结束日期">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</form>
|
||
</div>
|
||
<div class="grid grid-cols-2 gap-4 mb-2">
|
||
<div class=" border border-[#004446] p-4 rounded-lg shadow">
|
||
<h3 class="text-lg font-bold mb-1">能耗趋势分析</h3>
|
||
<div id="trendChart" style="height: 300px;"></div>
|
||
</div>
|
||
<div class=" border border-[#004446] p-4 rounded-lg shadow">
|
||
<h3 class="text-lg font-bold mb-1">设备能耗占比</h3>
|
||
<div id="deviceChart" style="height: 300px;width: 100%;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-2 gap-4 mb-2">
|
||
<div class=" border border-[#004446] p-4 rounded-lg shadow">
|
||
<h3 class="text-lg font-bold mb-2">设备节能占比</h3>
|
||
<div id="renewableUsedKwh" style="height: 270px;width: 100%;"></div>
|
||
</div>
|
||
<div class=" p-4 rounded-lg shadow border border-[#004446]">
|
||
<h3 class="text-lg font-bold mb-2">能耗异常分析</h3>
|
||
<div id="alarm-container" class="space-y-4"
|
||
style="height: 270px; overflow-y: auto;"></div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const trendChart = echarts.init(document.getElementById('trendChart'));
|
||
const deviceChart = echarts.init(document.getElementById('deviceChart'));
|
||
const renewableUsedKwhChart = echarts.init(document.getElementById('renewableUsedKwh'));
|
||
|
||
let table, layer, form, laydate;
|
||
layui.use(["layer", "table", "form"], function () {
|
||
layer = layui.layer;
|
||
table = layui.table;
|
||
form = layui.form;
|
||
laydate = layui.laydate;
|
||
let range = getDateRangeOneWeek();
|
||
|
||
range.startDate = "2024-09-17"
|
||
range.endDate = "2024-09-24"
|
||
laydate.render({
|
||
elem: '#ID-laydate-range',
|
||
range: ['#ID-laydate-start-date', '#ID-laydate-end-date'],
|
||
btns: ['confirm'],
|
||
value: range.startDate + ' - ' + range.endDate,
|
||
done: function (value) {
|
||
// value 是选择的字符串,比如 '2025-06-23 - 2025-07-23'
|
||
const [startDateStr, endDateStr] = value.split(" - ");
|
||
const startDate = new Date(startDateStr);
|
||
const endDate = new Date(endDateStr);
|
||
|
||
// 计算两个日期相差的天数
|
||
const diffDays = (endDate - startDate) / (1000 * 60 * 60 * 24);
|
||
|
||
if (diffDays > 7) {
|
||
layer.msg('起止时间不能超过7天', {icon: 0});
|
||
// 重置日期为上一次合法范围(或你预设的默认值)
|
||
this.elem.val(range.startDate + ' - ' + range.endDate);
|
||
return;
|
||
}
|
||
|
||
let data = {
|
||
"startDate": startDateStr,
|
||
"endDate": endDateStr,
|
||
"proId": parent.parent.$('#bidPro').val()
|
||
}
|
||
selectEnergyStatsByDateRange(data)
|
||
selectDeviceEnergyByDateRange(data)
|
||
selectAnomalyByDateRange(data)
|
||
// 这里可以写你想监听后做的操作
|
||
}
|
||
});
|
||
let data = {
|
||
"startDate": range.startDate,
|
||
"endDate": range.endDate,
|
||
"proId": parent.parent.$('#bidPro').val()
|
||
}
|
||
|
||
selectEnergyStatsByDateRange(data)
|
||
selectDeviceEnergyByDateRange(data)
|
||
selectAnomalyByDateRange(data)
|
||
});
|
||
|
||
// 获取今天和一个月前日期,格式 yyyy-MM-dd
|
||
function getDateRangeOneWeek() {
|
||
let today = new Date();
|
||
|
||
// 复制一个日期,减去7天
|
||
let oneWeekAgo = new Date(today);
|
||
oneWeekAgo.setDate(today.getDate() - 7);
|
||
|
||
function formatDate(d) {
|
||
let m = d.getMonth() + 1;
|
||
let day = d.getDate();
|
||
return d.getFullYear() + '-' + (m < 10 ? '0' + m : m) + '-' + (day < 10 ? '0' + day : day);
|
||
}
|
||
|
||
return {
|
||
startDate: formatDate(oneWeekAgo),
|
||
endDate: formatDate(today)
|
||
};
|
||
}
|
||
|
||
|
||
/* 加载数据分析应用 */
|
||
function selectEnergyStatsByDateRange(data) {
|
||
const url = commonUrl + 'screen/largeScreen/deviceEnergyAnalysis/selectEnergyStatsByDateRange';
|
||
ajaxRequest(url, "post", JSON.stringify(data), true, function () {
|
||
}, function (result) {
|
||
if (result.code === 200) {
|
||
trendChartFn(result.data)
|
||
} else if (result.code === 500) {
|
||
console.error('数据分析应用' + result.msg);
|
||
} else if (result.code === 401) {
|
||
|
||
}
|
||
}, function (xhr, status, error) {
|
||
|
||
}, "application/json", aqEnnable);
|
||
}
|
||
|
||
|
||
/* 加载数据分析应用 */
|
||
function selectDeviceEnergyByDateRange(data) {
|
||
const url = commonUrl + 'screen/largeScreen/deviceEnergyAnalysis/selectDeviceEnergyByDateRange';
|
||
ajaxRequest(url, "post", JSON.stringify(data), true, function () {
|
||
}, function (result) {
|
||
if (result.code === 200) {
|
||
deviceChartFn(result.data)
|
||
renewableUsedKwhFn(result.data)
|
||
} else if (result.code === 500) {
|
||
console.error('数据分析应用' + result.msg);
|
||
} else if (result.code === 401) {
|
||
|
||
}
|
||
}, function (xhr, status, error) {
|
||
|
||
}, "application/json", aqEnnable);
|
||
}
|
||
|
||
|
||
function selectAnomalyByDateRange(data) {
|
||
const url = commonUrl + 'screen/largeScreen/deviceEnergyAnalysis/selectAnomalyByDateRange';
|
||
ajaxRequest(url, "post", JSON.stringify(data), true, function () {
|
||
}, function (result) {
|
||
if (result.code === 200) {
|
||
insertAlarm(result.data)
|
||
} else if (result.code === 500) {
|
||
console.error('数据分析应用' + result.msg);
|
||
} else if (result.code === 401) {
|
||
|
||
}
|
||
}, function (xhr, status, error) {
|
||
|
||
}, "application/json", aqEnnable);
|
||
}
|
||
|
||
|
||
function insertAlarm(data) {
|
||
const container = document.getElementById('alarm-container');
|
||
container.innerHTML = ''; // 🔄 清空原有内容
|
||
const colorMap = {
|
||
info: {
|
||
bg: 'bg-blue-100',
|
||
icon: 'fa-info-circle',
|
||
iconColor: 'text-blue-500',
|
||
titleColor: 'text-blue-900',
|
||
timeColor: 'text-blue-700'
|
||
},
|
||
warning: {
|
||
bg: 'bg-yellow-100',
|
||
icon: 'fa-exclamation-triangle',
|
||
iconColor: 'text-yellow-500',
|
||
titleColor: 'text-yellow-900',
|
||
timeColor: 'text-yellow-700'
|
||
},
|
||
danger: {
|
||
bg: 'bg-red-100',
|
||
icon: 'fa-exclamation-circle',
|
||
iconColor: 'text-red-500',
|
||
titleColor: 'text-red-900',
|
||
timeColor: 'text-red-700'
|
||
}
|
||
};
|
||
data.map(item => {
|
||
const cfg = colorMap[item.anomalyLevel];
|
||
|
||
|
||
const div = document.createElement('div');
|
||
div.onclick = () => goDetail(item);
|
||
div.className = `flex items-start gap-3 p-4 ${cfg.bg} rounded-lg`;
|
||
div.innerHTML = `
|
||
<i class="fas ${cfg.icon} ${cfg.iconColor} mt-1"></i>
|
||
<div>
|
||
<div class="font-medium ${cfg.titleColor}" style="font-size: 16px">${item.deviceName}</div>
|
||
<div class="flex font-medium gap-2 p-1 ${cfg.titleColor}" style="width: 100%"><span>${item.anomalyDesc}</span><span style="float: right">${item.statDate}</span></div>
|
||
</div>`;
|
||
container.appendChild(div);
|
||
})
|
||
|
||
}
|
||
|
||
|
||
function goDetail(date) {
|
||
let layerIndex = layer.open({
|
||
type: 2, // page 层类型
|
||
area: ['600px', '400px'],
|
||
title: [`${date.deviceName} 异常详情`, 'font-size: 20px;color: #009B94;'],
|
||
shade: 0.6, // 遮罩透明度
|
||
shadeClose: true, // 点击遮罩区域,关闭弹层
|
||
anim: 0, // 0-6 的动画形式,-1 不开启
|
||
content: 'exception-detail.html',
|
||
success: function () {
|
||
if (date) {
|
||
let iframeWin = window["layui-layer-iframe" + layerIndex];
|
||
iframeWin.setParams(JSON.stringify(date));
|
||
}
|
||
|
||
}
|
||
});
|
||
}
|
||
|
||
|
||
function trendChartFn(data) {
|
||
let statDate = [];
|
||
let consumptionKwh = [];
|
||
let renewableUsedKwh = [];
|
||
|
||
data.map(item => {
|
||
statDate.push(item.statDate);
|
||
consumptionKwh.push(Number(parseFloat(item.consumptionKwh).toFixed(2)));
|
||
renewableUsedKwh.push(Number(parseFloat(item.renewableUsedKwh).toFixed(2)));
|
||
})
|
||
trendChart.setOption({
|
||
animation: false,
|
||
tooltip: {
|
||
trigger: 'axis'
|
||
},
|
||
textStyle: {
|
||
color: '#FFFFFF'
|
||
},
|
||
legend: {
|
||
data: ['能源消耗量', '节能减排量'],
|
||
textStyle: {
|
||
color: '#FFFFFF'
|
||
}
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: statDate
|
||
},
|
||
yAxis: [{
|
||
type: 'value',
|
||
name: '能源消耗量(kWh)',
|
||
|
||
}, {
|
||
type: 'value',
|
||
name: '节能减排量(kgCO₂)',
|
||
|
||
splitLine: {
|
||
show: false
|
||
}
|
||
}],
|
||
series: [{
|
||
name: '能源消耗量',
|
||
type: 'line',
|
||
data: consumptionKwh,
|
||
label: {
|
||
show: true,
|
||
position: 'top',
|
||
color: '#FFFFFF',
|
||
fontSize: 12,
|
||
formatter: '{c}'
|
||
}
|
||
}, {
|
||
name: '节能减排量',
|
||
type: 'line',
|
||
yAxisIndex: 1,
|
||
data: renewableUsedKwh,
|
||
label: {
|
||
show: true,
|
||
position: 'top',
|
||
color: '#FFFFFF',
|
||
fontSize: 12,
|
||
formatter: '{c}'
|
||
}
|
||
},]
|
||
});
|
||
}
|
||
|
||
function deviceChartFn(data) {
|
||
let pieData = data.map(item => ({
|
||
name: item.deviceName,
|
||
value: Number(parseFloat(item.consumptionKwh).toFixed(2))
|
||
}));
|
||
|
||
deviceChart.setOption({
|
||
animation: false,
|
||
tooltip: {
|
||
trigger: 'item',
|
||
formatter: '{b}: {c} kWh ({d}%)'
|
||
},
|
||
textStyle: { color: '#FFFFFF' },
|
||
legend: {
|
||
orient: 'vertical',
|
||
left: 'left',
|
||
textStyle: { color: '#FFFFFF' }
|
||
},
|
||
series: [{
|
||
name: '能耗占比',
|
||
type: 'pie',
|
||
radius: '55%',
|
||
center: ['50%', '50%'],
|
||
data: pieData,
|
||
label: {
|
||
show: true,
|
||
formatter: '{b}: {d}%',
|
||
color: '#FFFFFF',
|
||
fontSize: 12
|
||
},
|
||
emphasis: {
|
||
itemStyle: {
|
||
shadowBlur: 10,
|
||
shadowOffsetX: 0,
|
||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||
}
|
||
}
|
||
}]
|
||
});
|
||
}
|
||
|
||
|
||
function renewableUsedKwhFn(data) {
|
||
let pieData = data.map(item => ({
|
||
name: item.deviceName,
|
||
value: Number(parseFloat(item.renewableUsedKwh).toFixed(2))
|
||
}));
|
||
|
||
renewableUsedKwhChart.setOption({
|
||
animation: false,
|
||
tooltip: {
|
||
trigger: 'item',
|
||
formatter: '{b}: {c} kWh ({d}%)'
|
||
},
|
||
textStyle: { color: '#FFFFFF' },
|
||
legend: {
|
||
orient: 'vertical',
|
||
left: 'left',
|
||
textStyle: { color: '#FFFFFF' }
|
||
},
|
||
series: [{
|
||
name: '可再生能源使用占比',
|
||
type: 'pie',
|
||
radius: '55%',
|
||
center: ['50%', '50%'],
|
||
data: pieData,
|
||
label: {
|
||
show: true,
|
||
formatter: '{b}: {d}%',
|
||
color: '#FFFFFF',
|
||
fontSize: 12
|
||
},
|
||
emphasis: {
|
||
itemStyle: {
|
||
shadowBlur: 10,
|
||
shadowOffsetX: 0,
|
||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||
}
|
||
}
|
||
}]
|
||
});
|
||
}
|
||
|
||
|
||
|
||
window.addEventListener('resize', function () {
|
||
trendChart.resize();
|
||
deviceChart.resize();
|
||
renewableUsedKwhChart.resize();
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|