using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using MES.Application.InpuStorage.WInterface;
using MES.Domain.Entities;
using MES.Domain.InpuStorage.WInterface;
using MES.Shared.DTOs.Requests.InpuStorage;
using MES.Shared.DTOs.Responses.InputStorage;
using MES.Shared.Utilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using SqlSugar;
using static MES.Shared.Utilities.materialConfigsControl;
// 主服务类(实现接口)
namespace MES.Application.InpuStorage.Repository
{
public class InputStorageService : IInputStorageService
{
private readonly IMapper _mapper;
private readonly IPrintDataMapperFactory _mapperFactory;
private readonly IInputStorageControl _inputStorageControl;
private readonly ILogger _logger;
private readonly Dictionary<string, MaterialConfig> _materialConfigs;
private readonly string _baseReportPath;
// 常量定义 private const string StatusNG = "NG"; private const string StatusOK = "OK"; /// <summary> /// 列印標籤要加的卡點 /// </summary> private List<string> CheckProcedures { get; } = new List<string> { "PDL_CheckPackListPVS", "PDL_CheckPackListFCC", "PDL_CheckPackListQnty", "PDL_CheckPackListProdBasic", "PDL_CheckPackListOSP", "PDL_CheckPackOSP_2433", "sp_pack_2d_Code" }; // 构造函数注入依赖 public InputStorageService( IMapper mapper, IPrintDataMapperFactory mapperFactory, IInputStorageControl inputStorageControl,IConfiguration configuration,ILogger<InputStorageService> logger) { _mapper = mapper; _mapperFactory = mapperFactory; _inputStorageControl = inputStorageControl; _logger = logger; _baseReportPath = configuration["ReportPaths:BaseReportPath"] ?? @"\\10.112.65.20\acme_rpt$\Report\生管報表"; _materialConfigs = materialConfigsControl.LoadMaterialConfigs(configuration); } /// <summary> /// 主逻辑(实现接口方法) /// </summary> public async Task<PDL_PackingResponse> CheckInputStorage(PDL_PackingRequest query) { var response = new PDL_PackingResponse(); try { // 获取批号信息 var lotInfos = await GetLotInfoAsync(query);// await _inputStorageControl.GetLotInfo(_mapper.Map<LotInfo>(query)) if (!lotInfos.Any()) return SetErrorResponse(response, StatusNG, "2", "批号不存在"); // 進行卡點卡控 var spParams = CreateSpParameters(("@LotNum", query.LotNum)); foreach (var procedureName in CheckProcedures) { var errorResponse = await ExecuteCheckProcedure(procedureName, spParams, response); if (errorResponse != null) { return errorResponse; // 遇到首个错误立即返回 } } var spPtint = await _inputStorageControl.GetDataSetProcedure("PDL_Ptint", spParams); if (spPtint?.Tables.Count > 0 && spPtint.Tables[0].Rows.Count > 0) { return SetErrorResponse(response, StatusNG, "2", "此料號未走表面處理流程,不可列印標籤!!!"); } var spEXPDate = await _inputStorageControl.GetDataSetProcedure("PDL_SP_CKPackingEXPDate", spParams); if (spEXPDate?.Tables.Count > 0 && spEXPDate.Tables[0].Rows.Count > 0) { var flagValue = spEXPDate.Tables[0].Rows[0]["Resault"]?.ToString(); if (flagValue == "1") { return SetErrorResponse(response, StatusNG, "2", "此批號有效期已過,無法列印標籤!!!"); } } //取廠別 var lineId = lotInfos.First().LineID?.ToString().Trim() ?? "0"; return lineId switch { "1" => await ProcessLine1Logic(response, query, lotInfos.First().PartNum), "3" => SetErrorResponse(response, StatusNG, "7", "Line3功能待实现"), _ => SetErrorResponse(response, StatusNG, "2", "未獲取到廠別") }; } catch (Exception ex) { _logger.LogError(ex, "系统异常: {Message}", ex.Message); return SetErrorResponse(response, StatusNG, "99", $"系统异常: {ex.Message}"); } } // Line=1业务逻辑处理 private async Task<PDL_PackingResponse> ProcessLine1Logic(PDL_PackingResponse response, PDL_PackingRequest query, string partNum) { // 获取包装数据 var packDataList = await GetPackDataAsync(query); if (!packDataList.Any()) return SetErrorResponse(response, StatusNG, "3", "包裝資料不存在"); var vpartNum = GetPartNum(partNum); var mainConfig = await _inputStorageControl.LoadConfigByPartNum(vpartNum,1); if (mainConfig?.Any() != true) { return SetErrorResponse(response, StatusNG, "3", $"此料號尚未開發自動包裝機程式: {vpartNum}"); } var config = mainConfig.First(); var inputParams = config.HasSpecialJudgment ? await GetSpecialParameters(config, vpartNum, query.LotNum) : new Dictionary<string, string>(); // 获取配置信息 var spName = GetConfigValue(config, "sp_name", inputParams) as string; var labelPath = GetConfigValue(config, "template_path", inputParams) as string; var related = GetConfigValue(config, "related_num", inputParams) as string; var resultFields = GetConfigValue(config, "result_fields", inputParams) as List<string>; var fieldRenames = GetConfigValue(config, "field_rename", inputParams) as Dictionary<string, string> ?? new Dictionary<string, string>(); // 提供默认值; if (string.IsNullOrEmpty(spName) || string.IsNullOrEmpty(labelPath) || string.IsNullOrEmpty(related) || resultFields == null) { return SetErrorResponse(response, StatusNG, "3", "未获取到完整配置信息(存储过程名/模板路径/结果字段)"); } // 执行存储过程 var spParams = CreateSpParameters((" @LotNum", query.LotNum)); var spResult = await _inputStorageControl.GetDataSetProcedure(spName, spParams); if (spResult?.Tables.Count == 0 || spResult.Tables[0].Rows.Count == 0) { return SetErrorResponse(response, StatusNG, "3", "存储过程无返回数据"); } // 使用工厂创建映射器 var mapper = _mapperFactory.Create(vpartNum); var printData = mapper.Map(spResult.Tables[0], resultFields, fieldRenames, vpartNum); // 映射打印数据 response.StatusCode = "1"; response.CheckResult = StatusOK; response.Message = "返回成功"; response.LabelPath = Path.Combine(_baseReportPath, labelPath.Trim()); response.Related = related; response.PackData = packDataList; //response.PrintData = MapPrintData(spResult.Tables[0], resultFields, fieldRenames, vpartNum); response.PrintData = printData; return response; } // 獲取料號前4碼 private string GetPartNum(string partNum) => partNum.Length >= 4 ? partNum.Substring(0, 4) : partNum; // 异步获取批号信息 private async Task<List<LotInfo>> GetLotInfoAsync(PDL_PackingRequest query) { var lotInfo = _mapper.Map<LotInfo>(query); var result = await _inputStorageControl.GetLotInfo(lotInfo); return result?.ToList() ?? new List<LotInfo>(); } // 异步获取包装数据 private async Task<IEnumerable<PackingListDtl>> GetPackDataAsync(PDL_PackingRequest query) { var packDtl = _mapper.Map<PackingListDtl>(query); return await _inputStorageControl.GetPDL_PackData(packDtl) ?? Enumerable.Empty<PackingListDtl>(); } // 通用检查方法(提取重复逻辑) async Task<PDL_PackingResponse> ExecuteCheckProcedure( string procedureName, IEnumerable<SqlSugar.SugarParameter> parameters, PDL_PackingResponse response ) { // 类型匹配:parameters 直接传递给 GetDataSetProcedure var dataSet = await _inputStorageControl.GetDataSetProcedure(procedureName, parameters); if (dataSet?.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0) { var firstRow = dataSet.Tables[0].Rows[0]; var flagValue = firstRow["Flag"]?.ToString(); if (flagValue == "1") { return SetErrorResponse(response, StatusNG, "2", firstRow["Notes"]?.ToString()); } } return null; // 检查通过返回 null } // 配置获取逻辑 public object GetConfigValue(PackingMainConfig config, string configType, Dictionary<string, string> inputParams) { // 1. 优先匹配非默认规则 foreach (var rule in config.ConditionRules.Where(r => !r.IsDefault)) { if (inputParams.TryGetValue(rule.ConditionType, out string inputValue) && IsConditionMatch(rule.ConditionValue, inputValue)) { if (rule.ResultConfigs.TryGetValue(configType, out object matchedValue)) { _logger.LogInformation("匹配规则: {ConditionType}={ConditionValue}, 值: {Value}", rule.ConditionType, rule.ConditionValue, matchedValue); return matchedValue; } } } // 2. 匹配默认规则 var defaultRule = config.ConditionRules.FirstOrDefault(r => r.IsDefault); if (defaultRule?.ResultConfigs.TryGetValue(configType, out object defaultValue) == true) { _logger.LogInformation("使用默认规则, 值: {Value}", defaultValue); return defaultValue; } // 3. 回退到任意匹配的规则 foreach (var rule in config.ConditionRules) { if (rule.ResultConfigs.TryGetValue(configType, out object fallbackValue)) { _logger.LogInformation("使用后备规则: {ConditionType}, 值: {Value}", rule.ConditionType, fallbackValue); return fallbackValue; } } _logger.LogWarning("未找到 {ConfigType} 的配置值", configType); return null; } // 条件匹配逻辑封装 private bool IsConditionMatch(string conditionValue, string inputValue) { if (conditionValue.StartsWith("[", StringComparison.Ordinal) && conditionValue.EndsWith("]", StringComparison.Ordinal)) { var validValues = conditionValue.Trim('[', ']') .Split(',') .Select(v => v.Trim().Trim('\'')) .ToList(); return validValues.Contains(inputValue); } return inputValue == conditionValue; } /// <summary> /// 快速创建存储过程参数列表 /// </summary> private List<SugarParameter> CreateSpParameters(params (string Name, object Value)[] parameters) { return parameters.Select(p => new SugarParameter(p.Name, p.Value)).ToList(); } // 获取特殊料号参数 private async Task<Dictionary<string, string>> GetSpecialParameters(PackingMainConfig config, string partNum, string lotNum) { // 创建用于存储特殊参数的字典 var specialParams = new Dictionary<string, string>(); // 仅处理特定PartNum的逻辑 if (partNum == "2866") { // 准备存储过程参数 var spParams = CreateSpParameters(("@LotNum", lotNum)); // 调用存储过程获取数据(添加空值检查,避免NullReferenceException) var specialDs = await _inputStorageControl.GetDataSetProcedure(config.SpecialCheckSpName, spParams); // 验证数据集和表结构有效性 if (specialDs?.Tables.Count > 0 && specialDs.Tables[0].Rows.Count > 0) { var dataRow = specialDs.Tables[0].Rows[0]; // 从数据行提取值,使用空合并运算符确保非null specialParams["flagDummy"] = dataRow["FlagDummy"]?.ToString() ?? string.Empty; specialParams["pdFamily"] = dataRow["pd_family"]?.ToString() ?? string.Empty; } } // 返回填充后的参数字典(无数据时返回空字典而非null) return specialParams; } // 设置错误响应 private PDL_PackingResponse SetErrorResponse(PDL_PackingResponse response, string checkResult, string statusCode, string message) { response.CheckResult = checkResult; response.StatusCode = statusCode; response.Message = message; return response; } }
}
// 数据映射层
using System.Data;
using System.Dynamic;
using MES.Application.InpuStorage.WInterface;
using MES.Domain.Entities;
using MES.Domain.InpuStorage.WInterface;
using MES.Shared.DTOs.Requests.InpuStorage;
using MES.Shared.DTOs.Responses.InputStorage;
namespace MES.Application.InpuStorage.Repository
{
// 映射器工厂
public interface IPrintDataMapperFactory
{
IPrintDataMapper Create(string partNum);
}
public class PrintDataMapperFactory : IPrintDataMapperFactory { public IPrintDataMapper Create(string partNum) => partNum switch { "5808" => new Map5808LabelData(), _ => new MapPrintData() }; } // 通用映射器 public class MapPrintData : IPrintDataMapper { public List<object> Map(DataTable dataTable, List<string> fields, Dictionary<string, string> fieldRenames, string partNum) { return dataTable.AsEnumerable().Select(row => { dynamic expando = new ExpandoObject(); var dict = (IDictionary<string, object>)expando; foreach (var field in fields) { var targetField = fieldRenames.GetValueOrDefault(field, field); dict[targetField] = row[field]?.ToString() ?? "N/A"; } return expando; }).ToList(); } } // 特殊料号映射器 public class Map5808LabelData : IPrintDataMapper { public List<object> Map(DataTable dataTable, List<string> fields, Dictionary<string, string> fieldRenames, string partNum) { return dataTable.AsEnumerable().Select(row => { dynamic expando = new ExpandoObject(); var expandoDict = expando as IDictionary<string, object>; // 处理配置的原始字段(应用重命名) foreach (string sourceField in fields) { // 跳过需要特殊处理的字段 if (sourceField == "Remark" || sourceField == "MARK2" || sourceField == "bar_unit_qty" || sourceField == "llpiece" || sourceField == "ShortPartnum" || sourceField == "customer_name" || sourceField == "cust_part" || sourceField == "seq_no" || sourceField == "tnum") continue; string targetField = fieldRenames.ContainsKey(sourceField) ? fieldRenames[sourceField] : sourceField; // 确保字段存在 object value = dataTable.Columns.Contains(sourceField) ? row[sourceField]?.ToString().Trim() : "N/A"; expandoDict[targetField] = value; } // 2. 特殊字段转换逻辑(复刻VB) // 获取源值 string remark = dataTable.Columns.Contains("Remark") ? row["Remark"]?.ToString().Trim() ?? "" : ""; string mark2 = dataTable.Columns.Contains("MARK2") ? row["MARK2"]?.ToString().Trim() ?? "" : ""; string barUnitQty = dataTable.Columns.Contains("bar_unit_qty") ? row["bar_unit_qty"]?.ToString().Trim() ?? "" : ""; string llpiece = dataTable.Columns.Contains("llpiece") ? row["llpiece"]?.ToString().Trim() ?? "" : ""; string shortPartNum = dataTable.Columns.Contains("ShortPartnum") ? row["ShortPartnum"]?.ToString().Trim() ?? "" : ""; string customer_name = dataTable.Columns.Contains("customer_name") ? row["customer_name"]?.ToString().Trim() ?? "" : ""; string cust_part = dataTable.Columns.Contains("cust_part") ? row["cust_part"]?.ToString().Trim() ?? "" : ""; string seq_no = dataTable.Columns.Contains("seq_no") ? row["seq_no"]?.ToString().Trim() ?? "" : ""; string tnum = dataTable.Columns.Contains("tnum") ? row["tnum"]?.ToString().Trim() ?? "" : ""; // 3. 计算转换字段 // LREMARK转换 string lremark = remark == "LASER MARK" ? "LASER MARK" : ""; // PB/NON转换 string pbValue = ""; string nonHfValue = ""; switch (mark2) { case "1": pbValue = "Pb"; nonHfValue = "Non-HF"; break; case "2": pbValue = "Pb"; break; case "3": nonHfValue = "Non-HF"; break; } // 复合字段 string CustPartNum = $"{customer_name}({cust_part})"; string xOutValue = $"{barUnitQty}/{llpiece}"; string mftValue = $"({shortPartNum})"; string total = $"{seq_no}/{tnum}"; // 4. 添加转换字段(应用重命名) // 特殊字段映射 AddFieldWithRename(expandoDict, "CUSTPARTNUM", CustPartNum, fieldRenames); AddFieldWithRename(expandoDict, "TOTALPAGE", total, fieldRenames); AddFieldWithRename(expandoDict, "LREMARK", lremark, fieldRenames); AddFieldWithRename(expandoDict, "PB", pbValue, fieldRenames); AddFieldWithRename(expandoDict, "NON", nonHfValue, fieldRenames); AddFieldWithRename(expandoDict, "X_OUT", xOutValue, fieldRenames); AddFieldWithRename(expandoDict, "MFT", mftValue, fieldRenames); return expando; }).ToList(); } private void AddFieldWithRename(IDictionary<string, object> dict, string fieldName, object value, Dictionary<string, string> fieldRenames) { string targetField = fieldRenames.ContainsKey(fieldName) ? fieldRenames[fieldName] : fieldName; dict[targetField] = value; } }
}
SELECT *
FROM PackingMainConfig
1 1 2866 1 PDL_PackingCheck 2866系列物料配置 NULL NULL
2 1 5808 0 5808系列物料配置 NULL NULL
SELECT *
FROM PackingConditionRule
1 1 flagDummy Y 1 0
2 1 pdFamily MMC 2 0
3 1 3 1
4 2 1 1
SELECT *
FROM PackingResultConfig 1 1 result_fields [“PartNum”, “SSLotNum”, “CustomerPartNum”, “ShortPartnum”, “TotalDummyStrip”, “SerialNum” , “Page” ]
2 1 sp_name sp_PDL_Tag_Black2866
3 1 template_path pdl_Tag_2866_Dummy.btw
4 1 field_rename {“PartNum”: “PartNum”,“SSLotNum”: “SSLotNum”, “CustomerPartNum”: “CustomerPartNum”,“ShortPartnum”: “SHORT”,“TotalDummyStrip”: “STR”, “SerialNum”: “SerialNum”, “Page”: “TOTALPAGE”}
5 2 result_fields [“ShortPartNum”, “Item”, “BarCode2”, “BarCode3”, “PartNum”, “Xout1”, “Xout2”, “Xout3”, “MFG_Date”, “Expired_Date”, “Total”, “Yield”, “PKG_code”, “SerialNum”, “Page” ]
6 2 sp_name sp_PDL_Tag_Black2866
7 2 template_path pdl_Tag_2866_MMC.btw
8 2 field_rename {“ShortPartNum”: “SHORTPARTNUM”,“PartNum”: “FACPARTNUM”, “Xout1”: “XOUT1”,“Xout2”: “XOUTT”,“Xout3”: “XOUT3”, “Expired_Date”: “EXDATE”, “PKG_code”: “PKGCODE”, “Page”: “TOTALPAGE”}
9 3 result_fields [ “ShortPartNum”, “Item”, “BarCode2”, “BarCode3”, “PartNum”, “Xout1”, “Xout2”, “Xout3”, “Xout4”, “Xout5”, “Xout6”, “Xout7”, “Xout8”, “Xout9”, “Xout10”, “Xout11”, “Xout12”, “Xout13” , “Xout14”, “Xout15”, “Xout16”, “Xout17”, “Xout18” , “MFG_Date”, “Expired_Date”, “Total”, “Yield”, “PKG_code”, “SerialNum”, “Page” ]
10 3 sp_name sp_PDL_Tag_Black2866
11 3 template_path pdl_Tag_2866.btw
12 3 field_rename {“ShortPartNum”: “SHORTPARTNUM”,“PartNum”: “FACPARTNUM”, “Xout1”: “XOUT1”,“Xout2”: “XOUTT”,“Xout3”: “XOUT3”,“Xout4”: “XOUT4”,“Xout5”: “XOUT5”,“Xout6”: “XOUT6”,“Xout7”: “XOUT7”,“Xout8”: “XOUT8”,“Xout9”: “XOUT9”,“Xout10”: “XOUT10”,“Xout11”: “XOUT11”,“Xout12”: “XOUT12”,“Xout13”: “XOUT13”,“Xout14”: “XOUT14”,“Xout15”: “XOUT15”,“Xout16”: “XOUT16”,“Xout17”: “XOUT17”,“Xout18”: “XOUT18”, “Expired_Date”: “EXDATE”, “PKG_code”: “PKGCODE”, “Page”: “TOTALPAGE”}
13 1 related_num SerialNum
14 2 related_num SerialNum
15 3 related_num SerialNum
16 4 result_fields [ “T2Lotnum”, “customer_name”, “cust_part”, “datecode”, “unit_qty”, “vendercode”, “Remark”, “MARK2”, “bar_unit_qty”,“llpiece”, “ShortPartnum”, “Strips”, “grossqnty”, “packingdate”, “expired_date”, “userid”, “seq_no”, “tnum” , “SerialNum”, “mftdate”, “IsBack”, “BackNo”, “CODE2D” , “scpcode” ]
17 4 sp_name sp_PDL_5808表身標籤
18 4 template_path PDL_5808表身標籤.btw
19 4 field_rename {“datecode”: “DATECODE”, “expired_date”: “EXPDATE”,“T2Lotnum”: “LOTNUM”,“packingdate”: “PACKINGDATE”,“userid”: “USERID”,“Strips”: “STRIP”,“unit_qty”: “UNIT_QTY”,“vendercode”: “VENDOR_CODE”,“grossqnty”: “GROSS”,“mftdate”: “MFGDATE”,“CODE2D”: “2DCODE”,“scpcode”: “SCPCODE”}
20 4 related_num SerialNum 三張配置表,表數量太多,不利於維護,且字段用了json,複雜度高,留意怎麼設計改善
最新发布