|
|
@@ -15,17 +15,7 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="header-right">
|
|
|
- <el-date-picker
|
|
|
- v-model="dateRange"
|
|
|
- type="datetimerange"
|
|
|
- range-separator="至"
|
|
|
- start-placeholder="开始时间"
|
|
|
- end-placeholder="结束时间"
|
|
|
- style="width: 300px"
|
|
|
- size="default"
|
|
|
- />
|
|
|
<el-button type="primary" :icon="Refresh" @click="refreshData">刷新</el-button>
|
|
|
- <el-button :icon="Download" @click="exportReport">导出报表</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -36,20 +26,10 @@
|
|
|
<div class="kpi-label">最高甲烷浓度</div>
|
|
|
<div class="kpi-trend">场站: {{ maxMethaneStation }}</div>
|
|
|
</div>
|
|
|
- <div class="kpi-card">
|
|
|
- <div class="kpi-value">{{ avgInPressure }}<span class="unit">kPa</span></div>
|
|
|
- <div class="kpi-label">平均进口压力</div>
|
|
|
- <div class="kpi-trend">较昨日 ↑0.2%</div>
|
|
|
- </div>
|
|
|
- <div class="kpi-card">
|
|
|
- <div class="kpi-value">{{ avgOutPressure }}<span class="unit">kPa</span></div>
|
|
|
- <div class="kpi-label">平均出口压力</div>
|
|
|
- <div class="kpi-trend">较昨日 ↓0.1%</div>
|
|
|
- </div>
|
|
|
<div class="kpi-card">
|
|
|
<div class="kpi-value">{{ riskScore }}<span class="unit">分</span></div>
|
|
|
<div class="kpi-label">综合风险评分</div>
|
|
|
- <div class="kpi-trend trend-down">较昨日 ↓12%</div>
|
|
|
+ <div class="kpi-trend trend-down">越低越安全</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -71,34 +51,30 @@
|
|
|
<div class="station-list">
|
|
|
<div
|
|
|
v-for="station in paginatedStations"
|
|
|
- :key="station.id"
|
|
|
+ :key="station.pointId"
|
|
|
class="station-item"
|
|
|
:class="{
|
|
|
- selected: selectedStation?.id === station.id,
|
|
|
+ selected: selectedStation?.pointId === station.pointId,
|
|
|
alert: station.alertStatus
|
|
|
}"
|
|
|
@click="selectStation(station)"
|
|
|
>
|
|
|
<div class="station-header">
|
|
|
- <span class="station-name">{{ station.name }}</span>
|
|
|
+ <span class="station-name">{{ station.pointName }}</span>
|
|
|
<el-tag :type="station.alertStatus ? 'danger' : 'success'" size="small">
|
|
|
{{ station.alertStatus ? '告警' : '正常' }}
|
|
|
</el-tag>
|
|
|
</div>
|
|
|
<div class="station-address">
|
|
|
- <el-icon><Location /></el-icon> {{ station.address }}
|
|
|
+ <el-icon><Location /></el-icon> {{ station.location }}
|
|
|
</div>
|
|
|
<div class="station-metrics">
|
|
|
<div class="metric">
|
|
|
<span class="label">甲烷浓度</span>
|
|
|
- <span class="value" :class="{ 'alert-value': station.methane > station.methaneThreshold }">
|
|
|
- {{ station.methane }} ppm
|
|
|
+ <span class="value" :class="{ 'alert-value': station.alertStatus }">
|
|
|
+ {{ station.methaneValue }} ppm
|
|
|
</span>
|
|
|
</div>
|
|
|
- <div class="metric">
|
|
|
- <span class="label">进口压力</span>
|
|
|
- <span class="value">{{ station.inPressure }} kPa</span>
|
|
|
- </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -117,44 +93,28 @@
|
|
|
<div class="detail-panel" v-if="selectedStation">
|
|
|
<div class="detail-header">
|
|
|
<div class="title-section">
|
|
|
- <h3>{{ selectedStation.name }}</h3>
|
|
|
+ <h3>{{ selectedStation.pointName }}</h3>
|
|
|
<el-tag :type="selectedStation.alertStatus ? 'danger' : 'success'" size="large">
|
|
|
{{ selectedStation.alertStatus ? '实时告警中' : '运行正常' }}
|
|
|
</el-tag>
|
|
|
</div>
|
|
|
<div class="address-info">
|
|
|
- <el-icon><Location /></el-icon> {{ selectedStation.address }}
|
|
|
+ <el-icon><Location /></el-icon> {{ selectedStation.location }}
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 实时监测数据卡片 -->
|
|
|
<div class="realtime-cards">
|
|
|
- <div class="realtime-card" :class="{ warning: selectedStation.methane > selectedStation.methaneThreshold }">
|
|
|
+ <div class="realtime-card" :class="{ warning: selectedStation.alertStatus }">
|
|
|
<div class="card-icon"><el-icon><WindPower /></el-icon></div>
|
|
|
<div class="card-content">
|
|
|
<div class="card-label">甲烷浓度 (CH₄)</div>
|
|
|
- <div class="card-value">{{ selectedStation.methane }} <span class="unit">ppm</span></div>
|
|
|
+ <div class="card-value">{{ selectedStation.methaneValue }} <span class="unit">ppm</span></div>
|
|
|
<div class="card-threshold">阈值: {{ selectedStation.methaneThreshold }} ppm</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="realtime-card">
|
|
|
- <div class="card-icon"><el-icon><Connection /></el-icon></div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="card-label">进口压力</div>
|
|
|
- <div class="card-value">{{ selectedStation.inPressure }} <span class="unit">kPa</span></div>
|
|
|
- <div class="card-threshold">范围: 200-400 kPa</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="realtime-card">
|
|
|
- <div class="card-icon"><el-icon><Connection /></el-icon></div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="card-label">出口压力</div>
|
|
|
- <div class="card-value">{{ selectedStation.outPressure }} <span class="unit">kPa</span></div>
|
|
|
- <div class="card-threshold">范围: 150-250 kPa</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="realtime-card">
|
|
|
- <div class="card-icon"><el-icon></el-icon></div>
|
|
|
+ <div class="card-icon"><el-icon><Odometer /></el-icon></div>
|
|
|
<div class="card-content">
|
|
|
<div class="card-label">环境温度</div>
|
|
|
<div class="card-value">{{ selectedStation.temperature }} <span class="unit">°C</span></div>
|
|
|
@@ -166,35 +126,11 @@
|
|
|
<!-- 监测数据趋势图 -->
|
|
|
<div class="chart-section">
|
|
|
<div class="section-header">
|
|
|
- <span><el-icon><TrendCharts /></el-icon> 监测数据趋势(最近24小时)</span>
|
|
|
- <el-radio-group v-model="trendMetric" size="small">
|
|
|
- <el-radio-button label="methane">甲烷浓度</el-radio-button>
|
|
|
- <el-radio-button label="inPressure">进口压力</el-radio-button>
|
|
|
- <el-radio-button label="outPressure">出口压力</el-radio-button>
|
|
|
- </el-radio-group>
|
|
|
+ <span><el-icon><TrendCharts /></el-icon> 甲烷浓度趋势(最近24小时)</span>
|
|
|
</div>
|
|
|
<div ref="trendChartRef" class="chart-container"></div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 告警记录与处置建议 -->
|
|
|
- <div class="alert-section" v-if="selectedStation.alertStatus">
|
|
|
- <div class="section-header">
|
|
|
- <span><el-icon><BellFilled /></el-icon> 实时告警信息</span>
|
|
|
- <el-button type="primary" size="small" @click="handleAlert">立即处理</el-button>
|
|
|
- </div>
|
|
|
- <el-alert
|
|
|
- :title="`${selectedStation.name} 甲烷浓度 ${selectedStation.methane}ppm 超过阈值 ${selectedStation.methaneThreshold}ppm`"
|
|
|
- type="error"
|
|
|
- show-icon
|
|
|
- :closable="false"
|
|
|
- description="请立即安排检修人员前往现场排查泄漏点,同时通知周边居民做好防护措施。"
|
|
|
- />
|
|
|
- <div class="alert-actions">
|
|
|
- <el-button type="danger" @click="dispatchEmergency">派发应急工单</el-button>
|
|
|
- <el-button @click="viewAlertHistory">查看历史告警</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
<!-- SCADA系统接入信息 -->
|
|
|
<div class="scada-section">
|
|
|
<div class="section-header">
|
|
|
@@ -202,33 +138,15 @@
|
|
|
</div>
|
|
|
<el-descriptions :column="2" border size="small">
|
|
|
<el-descriptions-item label="数据来源">燃气公司SCADA系统</el-descriptions-item>
|
|
|
- <el-descriptions-item label="最后通讯时间">{{ selectedStation.lastUpdate }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="最后通讯时间">{{ selectedStation.lastUpdateTime || '--' }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="数据采集频率">10秒/次</el-descriptions-item>
|
|
|
<el-descriptions-item label="通讯状态">
|
|
|
<el-tag type="success">在线</el-tag>
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="场站编号">{{ selectedStation.stationCode }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="设备总数">{{ selectedStation.deviceCount }}台</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="关联设备">{{ selectedStation.deviceCount }}台</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- 历史告警记录 -->
|
|
|
- <div class="history-section">
|
|
|
- <div class="section-header"><span><el-icon><Document /></el-icon> 历史告警记录</span></div>
|
|
|
- <el-timeline>
|
|
|
- <el-timeline-item
|
|
|
- v-for="alert in selectedStation.alertHistory"
|
|
|
- :key="alert.id"
|
|
|
- :timestamp="alert.time"
|
|
|
- :type="alert.type"
|
|
|
- >
|
|
|
- {{ alert.content }}
|
|
|
- </el-timeline-item>
|
|
|
- <el-timeline-item v-if="!selectedStation.alertHistory?.length" timestamp="暂无告警记录" type="info">
|
|
|
- 该场站近30天无告警记录
|
|
|
- </el-timeline-item>
|
|
|
- </el-timeline>
|
|
|
- </div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 未选中状态 -->
|
|
|
@@ -240,124 +158,64 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
|
|
-import { Warning, Refresh, Download, Location, WindPower, Connection, TrendCharts, BellFilled, Monitor, Document, Search } from '@element-plus/icons-vue'
|
|
|
+import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
|
|
+import { Warning, Refresh, Location, WindPower, Odometer, TrendCharts, Monitor, Search } from '@element-plus/icons-vue'
|
|
|
import * as echarts from 'echarts'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
+import { getGasMonitorPoints, getGasMonitorTrend } from '@/api/pipeNetwork/gasMonitor'
|
|
|
|
|
|
-// 小时标签(24小时)
|
|
|
-const hourLabels = ['00:00','01:00','02:00','03:00','04:00','05:00','06:00','07:00','08:00','09:00','10:00','11:00','12:00','13:00','14:00','15:00','16:00','17:00','18:00','19:00','20:00','21:00','22:00','23:00']
|
|
|
+// ECharts实例
|
|
|
+const trendChartRef = ref(null)
|
|
|
+let trendChartInstance = null
|
|
|
|
|
|
-// 沅陵县燃气场站数据(6站,接入SCADA系统)
|
|
|
-const mockStations = ref([
|
|
|
- {
|
|
|
- id: 1, name: '太常LNG储配站', stationCode: 'YL-LNG-01', address: '沅陵县太常片区辰州东路末段',
|
|
|
- methane: 48, methaneThreshold: 20, inPressure: 395, outPressure: 242, temperature: 23.2,
|
|
|
- alertStatus: true, lastUpdate: '2026-06-15 15:23:45', deviceCount: 32,
|
|
|
- alertHistory: [
|
|
|
- { id: 1, time: '2026-06-15 15:23:45', type: 'danger', content: '甲烷浓度48ppm超过阈值20ppm,触发严重告警' },
|
|
|
- { id: 2, time: '2026-06-15 10:15:00', type: 'warning', content: '储罐区甲烷传感器示值偏高,安排巡检' },
|
|
|
- { id: 3, time: '2026-06-12 14:30:00', type: 'danger', content: 'LNG储罐B区微量泄漏,已紧急处置' }
|
|
|
- ],
|
|
|
- trendData: {
|
|
|
- methane: [8,7,9,8,10,12,15,18,20,22,25,28,30,32,35,38,40,42,44,45,46,47,48,48],
|
|
|
- inPressure: [388,390,392,394,395,396,394,392,390,388,390,393,395,397,398,396,394,393,392,394,395,396,394,393],
|
|
|
- outPressure: [238,240,241,242,243,244,242,240,239,238,240,242,243,244,242,241,240,241,242,243,242,241,240,242]
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2, name: '工业园计量站', stationCode: 'YL-GY-01', address: '沅陵县太常片区建设东路工业园入口东侧',
|
|
|
- methane: 35, methaneThreshold: 20, inPressure: 360, outPressure: 218, temperature: 24.5,
|
|
|
- alertStatus: true, lastUpdate: '2026-06-15 15:22:30', deviceCount: 20,
|
|
|
- alertHistory: [
|
|
|
- { id: 1, time: '2026-06-15 14:32:05', type: 'danger', content: '甲烷浓度35ppm超过阈值20ppm,触发告警' },
|
|
|
- { id: 2, time: '2026-06-14 09:20:00', type: 'warning', content: '计量间甲烷浓度异常波动,正在排查' }
|
|
|
- ],
|
|
|
- trendData: {
|
|
|
- methane: [6,7,8,9,10,11,13,15,18,20,22,25,27,28,30,31,32,33,34,35,35,34,33,35],
|
|
|
- inPressure: [355,357,358,360,361,362,360,358,356,355,357,359,361,362,360,358,357,358,359,360,361,359,357,358],
|
|
|
- outPressure: [215,216,217,218,219,220,218,216,215,214,216,218,219,220,218,217,216,217,218,219,218,217,216,218]
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 3, name: '太常调压站', stationCode: 'YL-TY-01', address: '沅陵县太常片区古城中路与天宁路交叉口东侧',
|
|
|
- methane: 18, methaneThreshold: 20, inPressure: 345, outPressure: 205, temperature: 22.8,
|
|
|
- alertStatus: false, lastUpdate: '2026-06-15 15:21:18', deviceCount: 16,
|
|
|
- alertHistory: [
|
|
|
- { id: 1, time: '2026-06-13 14:58:12', type: 'warning', content: '甲烷浓度接近阈值达到18ppm,加强监控' },
|
|
|
- { id: 2, time: '2026-05-20 08:00:00', type: 'success', content: '调压设备定期维护完成,恢复正常运行' }
|
|
|
- ],
|
|
|
- trendData: {
|
|
|
- methane: [12,11,12,13,14,14,15,15,16,16,17,17,18,18,17,17,16,16,15,15,14,14,13,12],
|
|
|
- inPressure: [340,342,343,345,346,347,345,343,341,340,342,344,346,347,345,343,342,343,344,345,346,344,342,343],
|
|
|
- outPressure: [200,202,203,205,206,207,205,203,201,200,202,204,206,207,205,203,202,203,204,205,206,204,202,203]
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 4, name: '城南调压站', stationCode: 'YL-CNTY-01', address: '沅陵县太常片区建设路与古城南路交叉口南侧',
|
|
|
- methane: 8, methaneThreshold: 20, inPressure: 330, outPressure: 195, temperature: 21.5,
|
|
|
- alertStatus: false, lastUpdate: '2026-06-15 15:20:45', deviceCount: 12,
|
|
|
- alertHistory: [
|
|
|
- { id: 1, time: '2026-06-12 22:45:00', type: 'warning', content: '出口压力瞬时波动,自动调节恢复' }
|
|
|
- ],
|
|
|
- trendData: {
|
|
|
- methane: [5,5,6,6,7,7,8,8,9,9,8,8,7,7,6,6,5,5,6,6,7,7,8,8],
|
|
|
- inPressure: [325,327,328,330,331,332,330,328,326,325,327,329,331,332,330,328,327,328,329,330,331,329,327,328],
|
|
|
- outPressure: [190,192,193,195,196,197,195,193,191,190,192,194,196,197,195,193,192,193,194,195,196,194,192,193]
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 5, name: '辰州路门站', stationCode: 'YL-CS-01', address: '沅陵县太常片区辰州中路与天宁路交叉口',
|
|
|
- methane: 12, methaneThreshold: 20, inPressure: 375, outPressure: 228, temperature: 22.0,
|
|
|
- alertStatus: false, lastUpdate: '2026-06-15 15:19:30', deviceCount: 24,
|
|
|
- alertHistory: [],
|
|
|
- trendData: {
|
|
|
- methane: [10,10,11,11,12,12,12,11,11,11,12,12,12,11,11,10,10,11,11,12,12,12,11,12],
|
|
|
- inPressure: [370,372,373,375,376,377,375,373,371,370,372,374,376,377,375,373,372,373,374,375,376,374,372,373],
|
|
|
- outPressure: [224,225,226,228,229,230,228,226,225,224,225,227,229,230,228,226,225,226,227,228,229,227,225,228]
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 6, name: '迎宾路调压站', stationCode: 'YL-YB-01', address: '沅陵县太常片区迎宾东路与建设路交叉口北侧',
|
|
|
- methane: 5, methaneThreshold: 20, inPressure: 310, outPressure: 188, temperature: 20.8,
|
|
|
- alertStatus: false, lastUpdate: '2026-06-15 15:18:50', deviceCount: 10,
|
|
|
- alertHistory: [],
|
|
|
- trendData: {
|
|
|
- methane: [4,4,5,5,4,4,5,5,6,5,5,4,4,5,5,6,5,5,4,4,5,5,4,5],
|
|
|
- inPressure: [305,307,308,310,311,312,310,308,306,305,307,309,311,312,310,308,307,308,309,310,311,309,307,308],
|
|
|
- outPressure: [184,185,186,188,189,190,188,186,185,184,185,187,189,190,188,186,185,186,187,188,189,187,185,188]
|
|
|
+// 加载数据
|
|
|
+const stations = ref([])
|
|
|
+const loading = ref(false)
|
|
|
+
|
|
|
+async function loadStations() {
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const res = await getGasMonitorPoints()
|
|
|
+ stations.value = res.data || []
|
|
|
+ if (stations.value.length > 0) {
|
|
|
+ selectStation(stations.value[0])
|
|
|
}
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
}
|
|
|
-])
|
|
|
+}
|
|
|
|
|
|
// 统计数据
|
|
|
-const totalStations = computed(() => mockStations.value.length)
|
|
|
-const alertCount = computed(() => mockStations.value.filter(s => s.alertStatus).length)
|
|
|
+const totalStations = computed(() => stations.value.length)
|
|
|
+const alertCount = computed(() => stations.value.filter(s => s.alertStatus).length)
|
|
|
const normalCount = computed(() => totalStations.value - alertCount.value)
|
|
|
-const maxMethane = computed(() => Math.max(...mockStations.value.map(s => s.methane)))
|
|
|
-const maxMethaneStation = computed(() => mockStations.value.find(s => s.methane === maxMethane.value)?.name || '—')
|
|
|
-const avgInPressure = computed(() => (mockStations.value.reduce((sum, s) => sum + s.inPressure, 0) / totalStations.value).toFixed(0))
|
|
|
-const avgOutPressure = computed(() => (mockStations.value.reduce((sum, s) => sum + s.outPressure, 0) / totalStations.value).toFixed(0))
|
|
|
+const maxMethane = computed(() => {
|
|
|
+ if (!stations.value.length) return 0
|
|
|
+ return Math.max(...stations.value.map(s => s.methaneValue))
|
|
|
+})
|
|
|
+const maxMethaneStation = computed(() => {
|
|
|
+ const max = maxMethane.value
|
|
|
+ return stations.value.find(s => s.methaneValue === max)?.pointName || '—'
|
|
|
+})
|
|
|
const riskScore = computed(() => {
|
|
|
+ if (!stations.value.length) return 0
|
|
|
const alertRatio = alertCount.value / totalStations.value
|
|
|
- const avgMethane = mockStations.value.reduce((sum, s) => sum + s.methane, 0) / totalStations.value
|
|
|
+ const avgMethane = stations.value.reduce((sum, s) => sum + s.methaneValue, 0) / totalStations.value
|
|
|
let score = 100 - (alertRatio * 50 + (avgMethane / 40) * 30)
|
|
|
return Math.max(0, Math.min(100, Math.round(score)))
|
|
|
})
|
|
|
|
|
|
// 筛选
|
|
|
const searchKeyword = ref('')
|
|
|
-const dateRange = ref([])
|
|
|
const currentPage = ref(1)
|
|
|
const pageSize = 5
|
|
|
-const selectedStation = ref(mockStations.value[0])
|
|
|
-const trendMetric = ref('methane')
|
|
|
+const selectedStation = ref(null)
|
|
|
|
|
|
const filteredStations = computed(() => {
|
|
|
- let list = mockStations.value
|
|
|
+ let list = stations.value
|
|
|
if (searchKeyword.value) {
|
|
|
const kw = searchKeyword.value.toLowerCase()
|
|
|
- list = list.filter(s => s.name.toLowerCase().includes(kw))
|
|
|
+ list = list.filter(s => s.pointName.toLowerCase().includes(kw))
|
|
|
}
|
|
|
return list
|
|
|
})
|
|
|
@@ -366,66 +224,69 @@ const paginatedStations = computed(() => {
|
|
|
return filteredStations.value.slice(start, start + pageSize)
|
|
|
})
|
|
|
|
|
|
-// 趋势图(echarts.init)
|
|
|
-const trendChartRef = ref(null)
|
|
|
-let trendChartInstance = null
|
|
|
-
|
|
|
-function renderTrendChart() {
|
|
|
+// 趋势图
|
|
|
+function renderTrendChart(trendRes) {
|
|
|
if (!trendChartRef.value || !selectedStation.value) return
|
|
|
if (!trendChartInstance) {
|
|
|
trendChartInstance = echarts.init(trendChartRef.value)
|
|
|
}
|
|
|
- const data = selectedStation.value.trendData[trendMetric.value]
|
|
|
- const unit = trendMetric.value === 'methane' ? 'ppm' : 'kPa'
|
|
|
- const color = trendMetric.value === 'methane' ? '#f56c6c' : '#409eff'
|
|
|
- const threshold = trendMetric.value === 'methane' ? selectedStation.value.methaneThreshold : null
|
|
|
+ const data = trendRes || {}
|
|
|
+ const times = data.times || []
|
|
|
+ const values = data.methaneValues || []
|
|
|
+ const threshold = data.threshold || 20
|
|
|
|
|
|
- const series = [{
|
|
|
- name: trendMetric.value === 'methane' ? '甲烷浓度' : trendMetric.value === 'inPressure' ? '进口压力' : '出口压力',
|
|
|
- type: 'line',
|
|
|
- data: data,
|
|
|
- smooth: true,
|
|
|
- lineStyle: { color, width: 2 },
|
|
|
- areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
- { offset: 0, color: color === '#f56c6c' ? 'rgba(245,108,108,0.3)' : 'rgba(64,158,255,0.3)' },
|
|
|
- { offset: 1, color: 'rgba(255,255,255,0.05)' }
|
|
|
- ])},
|
|
|
- symbol: 'none'
|
|
|
- }]
|
|
|
- if (threshold) {
|
|
|
- series.push({
|
|
|
- name: '报警阈值',
|
|
|
- type: 'line',
|
|
|
- data: Array(24).fill(threshold),
|
|
|
- lineStyle: { color: '#f56c6c', width: 1.5, type: 'dashed' },
|
|
|
- symbol: 'none'
|
|
|
- })
|
|
|
- }
|
|
|
trendChartInstance.setOption({
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
- legend: { data: threshold ? [series[0].name, '报警阈值'] : [series[0].name], bottom: 0 },
|
|
|
+ legend: { data: ['甲烷浓度', '报警阈值'], bottom: 0 },
|
|
|
grid: { left: 50, right: 30, top: 20, bottom: 30 },
|
|
|
- xAxis: { type: 'category', data: hourLabels, axisLabel: { rotate: 45, interval: 3, fontSize: 10 } },
|
|
|
- yAxis: { type: 'value', name: unit, axisLabel: { fontSize: 10 } },
|
|
|
- series
|
|
|
+ xAxis: {
|
|
|
+ type: 'category', data: times,
|
|
|
+ axisLabel: { rotate: 45, interval: 3, fontSize: 10 }
|
|
|
+ },
|
|
|
+ yAxis: { type: 'value', name: 'ppm', axisLabel: { fontSize: 10 } },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '甲烷浓度', type: 'line', data: values,
|
|
|
+ smooth: true,
|
|
|
+ lineStyle: { color: '#f56c6c', width: 2 },
|
|
|
+ areaStyle: {
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
+ { offset: 0, color: 'rgba(245,108,108,0.3)' },
|
|
|
+ { offset: 1, color: 'rgba(255,255,255,0.05)' }
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ symbol: 'none'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '报警阈值', type: 'line',
|
|
|
+ data: Array(times.length || 24).fill(threshold),
|
|
|
+ lineStyle: { color: '#f56c6c', width: 1.5, type: 'dashed' },
|
|
|
+ symbol: 'none'
|
|
|
+ }
|
|
|
+ ]
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-const selectStation = (station) => {
|
|
|
+async function selectStation(station) {
|
|
|
selectedStation.value = station
|
|
|
- nextTick(() => renderTrendChart())
|
|
|
+ currentPage.value = 1
|
|
|
+ try {
|
|
|
+ const res = await getGasMonitorTrend(station.pointId, 24)
|
|
|
+ await nextTick()
|
|
|
+ renderTrendChart(res.data || {})
|
|
|
+ } catch {
|
|
|
+ await nextTick()
|
|
|
+ renderTrendChart({})
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-const refreshData = () => { ElMessage.success('数据已刷新') }
|
|
|
-const exportReport = () => { ElMessage.success('导出监测报表(演示)') }
|
|
|
-const handleAlert = () => { ElMessage.warning('正在处理告警...') }
|
|
|
-const dispatchEmergency = () => { ElMessage.success('应急工单已派发') }
|
|
|
-const viewAlertHistory = () => { ElMessage.info('查看历史告警记录') }
|
|
|
-
|
|
|
-watch(trendMetric, () => nextTick(() => renderTrendChart()))
|
|
|
+function refreshData() {
|
|
|
+ ElMessage.success('数据已刷新')
|
|
|
+ loadStations()
|
|
|
+}
|
|
|
|
|
|
onMounted(() => {
|
|
|
- nextTick(() => renderTrendChart())
|
|
|
+ loadStations()
|
|
|
})
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
@@ -464,7 +325,7 @@ onBeforeUnmount(() => {
|
|
|
|
|
|
.kpi-cards {
|
|
|
display: grid;
|
|
|
- grid-template-columns: repeat(4, 1fr);
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
gap: 16px;
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
@@ -541,7 +402,7 @@ onBeforeUnmount(() => {
|
|
|
|
|
|
.realtime-cards {
|
|
|
display: grid;
|
|
|
- grid-template-columns: repeat(4, 1fr);
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
gap: 16px;
|
|
|
margin-bottom: 24px;
|
|
|
}
|
|
|
@@ -561,7 +422,7 @@ onBeforeUnmount(() => {
|
|
|
.card-value .unit { font-size: 12px; font-weight: normal; }
|
|
|
.card-threshold { font-size: 11px; color: #aaa; margin-top: 4px; }
|
|
|
|
|
|
-.chart-section, .alert-section, .scada-section, .history-section {
|
|
|
+.chart-section, .scada-section {
|
|
|
margin-bottom: 24px;
|
|
|
}
|
|
|
.section-header {
|
|
|
@@ -572,7 +433,6 @@ onBeforeUnmount(() => {
|
|
|
align-items: center;
|
|
|
}
|
|
|
.chart-container { height: 260px; }
|
|
|
-.alert-actions { display: flex; gap: 12px; margin-top: 16px; }
|
|
|
.empty-panel { flex: 1; display: flex; align-items: center; justify-content: center; background: white; border-radius: 16px; }
|
|
|
.pagination-area { padding: 12px; text-align: center; border-top: 1px solid #eee; }
|
|
|
-</style>
|
|
|
+</style>
|