| components.d.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/components/map/SceneMap.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/debug/debugdata.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/utils/map/marks.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inspection/MonitorControl.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inspection/check/components/CompSubTaskStatistic.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inspection/task/TaskManage.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inspection/task/components/CompTaskMap.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/monitor/DataDashboard.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/monitor/DataException.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/monitor/DataHistory.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
components.d.ts
@@ -27,6 +27,7 @@ ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElButton: typeof import('element-plus/es')['ElButton'] ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] ElCalendar: typeof import('element-plus/es')['ElCalendar'] ElCard: typeof import('element-plus/es')['ElCard'] ElCascader: typeof import('element-plus/es')['ElCascader'] @@ -43,10 +44,12 @@ ElDialog: typeof import('element-plus/es')['ElDialog'] ElDivider: typeof import('element-plus/es')['ElDivider'] ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFrom: typeof import('element-plus/es')['ElFrom'] ElHeader: typeof import('element-plus/es')['ElHeader'] ElIcon: typeof import('element-plus/es')['ElIcon'] ElImage: typeof import('element-plus/es')['ElImage'] @@ -59,6 +62,7 @@ ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] ElOption: typeof import('element-plus/es')['ElOption'] ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] ElProgress: typeof import('element-plus/es')['ElProgress'] @@ -109,9 +113,9 @@ FYReconfrimButton: typeof import('./src/components/button/FYReconfrimButton.vue')['default'] FYSearchBar: typeof import('./src/components/search-option/FYSearchBar.vue')['default'] FYTable: typeof import('./src/components/table/FYTable.vue')['default'] IEpArrowLeft: typeof import('~icons/ep/arrow-left')['default'] IEpArrowRight: typeof import('~icons/ep/arrow-right')['default'] IEpDataLine: typeof import('~icons/ep/data-line')['default'] IEpDownload: typeof import('~icons/ep/download')['default'] IEpGrid: typeof import('~icons/ep/grid')['default'] IEpInfoFilled: typeof import('~icons/ep/info-filled')['default'] ItemDevice: typeof import('./src/components/list-item/ItemDevice.vue')['default'] ItemMonitorObj: typeof import('./src/components/list-item/ItemMonitorObj.vue')['default'] @@ -150,6 +154,7 @@ const ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] const ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] const ElButton: typeof import('element-plus/es')['ElButton'] const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] const ElCalendar: typeof import('element-plus/es')['ElCalendar'] const ElCard: typeof import('element-plus/es')['ElCard'] const ElCascader: typeof import('element-plus/es')['ElCascader'] @@ -166,10 +171,12 @@ const ElDialog: typeof import('element-plus/es')['ElDialog'] const ElDivider: typeof import('element-plus/es')['ElDivider'] const ElDrawer: typeof import('element-plus/es')['ElDrawer'] const ElDropdown: typeof import('element-plus/es')['ElDropdown'] const ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] const ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] const ElEmpty: typeof import('element-plus/es')['ElEmpty'] const ElForm: typeof import('element-plus/es')['ElForm'] const ElFormItem: typeof import('element-plus/es')['ElFormItem'] const ElFrom: typeof import('element-plus/es')['ElFrom'] const ElHeader: typeof import('element-plus/es')['ElHeader'] const ElIcon: typeof import('element-plus/es')['ElIcon'] const ElImage: typeof import('element-plus/es')['ElImage'] @@ -182,6 +189,7 @@ const ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] const ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] const ElOption: typeof import('element-plus/es')['ElOption'] const ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] const ElPagination: typeof import('element-plus/es')['ElPagination'] const ElPopover: typeof import('element-plus/es')['ElPopover'] const ElProgress: typeof import('element-plus/es')['ElProgress'] @@ -232,9 +240,9 @@ const FYReconfrimButton: typeof import('./src/components/button/FYReconfrimButton.vue')['default'] const FYSearchBar: typeof import('./src/components/search-option/FYSearchBar.vue')['default'] const FYTable: typeof import('./src/components/table/FYTable.vue')['default'] const IEpArrowLeft: typeof import('~icons/ep/arrow-left')['default'] const IEpArrowRight: typeof import('~icons/ep/arrow-right')['default'] const IEpDataLine: typeof import('~icons/ep/data-line')['default'] const IEpDownload: typeof import('~icons/ep/download')['default'] const IEpGrid: typeof import('~icons/ep/grid')['default'] const IEpInfoFilled: typeof import('~icons/ep/info-filled')['default'] const ItemDevice: typeof import('./src/components/list-item/ItemDevice.vue')['default'] const ItemMonitorObj: typeof import('./src/components/list-item/ItemMonitorObj.vue')['default'] src/components/map/SceneMap.vue
@@ -758,7 +758,7 @@ } .card-left { background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.9); border-radius: 4px; /* width: 350px; */ /* height: 50vh; */ src/debug/debugdata.js
@@ -129,7 +129,7 @@ const time = new Date(now.getTime() - i * 10 * 60 * 1000) data.push({ sampleTime: time.toISOString().slice(0, 19).replace('T', ' '), oilSmokeConcentration: (Math.random() * 5).toFixed(2), oilSmokeConcentration: (Math.random() * 2).toFixed(2), purifierCurrent: (Math.random() * 10).toFixed(2), fanCurrent: (Math.random() * 15).toFixed(2), }) src/utils/map/marks.js
@@ -383,10 +383,14 @@ <h3 style="margin: 0 0 10px 0; color: #333;">${shop.shop.name}</h3> <div style="font-size: 14px; line-height: 1.5;"> <p><strong>地址:</strong>${shop.shop.address}</p> <p><strong>在线状态:</strong><span style="color: ${shop.shop.isOnline ? '#52c41a' : '#8c8c8c'}">${onlineStatusText}</span> </p> <p><strong>异常状态:</strong><span style="color: ${exceptionStatusColor}">${exceptionStatusText}</span></p> <p><strong>环信码等级:</strong><span style="color: ${getColorByRingCodeLevel(shop.shop.ringCodeLevel)}">${getRingCodeLevelText(shop.shop.ringCodeLevel)}</span></p> <p><strong>环信码发布时间:</strong>${shop.shop.ringCodePublishTime}</p> <div style="display: flex; flex-direction: row;"> <span style="flex:1"><strong>在线状态:</strong><span style="color: ${shop.shop.isOnline ? '#52c41a' : '#8c8c8c'}">${onlineStatusText}</span> </span> <span style="flex:1"><strong>异常状态:</strong><span style="color: ${exceptionStatusColor}">${exceptionStatusText}</span></span> </div> <div style="display: flex; flex-direction: row;"> <span style="flex:1"><strong>环信码等级:</strong><span style="color: ${getColorByRingCodeLevel(shop.shop.ringCodeLevel)}">${getRingCodeLevelText(shop.shop.ringCodeLevel)}</span></span> <span style="flex:1"><strong>发布时间:</strong>${shop.shop.ringCodePublishTime}</span> </div> <h4 style="margin: 10px 0 5px 0; color: #666;">近1小时监测数据</h4> <div id="infowindowChartContainer" style="width: 100%; height: 250px;"></div> </div> src/views/inspection/MonitorControl.vue
@@ -30,44 +30,50 @@ <!-- 左侧:已巡查店铺率、巡查点次、复查点次 --> <div class="stats-section left-section"> <h3>巡查概况</h3> <div class="chart-item"> <div class="progress-container"> <el-progress type="dashboard" :percentage="parseFloat(inspectionStats.inspectedRate)" :color="['#409EFF', '#67C23A']" :width="120" /> <div class="progress-label">已巡查店铺率</div> <div class="progress-value"> {{ `${inspectionStats.inspectedShops}/${inspectionStats.totalShops}` }} <el-row justify="space-between"> <div class="chart-item"> <div class="progress-container"> <el-progress type="dashboard" :percentage="parseFloat(inspectionStats.inspectedRate)" :color="['#409EFF', '#67C23A']" :width="120" /> <div class="progress-label">已巡查店铺率</div> <div class="progress-value"> {{ `${inspectionStats.inspectedShops}/${inspectionStats.totalShops}` }} </div> </div> </div> </div> <div class="stats-grid m-t-16"> <el-statistic class="stat-item" :value="inspectionStats.inspectionPoints" title="巡查点次" /> <el-statistic class="stat-item" :value="inspectionStats.reviewPoints" title="复查点次" /> </div> <div class="stats-grid m-l-16"> <el-statistic class="stat-item" :value="inspectionStats.inspectionPoints" title="巡查点次" /> <el-statistic class="stat-item" :value="inspectionStats.reviewPoints" title="复查点次" /> </div> </el-row> </div> <!-- 右侧:问题数、问题整改数、问题整改率统计图 --> <div class="stats-section right-section"> <h3>问题整改概况</h3> <div class="stats-grid"> <el-statistic class="stat-item" :value="inspectionStats.problemCount" title="问题数" /> <el-row justify="space-around"> <el-text>问题数:{{ inspectionStats.problemCount }}</el-text> <el-text>整改数:{{ inspectionStats.rectifiedProblems }}</el-text> </el-row> <!-- <el-statistic class="stat-item" :value="inspectionStats.problemCount" title="问题数" /> <el-statistic class="stat-item" :value="inspectionStats.rectifiedProblems" title="问题整改数" /> /> --> </div> <!-- <div class="chart-item"> --> <div ref="rectificationRateChart" class="chart"></div> @@ -320,7 +326,12 @@ chart.setOption({ xAxis: { type: 'category', data: ['当日整改率', '48小时内整改率', '综合整改率', '审核通过率'], data: [ '当日整改率', // '48小时内整改率', '综合整改率', '审核通过率', ], }, yAxis: { type: 'value', @@ -332,7 +343,7 @@ { data: [ parseFloat(inspectionStats.value.sameDayRectificationRate), parseFloat(inspectionStats.value.effectiveRectificationRate), // parseFloat(inspectionStats.value.effectiveRectificationRate), parseFloat(inspectionStats.value.comprehensiveRectificationRate), parseFloat(inspectionStats.value.auditPassRate), ], @@ -391,6 +402,9 @@ </script> <style scoped> :deep() .el-card__body { padding: 8px; } .mb-4 { /* width: 600px; */ } @@ -418,7 +432,6 @@ display: flex; flex-direction: column; gap: 20px; margin-bottom: 30px; } .stats-section { @@ -436,13 +449,13 @@ } .stats-grid { display: grid; grid-template-columns: 1fr 1fr; display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px; } .stat-item { flex: 1; background-color: #fff; padding: 20px; border-radius: 8px; @@ -479,6 +492,7 @@ } .chart-item { flex: 1; background-color: #fff; padding: 20px; border-radius: 8px; src/views/inspection/check/components/CompSubTaskStatistic.vue
@@ -84,7 +84,7 @@ </el-descriptions-item> </el-descriptions> <el-descriptions <!-- <el-descriptions class="m-l-4" :column="8" size="small" @@ -135,13 +135,6 @@ </template> {{ summary.proAllCheck }} </el-descriptions-item> <!-- </el-descriptions> <el-descriptions :column="4" size="small" border direction="vertical" > --> <el-descriptions-item label="未整改" label-class-name="change-check-label" @@ -188,7 +181,7 @@ </template> {{ summary.changeAllCheck }} </el-descriptions-item> </el-descriptions> </el-descriptions> --> </el-row> </template> <script> src/views/inspection/task/TaskManage.vue
@@ -2,7 +2,7 @@ <BaseContentLayout asideWidth="0"> <template #header> <div class="task-switcher"> <el-button @click="switchTask(-1)" icon="ArrowLeft">前一个</el-button> <el-button @click="switchTask(-1)" icon="ArrowLeft">上一期</el-button> <el-select v-model="curTaskTitle" @change="(t) => chooseTask(tasks.find((e) => e.title == t))" @@ -10,7 +10,7 @@ > <el-option v-for="s in tasks" :key="s.title" :label="s.title" :value="s.title" /> </el-select> <el-button @click="switchTask(1)" icon="ArrowRight">后一个</el-button> <el-button @click="switchTask(1)" icon="ArrowRight">下一期</el-button> </div> </template> <template #aside> src/views/inspection/task/components/CompTaskMap.vue
@@ -155,7 +155,7 @@ } .right-wrapper { background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.9); box-shadow: var(--el-box-shadow); border-radius: 4px; height: 80vh; src/views/monitor/DataDashboard.vue
@@ -1,5 +1,20 @@ <template> <div class="data-dashboard"> <!-- 地图模式切换 --> <div class="map-mode-card"> <div class="mode-tab-container"> <div v-for="mode in mapModes" :key="mode.value" class="mode-tab" :class="{ active: activeMode === mode.value }" @click="handleModeChange(mode)" > {{ mode.label }} </div> </div> </div> <!-- 顶部指标卡片区 --> <div class="top-cards"> <!-- 时间周期选项卡片 --> @@ -56,49 +71,8 @@ </div> </div> </div> <div class="cards-container"> <!-- 浓度预警 --> <div class="metric-card"> <div class="card-header"> <div class="card-title">{{ getPeriodLabel() }}浓度预警</div> <div class="card-icon warning-icon"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M12 9V13" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> <path d="M12 17.5V17" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> <path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> </div> <div class="card-value">{{ metrics.overStandardCount }}<el-text>次</el-text></div> <div class="card-trend"> <span class="trend-arrow" :class="{ up: metrics.overStandardTrend > 0, down: metrics.overStandardTrend < 0 }" > {{ metrics.overStandardTrend > 0 ? '↑' : '↓' }} </span> <span class="trend-text">{{ Math.abs(metrics.overStandardTrend) }}%</span> <span class="trend-label">{{ getCompareLabel() }}</span> </div> </div> <!-- 设备在线率 --> <el-popover placement="right-start" title="设备监控" width="400" trigger="click"> <div class="popover-content"> @@ -153,7 +127,7 @@ </svg> </div> </div> <div class="card-value">{{ metrics.onlineRate }}%</div> <div class="card-value">{{ metrics.onlineRate }}<el-text>%</el-text></div> <div class="card-trend"> <span class="trend-arrow" @@ -186,11 +160,11 @@ </template> </el-popover> <!-- 环信码绿码率 --> <!-- 浓度预警 --> <div class="metric-card"> <div class="card-header"> <div class="card-title">环信码绿码率</div> <div class="card-icon efficiency-icon"> <div class="card-title">{{ getPeriodLabel() }}浓度预警</div> <div class="card-icon warning-icon"> <svg width="20" height="20" @@ -198,15 +172,15 @@ fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M12 9V13" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2Z" d="M12 17.5V17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M12 6V12L16 14" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" @@ -215,23 +189,20 @@ </svg> </div> </div> <div class="card-value">{{ metrics.purifierEfficiency }}%</div> <div class="card-value">{{ metrics.overStandardCount }}<el-text>次</el-text></div> <div class="card-trend"> <span class="trend-arrow" :class="{ up: metrics.purifierEfficiencyTrend > 0, down: metrics.purifierEfficiencyTrend < 0, }" :class="{ up: metrics.overStandardTrend > 0, down: metrics.overStandardTrend < 0 }" > {{ metrics.purifierEfficiencyTrend > 0 ? '↑' : '↓' }} {{ metrics.overStandardTrend > 0 ? '↑' : '↓' }} </span> <span class="trend-text">{{ Math.abs(metrics.purifierEfficiencyTrend) }}%</span> <span class="trend-text">{{ Math.abs(metrics.overStandardTrend) }}%</span> <span class="trend-label">{{ getCompareLabel() }}</span> </div> </div> <!-- 巡查点次 --> <!-- 现场巡查 --> <el-popover placement="right-start" title="现场巡查统计" width="350" trigger="click"> <div class="inspection-popover-content"> <!-- 巡查量统计 --> @@ -318,7 +289,7 @@ <template #reference> <div class="metric-card"> <div class="card-header"> <div class="card-title">巡查点次</div> <div class="card-title">现场巡查</div> <div class="card-icon task-icon"> <svg width="20" @@ -344,7 +315,7 @@ </svg> </div> </div> <div class="card-value">{{ metrics.inspectionPoints }}</div> <div class="card-value">{{ metrics.inspectionPoints }}<el-text>点次</el-text></div> <div class="card-trend"> <span class="trend-arrow" @@ -379,6 +350,177 @@ </div> </template> </el-popover> <!-- 信访投诉 --> <div class="metric-card"> <div class="card-header"> <div class="card-title">信访投诉</div> <div class="card-icon warning-icon"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M21 6H3C2.46957 6 1.96086 6.21071 1.58579 6.58579C1.21071 6.96086 1 7.46957 1 8V18C1 19.1046 1.89543 20 3 20H21C22.1046 20 23 19.1046 23 18V8C23 7.46957 22.7893 6.96086 22.4142 6.58579C22.0391 6.21071 21.5304 6 21 6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M8 12H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M8 16H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M8 8H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> </div> <div class="card-value">{{ metrics.overStandardCount }}<el-text>件</el-text></div> <div class="card-trend"> <span class="trend-arrow" :class="{ up: metrics.overStandardTrend > 0, down: metrics.overStandardTrend < 0 }" > {{ metrics.overStandardTrend > 0 ? '↑' : '↓' }} </span> <span class="trend-text">{{ Math.abs(metrics.overStandardTrend) }}%</span> <span class="trend-label">{{ getCompareLabel() }}</span> </div> </div> <!-- 环信码 --> <div class="metric-card"> <div class="card-header"> <div class="card-title">环信码</div> <div class="card-icon efficiency-icon"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M12 8V16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M8 12H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> </div> <div class="card-value" style="color: #52c41a"> <div>{{ metrics.purifierEfficiency }}<el-text>%</el-text></div> <div class="card-subvalues"> <span style="color: #faad14; font-size: 14px">黄码:3%</span> <span style="color: #f5222d; font-size: 14px; margin-left: 12px">红码:2%</span> </div> </div> <div class="card-trend"> <span class="trend-arrow" :class="{ up: metrics.purifierEfficiencyTrend > 0, down: metrics.purifierEfficiencyTrend < 0, }" > {{ metrics.purifierEfficiencyTrend > 0 ? '↑' : '↓' }} </span> <span class="trend-text">{{ Math.abs(metrics.purifierEfficiencyTrend) }}%</span> <span class="trend-label">{{ getCompareLabel() }}</span> </div> </div> <!-- 行政处罚 --> <div class="metric-card"> <div class="card-header"> <div class="card-title">行政处罚</div> <div class="card-icon warning-icon"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M12 15C15.866 15 19 11.866 19 8C19 4.13401 15.866 1 12 1C8.13401 1 5 4.13401 5 8C5 11.866 8.13401 15 12 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M12 15C12 15 15 21 15 21H9C9 21 12 15 12 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M11 8H13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M11 11H13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> </div> <div class="card-value">{{ metrics.overStandardCount }}<el-text>次</el-text></div> <div class="card-trend"> <span class="trend-arrow" :class="{ up: metrics.overStandardTrend > 0, down: metrics.overStandardTrend < 0 }" > {{ metrics.overStandardTrend > 0 ? '↑' : '↓' }} </span> <span class="trend-text">{{ Math.abs(metrics.overStandardTrend) }}%</span> <span class="trend-label">{{ getCompareLabel() }}</span> </div> </div> </div> </div> @@ -387,10 +529,12 @@ <!-- 中部GIS地图区 --> <div class="map-section"> <div id="map" class="map-container"> <BaseMap :showSatellite="true"></BaseMap> <BaseMap :showSatellite="false"></BaseMap> </div> </div> </div> <!-- --> <div class="monitor-control-container"> <el-button size="large" @click="toggleMonitorControl" class="push-btn"> <div style="display: flex; flex-direction: column"> @@ -398,10 +542,10 @@ <ArrowRight v-if="isMonitorControlExpanded" /> <ArrowLeft v-else /> </el-icon> <div>现</div> <!-- <div>现</div> <div>场</div> <div>巡</div> <div>查</div> <div>查</div> --> </div> </el-button> <MonitorControl @@ -417,19 +561,21 @@ <h4>图例</h4> </div> <div class="legend-items"> <div class="legend-item"> <!-- 污染态势模式下显示的图例 --> <div v-if="activeMode === 'pollution'" class="legend-item"> <img src="@/assets/exceed.png" alt="油烟浓度超标" class="legend-icon" /> <span class="legend-text">油烟浓度超标</span> </div> <div class="legend-item"> <div v-if="activeMode === 'pollution'" class="legend-item"> <img src="@/assets/exception.png" alt="供电异常" class="legend-icon" /> <span class="legend-text">供电异常</span> </div> <div class="legend-item"> <div v-if="activeMode === 'pollution'" class="legend-item"> <img src="@/assets/offline.png" alt="设备或网络异常" class="legend-icon" /> <span class="legend-text">设备或网络异常</span> </div> <div class="legend-item"> <!-- 设备状态模式下也显示在线状态 --> <div v-if="activeMode === 'device'" class="legend-item"> <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSI1IiB5PSI4IiB3aWR0aD0iMjIiIGhlaWdodD0iMTYiIHJ4PSIzIiBmaWxsPSIjNTJjNDFhIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNNSA4IFEgMTYgMyAyNyA4IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9IiMzODllMGQiLz48cGF0aCBkPSJNNSAyNCBRIDE2IDI5IDI3IDI0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9IiM2NjY2NjYiLz48cmVjdCB4PSI4IiB5PSIxMSIgd2lkdGg9IjE2IiBoZWlnaHQ9IjEwIiByeD0iMiIgZmlsbD0id2hpdGUiLz48cGF0aCBkPSJNMTIgMTQgTCAyMSAxNCIgc3Ryb2tlPSIjNTJjNDFhIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxwYXRoIGQ9Ik0xMiAxNyBMIDE4IDE3IiBzdHJva2U9IiM1MmM0MWEiIHN0cm9rZS13aWR0aD0iMS41Ii8+PHBhdGggZD0iTTEyIDIwIEwgMTUgMjAiIHN0cm9rZT0iIzUyYzQxYSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48bGluZSB4MT0iMTYiIHkxPSI4IiB4Mj0iMTYiIHkyPSIzIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxjaXJjbGUgY3g9IjE2IiBjeT0iMyIgcj0iMS41IiBmaWxsPSJ3aGl0ZSIvPjxjaXJjbGUgY3g9IjI3IiBjeT0iMTYiIHI9IjMiIGZpbGw9IiNmZmZmZmYiLz48Y2lyY2xlIGN4PSIyNyIgY3k9IjE2IiByPSIxLjUiIGZpbGw9IiM1MmM0MWEiLz48bGluZSB4MT0iNSIgeTE9IjEzIiB4Mj0iNiIgeTI9IjEzIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxsaW5lIHgxPSI1IiB5MT0iMTkiIHgyPSI2IiB5Mj0iMTkiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41Ii8+PC9zdmc+" alt="在线状态" @@ -437,7 +583,7 @@ /> <span class="legend-text">在线状态</span> </div> <div class="legend-item"> <div v-if="activeMode === 'device'" class="legend-item"> <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSI1IiB5PSI4IiB3aWR0aD0iMjIiIGhlaWdodD0iMTYiIHJ4PSIzIiBmaWxsPSIjOGM4YzhjIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNNSA4IFEgMTYgMyAyNyA4IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9IiM2NjY2NjYiLz48cGF0aCBkPSJNNSAyNCBRIDE2IDI5IDI3IDI0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9IiM2NjY2NjYiLz48cmVjdCB4PSI4IiB5PSIxMSIgd2lkdGg9IjE2IiBoZWlnaHQ9IjEwIiByeD0iMiIgZmlsbD0id2hpdGUiLz48bGluZSB4MT0iMTEiIHkxPSIxMiIgeDI9IjIxIiB5Mj0iMjIiIHN0cm9rZT0iIzhjOGM4YyIgc3Ryb2tlLXdpZHRoPSIyIi8+PGxpbmUgeDE9IjExIiB5MT0iMjIiIHgyPSIyMSIgeTI9IjEyIiBzdHJva2U9IiM4YzhjOGMiIHN0cm9rZS13aWR0aD0iMiIvPjxsaW5lIHgxPSIxNiIgeTE9IjgiIHgyPSIxNiIgeTI9IjMiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGNpcmNsZSBjeD0iMTYiIGN5PSIzIiByPSIxLjUiIGZpbGw9IndoaXRlIi8+PGNpcmNsZSBjeD0iMjciIGN5PSIxNiIgcj0iMyIgZmlsbD0iI2ZmZmZmZiIvPjxjaXJjbGUgY3g9IjI3IiBjeT0iMTYiIHI9IjEuNSIgZmlsbD0iIzhjOGM4YyIvPjxsaW5lIHgxPSI1IiB5MT0iMTMiIHgyPSI2IiB5Mj0iMTMiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjUiIHkxPSIxOSIgeDI9IjYiIHkyPSIxOSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48L3N2Zz4=" alt="离线状态" @@ -466,11 +612,16 @@ data() { return { activeTime: 'day', activeMode: 'pollution', // 默认污染态势模式 currentDate: new Date('2023-08-01'), timeTabs: [ { label: '日', value: 'day' }, { label: '周', value: 'week' }, { label: '月', value: 'month' }, ], mapModes: [ { label: '污染态势', value: 'pollution' }, { label: '设备状态', value: 'device' }, ], selectedPoint: { enterpriseName: '', @@ -560,6 +711,9 @@ this.activeTime = tab.value // 模拟切换时间周期后的数据更新 this.updateMetrics() }, handleModeChange(mode) { this.activeMode = mode.value }, navigateTime(direction) { const newDate = new Date(this.currentDate) @@ -877,7 +1031,7 @@ /* 监控控制卡片 */ .monitor-control { /* position: absolute; */ width: 500px; width: 400px; transition: all 0.3s ease; /* top: 0px; */ /* right: 0px; */ @@ -887,7 +1041,7 @@ .push-btn { z-index: 1; width: 2.5rem; height: initial; height: 40px; margin: initial; display: flex; flex-direction: column; @@ -913,6 +1067,59 @@ justify-content: center; margin-bottom: 8px; min-width: 300px; } /* 地图模式卡片 */ .map-mode-card { position: absolute; top: 4px; left: 50%; transform: translateX(-50%); z-index: 10; background-color: #ffffff; border-radius: 8px; padding: 4px 16px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); display: flex; flex-direction: column; justify-content: center; margin-bottom: 8px; min-width: 300px; } .mode-tab-container { display: flex; flex-direction: row; gap: 8px; width: 100%; justify-content: center; } .mode-tab { padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.3s ease; color: #4e5969; text-align: center; border: 1px solid #e8e8e8; background-color: #fafafa; flex: 1; } .mode-tab.active { background-color: #1890ff; color: #ffffff; border-color: #1890ff; box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2); } .mode-tab:hover:not(.active) { color: #1890ff; border-color: #e6f7ff; background-color: #e6f7ff; } .time-period-card .card-title { @@ -1060,6 +1267,16 @@ margin: 12px 0; color: #262626; line-height: 1.2; /* display: flex; justify-content: space-between; align-items: flex-end; */ } .card-subvalues { display: flex; align-items: center; margin: 8px 0; font-weight: 500; } .card-trend { @@ -1391,8 +1608,11 @@ /* 地图图例样式 */ .map-legend { position: absolute; display: flex; align-items: center; bottom: 4px; left: 4px; left: 50%; transform: translateX(-50%); /* width: 200px; */ background-color: rgba(255, 255, 255, 0.9); border-radius: 8px; @@ -1402,7 +1622,7 @@ } .legend-header { margin-bottom: 12px; margin-right: 12px; } .legend-header h4 { @@ -1415,7 +1635,7 @@ .legend-items { display: flex; flex-direction: column; flex-direction: row; gap: 8px; } @@ -1505,4 +1725,4 @@ text-align: left; } } */ </style> </style> src/views/monitor/DataException.vue
@@ -6,7 +6,7 @@ <el-collapse-item name="1"> <template #title> <div class="search-header"> <h3>查询条件</h3> <h3>预警范围</h3> <span v-if="!isSearchExpanded" class="search-summary"> {{ getSearchSummary() }} </span> @@ -188,7 +188,7 @@ <el-collapse-item name="1"> <template #title> <div class="collapse-title"> <h4 class="table-title">异常数据</h4> <h4 class="table-title">预警记录</h4> </div> </template> <el-card v-show="!isNoData"> src/views/monitor/DataHistory.vue
@@ -6,6 +6,7 @@ import dayjs from 'dayjs' import axiosInstanceInstance from '@/utils/request.js' import TimeSelect from '@/sfc/TimeSelect.vue' import ExceptionType from '@/sfc/ExceptionType.vue' const ShopNameAndID = defineAsyncComponent(() => import('@/sfc/ShopNameAndID.vue')) @@ -16,6 +17,7 @@ lineChart, ShopNameAndID, TimeSelect, ExceptionType, }, data() { return { @@ -447,7 +449,7 @@ <!-- 店铺名 级联 --> <!-- <el-cascader v-model="devId" :options="optionsShop" :props="{ expandTrigger: 'hover' }" placeholder="请选择店铺名" clearable /> --> <span class="describe-info">店铺名选择:</span> <span class="describe-info">店铺选择:</span> <ShopNameAndID @submit-id="(n) => (devId[1] = n)" :devId="beginShowShopName"></ShopNameAndID> <!-- <span class="describe-time-text">起止时间:</span> --> @@ -455,6 +457,7 @@ <!-- <el-date-picker v-model="beginTime" type="datetime" placeholder="开始时间" value-format="YYYY-MM-DD HH:mm:ss" /> <el-date-picker v-model="endTime" type="datetime" placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" /> --> <TimeSelect @submit-time="giveTime"></TimeSelect> <ExceptionType></ExceptionType> <el-button type="primary" plain :loading="button.queryButton" @click="lineChart" >查询</el-button >