You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1765 lines
56 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>海洋生态实时监测智能预警平台</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.0/echarts.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts-gl/2.0.0/echarts-gl.min.js"></script>
<!-- 确保这些文件路径正确 -->
<script src="./model/mars3d-cesium/Build/Cesium/Cesium.js"></script>
<link href="./model/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<script src="./model/mars3d/mars3d.js"></script>
<link href="./model/mars3d/mars3d.css" rel="stylesheet">
<style>
/* 控制面板内容区域添加滚动条 */
.control-panel-content {
flex: 1;
overflow-y: auto;
padding-right: 10px;
margin-right: -10px;
}
/* 美化控制面板内容区域的滚动条 */
.control-panel-content::-webkit-scrollbar {
width: 4px;
}
.control-panel-content::-webkit-scrollbar-track {
background: rgba(12, 42, 73, 0.3);
border-radius: 4px;
}
.control-panel-content::-webkit-scrollbar-thumb {
background: rgba(79, 195, 247, 0.5);
border-radius: 4px;
}
.control-panel-content::-webkit-scrollbar-thumb:hover {
background: rgba(79, 195, 247, 0.8);
}
/* 替换原有的过滤器样式为以下代码 */
/* 修改过滤器相关样式 */
.filter-options {
display: flex;
flex-direction: column;
gap: 12px;
}
.filter-option {
display: flex;
align-items: center;
position: relative;
padding-left: 30px;
margin-bottom: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-option:hover {
transform: translateX(5px);
background: rgba(40, 80, 130, 0.3);
border-radius: 4px;
}
.filter-option input[type="checkbox"] {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.filter-option .checkmark {
position: absolute;
left: 0;
height: 20px;
width: 20px;
background-color: rgba(25, 55, 95, 0.6);
border: 2px solid #4fc3f7;
border-radius: 4px;
transition: all 0.3s ease;
pointer-events: all;
/* 确保可以点击 */
}
.filter-option:hover .checkmark {
background-color: rgba(79, 195, 247, 0.2);
}
.filter-option input:checked~.checkmark {
background-color: #4fc3f7;
}
.filter-option .checkmark:after {
content: "";
position: absolute;
display: none;
}
.filter-option input:checked~.checkmark:after {
display: block;
}
.filter-option .checkmark:after {
left: 6px;
top: 2px;
width: 6px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
.filter-option label {
font-size: 0.95rem;
color: #e0f0ff;
padding: 5px 0;
cursor: pointer;
width: 100%;
margin-left: 10px;
user-select: none;
/* 防止文本选择 */
}
.control-title {
font-size: 1.1rem;
margin: 15px 0 10px 0;
color: #4fc3f7;
padding-bottom: 5px;
border-bottom: 1px solid rgba(79, 195, 247, 0.3);
}
.control-group {
margin-bottom: 20px;
padding: 10px;
background: rgba(16, 36, 62, 0.3);
border-radius: 8px;
border: 1px solid rgba(64, 156, 255, 0.2);
}
/* 优化滚动条以确保内容可见 */
/* .info-panel {
overflow-y: auto;
} */
/* 美化滚动条 */
.info-panel::-webkit-scrollbar {
width: 4px;
}
.info-panel::-webkit-scrollbar-track {
background: rgba(12, 42, 73, 0.3);
border-radius: 4px;
}
.info-panel::-webkit-scrollbar-thumb {
background: rgba(79, 195, 247, 0.5);
border-radius: 4px;
}
.info-panel::-webkit-scrollbar-thumb:hover {
background: rgba(79, 195, 247, 0.8);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Arial, sans-serif;
}
body {
background: url('/assets/img/bg.png') no-repeat;
background-size: 100% 100%;
color: #e0f0ff;
overflow: hidden;
height: 100vh;
}
/* 新增顶部标题栏样式 */
.topDiv {
width: 100%;
height: 8vh;
background: url('/assets/img/topBg.png') top no-repeat;
background-size: 100% 115%;
display: flex;
justify-content: center;
z-index: 990;
position: relative;
/* background-color: rgba(12, 42, 73, 0.8); */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.topDiv .center {
font-family: PangMenZhengDao, 'Source Han Sans CN';
font-weight: 400;
font-size: 4.1vh;
color: #ffffff;
align-self: center;
margin-top: -40px;
}
.topDiv .left {
position: absolute;
top: 4vh;
left: 3vw;
color: #ffffff;
}
.topDiv .left span:nth-child(1) {
font-weight: bold;
font-size: 0.8vw;
margin-right: 0.5vh;
}
.topDiv .left span:nth-child(2) {
font-weight: bold;
font-size: 1.2vw;
}
.topDiv .right {
position: absolute;
top: 3vh;
right: 0;
color: #ffffff;
display: flex;
align-items: center;
}
.topDiv .right img:nth-child(1) {}
.topDiv .right span {
font-weight: bold;
font-size: 1.2vw;
}
.topDiv .icon-home {
position: absolute;
top: 1vh;
right: 8vw;
width: 4vh;
cursor: pointer;
}
.container {
display: flex;
height: calc(100vh - 8vh - 20px);
position: relative;
margin-bottom: 20px;
}
/* 左侧信息面板 */
.info-panel {
width: 300px;
height: 100%;
padding: 20px;
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(64, 156, 255, 0.3);
box-shadow: 5px 0 15px rgba(0, 0, 0, 0.3);
z-index: 10;
border-radius: 8px;
position: absolute;
left: 15px;
top: 0;
display: flex;
flex-direction: column;
}
/* 右侧控制面板 */
.control-panel {
width: 280px;
height: 100%;
padding: 20px;
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(64, 156, 255, 0.3);
box-shadow: -5px 0 15px rgba(0, 0, 0, 0.3);
z-index: 10;
border-radius: 8px;
position: absolute;
right: 15px;
top: 0;
display: flex;
flex-direction: column;
}
/* 卡片头部样式 */
/* .card-header {
height: 40px;
background: linear-gradient(to right, #1a3a5f, #2a5a8f);
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px 8px 0 0 !important;
border-bottom: 1px solid #4fc3f7;
padding: 12px 20px;
position: relative;
margin: -20px -20px 20px -20px;
}
.card-header span {
font-size: 1.2rem;
letter-spacing: 1px;
font-family: 'Microsoft YaHei';
font-weight: 400;
color: #ffffff;
} */
.stats-container {
display: flex;
flex-direction: column;
gap: 15px;
margin-bottom: 25px;
}
.stat-card {
background: rgba(25, 55, 95, 0.6);
/* background: url('/assets/img/common/kva2.png') no-repeat; */
/* background-size: 100% 100%; */
border-radius: 10px;
padding: 15px;
border-left: 4px solid #4fc3f7;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.stat-label {
font-size: 0.9rem;
color: #a0d2ff;
margin-bottom: 5px;
}
.stat-value {
font-size: 1.8rem;
font-weight: bold;
color: #4fc3f7;
}
.data-list {
flex: 1;
overflow-y: auto;
margin-top: 10px;
padding-right: 5px;
}
.data-item {
min-width: 200px;
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
padding: 10px;
border-left: 3px solid #4fc3f7;
transition: all 0.3s ease;
margin-bottom: 10px;
cursor: pointer;
}
.data-item:hover {
transform: translateX(5px);
background: rgba(40, 80, 130, 0.7);
}
.stream-device-info {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.stream-device-icon {
font-size: 1.5rem;
margin-right: 10px;
}
.stream-device-details {
flex: 1;
}
.stream-device-name {
font-weight: bold;
color: #4fc3f7;
font-size: 0.9rem;
}
.stream-parameter {
font-size: 0.8rem;
color: #a0d2ff;
}
.stream-value-section {
text-align: right;
}
.stream-value {
font-weight: bold;
font-size: 1.1rem;
font-family: 'Courier New', monospace;
}
.stream-timestamp {
font-size: 0.7rem;
color: #81d4fa;
}
.control-group {
margin-bottom: 25px;
}
.control-title {
font-size: 1.2rem;
margin-bottom: 15px;
color: #4fc3f7;
}
.toggle-switch {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.switch-label {
margin-right: 10px;
font-size: 1rem;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #2c3e50;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #4fc3f7;
}
input:checked+.slider:before {
transform: translateX(30px);
}
.filter-options {
display: flex;
flex-direction: column;
gap: 10px;
}
.filter-option {
display: flex;
align-items: center;
}
.filter-option input {
margin-right: 10px;
}
/* 地球容器样式 */
.earth-container {
flex: 1;
height: 100%;
position: relative;
margin: 0 300px 0 320px;
background: #0c1a2d;
}
#earthCanvas {
width: 100%;
height: 100%;
display: block;
}
/* 信息卡片样式 */
.info-card {
position: absolute;
background: rgba(16, 36, 62, 0.95);
backdrop-filter: blur(10px);
border-radius: 10px;
padding: 15px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.4);
border: 1px solid rgba(64, 156, 255, 0.3);
z-index: 1000;
width: 250px;
transform: translate(-50%, -100%);
margin-top: -20px;
}
.info-card::before {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border-width: 10px;
border-style: solid;
border-color: rgba(16, 36, 62, 0.95) transparent transparent transparent;
}
/* 卡片头部样式 */
.card-header {
height: 40px;
background: url('/assets/img/common/homeTitle2.png') no-repeat;
background-position: center;
background-size: 108% 120%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px 8px 0 0 !important;
border-bottom: 1px solid var(--light-blue);
padding: 32px 20px;
position: relative;
margin: -20px -20px 0px -20px;
}
.card-header span {
font-size: 1.2rem;
letter-spacing: 1px;
font-family: 'YouSheBiaoTiHei', 'Microsoft YaHei';
font-weight: 400;
color: #ffffff;
}
.info-card-title {
font-size: 1.1rem;
color: #4fc3f7;
margin: 0;
}
.info-card-close {
background: none;
border: none;
color: #a0d2ff;
font-size: 1.2rem;
cursor: pointer;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.info-card-close:hover {
color: #ffffff;
}
.info-card-content {
font-size: 0.9rem;
}
.info-item {
margin: 8px 0;
display: flex;
}
.info-label {
width: 70px;
color: #a0d2ff;
font-weight: bold;
}
.info-value {
flex: 1;
color: #e0f0ff;
word-break: break-all;
}
.status-online {
color: #4caf50;
font-weight: bold;
}
.status-offline {
color: #f44336;
font-weight: bold;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.info-panel,
.control-panel {
width: 260px;
}
.earth-container {
margin: 0 275px;
}
}
@media (max-width: 900px) {
.info-panel,
.control-panel {
width: 220px;
padding: 15px;
}
.earth-container {
margin: 0 235px;
}
.stat-value {
font-size: 1.5rem;
}
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: rgba(12, 42, 73, 0.3);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: rgba(106, 149, 201, 0.5);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(106, 149, 201, 0.7);
}
/* 警报列表样式 */
.alert-list {
/* height: 240px;
overflow-y: auto; */
height: calc(40vh - 8vh - 20px);
overflow: scroll;
}
.alert-item {
display: flex;
align-items: center;
padding: 12px 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
transition: background 0.3s;
}
.alert-item:hover {
background: rgba(255, 255, 255, 0.05);
}
.alert-level {
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 10px;
}
.level-high {
background: #ff4560;
box-shadow: 0 0 8px #ff4560;
}
.level-medium {
background: #ffa726;
box-shadow: 0 0 8px #ffa726;
}
.level-low {
background: #00e396;
box-shadow: 0 0 8px #00e396;
}
.alert-content {
flex: 1;
}
.alert-title {
font-weight: bold;
margin-bottom: 5px;
}
.alert-desc {
font-size: 13px;
color: #a0c8ff;
}
.alert-time {
font-size: 12px;
color: #7a9ccc;
}
/* 图表容器样式 */
.chart-container {
width: 100%;
/* height: 200px; */
margin-top: 10px;
height: calc(40vh - 8vh - 20px);
}
/* 新增样式:实时数据监控网格布局 */
.stats-grid {
height: calc(40vh - 8vh - 20px);
overflow: scroll;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 25px;
}
.stat-grid-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
padding: 12px;
/* border-left: 3px solid #4fc3f7; */
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.stat-grid-value {
font-size: 1rem;
font-weight: bold;
margin-bottom: 5px;
}
.stat-grid-label {
font-size: 0.8rem;
color: #a0d2ff;
margin-bottom: 3px;
}
.stat-grid-status {
font-size: 0.7rem;
color: #81d4fa;
}
/* 视频会议系统样式 */
.video-conference {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 25px;
}
.video-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
padding: 12px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.video-item:hover {
transform: translateY(-3px);
background: rgba(40, 80, 130, 0.7);
}
.video-icon {
font-size: 2rem;
margin-bottom: 8px;
}
.video-name {
font-size: 0.9rem;
color: #e0f0ff;
}
/* 网络系统状态样式 */
.network-status {
margin-top: 20px;
}
.network-item {
margin-bottom: 12px;
}
.network-label {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 0.9rem;
}
.network-name {
color: #a0d2ff;
}
.network-value {
color: #4fc3f7;
}
.network-progress {
height: 8px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
overflow: hidden;
}
.network-progress-bar {
height: 100%;
border-radius: 4px;
transition: width 0.5s ease;
}
/* 项目监控样式 */
.project-monitor {
margin-top: 10px;
}
.project-item {
margin-bottom: 12px;
}
.project-label {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 0.9rem;
}
.project-name {
color: #a0d2ff;
}
.project-value {
color: #4fc3f7;
}
.project-progress {
height: 8px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
overflow: hidden;
}
.project-progress-bar {
height: 100%;
border-radius: 4px;
transition: width 0.5s ease;
}
.mars3d-popup-background{
background: var(--mars-base-bg, rgba(16, 36, 62, 0.85)) !important;
}
</style>
</head>
<body>
<!-- 顶部标题栏 -->
<div class="topDiv">
<div class="left">
<span id="current-date">2025年9月17日</span>
<span id="current-time">15:18:00</span>
</div>
<div class="center">海洋生态实时监测智能预警平台</div>
<div class="right">
<img src="/common/images/logo_gt.png" alt="" />
</div>
</div>
<div class="container">
<!-- 左侧信息面板 -->
<!-- 修改左侧信息面板的结构 -->
<div class="info-panel">
<div class="card-header">
<span>实时数据监控</span>
</div>
<!-- 修改为网格布局 -->
<div class="stats-grid">
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #00e396;">42.8 mS/cm</div>
<div class="stat-grid-label">电导率</div>
<div class="stat-grid-status">正常: 30-50</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #00c6ff;">22.5°C</div>
<div class="stat-grid-label">温度</div>
<div class="stat-grid-status">正常: 18-26</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #4fc3f7;">5.8 mg/L</div>
<div class="stat-grid-label">溶解氧</div>
<div class="stat-grid-status">正常: 6-8</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #ffa726;">3.2 NTU</div>
<div class="stat-grid-label">浊度</div>
<div class="stat-grid-status">正常: 0-9</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #00e396;">8.2</div>
<div class="stat-grid-label">pH值</div>
<div class="stat-grid-status">正常: 7.8-8.5</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #ff4560;">2.3 mg/L</div>
<div class="stat-grid-label">COD</div>
<div class="stat-grid-status">正常: 0-3</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #4fc3f7;">3.6 μg/L</div>
<div class="stat-grid-label">叶绿素</div>
<div class="stat-grid-status">正常: 0-5</div>
</div>
<div class="stat-grid-item">
<div class="stat-grid-value" style="color: #00c6ff;">22.5°C</div>
<div class="stat-grid-label">海水温度</div>
<div class="stat-grid-status">正常: 18-26</div>
</div>
</div>
<div class="card-header">
<span>视频会议系统</span>
</div>
<!-- 视频会议系统 -->
<div class="video-conference">
<div class="video-item">
<div class="video-icon">📊</div>
<div class="video-name">项目指挥部</div>
</div>
<div class="video-item">
<div class="video-icon">📍</div>
<div class="video-name">监测站A点</div>
</div>
<div class="video-item">
<div class="video-icon">📍</div>
<div class="video-name">监测站B点</div>
</div>
<div class="video-item">
<div class="video-icon"></div>
<div class="video-name">待接入</div>
</div>
</div>
<div class="card-header">
<span>网络系统状态</span>
</div>
<!-- 网络系统状态 -->
<div class="network-status">
<div class="network-item">
<div class="network-label">
<span class="network-name">主干网络</span>
<span class="network-value">92%</span>
</div>
<div class="network-progress">
<div class="network-progress-bar" style="width: 92%; background-color: #00e396;"></div>
</div>
</div>
<div class="network-item">
<div class="network-label">
<span class="network-name">监测站点A</span>
<span class="network-value">85%</span>
</div>
<div class="network-progress">
<div class="network-progress-bar" style="width: 85%; background-color: #00c6ff;"></div>
</div>
</div>
<div class="network-item">
<div class="network-label">
<span class="network-name">监测站点B</span>
<span class="network-value">78%</span>
</div>
<div class="network-progress">
<div class="network-progress-bar" style="width: 78%; background-color: #4fc3f7;"></div>
</div>
</div>
<div class="network-item">
<div class="network-label">
<span class="network-name">监测站点C</span>
<span class="network-value">65%</span>
</div>
<div class="network-progress">
<div class="network-progress-bar" style="width: 65%; background-color: #ffa726;"></div>
</div>
</div>
<div class="network-item">
<div class="network-label">
<span class="network-name">服务器负载</span>
<span class="network-value">72%</span>
</div>
<div class="network-progress">
<div class="network-progress-bar" style="width: 72%; background-color: #00e396;"></div>
</div>
</div>
</div>
</div>
<!-- 地球容器 -->
<div class="earth-container">
<div id="mars3dMap" style="width:100%; height:100%;"></div>
</div>
<!-- 右侧控制面板 -->
<div class="control-panel">
<div class="card-header">
<span>实时预警信息</span>
</div>
<div class="alert-list" id="alertList">
<!-- 预警信息将通过JavaScript动态添加 -->
</div>
<div class="card-header">
<span>生态趋势分析</span>
</div>
<div class="chart-container" id="trendChart"></div>
<div class="card-header">
<span>项目监控</span>
</div>
<div class="project-monitor">
<div class="project-item">
<div class="project-label">
<span class="project-name">海岸修复工程</span>
<span class="project-value">75%</span>
</div>
<div class="project-progress">
<div class="project-progress-bar" style="width: 75%; background-color: #00e396;"></div>
</div>
</div>
<div class="project-item">
<div class="project-label">
<span class="project-name">海洋植被恢复</span>
<span class="project-value">62%</span>
</div>
<div class="project-progress">
<div class="project-progress-bar" style="width: 62%; background-color: #00c6ff;"></div>
</div>
</div>
<div class="project-item">
<div class="project-label">
<span class="project-name">渔业资源保护</span>
<span class="project-value">85%</span>
</div>
<div class="project-progress">
<div class="project-progress-bar" style="width: 85%; background-color: #4fc3f7;"></div>
</div>
</div>
<div class="project-item">
<div class="project-label">
<span class="project-name">污染源治理</span>
<span class="project-value">58%</span>
</div>
<div class="project-progress">
<div class="project-progress-bar" style="width: 58%; background-color: #ffa726;"></div>
</div>
</div>
<div class="project-item">
<div class="project-label">
<span class="project-name">监测系统建设</span>
<span class="project-value">92%</span>
</div>
<div class="project-progress">
<div class="project-progress-bar" style="width: 92%; background-color: #00e396;"></div>
</div>
</div>
</div>
</div>
</div>
<script>
// 全局变量
let map;
let isSimulationRunning = true;
let trendChart;
let qualityChart;
// 预警信息数据
const alertData = [
{
title: "A3监测点溶解氧异常",
desc: "溶解氧含量低于阈值,可能影响海洋生物生存",
time: "10:25:36",
level: "high"
},
{
title: "B7监测点营养盐超标",
desc: "氮磷含量超出正常范围,需关注藻类生长情况",
time: "09:42:15",
level: "medium"
},
{
title: "C2监测设备通信异常",
desc: "设备数据传输中断,技术人员已前往处理",
time: "08:15:22",
level: "low"
},
{
title: "D5区域叶绿素浓度升高",
desc: "叶绿素-a浓度较上周上升15%,需持续监测",
time: "昨天 16:38:44",
level: "medium"
},
{
title: "A1监测点pH值波动",
desc: "pH值轻微波动处于正常范围边缘",
time: "昨天 14:20:33",
level: "low"
}
];
// 监测设备数据
const monitoringDevices = [
{
id: 'A1',
name: '北部湾水质监测站1',
position: [108.321567, 21.537686, 0],
status: '正常',
data: {
'水质综合指数': '92.5',
'溶解氧': '7.8 mg/L',
'叶绿素': '5.2 μg/L',
'电导率': '45.2 mS/cm',
'COD含量': '2.8 mg/L'
}
},
{
id: 'A2',
name: '北部湾水质监测站2',
position: [108.51993, 21.583001, 0],
status: '正常',
data: {
'水质综合指数': '89.3',
'溶解氧': '7.2 mg/L',
'叶绿素': '6.1 μg/L',
'电导率': '48.7 mS/cm',
'COD含量': '3.1 mg/L'
}
},
{
id: 'A3',
name: '北海沿岸监测站1',
position: [109.123545, 21.571576, 0],
status: '异常',
data: {
'水质综合指数': '75.2',
'溶解氧': '5.1 mg/L',
'叶绿素': '8.7 μg/L',
'电导率': '52.3 mS/cm',
'COD含量': '4.5 mg/L'
}
},
{
id: 'B1',
name: '钦州湾监测站',
position: [108.625201, 21.80312, 0],
status: '正常',
data: {
'水质综合指数': '91.7',
'溶解氧': '7.6 mg/L',
'叶绿素': '5.8 μg/L',
'电导率': '46.1 mS/cm',
'COD含量': '2.9 mg/L'
}
},
{
id: 'B2',
name: '防城港监测站',
position: [108.3515, 21.6139, 0],
status: '正常',
data: {
'水质综合指数': '93.2',
'溶解氧': '8.1 mg/L',
'叶绿素': '4.9 μg/L',
'电导率': '44.8 mS/cm',
'COD含量': '2.6 mg/L'
}
},
{
id: 'B3',
name: '涠洲岛海域监测站',
position: [109.106875, 21.566059, 0],
status: '正常',
data: {
'水质综合指数': '94.1',
'溶解氧': '8.3 mg/L',
'叶绿素': '4.6 μg/L',
'电导率': '43.9 mS/cm',
'COD含量': '2.4 mg/L'
}
},
{
id: 'C1',
name: '铁山港监测站',
position: [109.455267, 21.849836, 0],
status: '正常',
data: {
'水质综合指数': '88.9',
'溶解氧': '7.4 mg/L',
'叶绿素': '6.3 μg/L',
'电导率': '47.5 mS/cm',
'COD含量': '3.2 mg/L'
}
},
{
id: 'C2',
name: '廉州湾监测站',
position: [109.255382, 21.193137, 0],
status: '通信异常',
data: {
'水质综合指数': 'N/A',
'溶解氧': 'N/A',
'叶绿素': 'N/A',
'电导率': 'N/A',
'COD含量': 'N/A'
}
}
];
// 初始化页面
document.addEventListener('DOMContentLoaded', function () {
initDateTime();
initAlertList();
initTrendChart();
initMap();
initEventListeners();
});
// 初始化日期时间
function initDateTime() {
function updateDateTime() {
const now = new Date();
const dateStr = now.getFullYear() + '年' +
(now.getMonth() + 1) + '月' +
now.getDate() + '日';
const timeStr = now.toTimeString().substr(0, 8);
document.getElementById('current-date').textContent = dateStr;
document.getElementById('current-time').textContent = timeStr;
}
updateDateTime();
setInterval(updateDateTime, 1000);
}
// 初始化预警列表
function initAlertList() {
const alertList = document.getElementById('alertList');
alertData.forEach(alert => {
const alertItem = document.createElement('div');
alertItem.className = 'data-item alert-item';
let levelClass = '';
switch (alert.level) {
case 'high':
levelClass = 'level-high';
break;
case 'medium':
levelClass = 'level-medium';
break;
case 'low':
levelClass = 'level-low';
break;
}
alertItem.innerHTML = `
<div class="alert-level ${levelClass}"></div>
<div class="alert-content">
<div class="alert-title">${alert.title}</div>
<div class="alert-desc">${alert.desc}</div>
</div>
<div class="alert-time">${alert.time}</div>
`;
alertList.appendChild(alertItem);
});
}
// 初始化趋势图表
function initTrendChart() {
trendChart = echarts.init(document.getElementById('trendChart'));
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis'
},
legend: {
data: ['PH值', '溶解氧', '海水温度'],
textStyle: {
color: '#e0f0ff'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'],
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(79, 195, 247, 0.2)'
}
}
},
series: [
{
name: 'PH值',
type: 'line',
smooth: true,
data: [7.9, 8.0, 8.1, 8.2, 8.1, 8.0, 8.2],
lineStyle: {
color: '#00e396'
},
itemStyle: {
color: '#00e396'
}
},
{
name: '溶解氧',
type: 'line',
smooth: true,
data: [6.5, 6.8, 7.2, 7.5, 7.3, 6.9, 7.1],
lineStyle: {
color: '#00c6ff'
},
itemStyle: {
color: '#00c6ff'
}
},
{
name: '海水温度',
type: 'line',
smooth: true,
data: [18.5, 19.2, 20.8, 22.5, 24.3, 25.7, 26.2],
lineStyle: {
color: '#4fc3f7'
},
itemStyle: {
color: '#4fc3f7'
}
}
]
};
trendChart.setOption(option);
}
// 初始化地图
function initMap() {
try {
// 通过 AJAX 加载 config.json 配置文件
fetch('./config/config.json')
.then(response => response.json())
.then(config => {
// 使用配置文件初始化地图
map = new mars3d.Map("mars3dMap", config.map3d);
// 添加监测设备到地图
addMonitoringDevices();
// 确保在地图初始化完成后添加广西行政区划图层
setTimeout(() => {
addGuangxiLayer();
}, 100);
// 添加广西行政区划图层
// setTimeout(() => {
// addWaterFlowEffect();
// }, 1000);
})
.catch(error => {
console.error('加载配置文件失败:', error);
// 如果配置文件加载失败,使用默认配置
map = new mars3d.Map("mars3dMap", {
scene: {
center: { lat: 21.0, lng: 108.0, alt: 100000 },
showSun: true,
showMoon: true,
showSkyBox: true,
showSkyAtmosphere: true,
fog: true,
fxaa: true,
cameraController: {
zoomFactor: 2.0,
minimumZoomDistance: 1,
maximumZoomDistance: 50000000,
}
},
control: {
homeButton: true,
sceneModePicker: true,
baseLayerPicker: true,
navigationHelpButton: true,
animation: true,
timeline: true,
fullscreenButton: true,
vrButton: true,
},
basemaps: [
{
id: 10,
name: "天地图影像",
icon: "img/basemaps/tdt_img.png",
type: "group",
layers: [
{
name: "底图",
type: "tdt",
layer: "img_d",
},
{
name: "注记",
type: "tdt",
layer: "cia_w",
}
]
},
{
id: 20,
name: "天地图电子",
icon: "img/basemaps/tdt_vec.png",
type: "group",
layers: [
{
name: "底图",
type: "tdt",
layer: "vec_d",
},
{
name: "注记",
type: "tdt",
layer: "cva_w",
}
]
}
]
});
// 添加监测设备到地图
addMonitoringDevices();
// 添加广西行政区划图层
setTimeout(() => {
addGuangxiLayer();
}, 1000);
// // 添加广西行政区划图层
// setTimeout(() => {
// addWaterFlowEffect();
// }, 1000);
});
} catch (error) {
console.error('初始化 Mars3D 地图时出错:', error);
}
}
// 修改后的 addGuangxiLayer 函数
function addGuangxiLayer() {
// 先移除可能存在的同名图层
if (map.getLayerById("guangxi")) {
map.removeLayer(map.getLayerById("guangxi"));
}
// 创建广西行政区划图层
const guangxiLayer = new mars3d.layer.GeoJsonLayer({
id: "guangxi",
name: "广西壮族自治区",
url: "./config/广西壮族自治区.json", // 确保路径正确
symbol: {
styleOptions: {
fill: true,
randomColor: true,
opacity: 0.3,
outline: true,
outlineStyle: {
color: "#4ECDC4",
width: 3,
opacity: 1,
},
label: {
text: "{name}",
position: "center",
opacity: 1,
font_size: 25,
color: "#fff",
font_family: "楷体",
outline: false,
background: true,
backgroundColor: "#000000",
backgroundOpacity: 0.5,
scaleByDistance: true,
scaleByDistance_far: 20000000,
scaleByDistance_farValue: 0.1,
scaleByDistance_near: 1000,
scaleByDistance_nearValue: 1,
},
},
},
flyTo: false,
});
// // 监听图层加载完成事件
// guangxiLayer.on(mars3d.EventType.load, function (event) {
// console.log("广西行政区划图层加载完成");
// // 定位到广西沿海区域(北部湾区域)
// map.flyToPosition({
// lat: 21.5,
// lng: 108.5,
// alt: 300000,
// heading: 0,
// pitch: -45
// });
// });
// 添加图层到地图
map.addLayer(guangxiLayer);
// // 如果图层已经加载完成,直接定位
// if (guangxiLayer.isAdded) {
// map.flyToPosition({
// lat: 21.5,
// lng: 108.5,
// alt: 300000,
// heading: 0,
// pitch: -45
// });
// }
}
// 添加监测设备到地图
function addMonitoringDevices() {
monitoringDevices.forEach(device => {
const graphic = new mars3d.graphic.BillboardEntity({
position: device.position,
style: {
image: device.status === '正常' ?
"img/marker/mark-green.png" :
(device.status === '异常' ?
"img/marker/mark-red.png" :
"img/marker/mark-yellow.png"),
scale: 1,
horizontalOrigin: mars3d.Cesium.HorizontalOrigin.CENTER,
verticalOrigin: mars3d.Cesium.VerticalOrigin.BOTTOM,
clampToGround: true,
},
attr: device,
popup: getDevicePopupContent(device)
});
map.graphicLayer.addGraphic(graphic);
// 绑定点击事件
graphic.on(mars3d.EventType.click, function (event) {
const device = event.graphic.attr;
showDeviceInfo(device);
});
});
// // 添加监测点
// monitoringDevices.forEach(device => {
// const point = new mars3d.graphic.PointEntity({
// position: device.position,
// style: {
// pixelSize: 12,
// color: device.status === '正常' ? '#00FF00' : '#FF0000',
// outlineColor: '#FFFFFF',
// outlineWidth: 2,
// heightReference: mars3d.Cesium.HeightReference.CLAMP_TO_GROUND
// },
// popup: `<div class="info-card">
// <div class="info-card-title">${device.name}</div>
// <div class="info-card-content">
// <div class="info-item">
// <div class="info-label">设备ID:</div>
// <div class="info-value">${device.id}</div>
// </div>
// <div class="info-item">
// <div class="info-label">状态:</div>
// <div class="info-value ${device.status === '正常' ? 'status-online' : 'status-offline'}">${device.status}</div>
// </div>
// ${Object.entries(device.data).map(([key, value]) => `
// <div class="info-item">
// <div class="info-label">${key}:</div>
// <div class="info-value">${value}</div>
// </div>
// `).join('')}
// </div>
// </div>`
// });
// map.graphicLayer.addGraphic(point);
// });
}
// 获取设备弹窗内容
function getDevicePopupContent(device) {
let content = `
<div style="padding: 10px;" >
<h3 style="margin: 0 0 10px 0; color: #4fc3f7;">${device.name}</h3>
<table style="width: 100%; border-collapse: collapse;">
`;
for (const [key, value] of Object.entries(device.data)) {
content += `
<tr>
<td style="padding: 3px 5px; border-bottom: 1px solid #eee; color: #a0d2ff;">${key}</td>
<td style="padding: 3px 5px; border-bottom: 1px solid #eee; color: #e0f0ff; text-align: right;">${value}</td>
</tr>
`;
}
content += `
</table>
<div style="margin-top: 10px; text-align: center;">
<span style="padding: 3px 8px; border-radius: 3px; background-color: ${device.status === '正常' ? '#4caf50' : (device.status === '异常' ? '#f44336' : '#9e9e9e')}; color: white; font-size: 12px;">
${device.status}
</span>
</div>
</div>
`;
return content;
}
// 显示设备详情信息
function showDeviceInfo(device) {
// 移除已存在的信息卡片
removeInfoCard();
// 创建信息卡片
const infoCard = document.createElement('div');
infoCard.className = 'info-card';
infoCard.innerHTML = `
<div class="info-card-header">
<h3 class="info-card-title">${device.name}</h3>
<button class="info-card-close">&times;</button>
</div>
<div class="info-card-content">
<div class="info-item">
<span class="info-label">设备ID:</span>
<span class="info-value">${device.id}</span>
</div>
<div class="info-item">
<span class="info-label">状态:</span>
<span class="info-value ${device.status === '正常' ? 'status-online' : 'status-offline'}">${device.status}</span>
</div>
<div class="info-item">
<span class="info-label">位置:</span>
<span class="info-value">纬度: ${device.position[1].toFixed(4)}°<br>经度: ${device.position[0].toFixed(4)}°</span>
</div>
<div class="info-item">
<span class="info-label">监测数据:</span>
<span class="info-value">
`;
for (const [key, value] of Object.entries(device.data)) {
infoCard.innerHTML += `${key}: ${value}<br>`;
}
infoCard.innerHTML += `
</span>
</div>
</div>
`;
// 设置位置在地图容器中央
const container = document.querySelector('.earth-container');
infoCard.style.left = '50%';
infoCard.style.top = '50%';
container.appendChild(infoCard);
// 添加关闭按钮事件
infoCard.querySelector('.info-card-close').addEventListener('click', function () {
infoCard.remove();
});
// 点击外部关闭
document.addEventListener('click', function closeCard(e) {
if (!infoCard.contains(e.target) && e.target.closest('.info-card') !== infoCard) {
infoCard.remove();
document.removeEventListener('click', closeCard);
}
});
}
// 移除信息卡片
function removeInfoCard() {
const existingCard = document.querySelector('.info-card');
if (existingCard) {
existingCard.remove();
}
}
// 初始化事件监听器
function initEventListeners() {
// 响应窗口大小变化
window.addEventListener('resize', function () {
if (trendChart) {
trendChart.resize();
}
if (qualityChart) {
qualityChart.resize();
}
});
}
</script>
</body>
</html>