前言
上篇介绍了用户管理界面部分的内容,这篇就开始说一说关于报警处理和报警界面相关的内容。报警是一台上位机软件中最重要的部分,设备出现故障时必须要准确报警,才能即使处理,确保生产正常进行。我这边这次用
功能介绍
我在框架中将报警内容分为三个部分。
1、实时报警触发和显示,
当报警触发时,在界面右上角逐行悬浮显示。可以通过右键点击来清除当前报警。2、历史报警显示,
软件启动后发生的所有报警都会被完整记录在内存队列中,同时可以通过时间筛选,可以用于后续故障追溯与数据分析。3、报警注册。
所有报警代码与中文释义统一在此处进行注册。所有的报警统一在报警注册界面中进行注册,如果报警触发时没有对应的报警代码,自动注册一个模板报警,然后手动再去修改内容即可。实时报警在右上角开始逐行显示,可以通过右击清除报警。
当前我只是完成了报警触发和显示部分的内容,还没有融入到状态机里面,这个后面做流程界面的时候再一起开发。下面是已经完成的三部分内容的界面显示。
代码实现
报警实体类
首先还是报警的实体类,包含报警代码,报警内容以及报警时间,注册报警也用的同一个类,后面的时间在注册时实际就是报警注册的时间,不过我在报警注册界面是没有显示时间的,但是config文件中会有体现。
public class AlarmItem{public string AlarmCode { get; set; }public string Content { get; set; }public DateTime Time { get; set; }}
报警仓储
之前做了关于数据库的仓储模式,包含了用户,产量等操作,后面做的时候,把配置文件也做成了仓储模式,这样会方便很多。
报警仓储中,包含了两个集合,分别是当前报警和注册报警。
public ObservableCollection<AlarmItem> ActuralAlarmList { get; private set; }public ObservableCollection<AlarmItem> RegisteredAlarms { get; private set; }
当前报警是实时更新的,注册报警则需要从配置文件中读取加载。
publicAlarmRepository(IConfigManagerFactory configManagerFactory, IEventAggregator eventAggregator, ILoggerFactory loggerFactory){_alarmConfigManager = configManagerFactory.CreateConfigManager(ConfigType.json, "alarm_config", "Alarm");_eventAggregator = eventAggregator;_logger = loggerFactory.CreateLogger("Alarms");ActuralAlarmList = new ObservableCollection<AlarmItem>();HistoryAlarms = new ObservableCollection<AlarmItem>();Restore();}publicvoidRestore(){RegisteredAlarms = new ObservableCollection<AlarmItem>(_alarmConfigManager.LoadConfig<List<AlarmItem>>());}
同时保存注册的报警内容也是放在仓储中,直接保存即可。
publicvoidRegisterAlarm(){_alarmConfigManager.SaveConfig(RegisteredAlarms);}
报警触发则是包含了判断是否注册,是否存在报警,以及日志记录、弹窗显示和发布报警。报警清除就是直接清空当前报警集合,同时发布清除报警事件。
publicvoidClearAlarm(string alarmCode){ActuralAlarmList.Remove(ActuralAlarmList.FirstOrDefault(x => x.AlarmCode == alarmCode));_eventAggregator.GetEvent<AlarmClearedEvent>().Publish();}publicvoidAlarm(string alarmCode){AlarmItem alarmItem;var now = DateTime.Now;var alarmitems = RegisteredAlarms.Where(x => x.AlarmCode == alarmCode).ToList();if (alarmitems.Count() >= 1){var config = alarmitems[0];alarmItem = new AlarmItem(){AlarmCode = config.AlarmCode,Content = config.Content,Time = now};}else{alarmItem = new AlarmItem(){AlarmCode = alarmCode,Content = "非手动注册报警,请确认代码,或者前往报警注册界面修改本内容!",Time = now};RegisterAlarm();RegisteredAlarms.Add(alarmItem);}if (!ActuralAlarmList.Contains(alarmItem)){ActuralAlarmList.Insert(0, alarmItem);string logMsg = $"- {alarmCode} - {alarmItem.Content}";_logger.Warn(logMsg);Growl.Error(new GrowlInfo{Message = $"{alarmCode} - {alarmItem.Content}",ActionBeforeClose = isConfirmed =>{ClearAlarm(alarmCode);return true;}});_eventAggregator.GetEvent<AlarmOccurredEvent>().Publish(alarmItem);}}
界面显示
界面分为历史报警和报警注册两项。
历史报警主要用来显示软件开启后出现过的所有报警内容,同时包含按照时间段筛选的功能。主要的代码功能一个是订阅报警,同时把报警添加到历史报警中,还有一个就是执行筛选。
publicAlarmHistoryViewModel(IEventAggregator eventAggregator){_eventAggregator = eventAggregator;_eventAggregator.GetEvent<AlarmOccurredEvent>().Subscribe(x =>{_historyAlarmList.Add(x);DisplayAlarmList = IsFiltered ?new ObservableCollection<AlarmItem>(_historyAlarmList.Where(a => a.Time > StartTime && a.Time < EndTime).ToList()) :_historyAlarmList;}, ThreadOption.UIThread);FilterCommand = new DelegateCommand(ExcuteFilter);}privatevoidExcuteFilter(){IsFiltered = !IsFiltered;DisplayAlarmList = IsFiltered ?new ObservableCollection<AlarmItem>(_historyAlarmList.Where(a => a.Time > StartTime && a.Time < EndTime).ToList()) :_historyAlarmList;}
报警注册主要包含了添加删除保存等操作,我还预留了导出导入功能,后续有时间再做。
publicAlarmRegisterViewModel(IAlarmRepository alarmRepository){_alarmRepository = alarmRepository;RegisteredAlarms = _alarmRepository.RegisteredAlarms;AddAlarmCommand = new DelegateCommand(ExcuteAddAlarm);DeleteAlarmCommand = new DelegateCommand(ExcuteDeleteAlarm);SaveCommand = new DelegateCommand(ExcuteSave);RestoreCommand = new DelegateCommand(ExcuteRestore);ImportCommand = new DelegateCommand(ExcuteImport);ExportCommand = new DelegateCommand(ExcuteExport);}privatevoidExcuteAddAlarm(){RegisteredAlarms.Insert(0, new AlarmItem());}privatevoidExcuteDeleteAlarm(){RegisteredAlarms.Remove(SelectedAlarm);}privatevoidExcuteSave(){var emptyItems = RegisteredAlarms.Where(x => x == null || string.IsNullOrWhiteSpace(x.AlarmCode)).ToList();foreach (var item in emptyItems){RegisteredAlarms.Remove(item);}_alarmRepository.RegisterAlarm();Growl.Success($"保存报警注册成功!");}privatevoidExcuteRestore(){_alarmRepository.Restore();RegisteredAlarms = _alarmRepository.RegisteredAlarms;}
事件
报警部分实现了两个事件,一个是清除报警,一个是报警触发,当前还没有融合到状态机中,这部分后续再继续完成。
public classAlarmClearedEvent : PubSubEvent{}_eventAggregator.GetEvent<AlarmClearedEvent>().Publish();public classAlarmOccurredEvent : PubSubEvent<AlarmItem>{}_eventAggregator.GetEvent<AlarmOccurredEvent>().Publish(alarmItem);_eventAggregator.GetEvent<AlarmOccurredEvent>().Subscribe(x =>{_historyAlarmList.Add(x);DisplayAlarmList = IsFiltered ?new ObservableCollection<AlarmItem>(_historyAlarmList.Where(a => a.Time > StartTime && a.Time < EndTime).ToList()) :_historyAlarmList;}, ThreadOption.UIThread);
后记
以上就是报警管理部分的全部内容了,下面应该会继续完善这部分关于状态机部分的内容,同时完成剩下的界面开发。
所有的代码都存放再Github中,欢迎大家前往Star、Fork、提Issue。所有文章都发布在专栏里,有需要看前期内容和后续更新的欢迎点击订阅。
如果大家在配置或者理解上有什么疑问,或者因为网络原因无法畅快访问 GitHub,可以直接在我的微信公众号后台私信我获取全套源码离线包。
https://github.com/JeffreyXXL/Sophon
夜雨聆风