大屏数据展示
This commit is contained in:
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
};
|
||||
12
package.json
12
package.json
@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "sipaiis-wms-root",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.6.6",
|
||||
"@commitlint/config-conventional": "^17.6.6",
|
||||
"husky": "^8.0.3"
|
||||
}
|
||||
}
|
||||
25
pom.xml
25
pom.xml
@ -1,4 +1,4 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>TGLW</groupId>
|
||||
@ -272,6 +272,7 @@
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@ -698,6 +699,12 @@
|
||||
<groupId>org.apache.axis2</groupId>
|
||||
<artifactId>axis2-kernel</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.axis2</groupId>
|
||||
@ -840,6 +847,22 @@
|
||||
<overwrite>true</overwrite>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Jetty Plugin for Hot Deployment (Servlet 3.1 support for Spring 5) -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>9.4.43.v20210629</version>
|
||||
<configuration>
|
||||
<httpConnector>
|
||||
<port>8088</port>
|
||||
</httpConnector>
|
||||
<scanIntervalSeconds>5</scanIntervalSeconds>
|
||||
<webApp>
|
||||
<contextPath>/</contextPath>
|
||||
</webApp>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -1,21 +1,21 @@
|
||||
#redis<69><73><EFBFBD><EFBFBD>
|
||||
#redis.host=122.51.194.184
|
||||
redis.host=127.0.0.1
|
||||
#<23><><EFBFBD><EFBFBD>single <20><>Ⱥcluster
|
||||
#redis<69><73><EFBFBD><EFBFBD>
|
||||
redis.host=122.51.194.184
|
||||
# redis.host=127.0.0.1
|
||||
#<23><><EFBFBD><EFBFBD>single <20><>Ⱥcluster
|
||||
redis.mode=single
|
||||
#redis.port=26739
|
||||
redis.port=6379
|
||||
redis.port=26739
|
||||
# redis.port=6379
|
||||
redis.password=Aa112211
|
||||
redis.maxIdle=100
|
||||
redis.maxActive=300
|
||||
redis.maxWait=1000
|
||||
redis.testOnBorrow=true
|
||||
redis.timeout=100000
|
||||
# <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>뻺<EFBFBD><EBBBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
# <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>뻺<EFBFBD><EBBBBA><EFBFBD><EFBFBD><EFBFBD>
|
||||
targetNames=xxxRecordManager,xxxSetRecordManager,xxxStatisticsIdentificationManager
|
||||
# <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD>
|
||||
# <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD>
|
||||
methodNames=
|
||||
#<23><><EFBFBD>û<EFBFBD><C3BB><EFBFBD>ʧЧʱ<D0A7><CAB1>
|
||||
#<23><><EFBFBD>û<EFBFBD><C3BB><EFBFBD>ʧЧʱ<D0A7><CAB1>
|
||||
com.service.impl.xxxRecordManager= 60
|
||||
com.service.impl.xxxSetRecordManager= 60
|
||||
defaultCacheExpireTime=3600
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 MiB After Width: | Height: | Size: 22 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 11 MiB After Width: | Height: | Size: 13 MiB |
@ -1,599 +0,0 @@
|
||||
<%@ 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="<%=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%;
|
||||
background-color: #030829;
|
||||
overflow: auto;
|
||||
}
|
||||
.screen-container {
|
||||
width: 6500px;
|
||||
height: 1800px;
|
||||
background-image: url('<%=request.getContextPath()%>/IMG/screen1.png');
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Common Text Styles */
|
||||
.text-white { color: #ffffff; }
|
||||
.text-blue { color: #00eaff; }
|
||||
.text-yellow { color: #ffaa00; }
|
||||
.text-green { color: #00ff00; }
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 130px;
|
||||
}
|
||||
.header-weather {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 40px;
|
||||
font-size: 48px;
|
||||
color: #00eaff;
|
||||
}
|
||||
.header-title {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 20px;
|
||||
transform: translateX(-50%);
|
||||
font-size: 80px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
text-shadow: 0 0 20px #00aaff;
|
||||
letter-spacing: 10px;
|
||||
}
|
||||
.header-time {
|
||||
position: absolute;
|
||||
right: 100px;
|
||||
top: 40px;
|
||||
font-size: 48px;
|
||||
color: #00eaff;
|
||||
}
|
||||
|
||||
/* --- LEFT COLUMN (0 - 1400) --- */
|
||||
|
||||
/* Section Titles */
|
||||
.section-header-small {
|
||||
position: absolute;
|
||||
font-size: 32px;
|
||||
color: #00eaff;
|
||||
font-weight: bold;
|
||||
padding-left: 20px;
|
||||
border-left: 6px solid #00eaff;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
/* Water Trend Circles */
|
||||
.water-trend-row {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 220px;
|
||||
width: 1350px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.circle-metric {
|
||||
text-align: center;
|
||||
width: 300px;
|
||||
}
|
||||
.circle-metric .val { font-size: 64px; font-weight: bold; color: white; }
|
||||
.circle-metric .label { font-size: 32px; color: #00eaff; margin-top: 10px; }
|
||||
|
||||
/* 7-Day Chart */
|
||||
.chart-7day-container {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 550px;
|
||||
width: 1350px;
|
||||
height: 450px;
|
||||
}
|
||||
|
||||
/* Sludge Metrics */
|
||||
.sludge-metrics-row {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 1120px;
|
||||
width: 1350px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.sludge-metric {
|
||||
text-align: center;
|
||||
background: rgba(0, 50, 150, 0.2);
|
||||
padding: 20px;
|
||||
width: 30%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.sludge-metric .val { font-size: 56px; color: white; }
|
||||
.sludge-metric .label { font-size: 28px; color: #00eaff; }
|
||||
|
||||
/* Sludge Chart */
|
||||
.chart-sludge-container {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 1350px;
|
||||
width: 1350px;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
/* --- MID-LEFT COLUMN (1450 - 2850) --- */
|
||||
|
||||
/* Chemicals */
|
||||
.chem-container {
|
||||
position: absolute;
|
||||
left: 1480px;
|
||||
top: 220px;
|
||||
width: 1350px;
|
||||
height: 250px;
|
||||
display: flex;
|
||||
}
|
||||
.chem-boxes {
|
||||
width: 60%;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
.chem-box {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
}
|
||||
.chem-box.yellow { border: 2px solid #ffaa00; background: rgba(255, 170, 0, 0.1); }
|
||||
.chem-box.green { border: 2px solid #00ff00; background: rgba(0, 255, 0, 0.1); }
|
||||
.chem-box.blue { border: 2px solid #00eaff; background: rgba(0, 234, 255, 0.1); }
|
||||
|
||||
.chem-val { font-size: 48px; font-weight: bold; }
|
||||
.chem-label { font-size: 24px; margin-top: 10px; }
|
||||
|
||||
.chem-list {
|
||||
width: 40%;
|
||||
padding-left: 20px;
|
||||
font-size: 24px;
|
||||
color: #00eaff;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.chem-list-item { display: flex; justify-content: space-between; }
|
||||
.chem-list-val { color: white; }
|
||||
|
||||
/* Quality Table */
|
||||
.quality-table-container {
|
||||
position: absolute;
|
||||
left: 1480px;
|
||||
top: 580px;
|
||||
width: 1350px;
|
||||
}
|
||||
.q-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 28px;
|
||||
text-align: center;
|
||||
}
|
||||
.q-table th { background: rgba(0, 80, 200, 0.4); color: #00eaff; padding: 15px; }
|
||||
.q-table td { border-bottom: 1px solid rgba(0, 80, 200, 0.3); color: white; padding: 15px; }
|
||||
|
||||
/* Quality Chart */
|
||||
.chart-quality-container {
|
||||
position: absolute;
|
||||
left: 1480px;
|
||||
top: 1200px;
|
||||
width: 1350px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
/* --- CENTER COLUMN (2900 - 4600) --- */
|
||||
|
||||
/* Center Items (Scattered) */
|
||||
.center-point {
|
||||
position: absolute;
|
||||
background: rgba(0, 20, 50, 0.6);
|
||||
border: 1px solid #0055aa;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.center-point::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #00eaff;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 10px #00eaff;
|
||||
}
|
||||
/* Connectors can be simulated or assumed in BG. Here we just position the boxes. */
|
||||
|
||||
.cp-label { font-size: 24px; color: #00eaff; }
|
||||
.cp-val { font-size: 32px; color: white; font-weight: bold; }
|
||||
|
||||
/* Specific Positions */
|
||||
.cp-1 { left: 2950px; top: 500px; } /* 泵房液位 */
|
||||
.cp-2 { left: 2900px; top: 700px; } /* 进水泵房1#电流 */
|
||||
.cp-3 { left: 2980px; top: 900px; } /* 进水泵房2#电流 */
|
||||
.cp-4 { left: 3100px; top: 1100px; } /* 进水泵房3#流量 */
|
||||
.cp-5 { left: 3200px; top: 1300px; } /* 外回流泵1#流量 */
|
||||
|
||||
.cp-6 { left: 4300px; top: 500px; } /* 外回流泵2#液位 */
|
||||
.cp-7 { left: 4350px; top: 700px; } /* 生化池剩余污泥泵 */
|
||||
.cp-8 { left: 4250px; top: 900px; } /* 沉淀池剩余污泥泵 */
|
||||
.cp-9 { left: 4150px; top: 1100px; } /* PAC加药流量 */
|
||||
.cp-10 { left: 4050px; top: 1300px; } /* PAC储罐液位 */
|
||||
|
||||
/* --- RIGHT DATA COLUMN (4650 - 5450) --- */
|
||||
|
||||
.right-data-col {
|
||||
position: absolute;
|
||||
left: 4680px;
|
||||
top: 220px;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
.section-block {
|
||||
margin-bottom: 40px;
|
||||
background: rgba(0, 20, 50, 0.3);
|
||||
padding: 20px;
|
||||
border-left: 5px solid #00eaff;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 36px;
|
||||
color: #00eaff;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.data-grid-2col {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.data-item {
|
||||
width: 50%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.data-item-label { font-size: 24px; color: #aaaaff; }
|
||||
.data-item-val { font-size: 32px; color: #00eaff; }
|
||||
|
||||
/* --- RIGHT VIDEO COLUMN (5500 - 6450) --- */
|
||||
.video-container {
|
||||
position: absolute;
|
||||
left: 5520px;
|
||||
top: 220px;
|
||||
width: 950px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
}
|
||||
.video-box {
|
||||
width: 460px;
|
||||
height: 280px;
|
||||
background: black;
|
||||
border: 2px solid #0055aa;
|
||||
position: relative;
|
||||
}
|
||||
.play-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 48px;
|
||||
color: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="screen-container">
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<div class="header-weather">上海 ☁️ 大雨 17-28℃</div>
|
||||
<div class="header-title">金山卫污水厂数据大屏</div>
|
||||
<div class="header-time" id="headerTime">2021.12.02 星期三 15:20:33</div>
|
||||
</div>
|
||||
|
||||
<!-- Left Column -->
|
||||
<div class="section-header-small" style="top: 150px; left: 50px;">水量趋势</div>
|
||||
<div class="water-trend-row">
|
||||
<div class="circle-metric">
|
||||
<div class="val">6040</div>
|
||||
<div class="label">今日处理</div>
|
||||
</div>
|
||||
<div class="circle-metric">
|
||||
<div class="val">4197</div>
|
||||
<div class="label">昨日处理</div>
|
||||
</div>
|
||||
<div class="circle-metric">
|
||||
<div class="val">12356</div>
|
||||
<div class="label">本月累计</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-header-small" style="top: 480px; left: 50px;">七日水量处理情况</div>
|
||||
<div class="chart-7day-container" id="chartWater"></div>
|
||||
|
||||
<div class="section-header-small" style="top: 1050px; left: 50px;">污泥处理指标</div>
|
||||
<div class="sludge-metrics-row">
|
||||
<div class="sludge-metric">
|
||||
<div class="val">0 m³</div>
|
||||
<div class="label">昨日产泥量</div>
|
||||
</div>
|
||||
<div class="sludge-metric">
|
||||
<div class="val">253 m³</div>
|
||||
<div class="label">今日产泥量</div>
|
||||
</div>
|
||||
<div class="sludge-metric">
|
||||
<div class="val">4.89 m</div>
|
||||
<div class="label">今日泥位</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-sludge-container" id="chartSludge"></div>
|
||||
|
||||
<!-- Mid-Left Column -->
|
||||
<div class="section-header-small" style="top: 150px; left: 1480px;">药耗</div>
|
||||
<div class="chem-container">
|
||||
<div class="chem-boxes">
|
||||
<div class="chem-box yellow">
|
||||
<div class="chem-label">PAC投加药耗</div>
|
||||
<div class="chem-val text-yellow">39.54</div>
|
||||
</div>
|
||||
<div class="chem-box green">
|
||||
<div class="chem-label">乙酸钠投加药耗</div>
|
||||
<div class="chem-val text-green">56.98</div>
|
||||
</div>
|
||||
<div class="chem-box blue">
|
||||
<div class="chem-label">次氯酸钠投加</div>
|
||||
<div class="chem-val text-blue">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chem-list">
|
||||
<div class="chem-list-item"><span>厌氧池ORP</span><span class="chem-list-val">-370 mV</span></div>
|
||||
<div class="chem-list-item"><span>缺氧池溶解氧1</span><span class="chem-list-val">0.05 mg/L</span></div>
|
||||
<div class="chem-list-item"><span>1#好氧池溶解氧</span><span class="chem-list-val">0.52 mg/L</span></div>
|
||||
<div class="chem-list-item"><span>2#好氧池溶解氧</span><span class="chem-list-val">0.40 mg/L</span></div>
|
||||
<div class="chem-list-item"><span>污泥浓度MLSS</span><span class="chem-list-val">1921 mg/L</span></div>
|
||||
<div class="chem-list-item"><span>混合液回流泵</span><span class="chem-list-val">8340 mg/L</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-header-small" style="top: 520px; left: 1480px;">质量指标</div>
|
||||
<div class="quality-table-container">
|
||||
<table class="q-table">
|
||||
<thead>
|
||||
<tr><th>参数</th><th>当前值</th><th>平均值</th><th>最高</th><th>最低</th><th>指标</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>COD (mg/L)</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td>0.000-20.000</td></tr>
|
||||
<tr><td>TP (mg/L)</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td>0.000-20.000</td></tr>
|
||||
<tr><td>NH3-N (mg/L)</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td>0.000-20.000</td></tr>
|
||||
<tr><td>TN (mg/L)</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td>0.000-20.000</td></tr>
|
||||
<tr><td>PH (mg/L)</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td>0.000-20.000</td></tr>
|
||||
<tr><td>SS</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td></td></tr>
|
||||
<tr><td>温度(°C)</td><td>13.106</td><td>12.996</td><td>14.656</td><td>11.92</td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="chart-quality-container" id="chartQuality"></div>
|
||||
|
||||
<!-- Center Column -->
|
||||
<div class="center-point cp-1">
|
||||
<div class="cp-label">泵房液位</div>
|
||||
<div class="cp-val">6.13 m</div>
|
||||
</div>
|
||||
<div class="center-point cp-2">
|
||||
<div class="cp-label">进水泵房1#电流</div>
|
||||
<div class="cp-val">66.6 A</div>
|
||||
</div>
|
||||
<div class="center-point cp-3">
|
||||
<div class="cp-label">进水泵房2#电流</div>
|
||||
<div class="cp-val">63.1 A</div>
|
||||
</div>
|
||||
<div class="center-point cp-4">
|
||||
<div class="cp-label">进水泵房3#流量</div>
|
||||
<div class="cp-val">2.84 L/s</div>
|
||||
</div>
|
||||
<div class="center-point cp-5">
|
||||
<div class="cp-label">外回流泵1#流量</div>
|
||||
<div class="cp-val">13.02 L/s</div>
|
||||
</div>
|
||||
|
||||
<div class="center-point cp-6">
|
||||
<div class="cp-label">外回流泵2#液位</div>
|
||||
<div class="cp-val">0.75 m</div>
|
||||
</div>
|
||||
<div class="center-point cp-7">
|
||||
<div class="cp-label">生化池剩余污泥泵</div>
|
||||
<div class="cp-val">0 m</div>
|
||||
</div>
|
||||
<div class="center-point cp-8">
|
||||
<div class="cp-label">沉淀池剩余污泥泵</div>
|
||||
<div class="cp-val">9.01 L/s</div>
|
||||
</div>
|
||||
<div class="center-point cp-9">
|
||||
<div class="cp-label">PAC加药流量</div>
|
||||
<div class="cp-val">1.03 L/s</div>
|
||||
</div>
|
||||
<div class="center-point cp-10">
|
||||
<div class="cp-label">PAC储罐液位</div>
|
||||
<div class="cp-val">4.2 m</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Data Column -->
|
||||
<div class="right-data-col">
|
||||
<div class="section-block">
|
||||
<div class="section-title">进水</div>
|
||||
<div class="data-grid-2col">
|
||||
<div class="data-item"><div class="data-item-label">进水流量</div><div class="data-item-val">1360 m³/h</div></div>
|
||||
<div class="data-item"><div class="data-item-label">进水PH</div><div class="data-item-val">6.75</div></div>
|
||||
<div class="data-item"><div class="data-item-label">进水COD</div><div class="data-item-val">82.4 mg/L</div></div>
|
||||
<div class="data-item"><div class="data-item-label">进水氨氮</div><div class="data-item-val">15.30 mg/L</div></div>
|
||||
<div class="data-item"><div class="data-item-label">进水温度</div><div class="data-item-val">25.87 °C</div></div>
|
||||
<div class="data-item"><div class="data-item-label">进水累计流量</div><div class="data-item-val">1761406 m³</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title">出水</div>
|
||||
<div class="data-grid-2col">
|
||||
<div class="data-item"><div class="data-item-label">出水流量</div><div class="data-item-val">2451.64 m³/h</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水PH</div><div class="data-item-val">6.95</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水COD</div><div class="data-item-val">62.4 mg/L</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水氨氮</div><div class="data-item-val">15.18 mg/L</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水温度</div><div class="data-item-val">25.87 °C</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水总磷</div><div class="data-item-val">25.87</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水总氮</div><div class="data-item-val">25.87</div></div>
|
||||
<div class="data-item"><div class="data-item-label">出水累计流量</div><div class="data-item-val">1761406 m³</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title">其他</div>
|
||||
<div class="data-grid-2col">
|
||||
<div class="data-item"><div class="data-item-label">反冲洗泵1#电流</div><div class="data-item-val">6.72 m³/h</div></div>
|
||||
<div class="data-item"><div class="data-item-label">反冲洗泵2#压力</div><div class="data-item-val">66.67 MPa</div></div>
|
||||
<div class="data-item"><div class="data-item-label">剩余污泥泵1#流量</div><div class="data-item-val">71.34 m³/h</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title">液位</div>
|
||||
<div class="data-grid-2col">
|
||||
<div class="data-item"><div class="data-item-label">清水池液位</div><div class="data-item-val">5.05 m</div></div>
|
||||
<div class="data-item"><div class="data-item-label">深床滤池液位</div><div class="data-item-val">4.03 m</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Video Column -->
|
||||
<div class="video-container">
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
<div class="video-box"><div class="play-icon">▶</div></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
initCharts();
|
||||
updateTime();
|
||||
setInterval(updateTime, 1000);
|
||||
|
||||
document.ondblclick = function() {
|
||||
var docElm = document.documentElement;
|
||||
if (docElm.requestFullscreen) {
|
||||
docElm.requestFullscreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function updateTime() {
|
||||
var now = new Date();
|
||||
var timeStr = now.getFullYear() + '.' + (now.getMonth()+1) + '.' + now.getDate() + ' 星期三 ' +
|
||||
now.getHours() + ':' + (now.getMinutes()<10?'0':'') + now.getMinutes() + ':' + (now.getSeconds()<10?'0':'') + now.getSeconds();
|
||||
document.getElementById('headerTime').innerHTML = timeStr;
|
||||
}
|
||||
|
||||
function initCharts() {
|
||||
// Water Chart (7-Day)
|
||||
var waterChart = echarts.init(document.getElementById('chartWater'));
|
||||
var waterOption = {
|
||||
color: ['#00eaff'],
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { top: '10%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['11-10', '11-11', '11-12', '11-13', '11-14', '11-15', '11-16'],
|
||||
axisLabel: { color: '#fff', fontSize: 24 },
|
||||
axisLine: { lineStyle: { color: '#0055aa' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 24 },
|
||||
splitLine: { show: false },
|
||||
axisLine: { show: false }
|
||||
},
|
||||
series: [{
|
||||
data: [3000, 4200, 3500, 3800, 5000, 4800, 5200],
|
||||
type: 'bar',
|
||||
barWidth: '20px',
|
||||
itemStyle: { normal: { barBorderRadius: [10, 10, 0, 0] } }
|
||||
}]
|
||||
};
|
||||
waterChart.setOption(waterOption);
|
||||
|
||||
// Sludge Chart (Area)
|
||||
var sludgeChart = echarts.init(document.getElementById('chartSludge'));
|
||||
var sludgeOption = {
|
||||
color: ['#00ffaa'],
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { top: '10%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['2:00', '4:00', '6:00', '8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00'],
|
||||
axisLabel: { color: '#fff', fontSize: 20 },
|
||||
axisLine: { lineStyle: { color: '#0055aa' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 20 },
|
||||
splitLine: { show: false },
|
||||
axisLine: { show: false }
|
||||
},
|
||||
series: [{
|
||||
data: [50, 80, 60, 120, 150, 140, 130, 160, 180, 100],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: { opacity: 0.3 }
|
||||
}]
|
||||
};
|
||||
sludgeChart.setOption(sludgeOption);
|
||||
|
||||
// Quality Chart (Line)
|
||||
var qualityChart = echarts.init(document.getElementById('chartQuality'));
|
||||
var qualityOption = {
|
||||
color: ['#00aaff'],
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { top: '10%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['11', '12', '13', '14', '15', '16', '17', '18', '19'],
|
||||
axisLabel: { color: '#fff', fontSize: 20 },
|
||||
axisLine: { lineStyle: { color: '#0055aa' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 20 },
|
||||
splitLine: { show: false },
|
||||
axisLine: { show: false }
|
||||
},
|
||||
series: [{
|
||||
data: [15, 18, 16, 20, 22, 21, 25, 24, 23],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: { opacity: 0.3 }
|
||||
}]
|
||||
};
|
||||
qualityChart.setOption(qualityOption);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -13,8 +13,6 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: #030829;
|
||||
font-family: "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
.screen-container {
|
||||
width: 6500px;
|
||||
@ -24,311 +22,436 @@
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Module Container */
|
||||
.rank-module-container {
|
||||
.stat-card {
|
||||
position: absolute;
|
||||
top: 356px;
|
||||
left: 198px;
|
||||
width: 1900px;
|
||||
height: 1400px;
|
||||
/* background: rgba(255, 0, 0, 0.1); Debugging background */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
top: 257px;
|
||||
/* left: 1910px; */
|
||||
width: 200px;
|
||||
height: 71px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-family: Gilroy;
|
||||
font-weight: 500;
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.card-1 { left: 1910px; }
|
||||
.card-2 { left: 2832px; }
|
||||
.card-3 { left: 3754px; }
|
||||
|
||||
.ring-chart-wrapper {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 1880px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.pie-chart-wrapper-2 {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 2572px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.gauge-chart-wrapper-3 {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 3264px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.gauge-chart-wrapper-4 {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 3956px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.bar-chart-wrapper-5 {
|
||||
position: absolute;
|
||||
top: 1158px;
|
||||
left: 1881px;
|
||||
width: 1353px;
|
||||
height: 592px;
|
||||
}
|
||||
.bar-chart-wrapper-6 {
|
||||
position: absolute;
|
||||
top: 1158px;
|
||||
left: 3265px;
|
||||
width: 1353px;
|
||||
height: 592px;
|
||||
}
|
||||
.ring-chart-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.4;
|
||||
mix-blend-mode: normal;
|
||||
/* border: 1px solid rgba(27, 126, 242, 1); */
|
||||
box-sizing: border-box;
|
||||
/* background: rgba(27, 126, 242, 0.6); */
|
||||
}
|
||||
|
||||
/* Statistics Header */
|
||||
.stats-header {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
background: rgba(0, 20, 50, 0.3);
|
||||
border: 1px solid rgba(0, 234, 255, 0.2);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 30px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 32px;
|
||||
color: #00eaff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 64px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
font-family: 'DIN Alternate', 'Arial Narrow', sans-serif;
|
||||
text-shadow: 0 0 20px rgba(0, 234, 255, 0.5);
|
||||
}
|
||||
|
||||
.stat-unit {
|
||||
font-size: 24px;
|
||||
color: #aaaaaa;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* Charts Area */
|
||||
.charts-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.chart-box {
|
||||
flex: 1;
|
||||
background: rgba(0, 20, 50, 0.3);
|
||||
border: 1px solid rgba(0, 234, 255, 0.2);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 36px;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid rgba(0, 234, 255, 0.2);
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
flex: 1;
|
||||
#ring-chart-content, #pie-chart-content-2, #gauge-chart-content-3, #gauge-chart-content-4, #bar-chart-content-5, #bar-chart-content-6 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
|
||||
<!-- Charts -->
|
||||
<div class="charts-wrapper">
|
||||
<div class="chart-box">
|
||||
<div class="chart-title">近30日排污量 TOP 10 (最大)</div>
|
||||
<div id="chartMax" class="chart-content"></div>
|
||||
</div>
|
||||
<div class="chart-box">
|
||||
<div class="chart-title">近30日排污量 TOP 10 (最小)</div>
|
||||
<div id="chartMin" class="chart-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card card-1">53829.5</div>
|
||||
<div class="stat-card card-2">2495</div>
|
||||
<div class="stat-card card-3">2460</div>
|
||||
|
||||
<div class="ring-chart-wrapper">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="ring-chart-content"></div>
|
||||
</div>
|
||||
|
||||
<div class="pie-chart-wrapper-2">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="pie-chart-content-2"></div>
|
||||
</div>
|
||||
|
||||
<div class="gauge-chart-wrapper-3">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="gauge-chart-content-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="gauge-chart-wrapper-4">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="gauge-chart-content-4"></div>
|
||||
</div>
|
||||
|
||||
<div class="bar-chart-wrapper-5">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="bar-chart-content-5"></div>
|
||||
</div>
|
||||
|
||||
<div class="bar-chart-wrapper-6">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="bar-chart-content-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
initData();
|
||||
launchIntoFullscreen(document.documentElement);
|
||||
initPieChart();
|
||||
initPieChart2();
|
||||
initGaugeChart('gauge-chart-content-3', 53829.5);
|
||||
initGaugeChart('gauge-chart-content-4', 12345.6);
|
||||
initBarChart('bar-chart-content-5', [3000, 4500, 1500, 5000, 23000, 1500, 15000, 3000, 4000, 5000, 2000, 1000, 500, 2563, 4000]);
|
||||
initBarChart('bar-chart-content-6', [2000, 3000, 1000, 4000, 18000, 1000, 12000, 2000, 3000, 4000, 1500, 800, 400, 2000, 3000]);
|
||||
|
||||
// Double click to toggle fullscreen
|
||||
$('body').on('dblclick', function() {
|
||||
launchIntoFullscreen(document.documentElement);
|
||||
});
|
||||
});
|
||||
|
||||
function initData() {
|
||||
// Mock Data Generation
|
||||
var enterprises = [];
|
||||
var total = 158;
|
||||
var connected = 124;
|
||||
var connecting = 34;
|
||||
|
||||
// Update Stats
|
||||
$('#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 random enterprise data
|
||||
for (var i = 1; i <= 50; i++) {
|
||||
enterprises.push({
|
||||
name: '企业-' + i,
|
||||
value: Math.floor(Math.random() * 10000) + 500
|
||||
});
|
||||
}
|
||||
|
||||
// Sort for Max
|
||||
var sortedMax = [...enterprises].sort((a, b) => b.value - a.value).slice(0, 10);
|
||||
|
||||
// Sort for Min
|
||||
var sortedMin = [...enterprises].sort((a, b) => a.value - b.value).slice(0, 10);
|
||||
|
||||
renderCharts(sortedMax, sortedMin);
|
||||
function initPieChart() {
|
||||
var chartDom = document.getElementById('ring-chart-content');
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
color: [
|
||||
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc',
|
||||
'#00d4ff', '#ffb700', '#2bff89', '#915eff', '#ff7f00'
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '管线类型统计',
|
||||
type: 'pie',
|
||||
radius: '55%',
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: true,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: '{b}',
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
align: 'left'
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 20,
|
||||
length2: 30,
|
||||
lineStyle: {
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{ value: 335, name: 'II级钢筋混凝土管 承插接口' },
|
||||
{ value: 310, name: '焊接钢管 焊接接口' },
|
||||
{ value: 274, name: '高密度聚乙烯双壁波纹管' },
|
||||
{ value: 235, name: '聚乙烯PE管' },
|
||||
{ value: 200, name: 'II级钢筋混凝土管' },
|
||||
{ value: 180, name: '高密度聚乙烯缠绕管' },
|
||||
{ value: 150, name: '焊接钢管 焊接连接' },
|
||||
{ value: 140, name: '高密度聚乙烯中空壁缠绕管' },
|
||||
{ value: 130, name: '钢筋混凝土管' },
|
||||
{ value: 110, name: '球墨铸铁管' },
|
||||
{ value: 100, name: '预应力钢筒混凝土管' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
function renderCharts(maxData, minData) {
|
||||
var chartMax = echarts.init(document.getElementById('chartMax'));
|
||||
var chartMin = echarts.init(document.getElementById('chartMin'));
|
||||
|
||||
// Max Option
|
||||
var optionMax = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' }
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 16 },
|
||||
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.1)' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: maxData.map(item => item.name).reverse(),
|
||||
axisLabel: { color: '#fff', fontSize: 18 },
|
||||
axisLine: { lineStyle: { color: '#00eaff' } }
|
||||
},
|
||||
series: [{
|
||||
name: '排污量',
|
||||
type: 'bar',
|
||||
data: maxData.map(item => item.value).reverse(),
|
||||
label: { show: true, position: 'right', color: '#fff', fontSize: 16 },
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
|
||||
offset: 0, color: '#ff5500'
|
||||
}, {
|
||||
offset: 1, color: '#ffbb00'
|
||||
}]),
|
||||
barBorderRadius: [0, 10, 10, 0]
|
||||
}
|
||||
},
|
||||
barWidth: 40,
|
||||
animationDuration: 2000,
|
||||
animationEasing: 'cubicOut'
|
||||
}]
|
||||
function initPieChart2() {
|
||||
var chartDom = document.getElementById('pie-chart-content-2');
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
color: [
|
||||
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc',
|
||||
'#00d4ff', '#ffb700', '#2bff89', '#915eff', '#ff7f00'
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '管线类型统计2',
|
||||
type: 'pie',
|
||||
radius: '55%',
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: true,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: '{b}',
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
align: 'left'
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 20,
|
||||
length2: 30,
|
||||
lineStyle: {
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{ value: 335, name: 'II级钢筋混凝土管 承插接口' },
|
||||
{ value: 310, name: '焊接钢管 焊接接口' },
|
||||
{ value: 274, name: '高密度聚乙烯双壁波纹管' },
|
||||
{ value: 235, name: '聚乙烯PE管' },
|
||||
{ value: 200, name: 'II级钢筋混凝土管' },
|
||||
{ value: 180, name: '高密度聚乙烯缠绕管' },
|
||||
{ value: 150, name: '焊接钢管 焊接连接' },
|
||||
{ value: 140, name: '高密度聚乙烯中空壁缠绕管' },
|
||||
{ value: 130, name: '钢筋混凝土管' },
|
||||
{ value: 110, name: '球墨铸铁管' },
|
||||
{ value: 100, name: '预应力钢筒混凝土管' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
// Min Option
|
||||
var optionMin = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' }
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 16 },
|
||||
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.1)' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: minData.map(item => item.name).reverse(),
|
||||
axisLabel: { color: '#fff', fontSize: 18 },
|
||||
axisLine: { lineStyle: { color: '#00eaff' } }
|
||||
},
|
||||
series: [{
|
||||
name: '排污量',
|
||||
type: 'bar',
|
||||
data: minData.map(item => item.value).reverse(),
|
||||
label: { show: true, position: 'right', color: '#fff', fontSize: 16 },
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
|
||||
offset: 0, color: '#00aa00'
|
||||
}, {
|
||||
offset: 1, color: '#00ff00'
|
||||
}]),
|
||||
barBorderRadius: [0, 10, 10, 0]
|
||||
}
|
||||
},
|
||||
barWidth: 40,
|
||||
animationDuration: 2000,
|
||||
animationEasing: 'cubicOut'
|
||||
}]
|
||||
function initGaugeChart(domId, value) {
|
||||
var chartDom = document.getElementById(domId);
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
series: [
|
||||
{
|
||||
type: 'gauge',
|
||||
startAngle: 180,
|
||||
endAngle: 0,
|
||||
min: 0,
|
||||
max: 300,
|
||||
splitNumber: 6,
|
||||
radius: '90%',
|
||||
center: ['50%', '70%'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 40,
|
||||
color: [[1, new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
{ offset: 0, color: 'rgba(65, 108, 243, 1)' },
|
||||
{ offset: 1, color: 'rgba(0, 68, 160, 1)' }
|
||||
])]]
|
||||
}
|
||||
},
|
||||
pointer: {
|
||||
show: true,
|
||||
length: '60%',
|
||||
width: 6,
|
||||
itemStyle: {
|
||||
color: '#00d4ff'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#00d4ff',
|
||||
fontSize: 14,
|
||||
distance: -60,
|
||||
formatter: function (value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
show: true,
|
||||
offsetCenter: [0, '40%'],
|
||||
fontSize: 30,
|
||||
color: '#fff',
|
||||
formatter: '{value} m'
|
||||
},
|
||||
data: [{
|
||||
value: value,
|
||||
name: ''
|
||||
}]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartMax.setOption(optionMax);
|
||||
chartMin.setOption(optionMin);
|
||||
|
||||
// Dynamic Sort Simulation (Update every 3 seconds)
|
||||
setInterval(function() {
|
||||
// Randomly change values slightly
|
||||
maxData.forEach(item => {
|
||||
item.value += Math.floor(Math.random() * 200) - 100;
|
||||
if(item.value < 0) item.value = 0;
|
||||
});
|
||||
|
||||
// Re-sort
|
||||
maxData.sort((a, b) => a.value - b.value); // For horizontal bar, small index is bottom. ECharts draws category 0 at bottom.
|
||||
// Actually in my code I used reverse() so data is Top to Bottom visually if array is Descending.
|
||||
// Let's keep data array as Ascending (Small -> Large) so index 0 is at bottom (or top depending on axis inverse).
|
||||
// Default category axis: index 0 at bottom.
|
||||
// If I want Top 1 at top, I need index 0 to be the smallest value (if not inverse) or configure axis.
|
||||
// In previous code: data: maxData.map(item => item.name).reverse()
|
||||
// If maxData was sorted Descending (Large -> Small), then reverse makes it Small -> Large.
|
||||
// So index 0 (bottom) is Smallest of the top 10. Index 9 (top) is Largest. Correct.
|
||||
|
||||
// Let's just re-sort the source array Descending
|
||||
maxData.sort((a, b) => b.value - a.value);
|
||||
|
||||
// Update chart
|
||||
chartMax.setOption({
|
||||
yAxis: {
|
||||
data: maxData.map(item => item.name).reverse()
|
||||
},
|
||||
series: [{
|
||||
data: maxData.map(item => item.value).reverse()
|
||||
}]
|
||||
});
|
||||
|
||||
// Do same for Min? Min usually doesn't fluctuate as much to swap "Top Min", but let's simulate.
|
||||
minData.forEach(item => {
|
||||
item.value += Math.floor(Math.random() * 50) - 25;
|
||||
if(item.value < 0) item.value = 0;
|
||||
});
|
||||
minData.sort((a, b) => a.value - b.value); // Small -> Large.
|
||||
// Display: I want Smallest at Top? Or Largest of the Smallest at Top?
|
||||
// Usually "Top 10 Min" means the 10 smallest values.
|
||||
// Visualizing: Smallest bar at Top.
|
||||
// If data is [1, 2, 3...], and I reverse it -> [..., 3, 2, 1].
|
||||
// Index 0 (bottom) = 10. Index 9 (top) = 1.
|
||||
// So I need the array to be sorted Small -> Large.
|
||||
// Then reverse it -> Large -> Small.
|
||||
// Then bottom (index 0) is Large. Top (index 9) is Small.
|
||||
// Correct.
|
||||
|
||||
chartMin.setOption({
|
||||
yAxis: {
|
||||
data: minData.map(item => item.name).reverse()
|
||||
},
|
||||
series: [{
|
||||
data: minData.map(item => item.value).reverse()
|
||||
}]
|
||||
});
|
||||
// Adjust value if it exceeds max for visual representation (optional)
|
||||
// For now, we just set the data value as is, but if it's large like 53829.5,
|
||||
// the pointer will be pegged at max.
|
||||
// If the gauge is just a visual indicator and the number is what matters:
|
||||
// Let's set the gauge pointer to max if value > 300
|
||||
if (value > 300) {
|
||||
option.series[0].data[0].value = 300; // Pointer at max
|
||||
option.series[0].detail.formatter = value + ' m'; // Show real value
|
||||
}
|
||||
|
||||
}, 3000);
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
function initBarChart(domId, data) {
|
||||
var chartDom = document.getElementById(domId);
|
||||
var myChart = echarts.init(chartDom);
|
||||
|
||||
// Find max value for markPoint (example logic)
|
||||
var maxVal = Math.max(...data);
|
||||
var minVal = Math.min(...data);
|
||||
|
||||
var option = {
|
||||
grid: {
|
||||
top: '20%',
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15'],
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.3)'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 14
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '长度(m)',
|
||||
nameTextStyle: {
|
||||
color: '#fff',
|
||||
padding: [0, 0, 0, 20]
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 14
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.1)'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: data,
|
||||
type: 'bar',
|
||||
barWidth: '40%',
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 170, 0, 0.4)',
|
||||
borderColor: '#ffaa00',
|
||||
borderWidth: 1
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'pin',
|
||||
symbolSize: 50,
|
||||
label: {
|
||||
show: true,
|
||||
color: '#fff',
|
||||
fontSize: 12
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#ffaa00'
|
||||
},
|
||||
data: [
|
||||
{ type: 'max', name: 'Max' },
|
||||
{ type: 'min', name: 'Min' }
|
||||
]
|
||||
},
|
||||
markLine: {
|
||||
symbol: 'none',
|
||||
data: [
|
||||
{ yAxis: 2563.31, name: 'Average' }
|
||||
],
|
||||
label: {
|
||||
show: true,
|
||||
position: 'end',
|
||||
formatter: '{c}',
|
||||
color: '#ffaa00'
|
||||
},
|
||||
lineStyle: {
|
||||
type: 'dotted',
|
||||
color: '#ffaa00'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>排污户大屏展示</title>
|
||||
<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;
|
||||
@ -11,6 +13,8 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: #030829;
|
||||
font-family: "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
.screen-container {
|
||||
width: 6500px;
|
||||
@ -20,10 +24,794 @@
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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;
|
||||
|
||||
$(document).ready(function() {
|
||||
launchIntoFullscreen(document.documentElement);
|
||||
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);
|
||||
var isHighlighted = (index === currentFocusIndex);
|
||||
var colorStart = isHighlighted ? '#ffffff' : '#ffaa00';
|
||||
var colorEnd = isHighlighted ? '#cccccc' : '#ff5500';
|
||||
|
||||
maxValues.push({
|
||||
value: item.value,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
|
||||
offset: 0, color: colorStart
|
||||
}, {
|
||||
offset: 1, color: colorEnd
|
||||
}])
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 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: '#00eaff'
|
||||
}, {
|
||||
offset: 1, color: '#0055ff'
|
||||
}])
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var option = {
|
||||
title: [{
|
||||
text: '近30天排污量最大 Top 10',
|
||||
left: 'center',
|
||||
top: '2%',
|
||||
textStyle: { color: '#ffaa00', fontSize: 24, fontWeight: 'bold' }
|
||||
}, {
|
||||
text: '近30天排污量最小 Top 10',
|
||||
left: 'center',
|
||||
top: '52%',
|
||||
textStyle: { color: '#00eaff', fontSize: 24, fontWeight: 'bold' }
|
||||
}],
|
||||
grid: [{
|
||||
top: '10%',
|
||||
left: '5%',
|
||||
right: '10%',
|
||||
bottom: '53%',
|
||||
containLabel: true
|
||||
}, {
|
||||
top: '60%',
|
||||
left: '5%',
|
||||
right: '10%',
|
||||
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: 18 },
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
gridIndex: 0
|
||||
}, {
|
||||
type: 'category',
|
||||
data: minNames,
|
||||
inverse: true,
|
||||
axisLabel: { color: '#fff', fontSize: 18 },
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
gridIndex: 1
|
||||
}],
|
||||
series: [{
|
||||
name: 'Max',
|
||||
type: 'bar',
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
data: maxValues,
|
||||
barWidth: 30,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
textStyle: { color: '#ffaa00', fontSize: 18, fontWeight: 'bold' },
|
||||
formatter: '{c} m³'
|
||||
}
|
||||
},
|
||||
itemStyle: { normal: { barBorderRadius: [0, 15, 15, 0] } },
|
||||
animationDuration: 1000,
|
||||
animationDurationUpdate: 1000
|
||||
}, {
|
||||
name: 'Min',
|
||||
type: 'bar',
|
||||
xAxisIndex: 1,
|
||||
yAxisIndex: 1,
|
||||
data: minValues,
|
||||
barWidth: 30,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
textStyle: { color: '#00eaff', fontSize: 18, fontWeight: 'bold' },
|
||||
formatter: '{c} m³'
|
||||
}
|
||||
},
|
||||
itemStyle: { normal: { barBorderRadius: [0, 15, 15, 0] } },
|
||||
animationDuration: 1000,
|
||||
animationDurationUpdate: 1000
|
||||
}]
|
||||
};
|
||||
|
||||
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>
|
||||
|
||||
|
||||
67
src/main/webapp/jsp/z_bigScreen/bigScreen1.html
Normal file
67
src/main/webapp/jsp/z_bigScreen/bigScreen1.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>水厂大屏展示</title>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto; /* Allow scrolling if window is smaller */
|
||||
}
|
||||
.screen-container {
|
||||
width: 6500px;
|
||||
height: 1800px;
|
||||
background-image: url('../../IMG/screen1.png');
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
}
|
||||
/* Specific Position for Data 6040 */
|
||||
.val-6040 {
|
||||
position: absolute;
|
||||
top: 335px;
|
||||
left: 209px;
|
||||
width: 121px;
|
||||
height: 62px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-family: 'Gilroy', 'DIN Alternate', 'Arial Narrow', sans-serif;
|
||||
font-weight: 900;
|
||||
font-size: 50px;
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
line-height: 62px;
|
||||
}
|
||||
.val-4197 {
|
||||
top: 335px;
|
||||
left: 592px;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
display: inline-flex;
|
||||
place-content: flex-start;
|
||||
place-items: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
.val-12356 {
|
||||
top: 335px;
|
||||
left: 975px;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
display: inline-flex;
|
||||
place-content: flex-start;
|
||||
place-items: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="screen-container">
|
||||
<div class="val-6040">6040</div>
|
||||
<div class="val-4197">4197</div>
|
||||
<div class="val-12356">12356</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
455
src/main/webapp/jsp/z_bigScreen/bigScreen2.html
Normal file
455
src/main/webapp/jsp/z_bigScreen/bigScreen2.html
Normal file
@ -0,0 +1,455 @@
|
||||
<!-- <%@ 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="<%=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;
|
||||
}
|
||||
.screen-container {
|
||||
width: 6500px;
|
||||
height: 1800px;
|
||||
background-image: url('<%=request.getContextPath()%>/IMG/screen2.png');
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
}
|
||||
.stat-card {
|
||||
position: absolute;
|
||||
top: 257px;
|
||||
/* left: 1910px; */
|
||||
width: 200px;
|
||||
height: 71px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-family: Gilroy;
|
||||
font-weight: 500;
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.card-1 { left: 1910px; }
|
||||
.card-2 { left: 2832px; }
|
||||
.card-3 { left: 3754px; }
|
||||
|
||||
.ring-chart-wrapper {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 1880px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.pie-chart-wrapper-2 {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 2572px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.gauge-chart-wrapper-3 {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 3264px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.gauge-chart-wrapper-4 {
|
||||
position: absolute;
|
||||
top: 563px;
|
||||
left: 3956px;
|
||||
width: 662px;
|
||||
height: 455px;
|
||||
}
|
||||
.bar-chart-wrapper-5 {
|
||||
position: absolute;
|
||||
top: 1158px;
|
||||
left: 1881px;
|
||||
width: 1353px;
|
||||
height: 592px;
|
||||
}
|
||||
.bar-chart-wrapper-6 {
|
||||
position: absolute;
|
||||
top: 1158px;
|
||||
left: 3265px;
|
||||
width: 1353px;
|
||||
height: 592px;
|
||||
}
|
||||
.ring-chart-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.4;
|
||||
mix-blend-mode: normal;
|
||||
/* border: 1px solid rgba(27, 126, 242, 1); */
|
||||
box-sizing: border-box;
|
||||
/* background: rgba(27, 126, 242, 0.6); */
|
||||
}
|
||||
#ring-chart-content, #pie-chart-content-2, #gauge-chart-content-3, #gauge-chart-content-4, #bar-chart-content-5, #bar-chart-content-6 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="screen-container">
|
||||
<div class="stat-card card-1">53829.5</div>
|
||||
<div class="stat-card card-2">2495</div>
|
||||
<div class="stat-card card-3">2460</div>
|
||||
|
||||
<div class="ring-chart-wrapper">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="ring-chart-content"></div>
|
||||
</div>
|
||||
|
||||
<div class="pie-chart-wrapper-2">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="pie-chart-content-2"></div>
|
||||
</div>
|
||||
|
||||
<div class="gauge-chart-wrapper-3">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="gauge-chart-content-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="gauge-chart-wrapper-4">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="gauge-chart-content-4"></div>
|
||||
</div>
|
||||
|
||||
<div class="bar-chart-wrapper-5">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="bar-chart-content-5"></div>
|
||||
</div>
|
||||
|
||||
<div class="bar-chart-wrapper-6">
|
||||
<div class="ring-chart-bg"></div>
|
||||
<div id="bar-chart-content-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
launchIntoFullscreen(document.documentElement);
|
||||
initPieChart();
|
||||
initPieChart2();
|
||||
initGaugeChart('gauge-chart-content-3', 53829.5);
|
||||
initGaugeChart('gauge-chart-content-4', 12345.6);
|
||||
initBarChart('bar-chart-content-5', [3000, 4500, 1500, 5000, 23000, 1500, 15000, 3000, 4000, 5000, 2000, 1000, 500, 2563, 4000]);
|
||||
initBarChart('bar-chart-content-6', [2000, 3000, 1000, 4000, 18000, 1000, 12000, 2000, 3000, 4000, 1500, 800, 400, 2000, 3000]);
|
||||
|
||||
// Double click to toggle fullscreen
|
||||
$('body').on('dblclick', function() {
|
||||
launchIntoFullscreen(document.documentElement);
|
||||
});
|
||||
});
|
||||
|
||||
function initPieChart() {
|
||||
var chartDom = document.getElementById('ring-chart-content');
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
color: [
|
||||
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc',
|
||||
'#00d4ff', '#ffb700', '#2bff89', '#915eff', '#ff7f00'
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '管线类型统计',
|
||||
type: 'pie',
|
||||
radius: '55%',
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: true,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: '{b}',
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
align: 'left'
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 20,
|
||||
length2: 30,
|
||||
lineStyle: {
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{ value: 335, name: 'II级钢筋混凝土管 承插接口' },
|
||||
{ value: 310, name: '焊接钢管 焊接接口' },
|
||||
{ value: 274, name: '高密度聚乙烯双壁波纹管' },
|
||||
{ value: 235, name: '聚乙烯PE管' },
|
||||
{ value: 200, name: 'II级钢筋混凝土管' },
|
||||
{ value: 180, name: '高密度聚乙烯缠绕管' },
|
||||
{ value: 150, name: '焊接钢管 焊接连接' },
|
||||
{ value: 140, name: '高密度聚乙烯中空壁缠绕管' },
|
||||
{ value: 130, name: '钢筋混凝土管' },
|
||||
{ value: 110, name: '球墨铸铁管' },
|
||||
{ value: 100, name: '预应力钢筒混凝土管' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
function initPieChart2() {
|
||||
var chartDom = document.getElementById('pie-chart-content-2');
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
color: [
|
||||
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc',
|
||||
'#00d4ff', '#ffb700', '#2bff89', '#915eff', '#ff7f00'
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '管线类型统计2',
|
||||
type: 'pie',
|
||||
radius: '55%',
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: true,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: '{b}',
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
align: 'left'
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 20,
|
||||
length2: 30,
|
||||
lineStyle: {
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{ value: 200, name: '雨水管' },
|
||||
{ value: 180, name: '污水管' },
|
||||
{ value: 150, name: '给水管' },
|
||||
{ value: 120, name: '电力管' },
|
||||
{ value: 100, name: '燃气管' },
|
||||
{ value: 80, name: '通信管' },
|
||||
{ value: 60, name: '热力管' },
|
||||
{ value: 40, name: '工业管' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
function initGaugeChart(domId, value) {
|
||||
var chartDom = document.getElementById(domId);
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
series: [
|
||||
{
|
||||
type: 'gauge',
|
||||
startAngle: 180,
|
||||
endAngle: 0,
|
||||
min: 0,
|
||||
max: 300,
|
||||
splitNumber: 6,
|
||||
radius: '90%',
|
||||
center: ['50%', '70%'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 40,
|
||||
color: [[1, new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
{ offset: 0, color: 'rgba(65, 108, 243, 1)' },
|
||||
{ offset: 1, color: 'rgba(0, 68, 160, 1)' }
|
||||
])]]
|
||||
}
|
||||
},
|
||||
pointer: {
|
||||
show: true,
|
||||
length: '60%',
|
||||
width: 6,
|
||||
itemStyle: {
|
||||
color: '#00d4ff'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#00d4ff',
|
||||
fontSize: 14,
|
||||
distance: -60,
|
||||
formatter: function (value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
show: true,
|
||||
offsetCenter: [0, '40%'],
|
||||
fontSize: 30,
|
||||
color: '#fff',
|
||||
formatter: '{value} m'
|
||||
},
|
||||
data: [{
|
||||
value: value,
|
||||
name: ''
|
||||
}]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Adjust value if it exceeds max for visual representation (optional)
|
||||
// For now, we just set the data value as is, but if it's large like 53829.5,
|
||||
// the pointer will be pegged at max.
|
||||
// If the gauge is just a visual indicator and the number is what matters:
|
||||
// Let's set the gauge pointer to max if value > 300
|
||||
if (value > 300) {
|
||||
option.series[0].data[0].value = 300; // Pointer at max
|
||||
option.series[0].detail.formatter = value + ' m'; // Show real value
|
||||
}
|
||||
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
function initBarChart(domId, data) {
|
||||
var chartDom = document.getElementById(domId);
|
||||
var myChart = echarts.init(chartDom);
|
||||
|
||||
// Find max value for markPoint (example logic)
|
||||
var maxVal = Math.max(...data);
|
||||
var minVal = Math.min(...data);
|
||||
|
||||
var option = {
|
||||
grid: {
|
||||
top: '20%',
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15'],
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.3)'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 14
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '长度(m)',
|
||||
nameTextStyle: {
|
||||
color: '#fff',
|
||||
padding: [0, 0, 0, 20]
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 14
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.1)'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: data,
|
||||
type: 'bar',
|
||||
barWidth: '40%',
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 170, 0, 0.4)',
|
||||
borderColor: '#ffaa00',
|
||||
borderWidth: 1
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'pin',
|
||||
symbolSize: 50,
|
||||
label: {
|
||||
show: true,
|
||||
color: '#fff',
|
||||
fontSize: 12
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#ffaa00'
|
||||
},
|
||||
data: [
|
||||
{ type: 'max', name: 'Max' },
|
||||
{ type: 'min', name: 'Min' }
|
||||
]
|
||||
},
|
||||
markLine: {
|
||||
symbol: 'none',
|
||||
data: [
|
||||
{ yAxis: 2563.31, name: 'Average' }
|
||||
],
|
||||
label: {
|
||||
show: true,
|
||||
position: 'end',
|
||||
formatter: '{c}',
|
||||
color: '#ffaa00'
|
||||
},
|
||||
lineStyle: {
|
||||
type: 'dotted',
|
||||
color: '#ffaa00'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
815
src/main/webapp/jsp/z_bigScreen/bigScreen3.html
Normal file
815
src/main/webapp/jsp/z_bigScreen/bigScreen3.html
Normal file
@ -0,0 +1,815 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>排污户大屏展示</title>
|
||||
<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('./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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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;
|
||||
|
||||
$(document).ready(function() {
|
||||
launchIntoFullscreen(document.documentElement);
|
||||
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);
|
||||
var isHighlighted = (index === currentFocusIndex);
|
||||
var colorStart = isHighlighted ? '#ffffff' : '#ffaa00';
|
||||
var colorEnd = isHighlighted ? '#cccccc' : '#ff5500';
|
||||
|
||||
maxValues.push({
|
||||
value: item.value,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
|
||||
offset: 0, color: colorStart
|
||||
}, {
|
||||
offset: 1, color: colorEnd
|
||||
}])
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 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: '#00eaff'
|
||||
}, {
|
||||
offset: 1, color: '#0055ff'
|
||||
}])
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var option = {
|
||||
title: [{
|
||||
text: '近30天排污量最大 Top 10',
|
||||
left: 'center',
|
||||
top: '2%',
|
||||
textStyle: { color: '#ffaa00', fontSize: 24, fontWeight: 'bold' }
|
||||
}, {
|
||||
text: '近30天排污量最小 Top 10',
|
||||
left: 'center',
|
||||
top: '52%',
|
||||
textStyle: { color: '#00eaff', fontSize: 24, fontWeight: 'bold' }
|
||||
}],
|
||||
grid: [{
|
||||
top: '10%',
|
||||
left: '5%',
|
||||
right: '10%',
|
||||
bottom: '53%',
|
||||
containLabel: true
|
||||
}, {
|
||||
top: '60%',
|
||||
left: '5%',
|
||||
right: '10%',
|
||||
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: 18 },
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
gridIndex: 0
|
||||
}, {
|
||||
type: 'category',
|
||||
data: minNames,
|
||||
inverse: true,
|
||||
axisLabel: { color: '#fff', fontSize: 18 },
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
gridIndex: 1
|
||||
}],
|
||||
series: [{
|
||||
name: 'Max',
|
||||
type: 'bar',
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
data: maxValues,
|
||||
barWidth: 30,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
textStyle: { color: '#ffaa00', fontSize: 18, fontWeight: 'bold' },
|
||||
formatter: '{c} m³'
|
||||
}
|
||||
},
|
||||
itemStyle: { normal: { barBorderRadius: [0, 15, 15, 0] } },
|
||||
animationDuration: 1000,
|
||||
animationDurationUpdate: 1000
|
||||
}, {
|
||||
name: 'Min',
|
||||
type: 'bar',
|
||||
xAxisIndex: 1,
|
||||
yAxisIndex: 1,
|
||||
data: minValues,
|
||||
barWidth: 30,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
textStyle: { color: '#00eaff', fontSize: 18, fontWeight: 'bold' },
|
||||
formatter: '{c} m³'
|
||||
}
|
||||
},
|
||||
itemStyle: { normal: { barBorderRadius: [0, 15, 15, 0] } },
|
||||
animationDuration: 1000,
|
||||
animationDurationUpdate: 1000
|
||||
}]
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
*/
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function startRotation() {
|
||||
rotationTimer = setInterval(function() {
|
||||
currentFocusIndex = (currentFocusIndex + 1) % 10;
|
||||
updateDetailView();
|
||||
}, 5000); // 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>
|
||||
BIN
src/main/webapp/jsp/z_bigScreen/screen2.png
Normal file
BIN
src/main/webapp/jsp/z_bigScreen/screen2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 MiB |
BIN
src/main/webapp/jsp/z_bigScreen/screen3.png
Normal file
BIN
src/main/webapp/jsp/z_bigScreen/screen3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 MiB |
Reference in New Issue
Block a user