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;
}
}
}