Files
2026-08-04 18:36:40 +08:00

464 lines
16 KiB
C#

using Google.Protobuf.WellKnownTypes;
using JinYuan.Models;
using JinYuan.VirtualDataLibrary;
using Language;
using MiniExcelLibs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace LargeSquareOne
{
public partial class FDConfigForm : MultiLanguageForm
{
// 定义事件
public static event EventHandler OnFDConfigChanged;
private readonly string fdConfigMappingPath = CommonMethods.FdConfigMappingPath;
private List<FDConfigMapping> configMappings = new List<FDConfigMapping>();
private BindingList<FDConfigMapping> bindList = new BindingList<FDConfigMapping>();
private bool _isLoading = false;
private readonly DataGridViewCellStyle _centerCellStyle = new DataGridViewCellStyle()
{
Alignment = DataGridViewContentAlignment.MiddleCenter
};
public FDConfigForm()
{
InitializeComponent();
groupTable.AutoGenerateColumns = false;
InitializeDataGridView();
EnsureConfigDirectoryExists();
configMappings = GetALLConfigs();
bindList = new BindingList<FDConfigMapping>(configMappings);
_isLoading = true;
LoadConfigs();
_isLoading = false;
}
private void EnsureConfigDirectoryExists()
{
string dir = Path.GetDirectoryName(fdConfigMappingPath);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
}
private void InitializeDataGridView()
{
// 禁用自动添加新行
groupTable.AllowUserToAddRows = false;
groupTable.AllowUserToDeleteRows = false;
groupTable.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
groupTable.MultiSelect = false;
groupTable.ReadOnly = false;
groupTable.DoubleBuffered(true);
// 设置默认单元格样式
groupTable.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
groupTable.RowHeadersVisible = false;
groupTable.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn
{
Name = "FDNum",
HeaderText = "分档编号".Translated(),
Width = 120,
ReadOnly = true,
DataPropertyName = "FDNum",
DefaultCellStyle = _centerCellStyle
},
new DataGridViewTextBoxColumn
{
Name = "FDName",
HeaderText = "分档类型".Translated(),
Width = 120,
DataPropertyName = "FDName",
DefaultCellStyle = _centerCellStyle
},
new DataGridViewTextBoxColumn
{
Name = "ModelType",
HeaderText = "电池型号".Translated(),
Width = 120,
DataPropertyName = "ModelType",
DefaultCellStyle = _centerCellStyle
},
new DataGridViewButtonColumn
{
Name = "SaveBtn",
HeaderText = "操作".Translated(),
Width = 100,
Text = "保存该行".Translated(),
UseColumnTextForButtonValue = true
},
new DataGridViewButtonColumn
{
Name = "DeleteBtn",
HeaderText = "操作".Translated(),
Width = 100,
Text = "删除".Translated(),
UseColumnTextForButtonValue = true
}
});
// 事件绑定
groupTable.CellContentClick += GroupTable_CellContentClick;
groupTable.DataError += GroupTable_DataError;
groupTable.CellBeginEdit += GroupTable_CellBeginEdit;
groupTable.CellValidating += GroupTable_CellValidating; // 添加验证事件
}
#region 数据错误处理
private void GroupTable_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.Cancel = true;
}
#endregion
#region 单元格编辑前事件 - 阻止编辑FDNum
private void GroupTable_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
if (groupTable.Columns[e.ColumnIndex].Name == "FDNum")
{
e.Cancel = true;
}
}
#endregion
#region 单元格验证 - 实时更新绑定数据
private void GroupTable_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
// 当单元格编辑完成时,确保数据更新到绑定列表
if (e.RowIndex < 0 || e.RowIndex >= bindList.Count)
return;
var row = groupTable.Rows[e.RowIndex];
var item = bindList[e.RowIndex];
string colName = groupTable.Columns[e.ColumnIndex].Name;
if (colName == "FDName")
{
string newValue = e.FormattedValue?.ToString()?.Trim() ?? string.Empty;
// 如果值为空,设置为空字符串
if (string.IsNullOrEmpty(newValue))
{
item.FDName = string.Empty;
}
else
{
item.FDName = newValue;
}
}
else if (colName == "ModelType")
{
string newValue = e.FormattedValue?.ToString()?.Trim() ?? string.Empty;
item.ModelType = newValue;
}
}
#endregion
private void LoadConfigs()
{
try
{
groupTable.DataSource = null;
groupTable.DataSource = bindList;
}
catch (Exception ex)
{
ShowError($"加载数据失败:{ex.Message}");
}
}
private List<FDConfigMapping> GetALLConfigs()
{
try
{
if (!File.Exists(fdConfigMappingPath))
return new List<FDConfigMapping>();
return MiniExcel.Query<FDConfigMapping>(fdConfigMappingPath).ToList();
}
catch (Exception ex)
{
ShowError($"读取配置文件失败:{ex.Message}");
return new List<FDConfigMapping>();
}
}
private void GroupTable_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0) return;
if (e.ColumnIndex < 0) return;
int rowIdx = e.RowIndex;
string colName = groupTable.Columns[e.ColumnIndex].Name;
// 检查行索引是否有效
if (rowIdx >= bindList.Count)
{
ShowError("数据行索引无效".Translated());
return;
}
if (colName == "SaveBtn")
{
var item = bindList[rowIdx];
// 验证数据
if (!ValidateSingleConfig(item, rowIdx))
return;
try
{
// 提交当前编辑
groupTable.CommitEdit(DataGridViewDataErrorContexts.Commit);
configMappings = new List<FDConfigMapping>(bindList);
SaveToExcel(configMappings);
ShowSuccess("保存成功".Translated());
}
catch (Exception ex)
{
ShowError($"保存失败:{ex.Message}");
}
}
else if (colName == "DeleteBtn")
{
var delItem = bindList[rowIdx];
string msg = $"{"确定删除该分档配置?".Translated()}\n{"分档编号:".Translated()}{delItem.FDNum}\n{"分档类型:".Translated()}{delItem.FDName}";
var res = MessageBox.Show(msg, "确认删除".Translated(), MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (res != DialogResult.Yes) return;
try
{
bindList.RemoveAt(rowIdx);
configMappings = new List<FDConfigMapping>(bindList);
SaveToExcel(configMappings);
ShowSuccess("删除成功".Translated());
}
catch (Exception ex)
{
ShowError($"删除失败:{ex.Message}");
}
}
}
// 保存成功后更新全局配置
private void SaveToExcel(List<FDConfigMapping> configs)
{
EnsureConfigDirectoryExists();
string dir = Path.GetDirectoryName(fdConfigMappingPath);
string tempFile = Path.Combine(dir, $"_tmp_{Path.GetFileName(fdConfigMappingPath)}");
try
{
MiniExcel.SaveAs(tempFile, configs);
if (!File.Exists(tempFile))
throw new Exception("临时文件生成失败".Translated());
// 备份原文件
string backupFile = Path.Combine(dir, $"{Path.GetFileNameWithoutExtension(fdConfigMappingPath)}_backup_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
if (File.Exists(fdConfigMappingPath))
{
File.Copy(fdConfigMappingPath, backupFile, true);
}
if (File.Exists(fdConfigMappingPath))
File.Delete(fdConfigMappingPath);
File.Move(tempFile, fdConfigMappingPath);
// 删除旧备份
CleanOldBackups(dir, 5);
// 更新全局分档配置
CommonMethods.FDConfigMappings = configs;
// 更新分档类型列表到全局
var gradeTypes = configs.Select(x => x.FDName).Distinct().ToList();
if (!gradeTypes.Contains("不设置"))
gradeTypes.Insert(0, "不设置");
if (!gradeTypes.Contains("NG"))
gradeTypes.Add("NG");
CommonMethods.FDGradeTypes = gradeTypes;
// 保存成功后,触发刷新事件
CommonMethods.LoadFDGradeTypes();
// 如果需要通知主窗体刷新,可以触发事件
OnFDConfigChanged?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
throw new Exception($"保存Excel失败:{ex.Message}", ex);
}
finally
{
if (File.Exists(tempFile))
{
try { File.Delete(tempFile); } catch { }
}
}
}
private void CleanOldBackups(string directory, int keepCount)
{
try
{
var backupFiles = Directory.GetFiles(directory, "*_backup_*.xlsx")
.OrderByDescending(f => f)
.Skip(keepCount)
.ToList();
foreach (var file in backupFiles)
{
try { File.Delete(file); } catch { }
}
}
catch { }
}
private bool ValidateSingleConfig(FDConfigMapping config, int rowIndex = -1)
{
if (string.IsNullOrWhiteSpace(config.FDName))
{
ShowError("分档类型不能为空".Translated());
return false;
}
if (config.FDNum <= 0)
{
ShowError("分档编号必须大于0".Translated());
return false;
}
bool duplicate;
if (rowIndex == -1)
{
duplicate = bindList.Any(x => x.FDNum == config.FDNum);
}
else
{
duplicate = bindList.Take(rowIndex).Any(x => x.FDNum == config.FDNum)
|| bindList.Skip(rowIndex + 1).Any(x => x.FDNum == config.FDNum);
}
if (duplicate)
{
ShowError($"分档编号 {config.FDNum} 已存在,不可重复".Translated());
return false;
}
return true;
}
#region 按钮事件
private void BtnAdd_Click(object sender, EventArgs e)
{
try
{
// 先提交当前编辑,防止数据丢失
groupTable.CommitEdit(DataGridViewDataErrorContexts.Commit);
// 计算新的编号
int maxNum = bindList.Count > 0 ? bindList.Max(x => x.FDNum) : 0;
int autoNum = maxNum + 1;
// 添加到绑定列表
var newItem = new FDConfigMapping
{
FDNum = autoNum,
FDName = string.Empty,
ModelType = string.Empty
};
bindList.Add(newItem);
// 刷新显示,不重新加载整个数据源,只刷新视图
int newIndex = bindList.Count - 1;
groupTable.Refresh();
// 选中新行并开始编辑
if (newIndex >= 0 && newIndex < groupTable.Rows.Count)
{
groupTable.ClearSelection();
groupTable.Rows[newIndex].Selected = true;
groupTable.CurrentCell = groupTable.Rows[newIndex].Cells["FDName"];
groupTable.BeginEdit(true);
}
}
catch (Exception ex)
{
ShowError($"添加行失败:{ex.Message}");
}
}
private void btn_Close_Click(object sender, EventArgs e)
{
// 关闭前提交所有编辑
try
{
groupTable.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
catch { }
this.Close();
}
#endregion
#region 提示弹窗
private void ShowError(string message)
{
MessageBox.Show(message, "错误".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private void ShowSuccess(string message)
{
MessageBox.Show(message, "提示".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
#endregion
#region 无边框拖动
private Point mPoint;
private void Panel_MouseDown(object sender, MouseEventArgs e)
{
mPoint = e.Location;
}
private void Panel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Left += e.X - mPoint.X;
this.Top += e.Y - mPoint.Y;
}
}
#endregion
#region 窗口防闪烁
protected override CreateParams CreateParams
{
get
{
var cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
#endregion
}
public static class DgvExt
{
public static void DoubleBuffered(this DataGridView dgv, bool enable)
{
var prop = dgv.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
prop?.SetValue(dgv, enable, null);
}
}
}