添加项目文件。
This commit is contained in:
@@ -0,0 +1,464 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user