<template> 
 | 
    <div class="safety-monitoring"> 
 | 
        <el-row :gutter="20"> 
 | 
            <!-- 左侧:实时监控区域 --> 
 | 
            <el-col :span="16"> 
 | 
                <el-card class="monitoring-card"> 
 | 
                    <div slot="header" class="card-header"> 
 | 
                        <span>实时气体浓度监控</span> 
 | 
                        <el-tag :type="systemStatus === 'normal' ? 'success' : 'danger'"> 
 | 
                            {{ systemStatus === 'normal' ? '系统正常' : '系统告警' }} 
 | 
                        </el-tag> 
 | 
                    </div> 
 | 
                     
 | 
                    <!-- 储罐区监控 --> 
 | 
                    <div class="monitoring-section"> 
 | 
                        <h3>储罐区监控</h3> 
 | 
                        <div class="sensor-grid"> 
 | 
                            <div class="sensor-item" v-for="sensor in tankSensors" :key="sensor.id"> 
 | 
                                <div class="sensor-header"> 
 | 
                                    <span>{{ sensor.name }}</span> 
 | 
                                    <el-tag :type="sensor.status === 'normal' ? 'success' : 'danger'" size="small"> 
 | 
                                        {{ sensor.status === 'normal' ? '正常' : '超标' }} 
 | 
                                    </el-tag> 
 | 
                                </div> 
 | 
                                <div class="sensor-data"> 
 | 
                                    <div class="data-item"> 
 | 
                                        <span>甲烷: {{ sensor.methane.toFixed(2) }}%</span> 
 | 
                                        <el-progress 
 | 
                                            :percentage="Math.min(Math.round(sensor.methane * 40 * 100) / 100, 100)" 
 | 
                                            :color="getProgressColor(Math.min(Math.round(sensor.methane * 40 * 100) / 100, 100), 80)" 
 | 
                                            :format="formatProgress" 
 | 
                                            :stroke-width="8" 
 | 
                                        /> 
 | 
                                    </div> 
 | 
                                    <div class="data-item"> 
 | 
                                        <span>硫化氢: {{ sensor.h2s.toFixed(2) }}ppm</span> 
 | 
                                        <el-progress 
 | 
                                            :percentage="Math.min(Math.round((sensor.h2s / 20) * 100 * 100) / 100, 100)" 
 | 
                                            :color="getProgressColor(Math.min(Math.round((sensor.h2s / 20) * 100 * 100) / 100, 100), 80)" 
 | 
                                            :format="formatProgress" 
 | 
                                            :stroke-width="8" 
 | 
                                        /> 
 | 
                                    </div> 
 | 
                                </div> 
 | 
                            </div> 
 | 
                        </div> 
 | 
                    </div> 
 | 
                     
 | 
                    <!-- 井口压缩机监控 --> 
 | 
                    <div class="monitoring-section"> 
 | 
                        <h3>井口压缩机监控</h3> 
 | 
                        <div class="sensor-grid"> 
 | 
                            <div class="sensor-item" v-for="sensor in compressorSensors" :key="sensor.id"> 
 | 
                                <div class="sensor-header"> 
 | 
                                    <span>{{ sensor.name }}</span> 
 | 
                                    <el-tag :type="sensor.status === 'normal' ? 'success' : 'danger'" size="small"> 
 | 
                                        {{ sensor.status === 'normal' ? '正常' : '超标' }} 
 | 
                                    </el-tag> 
 | 
                                </div> 
 | 
                                <div class="sensor-data"> 
 | 
                                    <div class="data-item"> 
 | 
                                        <span>甲烷: {{ sensor.methane.toFixed(2) }}%</span> 
 | 
                                        <el-progress 
 | 
                                            :percentage="Math.min(Math.round(sensor.methane * 40 * 100) / 100, 100)" 
 | 
                                            :color="getProgressColor(sensor.methane, 2.5)" 
 | 
                                            :format="formatProgress" 
 | 
                                            :stroke-width="8" 
 | 
                                        /> 
 | 
                                    </div> 
 | 
                                    <div class="data-item"> 
 | 
                                        <span>硫化氢: {{ sensor.h2s.toFixed(2) }}ppm</span> 
 | 
                                        <el-progress 
 | 
                                            :percentage="Math.min(Math.round((sensor.h2s / 20) * 100 * 100) / 100, 100)" 
 | 
                                            :color="getProgressColor(sensor.h2s, 10)" 
 | 
                                            :format="formatProgress" 
 | 
                                            :stroke-width="8" 
 | 
                                        /> 
 | 
                                    </div> 
 | 
                                </div> 
 | 
                            </div> 
 | 
                        </div> 
 | 
                    </div> 
 | 
                     
 | 
                    <!-- 实时曲线图 --> 
 | 
                    <div class="chart-section"> 
 | 
                        <h3>实时浓度曲线</h3> 
 | 
                        <div class="chart-container"> 
 | 
                            <div ref="chart" class="chart"></div> 
 | 
                        </div> 
 | 
                    </div> 
 | 
                </el-card> 
 | 
            </el-col> 
 | 
             
 | 
            <!-- 右侧:控制面板 --> 
 | 
            <el-col :span="8"> 
 | 
                <el-card class="control-card"> 
 | 
                    <div slot="header" class="card-header"> 
 | 
                        <span>应急控制面板</span> 
 | 
                    </div> 
 | 
                     
 | 
                    <!-- 喷淋状态 --> 
 | 
                    <div class="control-section"> 
 | 
                        <h4>喷淋系统状态</h4> 
 | 
                        <div class="status-grid"> 
 | 
                            <div class="status-item" v-for="sprinkler in sprinklerSystems" :key="sprinkler.id"> 
 | 
                                <div class="status-indicator" :class="sprinkler.status"> 
 | 
                                    <i class="el-icon-circle-check" v-if="sprinkler.status === 'active'"></i> 
 | 
                                    <i class="el-icon-circle-close" v-else></i> 
 | 
                                </div> 
 | 
                                <span>{{ sprinkler.name }}</span> 
 | 
                                <el-tag :type="sprinkler.status === 'active' ? 'success' : 'info'" size="small"> 
 | 
                                    {{ sprinkler.status === 'active' ? '运行中' : '待机' }} 
 | 
                                </el-tag> 
 | 
                            </div> 
 | 
                        </div> 
 | 
                    </div> 
 | 
                     
 | 
                    <!-- 应急记录按钮 --> 
 | 
                    <h4>应急管理</h4> 
 | 
                     
 | 
                    <div class="control-section1"> 
 | 
                        <el-button type="primary" @click="showEmergencyRecords" style="margin-bottom: 10px;"> 
 | 
                            应急记录 
 | 
                        </el-button> 
 | 
                        <el-button type="warning" @click="triggerEmergency" :disabled="!hasEmergency"> 
 | 
                            触发应急响应 
 | 
                        </el-button> 
 | 
                    </div> 
 | 
                     
 | 
                    <!-- 系统日志 --> 
 | 
                    <div class="control-section"> 
 | 
                        <h4>系统日志</h4> 
 | 
                        <div class="log-container"> 
 | 
                            <div class="log-item" v-for="log in systemLogs" :key="log.id"> 
 | 
                                <span class="log-time">{{ log.time }}</span> 
 | 
                                <span class="log-content">{{ log.content }}</span> 
 | 
                            </div> 
 | 
                        </div> 
 | 
                    </div> 
 | 
                </el-card> 
 | 
            </el-col> 
 | 
        </el-row> 
 | 
         
 | 
        <!-- 泄漏预警弹窗 --> 
 | 
        <el-dialog 
 | 
            title="⚠️ 泄漏预警" 
 | 
            :visible.sync="leakWarningVisible" 
 | 
            width="500px" 
 | 
            :close-on-click-modal="false" 
 | 
            :close-on-press-escape="false" 
 | 
            class="leak-warning-dialog" 
 | 
        > 
 | 
            <div class="warning-content"> 
 | 
                <div class="warning-icon"> 
 | 
                    <i class="el-icon-warning"></i> 
 | 
                </div> 
 | 
                <div class="warning-text"> 
 | 
                    <h3>检测到气体浓度超标!</h3> 
 | 
                    <p>位置:{{ currentWarning.location }}</p> 
 | 
                    <p>超标气体:{{ currentWarning.gas }}</p> 
 | 
                    <p>当前浓度:{{ currentWarning.value }}</p> 
 | 
                </div> 
 | 
            </div> 
 | 
            <div slot="footer" class="dialog-footer"> 
 | 
                <el-button type="danger" @click="acknowledgeWarning">确认告警</el-button> 
 | 
                <el-button type="primary" @click="viewDetails">查看详情</el-button> 
 | 
            </div> 
 | 
        </el-dialog> 
 | 
         
 | 
        <!-- 应急记录弹窗 --> 
 | 
        <el-dialog 
 | 
            title="应急记录" 
 | 
            :visible.sync="emergencyRecordsVisible" 
 | 
            width="800px" 
 | 
        > 
 | 
            <el-table :data="emergencyRecords" style="width: 100%" stripe> 
 | 
                <el-table-column prop="time" label="时间" width="180"></el-table-column> 
 | 
                <el-table-column prop="location" label="位置" width="150"></el-table-column> 
 | 
                <el-table-column prop="type" label="类型" width="120"></el-table-column> 
 | 
                <el-table-column prop="status" label="状态" width="100"> 
 | 
                    <template slot-scope="scope"> 
 | 
                        <el-tag :type="scope.row.status === 'resolved' ? 'success' : 'warning'"> 
 | 
                            {{ scope.row.status === 'resolved' ? '已解决' : '处理中' }} 
 | 
                        </el-tag> 
 | 
                    </template> 
 | 
                </el-table-column> 
 | 
                <el-table-column prop="description" label="描述"></el-table-column> 
 | 
                <el-table-column label="操作" width="120"> 
 | 
                    <template slot-scope="scope"> 
 | 
                        <el-button type="text" @click="viewBlockchainDetails(scope.row)"> 
 | 
                            区块链详情 
 | 
                        </el-button> 
 | 
                    </template> 
 | 
                </el-table-column> 
 | 
            </el-table> 
 | 
        </el-dialog> 
 | 
         
 | 
        <!-- 区块链存证详情弹窗 --> 
 | 
        <el-dialog 
 | 
            title="区块链存证详情" 
 | 
            :visible.sync="blockchainDetailsVisible" 
 | 
            width="900px" 
 | 
        > 
 | 
            <div class="blockchain-details"> 
 | 
                <el-descriptions :column="2" border> 
 | 
                    <el-descriptions-item label="事件ID">{{ currentEvent.id }}</el-descriptions-item> 
 | 
                    <el-descriptions-item label="时间戳">{{ currentEvent.timestamp }}</el-descriptions-item> 
 | 
                    <el-descriptions-item label="位置">{{ currentEvent.location }}</el-descriptions-item> 
 | 
                    <el-descriptions-item label="事件类型">{{ currentEvent.type }}</el-descriptions-item> 
 | 
                </el-descriptions> 
 | 
                 
 | 
                <div class="sensor-data-section"> 
 | 
                    <h4>传感器数据</h4> 
 | 
                    <el-table :data="currentEvent.sensorData" style="width: 100%" stripe> 
 | 
                        <el-table-column prop="sensor" label="传感器"></el-table-column> 
 | 
                        <el-table-column prop="methane" label="甲烷浓度"></el-table-column> 
 | 
                        <el-table-column prop="h2s" label="硫化氢浓度"></el-table-column> 
 | 
                        <el-table-column prop="timestamp" label="记录时间"></el-table-column> 
 | 
                    </el-table> 
 | 
                </div> 
 | 
                 
 | 
                <div class="action-log-section"> 
 | 
                    <h4>处置动作记录</h4> 
 | 
                    <el-timeline> 
 | 
                        <el-timeline-item 
 | 
                            v-for="action in currentEvent.actions" 
 | 
                            :key="action.id" 
 | 
                            :timestamp="action.timestamp" 
 | 
                            :type="action.type === 'emergency' ? 'danger' : 'primary'" 
 | 
                        > 
 | 
                            {{ action.description }} 
 | 
                        </el-timeline-item> 
 | 
                    </el-timeline> 
 | 
                </div> 
 | 
                 
 | 
                <div class="blockchain-info"> 
 | 
                    <h4>区块链信息</h4> 
 | 
                    <el-descriptions :column="1" border> 
 | 
                        <el-descriptions-item label="区块哈希">{{ currentEvent.blockHash }}</el-descriptions-item> 
 | 
                        <el-descriptions-item label="交易哈希">{{ currentEvent.txHash }}</el-descriptions-item> 
 | 
                        <el-descriptions-item label="确认数">{{ currentEvent.confirmations }}</el-descriptions-item> 
 | 
                    </el-descriptions> 
 | 
                </div> 
 | 
            </div> 
 | 
        </el-dialog> 
 | 
    </div> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
import * as echarts from 'echarts' 
 | 
  
 | 
export default { 
 | 
    name: 'SafetyMonitoring', 
 | 
    data() { 
 | 
        return { 
 | 
            systemStatus: 'normal', 
 | 
            leakWarningVisible: false, 
 | 
            emergencyRecordsVisible: false, 
 | 
            blockchainDetailsVisible: false, 
 | 
            currentWarning: {}, 
 | 
            currentEvent: {}, 
 | 
            hasEmergency: false, 
 | 
             
 | 
            // 储罐区传感器数据 
 | 
            tankSensors: [ 
 | 
                { id: 1, name: '储罐T-001', methane: 1.20, h2s: 2.10, status: 'normal' }, 
 | 
                { id: 2, name: '储罐T-002', methane: 0.80, h2s: 1.50, status: 'normal' }, 
 | 
                { id: 3, name: '储罐T-003', methane: 3.20, h2s: 8.50, status: 'warning' }, 
 | 
                { id: 4, name: '储罐T-004', methane: 0.60, h2s: 0.80, status: 'normal' } 
 | 
            ], 
 | 
             
 | 
            // 井口压缩机传感器数据 
 | 
            compressorSensors: [ 
 | 
                { id: 5, name: '压缩机C-001', methane: 2.10, h2s: 3.20, status: 'normal' }, 
 | 
                { id: 6, name: '压缩机C-002', methane: 4.80, h2s: 12.50, status: 'warning' }, 
 | 
                { id: 7, name: '压缩机C-003', methane: 1.80, h2s: 2.80, status: 'normal' } 
 | 
            ], 
 | 
             
 | 
            // 喷淋系统状态 
 | 
            sprinklerSystems: [ 
 | 
                { id: 1, name: '储罐区喷淋', status: 'active' }, 
 | 
                { id: 2, name: '压缩机区喷淋', status: 'standby' }, 
 | 
                { id: 3, name: '紧急喷淋', status: 'standby' } 
 | 
            ], 
 | 
             
 | 
            // 系统日志 
 | 
            systemLogs: [ 
 | 
                { id: 1, time: '14:30:25', content: '系统启动完成,所有传感器正常' }, 
 | 
                { id: 2, time: '14:35:12', content: '储罐T-003甲烷浓度超标,触发预警' }, 
 | 
                { id: 3, time: '14:35:15', content: '启动储罐区喷淋系统' }, 
 | 
                { id: 4, time: '14:35:20', content: '发送紧急疏散广播' } 
 | 
            ], 
 | 
             
 | 
            // 应急记录 
 | 
            emergencyRecords: [ 
 | 
                { 
 | 
                    id: 'EM001', 
 | 
                    time: '2024-01-15 14:35:12', 
 | 
                    location: '储罐T-003', 
 | 
                    type: '甲烷超标', 
 | 
                    status: 'resolved', 
 | 
                    description: '储罐T-003甲烷浓度达到3.2%,超过安全阈值2.5%' 
 | 
                }, 
 | 
                { 
 | 
                    id: 'EM002', 
 | 
                    time: '2024-01-15 14:35:15', 
 | 
                    location: '压缩机C-002', 
 | 
                    type: '硫化氢超标', 
 | 
                    status: 'processing', 
 | 
                    description: '压缩机C-002硫化氢浓度达到12.5ppm,超过安全阈值10ppm' 
 | 
                } 
 | 
            ], 
 | 
             
 | 
            // 图表实例 
 | 
            chart: null, 
 | 
             
 | 
            // 定时器 
 | 
            timer: null 
 | 
        } 
 | 
    }, 
 | 
     
 | 
    mounted() { 
 | 
        this.initChart() 
 | 
        this.startDataRefresh() 
 | 
        this.checkEmergencyStatus() 
 | 
    }, 
 | 
     
 | 
    beforeDestroy() { 
 | 
        if (this.timer) { 
 | 
            clearInterval(this.timer) 
 | 
        } 
 | 
        if (this.chart) { 
 | 
            this.chart.dispose() 
 | 
        } 
 | 
    }, 
 | 
     
 | 
    methods: { 
 | 
        // 统一进度条格式化为两位小数,避免浮点误差显示 
 | 
        formatProgress(percentage) { 
 | 
            if (percentage == null || isNaN(percentage)) return '0.00%' 
 | 
            const val = Math.round(Number(percentage) * 100) / 100 
 | 
            return `${val.toFixed(2)}%` 
 | 
        }, 
 | 
        // 初始化图表 
 | 
        initChart() { 
 | 
            this.chart = echarts.init(this.$refs.chart) 
 | 
            this.updateChart() 
 | 
        }, 
 | 
         
 | 
        // 更新图表数据 
 | 
        updateChart() { 
 | 
            const option = { 
 | 
                title: { 
 | 
                    text: '实时气体浓度监控', 
 | 
                    left: 'center' 
 | 
                }, 
 | 
                tooltip: { 
 | 
                    trigger: 'axis', 
 | 
                    axisPointer: { 
 | 
                        type: 'cross' 
 | 
                    } 
 | 
                }, 
 | 
                legend: { 
 | 
                    data: ['储罐区甲烷', '储罐区硫化氢', '压缩机甲烷', '压缩机硫化氢'], 
 | 
                    top: 30 
 | 
                }, 
 | 
                grid: { 
 | 
                    left: '3%', 
 | 
                    right: '4%', 
 | 
                    bottom: '3%', 
 | 
                    top: '15%', 
 | 
                    containLabel: true 
 | 
                }, 
 | 
                xAxis: { 
 | 
                    type: 'category', 
 | 
                    data: this.generateTimeData() 
 | 
                }, 
 | 
                yAxis: [ 
 | 
                    { 
 | 
                        type: 'value', 
 | 
                        name: '甲烷浓度(%)', 
 | 
                        position: 'left' 
 | 
                    }, 
 | 
                    { 
 | 
                        type: 'value', 
 | 
                        name: '硫化氢浓度(ppm)', 
 | 
                        position: 'right' 
 | 
                    } 
 | 
                ], 
 | 
                series: [ 
 | 
                    { 
 | 
                        name: '储罐区甲烷', 
 | 
                        type: 'line', 
 | 
                        data: this.generateRandomData(20, 0.5, 3.5), 
 | 
                        smooth: true, 
 | 
                        yAxisIndex: 0 
 | 
                    }, 
 | 
                    { 
 | 
                        name: '储罐区硫化氢', 
 | 
                        type: 'line', 
 | 
                        data: this.generateRandomData(20, 0.5, 12), 
 | 
                        smooth: true, 
 | 
                        yAxisIndex: 1 
 | 
                    }, 
 | 
                    { 
 | 
                        name: '压缩机甲烷', 
 | 
                        type: 'line', 
 | 
                        data: this.generateRandomData(20, 1.0, 5.0), 
 | 
                        smooth: true, 
 | 
                        yAxisIndex: 0 
 | 
                    }, 
 | 
                    { 
 | 
                        name: '压缩机硫化氢', 
 | 
                        type: 'line', 
 | 
                        data: this.generateRandomData(20, 1.0, 15), 
 | 
                        smooth: true, 
 | 
                        yAxisIndex: 1 
 | 
                    } 
 | 
                ] 
 | 
            } 
 | 
             
 | 
            this.chart.setOption(option) 
 | 
        }, 
 | 
         
 | 
        // 生成时间数据 
 | 
        generateTimeData() { 
 | 
            const times = [] 
 | 
            const now = new Date() 
 | 
            for (let i = 19; i >= 0; i--) { 
 | 
                const time = new Date(now.getTime() - i * 5 * 60 * 1000) 
 | 
                times.push(time.toLocaleTimeString('zh-CN', { hour12: false })) 
 | 
            } 
 | 
            return times 
 | 
        }, 
 | 
         
 | 
        // 生成随机数据 
 | 
        generateRandomData(count, min, max) { 
 | 
            const data = [] 
 | 
            for (let i = 0; i < count; i++) { 
 | 
                data.push(+(Math.random() * (max - min) + min).toFixed(2)) 
 | 
            } 
 | 
            return data 
 | 
        }, 
 | 
         
 | 
        // 开始数据刷新 
 | 
        startDataRefresh() { 
 | 
            this.timer = setInterval(() => { 
 | 
                this.refreshSensorData() 
 | 
                this.updateChart() 
 | 
                this.checkEmergencyStatus() 
 | 
            }, 5000) // 每5秒刷新一次 
 | 
        }, 
 | 
         
 | 
        // 刷新传感器数据 
 | 
        refreshSensorData() { 
 | 
            // 更新储罐区传感器数据 
 | 
            this.tankSensors.forEach(sensor => { 
 | 
                sensor.methane = +(Math.random() * 4).toFixed(2) 
 | 
                sensor.h2s = +(Math.random() * 15).toFixed(2) 
 | 
                sensor.status = this.getSensorStatus(sensor.methane, sensor.h2s) 
 | 
            }) 
 | 
             
 | 
            // 更新压缩机传感器数据 
 | 
            this.compressorSensors.forEach(sensor => { 
 | 
                sensor.methane = +(Math.random() * 6).toFixed(2) 
 | 
                sensor.h2s = +(Math.random() * 20).toFixed(2) 
 | 
                sensor.status = this.getSensorStatus(sensor.methane, sensor.h2s) 
 | 
            }) 
 | 
             
 | 
            // 检查是否需要触发预警 
 | 
            this.checkLeakWarning() 
 | 
        }, 
 | 
         
 | 
        // 获取传感器状态 
 | 
        getSensorStatus(methane, h2s) { 
 | 
            const methanePct = Math.min(Math.round(methane * 40 * 100) / 100, 100) 
 | 
            const h2sPct = Math.min(Math.round((h2s / 20) * 100 * 100) / 100, 100) 
 | 
            if (methanePct >= 80 || h2sPct >= 80) { 
 | 
                return 'warning' 
 | 
            } 
 | 
            return 'normal' 
 | 
        }, 
 | 
         
 | 
        // 检查泄漏预警 
 | 
        checkLeakWarning() { 
 | 
            const allSensors = [...this.tankSensors, ...this.compressorSensors] 
 | 
            const warningSensor = allSensors.find(sensor => this.getSensorStatus(sensor.methane, sensor.h2s) === 'warning') 
 | 
             
 | 
            if (warningSensor && !this.leakWarningVisible) { 
 | 
                this.triggerLeakWarning(warningSensor) 
 | 
            } 
 | 
        }, 
 | 
         
 | 
        // 触发泄漏预警 
 | 
        triggerLeakWarning(sensor) { 
 | 
            const methanePct = Math.min(Math.round(sensor.methane * 40 * 100) / 100, 100) 
 | 
            const h2sPct = Math.min(Math.round((sensor.h2s / 20) * 100 * 100) / 100, 100) 
 | 
            const isMethaneMajor = methanePct >= h2sPct 
 | 
            const overGas = isMethaneMajor ? '甲烷' : '硫化氢' 
 | 
            const percent = (isMethaneMajor ? methanePct : h2sPct).toFixed(2) 
 | 
            this.currentWarning = { 
 | 
                location: sensor.name, 
 | 
                gas: overGas, 
 | 
                value: `${percent}%` 
 | 
            } 
 | 
             
 | 
            this.leakWarningVisible = true 
 | 
            this.hasEmergency = true 
 | 
             
 | 
            // 自动触发应急响应 
 | 
            this.autoEmergencyResponse(sensor) 
 | 
             
 | 
            // 添加系统日志 
 | 
            this.addSystemLog(`检测到${sensor.name}气体浓度超标,触发泄漏预警`) 
 | 
        }, 
 | 
         
 | 
        // 自动应急响应 
 | 
        autoEmergencyResponse(sensor) { 
 | 
            // 启动喷淋系统 
 | 
            if (sensor.name.includes('储罐')) { 
 | 
                this.sprinklerSystems[0].status = 'active' 
 | 
            } else if (sensor.name.includes('压缩机')) { 
 | 
                this.sprinklerSystems[1].status = 'active' 
 | 
            } 
 | 
             
 | 
            // 添加系统日志 
 | 
            this.addSystemLog(`启动${sensor.name}区域喷淋系统`) 
 | 
            this.addSystemLog(`发送紧急疏散广播`) 
 | 
             
 | 
            // 创建应急记录 
 | 
            this.createEmergencyRecord(sensor) 
 | 
        }, 
 | 
         
 | 
        // 添加系统日志 
 | 
        addSystemLog(content) { 
 | 
            const now = new Date() 
 | 
            const time = now.toLocaleTimeString('zh-CN', { hour12: false }) 
 | 
             
 | 
            this.systemLogs.unshift({ 
 | 
                id: Date.now(), 
 | 
                time: time, 
 | 
                content: content 
 | 
            }) 
 | 
             
 | 
            // 保持最多20条日志 
 | 
            if (this.systemLogs.length > 20) { 
 | 
                this.systemLogs = this.systemLogs.slice(0, 20) 
 | 
            } 
 | 
        }, 
 | 
         
 | 
        // 创建应急记录 
 | 
        createEmergencyRecord(sensor) { 
 | 
            const now = new Date() 
 | 
            const record = { 
 | 
                id: `EM${Date.now()}`, 
 | 
                time: now.toLocaleString('zh-CN'), 
 | 
                location: sensor.name, 
 | 
                type: sensor.methane > 2.5 ? '甲烷超标' : '硫化氢超标', 
 | 
                status: 'processing', 
 | 
                description: `${sensor.name}检测到${sensor.methane > 2.5 ? '甲烷' : '硫化氢'}浓度超标` 
 | 
            } 
 | 
             
 | 
            this.emergencyRecords.unshift(record) 
 | 
        }, 
 | 
         
 | 
        // 获取进度条颜色 
 | 
        getProgressColor(value, threshold) { 
 | 
            if (value > threshold) { 
 | 
                return '#F56C6C' 
 | 
            } else if (value > threshold * 0.8) { 
 | 
                return '#E6A23C' 
 | 
            } 
 | 
            return '#67C23A' 
 | 
        }, 
 | 
         
 | 
        // 检查应急状态 
 | 
        checkEmergencyStatus() { 
 | 
            const allSensors = [...this.tankSensors, ...this.compressorSensors] 
 | 
            const has = allSensors.some(sensor => this.getSensorStatus(sensor.methane, sensor.h2s) === 'warning') 
 | 
            this.hasEmergency = has 
 | 
            this.systemStatus = has ? 'warning' : 'normal' 
 | 
        }, 
 | 
         
 | 
        // 确认告警 
 | 
        acknowledgeWarning() { 
 | 
            this.leakWarningVisible = false 
 | 
            this.addSystemLog('泄漏预警已确认') 
 | 
        }, 
 | 
         
 | 
        // 查看详情 
 | 
        viewDetails() { 
 | 
            this.leakWarningVisible = false 
 | 
            // 这里可以跳转到详细页面或显示更多信息 
 | 
        }, 
 | 
         
 | 
        // 显示应急记录 
 | 
        showEmergencyRecords() { 
 | 
            this.emergencyRecordsVisible = true 
 | 
        }, 
 | 
         
 | 
        // 查看区块链详情 
 | 
        viewBlockchainDetails(record) { 
 | 
            this.currentEvent = { 
 | 
                id: record.id, 
 | 
                timestamp: record.time, 
 | 
                location: record.location, 
 | 
                type: record.type, 
 | 
                sensorData: [ 
 | 
                    { 
 | 
                        sensor: '甲烷传感器', 
 | 
                        methane: '3.2%', 
 | 
                        h2s: '8.5ppm', 
 | 
                        timestamp: record.time 
 | 
                    }, 
 | 
                    { 
 | 
                        sensor: '硫化氢传感器', 
 | 
                        methane: '2.8%', 
 | 
                        h2s: '12.5ppm', 
 | 
                        timestamp: record.time 
 | 
                    } 
 | 
                ], 
 | 
                actions: [ 
 | 
                    { 
 | 
                        id: 1, 
 | 
                        timestamp: record.time, 
 | 
                        type: 'emergency', 
 | 
                        description: '检测到气体浓度超标,触发预警' 
 | 
                    }, 
 | 
                    { 
 | 
                        id: 2, 
 | 
                        timestamp: new Date(new Date(record.time).getTime() + 3000).toLocaleString('zh-CN'), 
 | 
                        type: 'action', 
 | 
                        description: '启动喷淋系统降温' 
 | 
                    }, 
 | 
                    { 
 | 
                        id: 3, 
 | 
                        timestamp: new Date(new Date(record.time).getTime() + 5000).toLocaleString('zh-CN'), 
 | 
                        type: 'action', 
 | 
                        description: '发送紧急疏散广播' 
 | 
                    } 
 | 
                ], 
 | 
                blockHash: '0x1234567890abcdef...', 
 | 
                txHash: '0xabcdef1234567890...', 
 | 
                confirmations: 12 
 | 
            } 
 | 
             
 | 
            this.emergencyRecordsVisible = false 
 | 
            this.blockchainDetailsVisible = true 
 | 
        }, 
 | 
         
 | 
        // 触发应急响应 
 | 
        triggerEmergency() { 
 | 
            this.$message.success('应急响应已触发') 
 | 
            this.addSystemLog('手动触发应急响应') 
 | 
        } 
 | 
    } 
 | 
} 
 | 
</script> 
 | 
  
 | 
<style scoped> 
 | 
.safety-monitoring { 
 | 
    padding: 20px; 
 | 
    background-color: #f5f7fa; 
 | 
    min-height: calc(100vh - 84px); 
 | 
} 
 | 
  
 | 
.monitoring-card, .control-card { 
 | 
    margin-bottom: 20px; 
 | 
} 
 | 
  
 | 
.card-header { 
 | 
    display: flex; 
 | 
    justify-content: space-between; 
 | 
    align-items: center; 
 | 
} 
 | 
  
 | 
.monitoring-section { 
 | 
    margin-bottom: 30px; 
 | 
} 
 | 
  
 | 
.monitoring-section h3 { 
 | 
    color: #303133; 
 | 
    margin-bottom: 15px; 
 | 
    padding-bottom: 8px; 
 | 
    border-bottom: 2px solid #409EFF; 
 | 
} 
 | 
  
 | 
.sensor-grid { 
 | 
    display: grid; 
 | 
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); 
 | 
    gap: 15px; 
 | 
} 
 | 
  
 | 
.sensor-item { 
 | 
    background: #fff; 
 | 
    border: 1px solid #e4e7ed; 
 | 
    border-radius: 8px; 
 | 
    padding: 15px; 
 | 
    box-shadow: 0 2px 4px rgba(0,0,0,0.1); 
 | 
} 
 | 
  
 | 
.sensor-header { 
 | 
    display: flex; 
 | 
    justify-content: space-between; 
 | 
    align-items: center; 
 | 
    margin-bottom: 15px; 
 | 
    font-weight: bold; 
 | 
} 
 | 
  
 | 
.sensor-data .data-item { 
 | 
    margin-bottom: 12px; 
 | 
} 
 | 
  
 | 
.sensor-data .data-item span { 
 | 
    display: block; 
 | 
    margin-bottom: 5px; 
 | 
    font-size: 14px; 
 | 
    color: #606266; 
 | 
} 
 | 
  
 | 
.chart-section { 
 | 
    margin-top: 30px; 
 | 
} 
 | 
  
 | 
.chart-section h3 { 
 | 
    color: #303133; 
 | 
    margin-bottom: 15px; 
 | 
    padding-bottom: 8px; 
 | 
    border-bottom: 2px solid #409EFF; 
 | 
} 
 | 
  
 | 
.chart-container { 
 | 
    background: #fff; 
 | 
    border-radius: 8px; 
 | 
    padding: 20px; 
 | 
} 
 | 
  
 | 
.chart { 
 | 
    width: 100%; 
 | 
    height: 400px; 
 | 
} 
 | 
  
 | 
.control-section { 
 | 
    margin-bottom: 25px; 
 | 
} 
 | 
.control-section1 { 
 | 
    display: flex; 
 | 
} 
 | 
  
 | 
.control-section h4 { 
 | 
    color: #303133; 
 | 
    margin-bottom: 15px; 
 | 
    font-size: 16px; 
 | 
} 
 | 
  
 | 
.status-grid { 
 | 
    display: grid; 
 | 
    gap: 10px; 
 | 
} 
 | 
  
 | 
.status-item { 
 | 
    display: flex; 
 | 
    align-items: center; 
 | 
    gap: 10px; 
 | 
    padding: 10px; 
 | 
    background: #f8f9fa; 
 | 
    border-radius: 6px; 
 | 
} 
 | 
  
 | 
.status-indicator { 
 | 
    width: 20px; 
 | 
    height: 20px; 
 | 
    border-radius: 50%; 
 | 
    display: flex; 
 | 
    align-items: center; 
 | 
    justify-content: center; 
 | 
} 
 | 
  
 | 
.status-indicator.active { 
 | 
    color: #67C23A; 
 | 
} 
 | 
  
 | 
.status-indicator.standby { 
 | 
    color: #909399; 
 | 
} 
 | 
  
 | 
.log-container { 
 | 
    max-height: 200px; 
 | 
    overflow-y: auto; 
 | 
    background: #f8f9fa; 
 | 
    border-radius: 6px; 
 | 
    padding: 10px; 
 | 
} 
 | 
  
 | 
.log-item { 
 | 
    display: flex; 
 | 
    gap: 10px; 
 | 
    margin-bottom: 8px; 
 | 
    font-size: 12px; 
 | 
} 
 | 
  
 | 
.log-time { 
 | 
    color: #909399; 
 | 
    min-width: 60px; 
 | 
} 
 | 
  
 | 
.log-content { 
 | 
    color: #606266; 
 | 
} 
 | 
  
 | 
/* 泄漏预警弹窗样式 */ 
 | 
.leak-warning-dialog { 
 | 
    background: #fff5f5; 
 | 
} 
 | 
  
 | 
.warning-content { 
 | 
    text-align: center; 
 | 
    padding: 20px 0; 
 | 
} 
 | 
  
 | 
.warning-icon { 
 | 
    font-size: 60px; 
 | 
    color: #F56C6C; 
 | 
    margin-bottom: 20px; 
 | 
} 
 | 
  
 | 
.warning-text h3 { 
 | 
    color: #F56C6C; 
 | 
    margin-bottom: 15px; 
 | 
} 
 | 
  
 | 
.warning-text p { 
 | 
    margin: 8px 0; 
 | 
    color: #606266; 
 | 
} 
 | 
  
 | 
/* 区块链详情样式 */ 
 | 
.blockchain-details { 
 | 
    padding: 20px 0; 
 | 
} 
 | 
  
 | 
.sensor-data-section, .action-log-section, .blockchain-info { 
 | 
    margin-top: 25px; 
 | 
} 
 | 
  
 | 
.sensor-data-section h4, .action-log-section h4, .blockchain-info h4 { 
 | 
    color: #303133; 
 | 
    margin-bottom: 15px; 
 | 
    padding-bottom: 8px; 
 | 
    border-bottom: 1px solid #e4e7ed; 
 | 
} 
 | 
  
 | 
/* 响应式设计 */ 
 | 
@media (max-width: 1200px) { 
 | 
    .sensor-grid { 
 | 
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 
 | 
    } 
 | 
} 
 | 
  
 | 
@media (max-width: 768px) { 
 | 
    .safety-monitoring { 
 | 
        padding: 10px; 
 | 
    } 
 | 
     
 | 
    .sensor-grid { 
 | 
        grid-template-columns: 1fr; 
 | 
    } 
 | 
     
 | 
    .chart { 
 | 
        height: 300px; 
 | 
    } 
 | 
} 
 | 
</style> 
 |