using LocalhostMES.Core; using LocalhostMES.DataBase; using LocalhostMES.Models; using Newtonsoft.Json; using Prism.Ioc; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web.Http; namespace LocalhostMES.Controller { [RoutePrefix("api/mes")] public class MesController : ApiController { private static readonly Random _random = new Random(); private static int _snCounter = 1; private Management management; public MesController() { management = Management.GetManagement(); } #region 2.1 厂级MES下发工单信息 [HttpPost] [Route("receiveWorkOrder")] public IHttpActionResult ReceiveWorkOrder([FromBody] WorkOrderRequest request) { try { LogHelper.WriteLogInfo("厂级MES下发工单信息"); // 验证必填字段 if (string.IsNullOrEmpty(request.WorkOrderNo) || string.IsNullOrEmpty(request.MaterialCode) || string.IsNullOrEmpty(request.MaterialName) || string.IsNullOrEmpty(request.LineCode)) { LogHelper.WriteLogInfo("必填字段不能为空"); return BadRequest("必填字段不能为空"); } // 工单状态验证 if (!IsValidStatus(request.Status)) { LogHelper.WriteLogInfo("无效的工单状态"); return BadRequest($"无效的工单状态: {request.Status}"); } // 创建或更新工单信息 var workOrder = new WorkOrderInfo { WorkOrderNo = request.WorkOrderNo, MaterialCode = request.MaterialCode, OrderNo = request.OrderNo, MaterialName = request.MaterialName, PlannedQuantity = int.TryParse(request.WorkOrderNum, out var qty) ? qty : 0, CompletedQuantity = 0, Status = request.Status, LineCode = request.LineCode, CreateTime = DateTime.Now, StartTime = DateTime.Now.AddSeconds(2), EndTime = DateTime.Now.AddSeconds(5) }; if (DatabaseHelper.InsertWorkOrderInfo(workOrder)) { var response = new ApiResponse { code = "200", success = true, msg = "工单接收成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = true }; LogHelper.WriteLogInfo("工单接收成功"); return Ok(response); } else { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"工单接收失败:数据库插入异常", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; LogHelper.WriteLogInfo("数据库插入异常"); return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"工单接收失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } [HttpGet] [Route("getWorkOrders")] public IHttpActionResult GetWorkOrders() { try { LogHelper.WriteLogInfo("接口getWorkOrders收到消息"); var workOrders = DatabaseHelper.SelectWorkOrderInfo(null, management.IsLocalhostMode); var response = new ApiResponse> { code = "200", success = true, msg = "获取成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = workOrders }; return Ok(response); } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"获取工单失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } #endregion #region 2.2 SN打印请求 [HttpPost] [Route("requestSnPrint")] public async Task RequestSnPrint([FromBody] SnPrintRequest request) { try { // 验证请求头 if (!ValidateHeaders()) { return Unauthorized(); } // 验证必填字段 if (string.IsNullOrEmpty(request.workOrderNo) || request.count <= 0) { return BadRequest("工单号和数量为必填项且数量必须大于0"); } var workOrder = DatabaseHelper.SelectWorkOrderInfo(request.workOrderNo); // 验证工单是否存在 if (workOrder.Count == 0) { return BadRequest($"工单 {request.workOrderNo} 不存在"); } // 验证打印类型 if (request.printType < 1 || request.printType > 4) { return BadRequest($"无效的打印类型: {request.printType}"); } LogHelper.WriteLogInfo("请求参数:"); LogHelper.WriteLogInfo(JsonConvert.SerializeObject(request, Formatting.Indented)); if (management.IsLocalhostMode) { var Manualsninfo = DatabaseHelper.SelectSnInfo(request.workOrderNo); DatabaseHelper.InsertSnInfo(new SnInfo() { Sn = "000001" +DateCodeConverter.GetYearCode(DateTime.Now.Year) + DateCodeConverter.GetMonthCode(DateTime.Now.Month) + DateCodeConverter.GetDayCode(DateTime.Now.Day) + "00000" + Manualsninfo.Count, IsUsed = false, WorkOrderNo= request.workOrderNo, GenerateTime=DateTime.Now, PrintType="1", }); } var sninfo = DatabaseHelper.SelectSnInfo(request.workOrderNo, true, false); if (sninfo.Count == 0) { ApiResponse mesres = await management.ApiClient.RequestSnPrintAsync(request); if (mesres.success && mesres.data!=null&& mesres.data.Sn.Count != 0) { for (int i = 0; i < mesres.data.Sn.Count; i++) { if (!DatabaseHelper.InsertSnInfo(new SnInfo() { WorkOrderNo = mesres.data.WorkOrderNo, Sn = mesres.data.Sn[i].Sn, GenerateTime = DateTime.Now, PrintType = "1", IsUsed = false, })) { mesres.msg = "插入SN到数据库出错"; mesres.success = false; return Content(System.Net.HttpStatusCode.InternalServerError, mesres); } } return Ok(mesres); } return Content(System.Net.HttpStatusCode.InternalServerError, mesres); } // 生成SN列表 var snList = new List(); if (sninfo.Count != 0) { snList.Add(new SnItem { Sn = sninfo[0].Sn }); var responseData = new SnPrintResponseData { Sn = snList, OrderNo = request.orderNo ?? "", WorkOrderNo = request.workOrderNo, Line = request.line ?? "", VehicleCode = workOrder[0].MaterialCode, MaterialDesc = workOrder[0].MaterialName }; var response = new ApiResponse { code = "200", success = true, msg = "SN生成成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = responseData }; return Ok(response); } var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"SN获取失败", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"SN生成失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } [HttpGet] [Route("getSns/{workOrderNo}")] public IHttpActionResult GetSns(string workOrderNo) { try { var sninfo = DatabaseHelper.SelectSnInfo(workOrderNo, true, false); if (sninfo.Count != 0) { var response = new ApiResponse> { code = "200", success = true, msg = "获取成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = sninfo }; return Ok(response); } var errorResponse = new ErrorResponse { code = "55001", success = false, msg = $"工单 {workOrderNo} 没有SN记录", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.NotFound, errorResponse); } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"获取SN失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } #endregion #region 2.3 接收SN和关键件 [HttpPost] [Route("receiveSnComponent")] public async Task ReceiveSnComponent([FromBody] SnKeyComponentRequest request) { try { LogHelper.WriteLogInfo($"收到请求: 接收SN和关键件"); if (management.IsLocalhostMode) { return Ok(new ApiResponse() { data = true }); } // 验证请求头 if (!ValidateHeaders()) { return Unauthorized(); } // 验证必填字段 if (string.IsNullOrEmpty(request.plant) || string.IsNullOrEmpty(request.stationCode) || string.IsNullOrEmpty(request.positionCode) || string.IsNullOrEmpty(request.sn) || string.IsNullOrEmpty(request.scanTime)) { return BadRequest("必填字段不能为空"); } // 处理关键件绑定 if (request.part != null && request.part.Count > 0) { foreach (var part in request.part) { if (string.IsNullOrEmpty(part.partNum)) { return BadRequest("关键件条码不能为空"); } var bindRecord = new BindRecord { Sn = request.sn, PartNum = part.partNum, StationCode = request.stationCode, BindTime = DateTime.TryParse(request.scanTime, out var scanTime) ? scanTime : DateTime.Now, Employee = request.employee ?? "", ScanType = request.scanTpye }; //DatabaseHelper.InsertBindRecord(bindRecord); if (management.IsLocalhostMode) { //if (DatabaseHelper.GetProductProductionRecords(request.sn) == 0) //{ var response = new ApiResponse { code = "200", success = true, msg = "已存在记录", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = true }; return Ok(response); //} //else //{ // var errorResponse = new ErrorResponse // { // code = "55000", // success = false, // msg = $"数据库查询失败", // msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), // traceId = Guid.NewGuid().ToString("N").Substring(0, 24) // }; // return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); //} } } } if (management.IsLocalhostMode) { LogHelper.WriteLogInfo($"收到请求: 接收SN和关键件 成功"); return Ok(new ApiResponse() { data=true} ); } var okresponse = await management.ApiClient.SendSnComponentAsync(request); if (okresponse.success && okresponse.code == "200") { LogHelper.WriteLogInfo($"收到请求: 接收SN和关键件 成功"); return Ok(okresponse); } else { LogHelper.WriteLogInfo($"收到请求: 接收SN和关键件 失败\r\n"+ okresponse.ToString()); okresponse.success = false; return Content(System.Net.HttpStatusCode.InternalServerError, okresponse); } } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"SN和关键件接收失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } [HttpGet] [Route("getBindRecords")] public IHttpActionResult GetBindRecords() { try { var records = DatabaseHelper.SelectBindRecord(); var response = new ApiResponse> { code = "200", success = true, msg = "获取成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = records }; return Ok(response); } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"获取绑定记录失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } #endregion #region 2.4 接收工件加工参数 [HttpPost] [Route("receiveProcessParameters")] public async Task ReceiveProcessParameters([FromBody] ProcessParameterRequest request) { try { LogHelper.WriteLogInfo($"收到请求:接收工件加工参数 "); // 验证请求头 if (!ValidateHeaders()) { return Unauthorized(); } // 验证必填字段 if (string.IsNullOrEmpty(request.plant) || string.IsNullOrEmpty(request.station) || string.IsNullOrEmpty(request.sn) || string.IsNullOrEmpty(request.overallResult)) { return BadRequest("必填字段不能为空"); } // 验证总结果 if (request.overallResult != "OK" && request.overallResult != "NG") { return BadRequest($"无效的总结果: {request.overallResult}"); } // 保存加工记录 var processRecord = new ProcessRecord { Sn = request.sn, Station = request.station, OverallResult = request.overallResult, ProcessTime = DateTime.TryParse(request.messageTime, out var msgTime) ? msgTime : DateTime.Now, Equipment = request.equipment ?? "" }; //DatabaseHelper.InsertProcessRecord(processRecord); if (management.IsLocalhostMode) { var response = new ApiResponse { code = "200", success = true, msg = "加工参数接收成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = true }; LogHelper.WriteLogInfo($"收到请求:接收工件加工参数 成功"); return Ok(response); } var mesres =await management.ApiClient.SendProcessParametersAsync(request); LogHelper.WriteLogInfo($"收到请求:接收工件加工参数 成功"); return Ok(mesres); } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"加工参数接收失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } [HttpGet] [Route("getProcessRecords")] public IHttpActionResult GetProcessRecords() { try { var records = DatabaseHelper.SelectProcessRecord(); var response = new ApiResponse> { code = "200", success = true, msg = "获取成功", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24), data = records }; return Ok(response); } catch (Exception ex) { var errorResponse = new ErrorResponse { code = "55000", success = false, msg = $"获取加工记录失败: {ex.Message}", msgTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), traceId = Guid.NewGuid().ToString("N").Substring(0, 24) }; return Content(System.Net.HttpStatusCode.InternalServerError, errorResponse); } } #endregion #region 辅助方法 private bool ValidateHeaders() { // 简单的token验证 if (Request.Headers.TryGetValues("app-key", out var appKeyValues) && Request.Headers.TryGetValues("token", out var tokenValues)) { var appKey = appKeyValues.FirstOrDefault(); var token = tokenValues.FirstOrDefault(); // 这里使用简单的验证 return appKey == "test-app-key" && token == "test-token-123"; } return false; } private bool IsValidStatus(string status) { var validStatuses = new[] { "0", "1", "2", "3", "4", "5", "6", "7" }; return validStatuses.Contains(status); } private string GenerateSn(WorkOrderInfo workOrder, int printType) { var prefix = GetPrintTypePrefix(printType); var timestamp = DateTime.Now.ToString("yyMMddHHmm"); var randomStr = Guid.NewGuid().ToString("N").Substring(0, 6).ToUpper(); var counter = Interlocked.Increment(ref _snCounter); return $"{prefix}-{workOrder.MaterialCode}-{timestamp}-{counter:D4}-{randomStr}"; } private string GetPrintTypePrefix(int printType) { switch (printType) { case 1: return "P"; case 2: return "C"; case 3: return "Q"; case 4: return "B"; default: return "U"; } } private string GetPrintTypeName(int printType) { switch (printType) { case 1: return "产品码"; case 2: return "零件码"; case 3: return "合格码"; case 4: return "装箱码"; default: return "未知"; } } #endregion } public class DateCodeConverter { // ============== 年份对照表 ============== private static readonly Dictionary yearToCode = new Dictionary { {2018, "1"}, {2019, "2"}, {2020, "3"}, {2021, "4"}, {2022, "5"}, {2023, "6"}, {2024, "7"}, {2025, "8"}, {2026, "9"}, {2027, "A"}, {2028, "B"}, {2029, "C"}, {2030, "D"}, {2031, "E"}, {2032, "F"}, {2033, "G"}, {2034, "H"}, {2035, "J"}, {2036, "K"}, {2037, "L"}, {2038, "M"}, {2039, "N"}, {2040, "P"}, {2041, "R"}, {2042, "S"}, {2043, "T"}, {2044, "V"}, {2045, "W"}, {2046, "X"}, {2047, "Y"}, {2048, "1"}, {2049, "2"}, {2050, "3"}, {2051, "4"}, {2052, "5"}, {2053, "6"}, {2054, "7"}, {2055, "8"}, {2056, "9"}, {2057, "A"} }; // ============== 月份对照表 ============== private static readonly Dictionary monthToCode = new Dictionary { {1, "1"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5"}, {6, "6"}, {7, "7"}, {8, "8"}, {9, "9"}, {10, "A"}, {11, "B"}, {12, "C"} }; // ============== 日期对照表 ============== private static readonly Dictionary dayToCode = new Dictionary { {1, "1"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5"}, {6, "6"}, {7, "7"}, {8, "8"}, {9, "9"}, {10, "A"}, {11, "B"}, {12, "C"}, {13, "D"}, {14, "E"}, {15, "F"}, {16, "G"}, {17, "H"}, {18, "J"}, {19, "K"},{20,"L"},{21, "M"}, {22, "N"}, {23, "P"}, {24, "R"}, {25, "S"}, {26, "T"}, {27, "U"}, {28, "V"}, {29, "W"}, {30, "X"}, {31, "Y"} }; // ============== 反向查找字典 ============== private static readonly Dictionary codeToYear; private static readonly Dictionary codeToMonth; private static readonly Dictionary codeToDay; static DateCodeConverter() { // 初始化反向字典 codeToYear = yearToCode .GroupBy(kv => kv.Value) .ToDictionary(g => g.Key, g => g.Last().Key); codeToMonth = monthToCode .ToDictionary(kv => kv.Value, kv => kv.Key); codeToDay = dayToCode .ToDictionary(kv => kv.Value, kv => kv.Key); } // ============== 年份相关方法 ============== /// /// 根据年份获取代码 /// public static string GetYearCode(int year) { return yearToCode.TryGetValue(year, out string code) ? code : "未知年份"; } /// /// 根据代码获取年份(返回最新的对应年份) /// public static int? GetYearByCode(string code) { return codeToYear.TryGetValue(code, out int year) ? year : (int?)null; } /// /// 获取所有对应某个代码的年份 /// public static List GetAllYearsByCode(string code) { return yearToCode .Where(kv => kv.Value == code) .Select(kv => kv.Key) .ToList(); } // ============== 月份相关方法 ============== /// /// 根据月份获取代码 /// public static string GetMonthCode(int month) { if (month < 1 || month > 12) return "无效月份"; return monthToCode.TryGetValue(month, out string code) ? code : "未知月份"; } /// /// 根据代码获取月份 /// public static int? GetMonthByCode(string code) { return codeToMonth.TryGetValue(code, out int month) ? month : (int?)null; } // ============== 日期相关方法 ============== /// /// 根据日期获取代码 /// public static string GetDayCode(int day) { if (day < 1 || day > 31) return "无效日期"; return dayToCode.TryGetValue(day, out string code) ? code : "未知日期"; } /// /// 根据代码获取日期 /// public static int? GetDayByCode(string code) { return codeToDay.TryGetValue(code, out int day) ? day : (int?)null; } // ============== 完整日期转换方法 ============== /// /// 将DateTime转换为日期代码(3位字符:年份代码 + 月份代码 + 日期代码) /// public static string ConvertToDateCode(DateTime date) { string yearCode = GetYearCode(date.Year); string monthCode = GetMonthCode(date.Month); string dayCode = GetDayCode(date.Day); // 检查是否有无效的代码 if (yearCode == "未知年份" || monthCode == "无效月份" || dayCode == "无效日期" || dayCode == "未知日期") { return "无效日期"; } return $"{yearCode}{monthCode}{dayCode}"; } /// /// 将日期代码转换为DateTime(如果有多个年份对应,返回最新的) /// public static DateTime? ConvertFromDateCode(string dateCode) { if (string.IsNullOrEmpty(dateCode) || dateCode.Length != 3) return null; string yearCode = dateCode.Substring(0, 1); string monthCode = dateCode.Substring(1, 1); string dayCode = dateCode.Substring(2, 1); var year = GetYearByCode(yearCode); var month = GetMonthByCode(monthCode); var day = GetDayByCode(dayCode); if (!year.HasValue || !month.HasValue || !day.HasValue) return null; try { return new DateTime(year.Value, month.Value, day.Value); } catch (ArgumentOutOfRangeException) { return null; } } /// /// 将日期代码转换为所有可能的DateTime列表(考虑年份重复的情况) /// public static List ConvertAllFromDateCode(string dateCode) { var result = new List(); if (string.IsNullOrEmpty(dateCode) || dateCode.Length != 3) return result; string yearCode = dateCode.Substring(0, 1); string monthCode = dateCode.Substring(1, 1); string dayCode = dateCode.Substring(2, 1); var allYears = GetAllYearsByCode(yearCode); var month = GetMonthByCode(monthCode); var day = GetDayByCode(dayCode); if (allYears.Count == 0 || !month.HasValue || !day.HasValue) return result; foreach (var year in allYears) { try { result.Add(new DateTime(year, month.Value, day.Value)); } catch (ArgumentOutOfRangeException) { // 跳过无效日期(如2月30日等) } } return result; } } }