diff --git a/Analysis/CjlrForm/FileSorter.cs b/Analysis/CjlrForm/FileSorter.cs
index 3e650d8..bc2b476 100644
--- a/Analysis/CjlrForm/FileSorter.cs
+++ b/Analysis/CjlrForm/FileSorter.cs
@@ -10,6 +10,19 @@ using System.Text;
namespace NSAnalysis
{
+ ///
+ /// CSV解析结果,替代全局静态变量 ConfigDfn.strEquipNo 等,消除多线程竞争
+ ///
+ public class CsvParseResult
+ {
+ public string CarID { get; set; }
+ public string CarModel { get; set; }
+ public string Position { get; set; }
+ public string GroupName { get; set; }
+ public string MeasureTime { get; set; }
+ public bool Success { get; set; }
+ }
+
public class FileSorter
{
public CjlrDAL _dal = new CjlrDAL();
@@ -21,6 +34,650 @@ namespace NSAnalysis
public event Action OnLog; // 日志事件
+ public event Action OnFileParsed; // 解析完成后通知:车号、位置、测量时间
+
+ // 关键流程节点日志事件
+ public event Action OnProcessStep; // 处理步骤日志事件
+
+ // 封装 OnProcessStep 事件
+ private void emitProcessStep(string message)
+ {
+ OnProcessStep?.Invoke(message);
+ }
+
+ public FileSorter()
+ {
+ }
+
+ // 主逻辑处理
+ public void ProcessFiles()
+ {
+ var tasks = GetTaskRecords();
+ // 增加空检查
+ if (tasks == null || tasks.Rows.Count == 0)
+ {
+ Trace("没有找到任何任务记录,处理终止。");
+ return;
+ }
+
+ Trace($"[ProcessFiles] 共查询到 {tasks.Rows.Count} 个分发任务,开始逐一执行。");
+
+ foreach (DataRow task in tasks.Rows)
+ {
+ string modelName = task["modelsName"].ToString();
+ string modelCode = task["modelsCode"].ToString();
+ string position = task["position"].ToString();
+ string sourceDir = task["sourceFile"].ToString();
+ string targetDir = task["targetFile"].ToString();
+
+ // 打印信息
+ Trace($"[ProcessFiles] 正在执行分发任务 - 源路径: {sourceDir}, 目标路径: {targetDir}, 匹配字符: {modelCode} 位置:{position}");
+ if (Directory.Exists(sourceDir))
+ {
+ ProcessDirectory(sourceDir, targetDir, modelCode, modelName, position);
+ }
+ else
+ {
+ Trace($"[ProcessFiles] 源文件地址不存在或错误: {sourceDir}");
+ }
+ }
+ }
+
+ // 获取任务记录
+ private DataTable GetTaskRecords()
+ {
+ DataTable dt = _dal.SelectTaskByCondition("", "", "start");
+
+ if (dt == null || dt.Rows.Count == 0)
+ {
+ Trace("未发现移动任务.");
+ return null;
+ }
+ return dt;
+ }
+
+ // 处理目录中的文件
+ private void ProcessDirectory(string sourceDir, string targetDir, string modelCode, string modelName, string position)
+ {
+ // 匹配信息
+ string matchStr = $"{modelCode}_{position}";
+ Trace($"匹配文件特征符: {matchStr}");
+
+ // 确保目标目录存在
+ if (!Directory.Exists(targetDir))
+ {
+ Directory.CreateDirectory(targetDir);
+ Trace($"创建目标文件夹: {targetDir}");
+ }
+
+ // 遍历源目录中的所有CSV文件
+ foreach (string file in Directory.GetFiles(sourceDir, "*.csv"))
+ {
+ // 打印正在处理的文件
+ Trace($"正在处理文件 : {file}");
+
+ // 解析入库,返回局部结果,不再写全局变量
+ CsvParseResult parseResult = AnalysisNxsCSV(file);
+
+ // 如果未启用分发功能,直接返回
+ if (!ConfigDfn.iEnableSort)
+ {
+ return;
+ }
+
+ #region 分发逻辑
+
+ if (MatchCsvValue(file, matchStr, readRowIndex, readColIndex))
+ {
+ // 记录日志,匹配到
+ Trace($"匹配成功,准备移动文件: {file} -> {targetDir}");
+
+ string destFile = Path.Combine(targetDir, Path.GetFileName(file));
+ if (File.Exists(destFile))
+ {
+ string backupFile = destFile + ".bak_" + DateTime.Now.ToString("yyyyMMdd_HHmmss");
+ File.Move(destFile, backupFile);
+ Trace($"目标文件已存在,已重命名为备份文件: {backupFile}");
+ }
+ File.Move(file, destFile);
+ Trace($"移动完成,: {file} -> {destFile}");
+ emitProcessStep($"---> 5、文件移动完成: -> {destFile}");
+
+ //插入分发详情
+ CjlrTaskReleaseDetailModel detailModel = new CjlrTaskReleaseDetailModel
+ {
+ ModelsName = modelName,
+ ModelsCode = modelCode,
+ Position = position,
+ SourceFile = file,
+ TargetFile = destFile,
+ TaskFileName = Path.GetFileName(file),
+ TaskStatus = 1,
+ TaskDetail = "文件移动成功",
+ CreateDate = DateTime.Now
+ };
+ _dal.InsertTaskDetail(detailModel);
+ }
+ else
+ {
+ Trace($"未匹配到文件: {file}");
+ emitProcessStep($"---> 5、未匹配到文件: {file}");
+
+ //记录到数据库
+ CjlrTaskReleaseDetailModel detailModel = new CjlrTaskReleaseDetailModel
+ {
+ ModelsName = modelName,
+ ModelsCode = modelCode,
+ Position = position,
+ SourceFile = file,
+ TargetFile = "",
+ TaskFileName = Path.GetFileName(file),
+ TaskStatus = 2,
+ TaskDetail = "文件未匹配",
+ CreateDate = DateTime.Now
+ };
+ try
+ {
+ _dal.InsertTaskDetail(detailModel);
+ }
+ catch (Exception ex)
+ {
+ Trace($"记录错误到数据库失败: {ex.Message}");
+ }
+ }
+
+ #endregion 分发逻辑
+ }
+ }
+
+ ///
+ /// 检查CSV文件中指定行列的字符串是否匹配目标值
+ ///
+ public static bool MatchCsvValue(string filePath, string targetValue, int rowIndex, int colIndex)
+ {
+ MyBase.TraceWriteLine($"[MatchCsvValue] 检查文件: {filePath}, 行索引: {rowIndex}, 列索引: {colIndex}, 目标值: {targetValue}");
+ try
+ {
+ string[] lines = File.ReadAllLines(filePath);
+
+ if (rowIndex < 0 || rowIndex >= lines.Length)
+ return false;
+
+ string[] columns = lines[rowIndex].Split(',');
+
+ if (colIndex < 0 || colIndex >= columns.Length)
+ return false;
+
+ return columns[colIndex].Trim().Contains(targetValue);
+ }
+ catch (Exception ex)
+ {
+ MyBase.TraceWriteLine($"处理CSV文件时出错: {ex.Message}");
+ return false;
+ }
+ }
+
+ // 生成单侧统计信息的方法(使用局部参数,不再依赖全局变量)
+ private void GenerateSingleSideStatistics(string carID, string carModel, string groupName, string position, string measureTime)
+ {
+ #region 统计信息显示
+
+ DataTable sampleData = _dal.SelectMeasureResultByCarID(carID, groupName);
+ if (sampleData == null || sampleData.Rows.Count == 0)
+ {
+ MyBase.TraceWriteLine("没有测量数据,无法生成统计信息。");
+ emitProcessStep(position + " 没有测量数据,无法生成统计信息。");
+ return;
+ }
+
+ AnalysisResult analysis = AnalysisResult.AnalyzeMeasureData(sampleData);
+
+ int dtRowCount = analysis.TotalCount;
+ double OutCount = analysis.OutCount;
+ double OKCount = analysis.OKCount;
+ double RejectedCount = analysis.RejectedCount;
+ double FPYPercent = analysis.FPYPercent;
+
+ TMeasureResultModel tmrm = new TMeasureResultModel();
+
+ FPYPercent = OKCount / (OKCount + OutCount);
+ if (FPYPercent >= ConfigDfn.dFPY)
+ {
+ tmrm.Result = 1;
+ }
+ else if (FPYPercent >= ConfigDfn.dFPY2 && FPYPercent < ConfigDfn.dFPY)
+ {
+ tmrm.Result = 1;
+ }
+ else
+ {
+ tmrm.Result = 2;
+ }
+
+ tmrm.CarID = carID;
+ tmrm.CarType = carModel;
+ tmrm.SumMeasureItems = dtRowCount;
+ tmrm.GoodMeasureItems = (int)OKCount;
+ tmrm.NoGoodMeasureItems = (int)OutCount;
+ tmrm.RejectMeasureItems = (int)RejectedCount;
+ tmrm.FPY = FPYPercent.ToString("F4");
+ tmrm.Remark = position;
+ tmrm.MeasureDate = measureTime;
+ _dal.InsertTMeasureResult(tmrm);
+
+ MyBase.TraceWriteLine("将总结果插入数据库完毕。");
+ emitProcessStep($"---> 3、统计信息已生成: 位置: {position}, 总测量项: {dtRowCount}, 合格项: {OKCount}, 不合格项: {OutCount}, 异常项: {RejectedCount}, FPY: {FPYPercent:F4}");
+
+ #endregion 统计信息显示
+ }
+
+ // 导入CSV文件到数据库,返回解析结果(不再写全局变量)
+ public CsvParseResult ImportCsv2Sql(string filePath)
+ {
+ var result = new CsvParseResult { Success = false };
+ var records = new List();
+ var lineNo = 0;
+ var groupName = string.Empty;
+ var position = string.Empty;
+
+ emitProcessStep($"正在处理: {filePath}");
+
+ // 判断文件是否已经处理过
+ if (_dal.IsFileProcessed(filePath))
+ {
+ MyBase.TraceWriteLine($"文件已处理过,跳过: {filePath}");
+ emitProcessStep($"---> 2、文件已处理过,跳过: {filePath}");
+ return result;
+ }
+
+ // 备份原始文件
+ try
+ {
+ string backupDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Backup");
+ if (!Directory.Exists(backupDir))
+ {
+ Directory.CreateDirectory(backupDir);
+ }
+ string backupFilePath = Path.Combine(backupDir, Path.GetFileName(filePath));
+ File.Copy(filePath, backupFilePath, true);
+ MyBase.TraceWriteLine("已备份文件到: " + backupFilePath);
+ }
+ catch (Exception ex)
+ {
+ MyBase.TraceWriteLine("备份文件时发生错误:" + ex.Message);
+ }
+
+ try
+ {
+ using (var reader = new StreamReader(filePath))
+ {
+ reader.ReadLine(); // Skip header
+
+ lineNo = 1;
+ while (!reader.EndOfStream)
+ {
+ lineNo++;
+ var line = reader.ReadLine();
+ var values = line.Split(',');
+
+ if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#") || line.StartsWith("//") || line.StartsWith("MeasPoint.Name"))
+ {
+ continue;
+ }
+
+ if (values.Length < 22)
+ {
+ MyBase.TraceWriteLine("CSV行数据不完整,跳过该行:" + line);
+ continue;
+ }
+
+ if (string.IsNullOrEmpty(values[2]))
+ {
+ MyBase.TraceWriteLine($"第 {lineNo} 行数据为0,跳过该行:" + line);
+ continue;
+ }
+
+ var record = new CJLR_MeaDataModel
+ {
+ PointName = values[0],
+ GroupName = values[1],
+ ProductNum = values[2],
+ Model = values[3],
+ Station = values[4],
+ Method = values[5],
+ Standard = values[6],
+ DimensionName = values[7],
+ DimensionValue = values[8],
+ DimensionUnit = values[9],
+ IsManual = bool.Parse(values[10]),
+ Classification = values[11],
+ ToleranceName0 = values[12],
+ ToleranceLower0 = values[13],
+ ToleranceUpper0 = values[14],
+ ToleranceName1 = values[15],
+ ToleranceLower1 = values[16],
+ ToleranceUpper1 = values[17],
+ NominalValue = values[18],
+ MeasureDate = DateTime.ParseExact(values[19], "yyyyMMdd", CultureInfo.InvariantCulture),
+ MeasureTime = TimeSpan.ParseExact(values[20], "hhmmss", CultureInfo.InvariantCulture),
+ SequenceNum = int.Parse(values[21])
+ };
+
+ records.Add(record);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ MyBase.TraceWriteLine("导入CSV文件时发生错误:" + ex.Message);
+ emitProcessStep($"---> 2、导入CSV文件时发生错误: {ex.Message}");
+
+ string errorDir = Path.Combine(Path.GetDirectoryName(filePath), "Error");
+ if (!Directory.Exists(errorDir))
+ {
+ Directory.CreateDirectory(errorDir);
+ }
+ string errorFilePath = Path.Combine(errorDir, Path.GetFileName(filePath));
+ File.Move(filePath, errorFilePath);
+ MyBase.TraceWriteLine("已将文件移动到错误文件夹: " + errorFilePath);
+ return result;
+ }
+
+ try
+ {
+ if (records.Count > 0)
+ {
+ var firstRecord = records[0];
+
+ // 所有解析结果存入局部变量,不写全局 ConfigDfn
+ result.MeasureTime = firstRecord.MeasureDate.ToString("yyyy-MM-dd") + " " + firstRecord.MeasureTime.ToString(@"hh\:mm\:ss");
+ result.CarID = firstRecord.ProductNum;
+ result.CarModel = firstRecord.Model;
+
+ groupName = firstRecord.GroupName;
+ result.GroupName = groupName;
+
+ MyBase.TraceWriteLine("测量时间:" + result.MeasureTime);
+ MyBase.TraceWriteLine("--------------------------------------------------------");
+ MyBase.TraceWriteLine("车号:" + result.CarID);
+ MyBase.TraceWriteLine("车型:" + result.CarModel);
+ MyBase.TraceWriteLine("组名:" + groupName);
+
+ if (string.IsNullOrEmpty(firstRecord.GroupName))
+ {
+ MyBase.TraceWriteLine("组名为空,使用默认位置。");
+ result.Position = "Default";
+ }
+ else
+ {
+ var parts2 = firstRecord.GroupName.Split('_');
+ if (parts2.Length > 1 && !string.IsNullOrEmpty(parts2[1]))
+ {
+ result.Position = parts2[1].Substring(0, 1);
+ }
+ else
+ {
+ result.Position = firstRecord.GroupName;
+ }
+ }
+
+ MyBase.TraceWriteLine("位置:" + result.Position);
+ MyBase.TraceWriteLine("测量时间:" + result.MeasureTime);
+
+ emitProcessStep($"---> 1、解析到, 车号: {result.CarID} 车型: {result.CarModel} 位置: {result.Position} 测量时间: {result.MeasureTime}");
+ }
+ else
+ {
+ MyBase.TraceWriteLine("没有找到有效的测量记录,无法设置测量时间。CSV文件导入到数据库失败!");
+ emitProcessStep($"---> 2、没有找到有效的测量记录,无法设置测量时间。CSV文件导入到数据库失败!");
+
+ string errorDir = Path.Combine(Path.GetDirectoryName(filePath), "Error");
+ if (!Directory.Exists(errorDir))
+ {
+ Directory.CreateDirectory(errorDir);
+ }
+ string errorFilePath = Path.Combine(errorDir, Path.GetFileName(filePath));
+ File.Move(filePath, errorFilePath);
+ MyBase.TraceWriteLine("已将文件移动到错误文件夹: " + errorFilePath);
+ return result;
+ }
+
+ // 逐条插入数据到数据库
+ foreach (var record in records)
+ {
+ _dal.InsertOrUpdateCJLRMeaData(record);
+ }
+
+ // 记录处理文件到数据库
+ _dal.InsertProcessedFile(filePath);
+ MyBase.TraceWriteLine("CSV文件导入到数据库成功!");
+ emitProcessStep($"---> 2、CSV文件导入到数据库成功");
+
+ result.Success = true;
+
+ #region 处理单侧统计信息
+
+ GenerateSingleSideStatistics(result.CarID, result.CarModel, groupName, result.Position, result.MeasureTime);
+
+ #endregion 处理单侧统计信息
+
+ MyBase.TraceWriteLine("--------------------------------------------------------");
+ }
+ catch (Exception ex)
+ {
+ MyBase.TraceWriteLine("导入CSV文件时发生错误:" + ex.Message);
+ emitProcessStep($"---> 2、导入CSV文件时发生错误: {ex.Message}");
+ }
+
+ return result;
+ }
+
+ // 解析CSV文件,返回解析结果(不再依赖/写入全局变量)
+ public CsvParseResult AnalysisNxsCSV(string strCSVName)
+ {
+ var emptyResult = new CsvParseResult { Success = false };
+
+ if (!File.Exists(strCSVName))
+ {
+ MyBase.TraceWriteLine("文件不存在:" + strCSVName);
+ return emptyResult;
+ }
+
+ try
+ {
+ // 解析 CSV 文件并导入到数据库,获取局部结果
+ CsvParseResult parseResult = ImportCsv2Sql(strCSVName);
+
+ if (!parseResult.Success || string.IsNullOrEmpty(parseResult.CarID))
+ {
+ return parseResult;
+ }
+
+ // 解析完成后触发事件,传递局部结果(不依赖全局变量)
+ Trace($"触发事件,车号: {parseResult.CarID} 位置: {parseResult.Position}");
+ OnFileParsed?.Invoke(parseResult.CarID, parseResult.Position, parseResult.MeasureTime);
+
+ // 检查是否有双侧测量结果(防御性检查)
+ bool isMeasureComplete = _dal.HasBothSidesMeasureResult(parseResult.CarID);
+
+ if (isMeasureComplete)
+ {
+ MyBase.TraceWriteLine("双侧测量结果已完成,开始生成客户报告。");
+ emitProcessStep($"---> 4、双侧测量结果已完成,开始生成客户报告,车号: {parseResult.CarID}");
+
+ if (parseResult.CarModel != null && parseResult.CarModel.Contains("MY"))
+ {
+ MyBase.TraceWriteLine("车型为 551_MY21,跳过客户报告生成。");
+ emitProcessStep($"---> 4、车型为 551_MY21,跳过客户报告生成,车号: {parseResult.CarID}");
+ return parseResult;
+ }
+
+ GenCustomerReport(parseResult.CarID, parseResult.CarModel);
+ }
+ else
+ {
+ MyBase.TraceWriteLine("双侧测量结果未完成,跳过客户报告生成。");
+ emitProcessStep($"---> 4、双侧测量结果未完成,跳过客户报告生成,车号: {parseResult.CarID}");
+ }
+
+ return parseResult;
+ }
+ catch (Exception ex)
+ {
+ MyBase.TraceWriteLine("解析 CSV 文件时发生错误:" + ex.Message);
+ return emptyResult;
+ }
+ }
+
+ // 生成客户报告函数(使用参数传入,不依赖全局变量)
+ private void GenCustomerReport(string strCarID, string carModel)
+ {
+ DataTable dtCSVContent = _dal.SelectPointDimensionByCarID(strCarID);
+
+ if (dtCSVContent == null || dtCSVContent.Rows.Count == 0)
+ {
+ MyBase.TraceWriteLine("没有找到测量数据,无法生成客户报告。");
+ return;
+ }
+
+ string fileName = strCarID + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv";
+
+ if (!Directory.Exists(ConfigDfn.strReportPath))
+ {
+ Directory.CreateDirectory(ConfigDfn.strReportPath);
+ MyBase.TraceWriteLine($"创建报告目录: {ConfigDfn.strReportPath}");
+ }
+
+ string backupDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ReportBackup");
+ if (!Directory.Exists(backupDir))
+ {
+ Directory.CreateDirectory(backupDir);
+ }
+
+ string savePath = Path.Combine(backupDir, fileName);
+ string target = Path.Combine(ConfigDfn.strReportPath, fileName);
+
+ GenerateCsvReport(strCarID, carModel, dtCSVContent, ConfigDfn.strCSVReportTemplatePath, savePath);
+
+ MyBase.TraceWriteLine($"客户报告已生成: {savePath}");
+ emitProcessStep($"---> 5、客户报告已生成: {savePath}");
+ try
+ {
+ File.Copy(savePath, target, true);
+ MyBase.TraceWriteLine("已拷贝客户报告到目标路径: " + target);
+ emitProcessStep($"---> 6、已拷贝客户报告到目标路径: {target}");
+ }
+ catch
+ {
+ MyBase.TraceWriteLine("拷贝客户报告到目标路径失败: " + target);
+ emitProcessStep($"---> 6、拷贝客户报告到目标路径失败: {target}");
+ }
+ }
+
+ // 生成CSV报告函数(carModel 作为参数传入,不依赖全局变量)
+ private void GenerateCsvReport(string strCarID, string carModel, DataTable measureData, string templatePath, string savePath)
+ {
+ var templateLines = File.ReadAllLines(templatePath);
+
+ StringBuilder sb = new StringBuilder();
+
+ foreach (var line in templateLines)
+ {
+ string processedLine = line;
+ if (processedLine.Contains("{datetime}"))
+ {
+ processedLine = processedLine.Replace("{datetime}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
+ }
+ if (processedLine.Contains("{Part_ident}"))
+ {
+ processedLine = processedLine.Replace("{Part_ident}", strCarID);
+ }
+ if (processedLine.Contains("{model}"))
+ {
+ processedLine = processedLine.Replace("{model}", carModel);
+ }
+ if (processedLine.Contains("{Part_code}"))
+ {
+ if (carModel == "E03")
+ processedLine = processedLine.Replace("{Part_code}", "E03_5000000FAonline");
+ else if (carModel == "E0Y")
+ processedLine = processedLine.Replace("{Part_code}", "E0Y_5000000FAonline");
+ else
+ processedLine = processedLine.Replace("{Part_code}", "UnknownModel_5000000FAonline");
+ }
+ processedLine = processedLine.Trim('"');
+ Console.WriteLine($"处理行: {processedLine}");
+ sb.AppendLine(processedLine);
+ }
+
+ sb.AppendLine();
+ sb.AppendLine();
+ sb.AppendLine();
+ sb.AppendLine();
+
+ sb.AppendLine("Characteristic,Extension,Measured_Value");
+
+ foreach (DataRow row in measureData.Rows)
+ {
+ var dimensionValue = row["DimensionValue"]?.ToString();
+ if (dimensionValue != null && dimensionValue.Contains("1.#R"))
+ {
+ dimensionValue = "";
+ }
+ sb.AppendFormat("{0},{1},{2}\n",
+ row["PointName"], row["DimensionName"], dimensionValue);
+ }
+
+ File.WriteAllText(savePath, sb.ToString(), Encoding.UTF8);
+ }
+
+ // 日志记录方法
+ private void Trace(string msg)
+ {
+ OnLog?.Invoke(msg);
+ MyBase.TraceWriteLine(msg);
+ }
+
+ // 打印 DataTable 对象的方法
+ public static void PrintDataTable(DataTable dt)
+ {
+ if (dt == null || dt.Rows.Count == 0)
+ {
+ Console.WriteLine("[PrintDataTable] DataTable is empty or null.");
+ return;
+ }
+ foreach (DataColumn column in dt.Columns)
+ {
+ Console.WriteLine($"{column.ColumnName}\t");
+ }
+ Console.WriteLine("");
+ foreach (DataRow row in dt.Rows)
+ {
+ foreach (var item in row.ItemArray)
+ {
+ Console.WriteLine($"{item}\t");
+ }
+ Console.WriteLine("");
+ }
+ }
+
+ // 测试方法
+ public void test()
+ {
+ SQLHelper.connStr = DatabaseDfn.SqlConnectStr();
+ GenCustomerReport("K0902906", "E03");
+ }
+ }
+}
+ public CjlrDAL _dal = new CjlrDAL();
+
+ //定义读取的位置
+ public int readRowIndex = 2; // 默认读取第3行(从0开始计数)
+
+ public int readColIndex = 1; // 默认读取第2列(从0开始计数)
+
+ public event Action OnLog; // 日志事件
+
public event Action OnFileParsed; // 解析完成后通知文件名
// 关键流程节点日志事件
diff --git a/Analysis/DAL/CjlrDAL.cs b/Analysis/DAL/CjlrDAL.cs
index 1fe26c8..496f3dc 100644
--- a/Analysis/DAL/CjlrDAL.cs
+++ b/Analysis/DAL/CjlrDAL.cs
@@ -234,6 +234,9 @@ NULLIF(
// check 是否有左右两侧的测量结果
public bool HasBothSidesMeasureResult(string carId)
{
+ if (string.IsNullOrEmpty(carId))
+ return false;
+
string sql = @"
SELECT CASE
WHEN COUNT(DISTINCT Remark) = 2 THEN 1
@@ -246,7 +249,10 @@ NULLIF(
new SqlParameter("@CarID", carId)
};
DataTable dt = SQLHelper.ExecuteQuery(sql, paras, CommandType.Text);
- return dt.Rows.Count > 0 && Convert.ToInt32(dt.Rows[0]["HasBothSides"]) == 1;
+ // 防御性检查:空表或列不存在时返回 false,避免 Column 'HasBothSides' does not belong to table 异常
+ if (dt == null || dt.Rows.Count == 0 || !dt.Columns.Contains("HasBothSides"))
+ return false;
+ return Convert.ToInt32(dt.Rows[0]["HasBothSides"]) == 1;
}
// 查询指定车辆ID的测量点维度数据
diff --git a/Analysis/DAL/SQLHelper.cs b/Analysis/DAL/SQLHelper.cs
index bd94461..5bba3af 100644
--- a/Analysis/DAL/SQLHelper.cs
+++ b/Analysis/DAL/SQLHelper.cs
@@ -7,36 +7,10 @@ namespace NSAnalysis.DAL
{
public class SQLHelper
{
- private static SqlConnection conn = null;
- private static SqlCommand cmd = null;
- private static SqlDataReader sdr = null;
public static string connStr = "";
public static int iFlag = 0;
- private static SqlConnection GetConn()
- {
- conn = new SqlConnection(connStr);
- try
- {
- if (conn.State == ConnectionState.Closed)
- {
- conn.Open();
- }
- return conn;
- }
- catch (Exception ex)
- {
- if (iFlag == 0)
- {
- iFlag++;
- MessageBox.Show("数据库打开连接失败,请检查数据库是否正确连接!原因:" + ex.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- // 这里建议抛出异常而不是返回未打开的连接
- throw;
- }
- }
-
#region 执行不带参数的增删改SQL语句或存储过程 返回int类型 返回受影响的行数
///
@@ -47,25 +21,15 @@ namespace NSAnalysis.DAL
/// 返回受影响的行数
public static int ExecuteNonQuery(string cmdText, CommandType ct)
{
- int res = 0;
- try
+ using (var conn = new SqlConnection(connStr))
{
- cmd = new SqlCommand(cmdText, GetConn());
- cmd.CommandType = ct;
- res = cmd.ExecuteNonQuery(); //返回受影响的行数
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- if (conn.State == ConnectionState.Open)
+ conn.Open();
+ using (var cmd = new SqlCommand(cmdText, conn))
{
- conn.Close();
+ cmd.CommandType = ct;
+ return cmd.ExecuteNonQuery();
}
}
- return res;
}
#endregion 执行不带参数的增删改SQL语句或存储过程 返回int类型 返回受影响的行数
@@ -80,7 +44,6 @@ namespace NSAnalysis.DAL
/// 返回受影响的行数
public static int ExecuteNonQuery(string cmdText, SqlParameter[] paras, CommandType ct)
{
- int res = 0;
using (var conn = new SqlConnection(connStr))
{
conn.Open();
@@ -88,10 +51,9 @@ namespace NSAnalysis.DAL
{
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
- res = cmd.ExecuteNonQuery();
+ return cmd.ExecuteNonQuery();
}
}
- return res;
}
#endregion 执行带参数的增删改SQL语句或存储过程 返回int类型 返回受影响的行数
@@ -107,11 +69,17 @@ namespace NSAnalysis.DAL
public static DataTable ExecuteQuery(string cmdText, CommandType ct)
{
DataTable dt = new DataTable();
- cmd = new SqlCommand(cmdText, GetConn());
- cmd.CommandType = ct;
- using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
+ using (var conn = new SqlConnection(connStr))
{
- dt.Load(sdr);
+ conn.Open();
+ using (var cmd = new SqlCommand(cmdText, conn))
+ {
+ cmd.CommandType = ct;
+ using (var sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
+ {
+ dt.Load(sdr);
+ }
+ }
}
return dt;
}
@@ -130,12 +98,18 @@ namespace NSAnalysis.DAL
public static DataTable ExecuteQuery(string cmdText, SqlParameter[] paras, CommandType ct)
{
DataTable dt = new DataTable();
- cmd = new SqlCommand(cmdText, GetConn());
- cmd.CommandType = ct;
- cmd.Parameters.AddRange(paras);
- using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
+ using (var conn = new SqlConnection(connStr))
{
- dt.Load(sdr);
+ conn.Open();
+ using (var cmd = new SqlCommand(cmdText, conn))
+ {
+ cmd.CommandType = ct;
+ cmd.Parameters.AddRange(paras);
+ using (var sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
+ {
+ dt.Load(sdr);
+ }
+ }
}
return dt;
}
@@ -149,11 +123,15 @@ namespace NSAnalysis.DAL
///
public static DataSet ExecuteDs(String Sqlstr)
{
- using (SqlDataAdapter da = new SqlDataAdapter(Sqlstr, GetConn()))
+ using (var conn = new SqlConnection(connStr))
{
- DataSet ds = new DataSet();
- da.Fill(ds);
- return ds;
+ conn.Open();
+ using (SqlDataAdapter da = new SqlDataAdapter(Sqlstr, conn))
+ {
+ DataSet ds = new DataSet();
+ da.Fill(ds);
+ return ds;
+ }
}
}
@@ -214,28 +192,32 @@ namespace NSAnalysis.DAL
public static int InsertMeasureDataToDB(DataTable InsertDT)
{
int iResult = 1;
- using (SqlBulkCopy bulkCopy = new SqlBulkCopy(GetConn()))
+ using (var conn = new SqlConnection(connStr))
{
- try
+ conn.Open();
+ using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))
{
- bulkCopy.DestinationTableName = "TMeasureData";//要插入的表的表明,创造映射关系,比下面的直接写表名称 更加灵活
- bulkCopy.ColumnMappings.Add("CarID", "CarID");//映射字段名 DataTable列名 ,数据库 对应的列名
- bulkCopy.ColumnMappings.Add("CarType", "CarType");//映射字段名 DataTable列名 ,数据库 对应的列名
- bulkCopy.ColumnMappings.Add("MeasPointName", "MeasPointName");
- bulkCopy.ColumnMappings.Add("DimensionName", "DimensionName");
- bulkCopy.ColumnMappings.Add("NormalValue", "NormalValue");
- bulkCopy.ColumnMappings.Add("LowerTolVal", "LowerTolVal");
- bulkCopy.ColumnMappings.Add("UpperTolVal", "UpperTolVal");
- bulkCopy.ColumnMappings.Add("MeasureValue", "MeasureValue");
- bulkCopy.ColumnMappings.Add("MeasureItemResult", "MeasureItemResult");
- bulkCopy.ColumnMappings.Add("MeasureDate", "MeasureDate");
- bulkCopy.ColumnMappings.Add("Remark", "Remark");
- bulkCopy.WriteToServer(InsertDT);
- }
- catch (Exception ex)
- {
- MessageBox.Show("批量插入测量数据到数据库失败!原因:" + ex.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- iResult = -1;
+ try
+ {
+ bulkCopy.DestinationTableName = "TMeasureData";
+ bulkCopy.ColumnMappings.Add("CarID", "CarID");
+ bulkCopy.ColumnMappings.Add("CarType", "CarType");
+ bulkCopy.ColumnMappings.Add("MeasPointName", "MeasPointName");
+ bulkCopy.ColumnMappings.Add("DimensionName", "DimensionName");
+ bulkCopy.ColumnMappings.Add("NormalValue", "NormalValue");
+ bulkCopy.ColumnMappings.Add("LowerTolVal", "LowerTolVal");
+ bulkCopy.ColumnMappings.Add("UpperTolVal", "UpperTolVal");
+ bulkCopy.ColumnMappings.Add("MeasureValue", "MeasureValue");
+ bulkCopy.ColumnMappings.Add("MeasureItemResult", "MeasureItemResult");
+ bulkCopy.ColumnMappings.Add("MeasureDate", "MeasureDate");
+ bulkCopy.ColumnMappings.Add("Remark", "Remark");
+ bulkCopy.WriteToServer(InsertDT);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("批量插入测量数据到数据库失败!原因:" + ex.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ iResult = -1;
+ }
}
}
return iResult;
@@ -251,27 +233,26 @@ namespace NSAnalysis.DAL
/// 要插入的数据表
public static void TWorkpieceListToSQLServer(DataTable InsertDT)
{
- using (SqlBulkCopy bulkCopy = new SqlBulkCopy(GetConn()))
+ using (var conn = new SqlConnection(connStr))
{
- try
+ conn.Open();
+ using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))
{
- bulkCopy.DestinationTableName = "TWorkpieceList";//要插入的表的表明,创造映射关系,比下面的直接写表名称 更加灵活
- bulkCopy.ColumnMappings.Add("WorkpieceID", "WorkpieceID");//映射字段名 DataTable列名 ,数据库 对应的列名
- bulkCopy.ColumnMappings.Add("DrawerID", "DrawerID");
- bulkCopy.ColumnMappings.Add("WorkpieceType", "WorkpieceType");
- bulkCopy.ColumnMappings.Add("TrayType", "TrayType");
- bulkCopy.ColumnMappings.Add("WorkpieceStatus", "WorkpieceStatus");
- bulkCopy.ColumnMappings.Add("WorkpiecePos", "WorkpiecePos");
- bulkCopy.WriteToServer(InsertDT);
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- finally
- {
- // Close the SqlDataReader. The SqlBulkCopy object is automatically closed at
- // the end of the using block.
+ try
+ {
+ bulkCopy.DestinationTableName = "TWorkpieceList";
+ bulkCopy.ColumnMappings.Add("WorkpieceID", "WorkpieceID");
+ bulkCopy.ColumnMappings.Add("DrawerID", "DrawerID");
+ bulkCopy.ColumnMappings.Add("WorkpieceType", "WorkpieceType");
+ bulkCopy.ColumnMappings.Add("TrayType", "TrayType");
+ bulkCopy.ColumnMappings.Add("WorkpieceStatus", "WorkpieceStatus");
+ bulkCopy.ColumnMappings.Add("WorkpiecePos", "WorkpiecePos");
+ bulkCopy.WriteToServer(InsertDT);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
}
}
}
@@ -287,24 +268,16 @@ namespace NSAnalysis.DAL
/// 数据集
public static void SqlBulkCopyInsert(string strDBTableName, DataTable InsertDataTable)
{
- try
+ using (var conn = new SqlConnection(connStr))
{
- using (SqlBulkCopy sqlRevdBulkCopy = new SqlBulkCopy(GetConn()))//引用SqlBulkCopy
+ conn.Open();
+ using (SqlBulkCopy sqlRevdBulkCopy = new SqlBulkCopy(conn))
{
- sqlRevdBulkCopy.DestinationTableName = strDBTableName;//数据库中对应的表名
-
- sqlRevdBulkCopy.NotifyAfter = InsertDataTable.Rows.Count;//有几行数据
-
- sqlRevdBulkCopy.WriteToServer(InsertDataTable);//数据导入数据库
-
- sqlRevdBulkCopy.Close();//关闭连接
+ sqlRevdBulkCopy.DestinationTableName = strDBTableName;
+ sqlRevdBulkCopy.NotifyAfter = InsertDataTable.Rows.Count;
+ sqlRevdBulkCopy.WriteToServer(InsertDataTable);
}
}
- catch (Exception ex)
- {
- Console.WriteLine("数据库处理出错,SqlBulkCopyInsert,原因:" + ex.Message);
- throw (ex);
- }
}
#endregion 使用SqlBulkCopy将DataTable中的数据批量插入数据库中
diff --git a/Analysis/FormMain.cs b/Analysis/FormMain.cs
index 7dc57d8..882cacd 100644
--- a/Analysis/FormMain.cs
+++ b/Analysis/FormMain.cs
@@ -6,6 +6,7 @@ using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Telerik.WinControls;
@@ -48,6 +49,7 @@ namespace NSAnalysis
{
private Timer fileSortTimer = new Timer(); // 定时器,用于定时分发任务
private FileSorter fileSorter = new FileSorter();
+ private int _isProcessing = 0; // 0=空闲, 1=处理中,防止定时器重入
#region 全局变量
@@ -282,7 +284,7 @@ namespace NSAnalysis
#endregion 分页相关
}
- private void DisplayMeasureData(string strCarID) // 其中 string strCarID 是车身ID_L 或 车身ID_R
+ private void DisplayMeasureData(string strCarID, string measureTime = "") // 其中 string strCarID 是车身ID_L 或 车身ID_R
{
try
{
@@ -293,27 +295,21 @@ namespace NSAnalysis
return;
}
AnalysisResult analysis = AnalysisResult.AnalyzeMeasureData(sampleData);
- //AnalysisResult.DisplayAnalysisResult(analysis);
- //表格行数
int dtRowCount = analysis.TotalCount;
- //超差个数
double OutCount = analysis.OutCount;
- //Ok个数
double OKCount = analysis.OKCount;
- //异常个数
double RejectedCount = analysis.RejectedCount;
- //合格率
double FPYPercent = analysis.FPYPercent;
+
// 更新统计信息显示
labVIN.Text = strCarID;
- labCarType.Text = ConfigDfn.strCarModel;
- //labPosition_L.Text = "左侧";
+ labCarType.Text = analysis.CarID; // 使用查询结果中的数据
labOKCount_L.Text = OKCount.ToString();
labNGCount_L.Text = OutCount.ToString();
labRejectCount_L.Text = RejectedCount.ToString();
labSumMeasureCount_L.Text = dtRowCount.ToString();
- labMeaTime_L.Text = ConfigDfn.strMeasureTime;
+ labMeaTime_L.Text = measureTime; // 使用传入的测量时间,不依赖全局变量
#region 表单区填充
@@ -359,16 +355,16 @@ namespace NSAnalysis
}
}
- private void FileSorter_OnFileParsed(string strCarID, string Position) //形如
+ private void FileSorter_OnFileParsed(string strCarID, string Position, string measureTime) //形如
{
// 线程安全更新 UI
if (InvokeRequired)
{
- Invoke(new Action(FileSorter_OnFileParsed), strCarID, Position);
+ Invoke(new Action(FileSorter_OnFileParsed), strCarID, Position, measureTime);
return;
}
// 显示数据 并更新单侧汇总结果, 此时为左侧或右侧数据
- DisplayMeasureData(strCarID);
+ DisplayMeasureData(strCarID, measureTime);
}
/// 通过给定的文件流,判断文件的编码类型
@@ -682,6 +678,13 @@ namespace NSAnalysis
private void FileSortTimer_Tick(object sender, EventArgs e) //分发定时器
{
+ // 防止上一轮未完成时重入
+ if (Interlocked.CompareExchange(ref _isProcessing, 1, 0) != 0)
+ {
+ MyBase.TraceWriteLine("[FileSortTimer] 上一轮分发任务仍在执行,跳过本次触发。");
+ return;
+ }
+
// 后台运行,避免阻塞UI
Task.Run(() =>
{
@@ -693,6 +696,10 @@ namespace NSAnalysis
{
MyBase.TraceWriteLine($"分发任务异常: {ex.Message}");
}
+ finally
+ {
+ Interlocked.Exchange(ref _isProcessing, 0);
+ }
});
}