| | |
| | | <div class="top-cards"> |
| | | <!-- 时间周期选项卡片 --> |
| | | <div class="time-period-card"> |
| | | <div class="card-title">时间选择</div> |
| | | <!-- <div class="card-title">时间选择</div> --> |
| | | <div class="time-controls"> |
| | | <div class="time-tab-container"> |
| | | <div |
| | |
| | | </div> |
| | | </div> |
| | | <div class="cards-container"> |
| | | <!-- 超标数 --> |
| | | <!-- 浓度预警 --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">{{ getPeriodLabel() }}超标数</div> |
| | | <div class="card-title">{{ getPeriodLabel() }}浓度预警</div> |
| | | <div class="card-icon warning-icon"> |
| | | <svg |
| | | width="20" |
| | |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.overStandardCount }}</div> |
| | | <div class="card-value">{{ metrics.overStandardCount }}<el-text>次</el-text></div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 在线率 --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">在线率</div> |
| | | <div class="card-icon online-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M9 12L11 14L15 10" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | <!-- 设备在线率 --> |
| | | <el-popover placement="right-start" title="设备监控" width="400" trigger="click"> |
| | | <div class="popover-content"> |
| | | <div class="overview-items-container"> |
| | | <div class="overview-item"> |
| | | <div class="overview-label">餐饮店铺总数</div> |
| | | <div class="overview-value">{{ overview.totalShops }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">在线设备数</div> |
| | | <div class="overview-value">{{ overview.onlineDevices }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">离线设备数</div> |
| | | <div class="overview-value">{{ overview.offlineDevices }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 设备状态饼图 --> |
| | | <div class="device-status-chart"> |
| | | <canvas id="deviceStatusChart"></canvas> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.onlineRate }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ up: metrics.onlineRateTrend > 0, down: metrics.onlineRateTrend < 0 }" |
| | | > |
| | | {{ metrics.onlineRateTrend > 0 ? '↑' : '↓' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.onlineRateTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | <template #reference> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">设备在线率</div> |
| | | <div class="card-icon online-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M9 12L11 14L15 10" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.onlineRate }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ up: metrics.onlineRateTrend > 0, down: metrics.onlineRateTrend < 0 }" |
| | | > |
| | | {{ metrics.onlineRateTrend > 0 ? '↑' : '↓' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.onlineRateTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | <div class="view-details"> |
| | | <span>详情</span> |
| | | <svg |
| | | width="12" |
| | | height="12" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M9 18L15 12L9 6" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-popover> |
| | | |
| | | <!-- 净化器运行效率 --> |
| | | <!-- 环信码绿码率 --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">净化器运行效率</div> |
| | | <div class="card-title">环信码绿码率</div> |
| | | <div class="card-icon efficiency-icon"> |
| | | <svg |
| | | width="20" |
| | |
| | | </div> |
| | | |
| | | <!-- 巡查点次 --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">巡查点次</div> |
| | | <div class="card-icon task-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M22 11.08V12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C15.7376 2 19.0503 4.16113 20.7748 7.33007" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M22 4L12 14.01L9 11.01" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | <el-popover placement="right-start" title="现场巡查统计" width="350" trigger="click"> |
| | | <div class="inspection-popover-content"> |
| | | <!-- 巡查量统计 --> |
| | | <div class="inspection-metrics"> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">店铺总计</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.totalShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">巡查店铺</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.inspectedShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">巡查点次</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.inspectionPoints }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">复查点次</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.reviewPoints }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 问题整改情况 --> |
| | | <div class="inspection-chart-container"> |
| | | <div class="section-header"><h3>问题整改</h3></div> |
| | | <canvas id="rectificationChart"></canvas> |
| | | </div> |
| | | |
| | | <!-- 问题审核情况 --> |
| | | <div class="inspection-table-container" style="display: none"> |
| | | <div class="section-header"><h3>审核汇总</h3></div> |
| | | <div class="inspection-metric-label">问题审核</div> |
| | | <div class="inspection-table"> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">无问题</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.noProblemShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">未审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.unreviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">部分审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.partiallyReviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">全部审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.fullyReviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-label">整改审核</div> |
| | | <div class="inspection-table"> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">未整改</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.unrectifiedShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">未审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.unreviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">部分审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.partiallyReviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">全部审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.fullyReviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.inspectionPoints }}</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ |
| | | up: metrics.inspectionPointsTrend > 0, |
| | | down: metrics.inspectionPointsTrend < 0, |
| | | }" |
| | | > |
| | | {{ metrics.inspectionPointsTrend > 0 ? '↑' : '↓' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.inspectionPointsTrend) }}</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | <template #reference> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">巡查点次</div> |
| | | <div class="card-icon task-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M22 11.08V12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C15.7376 2 19.0503 4.16113 20.7748 7.33007" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M22 4L12 14.01L9 11.01" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.inspectionPoints }}</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ |
| | | up: metrics.inspectionPointsTrend > 0, |
| | | down: metrics.inspectionPointsTrend < 0, |
| | | }" |
| | | > |
| | | {{ metrics.inspectionPointsTrend > 0 ? '↑' : '↓' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.inspectionPointsTrend) }}</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | <div class="view-details"> |
| | | <span>详情</span> |
| | | <svg |
| | | width="12" |
| | | height="12" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M9 18L15 12L9 6" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-popover> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <div id="map" class="map-container"> |
| | | <BaseMap :showSatellite="true"></BaseMap> |
| | | </div> |
| | | |
| | | <!-- 地图点位弹窗 --> |
| | | <el-dialog v-model="dialogVisible" title="企业实时数据" width="400px"> |
| | | <div class="dialog-content"> |
| | | <el-descriptions :column="1" border> |
| | | <el-descriptions-item label="企业名称">{{ |
| | | selectedPoint.enterpriseName |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="设备编号">{{ |
| | | selectedPoint.deviceId |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="油烟浓度" |
| | | >{{ selectedPoint.oilSmokeConcentration }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="颗粒物" |
| | | >{{ selectedPoint.particulateMatter }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="非甲烷总烃" |
| | | >{{ selectedPoint.nonMethaneHydrocarbon }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="监测时间">{{ |
| | | selectedPoint.monitoringTime |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="超标情况"> |
| | | <el-tag :type="selectedPoint.isOverStandard ? 'danger' : 'success'"> |
| | | {{ selectedPoint.isOverStandard ? '超标' : '正常' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">关闭</el-button> |
| | | <el-button type="primary" @click="viewDetails">查看详情</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | <!-- 右侧实时监测总览区 --> |
| | | <div class="overview-section"> |
| | | <div class="section-header"> |
| | | <h3>设备监控</h3> |
| | | <!-- <span class="view-more">查看更多</span> --> |
| | | </div> |
| | | |
| | | <div class="overview-items-container"> |
| | | <div class="overview-item"> |
| | | <div class="overview-label">餐饮店铺总数</div> |
| | | <div class="overview-value">{{ overview.totalShops }}</div> |
| | | <div class="monitor-control-container"> |
| | | <el-button size="large" @click="toggleMonitorControl" class="push-btn"> |
| | | <div style="display: flex; flex-direction: column"> |
| | | <el-icon> |
| | | <ArrowRight v-if="isMonitorControlExpanded" /> |
| | | <ArrowLeft v-else /> |
| | | </el-icon> |
| | | <div>现</div> |
| | | <div>场</div> |
| | | <div>巡</div> |
| | | <div>查</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">在线设备数</div> |
| | | <div class="overview-value">{{ overview.onlineDevices }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">离线设备数</div> |
| | | <div class="overview-value">{{ overview.offlineDevices }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 设备状态饼图 --> |
| | | <div class="device-status-chart"> |
| | | <canvas id="deviceStatusChart"></canvas> |
| | | </div> |
| | | </el-button> |
| | | <MonitorControl |
| | | v-if="isMonitorControlExpanded" |
| | | :class="{ 'monitor-control': true, collapsed: !isMonitorControlExpanded }" |
| | | style="height: calc(90vh - 40px)" |
| | | /> |
| | | </div> |
| | | |
| | | <!-- 地图图例 --> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 巡查情况统计卡片 --> |
| | | <el-scrollbar class="inspection-section"> |
| | | <div class="section-header"> |
| | | <h3>巡查汇总</h3> |
| | | </div> |
| | | |
| | | <!-- 巡查量统计 --> |
| | | <div class="inspection-metrics"> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">店铺总计</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.totalShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">巡查店铺</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.inspectedShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">巡查点次</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.inspectionPoints }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">复查点次</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.reviewPoints }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 问题整改情况 --> |
| | | <div class="inspection-chart-container"> |
| | | <div class="section-header"><h3>整改汇总</h3></div> |
| | | <canvas id="rectificationChart"></canvas> |
| | | </div> |
| | | |
| | | <!-- 问题审核情况 --> |
| | | <div class="inspection-table-container"> |
| | | <div class="section-header"><h3>审核汇总</h3></div> |
| | | <div class="inspection-metric-label">问题审核</div> |
| | | <div class="inspection-table"> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">无问题</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.noProblemShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">未审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.unreviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">部分审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.partiallyReviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">全部审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.fullyReviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-label">整改审核</div> |
| | | <div class="inspection-table"> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">未整改</div> |
| | | <div class="inspection-metric-value">{{ inspectionStats.unrectifiedShops }}</div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">未审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.unreviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">部分审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.partiallyReviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | <div class="inspection-metric-item"> |
| | | <div class="inspection-metric-label">全部审核</div> |
| | | <div class="inspection-metric-value"> |
| | | {{ inspectionStats.fullyReviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | <!-- <div class="table-row"> |
| | | <div class="table-cell">无问题店铺数量</div> |
| | | <div class="table-cell value">{{ inspectionStats.noProblemShops }}</div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">问题未审核店铺数量</div> |
| | | <div class="table-cell value">{{ inspectionStats.unreviewedProblemShops }}</div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">问题部分审核店铺数量</div> |
| | | <div class="table-cell value"> |
| | | {{ inspectionStats.partiallyReviewedProblemShops }} |
| | | </div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">问题全部审核店铺数量</div> |
| | | <div class="table-cell value">{{ inspectionStats.fullyReviewedProblemShops }}</div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">未整改店铺数</div> |
| | | <div class="table-cell value">{{ inspectionStats.unrectifiedShops }}</div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">整改未审核店铺数</div> |
| | | <div class="table-cell value">{{ inspectionStats.unreviewedRectifiedShops }}</div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">整改部分审核店铺数</div> |
| | | <div class="table-cell value"> |
| | | {{ inspectionStats.partiallyReviewedRectifiedShops }} |
| | | </div> |
| | | </div> |
| | | <div class="table-row"> |
| | | <div class="table-cell">整改全部审核店铺数</div> |
| | | <div class="table-cell value">{{ inspectionStats.fullyReviewedRectifiedShops }}</div> |
| | | </div> --> |
| | | </div> |
| | | </div> |
| | | </el-scrollbar> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import districtSearch from '@/utils/map/districtsearch.js' |
| | | import marks from '@/utils/map/marks.js' |
| | | import { generateTestShops } from '@/debug/debugdata' |
| | | import MonitorControl from '@/views/inspection/MonitorControl.vue' |
| | | |
| | | export default { |
| | | name: 'DataDashboard', |
| | | components: { |
| | | MonitorControl, |
| | | }, |
| | | data() { |
| | | return { |
| | | activeTime: 'day', |
| | | currentDate: new Date(), |
| | | currentDate: new Date('2023-08-01'), |
| | | timeTabs: [ |
| | | { label: '日', value: 'day' }, |
| | | { label: '周', value: 'week' }, |
| | | { label: '月', value: 'month' }, |
| | | ], |
| | | dialogVisible: false, |
| | | selectedPoint: { |
| | | enterpriseName: '', |
| | | deviceId: '', |
| | |
| | | overStandardTrend: 5, |
| | | onlineRate: 92, |
| | | onlineRateTrend: 2, |
| | | purifierEfficiency: 85, |
| | | purifierEfficiencyTrend: -3, |
| | | purifierEfficiency: 95, |
| | | purifierEfficiencyTrend: 2, |
| | | inspectionPoints: 350, |
| | | inspectionPointsTrend: 50, |
| | | }, |
| | |
| | | }, |
| | | map: null, |
| | | refreshTimer: null, |
| | | isMonitorControlExpanded: true, |
| | | } |
| | | }, |
| | | computed: { |
| | | currentTimeDisplay() { |
| | | const date = this.currentDate |
| | | let weekStart = new Date(date) |
| | | let weekEnd = new Date(date) |
| | | switch (this.activeTime) { |
| | | case 'day': |
| | | return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}` |
| | | case 'week': |
| | | // 简单计算周显示,实际项目中可能需要更复杂的周计算逻辑 |
| | | let weekStart = new Date(date) |
| | | weekStart.setDate(date.getDate() - date.getDay() + 1) |
| | | let weekEnd = new Date(date) |
| | | weekEnd.setDate(date.getDate() + (7 - date.getDay())) |
| | | return `${weekStart.getFullYear()}-${String(weekStart.getMonth() + 1).padStart(2, '0')}-${String(weekStart.getDate()).padStart(2, '0')} ~ ${weekEnd.getFullYear()}-${String(weekEnd.getMonth() + 1).padStart(2, '0')}-${String(weekEnd.getDate()).padStart(2, '0')}` |
| | | case 'month': |
| | |
| | | this.initMap() |
| | | this.initDeviceStatusChart() |
| | | this.initRectificationChart() |
| | | this.startAutoRefresh() |
| | | // this.startAutoRefresh() |
| | | }, |
| | | beforeUnmount() { |
| | | if (this.refreshTimer) { |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | toggleMonitorControl() { |
| | | this.isMonitorControlExpanded = !this.isMonitorControlExpanded |
| | | }, |
| | | handleTimeChange(tab) { |
| | | this.activeTime = tab.value |
| | | // 模拟切换时间周期后的数据更新 |
| | |
| | | // 这里应该根据选择的时间周期从接口获取数据 |
| | | // 模拟数据更新 |
| | | setTimeout(() => { |
| | | const m = Math.floor(Math.random() * 50) + 150 |
| | | this.overview = { |
| | | totalShops: 245, |
| | | onlineDevices: m, |
| | | offlineDevices: 245 - m, |
| | | } |
| | | this.metrics = { |
| | | overStandardCount: Math.floor(Math.random() * 30), |
| | | overStandardTrend: Math.floor(Math.random() * 20) - 10, |
| | | onlineRate: Math.floor(Math.random() * 20) + 80, |
| | | onlineRate: ((this.overview.onlineDevices / this.overview.totalShops) * 100).toFixed(0), |
| | | onlineRateTrend: Math.floor(Math.random() * 10) - 5, |
| | | purifierEfficiency: Math.floor(Math.random() * 30) + 70, |
| | | purifierEfficiency: Math.floor(Math.random() * 20) + 80, |
| | | purifierEfficiencyTrend: Math.floor(Math.random() * 10) - 5, |
| | | inspectionPoints: Math.floor(Math.random() * 100) + 300, |
| | | inspectionPointsTrend: Math.floor(Math.random() * 100) - 50, |
| | |
| | | } |
| | | |
| | | // 更新图表 |
| | | this.initDeviceStatusChart() |
| | | this.initRectificationChart() |
| | | }, 300) |
| | | }, |
| | |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | top: '5%', |
| | | containLabel: true, |
| | | }, |
| | | xAxis: { |
| | |
| | | /* padding: 16px; */ |
| | | border-radius: 8px; |
| | | /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */ |
| | | } |
| | | |
| | | /* 监控控制卡片 */ |
| | | .monitor-control { |
| | | /* position: absolute; */ |
| | | width: 500px; |
| | | transition: all 0.3s ease; |
| | | /* top: 0px; */ |
| | | /* right: 0px; */ |
| | | /* z-index: 10; */ |
| | | } |
| | | |
| | | .push-btn { |
| | | z-index: 1; |
| | | width: 2.5rem; |
| | | height: initial; |
| | | margin: initial; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | /* background-color: white; */ |
| | | /* border-color: white; */ |
| | | /* border-top: 1px solid; |
| | | border-left: 1px solid; |
| | | border-bottom: 1px solid; */ |
| | | border-top-right-radius: 0px; |
| | | border-bottom-right-radius: 0px; |
| | | /* box-shadow: var(--el-box-shadow-light); */ |
| | | } |
| | | |
| | | /* 时间周期卡片 */ |
| | |
| | | .metric-card:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .card-header { |
| | |
| | | } |
| | | |
| | | .efficiency-icon { |
| | | color: #722ed1; |
| | | color: #52c41a; |
| | | } |
| | | |
| | | .task-icon { |
| | |
| | | } |
| | | |
| | | /* 右侧实时监测总览区 */ |
| | | .overview-section { |
| | | position: absolute; |
| | | bottom: 4px; |
| | | left: 4px; |
| | | width: 320px; |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | padding: 20px; |
| | | .popover-content { |
| | | padding: 10px; |
| | | } |
| | | |
| | | .overview-items-container { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding-bottom: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .overview-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | z-index: 10; |
| | | max-height: calc(100vh - 220px); |
| | | align-items: center; |
| | | flex: 1; |
| | | text-align: center; |
| | | } |
| | | |
| | | .overview-label { |
| | | font-size: 12px; |
| | | color: #86909c; |
| | | font-weight: 500; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .overview-value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #262626; |
| | | } |
| | | |
| | | .device-status-chart { |
| | | flex: 1; |
| | | min-height: 200px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .view-details { |
| | | position: absolute; |
| | | bottom: 12px; |
| | | right: 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | font-size: 12px; |
| | | color: #1890ff; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .view-details:hover { |
| | | text-decoration: underline; |
| | | } |
| | | |
| | | .overview-items-container { |
| | |
| | | color: #262626; |
| | | } |
| | | |
| | | .device-status-chart { |
| | | flex: 1; |
| | | min-height: 100px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-bottom: 16px; |
| | | /* 巡查情况统计 */ |
| | | .inspection-popover-content { |
| | | padding: 10px; |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | /* 巡查情况统计 */ |
| | | .inspection-section { |
| | | .monitor-control-container { |
| | | position: absolute; |
| | | top: 4px; |
| | | right: 4px; |
| | | width: 320px; |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | padding: 20px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | z-index: 10; |
| | | max-height: calc(70vh); |
| | | border-top: 1px solid #f0f0f0; |
| | | transition: all 0.3s ease; |
| | | /* background-color: rgba(255, 255, 255, 0.9); */ |
| | | display: flex; |
| | | border-radius: 8px; |
| | | /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */ |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .monitor-control-container.collapsed { |
| | | width: 60px; |
| | | } |
| | | |
| | | .monitor-control-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 10px 15px; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | height: 40px; |
| | | position: relative; |
| | | } |
| | | |
| | | .monitor-control-header span { |
| | | font-weight: 600; |
| | | color: #333; |
| | | writing-mode: vertical-rl; |
| | | text-orientation: mixed; |
| | | letter-spacing: 2px; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .collapse-btn { |
| | | /* transform: translateY(-50%); */ |
| | | } |
| | | |
| | | .inspection-metrics { |
| | |
| | | .map-legend { |
| | | position: absolute; |
| | | bottom: 4px; |
| | | right: 4px; |
| | | width: 200px; |
| | | left: 4px; |
| | | /* width: 200px; */ |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | padding: 16px; |
| | | padding: 4px; |
| | | z-index: 10; |
| | | } |
| | | |