refactor: 插件窗体由 static 单例状态改为实例字段(对齐 TextViewer)

将 10 个 CycleGUI 窗体/管理器从进程级 static 单例状态改为实例字段 + 实例方法,
消除本地端/Web 端共享同一可变状态的隐患(对齐 TextViewer 正例)。

每个类保留一个 private static _instance 单实例持有者;静态入口 Open()/OpenViewer()
与实例 Show() 均转发到该实例,调用方零改动、单实例“置前”行为不变。

涉及:ChargeStationManagementForm、ChargeStrategyConfigForm、CommunicationMonitorForm、
AlarmConfigManagementForm、ButtonBoxManager、DoorManager、DoorMonitor、
LoopViewer、DeliveryViewer、TrafficInterlockViewer。

构建:dotnet build StandardScene.sln --no-incremental → 0 错误,30 警告(与基线一致,无新增)。
This commit is contained in:
zhaowei.huang
2026-06-26 15:31:02 +08:00
parent a0dc1e6cd0
commit 54cda958db
10 changed files with 297 additions and 257 deletions
@@ -14,28 +14,32 @@ namespace StandardScene.Charge
{
private const string TableId = "alarm-config-list";
private static readonly string[] LevelNames = { "无", "低", "中", "高", "严重" };
private static readonly string[] LevelFilterNames = { "全部", "无", "低", "中", "高", "严重" };
private readonly string[] LevelNames = { "无", "低", "中", "高", "严重" };
private readonly string[] LevelFilterNames = { "全部", "无", "低", "中", "高", "严重" };
private static readonly Color CriticalRowColor = Color.FromArgb(255, 235, 238);
private static readonly Color HighRowColor = Color.FromArgb(255, 243, 224);
private static readonly Color MediumRowColor = Color.FromArgb(255, 249, 196);
private static readonly Color LowRowColor = Color.FromArgb(232, 245, 233);
private static readonly Color DisabledRowColor = Color.FromArgb(238, 238, 238);
private readonly Color CriticalRowColor = Color.FromArgb(255, 235, 238);
private readonly Color HighRowColor = Color.FromArgb(255, 243, 224);
private readonly Color MediumRowColor = Color.FromArgb(255, 249, 196);
private readonly Color LowRowColor = Color.FromArgb(232, 245, 233);
private readonly Color DisabledRowColor = Color.FromArgb(238, 238, 238);
private static readonly AlarmConfigDataService DataService = AlarmConfigDataService.Instance;
private readonly AlarmConfigDataService DataService = AlarmConfigDataService.Instance;
private static Panel _panel;
private static Panel _dialog;
private static List<AlarmConfig> _allAlarms = new List<AlarmConfig>();
private static int _levelFilterIdx;
private static string _status = "";
private Panel _panel;
private Panel _dialog;
private List<AlarmConfig> _allAlarms = new List<AlarmConfig>();
private int _levelFilterIdx;
private string _status = "";
/// <summary>打开(或置前)报警配置管理面板。兼容原 <c>new AlarmConfigManagementForm().Show()</c> 调用方式。</summary>
public void Show() => Open();
/// <summary>打开(或置前)报警配置管理面板。</summary>
public static void Open()
public static void Open() => (_instance ??= new AlarmConfigManagementForm()).OpenCore();
private static AlarmConfigManagementForm _instance;
private void OpenCore()
{
if (_panel != null)
{
@@ -132,7 +136,7 @@ namespace StandardScene.Charge
});
}
private static void OpenEditDialog(AlarmConfig existing)
private void OpenEditDialog(AlarmConfig existing)
{
if (_dialog != null)
{
@@ -276,7 +280,7 @@ namespace StandardScene.Charge
});
}
private static void LoadAlarms()
private void LoadAlarms()
{
try
{
@@ -289,7 +293,7 @@ namespace StandardScene.Charge
}
}
private static List<AlarmConfig> GetFilteredAlarms()
private List<AlarmConfig> GetFilteredAlarms()
{
IEnumerable<AlarmConfig> query = _allAlarms;
if (_levelFilterIdx > 0)
@@ -297,7 +301,7 @@ namespace StandardScene.Charge
return query.ToList();
}
private static string GetStatisticsText()
private string GetStatisticsText()
{
var total = _allAlarms.Count;
var enabled = _allAlarms.Count(a => a.Enabled);
@@ -307,7 +311,7 @@ namespace StandardScene.Charge
return $"启用: {enabled} | 禁用: {disabled} | 严重: {critical} | 高级: {high}";
}
private static string GetLevelText(AlarmLevel level)
private string GetLevelText(AlarmLevel level)
{
switch (level)
{
@@ -18,29 +18,33 @@ namespace StandardScene.Charge
public class ChargeStationManagementForm
{
private const string TableId = "charge-station-list";
private static readonly string[] StatusFilterNames = { "全部状态", "空闲", "充电中", "故障", "离线" };
private static readonly string[] TypeNames = { "FRLD高款充电桩", "FRLD矮款充电桩", "牧星充电桩" };
private static readonly string[] MethodNames = { "地充", "尾充", "侧充" };
private static readonly string[] CarTypeNames = { "FRLD充电", "牧星充电桩充电" };
private readonly string[] StatusFilterNames = { "全部状态", "空闲", "充电中", "故障", "离线" };
private readonly string[] TypeNames = { "FRLD高款充电桩", "FRLD矮款充电桩", "牧星充电桩" };
private readonly string[] MethodNames = { "地充", "尾充", "侧充" };
private readonly string[] CarTypeNames = { "FRLD充电", "牧星充电桩充电" };
private static readonly ChargeStationDataService DataService = ChargeStationDataService.Instance;
private static readonly Ping Ping = new Ping();
private readonly ChargeStationDataService DataService = ChargeStationDataService.Instance;
private readonly Ping Ping = new Ping();
private static Panel _panel;
private static Panel _editDialog;
private static List<ChargeStation> _snapshot = new List<ChargeStation>();
private static volatile bool _refreshing;
private static DateTime _lastFlush = DateTime.MinValue;
private static readonly TimeSpan FlushInterval = TimeSpan.FromSeconds(3);
private Panel _panel;
private Panel _editDialog;
private List<ChargeStation> _snapshot = new List<ChargeStation>();
private volatile bool _refreshing;
private DateTime _lastFlush = DateTime.MinValue;
private readonly TimeSpan FlushInterval = TimeSpan.FromSeconds(3);
private static int _statusFilterIdx;
private static string _searchText = "";
private static string _statsText = "";
private static string _status = "";
private int _statusFilterIdx;
private string _searchText = "";
private string _statsText = "";
private string _status = "";
public void Show() => Open();
public static void Open()
public static void Open() => (_instance ??= new ChargeStationManagementForm()).OpenCore();
private static ChargeStationManagementForm _instance;
private void OpenCore()
{
if (_panel != null)
{
@@ -137,7 +141,7 @@ namespace StandardScene.Charge
});
}
private static void EnsureSnapshotFresh()
private void EnsureSnapshotFresh()
{
if (_refreshing) return;
if (DateTime.Now - _lastFlush < FlushInterval) return;
@@ -164,7 +168,7 @@ namespace StandardScene.Charge
});
}
private static List<ChargeStation> FilterSnapshot(List<ChargeStation> src)
private List<ChargeStation> FilterSnapshot(List<ChargeStation> src)
{
IEnumerable<ChargeStation> q = src;
if (_statusFilterIdx > 0)
@@ -183,7 +187,7 @@ namespace StandardScene.Charge
return q.ToList();
}
private static void UpdateStats(List<ChargeStation> all)
private void UpdateStats(List<ChargeStation> all)
{
_statsText = $"总数: {all.Count} | 空闲: {all.Count(s => s.Status == ChargeStationStatus.Idle)} | " +
$"充电中: {all.Count(s => s.Status == ChargeStationStatus.Charging)} | " +
@@ -191,7 +195,7 @@ namespace StandardScene.Charge
$"AGV电池已接入: {all.Count(s => s.Status == ChargeStationStatus.Battery)}";
}
private static void OpenEditDialog(ChargeStation existing)
private void OpenEditDialog(ChargeStation existing)
{
if (_editDialog != null)
{
@@ -296,7 +300,7 @@ namespace StandardScene.Charge
});
}
private static bool TryBuildStation(bool isAdd, ChargeStation existing, string stationId, string name,
private bool TryBuildStation(bool isAdd, ChargeStation existing, string stationId, string name,
int typeIdx, int methodIdx, int carTypeIdx, string ip, string port, string voltage, string current,
string siteIdText, string remarks, bool enabled, bool shield,
out ChargeStation station, out string err)
@@ -335,7 +339,7 @@ namespace StandardScene.Charge
return true;
}
private static void ConfirmDelete(ChargeStation station)
private void ConfirmDelete(ChargeStation station)
{
CycleUiHelper.ConfirmThen($"确定删除充电桩 [{station.StationId}] {station.Name}", () =>
{
@@ -359,7 +363,7 @@ namespace StandardScene.Charge
});
}
private static void ExportData(PanelBuilder pb)
private void ExportData(PanelBuilder pb)
{
if (!pb.SaveFile("导出充电桩", "*.json;*.csv", out var path) || string.IsNullOrEmpty(path)) return;
try
@@ -385,7 +389,7 @@ namespace StandardScene.Charge
catch (Exception ex) { CycleUiHelper.Alert("错误", $"导出失败: {ex.Message}"); }
}
private static void ApplyRowColor(PanelBuilder.Row row, ChargeStation s)
private void ApplyRowColor(PanelBuilder.Row row, ChargeStation s)
{
if (s.HasAlarm) row.SetColor(Color.FromArgb(255, 205, 210));
else if (s.Status == ChargeStationStatus.Idle) row.SetColor(Color.FromArgb(232, 245, 233));
@@ -394,7 +398,7 @@ namespace StandardScene.Charge
else if (s.Status == ChargeStationStatus.Battery) row.SetColor(Color.FromArgb(238, 238, 238));
}
private static ChargeStationStatus GetStatusFromFilterIndex(int idx) => idx switch
private ChargeStationStatus GetStatusFromFilterIndex(int idx) => idx switch
{
1 => ChargeStationStatus.Idle,
2 => ChargeStationStatus.Charging,
@@ -403,7 +407,7 @@ namespace StandardScene.Charge
_ => ChargeStationStatus.Idle
};
private static string GetStatusText(ChargeStationStatus status) => status switch
private string GetStatusText(ChargeStationStatus status) => status switch
{
ChargeStationStatus.Idle => "空闲",
ChargeStationStatus.Charging => "充电中",
@@ -412,7 +416,7 @@ namespace StandardScene.Charge
_ => "未知"
};
private static string GetTypeText(ChargeStationType type) => type switch
private string GetTypeText(ChargeStationType type) => type switch
{
ChargeStationType.FRLDTall => "FRLD高款充电桩",
ChargeStationType.FRLDShort => "FRLD矮款充电桩",
@@ -420,7 +424,7 @@ namespace StandardScene.Charge
_ => "未知"
};
private static string GetMethodText(ChargeMethodType m) => m switch
private string GetMethodText(ChargeMethodType m) => m switch
{
ChargeMethodType.Ground => "地充",
ChargeMethodType.Rear => "尾充",
@@ -428,7 +432,7 @@ namespace StandardScene.Charge
_ => "未知"
};
private static string FormatComm(CommunicationStatus s) => s switch
private string FormatComm(CommunicationStatus s) => s switch
{
CommunicationStatus.Normal => "✓ 正常",
CommunicationStatus.Delayed => "⚠ 延迟",
@@ -438,7 +442,7 @@ namespace StandardScene.Charge
_ => "? 未知"
};
private static string FormatMech(MechanismStatus s) => s switch
private string FormatMech(MechanismStatus s) => s switch
{
MechanismStatus.Extended => "◆ 伸出",
MechanismStatus.Retracted => "◇ 缩回",
@@ -446,7 +450,7 @@ namespace StandardScene.Charge
_ => "? 未知"
};
private static string FormatAlarm(ChargeStation s)
private string FormatAlarm(ChargeStation s)
{
if (!s.HasAlarm) return "正常";
return string.IsNullOrWhiteSpace(s.AlarmMessage) ? $"【{s.AlarmLevel}】" : s.AlarmMessage;
@@ -9,39 +9,43 @@ namespace StandardScene.Charge
/// </summary>
public class ChargeStrategyConfigForm
{
private static Panel _panel;
private static readonly ChargeStrategyConfigService ConfigService = ChargeStrategyConfigService.Instance;
private Panel _panel;
private readonly ChargeStrategyConfigService ConfigService = ChargeStrategyConfigService.Instance;
private static ChargeStrategyConfig _config;
private static string _status = "";
private ChargeStrategyConfig _config;
private string _status = "";
// SOC 参数
private static float _mustChargeSoc;
private static float _idleChargeSoc;
private static float _taskAvailableSoc;
private static float _fullChargeSoc;
private static float _allowInterruptSoc;
private float _mustChargeSoc;
private float _idleChargeSoc;
private float _taskAvailableSoc;
private float _fullChargeSoc;
private float _allowInterruptSoc;
// 时间参数
private static float _idleChargeSeconds;
private static float _idleSeconds;
private static float _mustChargeSeconds;
private static float _topUpMinutes;
private float _idleChargeSeconds;
private float _idleSeconds;
private float _mustChargeSeconds;
private float _topUpMinutes;
// 任务参数
private static int _minAllowFreeCarToChargeTaskCnt;
private int _minAllowFreeCarToChargeTaskCnt;
// 开关参数
private static bool _allowInterruptTask;
private static bool _useLowerSocForCharge;
private static bool _enableErrorChargeDetection;
private static bool _useChargeSiteFilter;
private bool _allowInterruptTask;
private bool _useLowerSocForCharge;
private bool _enableErrorChargeDetection;
private bool _useChargeSiteFilter;
/// <summary>打开(或置前)充电策略配置面板。兼容原 <c>new ChargeStrategyConfigForm().Show()</c> 调用方式。</summary>
public void Show() => Open();
/// <summary>打开(或置前)充电策略配置面板。</summary>
public static void Open()
public static void Open() => (_instance ??= new ChargeStrategyConfigForm()).OpenCore();
private static ChargeStrategyConfigForm _instance;
private void OpenCore()
{
if (_panel != null)
{
@@ -120,7 +124,7 @@ namespace StandardScene.Charge
});
}
private static bool TryLoadConfig()
private bool TryLoadConfig()
{
try
{
@@ -137,7 +141,7 @@ namespace StandardScene.Charge
}
}
private static void ApplyConfigToUi(ChargeStrategyConfig config)
private void ApplyConfigToUi(ChargeStrategyConfig config)
{
_mustChargeSoc = (float)config.MustChargeSoc;
_idleChargeSoc = (float)config.IdleChargeSoc;
@@ -158,7 +162,7 @@ namespace StandardScene.Charge
_useChargeSiteFilter = config.UseChargeSiteFilter;
}
private static void ApplyUiToConfig()
private void ApplyUiToConfig()
{
_config.MustChargeSoc = _mustChargeSoc;
_config.IdleChargeSoc = _idleChargeSoc;
@@ -180,7 +184,7 @@ namespace StandardScene.Charge
}
/// <summary>验证 SOC 阈值之间的逻辑关系(保存前)。</summary>
private static bool ValidateSocRanges(out string errorMessage)
private bool ValidateSocRanges(out string errorMessage)
{
if (_mustChargeSoc >= _idleChargeSoc)
{
@@ -210,7 +214,7 @@ namespace StandardScene.Charge
return true;
}
private static void TrySave(bool closeAfterSave)
private void TrySave(bool closeAfterSave)
{
ApplyUiToConfig();
@@ -245,7 +249,7 @@ namespace StandardScene.Charge
}
}
private static void RestoreDefaults()
private void RestoreDefaults()
{
CycleUiHelper.ConfirmThen("确定要恢复默认配置吗?当前配置将被覆盖。", () =>
{
@@ -24,33 +24,37 @@ namespace StandardScene.Charge
private const int StatsRefreshMs = 500;
private const string TableId = "comm-monitor-msgs";
private static readonly Color SendRowColor = Color.FromArgb(232, 245, 233);
private static readonly Color ReceiveRowColor = Color.FromArgb(227, 242, 253);
private static readonly Color SelectedRowColor = Color.FromArgb(255, 249, 196);
private readonly Color SendRowColor = Color.FromArgb(232, 245, 233);
private readonly Color ReceiveRowColor = Color.FromArgb(227, 242, 253);
private readonly Color SelectedRowColor = Color.FromArgb(255, 249, 196);
private static readonly CommunicationMessageService MessageService = CommunicationMessageService.Instance;
private readonly CommunicationMessageService MessageService = CommunicationMessageService.Instance;
private static Panel _panel;
private static bool _subscribed;
private static bool _paused;
private static int _selectedIpIndex;
private static string[] _ipOptions = { "全部" };
private static int _selectedRowIndex = -1;
private static string _parsedText = "";
private static string _statsText = "";
private Panel _panel;
private bool _subscribed;
private bool _paused;
private int _selectedIpIndex;
private string[] _ipOptions = { "全部" };
private int _selectedRowIndex = -1;
private string _parsedText = "";
private string _statsText = "";
private static List<CommunicationMessage> _displayMessages = new List<CommunicationMessage>();
private static readonly Queue<CommunicationMessage> PendingMessages = new Queue<CommunicationMessage>();
private static readonly object PendingLock = new object();
private List<CommunicationMessage> _displayMessages = new List<CommunicationMessage>();
private readonly Queue<CommunicationMessage> PendingMessages = new Queue<CommunicationMessage>();
private readonly object PendingLock = new object();
private static DateTime _lastStatsRefresh = DateTime.MinValue;
private static bool _pendingStatsRefresh;
private DateTime _lastStatsRefresh = DateTime.MinValue;
private bool _pendingStatsRefresh;
/// <summary>打开(或置前)通讯监控面板。兼容原 <c>new CommunicationMonitorForm().Show()</c> 调用方式。</summary>
public void Show() => Open();
/// <summary>打开(或置前)通讯监控面板。</summary>
public static void Open()
public static void Open() => (_instance ??= new CommunicationMonitorForm()).OpenCore();
private static CommunicationMonitorForm _instance;
private void OpenCore()
{
if (_panel != null)
{
@@ -169,7 +173,7 @@ namespace StandardScene.Charge
});
}
private static void Subscribe()
private void Subscribe()
{
if (_subscribed)
return;
@@ -177,7 +181,7 @@ namespace StandardScene.Charge
_subscribed = true;
}
private static void Unsubscribe()
private void Unsubscribe()
{
if (!_subscribed)
return;
@@ -187,7 +191,7 @@ namespace StandardScene.Charge
PendingMessages.Clear();
}
private static void OnMessageAdded(object sender, CommunicationMessage message)
private void OnMessageAdded(object sender, CommunicationMessage message)
{
if (!_subscribed || message == null)
return;
@@ -199,7 +203,7 @@ namespace StandardScene.Charge
}
/// <summary>定时批量刷新 UI,避免每条报文都抢占渲染线程。</summary>
private static void FlushPendingBatch()
private void FlushPendingBatch()
{
if (_paused)
return;
@@ -236,7 +240,7 @@ namespace StandardScene.Charge
RequestStatisticsRefresh();
}
private static void InsertMessageAtTop(CommunicationMessage msg)
private void InsertMessageAtTop(CommunicationMessage msg)
{
_displayMessages.Insert(0, msg);
while (_displayMessages.Count > MaxDisplayRows)
@@ -246,7 +250,7 @@ namespace StandardScene.Charge
_selectedRowIndex++;
}
private static void ReloadFromService()
private void ReloadFromService()
{
try
{
@@ -267,7 +271,7 @@ namespace StandardScene.Charge
}
}
private static void RefreshIpFilter()
private void RefreshIpFilter()
{
try
{
@@ -302,7 +306,7 @@ namespace StandardScene.Charge
}
}
private static void EnsureIpInFilter(string ipAddress)
private void EnsureIpInFilter(string ipAddress)
{
if (string.IsNullOrWhiteSpace(ipAddress))
return;
@@ -315,7 +319,7 @@ namespace StandardScene.Charge
_ipOptions = list.ToArray();
}
private static string SelectedIpFilter()
private string SelectedIpFilter()
{
if (_ipOptions == null || _ipOptions.Length == 0)
return "全部";
@@ -324,13 +328,13 @@ namespace StandardScene.Charge
return _ipOptions[_selectedIpIndex];
}
private static void RequestStatisticsRefresh()
private void RequestStatisticsRefresh()
{
_pendingStatsRefresh = true;
}
/// <summary>统计信息低频刷新(500ms)。</summary>
private static void MaybeRefreshStatistics()
private void MaybeRefreshStatistics()
{
if (!_pendingStatsRefresh)
return;
@@ -342,7 +346,7 @@ namespace StandardScene.Charge
UpdateStatistics(_displayMessages.Count);
}
private static void UpdateStatistics(int displayCount)
private void UpdateStatistics(int displayCount)
{
try
{
@@ -364,14 +368,14 @@ namespace StandardScene.Charge
}
}
private static string TruncateRawData(string rawData, int maxLen = 48)
private string TruncateRawData(string rawData, int maxLen = 48)
{
if (string.IsNullOrEmpty(rawData))
return "";
return rawData.Length <= maxLen ? rawData : rawData.Substring(0, maxLen) + "…";
}
private static string BuildParsedText(CommunicationMessage message)
private string BuildParsedText(CommunicationMessage message)
{
if (message == null)
return "";