1030 lines
33 KiB
HTML
1030 lines
33 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>设备总览</title>
|
||
<meta name="renderer" content="webkit">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all">
|
||
<link rel="stylesheet" href="../lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
|
||
<link rel="stylesheet" href="../css/public.css" media="all">
|
||
<link rel="stylesheet" href="../css/ol.css">
|
||
<!-- 谷歌地图的API接口,这个访问没有天地图的次数多,所以这边限制只有管理员能使用 -->
|
||
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBEBxB5n9vikPHbfNMzo_dzneXJi77YqjE" async defer></script>
|
||
<style>
|
||
.top-panel {
|
||
border: 1px solid #eceff9;
|
||
border-radius: 5px;
|
||
text-align: center;
|
||
}
|
||
|
||
.stats-panel {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.stats-panel > .layui-card-body {
|
||
height: auto;
|
||
min-height: 60px;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
.top-panel-number {
|
||
font-size: 30px;
|
||
border-right: 1px solid #eceff9;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.top-panel-tips{
|
||
line-height:30px;
|
||
font-size: 12px
|
||
}
|
||
|
||
.flex-row {
|
||
display: flex;
|
||
align-items: stretch;
|
||
flex-wrap: wrap;
|
||
}
|
||
.flex-row > .layui-col-xs12,
|
||
.flex-row > .layui-col-md6 {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.stats-panel .layui-col-xs3 a,
|
||
.stats-panel .layui-col-md4 a,
|
||
.stats-panel .layui-col-xs3 div a,
|
||
.stats-panel .layui-col-md4 div a {
|
||
display: block;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
ul li {
|
||
list-style: none;
|
||
}
|
||
|
||
.layuimini-main {
|
||
height: 96vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.map-wrapper {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
}
|
||
|
||
.map-card {
|
||
flex: 1;
|
||
background: white;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||
border: 1px solid #e6e8eb;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#map-container {
|
||
flex: 1;
|
||
width: 100%;
|
||
padding: 0;
|
||
margin: 0;
|
||
position: relative;
|
||
}
|
||
|
||
|
||
.device-overview-bar {
|
||
background: white;
|
||
border: 1px solid #e6e8eb;
|
||
border-radius: 6px;
|
||
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
|
||
padding: 10px 15px;
|
||
margin-bottom: 10px;
|
||
color: #333;
|
||
}
|
||
.map-toolbar {
|
||
position: absolute;
|
||
top: 15px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 1000;
|
||
background: rgba(255, 255, 255, 0.96);
|
||
backdrop-filter: blur(10px);
|
||
-webkit-backdrop-filter: blur(10px);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
border-radius: 12px;
|
||
padding: 8px 16px;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
width:auto;
|
||
max-width: 95vw;
|
||
}
|
||
|
||
.toolbar-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.toolbar-label {
|
||
font-size: 12px;
|
||
color: #666;
|
||
white-space: nowrap;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.toolbar-select {
|
||
border: 1px solid rgba(230, 230, 230, 0.8);
|
||
border-radius: 6px;
|
||
padding: 4px 8px;
|
||
font-size: 12px;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
min-width: 120px;
|
||
height: 28px;
|
||
}
|
||
|
||
.toolbar-input {
|
||
border: 1px solid rgba(230, 230, 230, 0.8);
|
||
border-radius: 6px;
|
||
padding: 4px 8px;
|
||
font-size: 12px;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
width: 140px;
|
||
height: 28px;
|
||
}
|
||
|
||
.toolbar-btn {
|
||
background: rgba(26, 160, 148, 0.9);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
padding: 4px 12px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
height: 28px;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.toolbar-btn:hover {
|
||
background: rgba(26, 160, 148, 1);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.toolbar-divider {
|
||
width: 1px;
|
||
height: 20px;
|
||
background: rgba(230, 230, 230, 0.6);
|
||
}
|
||
|
||
|
||
|
||
.overview-stats {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
align-items: center;
|
||
}
|
||
|
||
.stat-item {
|
||
display: flex;
|
||
align-items: center;
|
||
/* background: #f8f9fa;
|
||
border: 1px solid #e9ecef; */
|
||
border-radius: 4px;
|
||
padding: 5px 10px;
|
||
min-width: 85px;
|
||
transition: background-color 0.2s ease;
|
||
cursor: pointer;
|
||
height: 28px;
|
||
}
|
||
|
||
.stat-item:hover {
|
||
background: #e9ecef;
|
||
}
|
||
|
||
.stat-item.non-clickable {
|
||
cursor: default;
|
||
}
|
||
|
||
.stat-item.non-clickable:hover {
|
||
background: #f8f9fa;
|
||
}
|
||
|
||
.stat-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
margin-right: 6px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.dot-green { background-color: #48bb78; }
|
||
.dot-blue { background-color: #4299e1; }
|
||
.dot-gray { background-color: #a0aec0; }
|
||
.dot-orange { background-color: #ed8936; }
|
||
.dot-red { background-color: #f56565; }
|
||
.dot-yellow { background-color: #ecc94b; }
|
||
|
||
.stat-item span:nth-child(2) {
|
||
font-size: 12px;
|
||
color: #666;
|
||
margin-right: 4px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 13px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
/* 由于不使用layui的元素,所以这边还得适配手机端 */
|
||
@media screen and (max-width: 768px) {
|
||
.layuimini-main {
|
||
height: 120vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.map-wrapper {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.map-card {
|
||
margin: 8px;
|
||
height: calc(100% - 16px);
|
||
overflow: hidden;
|
||
}
|
||
|
||
#map-container {
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
|
||
|
||
.device-overview-bar {
|
||
padding: 8px 12px;
|
||
margin-bottom: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.overview-stats {
|
||
gap: 6px;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.stat-item {
|
||
flex: 0 0 auto;
|
||
min-width: 70px;
|
||
width: auto;
|
||
max-width: calc(50% - 4px);
|
||
padding: 4px 6px;
|
||
font-size: 10px;
|
||
height: 24px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2px;
|
||
}
|
||
|
||
.stat-item span:not(.stat-dot):not(.stat-number) {
|
||
font-size: 9px;
|
||
max-width: 40px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.stat-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
margin-right: 0;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.map-toolbar {
|
||
position: absolute;
|
||
transform: none;
|
||
left: auto;
|
||
margin: 8px;
|
||
margin-bottom: 8px;
|
||
min-width: auto;
|
||
max-width: none;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
padding: 6px 10px;
|
||
top:0px;
|
||
}
|
||
|
||
.toolbar-item {
|
||
gap: 4px;
|
||
flex: 0 0 auto;
|
||
width:100%
|
||
}
|
||
|
||
.toolbar-label {
|
||
font-size: 10px;
|
||
display: none;
|
||
}
|
||
|
||
.toolbar-select,
|
||
.toolbar-input {
|
||
font-size: 11px;
|
||
height: 24px;
|
||
width: 100%;
|
||
}
|
||
|
||
.toolbar-btn {
|
||
font-size: 11px;
|
||
height: 24px;
|
||
padding: 2px 8px;
|
||
}
|
||
|
||
.toolbar-divider {
|
||
display: none;
|
||
}
|
||
|
||
#toolbar-device-locate span:not(.toolbar-label) {
|
||
font-size: 10px;
|
||
padding: 2px 4px;
|
||
}
|
||
|
||
.dropdown-menu {
|
||
min-width: 180px;
|
||
max-width: 95vw;
|
||
}
|
||
|
||
.dropdown-item {
|
||
padding: 8px 12px;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
.ol-tooltip {
|
||
position: absolute;
|
||
background: rgba(255,255,255,0.8);
|
||
border-radius: 4px;
|
||
padding: 4px 8px;
|
||
border: 1px solid #d9d9d9;
|
||
color: #333;
|
||
font-size: 12px;
|
||
white-space: nowrap;
|
||
pointer-events: none;
|
||
z-index: 1001;
|
||
}
|
||
.ol-tooltip-static {
|
||
background: #ffcc33;
|
||
color: #222;
|
||
border: 1px solid #ffcc33;
|
||
}
|
||
|
||
.dropdown-container {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 100%;
|
||
}
|
||
|
||
.dropdown-toggle {
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
|
||
.dropdown-toggle::after {
|
||
content: '';
|
||
display: inline-block;
|
||
margin-left: 6px;
|
||
border-top: 4px solid;
|
||
border-right: 4px solid transparent;
|
||
border-left: 4px solid transparent;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dropdown-menu {
|
||
display: none;
|
||
position: absolute;
|
||
top: 100%;
|
||
left: 0;
|
||
z-index: 1100;
|
||
min-width: 200px;
|
||
padding: 8px 0;
|
||
margin-top: 2px;
|
||
background: white;
|
||
border-radius: 6px;
|
||
box-shadow: 0 3px 12px rgba(0,0,0,0.15);
|
||
border: 1px solid rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.dropdown-menu.show {
|
||
display: block;
|
||
}
|
||
|
||
.dropdown-group {
|
||
padding: 0 8px;
|
||
}
|
||
|
||
.dropdown-group-title {
|
||
font-size: 12px;
|
||
color: #666;
|
||
padding: 6px 8px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.dropdown-item {
|
||
padding: 6px 12px;
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
color: #333;
|
||
border-radius: 4px;
|
||
margin: 2px 0;
|
||
}
|
||
|
||
.dropdown-item:hover {
|
||
background: rgba(26, 160, 148, 0.1);
|
||
}
|
||
|
||
.dropdown-divider {
|
||
height: 1px;
|
||
background: #e9ecef;
|
||
margin: 8px 0;
|
||
}
|
||
|
||
.switch-label {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
width: 100%;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.switch-label input {
|
||
opacity: 0;
|
||
width: 0;
|
||
height: 0;
|
||
position: absolute;
|
||
}
|
||
|
||
.switch-slider {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 36px;
|
||
height: 18px;
|
||
background-color: #ccc;
|
||
border-radius: 18px;
|
||
transition: .4s;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.switch-slider:before {
|
||
position: absolute;
|
||
content: "";
|
||
height: 14px;
|
||
width: 14px;
|
||
left: 2px;
|
||
bottom: 2px;
|
||
background-color: white;
|
||
border-radius: 50%;
|
||
transition: .4s;
|
||
}
|
||
|
||
input:checked + .switch-slider {
|
||
background-color: #1aa094;
|
||
}
|
||
|
||
input:checked + .switch-slider:before {
|
||
transform: translateX(18px);
|
||
}
|
||
|
||
/* 测量状态指示器样式 */
|
||
#measureStatus {
|
||
background: rgba(255, 255, 255, 0.98);
|
||
border: 1px solid rgba(72, 187, 120, 0.3);
|
||
border-radius: 8px;
|
||
padding: 6px 12px;
|
||
box-shadow: 0 2px 8px rgba(72, 187, 120, 0.2);
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
#measureStatus .toolbar-btn {
|
||
padding: 2px 6px;
|
||
height: 24px;
|
||
min-width: 24px;
|
||
}
|
||
|
||
.weather-forecast-card {
|
||
position: absolute;
|
||
top: 55%;
|
||
right: 20px;
|
||
transform: translateY(-50%);
|
||
width: 280px;
|
||
background: rgba(255, 255, 255, 0.96);
|
||
backdrop-filter: blur(12px);
|
||
-webkit-backdrop-filter: blur(12px);
|
||
border-radius: 12px;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
|
||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||
z-index: 1100;
|
||
animation: slideInRight 0.3s ease-out;
|
||
padding: 16px;
|
||
}
|
||
|
||
@keyframes slideInRight {
|
||
from {
|
||
transform: translate(100%, -50%);
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
transform: translate(0, -50%);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.weather-card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
padding: 10px 20px;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||
border-radius: 8px 8px 0 0;
|
||
transition: background-color 0.2s ease;
|
||
margin: -16px -16px 12px -16px;
|
||
}
|
||
|
||
.weather-card-header:hover {
|
||
background-color: rgba(26, 160, 148, 0.05);
|
||
}
|
||
|
||
.weather-card-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #2d3748;
|
||
margin: 0;
|
||
}
|
||
|
||
.weather-close-btn {
|
||
background: none;
|
||
border: none;
|
||
color: #718096;
|
||
cursor: pointer;
|
||
font-size: 18px;
|
||
padding: 4px;
|
||
border-radius: 4px;
|
||
transition: all 0.2s ease;
|
||
line-height: 1;
|
||
}
|
||
|
||
.weather-close-btn:hover {
|
||
background: rgba(116, 129, 141, 0.1);
|
||
color: #4a5568;
|
||
}
|
||
|
||
.weather-device-info {
|
||
background: rgba(26, 160, 148, 0.1);
|
||
border-radius: 8px;
|
||
padding: 10px;
|
||
margin-bottom: 12px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
|
||
.weather-device-info span {
|
||
font-size: 12px;
|
||
color: #4a5568;
|
||
}
|
||
|
||
.weather-forecast-navigation {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
background: #f7fafc;
|
||
border-radius: 8px;
|
||
padding: 6px 10px;
|
||
}
|
||
|
||
.weather-nav-btn {
|
||
background: rgba(26, 160, 148, 0.1);
|
||
border: none;
|
||
color: #1aa094;
|
||
border-radius: 4px;
|
||
width: 28px;
|
||
height: 28px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.weather-nav-btn:hover:not(:disabled) {
|
||
background: rgba(26, 160, 148, 0.2);
|
||
}
|
||
|
||
.weather-nav-btn:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.forecast-time-display {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: #2d3748;
|
||
}
|
||
|
||
.weather-card-content {
|
||
padding: 12px;
|
||
background: #f7fafc;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.weather-loading {
|
||
text-align: center;
|
||
padding: 20px;
|
||
color: #718096;
|
||
}
|
||
|
||
.weather-error {
|
||
text-align: center;
|
||
padding: 20px;
|
||
color: #e53e3e;
|
||
background: rgba(229, 62, 62, 0.1);
|
||
border-radius: 8px;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.weather-forecast-item {
|
||
border-radius: 6px;
|
||
background: rgba(247, 250, 252, 0.5);
|
||
}
|
||
|
||
.weather-param-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 4px;
|
||
}
|
||
|
||
.weather-param {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.weather-param-icon {
|
||
font-size: 10px;
|
||
color: #1aa094;
|
||
width: 14px;
|
||
text-align: center;
|
||
}
|
||
|
||
.weather-param-label {
|
||
font-size: 10px;
|
||
color: #718096;
|
||
font-weight: 500;
|
||
flex: 1;
|
||
}
|
||
|
||
.weather-param-value {
|
||
font-size: 10px;
|
||
color: #2d3748;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.weather-wind-direction {
|
||
display: inline-block;
|
||
transform-origin: center;
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
/* 手机端适配 */
|
||
@media screen and (max-width: 768px) {
|
||
.weather-forecast-card {
|
||
right: 10px;
|
||
width: 240px;
|
||
padding: 12px;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.weather-card-header {
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.weather-card-title {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.weather-device-info {
|
||
padding: 8px;
|
||
margin-bottom: 8px;
|
||
gap: 4px;
|
||
}
|
||
|
||
.weather-device-info span {
|
||
font-size: 10px;
|
||
}
|
||
|
||
.weather-forecast-navigation {
|
||
padding: 4px 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.weather-nav-btn {
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
|
||
.forecast-time-display {
|
||
font-size: 11px;
|
||
}
|
||
|
||
.weather-card-content {
|
||
padding: 8px;
|
||
}
|
||
|
||
.weather-param {
|
||
gap: 2px;
|
||
}
|
||
|
||
.weather-param-icon {
|
||
font-size: 8px;
|
||
width: 12px;
|
||
}
|
||
|
||
.weather-param-label,
|
||
.weather-param-value {
|
||
font-size: 8px;
|
||
}
|
||
|
||
#measureStatus{
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 6px 0px;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script src="../js/ol.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="layuimini-main">
|
||
<div class="device-overview-bar">
|
||
<div class="overview-stats">
|
||
<div class="stat-item non-clickable">
|
||
<span class="stat-dot dot-green"></span>
|
||
<span>设备数量</span>
|
||
<span class="stat-number" th:text="${deviceOnlineNum}">1101</span>
|
||
</div>
|
||
<div class="stat-item non-clickable">
|
||
<span class="stat-dot dot-blue"></span>
|
||
<span>装机量</span>
|
||
<span class="stat-number" th:text="${deviceDeployedNum}">1123</span>
|
||
</div>
|
||
<div class="stat-item" onclick="queryDevices('offline')" th:if="${deviceOfflineNum > 0}">
|
||
<span class="stat-dot dot-gray"></span>
|
||
<span>掉线数</span>
|
||
<span class="stat-number" th:text="${deviceOfflineNum}">22</span>
|
||
</div>
|
||
<div class="stat-item" onclick="queryDevices('no_fwd')" th:if="${deviceNoFwdNum > 0}">
|
||
<span class="stat-dot dot-orange"></span>
|
||
<span>未推送数</span>
|
||
<span class="stat-number" th:text="${deviceNoFwdNum}">11</span>
|
||
</div>
|
||
<div class="stat-item" onclick="queryDevices('nofixed')" th:if="${noFix > 0}">
|
||
<span class="stat-dot dot-red"></span>
|
||
<span>长期无效解</span>
|
||
<span class="stat-number" th:text="${noFix}">10</span>
|
||
</div>
|
||
<div class="stat-item" onclick="queryDevices('warning2')" th:if="${warning2Num > 0}">
|
||
<span class="stat-dot dot-red"></span>
|
||
<span>严重告警</span>
|
||
<span class="stat-number" th:text="${warning2Num}">40</span>
|
||
</div>
|
||
<div class="stat-item" onclick="queryDevices('warning1')" th:if="${warning1Num > 0}">
|
||
<span class="stat-dot dot-orange"></span>
|
||
<span>一般告警</span>
|
||
<span class="stat-number" th:text="${warning1Num}">79</span>
|
||
</div>
|
||
<div class="stat-item" onclick="queryDevices('nogga')" th:if="${noGGA > 0}">
|
||
<span class="stat-dot dot-gray"></span>
|
||
<span>无GGA告警</span>
|
||
<span class="stat-number" th:text="${noGGA}">4</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="map-wrapper">
|
||
<div class="map-card">
|
||
|
||
<div id="map-container">
|
||
<div id="weatherForecastCard" class="weather-forecast-card" style="display: none;" th:if="${role=='SUPER_ADMIN'}">
|
||
<div class="weather-card-header">
|
||
<h3 class="weather-card-title">
|
||
Windy 天气预测
|
||
</h3>
|
||
<button class="weather-close-btn" onclick="closeWeatherCard()">×</button>
|
||
</div>
|
||
<div id="weatherDeviceInfo" class="weather-device-info">
|
||
<span id="weatherDeviceId">设备信息</span>
|
||
<span id="weatherDeviceCoords">坐标信息</span>
|
||
</div>
|
||
<div class="weather-forecast-navigation">
|
||
<button id="prevForecast" class="weather-nav-btn" onclick="showPrevForecast()" disabled>
|
||
<i class="layui-icon layui-icon-left"></i>
|
||
</button>
|
||
<span id="forecastTimeDisplay" class="forecast-time-display">--:--</span>
|
||
<button id="nextForecast" class="weather-nav-btn" onclick="showNextForecast()">
|
||
<i class="layui-icon layui-icon-right"></i>
|
||
</button>
|
||
</div>
|
||
<div id="weatherForecastContent" class="weather-card-content">
|
||
<div class="weather-loading">
|
||
<i class="layui-icon layui-icon-loading layui-icon-anim-rotate"></i>
|
||
<p>正在获取天气预测数据...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="map-toolbar">
|
||
<div class="toolbar-item">
|
||
<select id="mapTypeSelectNew" class="toolbar-select" lay-filter="mapTypeNew" onchange="onMapTypeChange()">
|
||
<option value="tianditu_satellite" selected>天地图-卫星影像</option>
|
||
<option value="tianditu_terrain_hybrid" >天地图-地形混合</option>
|
||
<option value="tianditu_normal">天地图-矢量</option>
|
||
<option value="tianditu_terrain">天地图-地形</option>
|
||
<option value="amap_satellite">高德-卫星影像</option>
|
||
<option value="amap">高德-矢量</option>
|
||
<!-- 只能超级管理员使用 -->
|
||
<option value="google_satellite" th:if="${role=='SUPER_ADMIN'}">谷歌-卫星影像</option>
|
||
<option value="google_terrain" th:if="${role=='SUPER_ADMIN'}">谷歌-地形图</option>
|
||
<option value="google_roadmap" th:if="${role=='SUPER_ADMIN'}">谷歌-道路图</option>
|
||
<option value="google_hybrid" th:if="${role=='SUPER_ADMIN'}">谷歌-混合</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="toolbar-divider"></div>
|
||
|
||
<div class="toolbar-item">
|
||
<input type="text" id="deviceSearchNew" class="toolbar-input" placeholder="搜索设备编号">
|
||
<button class="toolbar-btn" onclick="searchDeviceNew()">搜索</button>
|
||
</div>
|
||
|
||
<div class="toolbar-divider"></div>
|
||
|
||
<div class="toolbar-item">
|
||
<select id="warningFilter" class="toolbar-select" onchange="onWarningFilterChange()">
|
||
<option value="all">全部设备</option>
|
||
<option value="warning1">一般告警</option>
|
||
<option value="warning2" selected>严重告警</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="toolbar-divider"></div>
|
||
|
||
<div class="toolbar-item">
|
||
<div class="dropdown-container">
|
||
<button class="toolbar-btn dropdown-toggle" onclick="toggleMapFunctionsMenu()">地图功能</button>
|
||
<div id="mapFunctionsMenu" class="dropdown-menu">
|
||
<div class="dropdown-group">
|
||
<div class="dropdown-group-title">信息显示</div>
|
||
<div class="dropdown-item">
|
||
<label class="switch-label">
|
||
<span>显示设备信息</span>
|
||
<input type="checkbox" id="showDeviceIdSwitch" checked onchange="toggleDeviceId()">
|
||
<span class="switch-slider"></span>
|
||
</label>
|
||
</div>
|
||
<div class="dropdown-item">
|
||
<label class="switch-label">
|
||
<span>显示集群</span>
|
||
<input type="checkbox" id="showClusterSwitch" checked onchange="toggleCluster()">
|
||
<span class="switch-slider"></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<div class="dropdown-group">
|
||
<div class="dropdown-group-title">测量工具</div>
|
||
<div class="dropdown-item" onclick="toggleMeasureDistance()">
|
||
测距
|
||
</div>
|
||
<div class="dropdown-item" onclick="clearMeasure()">
|
||
清除测距
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<div class="dropdown-group" th:if="${role=='SUPER_ADMIN'}">
|
||
<div class="dropdown-group-title">Windy 天气预测</div>
|
||
<div class="dropdown-item">
|
||
<label class="switch-label">
|
||
<span>启用天气预测(需网络被代理)</span>
|
||
<input type="checkbox" id="enableWeatherSwitch" onchange="toggleWeatherForecast()">
|
||
<span class="switch-slider"></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="measureStatus" class="toolbar-item" style="display: none;">
|
||
<span style="color: #48bb78; font-weight: bold; font-size: 12px;">测量中</span>
|
||
<button class="toolbar-btn" onclick="finishMeasuring()" style="background: #f56565; margin-left: 6px;">
|
||
<i class="layui-icon layui-icon-close" style="font-size: 12px;"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- JavaScript 依赖 -->
|
||
<script src="../js/ol.js"></script>
|
||
<script src="../lib/jquery-3.4.1/jquery-3.4.1.min.js" charset="utf-8"></script>
|
||
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||
|
||
<!-- 设备总览模块化JavaScript文件 -->
|
||
<script src="../js/device-overview-module/coordinate-utils.js"></script>
|
||
<script src="../js/device-overview-module/map-layers.js"></script>
|
||
<script src="../js/device-overview-module/device-markers.js"></script>
|
||
<script src="../js/device-overview-module/search-filter.js"></script>
|
||
<script src="../js/device-overview-module/measure-tools.js"></script>
|
||
<script src="../js/device-overview-module/weather-forecast.js"></script>
|
||
<script src="../js/device-overview-module/map-core.js"></script>
|
||
<script src="../js/device-overview-module/device-overview-main.js"></script>
|
||
|
||
<script th:inline="javascript">
|
||
// 从服务器获取设备列表数据
|
||
var deviceList = [
|
||
/*[# th:each="device : ${deviceList}"]*/
|
||
{
|
||
deviceid: /*[[${device.deviceid}]]*/ '',
|
||
latitude: /*[[${device.latitude}]]*/ 0,
|
||
longitude: /*[[${device.longitude}]]*/ 0,
|
||
warning: /*[[${device.warning}]]*/ 0
|
||
}/*[# th:if="${!deviceStat.last}"]*/,/*[/]*/
|
||
/*[/]*/
|
||
];
|
||
|
||
// 获取用户角色
|
||
var userRole = /*[[${role}]]*/ 'USER';
|
||
|
||
// 初始化设备总览模块
|
||
DeviceOverview.init(deviceList, {
|
||
role: userRole
|
||
});
|
||
|
||
// 暴露全局函数供HTML调用
|
||
window.onMapTypeChange = DeviceOverview.onMapTypeChange;
|
||
window.searchDeviceNew = DeviceOverview.searchDeviceNew;
|
||
window.onWarningFilterChange = DeviceOverview.onWarningFilterChange;
|
||
window.toggleMapFunctionsMenu = DeviceOverview.toggleMapFunctionsMenu;
|
||
window.toggleDeviceId = DeviceOverview.toggleDeviceId;
|
||
window.toggleCluster = DeviceOverview.toggleCluster;
|
||
window.toggleMeasureDistance = DeviceOverview.toggleMeasureDistance;
|
||
window.finishMeasuring = DeviceOverview.finishMeasuring;
|
||
window.clearMeasure = DeviceOverview.clearMeasure;
|
||
window.toggleWeatherForecast = DeviceOverview.toggleWeatherForecast;
|
||
window.closeWeatherCard = DeviceOverview.closeWeatherCard;
|
||
window.showPrevForecast = DeviceOverview.showPrevForecast;
|
||
window.showNextForecast = DeviceOverview.showNextForecast;
|
||
window.queryDevices = DeviceOverview.queryDevices;
|
||
window.locateDeviceOnMap = DeviceOverview.locateDeviceOnMap;
|
||
window.locateDeviceDirectly = DeviceOverview.locateDeviceDirectly;
|
||
window.switchMapType = DeviceOverview.switchMapType;
|
||
</script>
|
||
|
||
</body>
|
||
</html> |