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 configMappings = new List(); private BindingList bindList = new BindingList(); 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(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 GetALLConfigs() { try { if (!File.Exists(fdConfigMappingPath)) return new List(); return MiniExcel.Query(fdConfigMappingPath).ToList(); } catch (Exception ex) { ShowError($"读取配置文件失败:{ex.Message}"); return new List(); } } 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(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(bindList); SaveToExcel(configMappings); ShowSuccess("删除成功".Translated()); } catch (Exception ex) { ShowError($"删除失败:{ex.Message}"); } } } // 保存成功后更新全局配置 private void SaveToExcel(List 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); } } }