|
|
@@ -173,9 +173,7 @@
|
|
|
<el-radio-button label="outPressure">出口压力</el-radio-button>
|
|
|
</el-radio-group>
|
|
|
</div>
|
|
|
- <div class="chart-container">
|
|
|
- <v-chart :option="trendChartOption" autoresize />
|
|
|
- </div>
|
|
|
+ <div ref="trendChartRef" class="chart-container"></div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 告警记录与处置建议 -->
|
|
|
@@ -242,85 +240,92 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, computed } from 'vue'
|
|
|
+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 { use } from 'echarts/core'
|
|
|
-import { CanvasRenderer } from 'echarts/renderers'
|
|
|
-import { LineChart } from 'echarts/charts'
|
|
|
-import { TitleComponent, TooltipComponent, LegendComponent, GridComponent, ToolboxComponent } from 'echarts/components'
|
|
|
+import * as echarts from 'echarts'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
|
-use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent, ToolboxComponent])
|
|
|
+// 小时标签(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']
|
|
|
|
|
|
-// 模拟燃气场站数据(接入SCADA系统)
|
|
|
+// 沅陵县燃气场站数据(6站,接入SCADA系统)
|
|
|
const mockStations = ref([
|
|
|
{
|
|
|
- id: 1, name: '浦东天然气门站', stationCode: 'PD-01', address: '浦东新区世纪大道888号',
|
|
|
- methane: 28, methaneThreshold: 20, inPressure: 385, outPressure: 235, temperature: 22.5,
|
|
|
- alertStatus: true, lastUpdate: '2025-04-02 15:23:45', deviceCount: 28,
|
|
|
+ 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: '2025-04-02 14:30:22', type: 'danger', content: '甲烷浓度28ppm超过阈值20ppm,触发告警' },
|
|
|
- { id: 2, time: '2025-04-01 08:15:00', type: 'warning', content: '进口压力波动异常' }
|
|
|
+ { 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: [12, 13, 14, 15, 18, 20, 22, 25, 28, 28, 27, 26, 25, 24],
|
|
|
- inPressure: [380, 382, 385, 388, 390, 385, 382, 380, 378, 375, 380, 385, 390, 388],
|
|
|
- outPressure: [230, 232, 235, 238, 240, 238, 235, 233, 230, 228, 232, 235, 238, 236]
|
|
|
+ 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: 'PX-02', address: '徐汇区漕溪北路200号',
|
|
|
- methane: 5, methaneThreshold: 20, inPressure: 350, outPressure: 210, temperature: 21.8,
|
|
|
- alertStatus: false, lastUpdate: '2025-04-02 15:22:30', deviceCount: 16,
|
|
|
- alertHistory: [],
|
|
|
+ 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: [4, 5, 5, 4, 6, 5, 5, 4, 5, 5, 6, 5, 4, 5],
|
|
|
- inPressure: [345, 348, 350, 352, 355, 350, 348, 345, 342, 345, 350, 352, 355, 350],
|
|
|
- outPressure: [205, 208, 210, 212, 215, 210, 208, 205, 202, 205, 210, 212, 215, 210]
|
|
|
+ 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: 'NH-03', address: '南汇区沪南公路168号',
|
|
|
- methane: 12, methaneThreshold: 20, inPressure: 320, outPressure: 195, temperature: 20.5,
|
|
|
- alertStatus: false, lastUpdate: '2025-04-02 15:21:18', deviceCount: 12,
|
|
|
- alertHistory: [{ id: 1, time: '2025-03-28 10:00:00', type: 'success', content: '设备检修完成,恢复正常' }],
|
|
|
+ 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: [10, 11, 12, 12, 13, 12, 11, 10, 11, 12, 12, 11, 10, 12],
|
|
|
- inPressure: [315, 318, 320, 322, 325, 320, 318, 315, 312, 315, 320, 322, 325, 320],
|
|
|
- outPressure: [190, 192, 195, 198, 200, 195, 193, 190, 188, 190, 195, 198, 200, 195]
|
|
|
+ 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: '宝山LNG储配站', stationCode: 'BS-04', address: '宝山区蕴川路500号',
|
|
|
- methane: 8, methaneThreshold: 20, inPressure: 400, outPressure: 245, temperature: 19.2,
|
|
|
- alertStatus: false, lastUpdate: '2025-04-02 15:20:45', deviceCount: 32,
|
|
|
- alertHistory: [],
|
|
|
+ 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: [6, 7, 8, 8, 7, 6, 7, 8, 9, 8, 7, 6, 7, 8],
|
|
|
- inPressure: [395, 398, 400, 402, 405, 400, 398, 395, 392, 395, 400, 402, 405, 400],
|
|
|
- outPressure: [240, 242, 245, 248, 250, 245, 243, 240, 238, 240, 245, 248, 250, 245]
|
|
|
+ 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: 'LG-05', address: '临港新城环湖西二路88号',
|
|
|
- methane: 18, methaneThreshold: 20, inPressure: 360, outPressure: 225, temperature: 21.0,
|
|
|
- alertStatus: false, lastUpdate: '2025-04-02 15:19:30', deviceCount: 20,
|
|
|
+ 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: [14, 15, 16, 17, 18, 18, 17, 16, 15, 16, 17, 18, 17, 18],
|
|
|
- inPressure: [355, 358, 360, 362, 365, 360, 358, 355, 352, 355, 360, 362, 365, 360],
|
|
|
- outPressure: [220, 222, 225, 228, 230, 225, 223, 220, 218, 220, 225, 228, 230, 225]
|
|
|
+ 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: 'JQ-06', address: '浦东新区金桥路666号',
|
|
|
- methane: 25, methaneThreshold: 20, inPressure: 370, outPressure: 230, temperature: 22.0,
|
|
|
- alertStatus: true, lastUpdate: '2025-04-02 15:18:50', deviceCount: 14,
|
|
|
- alertHistory: [{ id: 1, time: '2025-04-02 13:45:00', type: 'danger', content: '甲烷浓度25ppm,超过阈值20ppm' }],
|
|
|
+ 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: [15, 16, 18, 20, 22, 25, 25, 24, 23, 22, 21, 20, 19, 18],
|
|
|
- inPressure: [365, 368, 370, 372, 375, 370, 368, 365, 362, 365, 370, 372, 375, 370],
|
|
|
- outPressure: [225, 228, 230, 232, 235, 230, 228, 225, 222, 225, 230, 232, 235, 230]
|
|
|
+ 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]
|
|
|
}
|
|
|
}
|
|
|
])
|
|
|
@@ -361,11 +366,16 @@ const paginatedStations = computed(() => {
|
|
|
return filteredStations.value.slice(start, start + pageSize)
|
|
|
})
|
|
|
|
|
|
-// 趋势图配置
|
|
|
-const trendChartOption = computed(() => {
|
|
|
- if (!selectedStation.value) return {}
|
|
|
+// 趋势图(echarts.init)
|
|
|
+const trendChartRef = ref(null)
|
|
|
+let trendChartInstance = null
|
|
|
+
|
|
|
+function renderTrendChart() {
|
|
|
+ if (!trendChartRef.value || !selectedStation.value) return
|
|
|
+ if (!trendChartInstance) {
|
|
|
+ trendChartInstance = echarts.init(trendChartRef.value)
|
|
|
+ }
|
|
|
const data = selectedStation.value.trendData[trendMetric.value]
|
|
|
- const times = Array.from({ length: 24 }, (_, i) => `${i}:00`)
|
|
|
const unit = trendMetric.value === 'methane' ? 'ppm' : 'kPa'
|
|
|
const color = trendMetric.value === 'methane' ? '#f56c6c' : '#409eff'
|
|
|
const threshold = trendMetric.value === 'methane' ? selectedStation.value.methaneThreshold : null
|
|
|
@@ -375,38 +385,55 @@ const trendChartOption = computed(() => {
|
|
|
type: 'line',
|
|
|
data: data,
|
|
|
smooth: true,
|
|
|
- lineStyle: { color: color, width: 2 },
|
|
|
- areaStyle: { opacity: 0.1, color: color },
|
|
|
- symbol: 'circle',
|
|
|
- symbolSize: 6
|
|
|
+ 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: 2, type: 'dashed' },
|
|
|
+ lineStyle: { color: '#f56c6c', width: 1.5, type: 'dashed' },
|
|
|
symbol: 'none'
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
- return {
|
|
|
+ trendChartInstance.setOption({
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
- legend: { data: threshold ? [series[0].name, '报警阈值'] : [series[0].name] },
|
|
|
- xAxis: { type: 'category', data: times, axisLabel: { rotate: 45, interval: 4 } },
|
|
|
- yAxis: { type: 'value', name: unit },
|
|
|
- series: series,
|
|
|
- grid: { containLabel: true, left: '10%' }
|
|
|
- }
|
|
|
-})
|
|
|
+ legend: { data: threshold ? [series[0].name, '报警阈值'] : [series[0].name], 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
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const selectStation = (station) => {
|
|
|
+ selectedStation.value = station
|
|
|
+ nextTick(() => renderTrendChart())
|
|
|
+}
|
|
|
|
|
|
-const selectStation = (station) => { selectedStation.value = station }
|
|
|
const refreshData = () => { ElMessage.success('数据已刷新') }
|
|
|
const exportReport = () => { ElMessage.success('导出监测报表(演示)') }
|
|
|
const handleAlert = () => { ElMessage.warning('正在处理告警...') }
|
|
|
const dispatchEmergency = () => { ElMessage.success('应急工单已派发') }
|
|
|
const viewAlertHistory = () => { ElMessage.info('查看历史告警记录') }
|
|
|
+
|
|
|
+watch(trendMetric, () => nextTick(() => renderTrendChart()))
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ nextTick(() => renderTrendChart())
|
|
|
+})
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ if (trendChartInstance) {
|
|
|
+ trendChartInstance.dispose()
|
|
|
+ trendChartInstance = null
|
|
|
+ }
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|