1036 lines
30 KiB
Plaintext
1036 lines
30 KiB
Plaintext
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
pageEncoding="UTF-8"%>
|
|
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>排污户大屏展示</title>
|
|
<!-- <script
|
|
type="text/javascript"
|
|
src="../../node_modules/jquery/dist/jquery.min.js"
|
|
></script>
|
|
<script type="text/javascript" src="../../JS/echarts3.0.js"></script> -->
|
|
<script type="text/javascript" src="<%=request.getContextPath()%>/node_modules/jquery/dist/jquery.min.js"></script>
|
|
<script type="text/javascript" src="<%=request.getContextPath()%>/JS/echarts3.0.js"></script>
|
|
<style>
|
|
body,
|
|
html {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: auto;
|
|
background-color: #030829;
|
|
font-family: "Microsoft YaHei", sans-serif;
|
|
}
|
|
.screen-container {
|
|
width: 6500px;
|
|
height: 1800px;
|
|
background-image: url('<%=request.getContextPath()%>/IMG/screen3.png');
|
|
/* background-image: url("../../IMG/screen3.png"); */
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
position: relative;
|
|
}
|
|
|
|
/* Area 1: Left Stats + Ranking */
|
|
.rank-module-container {
|
|
position: absolute;
|
|
top: 275px;
|
|
left: 66px;
|
|
width: 1926px;
|
|
height: 1500px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* padding: 20px; */
|
|
box-sizing: border-box;
|
|
z-index: 10;
|
|
}
|
|
|
|
.stats-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 30px;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
padding: 20px;
|
|
border-radius: 10px;
|
|
border: 1px solid rgba(0, 234, 255, 0.2);
|
|
}
|
|
|
|
.stat-item {
|
|
text-align: center;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 24px;
|
|
color: #ccc;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 48px;
|
|
font-weight: bold;
|
|
color: #00eaff;
|
|
font-family: "DIN Alternate", sans-serif;
|
|
}
|
|
|
|
.stat-unit {
|
|
font-size: 20px;
|
|
margin-left: 5px;
|
|
color: #aaa;
|
|
}
|
|
|
|
.ranking-title {
|
|
font-size: 28px;
|
|
font-weight: bold;
|
|
padding-left: 10px;
|
|
border-left: 4px solid;
|
|
margin-bottom: 15px;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
/* Area 3: Right Details */
|
|
.detail-module-container {
|
|
position: absolute;
|
|
top: 275px;
|
|
right: 66px;
|
|
width: 1926px;
|
|
height: 1500px;
|
|
border: 1px solid rgba(0, 234, 255, 0.3);
|
|
backdrop-filter: blur(10px);
|
|
border-radius: 12px;
|
|
/* padding: 30px; */
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
color: #fff;
|
|
/* background: rgba(0, 20, 50, 0.6) url('<%=request.getContextPath()%>/IMG/bim/渐变背景.png') no-repeat center center; */
|
|
background-size: cover;
|
|
z-index: 10;
|
|
}
|
|
|
|
/* Area 2: Center Map */
|
|
.map-module-container {
|
|
position: absolute;
|
|
top: 180px;
|
|
left: 2000px; /* Positioned between Left (1900+66) and Right */
|
|
width: 2400px; /* Approximate remaining space: 6500 - 1900 - 1926 - margins */
|
|
height: 1500px;
|
|
/* background: rgba(0, 255, 0, 0.1); Debug */
|
|
position: relative;
|
|
z-index: 5;
|
|
}
|
|
|
|
.map-point {
|
|
position: absolute;
|
|
width: 30px;
|
|
height: 30px;
|
|
background: rgba(0, 234, 255, 0.8);
|
|
border: 2px solid #fff;
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
box-shadow: 0 0 15px #00eaff;
|
|
transition: all 0.3s ease;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
.map-point.active {
|
|
background: #ffaa00;
|
|
box-shadow: 0 0 25px #ffaa00;
|
|
transform: translate(-50%, -50%) scale(1.5);
|
|
z-index: 20;
|
|
}
|
|
|
|
.map-point:hover {
|
|
transform: translate(-50%, -50%) scale(1.2);
|
|
}
|
|
|
|
.map-tooltip {
|
|
position: absolute;
|
|
bottom: 40px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
background: rgba(0, 0, 0, 0.8);
|
|
color: #fff;
|
|
padding: 5px 10px;
|
|
border-radius: 4px;
|
|
white-space: nowrap;
|
|
font-size: 20px;
|
|
pointer-events: none;
|
|
display: none;
|
|
border: 1px solid #00eaff;
|
|
}
|
|
|
|
.map-point:hover .map-tooltip {
|
|
display: block;
|
|
}
|
|
|
|
.enterprise-detail-header {
|
|
font-size: 56px;
|
|
font-weight: bold;
|
|
color: #00eaff;
|
|
text-align: center;
|
|
margin-bottom: 40px;
|
|
text-shadow: 0 0 20px rgba(0, 234, 255, 0.8);
|
|
border-bottom: 2px solid rgba(0, 234, 255, 0.2);
|
|
padding-bottom: 20px;
|
|
letter-spacing: 2px;
|
|
}
|
|
|
|
.detail-content {
|
|
display: flex;
|
|
height: 450px;
|
|
margin-bottom: 40px;
|
|
gap: 30px;
|
|
}
|
|
|
|
.info-section {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
font-size: 36px;
|
|
line-height: 2.2;
|
|
padding: 20px;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.info-item {
|
|
border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.info-item span {
|
|
color: #ffaa00;
|
|
font-weight: bold;
|
|
margin-left: 15px;
|
|
font-family: "DIN Alternate", sans-serif;
|
|
}
|
|
|
|
.photo-section {
|
|
flex: 1;
|
|
border: 2px solid rgba(0, 234, 255, 0.3);
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
background: #000;
|
|
position: relative;
|
|
}
|
|
|
|
.photo-label {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
color: #fff;
|
|
text-align: center;
|
|
padding: 10px 0;
|
|
font-size: 24px;
|
|
}
|
|
|
|
.detail-charts {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 30px;
|
|
}
|
|
|
|
.detail-chart-box {
|
|
flex: 1;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border: 1px solid rgba(0, 234, 255, 0.1);
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.chart-subtitle {
|
|
font-size: 32px;
|
|
color: #ffffff;
|
|
margin-bottom: 15px;
|
|
padding-left: 15px;
|
|
border-left: 6px solid #00eaff;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.chart-content {
|
|
flex: 1;
|
|
width: 100%;
|
|
min-height: 0; /* Important for flex child scroll/resize */
|
|
}
|
|
|
|
.new-bar-chart-container {
|
|
position: absolute;
|
|
top: 400px;
|
|
left: 66px;
|
|
width: 1920px;
|
|
height: 1400px;
|
|
z-index: 100;
|
|
display: none;
|
|
}
|
|
/* 全屏提示遮罩 */
|
|
.fullscreen-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.9);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 9999;
|
|
cursor: pointer;
|
|
}
|
|
.fullscreen-overlay .tip-content {
|
|
text-align: center;
|
|
color: #fff;
|
|
}
|
|
.fullscreen-overlay .tip-content h2 {
|
|
font-size: 48px;
|
|
margin-bottom: 20px;
|
|
color: #46F2FF;
|
|
}
|
|
.fullscreen-overlay .tip-content p {
|
|
font-size: 24px;
|
|
color: #7ef3ff;
|
|
}
|
|
.fullscreen-overlay .tip-content .icon {
|
|
font-size: 80px;
|
|
margin-bottom: 20px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- 全屏提示遮罩 -->
|
|
<div class="fullscreen-overlay" id="fullscreenOverlay" onclick="enterFullscreen()">
|
|
<div class="tip-content">
|
|
<div class="icon">🖥️</div>
|
|
<h2>点击进入全屏展示</h2>
|
|
<p>按 ESC 键可退出全屏</p>
|
|
</div>
|
|
</div>
|
|
<div class="screen-container">
|
|
<div class="rank-module-container">
|
|
<!-- Statistics -->
|
|
<div class="stats-header">
|
|
<div class="stat-item">
|
|
<div class="stat-label">辖区排污企业总数</div>
|
|
<div class="stat-value" id="totalCount">
|
|
0<span class="stat-unit">家</span>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">已接入监控</div>
|
|
<div class="stat-value" style="color: #00ff00" id="connectedCount">
|
|
0<span class="stat-unit">家</span>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">正在接入中</div>
|
|
<div class="stat-value" style="color: #ffaa00" id="connectingCount">
|
|
0<span class="stat-unit">家</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ranking List -->
|
|
<div
|
|
class="ranking-list-wrapper"
|
|
style="
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
"
|
|
>
|
|
<div id="chartRanking" style="flex: 1; width: 100%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Left Side Detail Module -->
|
|
<div class="detail-module-container">
|
|
<div class="enterprise-detail-header" id="detailTitle">
|
|
企业名称加载中...
|
|
</div>
|
|
<div class="detail-content">
|
|
<div class="info-section">
|
|
<div class="info-item">
|
|
污水特性: <span id="sewageType">--</span>
|
|
</div>
|
|
<div class="info-item">
|
|
当前排污量: <span id="dischargeVolume">--</span>
|
|
</div>
|
|
<div class="info-item">
|
|
接入状态: <span id="connectionStatus">--</span>
|
|
</div>
|
|
</div>
|
|
<div class="photo-section">
|
|
<img
|
|
id="sitePhoto"
|
|
src="<%=request.getContextPath()%>/IMG/login/company.png"
|
|
alt="现场照片"
|
|
style="width: 100%; height: 100%; object-fit: cover"
|
|
/>
|
|
<div class="photo-label">现场监控画面</div>
|
|
</div>
|
|
</div>
|
|
<div class="detail-charts">
|
|
<div class="detail-chart-box">
|
|
<div class="chart-subtitle">瞬时排污量历史曲线 (近3天)</div>
|
|
<div id="chartInstant" class="chart-content"></div>
|
|
</div>
|
|
<div class="detail-chart-box">
|
|
<div class="chart-subtitle">累计流量历史曲线 (日差值 - 近14天)</div>
|
|
<div id="chartCumulative" class="chart-content"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- New Bar Chart Area -->
|
|
<div class="new-bar-chart-container">
|
|
<div id="newBarChart" style="width: 100%; height: 100%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
var myChartInstant = null;
|
|
var myChartCumulative = null;
|
|
var myChartRanking = null;
|
|
var myNewBarChart = null;
|
|
|
|
var currentMaxData = []; // Top 10 Max
|
|
var currentMinData = []; // Top 10 Min
|
|
var allEnterprises = []; // All data for map
|
|
var currentFocusIndex = 0;
|
|
var rotationTimer = null;
|
|
|
|
// 进入全屏函数
|
|
function enterFullscreen() {
|
|
var elem = document.documentElement;
|
|
if (elem.requestFullscreen) {
|
|
elem.requestFullscreen();
|
|
} else if (elem.webkitRequestFullscreen) {
|
|
elem.webkitRequestFullscreen();
|
|
} else if (elem.msRequestFullscreen) {
|
|
elem.msRequestFullscreen();
|
|
}
|
|
document.getElementById('fullscreenOverlay').style.display = 'none';
|
|
}
|
|
|
|
// 监听全屏状态变化
|
|
document.addEventListener('fullscreenchange', function() {
|
|
var overlay = document.getElementById('fullscreenOverlay');
|
|
if (!document.fullscreenElement) {
|
|
overlay.style.display = 'flex';
|
|
}
|
|
});
|
|
document.addEventListener('webkitfullscreenchange', function() {
|
|
var overlay = document.getElementById('fullscreenOverlay');
|
|
if (!document.webkitFullscreenElement) {
|
|
overlay.style.display = 'flex';
|
|
}
|
|
});
|
|
|
|
$(document).ready(function () {
|
|
initData();
|
|
|
|
// Double click to toggle fullscreen
|
|
$("body").on("dblclick", function () {
|
|
launchIntoFullscreen(document.documentElement);
|
|
});
|
|
});
|
|
|
|
function launchIntoFullscreen(element) {
|
|
if (element.requestFullscreen) {
|
|
element.requestFullscreen();
|
|
} else if (element.mozRequestFullScreen) {
|
|
element.mozRequestFullScreen();
|
|
} else if (element.webkitRequestFullscreen) {
|
|
element.webkitRequestFullscreen();
|
|
} else if (element.msRequestFullscreen) {
|
|
element.msRequestFullscreen();
|
|
}
|
|
}
|
|
|
|
function exitFullscreen() {
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen();
|
|
} else if (document.mozCancelFullScreen) {
|
|
document.mozCancelFullScreen();
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen();
|
|
}
|
|
}
|
|
|
|
function initData() {
|
|
// Stats
|
|
var total = 158;
|
|
var connected = 124;
|
|
var connecting = 34;
|
|
$("#totalCount").html(total + '<span class="stat-unit">家</span>');
|
|
$("#connectedCount").html(
|
|
connected + '<span class="stat-unit">家</span>',
|
|
);
|
|
$("#connectingCount").html(
|
|
connecting + '<span class="stat-unit">家</span>',
|
|
);
|
|
|
|
// Generate Enterprises with Details
|
|
var enterprises = [];
|
|
var sewageTypes = ["化学需氧量", "氨氮", "总磷", "重金属", "酸碱废水"];
|
|
var connectionStatuses = ["已接入", "接入中"];
|
|
|
|
for (var i = 1; i <= 50; i++) {
|
|
var val = Math.floor(Math.random() * 10000) + 500;
|
|
enterprises.push({
|
|
id: i,
|
|
name: "企业-" + i,
|
|
value: val,
|
|
// Details
|
|
sewageType:
|
|
sewageTypes[Math.floor(Math.random() * sewageTypes.length)],
|
|
connectionStatus:
|
|
connectionStatuses[
|
|
Math.floor(Math.random() * connectionStatuses.length)
|
|
],
|
|
indicator: val > 8000 ? "超级" : "普通",
|
|
photo: "<%=request.getContextPath()%>/IMG/login/company.png", // Placeholder
|
|
// Map Coordinates (Relative % in map container)
|
|
x: Math.random() * 90 + 5, // 5% to 95%
|
|
y: Math.random() * 80 + 10, // 10% to 90%
|
|
// History Data
|
|
instantHistory: generateHistoryData(72), // 3 days * 24 hours
|
|
cumulativeHistory: generateHistoryData(14), // 14 days
|
|
});
|
|
}
|
|
allEnterprises = enterprises;
|
|
|
|
// Init Charts
|
|
myChartInstant = echarts.init(document.getElementById("chartInstant"));
|
|
myChartCumulative = echarts.init(
|
|
document.getElementById("chartCumulative"),
|
|
);
|
|
myChartRanking = echarts.init(document.getElementById("chartRanking"));
|
|
// myNewBarChart = echarts.init(document.getElementById('newBarChart'));
|
|
|
|
// renderNewBarChart();
|
|
|
|
// Initial Sort
|
|
updateSortedData(enterprises);
|
|
|
|
// Render Lists & Map
|
|
renderRankingChart();
|
|
renderMapPoints();
|
|
|
|
updateDetailView();
|
|
|
|
// Start Loops
|
|
startDataSimulation(enterprises);
|
|
startRotation();
|
|
}
|
|
|
|
function generateHistoryData(count) {
|
|
var data = [];
|
|
for (var k = 0; k < count; k++) {
|
|
data.push(Math.floor(Math.random() * 500) + 50);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function updateSortedData(enterprises) {
|
|
// Sort Descending for Max
|
|
currentMaxData = [...enterprises]
|
|
.sort((a, b) => b.value - a.value)
|
|
.slice(0, 10);
|
|
|
|
// Sort Ascending for Min
|
|
currentMinData = [...enterprises]
|
|
.sort((a, b) => a.value - b.value)
|
|
.slice(0, 10);
|
|
}
|
|
|
|
function renderRankingChart() {
|
|
var maxNames = [];
|
|
var maxValues = [];
|
|
var minNames = [];
|
|
var minValues = [];
|
|
|
|
// Process Max Data (Top 10 High)
|
|
currentMaxData.forEach((item, index) => {
|
|
maxNames.push(item.name);
|
|
|
|
maxValues.push({
|
|
value: item.value,
|
|
itemStyle: {
|
|
normal: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
{
|
|
offset: 0,
|
|
color: "#ff5500",
|
|
},
|
|
{
|
|
offset: 1,
|
|
color: "#ffb700",
|
|
},
|
|
]),
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
// Process Min Data (Top 10 Low)
|
|
currentMinData.forEach((item) => {
|
|
minNames.push(item.name);
|
|
minValues.push({
|
|
value: item.value,
|
|
itemStyle: {
|
|
normal: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
{
|
|
offset: 0,
|
|
color: "#00aa00",
|
|
},
|
|
{
|
|
offset: 1,
|
|
color: "#00ff00",
|
|
},
|
|
]),
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
var option = {
|
|
title: [
|
|
{
|
|
text: "近30日排污量 TOP 10 (最大)",
|
|
left: "25%",
|
|
top: "2%",
|
|
textAlign: "center",
|
|
textStyle: { color: "#ffffff", fontSize: 30, fontWeight: "bold" },
|
|
},
|
|
{
|
|
text: "近30日排污量 TOP 10 (最小)",
|
|
left: "75%",
|
|
top: "2%",
|
|
textAlign: "center",
|
|
textStyle: { color: "#ffffff", fontSize: 30, fontWeight: "bold" },
|
|
},
|
|
],
|
|
grid: [
|
|
{
|
|
top: "12%",
|
|
left: "2%",
|
|
right: "52%",
|
|
bottom: "5%",
|
|
containLabel: true,
|
|
},
|
|
{
|
|
top: "12%",
|
|
left: "52%",
|
|
right: "2%",
|
|
bottom: "5%",
|
|
containLabel: true,
|
|
},
|
|
],
|
|
xAxis: [
|
|
{
|
|
type: "value",
|
|
show: false,
|
|
gridIndex: 0,
|
|
},
|
|
{
|
|
type: "value",
|
|
show: false,
|
|
gridIndex: 1,
|
|
},
|
|
],
|
|
yAxis: [
|
|
{
|
|
type: "category",
|
|
data: maxNames,
|
|
inverse: true,
|
|
axisLabel: { color: "#fff", fontSize: 20 },
|
|
axisLine: { show: false },
|
|
axisTick: { show: false },
|
|
gridIndex: 0,
|
|
},
|
|
{
|
|
type: "category",
|
|
data: minNames,
|
|
inverse: true,
|
|
axisLabel: { color: "#fff", fontSize: 20 },
|
|
axisLine: { show: false },
|
|
axisTick: { show: false },
|
|
gridIndex: 1,
|
|
},
|
|
],
|
|
series: [
|
|
{
|
|
name: "Max",
|
|
type: "bar",
|
|
xAxisIndex: 0,
|
|
yAxisIndex: 0,
|
|
data: maxValues,
|
|
barWidth: 45,
|
|
showBackground: true,
|
|
backgroundStyle: {
|
|
color: "rgba(255, 255, 255, 0.1)",
|
|
barBorderRadius: [0, 22, 22, 0],
|
|
},
|
|
label: {
|
|
normal: {
|
|
show: true,
|
|
position: "right",
|
|
textStyle: { color: "#ffffff", fontSize: 20 },
|
|
formatter: "{c}",
|
|
},
|
|
},
|
|
itemStyle: { normal: { barBorderRadius: [0, 22, 22, 0] } },
|
|
},
|
|
{
|
|
name: "Min",
|
|
type: "bar",
|
|
xAxisIndex: 1,
|
|
yAxisIndex: 1,
|
|
data: minValues,
|
|
barWidth: 45,
|
|
showBackground: true,
|
|
backgroundStyle: {
|
|
color: "rgba(255, 255, 255, 0.1)",
|
|
barBorderRadius: [0, 22, 22, 0],
|
|
},
|
|
label: {
|
|
normal: {
|
|
show: true,
|
|
position: "right",
|
|
textStyle: { color: "#ffffff", fontSize: 20 },
|
|
formatter: "{c}",
|
|
},
|
|
},
|
|
itemStyle: { normal: { barBorderRadius: [0, 22, 22, 0] } },
|
|
},
|
|
],
|
|
};
|
|
|
|
myChartRanking.setOption(option);
|
|
}
|
|
|
|
function renderMapPoints() {
|
|
var html = "";
|
|
allEnterprises.forEach((item) => {
|
|
html +=
|
|
'<div class="map-point ' +
|
|
(item.value > 8000 ? "super" : "") +
|
|
'" id="point-' +
|
|
item.id +
|
|
'" style="left:' +
|
|
item.x +
|
|
"%; top:" +
|
|
item.y +
|
|
'%;" onclick="handleMapClick(' +
|
|
item.id +
|
|
')">';
|
|
html += '<div class="map-tooltip" onclick="event.stopPropagation()">'; // Stop prop to prevent point click
|
|
html +=
|
|
'<div class="map-tooltip-row" style="font-weight:bold; color:#00eaff; font-size:22px; margin-bottom:10px; cursor:pointer;" onclick="handleMapClick(' +
|
|
item.id +
|
|
')">' +
|
|
item.name +
|
|
"</div>";
|
|
html +=
|
|
'<div class="map-tooltip-row"><span class="map-tooltip-label">瞬时流量:</span><span class="clickable-val" onclick="showHistoryModal(\'instant\', ' +
|
|
item.id +
|
|
')">' +
|
|
item.value +
|
|
" m³/h</span></div>";
|
|
html +=
|
|
'<div class="map-tooltip-row"><span class="map-tooltip-label">累计流量:</span><span class="clickable-val" onclick="showHistoryModal(\'cumulative\', ' +
|
|
item.id +
|
|
')">' +
|
|
item.value * 24 +
|
|
" m³</span></div>";
|
|
html += "</div>";
|
|
html += "</div>";
|
|
});
|
|
$("#mapContainer").html(html);
|
|
}
|
|
|
|
function closeModal() {
|
|
$("#historyModal").fadeOut();
|
|
}
|
|
|
|
var modalChartInstance = null;
|
|
|
|
function showHistoryModal(type, id) {
|
|
var ent = allEnterprises.find((e) => e.id === id);
|
|
if (!ent) return;
|
|
|
|
$("#historyModal").css("display", "flex").hide().fadeIn();
|
|
|
|
if (modalChartInstance) {
|
|
modalChartInstance.dispose();
|
|
}
|
|
modalChartInstance = echarts.init(
|
|
document.getElementById("modalChart"),
|
|
);
|
|
|
|
var title =
|
|
(type === "instant" ? "瞬时排污量" : "累计流量") +
|
|
"历史曲线 - " +
|
|
ent.name;
|
|
$("#modalTitle").text(title);
|
|
|
|
var xData, yData, color;
|
|
if (type === "instant") {
|
|
xData = [];
|
|
for (var i = 0; i < 72; i++) xData.push(i + "h");
|
|
yData = ent.instantHistory;
|
|
color = "#ffaa00";
|
|
} else {
|
|
xData = [];
|
|
for (var j = 0; j < 14; j++) xData.push("D" + (j + 1));
|
|
yData = ent.cumulativeHistory;
|
|
color = "#00eaff";
|
|
}
|
|
|
|
var option = {
|
|
tooltip: {
|
|
trigger: "axis",
|
|
backgroundColor: "rgba(0,0,0,0.8)",
|
|
textStyle: { color: "#fff" },
|
|
},
|
|
grid: {
|
|
left: "3%",
|
|
right: "4%",
|
|
bottom: "3%",
|
|
top: "10%",
|
|
containLabel: true,
|
|
},
|
|
xAxis: {
|
|
type: "category",
|
|
boundaryGap: false,
|
|
data: xData,
|
|
axisLabel: { color: "#fff", fontSize: 16 },
|
|
axisLine: { lineStyle: { color: "#00eaff" } },
|
|
},
|
|
yAxis: {
|
|
type: "value",
|
|
axisLabel: { color: "#fff", fontSize: 16 },
|
|
splitLine: { lineStyle: { color: "rgba(255,255,255,0.1)" } },
|
|
},
|
|
series: [
|
|
{
|
|
name: type === "instant" ? "瞬时流量" : "累计流量",
|
|
type: "line",
|
|
smooth: true,
|
|
data: yData,
|
|
lineStyle: { width: 3, color: color },
|
|
areaStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{
|
|
offset: 0,
|
|
color: color,
|
|
},
|
|
{
|
|
offset: 1,
|
|
color: "rgba(0,0,0,0)",
|
|
},
|
|
]),
|
|
},
|
|
itemStyle: { color: color },
|
|
},
|
|
],
|
|
};
|
|
|
|
modalChartInstance.setOption(option);
|
|
}
|
|
|
|
function handleMapClick(id) {
|
|
// Find if this enterprise is in currentMaxData
|
|
var index = currentMaxData.findIndex((e) => e.id === id);
|
|
if (index !== -1) {
|
|
currentFocusIndex = index;
|
|
updateDetailView();
|
|
// Reset rotation timer to pause briefly or restart?
|
|
// For simplicity, just let it continue or reset interval
|
|
clearInterval(rotationTimer);
|
|
startRotation();
|
|
} else {
|
|
// If clicked item is not in Top 10, we can still show it in Detail View
|
|
// But rotation logic might overwrite it next tick.
|
|
// Let's just show it temporarily.
|
|
var enterprise = allEnterprises.find((e) => e.id === id);
|
|
if (enterprise) {
|
|
renderDetailContent(enterprise);
|
|
highlightMapPoint(enterprise.id);
|
|
// Clear ranking highlight since it's not in the list (visually)
|
|
$(".ranking-row").removeClass("active");
|
|
}
|
|
}
|
|
}
|
|
|
|
function startDataSimulation(enterprises) {
|
|
setInterval(function () {
|
|
// Randomize values
|
|
enterprises.forEach((item) => {
|
|
item.value += Math.floor(Math.random() * 200) - 100;
|
|
if (item.value < 0) item.value = 0;
|
|
item.indicator = item.value > 8000 ? "超级" : "普通";
|
|
|
|
// Update Map Point Style
|
|
var el = $("#point-" + item.id);
|
|
if (item.value > 8000) {
|
|
el.addClass("super");
|
|
} else {
|
|
el.removeClass("super");
|
|
}
|
|
el.find(".map-tooltip").html(
|
|
item.name + "<br>排污量: " + item.value,
|
|
);
|
|
});
|
|
|
|
updateSortedData(enterprises);
|
|
renderRankingChart();
|
|
// Update map tooltips if needed? Or just let them be static until hover re-render?
|
|
// Re-rendering map points entirely is heavy if DOM is large, but 50 is fine.
|
|
// However, re-rendering loses hover state. Better to update text.
|
|
// For demo simplicity, we skip real-time map value update or do it simply:
|
|
/*
|
|
enterprises.forEach(item => {
|
|
$('#point-' + item.id + ' .map-tooltip').html(item.name + '<br>排污量: ' + item.value);
|
|
});
|
|
*/
|
|
}, 10000);
|
|
}
|
|
|
|
function startRotation() {
|
|
rotationTimer = setInterval(function () {
|
|
currentFocusIndex = (currentFocusIndex + 1) % 10;
|
|
updateDetailView();
|
|
}, 10000); // Rotate every 5 seconds
|
|
}
|
|
|
|
function updateDetailView() {
|
|
if (!currentMaxData || currentMaxData.length === 0) return;
|
|
if (currentFocusIndex >= currentMaxData.length) currentFocusIndex = 0;
|
|
|
|
var enterprise = currentMaxData[currentFocusIndex];
|
|
|
|
renderDetailContent(enterprise);
|
|
|
|
// Highlight Ranking Chart
|
|
renderRankingChart();
|
|
|
|
// Highlight Map Point
|
|
highlightMapPoint(enterprise.id);
|
|
}
|
|
|
|
function highlightMapPoint(id) {
|
|
$(".map-point").removeClass("active");
|
|
$("#point-" + id).addClass("active");
|
|
}
|
|
|
|
function renderDetailContent(enterprise) {
|
|
// Update DOM
|
|
$("#detailTitle").text(enterprise.name);
|
|
$("#sewageType").text(enterprise.sewageType);
|
|
$("#dischargeVolume").text(enterprise.value + " m³");
|
|
$("#connectionStatus").text(enterprise.connectionStatus);
|
|
|
|
renderDetailCharts(enterprise);
|
|
}
|
|
|
|
function renderDetailCharts(enterprise) {
|
|
// Generate X labels
|
|
var hours = [];
|
|
for (var i = 0; i < 72; i++) hours.push(i + "h");
|
|
|
|
var days = [];
|
|
for (var j = 0; j < 14; j++) days.push("D" + (j + 1));
|
|
|
|
// Instant Chart (Line)
|
|
var optionInstant = {
|
|
tooltip: { trigger: "axis" },
|
|
grid: {
|
|
left: "3%",
|
|
right: "4%",
|
|
bottom: "3%",
|
|
top: "15%",
|
|
containLabel: true,
|
|
},
|
|
xAxis: {
|
|
type: "category",
|
|
boundaryGap: false,
|
|
data: hours,
|
|
axisLabel: { color: "#ccc" },
|
|
axisLine: { lineStyle: { color: "#00eaff" } },
|
|
},
|
|
yAxis: {
|
|
type: "value",
|
|
axisLabel: { color: "#ccc" },
|
|
splitLine: { lineStyle: { color: "rgba(255,255,255,0.1)" } },
|
|
},
|
|
series: [
|
|
{
|
|
name: "瞬时量",
|
|
type: "line",
|
|
smooth: true,
|
|
symbol: "none",
|
|
sampling: "average",
|
|
itemStyle: { color: "#00eaff" },
|
|
areaStyle: {
|
|
normal: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: "rgba(0, 234, 255, 0.5)" },
|
|
{ offset: 1, color: "rgba(0, 234, 255, 0)" },
|
|
]),
|
|
},
|
|
},
|
|
data: enterprise.instantHistory,
|
|
},
|
|
],
|
|
};
|
|
|
|
// Cumulative Chart (Bar)
|
|
var optionCumulative = {
|
|
tooltip: { trigger: "axis" },
|
|
grid: {
|
|
left: "3%",
|
|
right: "4%",
|
|
bottom: "3%",
|
|
top: "15%",
|
|
containLabel: true,
|
|
},
|
|
xAxis: {
|
|
type: "category",
|
|
data: days,
|
|
axisLabel: { color: "#ccc" },
|
|
axisLine: { lineStyle: { color: "#ffaa00" } },
|
|
},
|
|
yAxis: {
|
|
type: "value",
|
|
axisLabel: { color: "#ccc" },
|
|
splitLine: { lineStyle: { color: "rgba(255,255,255,0.1)" } },
|
|
},
|
|
series: [
|
|
{
|
|
name: "累计流量",
|
|
type: "bar",
|
|
itemStyle: {
|
|
normal: { color: "#ffaa00", barBorderRadius: [5, 5, 0, 0] },
|
|
},
|
|
data: enterprise.cumulativeHistory,
|
|
},
|
|
],
|
|
};
|
|
|
|
myChartInstant.setOption(optionInstant);
|
|
myChartCumulative.setOption(optionCumulative);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|