290 lines
9.1 KiB
C#
290 lines
9.1 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using System.Linq;
|
||
|
|
using UnityEngine;
|
||
|
|
using LitJson;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 报警记录持久化数据模型
|
||
|
|
/// </summary>
|
||
|
|
[Serializable]
|
||
|
|
public class AlarmRecordData
|
||
|
|
{
|
||
|
|
public int Id;
|
||
|
|
public int Priority; // AlarmPriority枚举值
|
||
|
|
public string Reason;
|
||
|
|
public string Time; // DateTime序列化为字符串
|
||
|
|
public string AlarmCode; // 报警代码,用于去重
|
||
|
|
public bool IsTriggered; // true=报警触发, false=报警解除
|
||
|
|
|
||
|
|
public AlarmRecordData() { }
|
||
|
|
|
||
|
|
public AlarmRecordData(AlarmEvent alarmEvent, byte alarmCode, bool isTriggered)
|
||
|
|
{
|
||
|
|
Id = alarmEvent.Id;
|
||
|
|
Priority = (int)alarmEvent.Priority;
|
||
|
|
Reason = alarmEvent.Reason;
|
||
|
|
Time = alarmEvent.Time.ToString("yyyy-MM-dd HH:mm:ss");
|
||
|
|
AlarmCode = $"0x{alarmCode:X2}";
|
||
|
|
IsTriggered = isTriggered;
|
||
|
|
}
|
||
|
|
|
||
|
|
public AlarmEvent ToAlarmEvent()
|
||
|
|
{
|
||
|
|
return new AlarmEvent
|
||
|
|
{
|
||
|
|
Id = Id,
|
||
|
|
Priority = (AlarmPriority)Priority,
|
||
|
|
Reason = Reason,
|
||
|
|
Time = DateTime.TryParse(Time, out var dt) ? dt : DateTime.Now
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 报警记录存储容器
|
||
|
|
/// </summary>
|
||
|
|
[Serializable]
|
||
|
|
public class AlarmRecordStorage
|
||
|
|
{
|
||
|
|
public List<AlarmRecordData> Records = new List<AlarmRecordData>();
|
||
|
|
public int NextId = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 报警记录持久化服务
|
||
|
|
/// 负责报警记录的保存、加载和去重
|
||
|
|
/// </summary>
|
||
|
|
public class AlarmRecordPersistenceService
|
||
|
|
{
|
||
|
|
private readonly string _alarmRecordsPath;
|
||
|
|
private const int MAX_ALARM_RECORDS = 1000; // 最大记录数
|
||
|
|
private AlarmRecordStorage _storage;
|
||
|
|
|
||
|
|
// 去重窗口时间(秒)- 同一报警在此时间内不重复记录
|
||
|
|
private const int DEDUPLICATION_WINDOW_SECONDS = 60;
|
||
|
|
|
||
|
|
public AlarmRecordPersistenceService()
|
||
|
|
{
|
||
|
|
var dataPath = Application.persistentDataPath;
|
||
|
|
_alarmRecordsPath = Path.Combine(dataPath, "alarm_records.json");
|
||
|
|
|
||
|
|
LoadFromFile();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 添加报警记录(带去重)
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="alarmEvent">报警事件</param>
|
||
|
|
/// <param name="alarmCode">报警代码</param>
|
||
|
|
/// <param name="isTriggered">true=报警触发, false=报警解除</param>
|
||
|
|
public void AddRecord(AlarmEvent alarmEvent, byte alarmCode, bool isTriggered)
|
||
|
|
{
|
||
|
|
if (_storage == null)
|
||
|
|
{
|
||
|
|
_storage = new AlarmRecordStorage();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查是否为重复记录
|
||
|
|
if (IsDuplicateRecord(alarmCode, alarmEvent.Reason, alarmEvent.Time, isTriggered))
|
||
|
|
{
|
||
|
|
string statusStr = isTriggered ? "触发" : "解除";
|
||
|
|
Debug.Log($"[报警记录持久化] 跳过重复记录: {alarmEvent.Reason} (代码: 0x{alarmCode:X2}, 状态: {statusStr})");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建新记录
|
||
|
|
var recordData = new AlarmRecordData(alarmEvent, alarmCode, isTriggered);
|
||
|
|
recordData.Id = _storage.NextId++;
|
||
|
|
|
||
|
|
_storage.Records.Add(recordData);
|
||
|
|
|
||
|
|
// 保持记录数量在限制范围内
|
||
|
|
if (_storage.Records.Count > MAX_ALARM_RECORDS)
|
||
|
|
{
|
||
|
|
_storage.Records.RemoveAt(0); // 移除最旧的记录
|
||
|
|
}
|
||
|
|
|
||
|
|
// 保存到文件
|
||
|
|
SaveToFile();
|
||
|
|
|
||
|
|
string statusText = isTriggered ? "触发" : "解除";
|
||
|
|
Debug.Log($"[报警记录持久化] 添加记录: ID={recordData.Id}, {alarmEvent.Priority}, {alarmEvent.Reason} [{statusText}]");
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 检查是否为重复记录
|
||
|
|
/// 同一报警代码、同一状态在指定时间窗口内不重复记录
|
||
|
|
/// </summary>
|
||
|
|
private bool IsDuplicateRecord(byte alarmCode, string reason, DateTime time, bool isTriggered)
|
||
|
|
{
|
||
|
|
if (_storage?.Records == null || _storage.Records.Count == 0)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
string codeStr = $"0x{alarmCode:X2}";
|
||
|
|
|
||
|
|
var record = _storage.Records[ _storage.Records.Count - 1];
|
||
|
|
if (record.AlarmCode == codeStr && record.Reason == reason && record.IsTriggered == isTriggered)
|
||
|
|
{
|
||
|
|
if (DateTime.TryParse(record.Time, out var recordTime))
|
||
|
|
{
|
||
|
|
var timeDiff = (time - recordTime).TotalSeconds;
|
||
|
|
if (timeDiff < DEDUPLICATION_WINDOW_SECONDS)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// 从最新记录开始检查
|
||
|
|
// for (int i = _storage.Records.Count - 1; i >= 0; i--)
|
||
|
|
// {
|
||
|
|
// var record = _storage.Records[i];
|
||
|
|
|
||
|
|
// // 检查报警代码、原因和状态是否相同
|
||
|
|
// if (record.AlarmCode == codeStr && record.Reason == reason && record.IsTriggered == isTriggered)
|
||
|
|
// {
|
||
|
|
// // 检查时间差
|
||
|
|
// if (DateTime.TryParse(record.Time, out var recordTime))
|
||
|
|
// {
|
||
|
|
// var timeDiff = (time - recordTime).TotalSeconds;
|
||
|
|
|
||
|
|
// // 如果在去重窗口内,认为是重复记录
|
||
|
|
// if (timeDiff < DEDUPLICATION_WINDOW_SECONDS)
|
||
|
|
// {
|
||
|
|
// return true;
|
||
|
|
// }
|
||
|
|
|
||
|
|
// // 如果已经超过窗口时间,后面的记录更早,可以停止检查
|
||
|
|
// if (timeDiff > DEDUPLICATION_WINDOW_SECONDS * 2)
|
||
|
|
// {
|
||
|
|
// break;
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取报警记录列表
|
||
|
|
/// </summary>
|
||
|
|
public List<AlarmEvent> GetRecords(int maxCount = 1000)
|
||
|
|
{
|
||
|
|
if (_storage?.Records == null || _storage.Records.Count == 0)
|
||
|
|
return new List<AlarmEvent>();
|
||
|
|
|
||
|
|
var count = Math.Min(maxCount, _storage.Records.Count);
|
||
|
|
return _storage.Records
|
||
|
|
.Skip(_storage.Records.Count - count)
|
||
|
|
.Select(r => r.ToAlarmEvent())
|
||
|
|
.ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取所有报警记录
|
||
|
|
/// </summary>
|
||
|
|
public List<AlarmEvent> GetAllRecords()
|
||
|
|
{
|
||
|
|
if (_storage?.Records == null || _storage.Records.Count == 0)
|
||
|
|
return new List<AlarmEvent>();
|
||
|
|
|
||
|
|
return _storage.Records.Select(r => r.ToAlarmEvent()).ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 清除所有报警记录
|
||
|
|
/// </summary>
|
||
|
|
public void ClearRecords()
|
||
|
|
{
|
||
|
|
int clearedCount = _storage?.Records?.Count ?? 0;
|
||
|
|
|
||
|
|
_storage = new AlarmRecordStorage();
|
||
|
|
_storage.NextId = 1;
|
||
|
|
|
||
|
|
SaveToFile();
|
||
|
|
|
||
|
|
Debug.Log($"[报警记录持久化] 已清除 {clearedCount} 条记录");
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取报警记录总数
|
||
|
|
/// </summary>
|
||
|
|
public int GetRecordCount()
|
||
|
|
{
|
||
|
|
return _storage?.Records?.Count ?? 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 保存到文件
|
||
|
|
/// </summary>
|
||
|
|
private void SaveToFile()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var json = JsonMapper.ToJson(_storage);
|
||
|
|
File.WriteAllText(_alarmRecordsPath, json);
|
||
|
|
|
||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
|
|
AndroidFileLogger.Instance?.LogInfo("AlarmRecord",
|
||
|
|
$"报警记录已保存: {_storage.Records.Count} 条");
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
Debug.LogError($"[报警记录持久化] 保存失败: {ex.Message}");
|
||
|
|
|
||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
|
|
AndroidFileLogger.Instance?.LogError("AlarmRecord",
|
||
|
|
$"保存失败: {ex.Message}");
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从文件加载
|
||
|
|
/// </summary>
|
||
|
|
private void LoadFromFile()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (File.Exists(_alarmRecordsPath))
|
||
|
|
{
|
||
|
|
var json = File.ReadAllText(_alarmRecordsPath);
|
||
|
|
_storage = JsonMapper.ToObject<AlarmRecordStorage>(json);
|
||
|
|
|
||
|
|
Debug.Log($"[报警记录持久化] 加载成功: {_storage.Records.Count} 条记录");
|
||
|
|
|
||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
|
|
AndroidFileLogger.Instance?.LogInfo("AlarmRecord",
|
||
|
|
$"加载成功: {_storage.Records.Count} 条记录");
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
_storage = new AlarmRecordStorage();
|
||
|
|
Debug.Log("[报警记录持久化] 首次启动,创建新存储");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
Debug.LogError($"[报警记录持久化] 加载失败: {ex.Message}");
|
||
|
|
_storage = new AlarmRecordStorage();
|
||
|
|
|
||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
|
|
AndroidFileLogger.Instance?.LogError("AlarmRecord",
|
||
|
|
$"加载失败: {ex.Message}");
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取存储文件路径(用于调试)
|
||
|
|
/// </summary>
|
||
|
|
public string GetStoragePath()
|
||
|
|
{
|
||
|
|
return _alarmRecordsPath;
|
||
|
|
}
|
||
|
|
}
|