# 报警解除状态 - 基于ESP32的isActive字段 ## 🎯 核心逻辑 利用ESP32已有的 `isActive` 字段来判断报警是否已解除: - **`isActive: true`** = 报警正在持续中 - **`isActive: false`** = 报警已自动解除 ## 📊 ESP32数据格式 ESP32的报警历史API (`/api/alarm/history`) 已经包含 `isActive` 字段: ```json { "alarms": [ { "id": 1, "title": "燃烧报警报警", "desc": "热源持续升温,温度超过阈值", "temp": 65.5, "time": "14:26:10", "date": "01-22", "location": "厨房区域", "isActive": false, // ✅ 关键字段:false表示已解除 "timestamp_ms": 1737548770000 }, { "id": 2, "title": "无人值守风险", "desc": "热源持续升温,厨房无人5分钟", "temp": 45.2, "time": "21:30:00", "date": "01-22", "location": "厨房区域", "isActive": true, // ⚠️ 仍在持续 "timestamp_ms": 1737548400000 } ], "anyAlarmActive": true } ``` ## 🔧 前端实现逻辑 ### 1. 解除状态判断 在 `pages/kitchen/history.vue` 的 `parseAlarmHistory` 方法中: ```javascript // 1. 优先使用ESP32的isActive字段判断(isActive=false表示已解除) if (alarm.hasOwnProperty('isActive') && alarm.isActive === false) { resolved = true resolvedType = 'auto' // ESP32自动检测解除 // 如果ESP32提供了解除时间,使用它 if (alarm.resolvedAt || alarm.resolved_at || alarm.resolvedTimestamp) { const resolvedTimestamp = alarm.resolvedAt || alarm.resolved_at || alarm.resolvedTimestamp const resolvedDate = new Date(typeof resolvedTimestamp === 'number' ? resolvedTimestamp : Date.parse(resolvedTimestamp)) resolvedTime = resolvedDate.getHours() + ':' + String(resolvedDate.getMinutes()).padStart(2, '0') } else { // 如果没有解除时间,显示为"已解除"(不显示具体时间) resolvedTime = '' } } ``` ### 2. UI显示 在报警卡片中: ```vue 已于 {{alarm.resolvedTime}} {{alarm.resolvedType === 'auto' ? '自动解除' : '用户处理'}} {{alarm.resolvedType === 'auto' ? '已自动解除' : '已处理'}} ``` ### 3. 显示效果 **有解除时间**: ``` 无人值守风险 热源持续升温,厨房无人5分钟 热点区域: 厨房区域 ✅ 已于 21:38 自动解除 ``` **没有解除时间**: ``` 燃烧报警报警 热源持续升温,温度超过阈值 热点区域: 厨房区域 ✅ 已自动解除 ``` ## 🚀 ESP32端建议优化 ### 当前实现 ESP32已经在报警数据中提供了 `isActive` 字段,这很好! ### 建议增强 为了提供更完整的解除信息,建议ESP32在报警解除时记录解除时间: ```cpp // AlarmManager.cpp struct AlarmRecord { int id; String title; String desc; float temp; unsigned long timestamp; String location; bool isActive; // ✅ 已有 // 建议新增 unsigned long resolvedAt; // 解除时间戳(毫秒) }; // 当检测到报警解除时 void checkAndResolveAlarms() { for (auto& alarm : alarmHistory) { if (alarm.isActive && currentTemp < SAFE_TEMP) { alarm.isActive = false; alarm.resolvedAt = millis(); // 记录解除时间 ESP_LOGI(TAG, "报警已解除: %s, 解除时间: %lu", alarm.title.c_str(), alarm.resolvedAt); } } } ``` ### 增强后的API响应 ```json { "alarms": [ { "id": 1, "title": "燃烧报警报警", "desc": "热源持续升温,温度超过阈值", "temp": 65.5, "time": "14:26:10", "date": "01-22", "location": "厨房区域", "isActive": false, "timestamp_ms": 1737548770000, "resolvedAt": 1737548880000 // ✨ 新增:解除时间戳 } ] } ``` ## 📋 数据流程 ### 1. 报警触发 ``` ESP32检测到高温 → 创建报警记录 (isActive=true) → 推送到云端 → APP显示报警(无解除状态) ``` ### 2. 报警解除 ``` ESP32检测到温度恢复 → 更新报警记录 (isActive=false, resolvedAt=当前时间) → 同步到云端 → APP显示解除状态 ✅ ``` ### 3. APP查询 ``` APP请求报警历史 → ESP32返回所有报警(包含isActive字段) → APP根据isActive判断是否显示解除状态 → 如果有resolvedAt,显示具体解除时间 → 如果没有resolvedAt,只显示"已自动解除" ``` ## 🎨 UI效果对比 ### 未解除的报警 ``` ┌─────────────────────────────┐ │ 🔥 高温危险 65.5°C │ │ 14:26 │ │ │ │ 热源持续升温,温度超过阈值 │ │ 热点区域: 厨房区域 │ │ │ │ [标记已读] [删除] │ └─────────────────────────────┘ ``` ### 已解除的报警(有时间) ``` ┌─────────────────────────────┐ │ 👤 无人值守风险 45.2°C │ │ 21:30 │ │ │ │ 热源持续升温,厨房无人5分钟 │ │ 热点区域: 厨房区域 │ │ ┌─────────────────────────┐ │ │ │ ✅ 已于 21:38 自动解除 │ │ │ └─────────────────────────┘ │ │ │ │ [标记已读] [删除] │ └─────────────────────────────┘ ``` ### 已解除的报警(无时间) ``` ┌─────────────────────────────┐ │ 🔥 燃烧报警报警 65.5°C │ │ 14:26 │ │ │ │ 热源持续升温,温度超过阈值 │ │ 热点区域: 厨房区域 │ │ ┌─────────────────────────┐ │ │ │ ✅ 已自动解除 │ │ │ └─────────────────────────┘ │ │ │ │ [标记已读] [删除] │ └─────────────────────────────┘ ``` ## 🔍 调试信息 在首页 (`pages/index/index.vue`) 中已经有详细的调试日志: ```javascript console.log('📊 最新报警状态:', { id: this.recentAlarms[0].id, title: this.recentAlarms[0].title, isActive: this.recentAlarms[0].isActive, anyAlarmActive: response.data.anyAlarmActive, shouldShowResetBtn: this.isAlarmActive(this.recentAlarms[0]) }) console.log('🔍 Alarm Reset按钮显示检查:', { totalAlarms: this.recentAlarms.length, firstAlarmActive: this.recentAlarms.length > 0 ? this.isAlarmActive(this.recentAlarms[0]) : false, firstAlarmData: this.recentAlarms.length > 0 ? { hasIsActive: this.recentAlarms[0].hasOwnProperty('isActive'), isActiveValue: this.recentAlarms[0].isActive, timestamp_ms: this.recentAlarms[0].timestamp_ms, timeDiff: this.recentAlarms[0].timestamp_ms ? (Date.now() - this.recentAlarms[0].timestamp_ms) : null } : null }) ``` 这些日志可以帮助验证 `isActive` 字段是否正确传递。 ## ✅ 优势 使用 `isActive` 字段的优势: 1. **无需额外开发** - ESP32已经提供了这个字段 2. **实时准确** - ESP32实时检测温度,能准确判断报警是否解除 3. **向后兼容** - 即使ESP32不提供 `resolvedAt`,也能显示解除状态 4. **逻辑清晰** - `isActive=false` 直观表示报警已解除 ## 📝 总结 现在报警历史页面已经支持: 1. ✅ 读取ESP32的 `isActive` 字段 2. ✅ `isActive=false` 时显示"已自动解除" 3. ✅ 如果有 `resolvedAt` 时间,显示具体解除时间 4. ✅ 没有时间时,显示简化文案 5. ✅ 绿色背景样式,清晰易识别 **无需修改ESP32代码,即可立即使用!** 如果ESP32后续添加 `resolvedAt` 字段,APP会自动显示具体解除时间。