Files
CJLR-Analysis/Analysis/CjlrForm/FileSorter.cs
T
zhengxuan.zhang 08e623410f 260520 优化历史已解析入库但没有分发成功的问题
新到文件是否仍然正常出现 匹配成功 -> 待解析区 -> 解析成功 -> 正式区 -> 双侧完成 -> 客户报告生成。
历史遗留文件是否出现 已补充分发到正式区 这类新日志,并从源目录消失。
已经真正分发完成的文件,是否仍然保持 已处理且目标区域已存在,跳过,没有重复搬运。
2026-05-20 16:06:37 +08:00

833 lines
26 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
{
/// <summary>
/// CSV解析结果,替代全局静态变量 ConfigDfn.strEquipNo 等,消除多线程竞争
/// </summary>
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
{
private sealed class TaskRule
{
public string ModelName { get; set; }
public string ModelCode { get; set; }
public string Position { get; set; }
public string SourceDir { get; set; }
public string TargetDir { get; set; }
public string MatchToken { get; set; }
}
private sealed class StagingPaths
{
public string FinalDir { get; set; }
public string PendingDir { get; set; }
public string ErrorDir { get; set; }
}
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, string> OnFileParsed; // 解析完成后通知:车号、位置、测量时间
// 关键流程节点日志事件
public event Action<string> 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} 个分发任务,开始逐一执行。");
var rulesBySource = new Dictionary<string, List<TaskRule>>(StringComparer.OrdinalIgnoreCase);
foreach (DataRow task in tasks.Rows)
{
var rule = new TaskRule
{
ModelName = task["modelsName"].ToString(),
ModelCode = task["modelsCode"].ToString(),
Position = task["position"].ToString(),
SourceDir = task["sourceFile"].ToString(),
TargetDir = task["targetFile"].ToString()
};
rule.MatchToken = NormalizeMatchToken($"{rule.ModelCode}_{rule.Position}");
if (!rulesBySource.ContainsKey(rule.SourceDir))
{
rulesBySource[rule.SourceDir] = new List<TaskRule>();
}
rulesBySource[rule.SourceDir].Add(rule);
}
foreach (var item in rulesBySource)
{
string sourceDir = item.Key;
List<TaskRule> rules = item.Value;
Trace($"[ProcessFiles] 开始扫描源路径: {sourceDir},共 {rules.Count} 条匹配规则。");
foreach (var rule in rules)
{
Trace($"[ProcessFiles] 已加载分发任务 - 源路径: {rule.SourceDir}, 目标路径: {rule.TargetDir}, 匹配字符: {rule.ModelCode} 位置:{rule.Position}, 标准化特征符: {rule.MatchToken}");
}
if (!Directory.Exists(sourceDir))
{
Trace($"[ProcessFiles] 源文件地址不存在或错误: {sourceDir}");
continue;
}
ProcessDirectory(sourceDir, rules);
}
}
// 获取任务记录
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, List<TaskRule> rules)
{
foreach (string file in Directory.GetFiles(sourceDir, "*.csv"))
{
Trace($"正在处理文件 : {file}");
if (!ConfigDfn.iEnableSort)
{
return;
}
string rawMatchValue;
string normalizedMatchValue;
if (!TryReadMatchToken(file, readRowIndex, readColIndex, out rawMatchValue, out normalizedMatchValue))
{
Trace($"无法读取匹配特征,跳过文件: {file}");
emitProcessStep($"---> 2、无法读取匹配特征,跳过文件: {file}");
continue;
}
TaskRule matchedRule = null;
foreach (var rule in rules)
{
if (string.Equals(rule.MatchToken, normalizedMatchValue, StringComparison.OrdinalIgnoreCase))
{
matchedRule = rule;
break;
}
}
if (matchedRule == null)
{
Trace($"未匹配到文件: {file},原始特征符: {rawMatchValue},标准化后: {normalizedMatchValue}");
emitProcessStep($"---> 5、未匹配到文件: {Path.GetFileName(file)},特征符: {normalizedMatchValue}");
continue;
}
StagingPaths staging = EnsureStagingDirectories(matchedRule.TargetDir);
if (_dal.IsFileProcessed(file))
{
if (IsFileAlreadyInTargetArea(file, staging))
{
Trace($"文件已处理且目标区域已存在,跳过后续匹配和解析: {file}");
emitProcessStep($"---> 2、文件已处理且目标区域已存在,跳过: {file}");
continue;
}
string finalFile = MoveMatchedFile(file, staging.FinalDir);
Trace($"文件已有历史解析记录,但仍停留在源目录,已补充分发到正式区: {file} -> {finalFile}");
emitProcessStep($"---> 5、检测到历史已解析未分发文件,已补充分发: -> {finalFile}");
InsertTaskDetail(matchedRule, file, finalFile, 1, "历史已解析文件补充分发到正式区");
continue;
}
Trace($"匹配成功,准备移入待解析区: {file} -> {staging.PendingDir},原始特征符: {rawMatchValue},标准化后: {normalizedMatchValue}");
string pendingFile = MoveMatchedFile(file, staging.PendingDir);
Trace($"已移入待解析区: {file} -> {pendingFile}");
emitProcessStep($"---> 5、文件已移入待解析区: -> {pendingFile}");
InsertTaskDetail(matchedRule, file, pendingFile, 1, "文件已移入待解析区");
CsvParseResult parseResult = AnalysisNxsCSV(pendingFile);
if (parseResult.Success)
{
string finalFile = MoveMatchedFile(pendingFile, staging.FinalDir);
Trace($"解析成功,已转入正式区: {pendingFile} -> {finalFile}");
emitProcessStep($"---> 6、解析成功,已转入正式区: -> {finalFile}");
InsertTaskDetail(matchedRule, pendingFile, finalFile, 1, "解析成功并转入正式区");
}
else
{
if (File.Exists(pendingFile))
{
string errorFile = MoveMatchedFile(pendingFile, staging.ErrorDir);
Trace($"解析失败,已转入错误区: {pendingFile} -> {errorFile}");
emitProcessStep($"---> 6、解析失败,已转入错误区: -> {errorFile}");
InsertTaskDetail(matchedRule, pendingFile, errorFile, 2, "解析失败并转入错误区");
}
else
{
Trace($"解析失败后文件已不存在,无法转入错误区: {pendingFile}");
emitProcessStep($"---> 6、解析失败后文件已不存在,无法转入错误区: {pendingFile}");
}
}
}
}
/// <summary>
/// 检查CSV文件中指定行列的字符串是否匹配目标值
/// </summary>
public static bool MatchCsvValue(string filePath, string targetValue, int rowIndex, int colIndex)
{
MyBase.TraceWriteLine($"[MatchCsvValue] 检查文件: {filePath}, 行索引: {rowIndex}, 列索引: {colIndex}, 目标值: {targetValue}");
try
{
string rawValue;
if (!TryReadCsvCellValue(filePath, rowIndex, colIndex, out rawValue))
return false;
string normalizedSource = NormalizeMatchToken(rawValue);
string normalizedTarget = NormalizeMatchToken(targetValue);
MyBase.TraceWriteLine($"[MatchCsvValue] 原始值: {rawValue}, 标准化原始值: {normalizedSource}, 标准化目标值: {normalizedTarget}");
return string.Equals(normalizedSource, normalizedTarget, StringComparison.OrdinalIgnoreCase);
}
catch (Exception ex)
{
MyBase.TraceWriteLine($"处理CSV文件时出错: {ex.Message}");
return false;
}
}
private static bool TryReadMatchToken(string filePath, int rowIndex, int colIndex, out string rawValue, out string normalizedValue)
{
rawValue = string.Empty;
normalizedValue = string.Empty;
if (!TryReadCsvCellValue(filePath, rowIndex, colIndex, out rawValue))
{
return false;
}
normalizedValue = NormalizeMatchToken(rawValue);
MyBase.TraceWriteLine($"[MatchCsvValue] 检查文件: {filePath}, 行索引: {rowIndex}, 列索引: {colIndex}, 原始值: {rawValue}, 标准化值: {normalizedValue}");
return true;
}
private static bool TryReadCsvCellValue(string filePath, int rowIndex, int colIndex, out string cellValue)
{
cellValue = string.Empty;
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;
}
cellValue = columns[colIndex].Trim().Trim('"');
return !string.IsNullOrEmpty(cellValue);
}
private static string NormalizeMatchToken(string rawValue)
{
if (string.IsNullOrWhiteSpace(rawValue))
{
return string.Empty;
}
string cleaned = rawValue.Trim().Trim('"');
string[] parts = cleaned.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0)
{
return cleaned.ToUpperInvariant();
}
if (parts.Length >= 3 && IsSideToken(parts[parts.Length - 1]))
{
string prefix = string.Join("_", parts, 0, parts.Length - 1).ToUpperInvariant();
return $"{prefix}_{char.ToUpperInvariant(parts[parts.Length - 1][0])}";
}
if (parts.Length >= 2 && IsSideToken(parts[1]))
{
return $"{parts[0].ToUpperInvariant()}_{char.ToUpperInvariant(parts[1][0])}";
}
return cleaned.ToUpperInvariant();
}
private static bool IsSideToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
return false;
}
char side = char.ToUpperInvariant(token.Trim()[0]);
return side == 'L' || side == 'R';
}
private static StagingPaths EnsureStagingDirectories(string targetDir)
{
var paths = new StagingPaths
{
FinalDir = targetDir,
PendingDir = Path.Combine(targetDir, "_pending"),
ErrorDir = Path.Combine(targetDir, "_error")
};
EnsureDirectory(paths.FinalDir);
EnsureDirectory(paths.PendingDir);
EnsureDirectory(paths.ErrorDir);
return paths;
}
private static void EnsureDirectory(string dir)
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
MyBase.TraceWriteLine($"创建目标文件夹: {dir}");
}
}
private static bool IsFileAlreadyInTargetArea(string sourceFile, StagingPaths staging)
{
string fileName = Path.GetFileName(sourceFile);
return File.Exists(Path.Combine(staging.FinalDir, fileName))
|| File.Exists(Path.Combine(staging.PendingDir, fileName))
|| File.Exists(Path.Combine(staging.ErrorDir, fileName));
}
private static string MoveMatchedFile(string sourceFile, string targetDir)
{
string destFile = Path.Combine(targetDir, Path.GetFileName(sourceFile));
if (File.Exists(destFile))
{
string backupFile = destFile + ".bak_" + DateTime.Now.ToString("yyyyMMdd_HHmmss");
File.Move(destFile, backupFile);
MyBase.TraceWriteLine($"目标文件已存在,已重命名为备份文件: {backupFile}");
}
File.Move(sourceFile, destFile);
return destFile;
}
private void InsertTaskDetail(TaskRule rule, string sourceFile, string targetFile, int taskStatus, string taskDetail)
{
var detailModel = new CjlrTaskReleaseDetailModel
{
ModelsName = rule.ModelName,
ModelsCode = rule.ModelCode,
Position = rule.Position,
SourceFile = sourceFile,
TargetFile = targetFile,
TaskFileName = Path.GetFileName(sourceFile),
TaskStatus = taskStatus,
TaskDetail = taskDetail,
CreateDate = DateTime.Now
};
_dal.InsertTaskDetail(detailModel);
}
// 生成单侧统计信息的方法(使用局部参数,不再依赖全局变量)
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<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 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");
}
}
}