using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using WIDESEA_Core; using WIDESEA_Core.BaseController; using WIDESEA_DTO.Stock; using WIDESEA_DTO.MES; using WIDESEA_IStockService; using WIDESEA_IBasicService; using WIDESEA_ISystemService; using WIDESEA_Model.Models; using WIDESEA_Common.Constants; using WIDESEA_Common.StockEnum; using System.Diagnostics; namespace WIDESEA_WMSServer.Controllers.Stock { /// /// 库存 /// [Route("api/StockInfo")] [ApiController] public class StockInfoController : ApiBaseController { private readonly IMesLogService _mesLogService; private readonly IMesService _mesService; private readonly IMESDeviceConfigService _mesDeviceConfigService; private readonly ISys_DictionaryService _sysDictionaryService; private readonly IStockInfoService _stockInfoService; public StockInfoController( IStockInfoService service, IMesLogService mesLogService, IMesService mesService, IMESDeviceConfigService mesDeviceConfigService, ISys_DictionaryService sysDictionaryService, IStockInfoService stockInfoService) : base(service) { _mesLogService = mesLogService; _mesService = mesService; _mesDeviceConfigService = mesDeviceConfigService; _sysDictionaryService = sysDictionaryService; _stockInfoService = stockInfoService; } /// /// 获取仓库3D布局 /// /// 仓库ID /// 3D布局数据 [HttpGet("Get3DLayout")] public async Task Get3DLayout(int warehouseId) { var result = await Service.Get3DLayoutAsync(warehouseId); return WebResponseContent.Instance.OK(data: result); } /// /// 托盘进站 - 调用MES接口 /// /// 进站请求参数 /// 操作结果 [HttpPost("inboundInContainer")] public async Task InboundInContainer([FromBody] InboundInContainerRequestDto dto) { var response = new WebResponseContent(); try { // 1. 参数验证 if (string.IsNullOrWhiteSpace(dto.PalletCode)) { return response.Error("托盘编号不能为空"); } // 2. 查询库存信息 - 使用单条记录查询方法提高效率 var stockInfo = await Service.Repository.QueryDataNavFirstAsync(x => x.Id == dto.StockId); if (stockInfo == null) { return response.Error("库存信息不存在"); } // 3. 验证库存状态(仅"入库完成"状态允许进站) if (stockInfo.StockStatus != StockStatusEmun.入库完成.GetHashCode()) { return response.Error($"当前库存状态不允许进站操作,当前状态:{stockInfo.StockStatus}"); } // 4. 动态获取MES凭证 string deviceName = stockInfo.Remark == "GW_1" ? "高温静置1" : stockInfo.Remark == "GW_2" ? "高温静置2" : "常温静置1"; var mesConfig = _mesDeviceConfigService.GetByDeviceName(deviceName); var mesRequest = new InboundInContainerRequest { EquipmentCode = mesConfig?.EquipmentCode ?? StockConstants.MES_EQUIPMENT_CODE, ResourceCode = mesConfig?.ResourceCode ?? StockConstants.MES_RESOURCE_CODE, LocalTime = DateTime.Now, ContainerCode = dto.PalletCode }; string token = mesConfig?.Token; string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); string palletCode = stockInfo.PalletCode; // 5. 异步执行MES调用(fire-and-forget) _ = Task.Run(async () => { var localStopwatch = Stopwatch.StartNew(); try { var result = string.IsNullOrWhiteSpace(token) ? _mesService.InboundInContainer(mesRequest) : _mesService.InboundInContainer(mesRequest, token); localStopwatch.Stop(); bool isSuccess = result?.IsSuccess ?? false; int status = isSuccess ? (int)MesUploadStatusEnum.进站上传成功 : (int)MesUploadStatusEnum.进站上传失败; await _stockInfoService.UpdateMesUploadStatusAsync(palletCode, status); await _mesLogService.LogAsync(new MesApiLogDto { PalletCode = palletCode, ApiType = "InboundInContainer", RequestJson = requestJson, ResponseJson = System.Text.Json.JsonSerializer.Serialize(result), IsSuccess = isSuccess, ErrorMessage = result?.ErrorMessage ?? "未知错误", ElapsedMs = (int)localStopwatch.ElapsedMilliseconds, Creator = App.User.UserName }); } catch (Exception ex) { localStopwatch.Stop(); await _stockInfoService.UpdateMesUploadStatusAsync(palletCode, (int)MesUploadStatusEnum.进站上传失败); await _mesLogService.LogAsync(new MesApiLogDto { PalletCode = palletCode, ApiType = "InboundInContainer", IsSuccess = false, ErrorMessage = ex.Message, ElapsedMs = (int)localStopwatch.ElapsedMilliseconds, Creator = App.User.UserName }); } }); // 6. 立即返回成功 return response.OK("托盘进站成功"); } catch (System.Exception ex) { return response.Error($"托盘进站失败: {ex.Message}"); } } /// /// 托盘出站 - 调用MES接口 /// /// 出站请求参数 /// 操作结果 [HttpPost("outboundInContainer")] public async Task OutboundInContainer([FromBody] OutboundInContainerRequestDto dto) { var response = new WebResponseContent(); try { // 1. 参数验证 if (string.IsNullOrWhiteSpace(dto.PalletCode)) { return response.Error("托盘编号不能为空"); } // 2. 查询库存信息 - 使用单条记录查询方法提高效率 var stockInfo = await Service.Repository.QueryDataNavFirstAsync(x => x.Id == dto.StockId); if (stockInfo == null) { return response.Error("库存信息不存在"); } // 3. 验证库存状态("出库锁定"或"出库完成"状态允许出站) var allowedStatuses = new[] { StockStatusEmun.出库锁定.GetHashCode(), StockStatusEmun.出库完成.GetHashCode() }; if (!allowedStatuses.Contains(stockInfo.StockStatus)) { return response.Error($"当前库存状态不允许出站操作,当前状态:{stockInfo.StockStatus}"); } // 4. 动态获取MES凭证 string deviceName = stockInfo.Remark == "GW_1" ? "高温静置1" : stockInfo.Remark == "GW_2" ? "高温静置2" : "常温静置1"; var mesConfig = _mesDeviceConfigService.GetByDeviceName(deviceName); var mesRequest = new OutboundInContainerRequest { EquipmentCode = mesConfig?.EquipmentCode ?? StockConstants.MES_EQUIPMENT_CODE, ResourceCode = mesConfig?.ResourceCode ?? StockConstants.MES_RESOURCE_CODE, LocalTime = DateTime.Now, ContainerCode = dto.PalletCode, ParamList = dto.ParamList?.Select(p => new ParamItem { ParamCode = p.ParamCode, ParamValue = p.ParamValue, CollectionTime = DateTime.TryParse(p.CollectionTime, out var ct) ? ct : DateTime.Now }).ToList() }; string token = mesConfig?.Token; string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); string palletCode = stockInfo.PalletCode; // 5. 异步执行MES调用(fire-and-forget) _ = Task.Run(async () => { var localStopwatch = Stopwatch.StartNew(); try { var result = string.IsNullOrWhiteSpace(token) ? _mesService.OutboundInContainer(mesRequest) : _mesService.OutboundInContainer(mesRequest, token); localStopwatch.Stop(); bool isSuccess = result?.IsSuccess ?? false; int status = isSuccess ? (int)MesUploadStatusEnum.出站上传成功 : (int)MesUploadStatusEnum.出站上传失败; await _stockInfoService.UpdateMesUploadStatusAsync(palletCode, status); await _mesLogService.LogAsync(new MesApiLogDto { PalletCode = palletCode, ApiType = "OutboundInContainer", RequestJson = requestJson, ResponseJson = System.Text.Json.JsonSerializer.Serialize(result), IsSuccess = isSuccess, ErrorMessage = result?.ErrorMessage ?? "未知错误", ElapsedMs = (int)localStopwatch.ElapsedMilliseconds, Creator = App.User.UserName }); } catch (Exception ex) { localStopwatch.Stop(); await _stockInfoService.UpdateMesUploadStatusAsync(palletCode, (int)MesUploadStatusEnum.出站上传失败); await _mesLogService.LogAsync(new MesApiLogDto { PalletCode = palletCode, ApiType = "OutboundInContainer", IsSuccess = false, ErrorMessage = ex.Message, ElapsedMs = (int)localStopwatch.ElapsedMilliseconds, Creator = App.User.UserName }); } }); // 6. 立即返回成功 return response.OK("托盘出站成功"); } catch (System.Exception ex) { return response.Error($"托盘出站失败: {ex.Message}"); } } /// /// 从配置字典中获取配置值 /// /// 配置字典列表 /// 配置键 /// 默认值 /// 配置值 private string GetConfigValue(System.Collections.Generic.List configs, string key, string defaultValue = "") { if (configs != null) { var config = configs.FirstOrDefault(c => c.DicNo == key); if (config != null && config.Data != null) { // Data是dynamic类型,尝试获取第一个元素的value属性 try { // 使用dynamic来访问匿名类型的属性 dynamic data = config.Data; if (data != null) { // data可能是IEnumerable或者单个对象 var enumerable = data as System.Collections.IEnumerable; if (enumerable != null) { foreach (var item in enumerable) { // 获取第一个元素 dynamic firstItem = item; var value = firstItem.value; return value?.ToString() ?? defaultValue; } } } } catch { // 如果无法获取,返回默认值 return defaultValue; } } } return defaultValue; } } }