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.

3686 lines
114 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" issue="width=device-width, initial-scale=1.0">
<title>科考任务综合管理系统 - 系统主页</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="/js/echarts5.4.3/echarts.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Microsoft YaHei', Arial, sans-serif;
}
body {
background: url('/assets/img/bg.png') no-repeat;
background-size: 100% 100%;
color: #e0f0ff;
background-color: #0a1a2a;
overflow-x: hidden;
overflow-y: auto;
}
.container {
/* max-width: 1400px; */
margin: 0 auto;
padding: 20px;
}
/* 顶部标题栏 */
.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: fixed;
top: 0;
left: 0;
}
.top-header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0 20px;
}
.logo-container {
display: flex;
align-items: center;
space-x: 3;
}
.logo-container img {
height: 40px;
}
.system-title {
text-align: center;
font-size: 2rem;
font-weight: bold;
color: white;
margin-top: -30px;
}
.header-right {
display: flex;
align-items: center;
space-x: 5;
}
.notification-button {
position: relative;
margin-right: 20px;
}
.notification-button::after {
content: '';
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
background: #f44336;
border-radius: 50%;
box-shadow: 0 0 8px rgba(244, 67, 54, 0.7);
}
.user-info-container {
display: flex;
align-items: center;
space-x: 3;
}
.user-info-text {
color: white;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
border-bottom: 1px solid rgba(64, 156, 255, 0.3);
margin-bottom: 30px;
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border-radius: 8px;
padding: 15px 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
margin-top: 8vh;
/* 为顶部标题栏留出空间 */
}
.logo {
display: flex;
align-items: center;
}
.logo i {
font-size: 32px;
margin-right: 10px;
color: #40a9ff;
}
.logo h1 {
font-size: 24px;
font-weight: 600;
color: #e0f0ff;
}
.user-info {
display: flex;
align-items: center;
}
.user-info img {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
border: 2px solid #40a9ff;
}
/* 侧边栏样式 */
.sidebar {
position: fixed;
left: 0;
top: 0;
width: 50px;
height: 100%;
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
padding-top: 80px;
z-index: 100;
transition: all 0.3s ease;
border-right: 1px solid rgba(64, 156, 255, 0.3);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
/* margin-top: 8vh; */
/* 为顶部标题栏留出空间 */
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar li {
padding: 0;
}
.sidebar a {
display: block;
padding: 15px 20px;
color: #a0d2ff;
text-decoration: none;
transition: all 0.3s;
border-left: 4px solid transparent;
}
.sidebar a:hover,
.sidebar a.active {
background: rgba(59, 130, 246, 0.1);
border-left: 4px solid #3B82F6;
color: #e0f0ff;
}
.sidebar a i {
margin-right: 10px;
width: 20px;
text-align: center;
}
/* 主内容区域 */
.main-content {
margin-left: 50px;
padding: 20px;
margin-top: 3vh;
/* 为顶部标题栏留出空间 */
}
.section-title {
font-size: 24px;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(64, 156, 255, 0.3);
color: #e0f0ff;
}
.module-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.module-card {
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(64, 156, 255, 0.3);
color: #e0f0ff;
}
.module-title {
height: 40px;
background: url('/assets/img/common/homeTitle2.png') no-repeat;
background-position: center;
background-size: 100% 100%;
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;
}
.module-title span {
font-size: 1.2rem;
letter-spacing: 1px;
font-family: 'YouSheBiaoTiHei', 'Microsoft YaHei';
font-weight: 400;
color: #ffffff;
}
.module-title i {
margin-right: 10px;
color: #40a9ff;
}
.chart-container {
height: 200px;
position: relative;
}
.data-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
}
.data-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 5px;
padding: 10px;
text-align: center;
}
.data-label {
font-size: 12px;
color: #a0d2ff;
margin-bottom: 5px;
}
.data-value {
font-size: 16px;
font-weight: bold;
color: #e0f0ff;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th,
td {
padding: 8px 12px;
text-align: left;
border-bottom: 1px solid rgba(64, 156, 255, 0.3);
}
th {
background: rgba(25, 55, 95, 0.6);
font-weight: normal;
color: #4fc3f7;
}
.hidden {
display: none;
}
.video-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.video-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 10px;
padding: 15px;
text-align: center;
}
.video-placeholder {
height: 100%;
background-image: url("/img_kekao/6.png");
background-size: 100% 100%;
/* background: rgba(40, 80, 130, 0.7); */
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
}
.video-placeholder i {
color: #4fc3f7;
}
.status-item {
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border-radius: 8px;
padding: 15px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(64, 156, 255, 0.3);
flex: 1;
margin: 0 10px;
display: flex;
flex-direction: column;
align-items: center;
}
.status-item:first-child {
margin-left: 0;
}
.status-item:last-child {
margin-right: 0;
}
.status-item i {
font-size: 32px;
margin-bottom: 10px;
color: #40a9ff;
}
.status-value {
font-size: 24px;
font-weight: bold;
margin: 5px 0;
color: #e0f0ff;
}
.status-label {
font-size: 14px;
color: #a0d2ff;
}
.status {
display: flex;
justify-content: space-between;
margin-top: 30px;
}
footer {
margin-top: 40px;
text-align: center;
padding: 20px;
border-top: 1px solid rgba(64, 156, 255, 0.3);
color: #a0d2ff;
font-size: 14px;
}
/* 三行布局 */
.row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
/* 第二行特殊布局:激光测风雷达、风廓线雷达、测波雷达、水质测量仪 */
.row-second {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 20px;
}
/* 测波雷达和水质测量仪容器 */
.combined-modules {
grid-column: span 2;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
/* 测波雷达和水质测量仪内部三列布局 */
.wave-data-grid,
.water-data-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.wave-data-item,
.water-data-item {
/* background: rgba(25, 55, 95, 0.6);
border-radius: 5px; */
background: url('/img_kekao/kuang-wz-150_90.png') no-repeat;
background-position: center;
background-size: 100% 100%;
padding: 8px;
text-align: center;
position: relative;
}
.wave-data-label,
.water-data-label {
font-size: 11px;
color: #a0d2ff;
margin-bottom: 3px;
}
.wave-data-value,
.water-data-value {
font-size: 13px;
font-weight: bold;
color: #e0f0ff;
}
@media (max-width: 768px) {
.sidebar {
width: 70px;
}
.sidebar a span {
display: none;
}
.sidebar a i {
margin-right: 0;
font-size: 20px;
}
.main-content {
margin-left: 70px;
}
.data-grid {
grid-template-columns: 1fr 1fr;
}
.status {
flex-direction: column;
}
.status-item {
margin: 10px 0;
}
/* 响应式调整第二行布局 */
.row-second {
grid-template-columns: 1fr;
}
.combined-modules {
grid-column: span 1;
grid-template-columns: 1fr;
}
/* 响应式调整测波雷达和水质测量仪内部布局 */
.wave-data-grid,
.water-data-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* 态势图容器样式 */
.situation-chart-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-bottom: 15px;
}
.situation-chart {
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(1px);
border-radius: 8px;
padding: 10px;
border: 1px solid rgba(64, 156, 255, 0.3);
display: flex;
flex-direction: column;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.situation-title {
color: #40a9ff;
margin-bottom: 10px;
font-size: 14px;
border-bottom: 1px solid rgba(64, 169, 255, 0.3);
padding-bottom: 5px;
text-align: center;
}
/* 风向态势图 */
.wind-direction-container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
}
.wind-direction-indicator {
width: 120px;
height: 120px;
position: relative;
border-radius: 50%;
background: linear-gradient(135deg, #0a3d62, #1a5276);
border: 2px solid rgba(64, 169, 255, 0.5);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.wind-direction-compass {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
background: rgba(10, 25, 41, 0.3);
}
.wind-direction-arrow {
position: absolute;
top: 50%;
left: 50%;
width: 3px;
height: 45px;
background: linear-gradient(to top, #40a9ff, #0277bd);
transform-origin: 50% 100%;
transform: translate(-50%, -100%) rotate(0deg);
border-radius: 2px;
z-index: 10;
box-shadow: 0 0 5px rgba(64, 169, 255, 0.7);
transition: transform 1s ease;
}
.wind-direction-arrow::after {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 8px solid #40a9ff;
}
.wind-direction-labels {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.wind-direction-label {
position: absolute;
font-size: 10px;
color: #e0f0ff;
font-weight: bold;
}
.north {
top: 2px;
left: 50%;
transform: translateX(-50%);
}
.east {
top: 50%;
right: 2px;
transform: translateY(-50%);
}
.south {
bottom: 2px;
left: 50%;
transform: translateX(-50%);
}
.west {
top: 50%;
left: 2px;
transform: translateY(-50%);
}
.wind-direction-details {
display: flex;
justify-content: space-around;
width: 100%;
margin-top: 8px;
gap: 5px;
}
.wind-detail-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 4px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
min-width: 50px;
}
.wind-detail-label {
font-size: 10px;
color: #a0d2ff;
margin-bottom: 2px;
}
.wind-detail-value {
color: #40a9ff;
text-shadow: 0 0 8px rgba(64, 169, 255, 0.7);
font-weight: bold;
font-size: 10px;
}
/* 风速态势图 */
.wind-speed-container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
}
.wind-speed-gauge {
width: 60px;
height: 120px;
position: relative;
/* background: linear-gradient(135deg, #0a3d62, #1a5276); */
overflow: hidden;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
background-image: url(/img_kekao/wendu.png);
background-size: 100% 100%;
}
.wind-speed-fill {
position: absolute;
bottom: 0;
width: 100%;
background: linear-gradient(to top, #40a9ff, #0277bd);
border-radius: 8px 8px 0 0;
transition: height 1s ease;
}
.wind-speed-value {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 16px;
font-weight: bold;
color: #e0f0ff;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
z-index: 10;
}
.wind-speed-label {
position: absolute;
bottom: 5px;
left: 0;
width: 100%;
text-align: center;
font-size: 10px;
color: #a0d2ff;
font-weight: bold;
}
.wind-speed-details {
display: flex;
justify-content: space-around;
width: 100%;
margin-top: 8px;
gap: 5px;
}
.wind-speed-detail-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 4px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
min-width: 50px;
}
.wind-speed-detail-label {
font-size: 10px;
color: #a0d2ff;
margin-bottom: 2px;
}
.wind-speed-detail-value {
color: #64ffda;
text-shadow: 0 0 8px rgba(100, 255, 218, 0.7);
font-weight: bold;
font-size: 10px;
}
/* 波高态势图 */
.wave-height-container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
}
.wave-height-gauge {
width: 60px;
height: 120px;
position: relative;
/* background: linear-gradient(135deg, #0a3d62, #1a5276); */
overflow: hidden;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
background-image: url(/img_kekao/shidu.png);
background-size: 100% 100%;
}
.wave-height-fill {
position: absolute;
bottom: 0;
width: 100%;
background: linear-gradient(to top, #40a9ff, #0277bd);
border-radius: 8px 8px 0 0;
transition: height 1s ease;
}
.wave-height-value {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 16px;
font-weight: bold;
color: #e0f0ff;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
z-index: 10;
}
.wave-height-label {
position: absolute;
bottom: 5px;
left: 0;
width: 100%;
text-align: center;
font-size: 10px;
color: #a0d2ff;
font-weight: bold;
}
.wave-height-details {
display: flex;
justify-content: space-around;
width: 100%;
margin-top: 8px;
gap: 5px;
}
.wave-detail-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 4px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
min-width: 50px;
}
.wave-detail-label {
font-size: 10px;
color: #a0d2ff;
margin-bottom: 2px;
}
.wave-detail-value {
color: #29b6f6;
text-shadow: 0 0 8px rgba(41, 182, 246, 0.7);
font-weight: bold;
font-size: 10px;
}
/* 波向态势图 */
.wave-direction-container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
}
.wave-direction-indicator {
width: 120px;
height: 120px;
position: relative;
/* border-radius: 50%;
background: linear-gradient(135deg, #0a3d62, #1a5276);
border: 2px solid rgba(64, 169, 255, 0.5); */
/* box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); */
}
.wave-direction-compass {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
background: rgba(10, 25, 41, 0.3);
}
.wave-direction-arrow {
position: absolute;
top: 50%;
left: 50%;
width: 3px;
height: 45px;
background: linear-gradient(to top, #40a9ff, #0277bd);
transform-origin: 50% 100%;
transform: translate(-50%, -100%) rotate(0deg);
border-radius: 2px;
z-index: 10;
box-shadow: 0 0 5px rgba(64, 169, 255, 0.7);
transition: transform 1s ease;
}
.wave-direction-arrow::after {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 8px solid #40a9ff;
}
.wave-direction-labels {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.wave-direction-label {
position: absolute;
font-size: 10px;
color: #e0f0ff;
font-weight: bold;
}
.wave-direction-details {
display: flex;
justify-content: space-around;
width: 100%;
margin-top: 8px;
gap: 5px;
}
.wave-direction-detail-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 4px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
min-width: 50px;
}
.wave-direction-detail-label {
font-size: 10px;
color: #a0d2ff;
margin-bottom: 2px;
}
.wave-direction-detail-value {
color: #5c6bc0;
text-shadow: 0 0 8px rgba(92, 107, 192, 0.7);
font-weight: bold;
font-size: 10px;
}
/* 海洋波纹效果 */
.wave-pattern {
position: absolute;
bottom: 0;
width: 100%;
height: 10px;
background: linear-gradient(90deg, transparent, rgba(64, 169, 255, 0.3), transparent);
animation: wave-animation 3s infinite linear;
}
@keyframes wave-animation {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
.moule-img {
background-image: url("/img_kekao/海图.png");
background-size: 100% 100%;
}
/*四个角*/
.topL {
width: 10px;
height: 10px;
border-top-width: 2px;
border-top-color: #26c6f0;
border-top-style: solid;
border-left-width: 2px;
border-left-color: #26c6f0;
border-left-style: solid;
position: absolute;
top: -2px;
left: -2px
}
.topR {
width: 10px;
height: 10px;
border-top-width: 2px;
border-top-color: #26c6f0;
border-top-style: solid;
border-right-width: 2px;
border-right-color: #26c6f0;
border-right-style: solid;
position: absolute;
top: -2px;
right: -2px
}
.bottomL {
width: 10px;
height: 10px;
border-bottom-width: 2px;
border-bottom-color: #26c6f0;
border-bottom-style: solid;
border-left-width: 2px;
border-left-color: #26c6f0;
border-left-style: solid;
position: absolute;
bottom: -2px;
left: -2px
}
.bottomR {
width: 10px;
height: 10px;
border-bottom-width: 2px;
border-bottom-color: #26c6f0;
border-bottom-style: solid;
border-right-width: 2px;
border-right-color: #26c6f0;
border-right-style: solid;
position: absolute;
bottom: -2px;
right: -2px
}
/* 卡片头部样式 */
/* .card-header {
height: 40px;
background: url('/assets/img/common/homeTitle2.png') no-repeat;
background-position: center;
background-size: 100% 100%;
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;
} */
</style>
<style>
/* 页面内容自适应高度 */
.page-content {
height: calc(100vh - 8vh - 60px);
overflow-y: auto;
padding-right: 10px;
}
.page-content::-webkit-scrollbar {
width: 8px;
}
.page-content::-webkit-scrollbar-track {
background: rgba(25, 55, 95, 0.3);
border-radius: 4px;
}
.page-content::-webkit-scrollbar-thumb {
background: #40a9ff;
border-radius: 4px;
}
/* 内容卡片样式 */
.content-card {
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(64, 156, 255, 0.3);
color: #e0f0ff;
margin-bottom: 20px;
}
.content-card:last-child {
margin-bottom: 0;
}
.content-title {
height: 40px;
background: url('/assets/img/common/homeTitle2.png') no-repeat;
background-position: center;
background-size: 100% 100%;
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 20px -20px;
font-size: 1.2rem;
letter-spacing: 1px;
font-family: 'YouSheBiaoTiHei', 'Microsoft YaHei';
font-weight: 400;
color: #ffffff;
}
.content-title i {
margin-right: 10px;
color: #40a9ff;
}
/* 表格样式 */
.data-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
.data-table th,
.data-table td {
padding: 10px 15px;
text-align: left;
border-bottom: 1px solid rgba(64, 156, 255, 0.3);
}
.data-table th {
background: rgba(25, 55, 95, 0.6);
font-weight: normal;
color: #4fc3f7;
}
.data-table tr:hover {
background: rgba(64, 156, 255, 0.1);
}
/* 图表容器 */
.chart-wrapper {
height: 300px;
position: relative;
margin-top: 15px;
}
/* 通信记录样式 */
.communication-logs {
margin-top: 20px;
padding: 20px;
background: rgba(25, 55, 95, 0.6);
border-radius: 5px;
}
.log-list {
margin-top: 10px;
list-style: none;
}
.log-item {
padding: 8px 0;
border-bottom: 1px solid rgba(64, 156, 255, 0.3);
display: flex;
}
.log-time {
color: #40a9ff;
min-width: 80px;
font-weight: bold;
}
.log-content {
flex: 1;
}
.log-user {
color: #4fc3f7;
font-weight: bold;
margin-right: 5px;
}
/* 视频监控网格 */
.video-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-top: 15px;
}
.video-card {
background: rgba(25, 55, 95, 0.6);
border-radius: 10px;
padding: 15px;
text-align: center;
}
.video-placeholder-lg {
height: 180px;
background-image: url("/img_kekao/6.png");
background-size: 100% 100%;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
}
/* 设置项网格 */
.settings-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 15px;
}
.setting-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 5px;
padding: 15px;
position: relative;
}
.setting-item::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
border: 2px solid #26c6f0;
border-radius: 7px;
pointer-events: none;
clip-path: polygon(0% 0%, 10px 0%, 10px 2px, calc(100% - 10px) 2px, calc(100% - 10px) 0%, 100% 0%,
100% 10px, calc(100% - 2px) 10px, calc(100% - 2px) calc(100% - 10px), 100% calc(100% - 10px),
100% 100%, calc(100% - 10px) 100%, calc(100% - 10px) calc(100% - 2px), 10px calc(100% - 2px),
10px 100%, 0% 100%, 0% calc(100% - 10px), 2px calc(100% - 10px), 2px 10px, 0% 10px);
}
.setting-label {
font-size: 14px;
color: #a0d2ff;
margin-bottom: 8px;
}
.setting-value {
font-size: 18px;
font-weight: bold;
color: #e0f0ff;
}
.setting-input {
width: 100%;
padding: 8px;
background: rgba(12, 42, 73, 0.3);
border: 1px solid rgba(64, 156, 255, 0.5);
border-radius: 4px;
color: #e0f0ff;
margin-top: 5px;
}
.setting-input:focus {
outline: none;
border-color: #40a9ff;
box-shadow: 0 0 5px rgba(64, 169, 255, 0.5);
}
/* 按钮样式 */
.btn-primary {
background: rgba(64, 169, 255, 0.2);
border: 1px solid #40a9ff;
color: #e0f0ff;
padding: 8px 15px;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary:hover {
background: rgba(64, 169, 255, 0.4);
}
/* 响应式调整 */
@media (max-width: 768px) {
.page-content {
height: calc(100vh - 8vh - 40px);
padding-right: 5px;
}
.settings-grid,
.video-grid {
grid-template-columns: 1fr;
}
.data-grid {
grid-template-columns: 1fr 1fr;
}
}
</style>
</head>
<body>
<div class="topDiv">
<div class="top-header">
<div class="logo-container">
<!-- 这里应该放置实际的logo图片 -->
<img src="/common/images/logo_gt.png" alt="Logo">
</div>
<div class="system-title">科考任务综合管理系统</div>
<div class="header-right"> <i class="fa fa-ship"></i>
科考任务天数24
<!-- <div class="notification-button">
<button class="text-white hover:text-blue-300 transition-colors relative">
<i class="fa fa-bell text-xl"></i>
<span
class="absolute -top-1 -right-1 bg-danger text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">2</span>
</button>
</div> -->
<!-- <div class="user-info-container">
<div class="user-info-text">
<div class="text-sm"> <i class="fa fa-ship"></i>
科考任务天数</div>
<div class="text-sm">24</div>
</div>
</div> -->
</div>
</div>
</div>
<!-- 侧边栏 -->
<aside class="sidebar">
<ul>
<li><a href="#" class="active" data-page="home"><i class="fa fa-home"></i> <span>主页</span></a></li>
<li><a href="#" data-page="history"><i class="fa fa-history"></i> <span>历史查询</span></a></li>
<li><a href="#" data-page="voice"><i class="fa fa-microphone"></i> <span>语音通信</span></a></li>
<li><a href="#" data-page="video"><i class="fa fa-video-camera"></i> <span>视频监控</span></a></li>
<li><a href="#" data-page="settings"><i class="fa fa-cog"></i> <span>设置</span></a></li>
</ul>
</aside>
<!-- 主内容区域 -->
<div class="main-content">
<div class="container">
<!-- 主页内容 -->
<div id="home-page">
<!-- 第一行:天气现象及能见度仪曲线图 与 自动气象仪 -->
<div class="row" style="grid-template-columns: 1fr 3fr;">
<!-- 天气现象及能见度仪曲线图 -->
<div class="module-card" style="display: flex; flex-direction: column;">
<h3 class="module-title"><img src="/img/icon/云.png"> 天气现象及能见度仪曲线图</h3>
<div class="chart-container" style="flex: 1;">
<canvas id="weatherChart"></canvas>
</div>
</div>
<!-- 自动气象仪 -->
<div class="module-card" style="display: flex; flex-direction: column;">
<h3 class="module-title"><img src="/img/icon/气象仪.png">自动气象仪</h3>
<div class="row" style="flex: 1;grid-template-columns: 2fr 1fr;margin: 0;">
<div class="situation-chart-container" style="grid-template-columns: repeat(4, 1fr);">
<div class="situation-chart">
<div class="situation-title">实时风</div>
<div class="wind-direction-container">
<div class="wind-direction-indicator">
<div class="wind-direction-compass"></div>
<div class="wind-direction-arrow" id="windArrow"></div>
<div class="wind-direction-labels">
<div class="wind-direction-label north">N</div>
<div class="wind-direction-label east">E</div>
<div class="wind-direction-label south">S</div>
<div class="wind-direction-label west">W</div>
</div>
</div>
<div class="wind-direction-details">
<div class="wind-detail-item">
<div class="wind-detail-label">当前风向</div>
<div class="wind-detail-value" id="windDirectionValue">NE 45°</div>
</div>
<div class="wind-detail-item">
<div class="wind-detail-label">平均风速</div>
<div class="wind-detail-value">12.5 m/s</div>
</div>
</div>
</div>
</div>
<div class="situation-chart">
<div class="situation-title">气温</div>
<div class="wind-speed-container">
<div class="wind-speed-gauge">
<!-- <div class="wind-speed-fill" id="windSpeedFill" style="height: 60%"></div>
<div class="wind-speed-value" id="windSpeedValue">12.5m/s</div>
<div class="wind-speed-label">风速 (m/s)</div> -->
</div>
<div class="wind-speed-details">
<!-- <div class="wind-speed-detail-item">
<div class="wind-speed-detail-label">平均风速</div>
<div class="wind-speed-detail-value">12.5 m/s</div>
</div> -->
<div class="wind-speed-detail-item">
<div class="wind-speed-detail-label">温度</div>
<div class="wind-speed-detail-value">25.79 ℃</div>
</div>
</div>
</div>
</div>
<div class="situation-chart">
<div class="situation-title">湿度</div>
<div class="wave-height-container">
<div class="wave-height-gauge">
<!-- <div class="wave-height-fill" id="waveHeightFill" style="height: 60%"></div>
<div class="wave-height-value" id="waveHeightValue">2.5m</div>
<div class="wave-height-label">波高 (m)</div>
<div class="wave-pattern"></div> -->
</div>
<div class="wave-height-details">
<!-- <div class="wave-detail-item">
<div class="wave-detail-label">平均波高</div>
<div class="wave-detail-value">2.5 m</div>
</div> -->
<div class="wave-detail-item">
<div class="wave-detail-label">湿度</div>
<div class="wave-detail-value">60 %</div>
</div>
</div>
</div>
</div>
<div class="situation-chart">
<div class="situation-title">气压</div>
<div class="wave-direction-container">
<div class="wave-direction-indicator" id="humChart">
</div>
<div class="wave-direction-details">
<div class="wave-direction-detail-item">
<div class="wave-direction-detail-label">气压</div>
<div class="wave-direction-detail-value" id="waveDirectionValue">1013 hPa</div>
</div>
</div>
</div>
</div>
</div>
<div class="data-grid" style="grid-template-columns: repeat(4, 1fr);">
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">平均航速</div>
<div class="data-value">15.2 节</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">积累雨量</div>
<div class="data-value">63.35 mm</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">可见光云量</div>
<div class="data-value">14.9%</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">第一层云高</div>
<div class="data-value">257 m</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">第一层云厚</div>
<div class="data-value">33 m</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">雨强</div>
<div class="data-value">20.718 mm</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">红外云量</div>
<div class="data-value">9.1%</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">第二层云高</div>
<div class="data-value">1286 m</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">第二层云厚</div>
<div class="data-value">16 m</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">1分钟能见度</div>
<div class="data-value">5293 m</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">综合云量</div>
<div class="data-value">17.3 %</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">云底高</div>
<div class="data-value">257 m</div>
</div>
</div>
</div>
</div>
</div>
<!-- 第二行:激光测风雷达、风廓线雷达、测波雷达、水质测量仪 -->
<div class="row-second">
<!-- 修改激光测风雷达模块 -->
<div class="module-card">
<h3 class="module-title"><img src="/img/icon/激光雷达.png"> 激光测风雷达</h3>
<div class="chart-container">
<div id="windRadarChart" style="width: 100%; height: 100%;">
<div class="loading"
style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%;">
<div class="spinner"
style="border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 40px; height: 40px; animation: spin 2s linear infinite; margin-bottom: 15px;">
</div>
<div>风向杆图表加载中...</div>
</div>
</div>
</div>
</div>
<!-- 风廓线雷达 -->
<div class="module-card">
<h3 class="module-title"><img src="/img/icon/雷达.png">风廓线雷达</h3>
<div class="chart-container">
<div id="fanLineChart" style="width: 100%; height: 100%;"></div>
</div>
</div>
<!-- 测波雷达和水质测量仪容器 -->
<div class="combined-modules">
<!-- 测波雷达 -->
<div class="module-card">
<h3 class="module-title"><img src="/img/icon/测波雷达.png"> 测波雷达</h3>
<div class="wave-data-grid" style="gap: 20px;">
<div class="wave-data-item">
<div class="wave-data-label">最大波高</div>
<div class="wave-data-value">0.26 m</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">最大波高周期</div>
<div class="wave-data-value">2.75 s</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">1/10波高</div>
<div class="wave-data-value">0.2 m</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">1/10波高周期</div>
<div class="wave-data-value">3.81 s</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">有效波高</div>
<div class="wave-data-value">0.16 m</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">有效波高周期</div>
<div class="wave-data-value">3.15 s</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">平均波高</div>
<div class="wave-data-value">0.1 m</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">平均波高周期</div>
<div class="wave-data-value">2.18 s</div>
</div>
<div class="wave-data-item">
<div class="wave-data-label">皮向</div>
<div class="wave-data-value">82 Deg</div>
</div>
</div>
</div>
<!-- 水质测量仪 -->
<div class="module-card" style="display: flex; flex-direction: column;">
<h3 class="module-title"><img src="/img/icon/水质.png"> 水质测量仪</h3>
<div class="water-data-grid" style="flex: 1;">
<div class="water-data-item">
<div class="water-data-label">温度</div>
<div class="water-data-value">23.65 °C</div>
</div>
<div class="water-data-item">
<div class="water-data-label">浊度</div>
<div class="water-data-value">335.43 NTU</div>
</div>
<div class="water-data-item">
<div class="water-data-label">盐度</div>
<div class="water-data-value">0.2 ppt</div>
</div>
<div class="water-data-item">
<div class="water-data-label">电导率</div>
<div class="water-data-value">0.5094 mS/cm</div>
</div>
<div class="water-data-item">
<div class="water-data-label">溶解氧</div>
<div class="water-data-value">6.72 mg</div>
</div>
<div class="water-data-item">
<div class="water-data-label">PH</div>
<div class="water-data-value">7.53</div>
</div>
<div class="water-data-item">
<div class="water-data-label">蓝绿藻</div>
<div class="water-data-value">297.33 ug/L</div>
</div>
<div class="water-data-item">
<div class="water-data-label">叶绿素-a</div>
<div class="water-data-value">2.68 ug/L</div>
</div>
</div>
</div>
</div>
</div>
<!-- 第三行:海图显示、激光光阵雨滴谱仪/大气相干长度测量仪组合、ADCP、视频监控 -->
<div class="row">
<!-- 海图显示 -->
<div class="module-card" style="display: flex; flex-direction: column; height: 100%">
<h3 class="module-title"><img src="/img/icon/海图.png"> 海图显示</h3>
<div class="moule-img"
style="flex: 1; height: 100%; border-radius: 5px; display: flex; align-items: center; justify-content: center;">
<!-- <p>海图显示区域</p> -->
</div>
</div>
<!-- 激光光阵雨滴谱仪和大气相干长度测量仪组合 -->
<div class="module-card" style="display: flex; flex-direction: column; gap: 15px;">
<!-- 激光光阵雨滴谱仪 -->
<div style="flex: 1;">
<h3 class="module-title"><img src="/img/icon/云下载.png"> 激光光阵雨滴谱仪</h3>
<div class="data-grid" style="grid-template-columns: repeat(2, 1fr);">
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">天气</div>
<div class="data-value">小雨</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">更新时间</div>
<div class="data-value">2023-08-15 14:30:25</div>
</div>
</div>
</div>
<!-- 大气相干长度测量仪 -->
<div style="flex: 1; margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(64, 156, 255, 0.3);">
<h3 class="module-title"><img src="/img/icon/大气压.png">大气相干长度测量仪</h3>
<div class="data-grid">
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">大气相干长度</div>
<div class="data-value">0.020323 cm</div>
</div>
</div>
</div>
</div>
<!-- ADCP -->
<div class="module-card">
<h3 class="module-title"><img src="/img/icon/表格.png"> ADCP</h3>
<table>
<thead>
<tr>
<th>深度(m)</th>
<th>大小(m/s)</th>
<th>方向(Deg)</th>
<th>流速E(m/s)</th>
<th>流速N(m/s)</th>
<th>流速U(m/s)</th>
</tr>
</thead>
<tbody>
<tr>
<td>10</td>
<td>0.25</td>
<td>180</td>
<td>-0.25</td>
<td>0.00</td>
<td>0.05</td>
</tr>
<tr>
<td>20</td>
<td>0.30</td>
<td>190</td>
<td>-0.29</td>
<td>-0.05</td>
<td>0.08</td>
</tr>
<tr>
<td>30</td>
<td>0.35</td>
<td>200</td>
<td>-0.33</td>
<td>-0.12</td>
<td>0.12</td>
</tr>
<tr>
<td>40</td>
<td>0.40</td>
<td>210</td>
<td>-0.35</td>
<td>-0.20</td>
<td>0.15</td>
</tr>
<tr>
<td>50</td>
<td>0.45</td>
<td>220</td>
<td>-0.34</td>
<td>-0.29</td>
<td>0.18</td>
</tr>
</tbody>
</table>
</div>
<!-- 视频监控模块 -->
<div class="module-card" style="display: flex; flex-direction: column; height: 100%">
<h3 class="module-title"><img src="/img/icon/视频.png"> 视频监控</h3>
<div class="video-item" style="flex: 1;">
<div class="video-placeholder">
<!-- <i class="fa fa-video-camera fa-3x"></i> -->
</div>
<p>主甲板摄像头</p>
</div>
</div>
</div>
<!--
<div class="status">
<div class="status-item">
<i class="fa fa-signal"></i>
<div class="status-value">98%</div>
<div class="status-label">系统运行正常</div>
</div>
<div class="status-item">
<i class="fa fa-ship"></i>
<div class="status-value">24</div>
<div class="status-label">科考任务天数</div>
</div>
<div class="status-item">
<i class="fa fa-tachometer"></i>
<div class="status-value">15.2节</div>
<div class="status-label">平均航速</div>
</div>
<div class="status-item">
<i class="fa fa-thermometer-half"></i>
<div class="status-value">18.5°C</div>
<div class="status-label">海水表面温度</div>
</div>
</div> -->
<!--
<footer>
<p>科考任务综合管理系统 © 2023 国家海洋科学考察中心 | 当前版本: v2.5.1</p>
</footer> -->
</div>
<!-- 历史查询页面 -->
<div id="history-page" class="hidden">
<div class="page-content">
<div class="content-card">
<h3 class="content-title"><i class="fa fa-history"></i> 历史数据查询</h3>
<div class="data-grid">
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">查询时间范围</div>
<div class="data-value">2023-08-01 至 2023-08-15</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">数据类型</div>
<div class="data-value">气象数据</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">查询结果</div>
<div class="data-value">1,250 条记录</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">数据状态</div>
<div class="data-value">完整</div>
</div>
</div>
<div class="content-card" style="margin-top: 20px;">
<h4 class="content-title"><i class="fa fa-line-chart"></i> 历史数据图表</h4>
<div class="chart-wrapper">
<canvas id="historyChart"></canvas>
</div>
</div>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-database"></i> 历史数据详情</h3>
<table class="data-table">
<thead>
<tr>
<th>时间</th>
<th>温度 (°C)</th>
<th>湿度 (%)</th>
<th>风速 (m/s)</th>
<th>风向</th>
<th>气压 (hPa)</th>
</tr>
</thead>
<tbody>
<tr>
<td>2023-08-15 14:00</td>
<td>24.5</td>
<td>68</td>
<td>3.2</td>
<td>东北</td>
<td>1013.2</td>
</tr>
<tr>
<td>2023-08-15 13:00</td>
<td>24.2</td>
<td>70</td>
<td>2.8</td>
<td></td>
<td>1013.5</td>
</tr>
<tr>
<td>2023-08-15 12:00</td>
<td>25.1</td>
<td>65</td>
<td>3.5</td>
<td>东南</td>
<td>1012.8</td>
</tr>
<tr>
<td>2023-08-15 11:00</td>
<td>24.8</td>
<td>67</td>
<td>3.0</td>
<td></td>
<td>1013.0</td>
</tr>
<tr>
<td>2023-08-15 10:00</td>
<td>24.3</td>
<td>69</td>
<td>2.6</td>
<td>西南</td>
<td>1013.3</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- 语音通信页面 -->
<div id="voice-page" class="hidden">
<div class="page-content">
<div class="content-card">
<h3 class="content-title"><i class="fa fa-microphone"></i> 语音通信系统</h3>
<div class="data-grid">
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">通信状态</div>
<div class="data-value">正常</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">当前频道</div>
<div class="data-value">CH-08</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">信号强度</div>
<div class="data-value">-75 dBm</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">在线用户</div>
<div class="data-value">8/12</div>
</div>
</div>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-users"></i> 通信成员</h3>
<table class="data-table">
<thead>
<tr>
<th>成员</th>
<th>职位</th>
<th>状态</th>
<th>频道</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>张海洋</td>
<td>科考队长</td>
<td><span style="color: #4caf50;">在线</span></td>
<td>CH-08</td>
<td><button class="btn-primary">呼叫</button></td>
</tr>
<tr>
<td>李建国</td>
<td>船长</td>
<td><span style="color: #4caf50;">在线</span></td>
<td>CH-08</td>
<td><button class="btn-primary">呼叫</button></td>
</tr>
<tr>
<td>王海涛</td>
<td>大副</td>
<td><span style="color: #4caf50;">在线</span></td>
<td>CH-08</td>
<td><button class="btn-primary">呼叫</button></td>
</tr>
<tr>
<td>刘志强</td>
<td>气象员</td>
<td><span style="color: #ff9800;">离开</span></td>
<td>CH-05</td>
<td><button class="btn-primary">呼叫</button></td>
</tr>
<tr>
<td>陈海燕</td>
<td>海洋学家</td>
<td><span style="color: #4caf50;">在线</span></td>
<td>CH-08</td>
<td><button class="btn-primary">呼叫</button></td>
</tr>
</tbody>
</table>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-comments"></i> 通信记录</h3>
<div class="communication-logs">
<ul class="log-list">
<li class="log-item">
<div class="log-time">[14:25]</div>
<div class="log-content"><span class="log-user">船长:</span> 报告当前航向和速度</div>
</li>
<li class="log-item">
<div class="log-time">[14:26]</div>
<div class="log-content"><span class="log-user">大副:</span> 航向185度速度12.5节</div>
</li>
<li class="log-item">
<div class="log-time">[14:30]</div>
<div class="log-content"><span class="log-user">科考队长:</span> 请求调整航向至目标站点</div>
</li>
<li class="log-item">
<div class="log-time">[14:32]</div>
<div class="log-content"><span class="log-user">船长:</span> 收到,正在调整航向</div>
</li>
<li class="log-item">
<div class="log-time">[14:35]</div>
<div class="log-content"><span class="log-user">气象员:</span> 报告未来2小时天气稳定能见度良好</div>
</li>
<li class="log-item">
<div class="log-time">[14:40]</div>
<div class="log-content"><span class="log-user">海洋学家:</span> 请求启动CTD采样设备</div>
</li>
<li class="log-item">
<div class="log-time">[14:42]</div>
<div class="log-content"><span class="log-user">科考队长:</span> 同意启动,注意安全</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 视频监控页面 -->
<div id="video-page" class="hidden">
<div class="page-content">
<div class="content-card">
<h3 class="content-title"><i class="fa fa-video-camera"></i> 实时视频监控</h3>
<div class="video-grid">
<div class="video-card">
<div class="video-placeholder-lg">
<i class="fa fa-video-camera fa-3x"></i>
</div>
<p>主甲板摄像头 - 实时</p>
</div>
<div class="video-card">
<div class="video-placeholder-lg">
<i class="fa fa-video-camera fa-3x"></i>
</div>
<p>实验室监控 - 实时</p>
</div>
<div class="video-card">
<div class="video-placeholder-lg">
<i class="fa fa-video-camera fa-3x"></i>
</div>
<p>驾驶台监控 - 实时</p>
</div>
<div class="video-card">
<div class="video-placeholder-lg">
<i class="fa fa-video-camera fa-3x"></i>
</div>
<p>水下摄像头 - 实时</p>
</div>
</div>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-history"></i> 视频回放</h3>
<div class="data-grid">
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">回放时间</div>
<div class="data-value">2023-08-14 10:00</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">摄像头</div>
<div class="data-value">主甲板</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">时长</div>
<div class="data-value">2小时35分钟</div>
</div>
<div class="data-item" style="position: relative;">
<i class="topL"></i>
<i class="topR"></i>
<i class="bottomL"></i>
<i class="bottomR"></i>
<div class="data-label">状态</div>
<div class="data-value">已完成</div>
</div>
</div>
<div class="content-card" style="margin-top: 20px;">
<h4 class="content-title"><i class="fa fa-list"></i> 历史录像列表</h4>
<table class="data-table">
<thead>
<tr>
<th>时间</th>
<th>摄像头</th>
<th>时长</th>
<th>大小</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>2023-08-14 10:00</td>
<td>主甲板</td>
<td>2小时35分钟</td>
<td>1.2 GB</td>
<td><button class="btn-primary">播放</button></td>
</tr>
<tr>
<td>2023-08-14 08:00</td>
<td>实验室</td>
<td>2小时00分钟</td>
<td>1.1 GB</td>
<td><button class="btn-primary">播放</button></td>
</tr>
<tr>
<td>2023-08-14 06:00</td>
<td>驾驶台</td>
<td>2小时00分钟</td>
<td>1.0 GB</td>
<td><button class="btn-primary">播放</button></td>
</tr>
<tr>
<td>2023-08-13 14:00</td>
<td>主甲板</td>
<td>2小时15分钟</td>
<td>1.3 GB</td>
<td><button class="btn-primary">播放</button></td>
</tr>
<tr>
<td>2023-08-13 12:00</td>
<td>水下</td>
<td>1小时45分钟</td>
<td>0.9 GB</td>
<td><button class="btn-primary">播放</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 设置页面 -->
<div id="settings-page" class="hidden">
<div class="page-content">
<div class="content-card">
<h3 class="content-title"><i class="fa fa-user-circle"></i> 用户设置</h3>
<div class="settings-grid">
<div class="setting-item">
<div class="setting-label">用户名</div>
<div class="setting-value">张海洋</div>
</div>
<div class="setting-item">
<div class="setting-label">角色</div>
<div class="setting-value">科考队长</div>
</div>
<div class="setting-item">
<div class="setting-label">登录时间</div>
<div class="setting-value">2023-08-15 08:30</div>
</div>
<div class="setting-item">
<div class="setting-label">权限级别</div>
<div class="setting-value">管理员</div>
</div>
</div>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-sliders"></i> 系统参数</h3>
<div class="settings-grid">
<div class="setting-item">
<div class="setting-label">数据刷新频率</div>
<select class="setting-input">
<option>1 秒</option>
<option selected>5 秒</option>
<option>10 秒</option>
<option>30 秒</option>
<option>1 分钟</option>
</select>
</div>
<div class="setting-item">
<div class="setting-label">报警阈值</div>
<select class="setting-input">
<option>低敏感度</option>
<option selected>中敏感度</option>
<option>高敏感度</option>
</select>
</div>
<div class="setting-item">
<div class="setting-label">语言设置</div>
<select class="setting-input">
<option selected>中文</option>
<option>English</option>
</select>
</div>
<div class="setting-item">
<div class="setting-label">主题风格</div>
<select class="setting-input">
<option selected>深色主题</option>
<option>浅色主题</option>
</select>
</div>
</div>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-cog"></i> 设备配置</h3>
<div class="settings-grid">
<div class="setting-item">
<div class="setting-label">气象站</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">ADCP</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">水质仪</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">测波雷达</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">风廓线雷达</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">激光测风雷达</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">视频监控系统</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
<div class="setting-item">
<div class="setting-label">通信系统</div>
<div class="setting-value" style="color: #4caf50;">已连接</div>
</div>
</div>
</div>
<div class="content-card">
<h3 class="content-title"><i class="fa fa-info-circle"></i> 系统信息</h3>
<div class="settings-grid">
<div class="setting-item">
<div class="setting-label">系统版本</div>
<div class="setting-value">v2.5.1</div>
</div>
<div class="setting-item">
<div class="setting-label">运行时间</div>
<div class="setting-value">15天 6小时</div>
</div>
<div class="setting-item">
<div class="setting-label">内存使用率</div>
<div class="setting-value">42%</div>
</div>
<div class="setting-item">
<div class="setting-label">存储空间</div>
<div class="setting-value">2.1 TB / 4 TB</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 设置当前日期和时间
function updateDateTime() {
const now = new Date();
const dateStr = now.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
});
const timeStr = now.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
document.getElementById('current-date').textContent = dateStr;
document.getElementById('current-time').textContent = timeStr;
}
// updateDateTime();
// setInterval(updateDateTime, 1000);
// 页面切换功能增强
document.querySelectorAll('.sidebar a').forEach(link => {
link.addEventListener('click', function (e) {
e.preventDefault();
// 移除所有活动状态
document.querySelectorAll('.sidebar a').forEach(item => {
item.classList.remove('active');
});
// 添加当前活动状态
this.classList.add('active');
// 隐藏所有页面
document.querySelectorAll('#home-page, #history-page, #voice-page, #video-page, #settings-page').forEach(page => {
page.classList.add('hidden');
});
// 显示对应页面
const page = this.getAttribute('data-page');
document.getElementById(`${page}-page`).classList.remove('hidden');
// 如果是历史查询页面,初始化图表
if (page === 'history' && typeof initHistoryChart === 'function') {
initHistoryChart();
}
});
});
// 历史查询图表初始化
function initHistoryChart() {
const historyChartCtx = document.getElementById('historyChart');
if (historyChartCtx && !historyChartCtx.chart) {
const historyChart = new Chart(historyChartCtx, {
type: 'line',
data: {
labels: ['01-08', '02-08', '03-08', '04-08', '05-08', '06-08', '07-08', '08-08', '09-08', '10-08', '11-08', '12-08', '13-08', '14-08', '15-08'],
datasets: [
{
label: '温度 (°C)',
data: [22.5, 23.1, 24.2, 23.8, 22.9, 23.5, 24.1, 25.3, 24.8, 23.7, 22.6, 23.2, 24.0, 23.6, 24.4],
borderColor: '#40a9ff',
backgroundColor: 'rgba(64, 169, 255, 0.1)',
tension: 0.4,
fill: true
},
{
label: '湿度 (%)',
data: [65, 68, 70, 67, 63, 66, 69, 72, 71, 68, 64, 67, 70, 66, 69],
borderColor: '#7ec8e3',
backgroundColor: 'rgba(126, 200, 227, 0.1)',
tension: 0.4,
fill: true
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#e0f0ff'
}
}
},
scales: {
y: {
ticks: {
color: '#a0d2ff'
},
grid: {
color: 'rgba(64, 156, 255, 0.2)'
}
},
x: {
ticks: {
color: '#a0d2ff'
},
grid: {
color: 'rgba(64, 156, 255, 0.2)'
}
}
}
}
});
// 保存图表实例避免重复初始化
historyChartCtx.chart = historyChart;
}
}
// 天气现象及能见度仪曲线图
const weatherCtx = document.getElementById('weatherChart').getContext('2d');
const weatherChart = new Chart(weatherCtx, {
type: 'line',
data: {
labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
datasets: [{
label: '能见度 (m)',
data: [5000, 4800, 5200, 4900, 5100, 5300],
borderColor: '#40a9ff',
backgroundColor: 'rgba(64, 169, 255, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#e0f0ff'
}
}
},
scales: {
y: {
ticks: {
color: '#a0d2ff'
},
grid: {
color: 'rgba(64, 156, 255, 0.2)'
}
},
x: {
ticks: {
color: '#a0d2ff'
},
grid: {
color: 'rgba(64, 156, 255, 0.2)'
}
}
}
}
});
// // 风廓线雷达
// const fanLineCtx = document.getElementById('fanLineChart').getContext('2d');
// const fanLineChart = new Chart(fanLineCtx, {
// type: 'line',
// data: {
// labels: ['0m', '50m', '100m', '150m', '200m', '250m'],
// datasets: [{
// label: '风速剖面 (m/s)',
// data: [3, 4.5, 6, 7.2, 8, 8.5],
// borderColor: '#40a9ff',
// backgroundColor: 'rgba(64, 169, 255, 0.1)',
// tension: 0.4,
// fill: true
// }]
// },
// options: {
// responsive: true,
// maintainAspectRatio: false,
// plugins: {
// legend: {
// labels: {
// color: '#e0f0ff'
// }
// }
// },
// scales: {
// y: {
// ticks: {
// color: '#a0d2ff'
// },
// grid: {
// color: 'rgba(64, 156, 255, 0.2)'
// }
// },
// x: {
// ticks: {
// color: '#a0d2ff'
// },
// grid: {
// color: 'rgba(64, 156, 255, 0.2)'
// }
// }
// }
// }
// });
// 风向和波高态势图更新函数
function updateSituationCharts() {
// 随机更新风向0-360度
var windDirection = Math.floor(Math.random() * 360);
var windArrow = document.getElementById('windArrow');
if (windArrow) {
windArrow.style.transform = 'translate(-50%, -100%) rotate(' + windDirection + 'deg)';
}
// 更新风向显示
var directions = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'];
var index = Math.round(windDirection / 22.5) % 16;
var windDirectionValue = document.getElementById('windDirectionValue');
if (windDirectionValue) {
windDirectionValue.textContent = directions[index] + ' ' + windDirection + '°';
}
// // 随机更新风速5-20 m/s
// var windSpeed = 5 + Math.random() * 15;
// var windSpeedFill = document.getElementById('windSpeedFill');
// var windSpeedValue = document.getElementById('windSpeedValue');
// if (windSpeedFill && windSpeedValue) {
// // 风速填充高度最大20 m/s对应100%
// var windFillHeight = (windSpeed / 20) * 100;
// windSpeedFill.style.height = windFillHeight + '%';
// windSpeedValue.textContent = windSpeed.toFixed(1) + 'm/s';
// // 根据风速设置预警颜色
// if (windSpeed < 10) {
// windSpeedFill.className = 'wind-speed-fill';
// } else if (windSpeed < 15) {
// windSpeedFill.className = 'wind-speed-fill';
// } else {
// windSpeedFill.className = 'wind-speed-fill';
// }
// }
// // 随机更新波高0.5-5 m
// var waveHeight = 0.5 + Math.random() * 4.5;
// var waveHeightFill = document.getElementById('waveHeightFill');
// var waveHeightValue = document.getElementById('waveHeightValue');
// if (waveHeightFill && waveHeightValue) {
// // 波高填充高度最大5 m对应100%
// var waveFillHeight = (waveHeight / 5) * 100;
// waveHeightFill.style.height = waveFillHeight + '%';
// waveHeightValue.textContent = waveHeight.toFixed(1) + 'm';
// }
// // 随机更新波向0-360度
// var waveDirection = Math.floor(Math.random() * 360);
// var waveDirectionArrow = document.getElementById('waveDirectionArrow');
// var waveDirectionValue = document.getElementById('waveDirectionValue');
// if (waveDirectionArrow) {
// waveDirectionArrow.style.transform = 'translate(-50%, -100%) rotate(' + waveDirection + 'deg)';
// }
// if (waveDirectionValue) {
// var waveDirectionText = directions[Math.round(waveDirection / 22.5) % 16];
// waveDirectionValue.textContent = waveDirectionText + ' ' + waveDirection + '°';
// }
}
// 气压图表初始化函数
function initPressureChart() {
const humChartCtx = document.getElementById('humChart');
if (!humChartCtx) return;
const humChart = echarts.init(humChartCtx);
const humOptions = {
// 仪表盘系列配置(多个同心圆组成复合仪表盘)
series: [
// 第1个系列最内层红色圆环装饰用
{
type: 'gauge', // 类型为仪表盘
center: ['50%', '60%'], // 中心位置水平50%垂直60%
radius: '30%', // 半径占容器30%
min: 950, // 最小值
max: 1050, // 最大值
startAngle: 270, // 起始角度12点钟方向为0度
endAngle: -89.99999, // 结束角度形成270度的圆弧
splitNumber: 5, // 减少分割段数从10减少到5
axisLine: {
lineStyle: {
color: [[1, '#ff4500']], // 轴线颜色(红色)
width: 0, // 轴线宽度0表示不显示
shadowColor: '#fff', // 阴影颜色
shadowBlur: 10 // 阴影模糊大小
}
},
axisLabel: { show: false }, // 不显示刻度标签
axisTick: {
length: 4, // 刻度线长度
lineStyle: { color: 'rgba(176,204,53,.5)' } // 刻度线颜色(半透明绿色)
},
splitLine: { show: false }, // 不显示分割线
pointer: {
width: 0, // 指针宽度0表示不显示
shadowColor: '#fff', // 指针阴影颜色
shadowBlur: 5 // 指针阴影模糊大小
},
detail: { show: false } // 不显示详情
},
// 第2个系列中层灰色圆环装饰用
{
name: '气压', // 系列名称
type: 'gauge',
center: ['50%', '60%'],
radius: '60%', // 半径比内层大
min: 950,
max: 1050,
splitNumber: 5, // 减少分割段数从10减少到5
axisLine: {
lineStyle: {
color: [[1, '#037592']], // 轴线颜色(深灰色)
width: 8, // 轴线宽度
shadowBlur: 10 // 阴影模糊
}
},
axisLabel: {
textStyle: {
fontWeight: '',
color: 'rgba(30,144,255,0.3)', // 调整刻度数字颜色,降低透明度使其更清晰可见
shadowColor: '#fff',
shadowBlur: 10,
fontSize: 8 // 调整字体大小
},
distance: 0 // 调整标签距离
},
axisTick: {
length: 2, // 刻度线长度
lineStyle: { color: 'auto' } // 自动颜色
},
splitLine: {
length: 0, // 分割线长度0表示不显示
lineStyle: {
width: 0,
color: '#fff',
shadowColor: '#fff',
shadowBlur: 10
}
},
pointer: {
width: 0, // 不显示指针
shadowColor: '#fff',
shadowBlur: 5
},
detail: { show: false } // 不显示详情
},
// 第3个系列最外层主仪表盘显示红色指针
{
type: 'gauge',
center: ['50%', '60%'],
radius: '100%', // 最大半径(占满容器)
min: 950,
max: 2000,
name: '气压', // 系列名称(用于提示框显示)
splitNumber: 5, // 减少分割段数从10减少到5
axisLine: {
lineStyle: {
color: [[1, '#55D0D4']], // 轴线颜色(浅灰色)
width: 1 // 轴线宽度
}
},
itemStyle: {
normal: {
color: '#55D0D4' // 数据项颜色
}
},
axisTick: { length: 3 }, // 刻度线长度
axisLabel: {
textStyle: {
fontWeight: 'bolder', // 加粗字体
fontSize: 8, // 调整字体大小从10减小到8
fontFamily: 'Arial', // 字体
color: 'rgba(224, 240, 255, 0.8)' // 调整刻度数字颜色,使用半透明的浅色
},
distance: 2 // 调整标签距离
},
splitLine: {
length: 5, // 分割线长度
lineStyle: { width: 1 } // 分割线宽度
},
pointer: {
width: 3, // 指针宽度
length: '90%', // 指针长度(相对半径)
itemStyle: {
color: '#FF0000' // 指针颜色(红色)
}
},
detail: {
show: false,
formatter: '{value} hPa',
offsetCenter: [0, '80%'],
textStyle: {
fontSize: 14, // 稍微减小字体大小
color: '#e0f0ff'
}
}, // 显示详情
data: [{ value: 1013.2 }] // 绑定气压数据
}
]
};
humChart.setOption(humOptions);
// 添加窗口大小调整事件监听
window.addEventListener('resize', function () {
humChart.resize();
});
}
// 页面加载完成后初始化态势图
document.addEventListener('DOMContentLoaded', function () {
updateSituationCharts();
initPressureChart();
// 每5秒更新一次态势图数据
setInterval(updateSituationCharts, 5000);
});
</script>
<style>
.loading {
text-align: center;
padding: 50px;
font-size: 18px;
color: #666;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 2s linear infinite;
margin-bottom: 15px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.wind-barb-legend {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
margin: 10px 0;
font-size: 11px;
}
.legend-item {
text-align: center;
}
.legend-barb {
display: inline-block;
margin-bottom: 3px;
}
</style>
<script>
// 在页面加载完成后初始化风向杆图表
document.addEventListener('DOMContentLoaded', function () {
// 等待一段时间确保echarts加载完成
setTimeout(initWindBarbChart, 500);
setTimeout(initFanLineWindBarbChart, 1000);
});
function initWindBarbChart() {
const chartDom = document.getElementById('windRadarChart');
// 检查echarts是否已加载
if (typeof echarts === 'undefined') {
chartDom.innerHTML = `
<div class="loading">
<div style="color: #e74c3c; font-size: 24px;">⚠️</div>
<div>ECharts库加载失败</div>
<div style="font-size: 12px; margin-top: 10px;">请检查网络连接或刷新页面重试</div>
</div>
`;
return;
}
// 显示加载状态
chartDom.innerHTML = `
<div class="loading">
<div class="spinner"></div>
<div>正在生成风向杆数据...</div>
</div>
`;
// 延迟一小段时间后渲染图表,模拟数据加载
setTimeout(() => {
const myChart = echarts.init(chartDom);
// 风速颜色映射(与"风向杆.html"保持一致)
const windSpeedColors = [
{ min: 0, max: 2, color: '#98FB98', label: '0-2 m/s' }, // 浅绿色 - 微风
{ min: 2, max: 5, color: '#7EC8E3', label: '2-5 m/s' }, // 浅蓝色 - 轻风
{ min: 5, max: 10, color: '#FFD700', label: '5-10 m/s' }, // 黄色 - 和风
{ min: 10, max: 15, color: '#FFA500', label: '10-15 m/s' }, // 橙色 - 清风
{ min: 15, max: 20, color: '#FF6347', label: '15-20 m/s' }, // 番茄红 - 强风
{ min: 20, max: 25, color: '#DC143C', label: '20-25 m/s' }, // 深红 - 大风
{ min: 25, max: 50, color: '#8B0000', label: '25-50 m/s' } // 暗红 - 狂风
];
// 根据风速获取颜色
function getColorForWindSpeed(speed) {
for (const range of windSpeedColors) {
if (speed >= range.min && speed < range.max) {
return range.color;
}
}
return windSpeedColors[windSpeedColors.length - 1].color; // 默认返回最高风速颜色
}
// 绘制风矢杆
function drawWindBarb(ctx, direction, speed, barbLength, isExample = false) {
const radian = (direction - 180) * Math.PI / 180; // 指向风的来向
// 根据风速获取颜色
const color = getColorForWindSpeed(speed);
ctx.strokeStyle = color;
ctx.fillStyle = color;
ctx.lineWidth = 1.5;
ctx.lineCap = 'round';
if (speed === 0) {
// 静风 - 画圆圈
ctx.beginPath();
ctx.arc(0, 0, 4, 0, 2 * Math.PI);
ctx.stroke();
return;
}
// 绘制主杆
ctx.beginPath();
ctx.moveTo(0, 0);
const endX = Math.cos(radian) * barbLength;
const endY = Math.sin(radian) * barbLength;
ctx.lineTo(endX, endY);
ctx.stroke();
// 绘制风羽
let remainingSpeed = speed;
let position = 0;
const spacing = isExample ? 6 : 4;
// 绘制三角旗 (20 m/s)
const triangles = Math.floor(remainingSpeed / 20);
remainingSpeed %= 20;
for (let i = 0; i < triangles; i++) {
const posX = Math.cos(radian) * (position * spacing);
const posY = Math.sin(radian) * (position * spacing);
const perpendicular = radian + Math.PI / 2;
const triangleSize = isExample ? 8 : 6;
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(
posX + Math.cos(perpendicular) * triangleSize,
posY + Math.sin(perpendicular) * triangleSize
);
ctx.lineTo(
posX + Math.cos(radian) * triangleSize + Math.cos(perpendicular) * triangleSize,
posY + Math.sin(radian) * triangleSize + Math.sin(perpendicular) * triangleSize
);
ctx.closePath();
ctx.fill();
position += 2;
}
// 绘制长羽 (4 m/s)
const longFeathers = Math.floor(remainingSpeed / 4);
remainingSpeed %= 4;
for (let i = 0; i < longFeathers; i++) {
const posX = Math.cos(radian) * (position * spacing);
const posY = Math.sin(radian) * (position * spacing);
const perpendicular = radian + Math.PI / 2;
const featherLength = isExample ? 10 : 8;
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(
posX + Math.cos(perpendicular) * featherLength,
posY + Math.sin(perpendicular) * featherLength
);
ctx.stroke();
position += 1;
}
// 绘制短羽 (2 m/s)
const shortFeathers = Math.floor(remainingSpeed / 2);
for (let i = 0; i < shortFeathers; i++) {
const posX = Math.cos(radian) * (position * spacing);
const posY = Math.sin(radian) * (position * spacing);
const perpendicular = radian + Math.PI / 2;
const featherLength = isExample ? 6 : 5;
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(
posX + Math.cos(perpendicular) * featherLength,
posY + Math.sin(perpendicular) * featherLength
);
ctx.stroke();
position += 1;
}
}
// 生成精确数据
function generateData() {
const times = [];
const heights = [];
const data = [];
// 生成时间序列12个时间点
const now = new Date();
for (let i = 11; i >= 0; i--) {
const time = new Date(now.getTime() - i * 2 * 60 * 60 * 1000);
times.push(time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }));
}
// 生成高度序列从250m到3850m每240m一个点
for (let h = 250; h <= 3850; h += 240) {
heights.push(h);
}
// 根据要求生成精确的风向风速数据
for (let i = 0; i < times.length; i++) {
for (let j = 0; j < heights.length; j++) {
const height = heights[j];
let direction, speed;
// 根据高度设置风向风速
if (height === 250) {
// 250m: 东南风135°, 14m/s (3个长羽1个短羽)
direction = 135;
speed = 14;
} else if (height === 490) {
// 490m: 西北风315°, 16m/s (1个长羽)
direction = 315;
speed = 16;
} else if (height >= 730 && height <= 2170) {
// 730m至2170m: 东北风45°, 8m/s (1个长羽1个短羽)
direction = 45;
speed = 8;
} else if (height >= 2410 && height <= 3850) {
// 2410m至3850m: 东风90°, 45m/s (2个三角旗1个长羽1个短羽)
direction = 90;
speed = 45;
} else {
// 其他高度使用默认数据
const directions = [0, 45, 90, 135, 180, 225, 270, 315];
direction = directions[Math.floor(Math.random() * directions.length)];
speed = Math.floor(Math.random() * 20) + 5;
}
data.push([i, j, direction, speed]);
}
}
return { times, heights, data };
}
// 渲染风矢杆项目
function renderWindBarb(params, api) {
const xIndex = api.value(0);
const yIndex = api.value(1);
const direction = api.value(2);
const speed = api.value(3);
const point = api.coord([xIndex, yIndex]);
const barbLength = 25; // 风矢杆长度
const group = {
type: 'group',
children: [],
silent: false
};
// 创建canvas绘制风矢杆
const canvas = document.createElement('canvas');
canvas.width = 60;
canvas.height = 60;
const ctx = canvas.getContext('2d');
ctx.translate(30, 30);
drawWindBarb(ctx, direction, speed, barbLength);
group.children.push({
type: 'image',
style: {
image: canvas,
x: point[0] - 30,
y: point[1] - 30,
width: 60,
height: 60
}
});
return group;
}
// 获取风向文本描述
function getDirectionText(direction) {
const directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北'];
const index = Math.round(direction / 45) % 8;
return directions[index];
}
// 获取风羽描述
function getWindBarbDescription(speed) {
if (speed === 0) return '静风';
let description = '风羽: ';
let remaining = speed;
const triangles = Math.floor(remaining / 20);
remaining %= 20;
if (triangles > 0) description += `${triangles}个三角旗 `;
const longFeathers = Math.floor(remaining / 4);
remaining %= 4;
if (longFeathers > 0) description += `${longFeathers}个长羽 `;
const shortFeathers = Math.floor(remaining / 2);
if (shortFeathers > 0) description += `${shortFeathers}个短羽`;
return description.trim();
}
const { times, heights, data } = generateData();
const option = {
// title: {
// text: '激光测风雷达风向杆图',
// left: 'center',
// textStyle: {
// fontSize: 14,
// fontWeight: 'bold',
// color: '#e0f0ff'
// }
// },
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: '#40a9ff',
borderWidth: 1,
textStyle: {
color: '#e0f0ff'
},
formatter: function (params) {
const time = times[params.value[0]];
const height = heights[params.value[1]];
const direction = params.value[2];
const speed = params.value[3];
const directionText = getDirectionText(direction);
const barbDescription = getWindBarbDescription(speed);
const colorLabel = windSpeedColors.find(range => speed >= range.min && speed < range.max)?.label || '未知';
return `
<div style="font-weight: bold; margin-bottom: 5px;">${time}</div>
<div>高度: <b>${height}m</b></div>
<div>风向: <b>${Math.round(direction)}° ${directionText}</b></div>
<div>风速: <b>${speed} m/s</b></div>
<div style="margin-top: 5px; font-size: 12px; color: #ccc;">
${barbDescription}
</div>
<div style="font-size: 12px; color: #ccc;">
风速范围: ${colorLabel}
</div>
`;
}
},
grid: {
left: '60px',
right: '100px',
bottom: '30px',
top: '10px',
containLabel: false
},
xAxis: {
type: 'category',
data: times,
name: '时间',
nameLocation: 'middle',
nameGap: 30,
axisLabel: {
color: '#a0d2ff',
fontSize: 10,
interval: 1,
rotate: 45
},
axisLine: {
lineStyle: {
color: '#40a9ff'
}
}
},
yAxis: {
type: 'category',
data: heights.map(h => h + 'm'),
name: '高度 (m)',
nameLocation: 'middle',
nameGap: 50,
axisLabel: {
color: '#a0d2ff',
fontSize: 10
},
axisLine: {
lineStyle: {
color: '#40a9ff'
}
},
inverse: false // 从下往上递增
},
visualMap: {
type: 'piecewise',
min: 0,
max: 50,
orient: 'vertical',
right: 10,
top: 'center',
textStyle: {
color: '#a0d2ff',
fontSize: 9
},
pieces: windSpeedColors,
name: '风速\n(m/s)',
nameTextStyle: {
fontSize: 10,
fontWeight: 'bold',
color: '#e0f0ff'
},
formatter: function (value) {
// 自定义格式化显示
const range = windSpeedColors.find(range =>
value.min === range.min && value.max === range.max
);
return range ? range.label : '';
}
},
series: [{
name: '风矢杆',
type: 'custom',
renderItem: renderWindBarb,
data: data,
encode: {
x: [0],
y: [1]
},
animation: true,
animationDuration: 800
}],
// dataZoom: [ // 这里添加了dataZoom组件实现了横纵坐标轴的收缩功能
// {
// type: 'slider', // 这个 dataZoom 组件是滑动条类型
// start: 10, // 数据窗口的起始百分比默认为0即最左边
// end: 50 // 数据窗口的结束百分比默认为100即最右边
// },
// {
// type: 'inside', // 这个 dataZoom 组件是内置类型,即图表内部的一个滑动条
// }
// ]
};
myChart.setOption(option);
// 添加窗口大小调整事件监听
window.addEventListener('resize', function () {
myChart.resize();
});
// 创建图例示例
setTimeout(() => {
createLegendExamples();
}, 100);
// 创建图例示例
function createLegendExamples() {
// 创建图例容器
const legendContainer = document.createElement('div');
legendContainer.className = 'wind-barb-legend';
legendContainer.style.cssText = `
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
margin: 10px 0;
font-size: 11px;
`;
// 图例项
const legendItems = [
{ id: 'legend-short-feather', text: '短羽 = 2 m/s' },
{ id: 'legend-long-feather', text: '长羽 = 4 m/s' },
{ id: 'legend-triangle', text: '三角旗 = 20 m/s' },
{ id: 'legend-calm', text: '圆圈 = 静风' }
];
legendItems.forEach(item => {
const legendItem = document.createElement('div');
legendItem.className = 'legend-item';
legendItem.style.cssText = 'text-align: center;';
const legendBarb = document.createElement('div');
legendBarb.className = 'legend-barb';
legendBarb.id = item.id;
legendBarb.style.cssText = 'display: inline-block; margin-bottom: 3px;';
const legendText = document.createElement('div');
legendText.textContent = item.text;
legendItem.appendChild(legendBarb);
legendItem.appendChild(legendText);
legendContainer.appendChild(legendItem);
});
//chartDom.parentNode.appendChild(legendContainer);
// 创建风矢杆示例
createWindBarbExample('legend-short-feather', 0, 2, 0); // 短羽
createWindBarbExample('legend-long-feather', 0, 4, 0); // 长羽
createWindBarbExample('legend-triangle', 0, 20, 0); // 三角旗
createWindBarbExample('legend-calm', 0, 0, 0); // 静风
}
// 创建风矢杆示例
function createWindBarbExample(elementId, direction, speed, exampleDirection) {
const container = document.getElementById(elementId);
if (!container) return;
const canvas = document.createElement('canvas');
canvas.width = 50;
canvas.height = 50;
canvas.style.width = '50px';
canvas.style.height = '50px';
const ctx = canvas.getContext('2d');
ctx.translate(25, 25);
if (speed === 0) {
// 静风 - 画圆圈
ctx.beginPath();
ctx.arc(0, 0, 8, 0, 2 * Math.PI);
ctx.strokeStyle = '#000';
ctx.lineWidth = 1.5;
ctx.stroke();
} else {
// 风矢杆
drawWindBarb(ctx, exampleDirection, speed, 20, true);
}
container.appendChild(canvas);
}
}, 800); // 模拟数据加载时间
}
function initFanLineWindBarbChart() {
const chartDom = document.getElementById('fanLineChart');
// 检查echarts是否已加载
if (typeof echarts === 'undefined') {
chartDom.innerHTML = `
<div class="loading">
<div style="color: #e74c3c; font-size: 24px;">⚠️</div>
<div>ECharts库加载失败</div>
<div style="font-size: 12px; margin-top: 10px;">请检查网络连接或刷新页面重试</div>
</div>
`;
return;
}
// 显示加载状态
chartDom.innerHTML = `
<div class="loading">
<div class="spinner"></div>
<div>正在生成风廓线数据...</div>
</div>
`;
// 延迟一小段时间后渲染图表
setTimeout(() => {
const myChart = echarts.init(chartDom);
// 风速颜色映射(与"风向杆.html"保持一致)
const windSpeedColors = [
{ min: 0, max: 2, color: '#98FB98', label: '0-2 m/s' }, // 浅绿色 - 微风
{ min: 2, max: 5, color: '#7EC8E3', label: '2-5 m/s' }, // 浅蓝色 - 轻风
{ min: 5, max: 10, color: '#FFD700', label: '5-10 m/s' }, // 黄色 - 和风
{ min: 10, max: 15, color: '#FFA500', label: '10-15 m/s' }, // 橙色 - 清风
{ min: 15, max: 20, color: '#FF6347', label: '15-20 m/s' }, // 番茄红 - 强风
{ min: 20, max: 25, color: '#DC143C', label: '20-25 m/s' }, // 深红 - 大风
{ min: 25, max: 30, color: '#8B0000', label: '25-30 m/s' } // 深红色 - 狂风
];
// 生成风廓线数据(减少高度层数,优化显示效果)
function generateFanLineData() {
const times = [];
// 减少高度层数从原来21层减少到11层每隔200米一层
const heights = [0, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000];
const data = [];
// 生成时间序列12个时间点
const now = new Date();
for (let i = 11; i >= 0; i--) {
const time = new Date(now.getTime() - i * 10 * 60 * 1000);
times.push(time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }));
}
// 生成有规律的风向风速数据
for (let i = 0; i < times.length; i++) {
for (let j = 0; j < heights.length; j++) {
const height = heights[j];
let direction, speed;
// 根据高度和时间生成有规律的数据
// 高度影响风向和风速
if (height <= 200) {
// 地面附近:风向多变,风速较小
direction = (180 + Math.sin(i * 0.5) * 45 + Math.cos(height * 0.01) * 20) % 360;
speed = 2 + Math.sin(height * 0.02) * 1 + Math.cos(i * 0.3) * 0.5;
} else if (height <= 600) {
// 较低空域:偏南风,随高度增强
direction = (160 + Math.sin(i * 0.3) * 20) % 360;
speed = 4 + height * 0.01 + Math.sin(i * 0.4) * 1;
} else if (height <= 1200) {
// 中空域:西南风,较强且稳定
direction = (210 + Math.cos(i * 0.2) * 10) % 360;
speed = 8 + height * 0.005 + Math.sin(i * 0.2) * 2;
} else {
// 高空域:西风,很强且稳定
direction = (270 + Math.sin(i * 0.1) * 5) % 360;
speed = 15 + height * 0.003 + Math.cos(i * 0.15) * 3;
}
// 确保风速为正值
speed = Math.max(0, speed);
data.push([i, j, direction, speed]);
}
}
return { times, heights, data };
}
// 获取风向文本描述
function getDirectionText(direction) {
const directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北'];
const index = Math.round(direction / 45) % 8;
return directions[index];
}
// 获取风羽描述
function getWindBarbDescription(speed) {
if (speed === 0) return '静风';
let description = '风羽: ';
let remaining = speed;
const triangles = Math.floor(remaining / 20);
remaining %= 20;
if (triangles > 0) description += `${triangles}个三角旗 `;
const longFeathers = Math.floor(remaining / 4);
remaining %= 4;
if (longFeathers > 0) description += `${longFeathers}个长羽 `;
const shortFeathers = Math.floor(remaining / 2);
if (shortFeathers > 0) description += `${shortFeathers}个短羽`;
return description.trim() || '无风羽';
}
// 根据风速获取颜色
function getColorForWindSpeed(speed) {
for (const range of windSpeedColors) {
if (speed >= range.min && speed < range.max) {
return range.color;
}
}
return windSpeedColors[windSpeedColors.length - 1].color; // 默认返回最高风速颜色
}
// 绘制风矢杆
function drawWindBarb(ctx, direction, speed, barbLength, isExample = false) {
const radian = (direction - 180) * Math.PI / 180; // 指向风的来向
// 根据风速获取颜色
const color = getColorForWindSpeed(speed);
ctx.strokeStyle = color;
ctx.fillStyle = color;
ctx.lineWidth = 1.5;
ctx.lineCap = 'round';
if (speed === 0) {
// 静风 - 画圆圈
ctx.beginPath();
ctx.arc(0, 0, 4, 0, 2 * Math.PI);
ctx.stroke();
return;
}
// 绘制主干
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(Math.cos(radian) * barbLength, Math.sin(radian) * barbLength);
ctx.stroke();
// 绘制风羽
let remainingSpeed = speed;
let position = 1; // 羽毛位置计数器
const spacing = isExample ? 7 : 6; // 羽毛间距
// 绘制三角旗 (20 m/s)
const triangles = Math.floor(remainingSpeed / 20);
remainingSpeed %= 20;
for (let i = 0; i < triangles; i++) {
const posX = Math.cos(radian) * (position * spacing);
const posY = Math.sin(radian) * (position * spacing);
const perpendicular = radian + Math.PI / 2;
const featherLength = isExample ? 12 : 10;
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(
posX + Math.cos(perpendicular) * featherLength,
posY + Math.sin(perpendicular) * featherLength
);
ctx.lineTo(
posX + Math.cos(radian) * spacing * 0.8,
posY + Math.sin(radian) * spacing * 0.8
);
ctx.closePath();
ctx.fill();
position += 1;
}
// 绘制长羽 (4 m/s)
const longFeathers = Math.floor(remainingSpeed / 4);
remainingSpeed %= 4;
for (let i = 0; i < longFeathers; i++) {
const posX = Math.cos(radian) * (position * spacing);
const posY = Math.sin(radian) * (position * spacing);
const perpendicular = radian + Math.PI / 2;
const featherLength = isExample ? 10 : 8;
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(
posX + Math.cos(perpendicular) * featherLength,
posY + Math.sin(perpendicular) * featherLength
);
ctx.stroke();
position += 1;
}
// 绘制短羽 (2 m/s)
const shortFeathers = Math.floor(remainingSpeed / 2);
for (let i = 0; i < shortFeathers; i++) {
const posX = Math.cos(radian) * (position * spacing);
const posY = Math.sin(radian) * (position * spacing);
const perpendicular = radian + Math.PI / 2;
const featherLength = isExample ? 6 : 5;
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(
posX + Math.cos(perpendicular) * featherLength,
posY + Math.sin(perpendicular) * featherLength
);
ctx.stroke();
position += 1;
}
}
// 渲染风矢杆项目
function renderWindBarb(params, api) {
const xIndex = api.value(0);
const yIndex = api.value(1);
const direction = api.value(2);
const speed = api.value(3);
const point = api.coord([xIndex, yIndex]);
const barbLength = 20; // 风矢杆长度
const group = {
type: 'group',
children: [],
silent: false
};
// 创建canvas绘制风矢杆
const canvas = document.createElement('canvas');
canvas.width = 50;
canvas.height = 50;
const ctx = canvas.getContext('2d');
ctx.translate(25, 25);
drawWindBarb(ctx, direction, speed, barbLength);
group.children.push({
type: 'image',
style: {
image: canvas,
x: point[0] - 25,
y: point[1] - 25,
width: 50,
height: 50
}
});
return group;
}
const { times, heights, data } = generateFanLineData();
const option = {
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: '#40a9ff',
borderWidth: 1,
textStyle: {
color: '#e0f0ff'
},
formatter: function (params) {
const time = times[params.value[0]];
const height = heights[params.value[1]];
const direction = params.value[2];
const speed = params.value[3];
const directionText = getDirectionText(direction);
const barbDescription = getWindBarbDescription(speed);
const colorLabel = windSpeedColors.find(range => speed >= range.min && speed < range.max)?.label || '未知';
return `
<div style="font-weight: bold; margin-bottom: 5px;">${time}</div>
<div>高度: <b>${height}m</b></div>
<div>风向: <b>${Math.round(direction)}° ${directionText}</b></div>
<div>风速: <b>${speed.toFixed(1)} m/s</b></div>
<div style="margin-top: 5px; font-size: 12px; color: #ccc;">
${barbDescription}
</div>
<div style="font-size: 12px; color: #ccc;">
风速范围: ${colorLabel}
</div>
`;
}
},
grid: {
left: '60px',
right: '100px',
bottom: '30px',
top: '10px',
containLabel: false
},
xAxis: {
type: 'category',
data: times,
name: '时间',
nameLocation: 'middle',
nameGap: 30,
axisLabel: {
color: '#a0d2ff',
fontSize: 10,
interval: 1,
rotate: 45
},
axisLine: {
lineStyle: {
color: '#40a9ff'
}
}
},
yAxis: {
type: 'category',
data: heights.map(h => h + 'm'),
name: '高度 (m)',
nameLocation: 'middle',
nameGap: 50,
axisLabel: {
color: '#a0d2ff',
fontSize: 10
},
axisLine: {
lineStyle: {
color: '#40a9ff'
}
},
inverse: false // 从下往上递增
},
visualMap: {
type: 'piecewise',
min: 0,
max: 30,
orient: 'vertical',
right: 10,
top: 'center',
textStyle: {
color: '#a0d2ff',
fontSize: 9
},
pieces: windSpeedColors,
name: '风速\n(m/s)',
nameTextStyle: {
fontSize: 10,
fontWeight: 'bold',
color: '#e0f0ff'
},
formatter: function (value) {
// 自定义格式化显示
const range = windSpeedColors.find(range =>
value.min === range.min && value.max === range.max
);
return range ? range.label : '';
}
},
series: [{
name: '风矢杆',
type: 'custom',
renderItem: renderWindBarb,
data: data,
encode: {
x: [0],
y: [1]
},
animation: true,
animationDuration: 800
}]
};
myChart.setOption(option);
// 添加窗口大小调整事件监听
window.addEventListener('resize', function () {
myChart.resize();
});
}, 800);
}
</script>
</body>
</html>