refactor: 插件 UI 从 WinForms 迁移到 CycleGUI,并修复代码质量问题

将 StandardScene 各插件的配置/监控窗体从 WinForms 迁移到 CycleGUI(删除 .Designer.cs/.resx,重写为 PanelBuilder 立即模式 UI,新增 CycleUiHelper 统一对话框)。

同时修复代码审核中的问题:
- 后台文件写入加锁 + try/catch(ButtonBoxManager / DoorManager,对齐 LoopViewer.SaveTasks 模式)
- CoderFieldsMetadata.cs 启用 #nullable enable,消除 CS8632 警告
- DummyCar 移除已废弃的 rightClickAction()/SetPosition()
- CarRemoteHelper.OpenVehicleWebPage 的 Process.Start 加 try/catch
- 重命名名不副实的 Mstsc()(现为打开网页)
- 统一弃元命名为 _
- TrafficInterlockViewer 改用稳定 Id(GUID)做选择/编辑,替代行索引
- csproj 改用 $(CGUILibDir) 解析 CycleGUI,绝对路径收敛到 Directory.Build.props

构建:dotnet build StandardScene.sln → 0 错误,30 警告(均为历史遗留)。
注:static 单例状态重构(审核第 8 项)暂未处理,留待单独任务。
This commit is contained in:
zhaowei.huang
2026-06-26 15:00:53 +08:00
parent c8e540d272
commit a0dc1e6cd0
91 changed files with 3946 additions and 15419 deletions
@@ -1,596 +0,0 @@
namespace StandardScene.Charge
{
partial class AlarmConfigManagementForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle();
this.splitContainer = new System.Windows.Forms.SplitContainer();
this.pnlList = new System.Windows.Forms.Panel();
this.dgvAlarmConfigs = new System.Windows.Forms.DataGridView();
this.pnlListButtons = new System.Windows.Forms.Panel();
this.lblStatistics = new System.Windows.Forms.Label();
this.btnClose = new System.Windows.Forms.Button();
this.btnRefresh = new System.Windows.Forms.Button();
this.pnlSearch = new System.Windows.Forms.Panel();
this.cmbLevelFilter = new System.Windows.Forms.ComboBox();
this.lblLevelFilter = new System.Windows.Forms.Label();
this.txtSearch = new System.Windows.Forms.TextBox();
this.lblSearch = new System.Windows.Forms.Label();
this.pnlEdit = new System.Windows.Forms.Panel();
this.grpEditInfo = new System.Windows.Forms.GroupBox();
this.txtRemarks = new System.Windows.Forms.TextBox();
this.lblRemarks = new System.Windows.Forms.Label();
this.chkEnabled = new System.Windows.Forms.CheckBox();
this.cmbLevel = new System.Windows.Forms.ComboBox();
this.lblLevel = new System.Windows.Forms.Label();
this.txtAlarmContent = new System.Windows.Forms.TextBox();
this.lblAlarmContent = new System.Windows.Forms.Label();
this.numAlarmCode = new System.Windows.Forms.NumericUpDown();
this.lblAlarmCode = new System.Windows.Forms.Label();
this.txtAlarmId = new System.Windows.Forms.TextBox();
this.lblAlarmId = new System.Windows.Forms.Label();
this.pnlEditButtons = new System.Windows.Forms.Panel();
this.btnCancel = new System.Windows.Forms.Button();
this.btnDelete = new System.Windows.Forms.Button();
this.btnSave = new System.Windows.Forms.Button();
this.colAlarmId = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colAlarmCode = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colAlarmContent = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colLevel = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colEnabled = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colRemarks = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout();
this.splitContainer.Panel2.SuspendLayout();
this.splitContainer.SuspendLayout();
this.pnlList.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dgvAlarmConfigs)).BeginInit();
this.pnlListButtons.SuspendLayout();
this.pnlSearch.SuspendLayout();
this.pnlEdit.SuspendLayout();
this.grpEditInfo.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.numAlarmCode)).BeginInit();
this.pnlEditButtons.SuspendLayout();
this.SuspendLayout();
//
// splitContainer
//
this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer.Location = new System.Drawing.Point(0, 0);
this.splitContainer.Margin = new System.Windows.Forms.Padding(4);
this.splitContainer.Name = "splitContainer";
//
// splitContainer.Panel1
//
this.splitContainer.Panel1.Controls.Add(this.pnlList);
//
// splitContainer.Panel2
//
this.splitContainer.Panel2.Controls.Add(this.pnlEdit);
this.splitContainer.Size = new System.Drawing.Size(1400, 750);
this.splitContainer.SplitterDistance = 900;
this.splitContainer.SplitterWidth = 5;
this.splitContainer.TabIndex = 0;
//
// pnlList
//
this.pnlList.Controls.Add(this.dgvAlarmConfigs);
this.pnlList.Controls.Add(this.pnlListButtons);
this.pnlList.Controls.Add(this.pnlSearch);
this.pnlList.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlList.Location = new System.Drawing.Point(0, 0);
this.pnlList.Margin = new System.Windows.Forms.Padding(4);
this.pnlList.Name = "pnlList";
this.pnlList.Size = new System.Drawing.Size(900, 750);
this.pnlList.TabIndex = 0;
//
// dgvAlarmConfigs
//
this.dgvAlarmConfigs.AllowUserToAddRows = false;
this.dgvAlarmConfigs.AllowUserToDeleteRows = false;
this.dgvAlarmConfigs.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dgvAlarmConfigs.BackgroundColor = System.Drawing.Color.White;
this.dgvAlarmConfigs.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.dgvAlarmConfigs.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleHorizontal;
dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(63)))), ((int)(((byte)(81)))), ((int)(((byte)(181)))));
dataGridViewCellStyle3.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
dataGridViewCellStyle3.ForeColor = System.Drawing.Color.White;
dataGridViewCellStyle3.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(63)))), ((int)(((byte)(81)))), ((int)(((byte)(181)))));
dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dgvAlarmConfigs.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle3;
this.dgvAlarmConfigs.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dgvAlarmConfigs.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.colAlarmId,
this.colAlarmCode,
this.colAlarmContent,
this.colLevel,
this.colEnabled,
this.colRemarks});
dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle4.BackColor = System.Drawing.Color.White;
dataGridViewCellStyle4.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
dataGridViewCellStyle4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
dataGridViewCellStyle4.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(197)))), ((int)(((byte)(202)))), ((int)(((byte)(233)))));
dataGridViewCellStyle4.SelectionForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(33)))), ((int)(((byte)(33)))), ((int)(((byte)(33)))));
dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
this.dgvAlarmConfigs.DefaultCellStyle = dataGridViewCellStyle4;
this.dgvAlarmConfigs.Dock = System.Windows.Forms.DockStyle.Fill;
this.dgvAlarmConfigs.EnableHeadersVisualStyles = false;
this.dgvAlarmConfigs.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this.dgvAlarmConfigs.Location = new System.Drawing.Point(0, 62);
this.dgvAlarmConfigs.Margin = new System.Windows.Forms.Padding(4);
this.dgvAlarmConfigs.MultiSelect = false;
this.dgvAlarmConfigs.Name = "dgvAlarmConfigs";
this.dgvAlarmConfigs.ReadOnly = true;
this.dgvAlarmConfigs.RowHeadersVisible = false;
this.dgvAlarmConfigs.RowHeadersWidth = 30;
this.dgvAlarmConfigs.RowTemplate.Height = 35;
this.dgvAlarmConfigs.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.dgvAlarmConfigs.Size = new System.Drawing.Size(900, 600);
this.dgvAlarmConfigs.TabIndex = 2;
this.dgvAlarmConfigs.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dgvAlarmConfigs_CellDoubleClick);
//
// pnlListButtons
//
this.pnlListButtons.Controls.Add(this.lblStatistics);
this.pnlListButtons.Controls.Add(this.btnClose);
this.pnlListButtons.Controls.Add(this.btnRefresh);
this.pnlListButtons.Dock = System.Windows.Forms.DockStyle.Bottom;
this.pnlListButtons.Location = new System.Drawing.Point(0, 662);
this.pnlListButtons.Margin = new System.Windows.Forms.Padding(4);
this.pnlListButtons.Name = "pnlListButtons";
this.pnlListButtons.Padding = new System.Windows.Forms.Padding(13, 12, 13, 12);
this.pnlListButtons.Size = new System.Drawing.Size(900, 88);
this.pnlListButtons.TabIndex = 1;
//
// lblStatistics
//
this.lblStatistics.AutoSize = true;
this.lblStatistics.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblStatistics.Location = new System.Drawing.Point(20, 31);
this.lblStatistics.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblStatistics.Name = "lblStatistics";
this.lblStatistics.Size = new System.Drawing.Size(204, 24);
this.lblStatistics.TabIndex = 2;
this.lblStatistics.Text = "总数: 0 | 启用: 0 | 禁用: 0";
//
// btnClose
//
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnClose.Location = new System.Drawing.Point(753, 19);
this.btnClose.Margin = new System.Windows.Forms.Padding(4);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(120, 50);
this.btnClose.TabIndex = 1;
this.btnClose.Text = "关闭";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// btnRefresh
//
this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnRefresh.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnRefresh.Location = new System.Drawing.Point(620, 19);
this.btnRefresh.Margin = new System.Windows.Forms.Padding(4);
this.btnRefresh.Name = "btnRefresh";
this.btnRefresh.Size = new System.Drawing.Size(120, 50);
this.btnRefresh.TabIndex = 0;
this.btnRefresh.Text = "刷新";
this.btnRefresh.UseVisualStyleBackColor = true;
this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
//
// pnlSearch
//
this.pnlSearch.Controls.Add(this.cmbLevelFilter);
this.pnlSearch.Controls.Add(this.lblLevelFilter);
this.pnlSearch.Controls.Add(this.txtSearch);
this.pnlSearch.Controls.Add(this.lblSearch);
this.pnlSearch.Dock = System.Windows.Forms.DockStyle.Top;
this.pnlSearch.Location = new System.Drawing.Point(0, 0);
this.pnlSearch.Margin = new System.Windows.Forms.Padding(4);
this.pnlSearch.Name = "pnlSearch";
this.pnlSearch.Padding = new System.Windows.Forms.Padding(13, 12, 13, 12);
this.pnlSearch.Size = new System.Drawing.Size(900, 62);
this.pnlSearch.TabIndex = 0;
//
// cmbLevelFilter
//
this.cmbLevelFilter.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbLevelFilter.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.cmbLevelFilter.FormattingEnabled = true;
this.cmbLevelFilter.Location = new System.Drawing.Point(550, 16);
this.cmbLevelFilter.Margin = new System.Windows.Forms.Padding(4);
this.cmbLevelFilter.Name = "cmbLevelFilter";
this.cmbLevelFilter.Size = new System.Drawing.Size(150, 31);
this.cmbLevelFilter.TabIndex = 3;
this.cmbLevelFilter.SelectedIndexChanged += new System.EventHandler(this.cmbLevelFilter_SelectedIndexChanged);
//
// lblLevelFilter
//
this.lblLevelFilter.AutoSize = true;
this.lblLevelFilter.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblLevelFilter.Location = new System.Drawing.Point(463, 21);
this.lblLevelFilter.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblLevelFilter.Name = "lblLevelFilter";
this.lblLevelFilter.Size = new System.Drawing.Size(61, 23);
this.lblLevelFilter.TabIndex = 2;
this.lblLevelFilter.Text = "级别:";
//
// txtSearch
//
this.txtSearch.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.txtSearch.Location = new System.Drawing.Point(100, 16);
this.txtSearch.Margin = new System.Windows.Forms.Padding(4);
this.txtSearch.Name = "txtSearch";
this.txtSearch.Size = new System.Drawing.Size(300, 29);
this.txtSearch.TabIndex = 1;
this.txtSearch.TextChanged += new System.EventHandler(this.txtSearch_TextChanged);
//
// lblSearch
//
this.lblSearch.AutoSize = true;
this.lblSearch.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblSearch.Location = new System.Drawing.Point(13, 21);
this.lblSearch.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblSearch.Name = "lblSearch";
this.lblSearch.Size = new System.Drawing.Size(61, 23);
this.lblSearch.TabIndex = 0;
this.lblSearch.Text = "搜索:";
//
// pnlEdit
//
this.pnlEdit.Controls.Add(this.grpEditInfo);
this.pnlEdit.Controls.Add(this.pnlEditButtons);
this.pnlEdit.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlEdit.Location = new System.Drawing.Point(0, 0);
this.pnlEdit.Margin = new System.Windows.Forms.Padding(4);
this.pnlEdit.Name = "pnlEdit";
this.pnlEdit.Size = new System.Drawing.Size(495, 750);
this.pnlEdit.TabIndex = 0;
//
// grpEditInfo
//
this.grpEditInfo.Controls.Add(this.txtRemarks);
this.grpEditInfo.Controls.Add(this.lblRemarks);
this.grpEditInfo.Controls.Add(this.chkEnabled);
this.grpEditInfo.Controls.Add(this.cmbLevel);
this.grpEditInfo.Controls.Add(this.lblLevel);
this.grpEditInfo.Controls.Add(this.txtAlarmContent);
this.grpEditInfo.Controls.Add(this.lblAlarmContent);
this.grpEditInfo.Controls.Add(this.numAlarmCode);
this.grpEditInfo.Controls.Add(this.lblAlarmCode);
this.grpEditInfo.Controls.Add(this.txtAlarmId);
this.grpEditInfo.Controls.Add(this.lblAlarmId);
this.grpEditInfo.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpEditInfo.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.grpEditInfo.Location = new System.Drawing.Point(0, 0);
this.grpEditInfo.Margin = new System.Windows.Forms.Padding(4);
this.grpEditInfo.Name = "grpEditInfo";
this.grpEditInfo.Padding = new System.Windows.Forms.Padding(20, 19, 20, 19);
this.grpEditInfo.Size = new System.Drawing.Size(495, 625);
this.grpEditInfo.TabIndex = 1;
this.grpEditInfo.TabStop = false;
this.grpEditInfo.Text = "报警配置信息";
//
// txtRemarks
//
this.txtRemarks.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.txtRemarks.Location = new System.Drawing.Point(130, 350);
this.txtRemarks.Margin = new System.Windows.Forms.Padding(4);
this.txtRemarks.Multiline = true;
this.txtRemarks.Name = "txtRemarks";
this.txtRemarks.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.txtRemarks.Size = new System.Drawing.Size(330, 80);
this.txtRemarks.TabIndex = 10;
//
// lblRemarks
//
this.lblRemarks.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblRemarks.Location = new System.Drawing.Point(27, 350);
this.lblRemarks.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblRemarks.Name = "lblRemarks";
this.lblRemarks.Size = new System.Drawing.Size(100, 31);
this.lblRemarks.TabIndex = 9;
this.lblRemarks.Text = "备注:";
this.lblRemarks.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// chkEnabled
//
this.chkEnabled.AutoSize = true;
this.chkEnabled.Checked = true;
this.chkEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkEnabled.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.chkEnabled.Location = new System.Drawing.Point(130, 300);
this.chkEnabled.Margin = new System.Windows.Forms.Padding(4);
this.chkEnabled.Name = "chkEnabled";
this.chkEnabled.Size = new System.Drawing.Size(83, 27);
this.chkEnabled.TabIndex = 8;
this.chkEnabled.Text = "启用中";
this.chkEnabled.UseVisualStyleBackColor = true;
this.chkEnabled.Visible = false;
//
// cmbLevel
//
this.cmbLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbLevel.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.cmbLevel.FormattingEnabled = true;
this.cmbLevel.Location = new System.Drawing.Point(130, 244);
this.cmbLevel.Margin = new System.Windows.Forms.Padding(4);
this.cmbLevel.Name = "cmbLevel";
this.cmbLevel.Size = new System.Drawing.Size(330, 31);
this.cmbLevel.TabIndex = 7;
//
// lblLevel
//
this.lblLevel.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblLevel.Location = new System.Drawing.Point(27, 244);
this.lblLevel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblLevel.Name = "lblLevel";
this.lblLevel.Size = new System.Drawing.Size(100, 31);
this.lblLevel.TabIndex = 6;
this.lblLevel.Text = "报警级别:";
this.lblLevel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txtAlarmContent
//
this.txtAlarmContent.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.txtAlarmContent.Location = new System.Drawing.Point(130, 181);
this.txtAlarmContent.Margin = new System.Windows.Forms.Padding(4);
this.txtAlarmContent.Multiline = true;
this.txtAlarmContent.Name = "txtAlarmContent";
this.txtAlarmContent.Size = new System.Drawing.Size(330, 50);
this.txtAlarmContent.TabIndex = 5;
//
// lblAlarmContent
//
this.lblAlarmContent.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblAlarmContent.Location = new System.Drawing.Point(27, 181);
this.lblAlarmContent.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblAlarmContent.Name = "lblAlarmContent";
this.lblAlarmContent.Size = new System.Drawing.Size(100, 31);
this.lblAlarmContent.TabIndex = 4;
this.lblAlarmContent.Text = "报警内容:";
this.lblAlarmContent.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// numAlarmCode
//
this.numAlarmCode.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.numAlarmCode.Location = new System.Drawing.Point(130, 119);
this.numAlarmCode.Margin = new System.Windows.Forms.Padding(4);
this.numAlarmCode.Maximum = new decimal(new int[] {
99999,
0,
0,
0});
this.numAlarmCode.Name = "numAlarmCode";
this.numAlarmCode.Size = new System.Drawing.Size(330, 29);
this.numAlarmCode.TabIndex = 3;
//
// lblAlarmCode
//
this.lblAlarmCode.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblAlarmCode.Location = new System.Drawing.Point(27, 119);
this.lblAlarmCode.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblAlarmCode.Name = "lblAlarmCode";
this.lblAlarmCode.Size = new System.Drawing.Size(100, 31);
this.lblAlarmCode.TabIndex = 2;
this.lblAlarmCode.Text = "报警编码:";
this.lblAlarmCode.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txtAlarmId
//
this.txtAlarmId.BackColor = System.Drawing.Color.LightGray;
this.txtAlarmId.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.txtAlarmId.Location = new System.Drawing.Point(130, 56);
this.txtAlarmId.Margin = new System.Windows.Forms.Padding(4);
this.txtAlarmId.Name = "txtAlarmId";
this.txtAlarmId.ReadOnly = true;
this.txtAlarmId.Size = new System.Drawing.Size(330, 27);
this.txtAlarmId.TabIndex = 1;
this.txtAlarmId.Visible = false;
//
// lblAlarmId
//
this.lblAlarmId.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblAlarmId.Location = new System.Drawing.Point(27, 56);
this.lblAlarmId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblAlarmId.Name = "lblAlarmId";
this.lblAlarmId.Size = new System.Drawing.Size(100, 31);
this.lblAlarmId.TabIndex = 0;
this.lblAlarmId.Text = "编号:";
this.lblAlarmId.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.lblAlarmId.Visible = false;
//
// pnlEditButtons
//
this.pnlEditButtons.Controls.Add(this.btnCancel);
this.pnlEditButtons.Controls.Add(this.btnDelete);
this.pnlEditButtons.Controls.Add(this.btnSave);
this.pnlEditButtons.Dock = System.Windows.Forms.DockStyle.Bottom;
this.pnlEditButtons.Location = new System.Drawing.Point(0, 625);
this.pnlEditButtons.Margin = new System.Windows.Forms.Padding(4);
this.pnlEditButtons.Name = "pnlEditButtons";
this.pnlEditButtons.Padding = new System.Windows.Forms.Padding(13, 12, 13, 12);
this.pnlEditButtons.Size = new System.Drawing.Size(495, 125);
this.pnlEditButtons.TabIndex = 0;
//
// btnCancel
//
this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnCancel.Location = new System.Drawing.Point(333, 25);
this.btnCancel.Margin = new System.Windows.Forms.Padding(4);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(133, 62);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "取消";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnDelete
//
this.btnDelete.BackColor = System.Drawing.Color.LightCoral;
this.btnDelete.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnDelete.Location = new System.Drawing.Point(180, 25);
this.btnDelete.Margin = new System.Windows.Forms.Padding(4);
this.btnDelete.Name = "btnDelete";
this.btnDelete.Size = new System.Drawing.Size(133, 62);
this.btnDelete.TabIndex = 1;
this.btnDelete.Text = "删除";
this.btnDelete.UseVisualStyleBackColor = false;
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
//
// btnSave
//
this.btnSave.BackColor = System.Drawing.Color.LightBlue;
this.btnSave.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnSave.Location = new System.Drawing.Point(27, 25);
this.btnSave.Margin = new System.Windows.Forms.Padding(4);
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(133, 62);
this.btnSave.TabIndex = 0;
this.btnSave.Text = "新增";
this.btnSave.UseVisualStyleBackColor = false;
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// colAlarmId
//
this.colAlarmId.HeaderText = "编号";
this.colAlarmId.MinimumWidth = 6;
this.colAlarmId.Name = "colAlarmId";
this.colAlarmId.ReadOnly = true;
this.colAlarmId.Visible = false;
//
// colAlarmCode
//
this.colAlarmCode.HeaderText = "报警编码";
this.colAlarmCode.MinimumWidth = 6;
this.colAlarmCode.Name = "colAlarmCode";
this.colAlarmCode.ReadOnly = true;
//
// colAlarmContent
//
this.colAlarmContent.HeaderText = "报警内容";
this.colAlarmContent.MinimumWidth = 6;
this.colAlarmContent.Name = "colAlarmContent";
this.colAlarmContent.ReadOnly = true;
//
// colLevel
//
this.colLevel.HeaderText = "级别";
this.colLevel.MinimumWidth = 6;
this.colLevel.Name = "colLevel";
this.colLevel.ReadOnly = true;
//
// colEnabled
//
this.colEnabled.HeaderText = "启用";
this.colEnabled.MinimumWidth = 6;
this.colEnabled.Name = "colEnabled";
this.colEnabled.ReadOnly = true;
//
// colRemarks
//
this.colRemarks.HeaderText = "备注";
this.colRemarks.MinimumWidth = 6;
this.colRemarks.Name = "colRemarks";
this.colRemarks.ReadOnly = true;
//
// AlarmConfigManagementForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1400, 750);
this.Controls.Add(this.splitContainer);
this.Margin = new System.Windows.Forms.Padding(4);
this.MinimumSize = new System.Drawing.Size(1200, 600);
this.Name = "AlarmConfigManagementForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "报警配置管理";
this.splitContainer.Panel1.ResumeLayout(false);
this.splitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
this.splitContainer.ResumeLayout(false);
this.pnlList.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.dgvAlarmConfigs)).EndInit();
this.pnlListButtons.ResumeLayout(false);
this.pnlListButtons.PerformLayout();
this.pnlSearch.ResumeLayout(false);
this.pnlSearch.PerformLayout();
this.pnlEdit.ResumeLayout(false);
this.grpEditInfo.ResumeLayout(false);
this.grpEditInfo.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.numAlarmCode)).EndInit();
this.pnlEditButtons.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.SplitContainer splitContainer;
private System.Windows.Forms.Panel pnlList;
private System.Windows.Forms.DataGridView dgvAlarmConfigs;
private System.Windows.Forms.Panel pnlListButtons;
private System.Windows.Forms.Label lblStatistics;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.Button btnRefresh;
private System.Windows.Forms.Panel pnlSearch;
private System.Windows.Forms.ComboBox cmbLevelFilter;
private System.Windows.Forms.Label lblLevelFilter;
private System.Windows.Forms.TextBox txtSearch;
private System.Windows.Forms.Label lblSearch;
private System.Windows.Forms.Panel pnlEdit;
private System.Windows.Forms.GroupBox grpEditInfo;
private System.Windows.Forms.TextBox txtRemarks;
private System.Windows.Forms.Label lblRemarks;
private System.Windows.Forms.CheckBox chkEnabled;
private System.Windows.Forms.ComboBox cmbLevel;
private System.Windows.Forms.Label lblLevel;
private System.Windows.Forms.TextBox txtAlarmContent;
private System.Windows.Forms.Label lblAlarmContent;
private System.Windows.Forms.NumericUpDown numAlarmCode;
private System.Windows.Forms.Label lblAlarmCode;
private System.Windows.Forms.TextBox txtAlarmId;
private System.Windows.Forms.Label lblAlarmId;
private System.Windows.Forms.Panel pnlEditButtons;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnDelete;
private System.Windows.Forms.Button btnSave;
private System.Windows.Forms.DataGridViewTextBoxColumn colAlarmId;
private System.Windows.Forms.DataGridViewTextBoxColumn colAlarmCode;
private System.Windows.Forms.DataGridViewTextBoxColumn colAlarmContent;
private System.Windows.Forms.DataGridViewTextBoxColumn colLevel;
private System.Windows.Forms.DataGridViewTextBoxColumn colEnabled;
private System.Windows.Forms.DataGridViewTextBoxColumn colRemarks;
}
}
@@ -1,240 +1,313 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CycleGUI;
using StandardScene.Utils;
namespace StandardScene.Charge
{
/// <summary>
/// 报警配置管理窗体
/// 报警配置管理界面(CycleGUI 版,替代原 WinForms 窗体)。
/// </summary>
public partial class AlarmConfigManagementForm : Form
public class AlarmConfigManagementForm
{
private readonly AlarmConfigDataService dataService;
private AlarmConfig selectedAlarmConfig;
private const string TableId = "alarm-config-list";
public AlarmConfigManagementForm()
private static readonly string[] LevelNames = { "无", "低", "中", "高", "严重" };
private static 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 static 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 = "";
/// <summary>打开(或置前)报警配置管理面板。兼容原 <c>new AlarmConfigManagementForm().Show()</c> 调用方式。</summary>
public void Show() => Open();
/// <summary>打开(或置前)报警配置管理面板。</summary>
public static void Open()
{
try
if (_panel != null)
{
InitializeComponent();
dataService = AlarmConfigDataService.Instance;
// 订阅Load事件,确保所有控件都已初始化后再加载数据
this.Load += AlarmConfigManagementForm_Load;
try
{
_panel.BringToFront();
return;
}
catch
{
_panel = null;
}
}
catch (Exception ex)
LoadAlarms();
var panel = GUI.DeclarePanel()
.ShowTitle("报警配置管理")
.SetDefaultDocking(Panel.Docking.None)
.InitSize(1100, 680)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
_panel = panel;
panel.IfTerminalQuit(() => _panel = null);
panel.Define(pb =>
{
MessageBox.Show($"初始化报警配置管理窗体失败: {ex.Message}\n\n详细信息:\n{ex.StackTrace}",
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 窗体加载事件
/// </summary>
private void AlarmConfigManagementForm_Load(object sender, EventArgs e)
{
InitializeForm();
}
/// <summary>
/// 初始化窗体
/// </summary>
private void InitializeForm()
{
try
{
// 初始化报警级别下拉框
if (cmbLevel != null)
{
cmbLevel.Items.Clear();
cmbLevel.Items.Add("无");
cmbLevel.Items.Add("低");
cmbLevel.Items.Add("中");
cmbLevel.Items.Add("高");
cmbLevel.Items.Add("严重");
cmbLevel.SelectedIndex = 2; // 默认选择"中"
}
// 初始化级别筛选下拉框
if (cmbLevelFilter != null)
{
cmbLevelFilter.Items.Clear();
cmbLevelFilter.Items.Add("全部");
cmbLevelFilter.Items.Add("无");
cmbLevelFilter.Items.Add("低");
cmbLevelFilter.Items.Add("中");
cmbLevelFilter.Items.Add("高");
cmbLevelFilter.Items.Add("严重");
cmbLevelFilter.SelectedIndex = 0;
}
LoadAlarmConfigs();
ClearEditFields();
}
catch (Exception ex)
{
MessageBox.Show($"初始化窗体失败: {ex.Message}\n\n{ex.StackTrace}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 加载报警配置列表
/// </summary>
private void LoadAlarmConfigs()
{
try
{
if (dgvAlarmConfigs == null)
{
return; // 控件还未初始化,直接返回
}
var alarmConfigs = dataService.GetAllAlarmConfigs();
if (alarmConfigs == null)
{
alarmConfigs = new System.Collections.Generic.List<AlarmConfig>();
}
// 根据级别筛选
if (cmbLevelFilter != null && cmbLevelFilter.SelectedIndex > 0)
{
var filterLevel = (AlarmLevel)(cmbLevelFilter.SelectedIndex - 1);
alarmConfigs = alarmConfigs.Where(a => a.Level == filterLevel).ToList();
}
// 根据搜索文本筛选
if (txtSearch != null && !string.IsNullOrWhiteSpace(txtSearch.Text))
{
var searchText = txtSearch.Text.Trim().ToLower();
alarmConfigs = alarmConfigs.Where(a =>
a.AlarmId.ToLower().Contains(searchText) ||
a.AlarmCode.ToString().Contains(searchText) ||
a.AlarmContent.ToLower().Contains(searchText)
).ToList();
}
dgvAlarmConfigs.Rows.Clear();
foreach (var alarm in alarmConfigs)
{
var index = dgvAlarmConfigs.Rows.Add(
alarm.AlarmId,
alarm.AlarmCode,
alarm.AlarmContent,
GetLevelText(alarm.Level),
alarm.Enabled ? "是" : "否",
alarm.Remarks
);
// 根据级别设置行颜色
var row = dgvAlarmConfigs.Rows[index];
switch (alarm.Level)
{
case AlarmLevel.Critical:
row.DefaultCellStyle.BackColor = Color.FromArgb(255, 235, 238); // 浅红色
row.DefaultCellStyle.ForeColor = Color.FromArgb(183, 28, 28);
// 安全地创建粗体字体
var baseFont = row.DefaultCellStyle.Font ?? dgvAlarmConfigs.DefaultCellStyle.Font ?? new Font("微软雅黑", 9F);
row.DefaultCellStyle.Font = new Font(baseFont, FontStyle.Bold);
break;
case AlarmLevel.High:
row.DefaultCellStyle.BackColor = Color.FromArgb(255, 243, 224); // 浅橙色
row.DefaultCellStyle.ForeColor = Color.FromArgb(230, 81, 0);
break;
case AlarmLevel.Medium:
row.DefaultCellStyle.BackColor = Color.FromArgb(255, 249, 196); // 浅黄色
row.DefaultCellStyle.ForeColor = Color.FromArgb(245, 127, 23);
break;
case AlarmLevel.Low:
row.DefaultCellStyle.BackColor = Color.FromArgb(232, 245, 233); // 浅绿色
row.DefaultCellStyle.ForeColor = Color.FromArgb(46, 125, 50);
break;
}
// 如果未启用,显示为灰色
if (!alarm.Enabled)
{
row.DefaultCellStyle.BackColor = Color.FromArgb(238, 238, 238);
row.DefaultCellStyle.ForeColor = Color.FromArgb(158, 158, 158);
}
}
UpdateStatistics();
UpdateTitleWithFilter(alarmConfigs.Count);
}
catch (Exception ex)
{
MessageBox.Show($"加载数据失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 更新统计信息
/// </summary>
private void UpdateStatistics()
{
try
{
if (lblStatistics == null)
if (pb.Closing())
{
panel.Exit();
_panel = null;
return;
}
var alarmConfigs = dataService.GetAllAlarmConfigs();
if (alarmConfigs == null)
if (pb.Button("新增", distinct: "alarm-add"))
OpenEditDialog(null);
pb.SameLine(12);
if (pb.Button("刷新", distinct: "alarm-refresh"))
{
alarmConfigs = new System.Collections.Generic.List<AlarmConfig>();
DataService.Reload();
LoadAlarms();
_status = "数据已刷新";
}
pb.SameLine(12);
if (pb.Button("关闭", distinct: "alarm-close"))
{
panel.Exit();
_panel = null;
return;
}
var total = alarmConfigs.Count;
var enabled = alarmConfigs.Count(a => a.Enabled);
var disabled = total - enabled;
var critical = alarmConfigs.Count(a => a.Level == AlarmLevel.Critical);
var high = alarmConfigs.Count(a => a.Level == AlarmLevel.High);
pb.Separator();
pb.DropdownBox("级别筛选", LevelFilterNames, ref _levelFilterIdx);
lblStatistics.Text = $"总数: {total} | 启用: {enabled} | 禁用: {disabled} | 严重: {critical} | 高级: {high}";
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"更新统计信息失败: {ex.Message}");
}
var filtered = GetFilteredAlarms();
var totalCount = _allAlarms.Count;
if (_levelFilterIdx > 0)
pb.Label($"显示: {filtered.Count}/{totalCount} ({LevelFilterNames[_levelFilterIdx]})");
else
pb.Label($"总数: {totalCount} | {GetStatisticsText()}");
pb.Table(TableId,
new[] { "报警编码", "报警内容", "级别", "启用", "备注", "操作" },
filtered.Count, (row, i) =>
{
var alarm = filtered[i];
if (!alarm.Enabled)
row.SetColor(DisabledRowColor);
else if (alarm.Level == AlarmLevel.Critical)
row.SetColor(CriticalRowColor);
else if (alarm.Level == AlarmLevel.High)
row.SetColor(HighRowColor);
else if (alarm.Level == AlarmLevel.Medium)
row.SetColor(MediumRowColor);
else if (alarm.Level == AlarmLevel.Low)
row.SetColor(LowRowColor);
row.Label($"{alarm.AlarmCode}");
row.Label(alarm.AlarmContent ?? "");
row.Label(GetLevelText(alarm.Level));
row.Label(alarm.Enabled ? "是" : "否");
row.Label(alarm.Remarks ?? "");
if (row.ButtonGroup(new[] { "编辑" }, new[] { "编辑该报警配置" }) == 0)
OpenEditDialog(alarm);
}, height: 16, enableSearch: true);
if (!string.IsNullOrEmpty(_status))
{
pb.Separator();
pb.Label(_status);
}
pb.Panel.Repaint(repaintTimeMs: 500);
});
}
/// <summary>
/// 更新标题显示筛选信息
/// </summary>
private void UpdateTitleWithFilter(int displayCount)
private static void OpenEditDialog(AlarmConfig existing)
{
if (_dialog != null)
{
try
{
_dialog.BringToFront();
return;
}
catch
{
_dialog = null;
}
}
bool isAdd = existing == null;
var draft = isAdd ? new AlarmConfig() : existing;
int levelIdx = (int)draft.Level;
if (levelIdx < 0 || levelIdx >= LevelNames.Length)
levelIdx = 2;
string codeText = draft.AlarmCode.ToString();
string contentText = draft.AlarmContent ?? "";
string remarksText = draft.Remarks ?? "";
bool enabled = draft.Enabled;
string err = "";
var dlg = GUI.DeclarePanel()
.ShowTitle(isAdd ? "新增报警配置" : $"编辑报警配置 [{draft.AlarmCode}]")
.SetDefaultDocking(Panel.Docking.None)
.InitSize(460, 420)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
_dialog = dlg;
dlg.IfTerminalQuit(() => _dialog = null);
dlg.Define(pb =>
{
if (pb.Closing())
{
dlg.Exit();
_dialog = null;
return;
}
if (isAdd)
pb.Label("编号: (新增时自动生成)");
else
pb.Label($"编号: {draft.AlarmId}");
var (code, _) = pb.TextInput("1. 报警编码 (0~99999)", codeText, alwaysReturnString: true);
codeText = code;
var (content, _) = pb.TextInput("2. 报警内容", contentText, alwaysReturnString: true);
contentText = content;
pb.DropdownBox("3. 报警级别", LevelNames, ref levelIdx);
pb.CheckBox("4. 启用", ref enabled);
var (remarks, _) = pb.TextInput("5. 备注", remarksText, alwaysReturnString: true);
remarksText = remarks;
if (!string.IsNullOrEmpty(err))
{
pb.Separator();
pb.Label(err);
}
pb.Separator();
if (pb.Button(isAdd ? "新增" : "保存", distinct: "alarm-edit-save"))
{
if (!int.TryParse(codeText?.Trim(), out var alarmCode) || alarmCode < 0 || alarmCode > 99999)
{
err = "报警编码需为 0~99999 的整数";
return;
}
if (string.IsNullOrWhiteSpace(contentText))
{
err = "报警内容不能为空";
return;
}
draft.AlarmCode = alarmCode;
draft.AlarmContent = contentText.Trim();
draft.Level = (AlarmLevel)levelIdx;
draft.Enabled = enabled;
draft.Remarks = remarksText?.Trim() ?? "";
bool success;
string errorMessage;
if (isAdd)
success = DataService.AddAlarmConfig(draft, out errorMessage);
else
success = DataService.UpdateAlarmConfig(draft, out errorMessage);
if (success)
{
CycleUiHelper.Alert("成功", "保存成功!");
LoadAlarms();
_status = isAdd ? "已新增报警配置" : $"已保存报警配置 [{draft.AlarmCode}]";
dlg.Exit();
_dialog = null;
_panel?.Repaint();
}
else
{
err = $"保存失败: {errorMessage}";
}
}
if (!isAdd)
{
pb.SameLine(8);
if (pb.Button("删除", distinct: "alarm-edit-delete"))
{
var toDelete = draft;
CycleUiHelper.ConfirmThen(
$"确定要删除报警配置 [{toDelete.AlarmCode}] {toDelete.AlarmContent} 吗?",
() =>
{
if (DataService.DeleteAlarmConfig(toDelete.AlarmId, out string errorMessage))
{
CycleUiHelper.Alert("成功", "删除成功!");
LoadAlarms();
_status = $"已删除报警配置 [{toDelete.AlarmCode}]";
dlg.Exit();
_dialog = null;
_panel?.Repaint();
}
else
{
CycleUiHelper.Alert("错误", $"删除失败: {errorMessage}");
}
});
}
}
pb.SameLine(8);
if (pb.Button("取消", distinct: "alarm-edit-cancel"))
{
dlg.Exit();
_dialog = null;
}
});
}
private static void LoadAlarms()
{
try
{
var allConfigs = dataService.GetAllAlarmConfigs();
var totalCount = allConfigs != null ? allConfigs.Count : 0;
if (cmbLevelFilter != null && cmbLevelFilter.SelectedIndex > 0)
{
this.Text = $"报警配置管理 - 显示: {displayCount}/{totalCount} ({cmbLevelFilter.Text})";
}
else
{
this.Text = $"报警配置管理 - 总数: {totalCount}";
}
_allAlarms = DataService.GetAllAlarmConfigs() ?? new List<AlarmConfig>();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"更新标题失败: {ex.Message}");
this.Text = "报警配置管理";
_allAlarms = new List<AlarmConfig>();
CycleUiHelper.Alert("错误", $"加载数据失败: {ex.Message}");
}
}
/// <summary>
/// 获取级别文本
/// </summary>
private string GetLevelText(AlarmLevel level)
private static List<AlarmConfig> GetFilteredAlarms()
{
IEnumerable<AlarmConfig> query = _allAlarms;
if (_levelFilterIdx > 0)
query = query.Where(a => a.Level == (AlarmLevel)(_levelFilterIdx - 1));
return query.ToList();
}
private static string GetStatisticsText()
{
var total = _allAlarms.Count;
var enabled = _allAlarms.Count(a => a.Enabled);
var disabled = total - enabled;
var critical = _allAlarms.Count(a => a.Level == AlarmLevel.Critical);
var high = _allAlarms.Count(a => a.Level == AlarmLevel.High);
return $"启用: {enabled} | 禁用: {disabled} | 严重: {critical} | 高级: {high}";
}
private static string GetLevelText(AlarmLevel level)
{
switch (level)
{
@@ -247,301 +320,5 @@ namespace StandardScene.Charge
}
}
/// <summary>
/// 清空编辑字段
/// </summary>
private void ClearEditFields()
{
try
{
selectedAlarmConfig = null;
if (txtAlarmId != null)
{
txtAlarmId.Text = "";
txtAlarmId.Enabled = false; // 新增时编号自动生成
}
if (numAlarmCode != null)
{
numAlarmCode.Value = 0;
numAlarmCode.Enabled = true;
numAlarmCode.ReadOnly = false;
}
if (txtAlarmContent != null)
{
txtAlarmContent.Text = "";
txtAlarmContent.Enabled = true;
txtAlarmContent.ReadOnly = false;
}
if (cmbLevel != null)
{
cmbLevel.SelectedIndex = 2; // 中
cmbLevel.Enabled = true;
}
if (chkEnabled != null)
{
chkEnabled.Checked = true;
chkEnabled.Enabled = true;
}
if (txtRemarks != null)
{
txtRemarks.Text = "";
txtRemarks.Enabled = true;
txtRemarks.ReadOnly = false;
}
if (btnSave != null)
{
btnSave.Text = "新增";
btnSave.Enabled = true;
}
if (btnDelete != null)
{
btnDelete.Enabled = false;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"清空编辑字段失败: {ex.Message}");
}
}
/// <summary>
/// 从字段创建报警配置
/// </summary>
private AlarmConfig CreateAlarmConfigFromFields()
{
var alarmConfig = selectedAlarmConfig ?? new AlarmConfig();
alarmConfig.AlarmCode = (int)numAlarmCode.Value;
alarmConfig.AlarmContent = txtAlarmContent.Text.Trim();
alarmConfig.Level = (AlarmLevel)cmbLevel.SelectedIndex;
alarmConfig.Enabled = chkEnabled.Checked;
alarmConfig.Remarks = txtRemarks.Text.Trim();
return alarmConfig;
}
/// <summary>
/// 加载报警配置到编辑区
/// </summary>
private void LoadAlarmConfigToFields(AlarmConfig alarmConfig)
{
try
{
selectedAlarmConfig = alarmConfig;
// 填充数据
if (txtAlarmId != null)
{
txtAlarmId.Text = alarmConfig.AlarmId;
txtAlarmId.Enabled = false; // 编号不可修改
}
if (numAlarmCode != null)
{
numAlarmCode.Value = alarmConfig.AlarmCode;
numAlarmCode.Enabled = true;
numAlarmCode.ReadOnly = false;
}
if (txtAlarmContent != null)
{
txtAlarmContent.Text = alarmConfig.AlarmContent;
txtAlarmContent.Enabled = true;
txtAlarmContent.ReadOnly = false;
}
if (cmbLevel != null)
{
cmbLevel.SelectedIndex = (int)alarmConfig.Level;
cmbLevel.Enabled = true;
}
if (chkEnabled != null)
{
chkEnabled.Checked = alarmConfig.Enabled;
chkEnabled.Enabled = true;
}
if (txtRemarks != null)
{
txtRemarks.Text = alarmConfig.Remarks ?? "";
txtRemarks.Enabled = true;
txtRemarks.ReadOnly = false;
}
// 设置按钮状态
if (btnSave != null)
{
btnSave.Text = "保存";
btnSave.Enabled = true;
}
if (btnDelete != null)
{
btnDelete.Enabled = true;
}
}
catch (Exception ex)
{
MessageBox.Show($"加载数据到编辑区失败: {ex.Message}\n\n{ex.StackTrace}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// ==================== 事件处理 ====================
private void btnSave_Click(object sender, EventArgs e)
{
try
{
// 验证报警编码
if (numAlarmCode.Value < 0)
{
MessageBox.Show("报警编码不能为负数", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
numAlarmCode.Focus();
return;
}
// 验证报警内容
if (string.IsNullOrWhiteSpace(txtAlarmContent.Text))
{
MessageBox.Show("报警内容不能为空", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
txtAlarmContent.Focus();
return;
}
var alarmConfig = CreateAlarmConfigFromFields();
string errorMessage;
bool success;
if (selectedAlarmConfig == null)
{
// 新增
success = dataService.AddAlarmConfig(alarmConfig, out errorMessage);
}
else
{
// 更新
success = dataService.UpdateAlarmConfig(alarmConfig, out errorMessage);
}
if (success)
{
MessageBox.Show("保存成功!", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
LoadAlarmConfigs();
ClearEditFields();
}
else
{
MessageBox.Show($"保存失败: {errorMessage}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show($"保存失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
if (selectedAlarmConfig == null)
{
MessageBox.Show("请先选择要删除的报警配置", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
var result = MessageBox.Show(
$"确定要删除报警配置 [{selectedAlarmConfig.AlarmCode}] {selectedAlarmConfig.AlarmContent} 吗?",
"确认删除",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
if (dataService.DeleteAlarmConfig(selectedAlarmConfig.AlarmId, out string errorMessage))
{
MessageBox.Show("删除成功!", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
LoadAlarmConfigs();
ClearEditFields();
}
else
{
MessageBox.Show($"删除失败: {errorMessage}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
ClearEditFields();
}
private void btnRefresh_Click(object sender, EventArgs e)
{
dataService.Reload();
LoadAlarmConfigs();
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void dgvAlarmConfigs_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.RowIndex >= 0 && e.RowIndex < dgvAlarmConfigs.Rows.Count)
{
var row = dgvAlarmConfigs.Rows[e.RowIndex];
if (row.Cells[0].Value != null)
{
var alarmId = row.Cells[1].Value.ToString();
var alarmConfig = dataService.GetAlarmConfigAlarmCode(int.Parse(alarmId));
if (alarmConfig != null)
{
LoadAlarmConfigToFields(alarmConfig);
}
else
{
MessageBox.Show($"未找到报警配置: {alarmId}", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show($"加载报警配置失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
LoadAlarmConfigs();
}
private void cmbLevelFilter_SelectedIndexChanged(object sender, EventArgs e)
{
LoadAlarmConfigs();
}
}
}
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using CycleGUI;
using SimpleCore;
using SimpleCore.Library;
using StandardScene.Utils;
namespace StandardScene.Charge
{
@@ -13,36 +14,11 @@ namespace StandardScene.Charge
/// </summary>
public static class ChargeStationHelper
{
private static ChargeStationManagementForm _managementForm;
/// <summary>打开充电桩管理面板(单实例)。</summary>
public static void OpenManagementWindow() => ChargeStationManagementForm.Open();
/// <summary>
/// 打开充电桩管理窗口(单例模式)
/// </summary>
public static void OpenManagementWindow()
{
if (_managementForm == null || _managementForm.IsDisposed)
{
_managementForm = new ChargeStationManagementForm();
_managementForm.FormClosed += (s, e) => _managementForm = null;
_managementForm.Show();
}
else
{
_managementForm.BringToFront();
_managementForm.Activate();
}
}
/// <summary>
/// 打开充电桩管理窗口(对话框模式)
/// </summary>
public static DialogResult OpenManagementDialog()
{
using (var form = new ChargeStationManagementForm())
{
return form.ShowDialog();
}
}
/// <summary>打开充电桩管理面板(兼容旧 API)。</summary>
public static void OpenManagementDialog() => ChargeStationManagementForm.Open();
/// <summary>
/// 获取指定站点的充电桩
@@ -297,65 +273,44 @@ namespace StandardScene.Charge
return success;
}
/// <summary>
/// 显示充电桩选择对话框
/// </summary>
/// <param name="filterByStatus">按状态过滤(null表示显示全部)</param>
/// <returns>选中的充电桩,取消则返回null</returns>
public static ChargeStation ShowStationSelectionDialog(ChargeStationStatus? filterByStatus = null)
/// <summary>显示充电桩选择面板(非阻塞;通过 <paramref name="onSelected"/> 回调返回结果)。</summary>
public static void ShowStationSelectionDialog(ChargeStationStatus? filterByStatus, System.Action<ChargeStation> onSelected)
{
var dataService = ChargeStationDataService.Instance;
var stations = dataService.GetAllStations();
var stations = ChargeStationDataService.Instance.GetAllStations();
if (filterByStatus.HasValue)
{
stations = stations.Where(s => s.Status == filterByStatus.Value).ToList();
}
if (stations.Count == 0)
{
MessageBox.Show("没有符合条件的充电桩", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return null;
CycleUiHelper.Alert("提示", "没有符合条件的充电桩");
onSelected?.Invoke(null);
return;
}
// 创建简单的选择对话框
using (var dialog = new Form())
var labels = stations.Select(s =>
$"[{s.StationId}] {s.Name} - {s.IpAddress}:{s.Port} - {GetStatusText(s.Status)}").ToArray();
int sel = 0;
var dlg = GUI.DeclarePanel()
.ShowTitle("选择充电桩")
.TopMost(true)
.InitSize(520, 400)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
dlg.Define(pb =>
{
dialog.Text = "选择充电桩";
dialog.Size = new System.Drawing.Size(500, 400);
dialog.StartPosition = FormStartPosition.CenterParent;
var listBox = new ListBox
if (pb.Closing()) { dlg.Exit(); onSelected?.Invoke(null); return; }
sel = pb.ListBox("充电桩", labels, height: 12);
if (pb.Button("确定", distinct: "cs-pick-ok"))
{
Dock = DockStyle.Fill,
Font = new System.Drawing.Font("微软雅黑", 10F)
};
foreach (var station in stations)
{
listBox.Items.Add($"[{station.StationId}] {station.Name} - {station.IpAddress}:{station.Port} - {GetStatusText(station.Status)}");
dlg.Exit();
onSelected?.Invoke(sel >= 0 && sel < stations.Count ? stations[sel] : null);
}
var btnOK = new Button
pb.SameLine(8);
if (pb.Button("取消", distinct: "cs-pick-cancel"))
{
Text = "确定",
DialogResult = DialogResult.OK,
Dock = DockStyle.Bottom,
Height = 40
};
dialog.Controls.Add(listBox);
dialog.Controls.Add(btnOK);
dialog.AcceptButton = btnOK;
if (dialog.ShowDialog() == DialogResult.OK && listBox.SelectedIndex >= 0)
{
return stations[listBox.SelectedIndex];
dlg.Exit();
onSelected?.Invoke(null);
}
return null;
}
});
}
/// <summary>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,572 +0,0 @@
namespace StandardScene.Charge
{
partial class ChargeStrategyConfigForm
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
// 创建所有控件实例
this.pnlMain = new System.Windows.Forms.Panel();
this.pnlBottom = new System.Windows.Forms.Panel();
this.grpSocParams = new System.Windows.Forms.GroupBox();
this.grpTimeParams = new System.Windows.Forms.GroupBox();
this.grpTaskParams = new System.Windows.Forms.GroupBox();
this.grpSwitchParams = new System.Windows.Forms.GroupBox();
// SOC 参数控件
this.lblMustChargeSoc = new System.Windows.Forms.Label();
this.numMustChargeSoc = new System.Windows.Forms.NumericUpDown();
this.lblIdleChargeSoc = new System.Windows.Forms.Label();
this.numIdleChargeSoc = new System.Windows.Forms.NumericUpDown();
this.lblTaskAvailableSoc = new System.Windows.Forms.Label();
this.numTaskAvailableSoc = new System.Windows.Forms.NumericUpDown();
this.lblFullChargeSoc = new System.Windows.Forms.Label();
this.numFullChargeSoc = new System.Windows.Forms.NumericUpDown();
this.lblAllowInterruptSoc = new System.Windows.Forms.Label();
this.numAllowInterruptSoc = new System.Windows.Forms.NumericUpDown();
// 时间参数控件
this.lblIdleChargeSeconds = new System.Windows.Forms.Label();
this.numIdleChargeSeconds = new System.Windows.Forms.NumericUpDown();
this.lblIdleSeconds = new System.Windows.Forms.Label();
this.numIdleSeconds = new System.Windows.Forms.NumericUpDown();
this.lblMustChargeSeconds = new System.Windows.Forms.Label();
this.numMustChargeSeconds = new System.Windows.Forms.NumericUpDown();
this.lblTopUpMinutes = new System.Windows.Forms.Label();
this.numTopUpMinutes = new System.Windows.Forms.NumericUpDown();
// 任务参数控件
this.lblMinAllowFreeCarToChargeTaskCnt = new System.Windows.Forms.Label();
this.numMinAllowFreeCarToChargeTaskCnt = new System.Windows.Forms.NumericUpDown();
// 开关参数控件
this.chkAllowInterruptTask = new System.Windows.Forms.CheckBox();
this.chkUseLowerSocForCharge = new System.Windows.Forms.CheckBox();
this.chkEnableErrorChargeDetection = new System.Windows.Forms.CheckBox();
this.chkUseChargeSiteFilter = new System.Windows.Forms.CheckBox();
// 底部控件
this.lblStatus = new System.Windows.Forms.Label();
this.btnSave = new System.Windows.Forms.Button();
this.btnApply = new System.Windows.Forms.Button();
this.btnRestoreDefaults = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.pnlMain.SuspendLayout();
this.grpSwitchParams.SuspendLayout();
this.grpTaskParams.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.numMinAllowFreeCarToChargeTaskCnt)).BeginInit();
this.grpTimeParams.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.numTopUpMinutes)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numMustChargeSeconds)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numIdleSeconds)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numIdleChargeSeconds)).BeginInit();
this.grpSocParams.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.numAllowInterruptSoc)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numFullChargeSoc)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numTaskAvailableSoc)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numIdleChargeSoc)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numMustChargeSoc)).BeginInit();
this.pnlBottom.SuspendLayout();
this.SuspendLayout();
//
// pnlMain
//
this.pnlMain.AutoScroll = true;
this.pnlMain.Controls.Add(this.grpSwitchParams);
this.pnlMain.Controls.Add(this.grpTaskParams);
this.pnlMain.Controls.Add(this.grpTimeParams);
this.pnlMain.Controls.Add(this.grpSocParams);
this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlMain.Location = new System.Drawing.Point(0, 0);
this.pnlMain.Name = "pnlMain";
this.pnlMain.Padding = new System.Windows.Forms.Padding(10);
this.pnlMain.Size = new System.Drawing.Size(784, 631);
this.pnlMain.TabIndex = 0;
//
// grpSwitchParams
//
this.grpSwitchParams.Controls.Add(this.chkUseChargeSiteFilter);
this.grpSwitchParams.Controls.Add(this.chkEnableErrorChargeDetection);
this.grpSwitchParams.Controls.Add(this.chkUseLowerSocForCharge);
this.grpSwitchParams.Controls.Add(this.chkAllowInterruptTask);
this.grpSwitchParams.Dock = System.Windows.Forms.DockStyle.Top;
this.grpSwitchParams.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold);
this.grpSwitchParams.Location = new System.Drawing.Point(10, 460);
this.grpSwitchParams.Name = "grpSwitchParams";
this.grpSwitchParams.Padding = new System.Windows.Forms.Padding(10);
this.grpSwitchParams.Size = new System.Drawing.Size(764, 150);
this.grpSwitchParams.TabIndex = 3;
this.grpSwitchParams.TabStop = false;
this.grpSwitchParams.Text = "开关参数";
//
// chkUseChargeSiteFilter
//
this.chkUseChargeSiteFilter.AutoSize = true;
this.chkUseChargeSiteFilter.Font = new System.Drawing.Font("微软雅黑", 9F);
this.chkUseChargeSiteFilter.Location = new System.Drawing.Point(400, 80);
this.chkUseChargeSiteFilter.Name = "chkUseChargeSiteFilter";
this.chkUseChargeSiteFilter.Size = new System.Drawing.Size(147, 24);
this.chkUseChargeSiteFilter.TabIndex = 3;
this.chkUseChargeSiteFilter.Text = "使用充电站点筛选";
this.chkUseChargeSiteFilter.UseVisualStyleBackColor = true;
//
// chkEnableErrorChargeDetection
//
this.chkEnableErrorChargeDetection.AutoSize = true;
this.chkEnableErrorChargeDetection.Font = new System.Drawing.Font("微软雅黑", 9F);
this.chkEnableErrorChargeDetection.Location = new System.Drawing.Point(30, 80);
this.chkEnableErrorChargeDetection.Name = "chkEnableErrorChargeDetection";
this.chkEnableErrorChargeDetection.Size = new System.Drawing.Size(147, 24);
this.chkEnableErrorChargeDetection.TabIndex = 2;
this.chkEnableErrorChargeDetection.Text = "启用充电错误检测";
this.chkEnableErrorChargeDetection.UseVisualStyleBackColor = true;
//
// chkUseLowerSocForCharge
//
this.chkUseLowerSocForCharge.AutoSize = true;
this.chkUseLowerSocForCharge.Font = new System.Drawing.Font("微软雅黑", 9F);
this.chkUseLowerSocForCharge.Location = new System.Drawing.Point(400, 40);
this.chkUseLowerSocForCharge.Name = "chkUseLowerSocForCharge";
this.chkUseLowerSocForCharge.Size = new System.Drawing.Size(195, 24);
this.chkUseLowerSocForCharge.TabIndex = 1;
this.chkUseLowerSocForCharge.Text = "优先使用低电量车辆充电";
this.chkUseLowerSocForCharge.UseVisualStyleBackColor = true;
//
// chkAllowInterruptTask
//
this.chkAllowInterruptTask.AutoSize = true;
this.chkAllowInterruptTask.Font = new System.Drawing.Font("微软雅黑", 9F);
this.chkAllowInterruptTask.Location = new System.Drawing.Point(30, 40);
this.chkAllowInterruptTask.Name = "chkAllowInterruptTask";
this.chkAllowInterruptTask.Size = new System.Drawing.Size(147, 24);
this.chkAllowInterruptTask.TabIndex = 0;
this.chkAllowInterruptTask.Text = "允许中断充电任务";
this.chkAllowInterruptTask.UseVisualStyleBackColor = true;
//
// grpTaskParams
//
this.grpTaskParams.Controls.Add(this.numMinAllowFreeCarToChargeTaskCnt);
this.grpTaskParams.Controls.Add(this.lblMinAllowFreeCarToChargeTaskCnt);
this.grpTaskParams.Dock = System.Windows.Forms.DockStyle.Top;
this.grpTaskParams.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold);
this.grpTaskParams.Location = new System.Drawing.Point(10, 370);
this.grpTaskParams.Name = "grpTaskParams";
this.grpTaskParams.Padding = new System.Windows.Forms.Padding(10);
this.grpTaskParams.Size = new System.Drawing.Size(764, 90);
this.grpTaskParams.TabIndex = 2;
this.grpTaskParams.TabStop = false;
this.grpTaskParams.Text = "任务参数";
//
// numMinAllowFreeCarToChargeTaskCnt
//
this.numMinAllowFreeCarToChargeTaskCnt.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numMinAllowFreeCarToChargeTaskCnt.Location = new System.Drawing.Point(250, 40);
this.numMinAllowFreeCarToChargeTaskCnt.Maximum = new decimal(new int[] {
100,
0,
0,
0});
this.numMinAllowFreeCarToChargeTaskCnt.Name = "numMinAllowFreeCarToChargeTaskCnt";
this.numMinAllowFreeCarToChargeTaskCnt.Size = new System.Drawing.Size(120, 27);
this.numMinAllowFreeCarToChargeTaskCnt.TabIndex = 1;
//
// lblMinAllowFreeCarToChargeTaskCnt
//
this.lblMinAllowFreeCarToChargeTaskCnt.AutoSize = true;
this.lblMinAllowFreeCarToChargeTaskCnt.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblMinAllowFreeCarToChargeTaskCnt.Location = new System.Drawing.Point(30, 42);
this.lblMinAllowFreeCarToChargeTaskCnt.Name = "lblMinAllowFreeCarToChargeTaskCnt";
this.lblMinAllowFreeCarToChargeTaskCnt.Size = new System.Drawing.Size(207, 20);
this.lblMinAllowFreeCarToChargeTaskCnt.TabIndex = 0;
this.lblMinAllowFreeCarToChargeTaskCnt.Text = "允许空闲车充电的最小任务数:";
//
// grpTimeParams
//
this.grpTimeParams.Controls.Add(this.numTopUpMinutes);
this.grpTimeParams.Controls.Add(this.lblTopUpMinutes);
this.grpTimeParams.Controls.Add(this.numMustChargeSeconds);
this.grpTimeParams.Controls.Add(this.lblMustChargeSeconds);
this.grpTimeParams.Controls.Add(this.numIdleSeconds);
this.grpTimeParams.Controls.Add(this.lblIdleSeconds);
this.grpTimeParams.Controls.Add(this.numIdleChargeSeconds);
this.grpTimeParams.Controls.Add(this.lblIdleChargeSeconds);
this.grpTimeParams.Dock = System.Windows.Forms.DockStyle.Top;
this.grpTimeParams.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold);
this.grpTimeParams.Location = new System.Drawing.Point(10, 210);
this.grpTimeParams.Name = "grpTimeParams";
this.grpTimeParams.Padding = new System.Windows.Forms.Padding(10);
this.grpTimeParams.Size = new System.Drawing.Size(764, 160);
this.grpTimeParams.TabIndex = 1;
this.grpTimeParams.TabStop = false;
this.grpTimeParams.Text = "时间参数";
//
// numTopUpMinutes
//
this.numTopUpMinutes.DecimalPlaces = 1;
this.numTopUpMinutes.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numTopUpMinutes.Location = new System.Drawing.Point(580, 100);
this.numTopUpMinutes.Maximum = new decimal(new int[] {
1000,
0,
0,
0});
this.numTopUpMinutes.Name = "numTopUpMinutes";
this.numTopUpMinutes.Size = new System.Drawing.Size(120, 27);
this.numTopUpMinutes.TabIndex = 7;
//
// lblTopUpMinutes
//
this.lblTopUpMinutes.AutoSize = true;
this.lblTopUpMinutes.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblTopUpMinutes.Location = new System.Drawing.Point(400, 102);
this.lblTopUpMinutes.Name = "lblTopUpMinutes";
this.lblTopUpMinutes.Size = new System.Drawing.Size(159, 20);
this.lblTopUpMinutes.TabIndex = 6;
this.lblTopUpMinutes.Text = "补电时间 (分钟,min):";
//
// numMustChargeSeconds
//
this.numMustChargeSeconds.DecimalPlaces = 1;
this.numMustChargeSeconds.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numMustChargeSeconds.Location = new System.Drawing.Point(250, 100);
this.numMustChargeSeconds.Maximum = new decimal(new int[] {
10000,
0,
0,
0});
this.numMustChargeSeconds.Name = "numMustChargeSeconds";
this.numMustChargeSeconds.Size = new System.Drawing.Size(120, 27);
this.numMustChargeSeconds.TabIndex = 5;
//
// lblMustChargeSeconds
//
this.lblMustChargeSeconds.AutoSize = true;
this.lblMustChargeSeconds.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblMustChargeSeconds.Location = new System.Drawing.Point(30, 102);
this.lblMustChargeSeconds.Name = "lblMustChargeSeconds";
this.lblMustChargeSeconds.Size = new System.Drawing.Size(147, 20);
this.lblMustChargeSeconds.TabIndex = 4;
this.lblMustChargeSeconds.Text = "必充时间 (秒,sec):";
//
// numIdleSeconds
//
this.numIdleSeconds.DecimalPlaces = 1;
this.numIdleSeconds.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numIdleSeconds.Location = new System.Drawing.Point(580, 40);
this.numIdleSeconds.Maximum = new decimal(new int[] {
10000,
0,
0,
0});
this.numIdleSeconds.Name = "numIdleSeconds";
this.numIdleSeconds.Size = new System.Drawing.Size(120, 27);
this.numIdleSeconds.TabIndex = 3;
//
// lblIdleSeconds
//
this.lblIdleSeconds.AutoSize = true;
this.lblIdleSeconds.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblIdleSeconds.Location = new System.Drawing.Point(400, 42);
this.lblIdleSeconds.Name = "lblIdleSeconds";
this.lblIdleSeconds.Size = new System.Drawing.Size(147, 20);
this.lblIdleSeconds.TabIndex = 2;
this.lblIdleSeconds.Text = "空闲时间 (秒,sec):";
//
// numIdleChargeSeconds
//
this.numIdleChargeSeconds.DecimalPlaces = 1;
this.numIdleChargeSeconds.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numIdleChargeSeconds.Location = new System.Drawing.Point(250, 40);
this.numIdleChargeSeconds.Maximum = new decimal(new int[] {
10000,
0,
0,
0});
this.numIdleChargeSeconds.Name = "numIdleChargeSeconds";
this.numIdleChargeSeconds.Size = new System.Drawing.Size(120, 27);
this.numIdleChargeSeconds.TabIndex = 1;
//
// lblIdleChargeSeconds
//
this.lblIdleChargeSeconds.AutoSize = true;
this.lblIdleChargeSeconds.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblIdleChargeSeconds.Location = new System.Drawing.Point(30, 42);
this.lblIdleChargeSeconds.Name = "lblIdleChargeSeconds";
this.lblIdleChargeSeconds.Size = new System.Drawing.Size(171, 20);
this.lblIdleChargeSeconds.TabIndex = 0;
this.lblIdleChargeSeconds.Text = "空闲充电时间 (秒,sec):";
//
// grpSocParams
//
this.grpSocParams.Controls.Add(this.numAllowInterruptSoc);
this.grpSocParams.Controls.Add(this.lblAllowInterruptSoc);
this.grpSocParams.Controls.Add(this.numFullChargeSoc);
this.grpSocParams.Controls.Add(this.lblFullChargeSoc);
this.grpSocParams.Controls.Add(this.numTaskAvailableSoc);
this.grpSocParams.Controls.Add(this.lblTaskAvailableSoc);
this.grpSocParams.Controls.Add(this.numIdleChargeSoc);
this.grpSocParams.Controls.Add(this.lblIdleChargeSoc);
this.grpSocParams.Controls.Add(this.numMustChargeSoc);
this.grpSocParams.Controls.Add(this.lblMustChargeSoc);
this.grpSocParams.Dock = System.Windows.Forms.DockStyle.Top;
this.grpSocParams.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold);
this.grpSocParams.Location = new System.Drawing.Point(10, 10);
this.grpSocParams.Name = "grpSocParams";
this.grpSocParams.Padding = new System.Windows.Forms.Padding(10);
this.grpSocParams.Size = new System.Drawing.Size(764, 200);
this.grpSocParams.TabIndex = 0;
this.grpSocParams.TabStop = false;
this.grpSocParams.Text = "SOC 参数 (电量百分比)";
//
// numAllowInterruptSoc
//
this.numAllowInterruptSoc.DecimalPlaces = 1;
this.numAllowInterruptSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numAllowInterruptSoc.Location = new System.Drawing.Point(250, 150);
this.numAllowInterruptSoc.Name = "numAllowInterruptSoc";
this.numAllowInterruptSoc.Size = new System.Drawing.Size(120, 27);
this.numAllowInterruptSoc.TabIndex = 9;
//
// lblAllowInterruptSoc
//
this.lblAllowInterruptSoc.AutoSize = true;
this.lblAllowInterruptSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblAllowInterruptSoc.Location = new System.Drawing.Point(30, 152);
this.lblAllowInterruptSoc.Name = "lblAllowInterruptSoc";
this.lblAllowInterruptSoc.Size = new System.Drawing.Size(135, 20);
this.lblAllowInterruptSoc.TabIndex = 8;
this.lblAllowInterruptSoc.Text = "允许中断电量 (%):";
//
// numFullChargeSoc
//
this.numFullChargeSoc.DecimalPlaces = 1;
this.numFullChargeSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numFullChargeSoc.Location = new System.Drawing.Point(580, 95);
this.numFullChargeSoc.Name = "numFullChargeSoc";
this.numFullChargeSoc.Size = new System.Drawing.Size(120, 27);
this.numFullChargeSoc.TabIndex = 7;
//
// lblFullChargeSoc
//
this.lblFullChargeSoc.AutoSize = true;
this.lblFullChargeSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblFullChargeSoc.Location = new System.Drawing.Point(400, 97);
this.lblFullChargeSoc.Name = "lblFullChargeSoc";
this.lblFullChargeSoc.Size = new System.Drawing.Size(99, 20);
this.lblFullChargeSoc.TabIndex = 6;
this.lblFullChargeSoc.Text = "满电电量 (%):";
//
// numTaskAvailableSoc
//
this.numTaskAvailableSoc.DecimalPlaces = 1;
this.numTaskAvailableSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numTaskAvailableSoc.Location = new System.Drawing.Point(250, 95);
this.numTaskAvailableSoc.Name = "numTaskAvailableSoc";
this.numTaskAvailableSoc.Size = new System.Drawing.Size(120, 27);
this.numTaskAvailableSoc.TabIndex = 5;
//
// lblTaskAvailableSoc
//
this.lblTaskAvailableSoc.AutoSize = true;
this.lblTaskAvailableSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblTaskAvailableSoc.Location = new System.Drawing.Point(30, 97);
this.lblTaskAvailableSoc.Name = "lblTaskAvailableSoc";
this.lblTaskAvailableSoc.Size = new System.Drawing.Size(135, 20);
this.lblTaskAvailableSoc.TabIndex = 4;
this.lblTaskAvailableSoc.Text = "任务可用电量 (%):";
//
// numIdleChargeSoc
//
this.numIdleChargeSoc.DecimalPlaces = 1;
this.numIdleChargeSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numIdleChargeSoc.Location = new System.Drawing.Point(580, 40);
this.numIdleChargeSoc.Name = "numIdleChargeSoc";
this.numIdleChargeSoc.Size = new System.Drawing.Size(120, 27);
this.numIdleChargeSoc.TabIndex = 3;
//
// lblIdleChargeSoc
//
this.lblIdleChargeSoc.AutoSize = true;
this.lblIdleChargeSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblIdleChargeSoc.Location = new System.Drawing.Point(400, 42);
this.lblIdleChargeSoc.Name = "lblIdleChargeSoc";
this.lblIdleChargeSoc.Size = new System.Drawing.Size(135, 20);
this.lblIdleChargeSoc.TabIndex = 2;
this.lblIdleChargeSoc.Text = "空闲充电电量 (%):";
//
// numMustChargeSoc
//
this.numMustChargeSoc.DecimalPlaces = 1;
this.numMustChargeSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.numMustChargeSoc.Location = new System.Drawing.Point(250, 40);
this.numMustChargeSoc.Name = "numMustChargeSoc";
this.numMustChargeSoc.Size = new System.Drawing.Size(120, 27);
this.numMustChargeSoc.TabIndex = 1;
//
// lblMustChargeSoc
//
this.lblMustChargeSoc.AutoSize = true;
this.lblMustChargeSoc.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblMustChargeSoc.Location = new System.Drawing.Point(30, 42);
this.lblMustChargeSoc.Name = "lblMustChargeSoc";
this.lblMustChargeSoc.Size = new System.Drawing.Size(99, 20);
this.lblMustChargeSoc.TabIndex = 0;
this.lblMustChargeSoc.Text = "必充电量 (%):";
//
// pnlBottom
//
this.pnlBottom.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250)))));
this.pnlBottom.Controls.Add(this.lblStatus);
this.pnlBottom.Controls.Add(this.btnApply);
this.pnlBottom.Controls.Add(this.btnRestoreDefaults);
this.pnlBottom.Controls.Add(this.btnCancel);
this.pnlBottom.Controls.Add(this.btnSave);
this.pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.pnlBottom.Location = new System.Drawing.Point(0, 631);
this.pnlBottom.Name = "pnlBottom";
this.pnlBottom.Size = new System.Drawing.Size(784, 70);
this.pnlBottom.TabIndex = 1;
//
// lblStatus
//
this.lblStatus.AutoSize = true;
this.lblStatus.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblStatus.Location = new System.Drawing.Point(20, 25);
this.lblStatus.Name = "lblStatus";
this.lblStatus.Size = new System.Drawing.Size(54, 20);
this.lblStatus.TabIndex = 4;
this.lblStatus.Text = "就绪...";
//
// btnApply
//
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnApply.Font = new System.Drawing.Font("微软雅黑", 9F);
this.btnApply.Location = new System.Drawing.Point(564, 18);
this.btnApply.Name = "btnApply";
this.btnApply.Size = new System.Drawing.Size(100, 35);
this.btnApply.TabIndex = 3;
this.btnApply.Text = "应用";
this.btnApply.UseVisualStyleBackColor = true;
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
//
// btnRestoreDefaults
//
this.btnRestoreDefaults.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnRestoreDefaults.Font = new System.Drawing.Font("微软雅黑", 9F);
this.btnRestoreDefaults.Location = new System.Drawing.Point(344, 18);
this.btnRestoreDefaults.Name = "btnRestoreDefaults";
this.btnRestoreDefaults.Size = new System.Drawing.Size(100, 35);
this.btnRestoreDefaults.TabIndex = 2;
this.btnRestoreDefaults.Text = "恢复默认";
this.btnRestoreDefaults.UseVisualStyleBackColor = true;
this.btnRestoreDefaults.Click += new System.EventHandler(this.btnRestoreDefaults_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 9F);
this.btnCancel.Location = new System.Drawing.Point(674, 18);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(100, 35);
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "取消";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnSave
//
this.btnSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnSave.Font = new System.Drawing.Font("微软雅黑", 9F);
this.btnSave.Location = new System.Drawing.Point(454, 18);
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(100, 35);
this.btnSave.TabIndex = 0;
this.btnSave.Text = "保存";
this.btnSave.UseVisualStyleBackColor = true;
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// ChargeStrategyConfigForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(784, 701);
this.Controls.Add(this.pnlMain);
this.Controls.Add(this.pnlBottom);
this.Name = "ChargeStrategyConfigForm";
this.Text = "充电策略配置";
this.pnlMain.ResumeLayout(false);
this.grpSwitchParams.ResumeLayout(false);
this.grpSwitchParams.PerformLayout();
this.grpTaskParams.ResumeLayout(false);
this.grpTaskParams.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.numMinAllowFreeCarToChargeTaskCnt)).EndInit();
this.grpTimeParams.ResumeLayout(false);
this.grpTimeParams.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.numTopUpMinutes)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numMustChargeSeconds)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numIdleSeconds)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numIdleChargeSeconds)).EndInit();
this.grpSocParams.ResumeLayout(false);
this.grpSocParams.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.numAllowInterruptSoc)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numFullChargeSoc)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numTaskAvailableSoc)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numIdleChargeSoc)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numMustChargeSoc)).EndInit();
this.pnlBottom.ResumeLayout(false);
this.pnlBottom.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel pnlMain;
private System.Windows.Forms.GroupBox grpSocParams;
private System.Windows.Forms.NumericUpDown numMustChargeSoc;
private System.Windows.Forms.Label lblMustChargeSoc;
private System.Windows.Forms.NumericUpDown numIdleChargeSoc;
private System.Windows.Forms.Label lblIdleChargeSoc;
private System.Windows.Forms.NumericUpDown numTaskAvailableSoc;
private System.Windows.Forms.Label lblTaskAvailableSoc;
private System.Windows.Forms.NumericUpDown numFullChargeSoc;
private System.Windows.Forms.Label lblFullChargeSoc;
private System.Windows.Forms.NumericUpDown numAllowInterruptSoc;
private System.Windows.Forms.Label lblAllowInterruptSoc;
private System.Windows.Forms.GroupBox grpTimeParams;
private System.Windows.Forms.NumericUpDown numIdleChargeSeconds;
private System.Windows.Forms.Label lblIdleChargeSeconds;
private System.Windows.Forms.NumericUpDown numIdleSeconds;
private System.Windows.Forms.Label lblIdleSeconds;
private System.Windows.Forms.NumericUpDown numMustChargeSeconds;
private System.Windows.Forms.Label lblMustChargeSeconds;
private System.Windows.Forms.NumericUpDown numTopUpMinutes;
private System.Windows.Forms.Label lblTopUpMinutes;
private System.Windows.Forms.GroupBox grpTaskParams;
private System.Windows.Forms.NumericUpDown numMinAllowFreeCarToChargeTaskCnt;
private System.Windows.Forms.Label lblMinAllowFreeCarToChargeTaskCnt;
private System.Windows.Forms.GroupBox grpSwitchParams;
private System.Windows.Forms.CheckBox chkAllowInterruptTask;
private System.Windows.Forms.CheckBox chkUseLowerSocForCharge;
private System.Windows.Forms.CheckBox chkEnableErrorChargeDetection;
private System.Windows.Forms.CheckBox chkUseChargeSiteFilter;
private System.Windows.Forms.Panel pnlBottom;
private System.Windows.Forms.Button btnSave;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnRestoreDefaults;
private System.Windows.Forms.Button btnApply;
private System.Windows.Forms.Label lblStatus;
}
}
@@ -1,215 +1,259 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using CycleGUI;
using StandardScene.Utils;
namespace StandardScene.Charge
{
/// <summary>
/// 充电策略配置窗体
/// 充电策略配置界面(CycleGUI 版,替代原 WinForms 窗体)。
/// </summary>
public partial class ChargeStrategyConfigForm : Form
public class ChargeStrategyConfigForm
{
private ChargeStrategyConfig config;
private ChargeStrategyConfigService configService;
private static Panel _panel;
private static readonly ChargeStrategyConfigService ConfigService = ChargeStrategyConfigService.Instance;
public ChargeStrategyConfigForm()
private static ChargeStrategyConfig _config;
private static string _status = "";
// SOC 参数
private static float _mustChargeSoc;
private static float _idleChargeSoc;
private static float _taskAvailableSoc;
private static float _fullChargeSoc;
private static float _allowInterruptSoc;
// 时间参数
private static float _idleChargeSeconds;
private static float _idleSeconds;
private static float _mustChargeSeconds;
private static float _topUpMinutes;
// 任务参数
private static int _minAllowFreeCarToChargeTaskCnt;
// 开关参数
private static bool _allowInterruptTask;
private static bool _useLowerSocForCharge;
private static bool _enableErrorChargeDetection;
private static bool _useChargeSiteFilter;
/// <summary>打开(或置前)充电策略配置面板。兼容原 <c>new ChargeStrategyConfigForm().Show()</c> 调用方式。</summary>
public void Show() => Open();
/// <summary>打开(或置前)充电策略配置面板。</summary>
public static void Open()
{
InitializeComponent();
configService = ChargeStrategyConfigService.Instance;
InitializeForm();
}
private void InitializeForm()
{
this.Text = "充电策略配置";
this.Size = new Size(800, 700);
this.StartPosition = FormStartPosition.CenterScreen;
this.MinimumSize = new Size(700, 600);
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
// 加载配置
LoadConfig();
}
/// <summary>
/// 加载配置到界面
/// </summary>
private void LoadConfig(bool isDef = false)
{
try
if (_panel != null)
{
if (!isDef)
try
{
config = configService.LoadConfig();
_panel.BringToFront();
return;
}
catch
{
_panel = null;
}
// SOC 相关参数
numMustChargeSoc.Value = (decimal)config.MustChargeSoc;
numIdleChargeSoc.Value = (decimal)config.IdleChargeSoc;
numTaskAvailableSoc.Value = (decimal)config.TaskAvailableSoc;
numFullChargeSoc.Value = (decimal)config.FullChargeSoc;
numAllowInterruptSoc.Value = (decimal)config.AllowInterruptSoc;
// 时间相关参数
numIdleChargeSeconds.Value = (decimal)config.IdleChargeSeconds;
numIdleSeconds.Value = (decimal)config.IdleSeconds;
numMustChargeSeconds.Value = (decimal)config.MustChargeSeconds;
numTopUpMinutes.Value = (decimal)config.TopUpMinutes;
// 任务相关参数
numMinAllowFreeCarToChargeTaskCnt.Value = config.MinAllowFreeCarToChargeTaskCnt;
// 开关参数
chkAllowInterruptTask.Checked = config.AllowInterruptTask;
chkUseLowerSocForCharge.Checked = config.UseLowerSocForCharge;
chkEnableErrorChargeDetection.Checked = config.EnableErrorChargeDetection;
chkUseChargeSiteFilter.Checked = config.UseChargeSiteFilter;
lblStatus.Text = "配置加载成功";
lblStatus.ForeColor = Color.Green;
}
catch (Exception ex)
if (!TryLoadConfig())
return;
var panel = GUI.DeclarePanel()
.ShowTitle("充电策略配置")
.SetDefaultDocking(Panel.Docking.None)
.InitSize(780, 680)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
_panel = panel;
panel.IfTerminalQuit(() => _panel = null);
panel.Define(pb =>
{
MessageBox.Show($"加载配置失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
lblStatus.Text = "配置加载失败";
lblStatus.ForeColor = Color.Red;
}
if (pb.Closing())
{
panel.Exit();
_panel = null;
return;
}
pb.SeparatorText("SOC 参数 (电量百分比)");
pb.DragFloat("1. 必充电量 (%)", ref _mustChargeSoc, step: 0.1f, min: 0, max: 100);
pb.DragFloat("2. 空闲充电电量 (%)", ref _idleChargeSoc, step: 0.1f, min: 0, max: 100);
pb.DragFloat("3. 任务可用电量 (%)", ref _taskAvailableSoc, step: 0.1f, min: 0, max: 100);
pb.DragFloat("4. 满电电量 (%)", ref _fullChargeSoc, step: 0.1f, min: 0, max: 100);
pb.DragFloat("5. 允许中断电量 (%)", ref _allowInterruptSoc, step: 0.1f, min: 0, max: 100);
pb.SeparatorText("时间参数");
pb.DragFloat("6. 空闲充电时间 (秒)", ref _idleChargeSeconds, step: 0.1f, min: 0, max: 10000);
pb.DragFloat("7. 空闲时间 (秒)", ref _idleSeconds, step: 0.1f, min: 0, max: 10000);
pb.DragFloat("8. 必充时间 (秒)", ref _mustChargeSeconds, step: 0.1f, min: 0, max: 10000);
pb.DragFloat("9. 补电时间 (分钟)", ref _topUpMinutes, step: 0.1f, min: 0, max: 1000);
pb.SeparatorText("任务参数");
pb.SliderInt("10. 允许空闲车充电的最小任务数", ref _minAllowFreeCarToChargeTaskCnt, min: 0, max: 100);
pb.SeparatorText("开关参数");
pb.CheckBox("11. 允许中断充电任务", ref _allowInterruptTask);
pb.CheckBox("12. 优先使用低电量车辆充电", ref _useLowerSocForCharge);
pb.CheckBox("13. 启用充电错误检测", ref _enableErrorChargeDetection);
pb.CheckBox("14. 使用充电站点筛选", ref _useChargeSiteFilter);
pb.Separator();
if (!string.IsNullOrEmpty(_status))
pb.Label(_status);
pb.Separator();
if (pb.Button("保存", distinct: "charge-strategy-save"))
TrySave(closeAfterSave: false);
pb.SameLine(8);
if (pb.Button("应用", distinct: "charge-strategy-apply"))
TrySave(closeAfterSave: false);
pb.SameLine(8);
if (pb.Button("恢复默认", distinct: "charge-strategy-restore"))
RestoreDefaults();
pb.SameLine(8);
if (pb.Button("取消", distinct: "charge-strategy-cancel"))
{
panel.Exit();
_panel = null;
}
});
}
/// <summary>
/// 从界面保存配置
/// </summary>
private void SaveConfig()
private static bool TryLoadConfig()
{
try
{
// SOC 相关参数
config.MustChargeSoc = (double)numMustChargeSoc.Value;
config.IdleChargeSoc = (double)numIdleChargeSoc.Value;
config.TaskAvailableSoc = (double)numTaskAvailableSoc.Value;
config.FullChargeSoc = (double)numFullChargeSoc.Value;
config.AllowInterruptSoc = (double)numAllowInterruptSoc.Value;
// 时间相关参数
config.IdleChargeSeconds = (double)numIdleChargeSeconds.Value;
config.IdleSeconds = (double)numIdleSeconds.Value;
config.MustChargeSeconds = (double)numMustChargeSeconds.Value;
config.TopUpMinutes = (double)numTopUpMinutes.Value;
// 任务相关参数
config.MinAllowFreeCarToChargeTaskCnt = (int)numMinAllowFreeCarToChargeTaskCnt.Value;
// 开关参数
config.AllowInterruptTask = chkAllowInterruptTask.Checked;
config.UseLowerSocForCharge = chkUseLowerSocForCharge.Checked;
config.EnableErrorChargeDetection = chkEnableErrorChargeDetection.Checked;
config.UseChargeSiteFilter = chkUseChargeSiteFilter.Checked;
// 保存到文件
configService.SaveConfig(config);
lblStatus.Text = "配置保存成功";
lblStatus.ForeColor = Color.Green;
MessageBox.Show("充电策略配置保存成功!", "成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
_config = ConfigService.LoadConfig();
ApplyConfigToUi(_config);
_status = "配置加载成功";
return true;
}
catch (Exception ex)
{
MessageBox.Show($"保存配置失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
lblStatus.Text = "配置保存失败";
lblStatus.ForeColor = Color.Red;
CycleUiHelper.Alert("错误", $"加载配置失败: {ex.Message}");
_status = "配置加载失败";
return false;
}
}
/// <summary>
/// 恢复默认配置
/// </summary>
private void RestoreDefaults()
private static void ApplyConfigToUi(ChargeStrategyConfig config)
{
var result = MessageBox.Show(
"确定要恢复默认配置吗?当前配置将被覆盖。",
"确认恢复",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
_mustChargeSoc = (float)config.MustChargeSoc;
_idleChargeSoc = (float)config.IdleChargeSoc;
_taskAvailableSoc = (float)config.TaskAvailableSoc;
_fullChargeSoc = (float)config.FullChargeSoc;
_allowInterruptSoc = (float)config.AllowInterruptSoc;
if (result == DialogResult.Yes)
{
config = ChargeStrategyConfig.CreateDefault();
LoadConfig(true);
lblStatus.Text = "已恢复默认配置(未保存)";
lblStatus.ForeColor = Color.Blue;
}
_idleChargeSeconds = (float)config.IdleChargeSeconds;
_idleSeconds = (float)config.IdleSeconds;
_mustChargeSeconds = (float)config.MustChargeSeconds;
_topUpMinutes = (float)config.TopUpMinutes;
_minAllowFreeCarToChargeTaskCnt = config.MinAllowFreeCarToChargeTaskCnt;
_allowInterruptTask = config.AllowInterruptTask;
_useLowerSocForCharge = config.UseLowerSocForCharge;
_enableErrorChargeDetection = config.EnableErrorChargeDetection;
_useChargeSiteFilter = config.UseChargeSiteFilter;
}
/// <summary>
/// 验证配置参数
/// </summary>
private bool ValidateConfig()
private static void ApplyUiToConfig()
{
// 验证 SOC 范围
if (numMustChargeSoc.Value >= numIdleChargeSoc.Value)
_config.MustChargeSoc = _mustChargeSoc;
_config.IdleChargeSoc = _idleChargeSoc;
_config.TaskAvailableSoc = _taskAvailableSoc;
_config.FullChargeSoc = _fullChargeSoc;
_config.AllowInterruptSoc = _allowInterruptSoc;
_config.IdleChargeSeconds = _idleChargeSeconds;
_config.IdleSeconds = _idleSeconds;
_config.MustChargeSeconds = _mustChargeSeconds;
_config.TopUpMinutes = _topUpMinutes;
_config.MinAllowFreeCarToChargeTaskCnt = _minAllowFreeCarToChargeTaskCnt;
_config.AllowInterruptTask = _allowInterruptTask;
_config.UseLowerSocForCharge = _useLowerSocForCharge;
_config.EnableErrorChargeDetection = _enableErrorChargeDetection;
_config.UseChargeSiteFilter = _useChargeSiteFilter;
}
/// <summary>验证 SOC 阈值之间的逻辑关系(保存前)。</summary>
private static bool ValidateSocRanges(out string errorMessage)
{
if (_mustChargeSoc >= _idleChargeSoc)
{
MessageBox.Show("必充电量必须小于空闲充电电量", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
errorMessage = "必充电量必须小于空闲充电电量";
return false;
}
if (numTaskAvailableSoc.Value <= numMustChargeSoc.Value)
if (_taskAvailableSoc <= _mustChargeSoc)
{
MessageBox.Show("任务可用电量必须大于必充电量", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
errorMessage = "任务可用电量必须大于必充电量";
return false;
}
if (numFullChargeSoc.Value < numIdleChargeSoc.Value)
if (_fullChargeSoc < _idleChargeSoc)
{
MessageBox.Show("满电电量必须大于等于空闲充电电量", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
errorMessage = "满电电量必须大于等于空闲充电电量";
return false;
}
if (numAllowInterruptSoc.Value <= numMustChargeSoc.Value)
if (_allowInterruptSoc <= _mustChargeSoc)
{
MessageBox.Show("允许中断电量必须大于必充电量", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
errorMessage = "允许中断电量必须大于必充电量";
return false;
}
errorMessage = string.Empty;
return true;
}
// ==================== 事件处理 ====================
private void btnSave_Click(object sender, EventArgs e)
private static void TrySave(bool closeAfterSave)
{
if (ValidateConfig())
ApplyUiToConfig();
if (!ValidateSocRanges(out var socError))
{
SaveConfig();
CycleUiHelper.Alert("验证失败", socError);
_status = "配置保存失败";
_panel?.Repaint();
return;
}
try
{
ConfigService.SaveConfig(_config);
_status = "配置保存成功";
CycleUiHelper.Alert("成功", "充电策略配置保存成功!");
if (closeAfterSave)
{
_panel?.Exit();
_panel = null;
}
else
{
_panel?.Repaint();
}
}
catch (Exception ex)
{
CycleUiHelper.Alert("错误", $"保存配置失败: {ex.Message}");
_status = "配置保存失败";
_panel?.Repaint();
}
}
private void btnCancel_Click(object sender, EventArgs e)
private static void RestoreDefaults()
{
this.Close();
}
private void btnRestoreDefaults_Click(object sender, EventArgs e)
{
RestoreDefaults();
}
private void btnApply_Click(object sender, EventArgs e)
{
if (ValidateConfig())
CycleUiHelper.ConfirmThen("确定要恢复默认配置吗?当前配置将被覆盖。", () =>
{
SaveConfig();
}
_config = ChargeStrategyConfig.CreateDefault();
ApplyConfigToUi(_config);
_status = "已恢复默认配置(未保存)";
_panel?.Repaint();
});
}
}
}
@@ -1,376 +0,0 @@
namespace StandardScene.Charge
{
partial class CommunicationMonitorForm
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
this.splitContainer = new System.Windows.Forms.SplitContainer();
this.pnlLeft = new System.Windows.Forms.Panel();
this.dgvMessages = new System.Windows.Forms.DataGridView();
this.colTime = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colDirection = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colIpAddress = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colPort = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colLength = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colRawData = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colStationId = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.type = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.pnlLeftTop = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.btnClear = new System.Windows.Forms.Button();
this.btnRefresh = new System.Windows.Forms.Button();
this.lblStatistics = new System.Windows.Forms.Label();
this.cmbIpFilter = new System.Windows.Forms.ComboBox();
this.lblIpFilter = new System.Windows.Forms.Label();
this.pnlRight = new System.Windows.Forms.Panel();
this.txtParsedData = new System.Windows.Forms.TextBox();
this.pnlRightTop = new System.Windows.Forms.Panel();
this.btnClose = new System.Windows.Forms.Button();
this.lblParsedTitle = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout();
this.splitContainer.Panel2.SuspendLayout();
this.splitContainer.SuspendLayout();
this.pnlLeft.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dgvMessages)).BeginInit();
this.pnlLeftTop.SuspendLayout();
this.pnlRight.SuspendLayout();
this.pnlRightTop.SuspendLayout();
this.SuspendLayout();
//
// splitContainer
//
this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer.Location = new System.Drawing.Point(0, 0);
this.splitContainer.Name = "splitContainer";
//
// splitContainer.Panel1
//
this.splitContainer.Panel1.Controls.Add(this.pnlLeft);
//
// splitContainer.Panel2
//
this.splitContainer.Panel2.Controls.Add(this.pnlRight);
this.splitContainer.Size = new System.Drawing.Size(1400, 800);
this.splitContainer.SplitterDistance = 850;
this.splitContainer.TabIndex = 0;
//
// pnlLeft
//
this.pnlLeft.Controls.Add(this.dgvMessages);
this.pnlLeft.Controls.Add(this.pnlLeftTop);
this.pnlLeft.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlLeft.Location = new System.Drawing.Point(0, 0);
this.pnlLeft.Name = "pnlLeft";
this.pnlLeft.Size = new System.Drawing.Size(850, 800);
this.pnlLeft.TabIndex = 0;
//
// dgvMessages
//
this.dgvMessages.AllowUserToAddRows = false;
this.dgvMessages.AllowUserToDeleteRows = false;
this.dgvMessages.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dgvMessages.BackgroundColor = System.Drawing.Color.White;
this.dgvMessages.BorderStyle = System.Windows.Forms.BorderStyle.None;
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(63)))), ((int)(((byte)(81)))), ((int)(((byte)(181)))));
dataGridViewCellStyle1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
dataGridViewCellStyle1.ForeColor = System.Drawing.Color.White;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dgvMessages.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.dgvMessages.ColumnHeadersHeight = 35;
this.dgvMessages.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.colTime,
this.colDirection,
this.colIpAddress,
this.colPort,
this.colLength,
this.colRawData,
this.colStationId,
this.type});
this.dgvMessages.Dock = System.Windows.Forms.DockStyle.Fill;
this.dgvMessages.EnableHeadersVisualStyles = false;
this.dgvMessages.GridColor = System.Drawing.Color.LightGray;
this.dgvMessages.Location = new System.Drawing.Point(0, 80);
this.dgvMessages.MultiSelect = false;
this.dgvMessages.Name = "dgvMessages";
this.dgvMessages.ReadOnly = true;
this.dgvMessages.RowHeadersVisible = false;
this.dgvMessages.RowHeadersWidth = 51;
this.dgvMessages.RowTemplate.Height = 30;
this.dgvMessages.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.dgvMessages.Size = new System.Drawing.Size(850, 720);
this.dgvMessages.TabIndex = 1;
this.dgvMessages.SelectionChanged += new System.EventHandler(this.dgvMessages_SelectionChanged);
//
// colTime
//
this.colTime.FillWeight = 80F;
this.colTime.HeaderText = "时间";
this.colTime.MinimumWidth = 6;
this.colTime.Name = "colTime";
this.colTime.ReadOnly = true;
//
// colDirection
//
this.colDirection.FillWeight = 50F;
this.colDirection.HeaderText = "方向";
this.colDirection.MinimumWidth = 6;
this.colDirection.Name = "colDirection";
this.colDirection.ReadOnly = true;
//
// colIpAddress
//
this.colIpAddress.FillWeight = 80F;
this.colIpAddress.HeaderText = "IP地址";
this.colIpAddress.MinimumWidth = 6;
this.colIpAddress.Name = "colIpAddress";
this.colIpAddress.ReadOnly = true;
//
// colPort
//
this.colPort.FillWeight = 50F;
this.colPort.HeaderText = "端口";
this.colPort.MinimumWidth = 6;
this.colPort.Name = "colPort";
this.colPort.ReadOnly = true;
//
// colLength
//
this.colLength.FillWeight = 50F;
this.colLength.HeaderText = "长度";
this.colLength.MinimumWidth = 6;
this.colLength.Name = "colLength";
this.colLength.ReadOnly = true;
//
// colRawData
//
this.colRawData.FillWeight = 200F;
this.colRawData.HeaderText = "原始数据";
this.colRawData.MinimumWidth = 6;
this.colRawData.Name = "colRawData";
this.colRawData.ReadOnly = true;
//
// colStationId
//
this.colStationId.FillWeight = 80F;
this.colStationId.HeaderText = "充电桩";
this.colStationId.MinimumWidth = 6;
this.colStationId.Name = "colStationId";
this.colStationId.ReadOnly = true;
//
// type
//
this.type.HeaderText = "协议类型";
this.type.MinimumWidth = 6;
this.type.Name = "type";
this.type.ReadOnly = true;
//
// pnlLeftTop
//
this.pnlLeftTop.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250)))));
this.pnlLeftTop.Controls.Add(this.button1);
this.pnlLeftTop.Controls.Add(this.btnClear);
this.pnlLeftTop.Controls.Add(this.btnRefresh);
this.pnlLeftTop.Controls.Add(this.lblStatistics);
this.pnlLeftTop.Controls.Add(this.cmbIpFilter);
this.pnlLeftTop.Controls.Add(this.lblIpFilter);
this.pnlLeftTop.Dock = System.Windows.Forms.DockStyle.Top;
this.pnlLeftTop.Location = new System.Drawing.Point(0, 0);
this.pnlLeftTop.Name = "pnlLeftTop";
this.pnlLeftTop.Padding = new System.Windows.Forms.Padding(10);
this.pnlLeftTop.Size = new System.Drawing.Size(850, 80);
this.pnlLeftTop.TabIndex = 0;
//
// button1
//
this.button1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.button1.Location = new System.Drawing.Point(546, 16);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(80, 32);
this.button1.TabIndex = 5;
this.button1.Text = "暂停";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// btnClear
//
this.btnClear.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnClear.Location = new System.Drawing.Point(460, 15);
this.btnClear.Name = "btnClear";
this.btnClear.Size = new System.Drawing.Size(80, 32);
this.btnClear.TabIndex = 4;
this.btnClear.Text = "清空";
this.btnClear.UseVisualStyleBackColor = true;
this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
//
// btnRefresh
//
this.btnRefresh.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnRefresh.Location = new System.Drawing.Point(370, 15);
this.btnRefresh.Name = "btnRefresh";
this.btnRefresh.Size = new System.Drawing.Size(80, 32);
this.btnRefresh.TabIndex = 3;
this.btnRefresh.Text = "刷新";
this.btnRefresh.UseVisualStyleBackColor = true;
this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
//
// lblStatistics
//
this.lblStatistics.AutoSize = true;
this.lblStatistics.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblStatistics.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(100)))), ((int)(((byte)(100)))));
this.lblStatistics.Location = new System.Drawing.Point(13, 52);
this.lblStatistics.Name = "lblStatistics";
this.lblStatistics.Size = new System.Drawing.Size(115, 20);
this.lblStatistics.TabIndex = 2;
this.lblStatistics.Text = "显示: 0 | 总数: 0";
//
// cmbIpFilter
//
this.cmbIpFilter.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbIpFilter.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.cmbIpFilter.FormattingEnabled = true;
this.cmbIpFilter.Location = new System.Drawing.Point(100, 17);
this.cmbIpFilter.Name = "cmbIpFilter";
this.cmbIpFilter.Size = new System.Drawing.Size(250, 28);
this.cmbIpFilter.TabIndex = 1;
this.cmbIpFilter.SelectedIndexChanged += new System.EventHandler(this.cmbIpFilter_SelectedIndexChanged);
//
// lblIpFilter
//
this.lblIpFilter.AutoSize = true;
this.lblIpFilter.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblIpFilter.Location = new System.Drawing.Point(13, 21);
this.lblIpFilter.Name = "lblIpFilter";
this.lblIpFilter.Size = new System.Drawing.Size(67, 20);
this.lblIpFilter.TabIndex = 0;
this.lblIpFilter.Text = "IP筛选:";
//
// pnlRight
//
this.pnlRight.Controls.Add(this.txtParsedData);
this.pnlRight.Controls.Add(this.pnlRightTop);
this.pnlRight.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlRight.Location = new System.Drawing.Point(0, 0);
this.pnlRight.Name = "pnlRight";
this.pnlRight.Size = new System.Drawing.Size(546, 800);
this.pnlRight.TabIndex = 0;
//
// txtParsedData
//
this.txtParsedData.BackColor = System.Drawing.Color.White;
this.txtParsedData.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtParsedData.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtParsedData.Location = new System.Drawing.Point(0, 60);
this.txtParsedData.Multiline = true;
this.txtParsedData.Name = "txtParsedData";
this.txtParsedData.ReadOnly = true;
this.txtParsedData.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtParsedData.Size = new System.Drawing.Size(546, 740);
this.txtParsedData.TabIndex = 1;
this.txtParsedData.WordWrap = false;
//
// pnlRightTop
//
this.pnlRightTop.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250)))));
this.pnlRightTop.Controls.Add(this.btnClose);
this.pnlRightTop.Controls.Add(this.lblParsedTitle);
this.pnlRightTop.Dock = System.Windows.Forms.DockStyle.Top;
this.pnlRightTop.Location = new System.Drawing.Point(0, 0);
this.pnlRightTop.Name = "pnlRightTop";
this.pnlRightTop.Padding = new System.Windows.Forms.Padding(10);
this.pnlRightTop.Size = new System.Drawing.Size(546, 60);
this.pnlRightTop.TabIndex = 0;
//
// btnClose
//
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btnClose.Location = new System.Drawing.Point(446, 15);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(80, 32);
this.btnClose.TabIndex = 1;
this.btnClose.Text = "关闭";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// lblParsedTitle
//
this.lblParsedTitle.AutoSize = true;
this.lblParsedTitle.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblParsedTitle.Location = new System.Drawing.Point(13, 20);
this.lblParsedTitle.Name = "lblParsedTitle";
this.lblParsedTitle.Size = new System.Drawing.Size(112, 24);
this.lblParsedTitle.TabIndex = 0;
this.lblParsedTitle.Text = "报文数据解析";
//
// CommunicationMonitorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1400, 800);
this.Controls.Add(this.splitContainer);
this.Name = "CommunicationMonitorForm";
this.Text = "通讯监控";
this.Load += new System.EventHandler(this.CommunicationMonitorForm_Load);
this.splitContainer.Panel1.ResumeLayout(false);
this.splitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
this.splitContainer.ResumeLayout(false);
this.pnlLeft.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.dgvMessages)).EndInit();
this.pnlLeftTop.ResumeLayout(false);
this.pnlLeftTop.PerformLayout();
this.pnlRight.ResumeLayout(false);
this.pnlRight.PerformLayout();
this.pnlRightTop.ResumeLayout(false);
this.pnlRightTop.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.SplitContainer splitContainer;
private System.Windows.Forms.Panel pnlLeft;
private System.Windows.Forms.DataGridView dgvMessages;
private System.Windows.Forms.Panel pnlLeftTop;
private System.Windows.Forms.ComboBox cmbIpFilter;
private System.Windows.Forms.Label lblIpFilter;
private System.Windows.Forms.Panel pnlRight;
private System.Windows.Forms.TextBox txtParsedData;
private System.Windows.Forms.Panel pnlRightTop;
private System.Windows.Forms.Label lblParsedTitle;
private System.Windows.Forms.Label lblStatistics;
private System.Windows.Forms.Button btnRefresh;
private System.Windows.Forms.Button btnClear;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.DataGridViewTextBoxColumn colTime;
private System.Windows.Forms.DataGridViewTextBoxColumn colDirection;
private System.Windows.Forms.DataGridViewTextBoxColumn colIpAddress;
private System.Windows.Forms.DataGridViewTextBoxColumn colPort;
private System.Windows.Forms.DataGridViewTextBoxColumn colLength;
private System.Windows.Forms.DataGridViewTextBoxColumn colRawData;
private System.Windows.Forms.DataGridViewTextBoxColumn colStationId;
private System.Windows.Forms.DataGridViewTextBoxColumn type;
private System.Windows.Forms.Button button1;
}
}
@@ -2,108 +2,298 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Text;
using CycleGUI;
using StandardScene.Utils;
namespace StandardScene.Charge
{
/// <summary>
/// 通讯监控窗体
/// 通讯监控面板(CycleGUI 版,替代原 WinForms 窗体)。
/// <list type="bullet">
/// <item>单实例:再次打开则把已有面板置前。</item>
/// <item>订阅 <see cref="CommunicationMessageService.MessageAdded"/>,批量刷新 UI500ms 节流),最多显示 100 行。</item>
/// <item>支持 IP 筛选、暂停/继续、清空(二次确认)、选中报文解析详情。</item>
/// </list>
/// 保留可实例化 + <see cref="Show"/> 以兼容既有调用。
/// </summary>
public partial class CommunicationMonitorForm : Form
public class CommunicationMonitorForm
{
private readonly CommunicationMessageService messageService;
private bool isFormLoaded = false;
private bool isFormMessageStop = false;
private const int MaxDisplayRows = 100;
private const int UiBatchSize = 20;
private const int StatsRefreshMs = 500;
private readonly Queue<CommunicationMessage> pendingMessages = new Queue<CommunicationMessage>();
private readonly object pendingMessagesLock = new object();
private readonly Timer uiFlushTimer;
private readonly Timer statsRefreshTimer;
private bool pendingStatsRefresh = false;
private int lastDisplayCountForStats = 0;
public CommunicationMonitorForm()
{
InitializeComponent();
messageService = CommunicationMessageService.Instance;
uiFlushTimer = new Timer { Interval = 500 };
uiFlushTimer.Tick += UiFlushTimer_Tick;
statsRefreshTimer = new Timer { Interval = StatsRefreshMs };
statsRefreshTimer.Tick += StatsRefreshTimer_Tick;
private const string TableId = "comm-monitor-msgs";
// 订阅窗体关闭事件
this.FormClosing += CommunicationMonitorForm_FormClosing;
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 static 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 static List<CommunicationMessage> _displayMessages = new List<CommunicationMessage>();
private static readonly Queue<CommunicationMessage> PendingMessages = new Queue<CommunicationMessage>();
private static readonly object PendingLock = new object();
private static DateTime _lastStatsRefresh = DateTime.MinValue;
private static bool _pendingStatsRefresh;
/// <summary>打开(或置前)通讯监控面板。兼容原 <c>new CommunicationMonitorForm().Show()</c> 调用方式。</summary>
public void Show() => Open();
/// <summary>打开(或置前)通讯监控面板。</summary>
public static void Open()
{
if (_panel != null)
{
try
{
_panel.BringToFront();
return;
}
catch
{
_panel = null;
}
}
_paused = false;
_selectedRowIndex = -1;
_parsedText = "";
RefreshIpFilter();
ReloadFromService();
var panel = GUI.DeclarePanel()
.ShowTitle("通讯监控")
.SetDefaultDocking(Panel.Docking.None)
.InitSize(1400, 800)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
_panel = panel;
panel.IfTerminalQuit(() =>
{
Unsubscribe();
_panel = null;
});
Subscribe();
panel.Define(pb =>
{
if (pb.Closing())
{
Unsubscribe();
panel.Exit();
_panel = null;
return;
}
FlushPendingBatch();
if (pb.DropdownBox("IP筛选", _ipOptions, ref _selectedIpIndex))
ReloadFromService();
pb.SameLine(16);
if (pb.Button(_paused ? "继续" : "暂停", distinct: "comm-pause"))
_paused = !_paused;
pb.SameLine(8);
if (pb.Button("刷新", distinct: "comm-refresh"))
{
RefreshIpFilter();
ReloadFromService();
RequestStatisticsRefresh();
}
pb.SameLine(8);
if (pb.Button("清空", distinct: "comm-clear"))
{
CycleUiHelper.ConfirmThen("确定要清空所有报文记录吗?", () =>
{
MessageService.Clear();
lock (PendingLock)
PendingMessages.Clear();
RefreshIpFilter();
_displayMessages.Clear();
_selectedRowIndex = -1;
_parsedText = "";
RequestStatisticsRefresh();
});
}
pb.SameLine(8);
if (pb.Button("关闭", distinct: "comm-close"))
{
Unsubscribe();
panel.Exit();
_panel = null;
return;
}
MaybeRefreshStatistics();
pb.Label(_statsText);
pb.Table(TableId,
new[] { "时间", "方向", "IP地址", "端口", "长度", "原始数据", "站点", "类型", "操作" },
_displayMessages.Count, (row, i) =>
{
var msg = _displayMessages[i];
row.SetColor(_selectedRowIndex == i
? SelectedRowColor
: msg.Direction == MessageDirection.Send ? SendRowColor : ReceiveRowColor);
row.Label($"{msg.Timestamp:HH:mm:ss.fff}");
row.Label(msg.Direction == MessageDirection.Send ? "发送" : "接收");
row.Label(msg.IpAddress ?? "");
row.Label($"{msg.Port}");
row.Label($"{msg.Length}");
row.Label(TruncateRawData(msg.RawData));
row.Label(string.IsNullOrEmpty(msg.StationId) ? "-" : msg.StationId);
row.Label(msg.Type ?? "");
if (row.ButtonGroup(new[] { "解析" }, new[] { "解析该报文" }) == 0)
{
_selectedRowIndex = i;
_parsedText = BuildParsedText(msg);
}
}, height: 20, enableSearch: true);
pb.SeparatorText("报文解析");
pb.SelectableText(null, _parsedText ?? "", copyButton: true);
pb.Panel.Repaint(repaintTimeMs: 500);
});
}
private void CommunicationMonitorForm_Load(object sender, EventArgs e)
private static void Subscribe()
{
if (_subscribed)
return;
MessageService.MessageAdded += OnMessageAdded;
_subscribed = true;
}
private static void Unsubscribe()
{
if (!_subscribed)
return;
MessageService.MessageAdded -= OnMessageAdded;
_subscribed = false;
lock (PendingLock)
PendingMessages.Clear();
}
private static void OnMessageAdded(object sender, CommunicationMessage message)
{
if (!_subscribed || message == null)
return;
lock (PendingLock)
PendingMessages.Enqueue(message);
_panel?.Repaint();
}
/// <summary>定时批量刷新 UI,避免每条报文都抢占渲染线程。</summary>
private static void FlushPendingBatch()
{
if (_paused)
return;
List<CommunicationMessage> batch = null;
lock (PendingLock)
{
if (PendingMessages.Count == 0)
return;
int count = Math.Min(UiBatchSize, PendingMessages.Count);
batch = new List<CommunicationMessage>(count);
for (int i = 0; i < count; i++)
batch.Add(PendingMessages.Dequeue());
}
if (batch == null || batch.Count == 0)
return;
var filter = SelectedIpFilter();
bool displayChanged = false;
foreach (var message in batch)
{
EnsureIpInFilter(message.IpAddress);
if (string.IsNullOrEmpty(filter) || filter == "全部" || filter == message.IpAddress)
{
InsertMessageAtTop(message);
displayChanged = true;
}
}
if (displayChanged)
RequestStatisticsRefresh();
}
private static void InsertMessageAtTop(CommunicationMessage msg)
{
_displayMessages.Insert(0, msg);
while (_displayMessages.Count > MaxDisplayRows)
_displayMessages.RemoveAt(_displayMessages.Count - 1);
if (_selectedRowIndex >= 0)
_selectedRowIndex++;
}
private static void ReloadFromService()
{
try
{
InitializeForm();
LoadMessages();
var filter = SelectedIpFilter();
var messages = string.IsNullOrEmpty(filter) || filter == "全部"
? MessageService.GetAllMessages()
: MessageService.GetMessagesByIp(filter);
// 标记窗体已加载完成
isFormLoaded = true;
uiFlushTimer.Start();
statsRefreshTimer.Start();
// 在窗体加载完成后再订阅报文添加事件(避免在初始化期间触发)
messageService.MessageAdded += OnMessageAdded;
_displayMessages = messages.Take(MaxDisplayRows).ToList();
_selectedRowIndex = -1;
_parsedText = "";
_pendingStatsRefresh = false;
UpdateStatistics(_displayMessages.Count);
}
catch (Exception ex)
{
MessageBox.Show($"窗体加载失败: {ex.Message}\r\n{ex.StackTrace}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
_statsText = $"加载报文失败: {ex.Message}";
}
}
private void InitializeForm()
{
this.Text = "通讯监控";
this.Size = new Size(1400, 800);
this.StartPosition = FormStartPosition.CenterScreen;
this.MinimumSize = new Size(1200, 600);
// 初始化IP筛选下拉框
RefreshIpFilter();
}
/// <summary>
/// 刷新IP筛选下拉框
/// </summary>
private void RefreshIpFilter()
private static void RefreshIpFilter()
{
try
{
if (cmbIpFilter == null || messageService == null)
return;
var selectedIp = SelectedIpFilter();
var options = new List<string> { "全部" };
var selectedIp = cmbIpFilter.SelectedItem?.ToString();
cmbIpFilter.Items.Clear();
cmbIpFilter.Items.Add("全部");
var ipAddresses = messageService.GetUniqueIpAddresses();
var ipAddresses = MessageService.GetUniqueIpAddresses();
if (ipAddresses != null)
{
foreach (var ip in ipAddresses)
{
if (!string.IsNullOrEmpty(ip))
{
cmbIpFilter.Items.Add(ip);
}
options.Add(ip);
}
}
// 恢复选中项
if (!string.IsNullOrEmpty(selectedIp) && cmbIpFilter.Items.Contains(selectedIp))
_ipOptions = options.ToArray();
if (!string.IsNullOrEmpty(selectedIp))
{
cmbIpFilter.SelectedItem = selectedIp;
var idx = Array.IndexOf(_ipOptions, selectedIp);
_selectedIpIndex = idx >= 0 ? idx : 0;
}
else if (cmbIpFilter.Items.Count > 0)
else
{
cmbIpFilter.SelectedIndex = 0;
_selectedIpIndex = 0;
}
}
catch (Exception ex)
@@ -112,248 +302,83 @@ namespace StandardScene.Charge
}
}
/// <summary>
/// 加载报文列表
/// </summary>
private void LoadMessages()
private static void EnsureIpInFilter(string ipAddress)
{
var layoutSuspended = false;
try
{
if (dgvMessages == null|| isFormMessageStop)
return;
var selectedIp = cmbIpFilter?.SelectedItem?.ToString();
var messages = string.IsNullOrEmpty(selectedIp) || selectedIp == "全部"
? messageService.GetAllMessages()
: messageService.GetMessagesByIp(selectedIp);
dgvMessages.SuspendLayout();
layoutSuspended = true;
dgvMessages.Rows.Clear();
foreach (var msg in messages)
{
AddMessageRow(msg, false);
}
UpdateStatistics(messages.Count);
pendingStatsRefresh = false;
}
catch (Exception ex)
{
MessageBox.Show($"加载报文失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
if (layoutSuspended && dgvMessages != null)
{
dgvMessages.ResumeLayout();
}
}
}
/// <summary>
/// 定时批量刷新UI,避免每条报文都抢占UI线程
/// </summary>
private void UiFlushTimer_Tick(object sender, EventArgs e)
{
if (!isFormLoaded || isFormMessageStop)
if (string.IsNullOrWhiteSpace(ipAddress))
return;
List<CommunicationMessage> batch = null;
lock (pendingMessagesLock)
{
if (pendingMessages.Count == 0)
return;
int count = Math.Min(UiBatchSize, pendingMessages.Count);
batch = new List<CommunicationMessage>(count);
for (int i = 0; i < count; i++)
{
batch.Add(pendingMessages.Dequeue());
}
}
if (batch == null || batch.Count == 0)
if (_ipOptions.Contains(ipAddress))
return;
dgvMessages.SuspendLayout();
try
{
var selectedIp = cmbIpFilter?.SelectedItem?.ToString();
bool displayChanged = false;
foreach (var message in batch)
{
EnsureIpInFilter(message.IpAddress);
if (string.IsNullOrEmpty(selectedIp) || selectedIp == "全部" || selectedIp == message.IpAddress)
{
AddMessageRow(message, true);
displayChanged = true;
}
}
if (displayChanged)
{
RequestStatisticsRefresh(dgvMessages.Rows.Count);
}
}
finally
{
dgvMessages.ResumeLayout();
}
var list = _ipOptions.ToList();
list.Add(ipAddress);
_ipOptions = list.ToArray();
}
/// <summary>
/// 统计信息低频刷新(500ms
/// </summary>
private void StatsRefreshTimer_Tick(object sender, EventArgs e)
private static string SelectedIpFilter()
{
if (!isFormLoaded || isFormMessageStop || !pendingStatsRefresh)
if (_ipOptions == null || _ipOptions.Length == 0)
return "全部";
if (_selectedIpIndex < 0 || _selectedIpIndex >= _ipOptions.Length)
return "全部";
return _ipOptions[_selectedIpIndex];
}
private static void RequestStatisticsRefresh()
{
_pendingStatsRefresh = true;
}
/// <summary>统计信息低频刷新(500ms)。</summary>
private static void MaybeRefreshStatistics()
{
if (!_pendingStatsRefresh)
return;
if (DateTime.Now - _lastStatsRefresh < TimeSpan.FromMilliseconds(StatsRefreshMs))
return;
pendingStatsRefresh = false;
UpdateStatistics(lastDisplayCountForStats);
_pendingStatsRefresh = false;
_lastStatsRefresh = DateTime.Now;
UpdateStatistics(_displayMessages.Count);
}
private void RequestStatisticsRefresh(int displayCount)
{
lastDisplayCountForStats = displayCount;
pendingStatsRefresh = true;
}
private void EnsureIpInFilter(string ipAddress)
{
if (cmbIpFilter == null || string.IsNullOrWhiteSpace(ipAddress))
return;
if (!cmbIpFilter.Items.Contains(ipAddress))
{
cmbIpFilter.Items.Add(ipAddress);
}
}
/// <summary>
/// 向表格新增一条报文行(支持头部插入)
/// </summary>
private void AddMessageRow(CommunicationMessage msg, bool insertAtTop = true)
{
if (msg == null || dgvMessages == null)
return;
DataGridViewRow row;
if (insertAtTop)
{
dgvMessages.Rows.Insert(0,
msg.Timestamp.ToString("HH:mm:ss.fff"),
msg.Direction == MessageDirection.Send ? "发送" : "接收",
msg.IpAddress,
msg.Port,
msg.Length,
msg.RawData,
msg.StationId ?? "-",
msg.Type);
row = dgvMessages.Rows[0];
}
else
{
var index = dgvMessages.Rows.Add(
msg.Timestamp.ToString("HH:mm:ss.fff"),
msg.Direction == MessageDirection.Send ? "发送" : "接收",
msg.IpAddress,
msg.Port,
msg.Length,
msg.RawData,
msg.StationId ?? "-",
msg.Type);
row = dgvMessages.Rows[index];
}
if (msg.Direction == MessageDirection.Send)
{
row.DefaultCellStyle.BackColor = Color.FromArgb(232, 245, 233);
row.DefaultCellStyle.ForeColor = Color.FromArgb(46, 125, 50);
}
else
{
row.DefaultCellStyle.BackColor = Color.FromArgb(227, 242, 253);
row.DefaultCellStyle.ForeColor = Color.FromArgb(13, 71, 161);
}
while (dgvMessages.Rows.Count > MaxDisplayRows)
{
dgvMessages.Rows.RemoveAt(dgvMessages.Rows.Count - 1);
}
}
/// <summary>
/// 更新统计信息
/// </summary>
private void UpdateStatistics(int displayCount)
private static void UpdateStatistics(int displayCount)
{
try
{
if (lblStatistics == null || messageService == null)
return;
var allMessages = messageService.GetAllMessages();
var allMessages = MessageService.GetAllMessages();
if (allMessages == null)
{
_statsText = "统计信息加载失败";
return;
}
var sendCount = allMessages.Count(m => m.Direction == MessageDirection.Send);
var receiveCount = allMessages.Count(m => m.Direction == MessageDirection.Receive);
lblStatistics.Text = $"显示: {displayCount} | 总数: {allMessages.Count} | 发送: {sendCount} | 接收: {receiveCount}";
_statsText = $"显示: {displayCount} | 总数: {allMessages.Count} | 发送: {sendCount} | 接收: {receiveCount}";
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"更新统计信息失败: {ex.Message}");
if (lblStatistics != null)
{
lblStatistics.Text = "统计信息加载失败";
}
_statsText = "统计信息加载失败";
}
}
/// <summary>
/// 新报文添加事件处理(线程安全)
/// </summary>
private void OnMessageAdded(object sender, CommunicationMessage message)
private static string TruncateRawData(string rawData, int maxLen = 48)
{
// 如果窗体还未加载完成,忽略此事件
if (!isFormLoaded || isFormMessageStop)
return;
try
{
if (message == null)
{
return;
}
lock (pendingMessagesLock)
{
pendingMessages.Enqueue(message);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"处理新报文失败: {ex.Message}");
}
if (string.IsNullOrEmpty(rawData))
return "";
return rawData.Length <= maxLen ? rawData : rawData.Substring(0, maxLen) + "…";
}
/// <summary>
/// 解析报文数据
/// </summary>
private void ParseMessage(CommunicationMessage message)
private static string BuildParsedText(CommunicationMessage message)
{
if (message == null || txtParsedData == null)
return;
if (message == null)
return "";
try
{
var parsed = new System.Text.StringBuilder();
var parsed = new StringBuilder();
parsed.AppendLine("=== 报文解析 ===");
parsed.AppendLine($"时间: {message.Timestamp:yyyy-MM-dd HH:mm:ss.fff}");
parsed.AppendLine($"方向: {(message.Direction == MessageDirection.Send ? "" : "")}");
@@ -363,199 +388,43 @@ namespace StandardScene.Charge
parsed.AppendLine();
parsed.AppendLine("=== 原始数据 (HEX) ===");
parsed.AppendLine(message.RawData);
// parsed.AppendLine(FormatHexString(message.RawData));
parsed.AppendLine();
parsed.AppendLine("=== 数据解析 ===");
// TODO: 根据实际协议进行解析
parsed.AppendLine();
if (message.Direction== MessageDirection.Send)
if (message.Direction == MessageDirection.Send)
{
var sendDate = messageService.ParseSendRawData(message.RawData, message.Type);
var sendData = MessageService.ParseSendRawData(message.RawData, message.Type);
parsed.AppendLine("示例解析:");
parsed.AppendLine($"充电指令:{sendDate.ChargeCommand}");
parsed.AppendLine($"发送电压:{sendDate.SetVoltage}");
parsed.AppendLine($"发送电流:{sendDate.SetCurrent}");
parsed.AppendLine($"车辆ID{sendDate.CurrentVehicleId}");
parsed.AppendLine($"车辆电量:{sendDate.BatteryLevel}");
parsed.AppendLine($"车辆电压:{sendDate.CarVoltage}");
parsed.AppendLine($"车辆电流:{sendDate.CarCurrent}");
parsed.AppendLine($"充电指令:{sendData.ChargeCommand}");
parsed.AppendLine($"发送电压:{sendData.SetVoltage}");
parsed.AppendLine($"发送电流:{sendData.SetCurrent}");
parsed.AppendLine($"车辆ID{sendData.CurrentVehicleId}");
parsed.AppendLine($"车辆电量:{sendData.BatteryLevel}");
parsed.AppendLine($"车辆电压:{sendData.CarVoltage}");
parsed.AppendLine($"车辆电流:{sendData.CarCurrent}");
}
else
{
var recDate = messageService.ParseReceiveRawData(message.RawData, message.Type);
string mechanismStatus = (int)recDate.MechanismStatus == 1 ? "伸出" : (int)recDate.MechanismStatus == 2 ? "缩回" : (int)recDate.MechanismStatus == 3 ? "运动中" : recDate.MechanismStatus.ToString();
var recData = MessageService.ParseReceiveRawData(message.RawData, message.Type);
string mechanismStatus = (int)recData.MechanismStatus == 1 ? "伸出"
: (int)recData.MechanismStatus == 2 ? "缩回"
: (int)recData.MechanismStatus == 3 ? "运动中"
: recData.MechanismStatus.ToString();
parsed.AppendLine("示例解析:");
parsed.AppendLine($"机构状态:{mechanismStatus}");
parsed.AppendLine($"实时电压:{recDate.RealTimeVoltage}");
parsed.AppendLine($"实时电流:{recDate.RealTimeCurrent}");
parsed.AppendLine($"充电量: {recDate.BatteryAH}");
parsed.AppendLine($"是否报警:{recDate.HasAlarm}");
parsed.AppendLine($"充电状态:{recDate.Status.ToString()}");
parsed.AppendLine($"实时电压:{recData.RealTimeVoltage}");
parsed.AppendLine($"实时电流:{recData.RealTimeCurrent}");
parsed.AppendLine($"充电量: {recData.BatteryAH}");
parsed.AppendLine($"是否报警:{recData.HasAlarm}");
parsed.AppendLine($"充电状态:{recData.Status}");
}
txtParsedData.Text = parsed.ToString();
return parsed.ToString();
}
catch (Exception ex)
{
txtParsedData.Text = $"解析失败: {ex.Message}";
}
}
/// <summary>
/// 格式化十六进制字符串
/// </summary>
private string FormatHexString(string hexData)
{
if (string.IsNullOrEmpty(hexData))
return string.Empty;
var formatted = new System.Text.StringBuilder();
for (int i = 0; i < hexData.Length; i += 2)
{
if (i > 0 && i % 32 == 0)
formatted.AppendLine();
else if (i > 0)
formatted.Append(" ");
if (i + 1 < hexData.Length)
formatted.Append(hexData.Substring(i, 2));
else
formatted.Append(hexData[i]);
}
return formatted.ToString();
}
// ==================== 事件处理 ====================
private void cmbIpFilter_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
LoadMessages();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"筛选改变失败: {ex.Message}");
}
}
private void dgvMessages_SelectionChanged(object sender, EventArgs e)
{
try
{
if (dgvMessages.SelectedRows.Count > 0)
{
var row = dgvMessages.SelectedRows[0];
var rawData = row.Cells[5].Value?.ToString();
var ipAddress = row.Cells[2].Value?.ToString();
var port = int.Parse(row.Cells[3].Value?.ToString() ?? "0");
var timeStr = row.Cells[0].Value?.ToString();
var directionStr = row.Cells[1].Value?.ToString();
var stationId = row.Cells[6].Value?.ToString();
var type = row.Cells[7].Value?.ToString();
// 构造消息对象用于解析
var message = new CommunicationMessage
{
RawData = rawData,
IpAddress = ipAddress,
Port = port,
Direction = directionStr == "发送" ? MessageDirection.Send : MessageDirection.Receive,
StationId = stationId == "-" ? null : stationId,
Length = rawData.Split(' ')?.Length ?? 0,
Type=type,
};
if (DateTime.TryParse(timeStr, out DateTime timestamp))
{
message.Timestamp = timestamp;
}
ParseMessage(message);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"选择报文失败: {ex.Message}");
}
}
private void btnRefresh_Click(object sender, EventArgs e)
{
try
{
RefreshIpFilter();
LoadMessages();
RequestStatisticsRefresh(dgvMessages?.Rows.Count ?? 0);
}
catch (Exception ex)
{
MessageBox.Show($"刷新失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnClear_Click(object sender, EventArgs e)
{
try
{
var result = MessageBox.Show(
"确定要清空所有报文记录吗?",
"确认清空",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
messageService.Clear();
RefreshIpFilter();
LoadMessages();
if (txtParsedData != null)
{
txtParsedData.Clear();
}
dgvMessages.Rows.Clear();
RequestStatisticsRefresh(0);
}
}
catch (Exception ex)
{
MessageBox.Show($"清空报文失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void CommunicationMonitorForm_FormClosing(object sender, FormClosingEventArgs e)
{
// 取消订阅事件
messageService.MessageAdded -= OnMessageAdded;
uiFlushTimer.Stop();
uiFlushTimer.Dispose();
statsRefreshTimer.Stop();
statsRefreshTimer.Dispose();
}
private void button1_Click(object sender, EventArgs e)
{
isFormMessageStop = !isFormMessageStop;
if (sender is Button pauseButton)
{
pauseButton.Text = isFormMessageStop ? "继续" : "暂停";
return $"解析失败: {ex.Message}";
}
}
}
}
@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="type.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>
@@ -5,7 +5,7 @@ using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using StandardScene.Utils;
using CommonUsage;
using LessokajiWeaverUtilities.Utilities;
using Newtonsoft.Json;
@@ -278,7 +278,7 @@ namespace StandardScene.Charge
// 防止重复启动
if (myStarted)
{
MessageBox.Show("充电进程已启动,不可重复启动");
CycleUiHelper.Alert("提示", "充电进程已启动,不可重复启动");
return;
}
status.status = "已启动";