1205 lines
43 KiB
HTML
1205 lines
43 KiB
HTML
<!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://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
font-family: 'Microsoft YaHei', 'Segoe UI', Arial, sans-serif;
|
||
}
|
||
|
||
:root {
|
||
--primary-color: #1890ff;
|
||
--primary-light: #40a9ff;
|
||
--primary-lighter: #69c0ff;
|
||
--fire-color: #ff4d4f;
|
||
--building-color: #faad14;
|
||
--environment-color: #52c41a;
|
||
--bg-color: #f0f8ff;
|
||
--card-bg: #ffffff;
|
||
--shadow-color: rgba(24, 144, 255, 0.1);
|
||
--border-color: #e6f7ff;
|
||
}
|
||
|
||
body {
|
||
background-color: var(--bg-color);
|
||
color: #1d3557;
|
||
min-height: 100vh;
|
||
padding: 20px;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30px;
|
||
padding: 0 20px;
|
||
}
|
||
|
||
.title-section h1 {
|
||
font-size: 28px;
|
||
color: var(--primary-color);
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.title-section .subtitle {
|
||
color: #666;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.notification-badge {
|
||
background-color: var(--fire-color);
|
||
color: white;
|
||
padding: 6px 12px;
|
||
border-radius: 20px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
/* 主内容区域 */
|
||
.main-container {
|
||
display: grid;
|
||
grid-template-columns: 2fr 1fr;
|
||
gap: 25px;
|
||
max-width: 1600px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* 左侧内容 */
|
||
.left-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 25px;
|
||
}
|
||
|
||
/* 平台卡片 */
|
||
.platform-cards {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.platform-card {
|
||
background-color: var(--card-bg);
|
||
border-radius: 12px;
|
||
padding: 25px;
|
||
box-shadow: 0 6px 16px var(--shadow-color);
|
||
transition: transform 0.3s, box-shadow 0.3s;
|
||
border-top: 5px solid transparent;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.platform-card:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.platform-card.fire-platform {
|
||
border-top-color: var(--fire-color);
|
||
}
|
||
|
||
.platform-card.building-platform {
|
||
border-top-color: var(--building-color);
|
||
}
|
||
|
||
.platform-card.environment-platform {
|
||
border-top-color: var(--environment-color);
|
||
}
|
||
|
||
.platform-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
width: 60px;
|
||
height: 60px;
|
||
background: rgba(0, 0, 0, 0.03);
|
||
border-radius: 50%;
|
||
transform: translate(20px, -20px);
|
||
}
|
||
|
||
.platform-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.platform-icon {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24px;
|
||
margin-right: 15px;
|
||
}
|
||
|
||
.fire-platform .platform-icon {
|
||
background-color: rgba(255, 77, 79, 0.1);
|
||
color: var(--fire-color);
|
||
}
|
||
|
||
.building-platform .platform-icon {
|
||
background-color: rgba(250, 173, 20, 0.1);
|
||
color: var(--building-color);
|
||
}
|
||
|
||
.environment-platform .platform-icon {
|
||
background-color: rgba(82, 196, 26, 0.1);
|
||
color: var(--environment-color);
|
||
}
|
||
|
||
.platform-info h3 {
|
||
font-size: 20px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.platform-status {
|
||
font-size: 14px;
|
||
color: #666;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.status-indicator {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background-color: #52c41a;
|
||
}
|
||
|
||
.status-indicator.offline {
|
||
background-color: #ff4d4f;
|
||
}
|
||
|
||
.platform-stats {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.stat-item {
|
||
text-align: center;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
display: block;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 12px;
|
||
color: #666;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.platform-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
transition: all 0.3s;
|
||
flex: 1;
|
||
}
|
||
|
||
.btn-primary {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background-color: var(--primary-light);
|
||
}
|
||
|
||
.btn-test {
|
||
background-color: #f0f0f0;
|
||
color: #333;
|
||
}
|
||
|
||
.btn-test:hover {
|
||
background-color: #e0e0e0;
|
||
}
|
||
|
||
/* 线索推送历史 */
|
||
.clue-history {
|
||
background-color: var(--card-bg);
|
||
border-radius: 12px;
|
||
padding: 25px;
|
||
box-shadow: 0 6px 16px var(--shadow-color);
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 20px;
|
||
margin-bottom: 20px;
|
||
color: #1d3557;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.history-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.history-table th {
|
||
text-align: left;
|
||
padding: 12px 15px;
|
||
border-bottom: 2px solid var(--border-color);
|
||
color: #666;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.history-table td {
|
||
padding: 15px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
font-size: 14px;
|
||
}
|
||
|
||
.history-table tr:hover {
|
||
background-color: #f9fdff;
|
||
}
|
||
|
||
/* 状态标签 */
|
||
.status-badge {
|
||
padding: 4px 10px;
|
||
border-radius: 20px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
display: inline-block;
|
||
}
|
||
|
||
.status-success {
|
||
background-color: rgba(82, 196, 26, 0.1);
|
||
color: #52c41a;
|
||
}
|
||
|
||
.status-pending {
|
||
background-color: rgba(250, 173, 20, 0.1);
|
||
color: #faad14;
|
||
}
|
||
|
||
.status-failed {
|
||
background-color: rgba(255, 77, 79, 0.1);
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
/* 右侧内容 */
|
||
.right-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 25px;
|
||
}
|
||
|
||
/* 推送配置 */
|
||
.push-config {
|
||
background-color: var(--card-bg);
|
||
border-radius: 12px;
|
||
padding: 25px;
|
||
box-shadow: 0 6px 16px var(--shadow-color);
|
||
}
|
||
|
||
.config-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
}
|
||
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.form-group label {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
|
||
.form-group input, .form-group select {
|
||
padding: 10px 15px;
|
||
border: 1px solid #d9d9d9;
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
transition: border-color 0.3s;
|
||
}
|
||
|
||
.form-group input:focus, .form-group select:focus {
|
||
outline: none;
|
||
border-color: var(--primary-color);
|
||
}
|
||
|
||
.checkbox-group {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 15px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.checkbox-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
/* 实时推送监控 */
|
||
.push-monitor {
|
||
background-color: var(--card-bg);
|
||
border-radius: 12px;
|
||
padding: 25px;
|
||
box-shadow: 0 6px 16px var(--shadow-color);
|
||
}
|
||
|
||
.monitor-chart {
|
||
height: 200px;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 推送统计 */
|
||
.push-stats {
|
||
background-color: var(--card-bg);
|
||
border-radius: 12px;
|
||
padding: 25px;
|
||
box-shadow: 0 6px 16px var(--shadow-color);
|
||
}
|
||
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 20px;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.stat-card {
|
||
text-align: center;
|
||
padding: 20px;
|
||
border-radius: 10px;
|
||
background-color: #f9fdff;
|
||
}
|
||
|
||
.stat-card.fire-stat {
|
||
border-left: 4px solid var(--fire-color);
|
||
}
|
||
|
||
.stat-card.building-stat {
|
||
border-left: 4px solid var(--building-color);
|
||
}
|
||
|
||
.stat-card .stat-number {
|
||
font-size: 28px;
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.stat-card .stat-label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 模态框 */
|
||
.modal {
|
||
display: none;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
z-index: 1000;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-content {
|
||
background-color: white;
|
||
border-radius: 12px;
|
||
padding: 30px;
|
||
width: 90%;
|
||
max-width: 600px;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.modal-title {
|
||
font-size: 20px;
|
||
color: #1d3557;
|
||
}
|
||
|
||
.close-modal {
|
||
background: none;
|
||
border: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
color: #999;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.main-container {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.platform-cards {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.header {
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.stats-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
/* 动画效果 */
|
||
@keyframes pulse {
|
||
0% { transform: scale(1); }
|
||
50% { transform: scale(1.05); }
|
||
100% { transform: scale(1); }
|
||
}
|
||
|
||
.pulse {
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
/* 滚动条美化 */
|
||
::-webkit-scrollbar {
|
||
width: 8px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
background: var(--primary-light);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background: var(--primary-color);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- 顶部导航 -->
|
||
<div class="header">
|
||
<div class="title-section">
|
||
<h1>无人机多平台线索推送系统</h1>
|
||
<div class="subtitle">智能识别结果自动分发至各业务平台</div>
|
||
</div>
|
||
<div class="notification-badge">
|
||
<span>📢</span>
|
||
<span id="unread-count">3条待处理线索</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-container">
|
||
<!-- 左侧内容 -->
|
||
<div class="left-content">
|
||
<!-- 平台卡片 -->
|
||
<div class="platform-cards">
|
||
<div class="platform-card fire-platform">
|
||
<div class="platform-header">
|
||
<div class="platform-icon">🔥</div>
|
||
<div class="platform-info">
|
||
<h3>防火监控平台</h3>
|
||
<div class="platform-status">
|
||
<span class="status-indicator"></span>
|
||
<span>连接正常</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="platform-stats">
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="fire-today">12</span>
|
||
<span class="stat-label">今日推送</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="fire-success">98%</span>
|
||
<span class="stat-label">成功率</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="fire-response">3.2s</span>
|
||
<span class="stat-label">平均响应</span>
|
||
</div>
|
||
</div>
|
||
<div class="platform-actions">
|
||
<button class="btn btn-primary" onclick="openPushModal('fire')">推送测试</button>
|
||
<button class="btn btn-test" onclick="viewPlatformDetails('fire')">查看详情</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="platform-card building-platform">
|
||
<div class="platform-header">
|
||
<div class="platform-icon">🏗️</div>
|
||
<div class="platform-info">
|
||
<h3>违建监测平台</h3>
|
||
<div class="platform-status">
|
||
<span class="status-indicator"></span>
|
||
<span>连接正常</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="platform-stats">
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="building-today">8</span>
|
||
<span class="stat-label">今日推送</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="building-success">95%</span>
|
||
<span class="stat-label">成功率</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="building-response">4.5s</span>
|
||
<span class="stat-label">平均响应</span>
|
||
</div>
|
||
</div>
|
||
<div class="platform-actions">
|
||
<button class="btn btn-primary" onclick="openPushModal('building')">推送测试</button>
|
||
<button class="btn btn-test" onclick="viewPlatformDetails('building')">查看详情</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="platform-card environment-platform">
|
||
<div class="platform-header">
|
||
<div class="platform-icon">🌳</div>
|
||
<div class="platform-info">
|
||
<h3>环保监测平台</h3>
|
||
<div class="platform-status">
|
||
<span class="status-indicator offline"></span>
|
||
<span>连接异常</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="platform-stats">
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="env-today">5</span>
|
||
<span class="stat-label">今日推送</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="env-success">87%</span>
|
||
<span class="stat-label">成功率</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-value" id="env-response">5.8s</span>
|
||
<span class="stat-label">平均响应</span>
|
||
</div>
|
||
</div>
|
||
<div class="platform-actions">
|
||
<button class="btn btn-primary" onclick="openPushModal('environment')">推送测试</button>
|
||
<button class="btn btn-test" onclick="reconnectPlatform('environment')">重新连接</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 线索推送历史 -->
|
||
<div class="clue-history">
|
||
<div class="section-title">
|
||
<span>最近推送记录</span>
|
||
<button class="btn btn-test" onclick="refreshHistory()">刷新</button>
|
||
</div>
|
||
<table class="history-table">
|
||
<thead>
|
||
<tr>
|
||
<th>时间</th>
|
||
<th>线索类型</th>
|
||
<th>目标平台</th>
|
||
<th>内容摘要</th>
|
||
<th>状态</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="history-body">
|
||
<!-- 历史记录将通过JavaScript动态生成 -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧内容 -->
|
||
<div class="right-content">
|
||
<!-- 推送配置 -->
|
||
<div class="push-config">
|
||
<div class="section-title">推送规则配置</div>
|
||
<form class="config-form" id="push-config-form">
|
||
<div class="form-group">
|
||
<label for="clue-type">线索类型自动分发</label>
|
||
<select id="clue-type">
|
||
<option value="auto">智能自动分发</option>
|
||
<option value="manual">手动确认分发</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>推送优先级设置</label>
|
||
<select id="priority-level">
|
||
<option value="high">高优先级(立即推送)</option>
|
||
<option value="normal" selected>普通优先级(批量推送)</option>
|
||
<option value="low">低优先级(定时推送)</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>重试机制</label>
|
||
<div class="checkbox-group">
|
||
<label class="checkbox-item">
|
||
<input type="checkbox" id="retry-enable" checked>
|
||
<span>启用失败重试</span>
|
||
</label>
|
||
<label class="checkbox-item">
|
||
<input type="checkbox" id="alert-enable" checked>
|
||
<span>失败时告警</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="retry-count">最大重试次数</label>
|
||
<input type="number" id="retry-count" value="3" min="1" max="10">
|
||
</div>
|
||
|
||
<button type="button" class="btn btn-primary" onclick="saveConfig()">保存配置</button>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- 实时推送监控 -->
|
||
<div class="push-monitor">
|
||
<div class="section-title">实时推送监控</div>
|
||
<div class="monitor-chart" id="monitor-chart"></div>
|
||
</div>
|
||
|
||
<!-- 推送统计 -->
|
||
<div class="push-stats">
|
||
<div class="section-title">今日推送统计</div>
|
||
<div class="stats-grid">
|
||
<div class="stat-card fire-stat">
|
||
<div class="stat-number" id="today-fire">12</div>
|
||
<div class="stat-label">防火线索</div>
|
||
</div>
|
||
<div class="stat-card building-stat">
|
||
<div class="stat-number" id="today-building">8</div>
|
||
<div class="stat-label">违建线索</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="success-rate">95%</div>
|
||
<div class="stat-label">推送成功率</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="avg-time">4.2s</div>
|
||
<div class="stat-label">平均响应时间</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 推送测试模态框 -->
|
||
<div class="modal" id="push-modal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<div class="modal-title" id="modal-title">推送测试到防火平台</div>
|
||
<button class="close-modal" onclick="closeModal()">×</button>
|
||
</div>
|
||
<div id="modal-body">
|
||
<!-- 模态框内容将通过JavaScript动态生成 -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 模拟数据
|
||
const platformData = {
|
||
fire: {
|
||
name: "防火监控平台",
|
||
todayPush: 12,
|
||
successRate: 98,
|
||
avgResponse: 3.2,
|
||
endpoint: "https://fire-platform.example.com/api/clue",
|
||
status: "connected"
|
||
},
|
||
building: {
|
||
name: "违建监测平台",
|
||
todayPush: 8,
|
||
successRate: 95,
|
||
avgResponse: 4.5,
|
||
endpoint: "https://building-platform.example.com/api/report",
|
||
status: "connected"
|
||
},
|
||
environment: {
|
||
name: "环保监测平台",
|
||
todayPush: 5,
|
||
successRate: 87,
|
||
avgResponse: 5.8,
|
||
endpoint: "https://env-platform.example.com/api/alert",
|
||
status: "disconnected"
|
||
}
|
||
};
|
||
|
||
// 模拟推送历史数据
|
||
const pushHistory = [
|
||
{ time: "10:23:15", type: "火点检测", platform: "防火平台", content: "发现疑似火点,坐标: (116.397, 39.916)", status: "success" },
|
||
{ time: "10:15:42", type: "违建识别", platform: "违建平台", content: "发现新增违建,面积约120㎡", status: "success" },
|
||
{ time: "10:08:33", type: "烟雾检测", platform: "防火平台", content: "发现异常烟雾,置信度92%", status: "success" },
|
||
{ time: "09:56:21", type: "排污监测", platform: "环保平台", content: "发现污水排放,坐标: (116.401, 39.912)", status: "failed" },
|
||
{ time: "09:42:11", type: "违建识别", platform: "违建平台", content: "发现施工违建,已持续3天", status: "success" },
|
||
{ time: "09:35:47", type: "火点检测", platform: "防火平台", content: "发现高温区域,温度65℃", status: "pending" },
|
||
{ time: "09:22:18", type: "垃圾堆放", platform: "环保平台", content: "发现违规垃圾堆放点", status: "success" },
|
||
{ time: "09:10:05", type: "违建识别", platform: "违建平台", content: "发现扩建违建,增加面积80㎡", status: "success" }
|
||
];
|
||
|
||
// 模拟线索类型
|
||
const clueTypes = [
|
||
{ id: 1, name: "火点检测", platform: "fire", icon: "🔥", color: "#ff4d4f" },
|
||
{ id: 2, name: "烟雾检测", platform: "fire", icon: "💨", color: "#ff4d4f" },
|
||
{ id: 3, name: "高温区域", platform: "fire", icon: "🌡️", color: "#ff4d4f" },
|
||
{ id: 4, name: "新增违建", platform: "building", icon: "🏗️", color: "#faad14" },
|
||
{ id: 5, name: "扩建违建", platform: "building", icon: "🔨", color: "#faad14" },
|
||
{ id: 6, name: "施工违建", platform: "building", icon: "🚧", color: "#faad14" },
|
||
{ id: 7, name: "排污监测", platform: "environment", icon: "🌊", color: "#52c41a" },
|
||
{ id: 8, name: "垃圾堆放", platform: "environment", icon: "🗑️", color: "#52c41a" },
|
||
{ id: 9, name: "水质异常", platform: "environment", icon: "💧", color: "#52c41a" }
|
||
];
|
||
|
||
// 初始化函数
|
||
function init() {
|
||
updatePlatformStats();
|
||
renderPushHistory();
|
||
initMonitorChart();
|
||
updateTodayStats();
|
||
|
||
// 模拟实时更新
|
||
setInterval(() => {
|
||
updateRealTimeData();
|
||
}, 3000);
|
||
}
|
||
|
||
// 更新平台统计信息
|
||
function updatePlatformStats() {
|
||
// 防火平台
|
||
document.getElementById('fire-today').textContent = platformData.fire.todayPush;
|
||
document.getElementById('fire-success').textContent = platformData.fire.successRate + '%';
|
||
document.getElementById('fire-response').textContent = platformData.fire.avgResponse + 's';
|
||
|
||
// 违建平台
|
||
document.getElementById('building-today').textContent = platformData.building.todayPush;
|
||
document.getElementById('building-success').textContent = platformData.building.successRate + '%';
|
||
document.getElementById('building-response').textContent = platformData.building.avgResponse + 's';
|
||
|
||
// 环保平台
|
||
document.getElementById('env-today').textContent = platformData.environment.todayPush;
|
||
document.getElementById('env-success').textContent = platformData.environment.successRate + '%';
|
||
document.getElementById('env-response').textContent = platformData.environment.avgResponse + 's';
|
||
}
|
||
|
||
// 渲染推送历史
|
||
function renderPushHistory() {
|
||
const historyBody = document.getElementById('history-body');
|
||
historyBody.innerHTML = '';
|
||
|
||
pushHistory.forEach(record => {
|
||
const row = document.createElement('tr');
|
||
|
||
// 状态标签
|
||
let statusBadge = '';
|
||
if (record.status === 'success') {
|
||
statusBadge = '<span class="status-badge status-success">成功</span>';
|
||
} else if (record.status === 'pending') {
|
||
statusBadge = '<span class="status-badge status-pending">处理中</span>';
|
||
} else {
|
||
statusBadge = '<span class="status-badge status-failed">失败</span>';
|
||
}
|
||
|
||
row.innerHTML = `
|
||
<td>${record.time}</td>
|
||
<td>${record.type}</td>
|
||
<td>${record.platform}</td>
|
||
<td>${record.content}</td>
|
||
<td>${statusBadge}</td>
|
||
`;
|
||
|
||
historyBody.appendChild(row);
|
||
});
|
||
}
|
||
|
||
// 初始化监控图表
|
||
function initMonitorChart() {
|
||
const chartDom = document.getElementById('monitor-chart');
|
||
const chart = echarts.init(chartDom);
|
||
|
||
const option = {
|
||
color: ['#1890ff', '#52c41a', '#faad14'],
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
axisPointer: {
|
||
type: 'shadow'
|
||
}
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
top: '10%',
|
||
containLabel: true
|
||
},
|
||
legend: {
|
||
data: ['防火平台', '违建平台', '环保平台'],
|
||
textStyle: {
|
||
color: '#666'
|
||
},
|
||
top: 0
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: ['09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00'],
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#d9d9d9'
|
||
}
|
||
}
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
name: '推送次数',
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#d9d9d9'
|
||
}
|
||
}
|
||
},
|
||
series: [
|
||
{
|
||
name: '防火平台',
|
||
type: 'bar',
|
||
stack: 'total',
|
||
emphasis: {
|
||
focus: 'series'
|
||
},
|
||
data: [2, 4, 3, 5, 3, 4, 2]
|
||
},
|
||
{
|
||
name: '违建平台',
|
||
type: 'bar',
|
||
stack: 'total',
|
||
emphasis: {
|
||
focus: 'series'
|
||
},
|
||
data: [1, 2, 2, 3, 2, 3, 1]
|
||
},
|
||
{
|
||
name: '环保平台',
|
||
type: 'bar',
|
||
stack: 'total',
|
||
emphasis: {
|
||
focus: 'series'
|
||
},
|
||
data: [0, 1, 1, 2, 1, 2, 0]
|
||
}
|
||
]
|
||
};
|
||
|
||
chart.setOption(option);
|
||
|
||
// 响应式调整
|
||
window.addEventListener('resize', function() {
|
||
chart.resize();
|
||
});
|
||
}
|
||
|
||
// 更新今日统计
|
||
function updateTodayStats() {
|
||
// 计算今日总数
|
||
let totalFire = 0;
|
||
let totalBuilding = 0;
|
||
|
||
pushHistory.forEach(record => {
|
||
if (record.platform === '防火平台') {
|
||
totalFire++;
|
||
} else if (record.platform === '违建平台') {
|
||
totalBuilding++;
|
||
}
|
||
});
|
||
|
||
// 计算成功率
|
||
let successCount = 0;
|
||
pushHistory.forEach(record => {
|
||
if (record.status === 'success') {
|
||
successCount++;
|
||
}
|
||
});
|
||
const successRate = Math.round((successCount / pushHistory.length) * 100);
|
||
|
||
// 更新显示
|
||
document.getElementById('today-fire').textContent = totalFire;
|
||
document.getElementById('today-building').textContent = totalBuilding;
|
||
document.getElementById('success-rate').textContent = successRate + '%';
|
||
}
|
||
|
||
// 更新实时数据
|
||
function updateRealTimeData() {
|
||
// 模拟数据变化
|
||
const now = new Date();
|
||
const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
||
|
||
// 随机添加新的推送记录
|
||
if (Math.random() > 0.7 && pushHistory.length < 15) {
|
||
const types = ['火点检测', '烟雾检测', '新增违建', '排污监测'];
|
||
const platforms = ['防火平台', '违建平台', '环保平台'];
|
||
const statuses = ['success', 'pending', 'failed'];
|
||
|
||
const newRecord = {
|
||
time: timeString,
|
||
type: types[Math.floor(Math.random() * types.length)],
|
||
platform: platforms[Math.floor(Math.random() * platforms.length)],
|
||
content: '模拟推送测试数据,坐标: (116.' + (397 + Math.floor(Math.random() * 10)) + ', 39.' + (916 + Math.floor(Math.random() * 10)) + ')',
|
||
status: statuses[Math.floor(Math.random() * statuses.length)]
|
||
};
|
||
|
||
pushHistory.unshift(newRecord);
|
||
if (pushHistory.length > 10) pushHistory.pop();
|
||
|
||
renderPushHistory();
|
||
updateTodayStats();
|
||
|
||
// 更新未读数量
|
||
const unreadCount = pushHistory.filter(r => r.status === 'pending').length;
|
||
document.getElementById('unread-count').textContent = unreadCount + '条待处理线索';
|
||
}
|
||
}
|
||
|
||
// 打开推送测试模态框
|
||
function openPushModal(platformType) {
|
||
const modal = document.getElementById('push-modal');
|
||
const modalTitle = document.getElementById('modal-title');
|
||
const modalBody = document.getElementById('modal-body');
|
||
|
||
const platform = platformData[platformType];
|
||
|
||
modalTitle.textContent = `推送测试到${platform.name}`;
|
||
|
||
// 根据平台类型生成不同的测试内容
|
||
let testContent = '';
|
||
let testButtonText = '立即推送';
|
||
|
||
if (platformType === 'fire') {
|
||
testContent = `
|
||
<div style="margin-bottom: 20px;">
|
||
<h3 style="margin-bottom: 10px; color: #ff4d4f;">🔥 防火线索测试</h3>
|
||
<p style="color: #666; margin-bottom: 15px;">模拟推送一条防火线索到${platform.name}</p>
|
||
<div style="background-color: #f9fdff; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
||
<p><strong>线索内容:</strong>发现疑似火点,坐标: (116.397128, 39.916527)</p>
|
||
<p><strong>置信度:</strong>92%</p>
|
||
<p><strong>温度:</strong>65℃</p>
|
||
<p><strong>推送端点:</strong>${platform.endpoint}</p>
|
||
</div>
|
||
</div>
|
||
`;
|
||
} else if (platformType === 'building') {
|
||
testContent = `
|
||
<div style="margin-bottom: 20px;">
|
||
<h3 style="margin-bottom: 10px; color: #faad14;">🏗️ 违建线索测试</h3>
|
||
<p style="color: #666; margin-bottom: 15px;">模拟推送一条违建线索到${platform.name}</p>
|
||
<div style="background-color: #f9fdff; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
||
<p><strong>线索内容:</strong>发现新增违建,面积约120㎡</p>
|
||
<p><strong>置信度:</strong>88%</p>
|
||
<p><strong>位置:</strong>XX区XX街道XX号</p>
|
||
<p><strong>推送端点:</strong>${platform.endpoint}</p>
|
||
</div>
|
||
</div>
|
||
`;
|
||
} else {
|
||
testContent = `
|
||
<div style="margin-bottom: 20px;">
|
||
<h3 style="margin-bottom: 10px; color: #52c41a;">🌳 环保线索测试</h3>
|
||
<p style="color: #666; margin-bottom: 15px;">模拟推送一条环保线索到${platform.name}</p>
|
||
<div style="background-color: #f9fdff; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
||
<p><strong>线索内容:</strong>发现污水排放,坐标: (116.401, 39.912)</p>
|
||
<p><strong>置信度:</strong>85%</p>
|
||
<p><strong>排放类型:</strong>工业废水</p>
|
||
<p><strong>推送端点:</strong>${platform.endpoint}</p>
|
||
</div>
|
||
${platform.status === 'disconnected' ? '<div style="background-color: #fff2f0; padding: 10px; border-radius: 6px; margin-bottom: 15px; color: #ff4d4f; border: 1px solid #ffccc7;">⚠️ 当前平台连接异常,推送可能失败</div>' : ''}
|
||
</div>
|
||
`;
|
||
|
||
if (platform.status === 'disconnected') {
|
||
testButtonText = '尝试推送';
|
||
}
|
||
}
|
||
|
||
modalBody.innerHTML = testContent + `
|
||
<div style="display: flex; gap: 10px;">
|
||
<button class="btn btn-primary" style="flex: 1;" onclick="testPush('${platformType}')">${testButtonText}</button>
|
||
<button class="btn btn-test" style="flex: 1;" onclick="closeModal()">取消</button>
|
||
</div>
|
||
`;
|
||
|
||
modal.style.display = 'flex';
|
||
}
|
||
|
||
// 关闭模态框
|
||
function closeModal() {
|
||
document.getElementById('push-modal').style.display = 'none';
|
||
}
|
||
|
||
// 测试推送
|
||
function testPush(platformType) {
|
||
const platform = platformData[platformType];
|
||
|
||
// 模拟推送延迟
|
||
setTimeout(() => {
|
||
// 模拟成功或失败
|
||
const isSuccess = platform.status === 'connected' ? Math.random() > 0.3 : false;
|
||
|
||
if (isSuccess) {
|
||
alert(`✅ 推送测试成功!线索已发送到${platform.name}`);
|
||
|
||
// 更新统计数据
|
||
platform.todayPush++;
|
||
updatePlatformStats();
|
||
|
||
// 添加到历史记录
|
||
const now = new Date();
|
||
const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
||
|
||
let typeName = '';
|
||
let content = '';
|
||
|
||
if (platformType === 'fire') {
|
||
typeName = '火点检测';
|
||
content = '测试推送:发现疑似火点,坐标: (116.397, 39.916)';
|
||
} else if (platformType === 'building') {
|
||
typeName = '违建识别';
|
||
content = '测试推送:发现新增违建,面积约120㎡';
|
||
} else {
|
||
typeName = '排污监测';
|
||
content = '测试推送:发现污水排放,坐标: (116.401, 39.912)';
|
||
}
|
||
|
||
pushHistory.unshift({
|
||
time: timeString,
|
||
type: typeName,
|
||
platform: platform.name,
|
||
content: content,
|
||
status: 'success'
|
||
});
|
||
|
||
if (pushHistory.length > 10) pushHistory.pop();
|
||
|
||
renderPushHistory();
|
||
updateTodayStats();
|
||
} else {
|
||
alert(`❌ 推送测试失败!${platform.name}连接异常,请检查网络配置或平台状态。`);
|
||
|
||
// 添加到失败记录
|
||
const now = new Date();
|
||
const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
||
|
||
pushHistory.unshift({
|
||
time: timeString,
|
||
type: '连接测试',
|
||
platform: platform.name,
|
||
content: '平台连接测试失败',
|
||
status: 'failed'
|
||
});
|
||
|
||
if (pushHistory.length > 10) pushHistory.pop();
|
||
|
||
renderPushHistory();
|
||
}
|
||
|
||
closeModal();
|
||
}, 1000);
|
||
}
|
||
|
||
// 查看平台详情
|
||
function viewPlatformDetails(platformType) {
|
||
const platform = platformData[platformType];
|
||
alert(`📋 ${platform.name}详情\n\n` +
|
||
`接口端点: ${platform.endpoint}\n` +
|
||
`今日推送: ${platform.todayPush}条\n` +
|
||
`推送成功率: ${platform.successRate}%\n` +
|
||
`平均响应时间: ${platform.avgResponse}秒\n` +
|
||
`连接状态: ${platform.status === 'connected' ? '正常' : '异常'}`);
|
||
}
|
||
|
||
// 重新连接平台
|
||
function reconnectPlatform(platformType) {
|
||
const platform = platformData[platformType];
|
||
|
||
// 模拟重新连接过程
|
||
setTimeout(() => {
|
||
platform.status = 'connected';
|
||
document.querySelector(`.${platformType}-platform .status-indicator`).classList.remove('offline');
|
||
document.querySelector(`.${platformType}-platform .platform-status span:nth-child(2)`).textContent = '连接正常';
|
||
|
||
alert(`✅ ${platform.name}重新连接成功!`);
|
||
}, 1500);
|
||
}
|
||
|
||
// 刷新历史记录
|
||
function refreshHistory() {
|
||
renderPushHistory();
|
||
alert('历史记录已刷新!');
|
||
}
|
||
|
||
// 保存配置
|
||
function saveConfig() {
|
||
const clueType = document.getElementById('clue-type').value;
|
||
const priority = document.getElementById('priority-level').value;
|
||
const retryCount = document.getElementById('retry-count').value;
|
||
|
||
alert(`✅ 配置已保存!\n\n` +
|
||
`线索分发模式: ${clueType === 'auto' ? '智能自动分发' : '手动确认分发'}\n` +
|
||
`推送优先级: ${priority === 'high' ? '高' : priority === 'normal' ? '普通' : '低'}\n` +
|
||
`最大重试次数: ${retryCount}次`);
|
||
}
|
||
|
||
// 页面加载完成后初始化
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
|
||
// 点击模态框外部关闭
|
||
window.onclick = function(event) {
|
||
const modal = document.getElementById('push-modal');
|
||
if (event.target === modal) {
|
||
closeModal();
|
||
}
|
||
};
|
||
</script>
|
||
</body>
|
||
</html> |