Files
CJLR-Analysis/Analysis/CjlrForm/FileSorter.cs
T
2025-09-01 10:14:57 +08:00

710 lines
22 KiB
C#

using BaseFunction;
using NSAnalysis.DAL;
using NSAnalysis.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Text;
namespace NSAnalysis
{
public class FileSorter
{
public CjlrDAL _dal = new CjlrDAL();
//定义读取的位置
public int readRowIndex = 2; // 默认读取第3行(从0开始计数)
public int readColIndex = 1; // 默认读取第2列(从0开始计数)
public event Action<string> OnLog; // 日志事件
public event Action<string, string> OnFileParsed; // 解析完成后通知文件名
// 关键流程节点日志事件
public event Action<string> OnProcessStep; // 处理步骤日志事件
// 封装 OnProcessStep 事件
private void emitProcessStep(string message)
{
OnProcessStep?.Invoke(message);
//Console.WriteLine(message); // 控制台输出
}
public FileSorter()
{
//SQLHelper.connStr = DatabaseDfn.SqlConnectStr();
}
// 主逻辑处理
public void ProcessFiles()
{
var tasks = GetTaskRecords();
// 增加空检查
if (tasks == null || tasks.Rows.Count == 0)
{
Trace("没有找到任何任务记录,处理终止。");
return;
}
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");
//打印 dt
//PrintDataTable(dt);
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}");
// 解析入库
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))
{
// 生成备份文件名,格式如:xxx.csv.bak_20240613_153012
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, // 假设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, // 假设2表示未处理
TaskDetail = "文件未匹配",
CreateDate = DateTime.Now
};
try
{
_dal.InsertTaskDetail(detailModel);
}
catch (Exception ex)
{
Trace($"记录错误到数据库失败: {ex.Message}");
}
}
#endregion
}
}
/// <summary>
/// 检查CSV文件中指定行列的字符串是否匹配目标值
/// </summary>
/// <param name="filePath">CSV文件路径</param>
/// <param name="targetValue">要匹配的目标字符串</param>
/// <param name="rowIndex">行索引(从0开始)</param>
/// <param name="colIndex">列索引(从0开始)</param>
/// <returns>匹配成功返回true,否则false</returns>
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 GroupName, string Position)
{
#region
DataTable sampleData = _dal.SelectMeasureResultByCarID(ConfigDfn.strEquipNo, GroupName);
if (sampleData == null || sampleData.Rows.Count == 0)
{
MyBase.TraceWriteLine("没有测量数据,无法生成统计信息。");
// 触发日志事件
emitProcessStep(Position + " 没有测量数据,无法生成统计信息。");
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;
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 = ConfigDfn.strEquipNo;
tmrm.CarType = ConfigDfn.strCarModel;
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 = ConfigDfn.strMeasureTime;
_dal.InsertTMeasureResult(tmrm);
MyBase.TraceWriteLine("将总结果插入数据库完毕。");
emitProcessStep($"---> 3、统计信息已生成: 位置: {Position}, 总测量项: {dtRowCount}, 合格项: {OKCount}, 不合格项: {OutCount}, 异常项: {RejectedCount}, FPY: {FPYPercent:F4}");
#endregion
}
// 导入CSV文件到数据库
public void ImportCsv2Sql(string filePath)
{
var records = new List<CJLR_MeaDataModel>();
var lineNo = 0; // 行号计数器
var groupName = string.Empty; // 组名变量
var position = string.Empty; // 位置变量
emitProcessStep($"正在处理: {filePath}");
// 判断文件是否已经处理过
if (_dal.IsFileProcessed(filePath))
{
MyBase.TraceWriteLine($"文件已处理过,跳过: {filePath}");
emitProcessStep($"---> 2、文件已处理过,跳过: {filePath}");
return;
}
// 解析数据之前,备份原始数据,如果已存在备份文件,则覆盖, 备份到 程序根目录\Backup 文件夹
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))
{
// Skip header
reader.ReadLine();
lineNo = 1; // 初始化行号计数器
while (!reader.EndOfStream)
{
lineNo++; // 增加行号计数器
var line = reader.ReadLine();
var values = line.Split(','); // 假设 CSV 使用制表符分隔
// 跳过前两行(如果有标题行或其他非数据行
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#") || line.StartsWith("//") || line.StartsWith("MeasPoint.Name"))
{
continue; // 跳过空行或注释行
}
// 跳过前两行(如果有标题行或其他非数据行),理论应该有19列
if (values.Length < 22)
{
MyBase.TraceWriteLine("CSV行数据不完整,跳过该行:" + line);
continue; // 跳过不完整的行
}
// 判断 values[2] 是否为 ,如果是则跳过该行
if (string.IsNullOrEmpty(values[2]))
{
MyBase.TraceWriteLine($"第 {lineNo} 行数据为0,跳过该行:" + line);
continue; // 跳过该行
}
// 创建 MeasurementRecord 对象并填充数据
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}");
// 1、解析出错的,移动到 源路径文件夹\Error 文件夹
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;
}
try
{
// 取第一条记录的时间作为测量时间
if (records.Count > 0)
{
var firstRecord = records[0];
ConfigDfn.strMeasureTime = firstRecord.MeasureDate.ToString("yyyy-MM-dd") + " " + firstRecord.MeasureTime.ToString(@"hh\:mm\:ss");
// 记录时间
MyBase.TraceWriteLine("测量时间:" + ConfigDfn.strMeasureTime);
// 获取车号
MyBase.TraceWriteLine("--------------------------------------------------------");
ConfigDfn.strEquipNo = firstRecord.ProductNum;
MyBase.TraceWriteLine("车号:" + ConfigDfn.strEquipNo);
ConfigDfn.strCarModel = firstRecord.Model; //获取车型
MyBase.TraceWriteLine("车型:" + ConfigDfn.strCarModel);
// 从 firstRecord.GroupName 中提取位置 ,使用下划线分隔 例如:X540_R,提取 R 作为位置
groupName = firstRecord.GroupName;
MyBase.TraceWriteLine("组名:" + firstRecord.GroupName);
// 如果 GroupName 为空,则使用默认位置
if (string.IsNullOrEmpty(firstRecord.GroupName))
{
MyBase.TraceWriteLine("组名为空,使用默认位置。");
ConfigDfn.strEquipPosition = "Default"; // 默认位置
}
else
{
// 使用下划线分隔 GroupName,提取最后一部分作为位置
var parts2 = firstRecord.GroupName.Split('_');
if (parts2.Length > 1 && !string.IsNullOrEmpty(parts2[1]))
{
// 提取下划线后第一个字符
ConfigDfn.strEquipPosition = parts2[1].Substring(0, 1);
}
else
{
ConfigDfn.strEquipPosition = firstRecord.GroupName; // 如果没有下划线,直接使用原值
}
}
// 打印提取后位置
MyBase.TraceWriteLine("位置:" + ConfigDfn.strEquipPosition);
MyBase.TraceWriteLine("测量时间:" + ConfigDfn.strMeasureTime);
emitProcessStep($"---> 1、解析到, 车号: {ConfigDfn.strEquipNo} 车型: {ConfigDfn.strCarModel} 位置: {ConfigDfn.strEquipPosition} 测量时间: {ConfigDfn.strMeasureTime}");
}
else
{
MyBase.TraceWriteLine("没有找到有效的测量记录,无法设置测量时间。CSV文件导入到数据库失败!");
//将错误信息
emitProcessStep($"---> 2、没有找到有效的测量记录,无法设置测量时间。CSV文件导入到数据库失败!");
// 2、解析未出错(有可能整个文件被跳过),但没有有效数据的,移动到 源路径文件夹\Error 文件夹
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;
}
// 逐条插入数据到数据库
foreach (var record in records)
{
_dal.InsertOrUpdateCJLRMeaData(record);
}
// 记录处理文件到数据库
_dal.InsertProcessedFile(filePath);
MyBase.TraceWriteLine("CSV文件导入到数据库成功!");
emitProcessStep($"---> 2、CSV文件导入到数据库成功");
#region
GenerateSingleSideStatistics(groupName, ConfigDfn.strEquipPosition);
#endregion
MyBase.TraceWriteLine("--------------------------------------------------------");
}
catch (Exception ex)
{
MyBase.TraceWriteLine("导入CSV文件时发生错误:" + ex.Message);
emitProcessStep($"---> 2、导入CSV文件时发生错误: {ex.Message}");
}
}
//解析EH3 CSV文件函数
public void AnalysisNxsCSV(string strCSVName)
{
// 判断文件是否存在
if (!File.Exists(strCSVName))
{
MyBase.TraceWriteLine("文件不存在:" + strCSVName);
return;
}
try
{
// 解析 CSV 文件并导入到数据库
ImportCsv2Sql(strCSVName);
// 解析完成后触发事件
if (!string.IsNullOrEmpty(ConfigDfn.strEquipNo))
{
// 构造 事件参数
Trace($"触发事件,车号: {ConfigDfn.strEquipNo} 位置: {ConfigDfn.strEquipPosition}");
OnFileParsed?.Invoke(ConfigDfn.strEquipNo, ConfigDfn.strEquipPosition);
}
// 每次解析完一个文件后,检查是否有双侧测量结果
bool isMeasureComplete = _dal.HasBothSidesMeasureResult(ConfigDfn.strEquipNo);
if (isMeasureComplete)
{
MyBase.TraceWriteLine("双侧测量结果已完成,开始生成客户报告。");
emitProcessStep($"---> 4、双侧测量结果已完成,开始生成客户报告,车号: {ConfigDfn.strEquipNo}");
// 生成客户报告
GenCustomerReport(ConfigDfn.strEquipNo);
}
else
{
MyBase.TraceWriteLine("双侧测量结果未完成,跳过客户报告生成。");
emitProcessStep($"---> 4、双侧测量结果未完成,跳过客户报告生成,车号: {ConfigDfn.strEquipNo}");
}
}
catch (Exception ex)
{
MyBase.TraceWriteLine("解析 CSV 文件时发生错误:" + ex.Message);
}
}
// 生成客户报告函数
private void GenCustomerReport(string strCarID)
{
// 从数据库获取测量数据
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}");
}
// 构造备份路径 ,备份到 程序根目录\ReportBackup 文件夹
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, 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报告函数
private void GenerateCsvReport(string strCarID, 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}", ConfigDfn.strCarModel);
}
if (processedLine.Contains("{Part_code}"))
{
if (ConfigDfn.strCarModel == "E03")
processedLine = processedLine.Replace("{Part_code}", "E03_5000000FAonline");
else if (ConfigDfn.strCarModel == "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)
{
//sb.AppendFormat("{0},{1},{2}\n",
// row["PointName"], row["DimensionName"], row["DimensionValue"]);
var dimensionValue = row["DimensionValue"]?.ToString();
if (dimensionValue != null && dimensionValue.Contains("1.#R"))
{
dimensionValue = "";
}
sb.AppendFormat("{0},{1},{2}\n",
row["PointName"], row["DimensionName"], dimensionValue);
}
// 可根据实际需求添加统计行 sb.AppendLine("POP,P,99.99");
// 写入文件
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();
//string testPath = @"D:\CJLR\DATA\Input\LLL\K0902906.csv";
//bool result = MatchCsvValue(testPath, "X540_L", 3, 1);
//MyBase.TraceWriteLine($"匹配结果: {result}");
GenCustomerReport("K0902906");
}
}
}