Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/DeviceProviderService.cs
yang.lee 33e4028853 1、调整电梯逻辑代码
2、新增内部测试类
2023-12-01 22:16:39 +08:00

469 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using JNPF;
using JNPF.Common.Core.Manager;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Manager;
using JNPF.Common.Net;
using JNPF.Common.Security;
using JNPF.EventBus;
using JNPF.EventHandler;
using JNPF.Logging;
using JNPF.Systems.Entitys.System;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Senparc.CO2NET.Cache;
using SqlSugar;
using Tnb.Common.Extension;
using Tnb.EquipMgr.Entities;
using Tnb.WarehouseMgr.Entities;
using Tnb.WarehouseMgr.Entities.Configs;
using Tnb.WarehouseMgr.Entities.Consts;
using Tnb.WarehouseMgr.Entities.Dto;
using Tnb.WarehouseMgr.Entities.Dto.Inputs;
using Tnb.WarehouseMgr.Entities.Dto.Outputs;
using Tnb.WarehouseMgr.Entities.Dto.Queries;
using Tnb.WarehouseMgr.Entities.Entity;
using Tnb.WarehouseMgr.Entities.Enums;
using Tnb.WarehouseMgr.Interfaces;
namespace Tnb.WarehouseMgr
{
/// <summary>
/// Wms设备接口提供程序服务类
/// </summary>
public class DeviceProviderService : ServiceLoggerBase<DeviceProviderService>
{
private readonly ISqlSugarClient _db;
private readonly IWareHouseService _wareHouseService;
private readonly ICacheManager _cacheManager;
private readonly IEventPublisher _eventPublisher;
private readonly IUserManager _userManager;
private readonly IElevatorControlService _elevatorControlService;
private readonly ElevatorControlConfiguration _eleCtlCfg = App.Configuration.Build<ElevatorControlConfiguration>();
private readonly ILoggerFactory _loggerFactory;
public DeviceProviderService(ISqlSugarRepository<WmsInstockH> repository, IWareHouseService wareHouseService,
ICacheManager cacheManager,
IEventPublisher eventPublisher,
IUserManager userManger,
IElevatorControlService elevatorControlService
) //: base(repository.AsSugarClient())
{
_db = repository.AsSugarClient();
_wareHouseService = wareHouseService;
_cacheManager = cacheManager;
_eventPublisher = eventPublisher;
_userManager = userManger;
_elevatorControlService = elevatorControlService;
_ = InitializationTask;
}
/// <summary>
/// 创建任务链
/// </summary>
/// <returns></returns>
[HttpPost, NonUnify]
public async Task<Result> CreateTaskChain()
{
Logger.LogInformation("fasdfadsfadsfasdfasdfadsfasdfadsfadsfasdfasdfasdfasdfas");
return await Task.FromResult<Result>(null);
}
/// <summary>
/// 取货确认/申请取货
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost, NonUnify, AllowAnonymous]
public async Task<Result> LoadConfirm(ConfirmInput input)
{
Logger.Information("--------------------------------------------------------");
Logger.Information("取货确认..................");
var whereExp = Expressionable.Create<WmsElevatorH, WmsElevatorD, WmsDistaskH>()
.And((a, b, c) => c.bill_code == input.taskCode)
.AndIF(SqlFunc.Contains("DT-R", input.sourceName), (a, b, c) => c.startpoint_code == input.sourceName)
.AndIF(SqlFunc.Contains("DT-C", input.sourceName), (a, b, c) => c.endlocation_code == input.sourceName)
.ToExpression();
WmsElevatorH elevator = await _db.Queryable<WmsElevatorH>().InnerJoin<WmsElevatorD>((a, b) => a.id == b.bill_id)
.InnerJoin<WmsDistaskH>((a, b, c) => b.location_id == c.startlocation_id)
.Where(whereExp)
.Select((a, b, c) => new WmsElevatorH
{
distask_id = c.id,
device_id = a.elevator_id,
}, true)
.FirstAsync();
if (elevator.IsNull())
{
Logger.Error("未找到匹配的电梯任务", new Exception($"根据参数,sourceName:{input.sourceName},taskCode:{input.taskCode},未找到匹配的电梯任务"));
return await ToApiResult(HttpStatusCode.InternalServerError, $"根据参数,sourceName:{input.sourceName},taskCode:{input.taskCode},未找到匹配的电梯任务");
}
try
{
Logger.Information($"当前任务Id:{elevator.distask_id}");
Logger.Information($"elevator.device_id={elevator.device_id}");
if (s_elevatorMap.TryGetValue(elevator.device_id, out object? elevatorCode))
{
string devName = elevatorCode?.ToString() ?? _eleCtlCfg.DevName3;
var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" };
(int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None);
Logger.Information($"电梯当前状态->系统状态:{sysStatus.ToEnum<EnumSysStatus>()},运行状态:{runStatus.ToEnum<EnumRunStatus>()},Agv状态:{agvStatus.ToEnum<EnumAgvStatus>()},当前楼层:{floorNo}");
{
if (doorStatus.ToEnum<EnumDoorStatus>() != EnumDoorStatus.)
{
_ = await _elevatorControlService.SendOpenCloseCmd(devName, 3); //发送电梯前门开门指令
}
if (sysStatus.ToEnum<EnumSysStatus>() == EnumSysStatus. && runStatus.ToEnum<EnumRunStatus>() == EnumRunStatus.)
{
//elevator.current_floor = floor;
//await _db.Updateable(elevator).UpdateColumns(it => it.current_floor).ExecuteCommandAsync();
return await ToApiResult(HttpStatusCode.OK, "成功");
}
return await ToApiResult(HttpStatusCode.InternalServerError, "电梯还未开门,请重试!");
}
}
}
catch (Exception)
{
return await ToApiResult(HttpStatusCode.InternalServerError, "请重试!");
throw;
}
return await ToApiResult(HttpStatusCode.OK, "未启用");
Logger.Information("--------------------------------------------------------");
}
/// <summary>
/// 放货确认/申请放货
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost, NonUnify, AllowAnonymous]
public async Task<Result> UnloadConfirm(ConfirmInput input)//
{
Logger.Information("--------------------------------------------------------");
Logger.Information("放货确认..................");
Logger.Information($"输入参数:{JsonConvert.SerializeObject(input)}");
try
{
var whereExp = Expressionable.Create<WmsElevatorH, WmsElevatorD, WmsDistaskH>()
.And((a, b, c) => c.bill_code == input.taskCode)
.AndIF(SqlFunc.Contains("DT-R", input.sourceName), (a, b, c) => c.startpoint_code == input.sourceName)
.AndIF(SqlFunc.Contains("DT-C", input.sourceName), (a, b, c) => c.endlocation_code == input.sourceName)
.ToExpression();
//根据Agv传递的参数获取对应的电梯
WmsElevatorH elevator = await _db.Queryable<WmsElevatorH>().LeftJoin<WmsElevatorD>((a, b) => a.id == b.bill_id)
.LeftJoin<WmsDistaskH>((a, b, c) => b.location_id == c.endlocation_id)
.Where(whereExp)
.Select((a, b, c) => new WmsElevatorH
{
end_floor = SqlFunc.ToInt32(c.end_floor),
device_id = a.elevator_id,
}, true)
.FirstAsync();
if (elevator.IsNull())
{
throw new Exception($"根据参数,sourceName:{input.sourceName},taskCode:{input.taskCode},未找到匹配的电梯任务");
}
if (s_elevatorMap.TryGetValue(elevator.device_id, out object? elevatorCode))
{
string devName = elevatorCode?.ToString() ?? _eleCtlCfg.DevName3;
var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" };
(int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None);//elevator.elevator_code
Logger.Information($"电梯当前状态->系统状态:{sysStatus.ToEnum<EnumSysStatus>()},运行状态:{runStatus},门状态:{doorStatus},Agv状态:{agvStatus},当前楼层:{floorNo}");
//判断Agv电梯是否进入状态
if (agvStatus != (int)EnumAgvStatus.AGV运行状态)
{
await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1);
}
Logger.Information("目前正常");
//电梯到达目标楼层后,判断当前电梯门状态是否为开门到位保持状态
if (doorStatus != (int)EnumDoorStatus.)
{
_ = await _elevatorControlService.SendOpenCloseCmd(devName, 3); //发送电梯前门开门指令
}
if (sysStatus == (int)EnumSysStatus. && runStatus == (int)EnumRunStatus.
&& doorStatus == (int)EnumDoorStatus.)
{
Log.Information("进入开门状态,马上要成功了");
try
{
/* elevator.current_floor = elevator.end_floor;
await _db.Updateable(elevator).UpdateColumns(it => it.current_floor).ExecuteCommandAsync();*/
}
catch (Exception ex)
{
Logger.LogError("更新延迟队列异常", ex);
throw;
}
return await ToApiResult(HttpStatusCode.OK, "成功");
}
}
return await ToApiResult(HttpStatusCode.InternalServerError, "电梯还未开门,请重试!");
}
catch (Exception ex)
{
Logger.Error("放货确认失败", ex);
return await ToApiResult(HttpStatusCode.InternalServerError, "电梯还未开门,请重试!");
throw;
}
Logger.Information("--------------------------------------------------------");
}
/// <summary>
/// 任务链状态上报
/// </summary>
/// <returns></returns>
[HttpPost, NonUnify, AllowAnonymous]
public async Task<Result> TaskChainCallBack(TaskChainCallBackInput input)
{
Logger.Information("--------------------------------------------------------");
try
{
Logger.Information($"任务链上报->任务链编号:{input.taskChainCode},状态:{input.status},设备ID{input.deviceID}");
switch (input.status)
{
case "CREATED": break;
case "ALLOCATED": break;
case "PROCESSING":
if (input.taskChainCode.Trim().IsNullOrEmpty())
{
return await ToApiResult(HttpStatusCode.InternalServerError, "请重试!");
}
List<WmsDistaskH> disTasks = await _db.Queryable<WmsDistaskH>().Where(it => it.bill_code.Contains(input.taskChainCode)).ToListAsync();
List<EqpEquipment> eps = await _db.Queryable<EqpEquipment>().Where(it => it.code.Contains(input.deviceID)).ToListAsync();
if (disTasks == null || disTasks.Count < 1)
{
Logger.Error($"根据任务链编号:{input.taskChainCode} ,未获取到任何任务");
}
if (disTasks?.Count > 0)
{
TaskExecuteUpInput taskExecuteUpInput = new()
{
disTaskIds = disTasks?.Select(x => x.id).ToList() ?? Enumerable.Empty<string>().ToList(),
EqpIds = eps?.Select(x => x.id).ToList() ?? Enumerable.Empty<string>().ToList(),
};
await _wareHouseService.TaskExecute(taskExecuteUpInput);
}
break;
case "CANCELLED": break;
case "SUCCEED": break;
case "FAILURE": break;
case "FINISHED": break;
default: break;
}
/*ConnectionConfigOptions opts = App.GetOptions<ConnectionConfigOptions>();
UserAgent userAgent = new(App.HttpContext);
//写系统日志
await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateOpLog", opts, new SysLogEntity
{
Id = SnowflakeIdHelper.NextId(),
Category = 4,
UserId = _userManager.UserId,
UserName = _userManager.User.RealName,
IPAddress = NetHelper.Ip,
RequestURL = App.HttpContext.Request.Path,
RequestMethod = App.HttpContext.Request.Method,
Json = $"任务链状态上报,任务链编号:{input.taskChainCode},上报状态:{input.status},设备编号:{input.deviceID}",
PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue),
CreatorTime = DateTime.Now
}));*/
}
catch (Exception ex)
{
Logger.Error("任务链状态上报", ex);
Logger.Error($"任务链状态上报错误堆栈{Environment.NewLine}{ex.StackTrace}");
return await ToApiResult(HttpStatusCode.InternalServerError, "请重试!");
throw;
}
Logger.Information("--------------------------------------------------------");
return await ToApiResult(HttpStatusCode.OK, "成功");
}
/// <summary>
/// 任务状态上报
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost, NonUnify, AllowAnonymous]
public async Task<Result> TaskCallback(TaskCallBackInput input)
{
Logger.Information("--------------------------------------------------------");
Logger.Information($"任务状态上报->接收参数:{JsonConvert.SerializeObject(input)}");
try
{
List<WmsDistaskH> disTasks = await _db.Queryable<WmsDistaskH>().Where(it => it.bill_code.Contains(input.taskCode)).ToListAsync();
if (input.action == "LOAD")
{
Logger.Information("----------Load Begin----------");
TaskExecuteAfterUpInput taskExecuteAfterUpInput = new()
{
disTaskIds = disTasks.Select(x => x.id).ToList()
};
Logger.Information($"设备取返回输入参数:{JsonConvert.SerializeObject(taskExecuteAfterUpInput)}");
await _wareHouseService.TaskExecuteAfter(taskExecuteAfterUpInput);
Logger.Information($"Agv取货完成,任务Id:{string.Join(",", disTasks.Select(x => x.id))}");
WmsElevatorUnexecute elevatorQueueItem = await _db.Queryable<WmsElevatorUnexecute>().FirstAsync(it => disTasks.Select(x => x.id).Contains(it.distask_id) && it.task_status == "执行中");
if (elevatorQueueItem != null)
{
Logger.Information("开始进入关门流程");
var disTask = disTasks.Find(x => x.id == elevatorQueueItem.distask_id);
int doorStatus = await _elevatorControlService.GetTagAsync(elevatorQueueItem.elevator_code, ElevatorConsts.DoorStatus);
if (doorStatus.ToEnum<EnumDoorStatus>() != EnumDoorStatus.
&& !disTask.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase)
)
{
_ = await _elevatorControlService.SendOpenCloseCmd(elevatorQueueItem.elevator_code, 4); //向电梯发送前门关门指令
_ = await _db.Deleteable(elevatorQueueItem).ExecuteCommandAsync();
}
}
Logger.Information("----------Load End----------");
}
else if (input.action == "UNLOAD")
{
Logger.Information("----------UnLoad Begin----------");
TaskCompleUpInput taskCompleUpInput = new()
{
disTaskIds = disTasks.Select(x => x.id).ToList()
};
Logger.Information($"taskCompleUpInput json parameter:{JsonConvert.SerializeObject(taskCompleUpInput)}");
await _wareHouseService.TaskComplate(taskCompleUpInput);
Logger.Information("----------UnLoad end----------");
}
}
catch (Exception ex)
{
Logger.Error("任务状态上报出现错误", ex);
return await ToApiResult(HttpStatusCode.InternalServerError, "请重试!");
throw;
}
finally
{
_ = InvokeGenPretaskExcute();
}
Logger.Information("--------------------------------------------------------");
return await ToApiResult(HttpStatusCode.OK, "成功");
}
/// <summary>
/// 申请进出电梯
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost, NonUnify, AllowAnonymous]
public async Task<Result> ElevatorConfirm(ConfirmInput input)
{
try
{
List<WmsElevatorH> eles = await _db.Queryable<WmsElevatorH>().LeftJoin<WmsElevatorD>((a, b) => a.id == b.bill_id)
.LeftJoin<WmsDistaskH>((a, b, c) => b.location_id == c.startlocation_id)
.Where((a, b, c) => c.startlocation_code == input.sourceName && c.bill_code == input.taskCode)
.ToListAsync();
}
catch (Exception)
{
return await ToApiResult(HttpStatusCode.InternalServerError, "请重试!");
throw;
}
return await ToApiResult(HttpStatusCode.OK, "未启用");
}
/// <summary>
/// 根据产线获取Agv列表
/// </summary>
/// <param name="lineId">产线Id默认空(潍柴的只有一条产线所以不用传)</param>
/// <remarks>
/// returns:
/// <br/>{
/// <br/> name:设备名称
/// <br/> code:设备代码
/// <br/>}
/// </remarks>
[HttpGet("lineId"), AllowAnonymous]
public async Task<dynamic> GetAgvListByLineId(string lineId = "")
{
var devList = await _db.Queryable<EqpEquipment>().InnerJoin<EqpEquipType>((a, b) => a.equip_type_id == b.id)
.Where((a, b) => b.code == "003" && b.status == 1)
.Select((a, b) => new
{
a.name,
a.code,
})
.ToListAsync();
return devList;
}
/// <summary>
/// 获取Agv实时信息
/// </summary>
/// <param name="q">查询输入参数</param>
///<remarks>
/// <br/>{
/// <br/> deviceCode:设备序号
/// <br/> devicePostionRec:设备所在二维码的x,y坐标前边的值是x后边的是y
/// <br/> devicePosition:设备当前位置
/// <br/> oritation:方向
/// <br/> speed:速度
/// <br/> shelfNumber当前搬运的货架编号,对应载具编号
/// <br/>}
///</remarks>
[HttpGet, AllowAnonymous]
public async Task<List<AgvRealInfoOutput>> GetAgvRealInfo([FromQuery] AgvRealInfoQuery q)
{
//请求Les接口bing解析返回结果 绑定到AgvRealInfoOutput实例 此处忽略
var devCodes = new[] { "Dev01", "Dev02", "Dev03", "Dev04", "Dev05" };
if (!q.deviceCode.IsNullOrWhiteSpace())
{
devCodes = devCodes.Where(x => q.deviceCode.Contains(x)).ToArray();
}
var result = new List<AgvRealInfoOutput>();
for (int i = 0; i < devCodes.Length; i++)
{
AgvRealInfoOutput output = new();
output.deviceCode = devCodes[i];
output.oritation = 0;
output.speed = Random.Shared.Next(0, 100);
var x = Random.Shared.NextDouble() * 100;
var y = Random.Shared.NextDouble() * 100;
output.devicePostionRec = new[] { x, y };
output.shelfNumber = "xxxx";
result.Add(output);
}
return result;
}
}
}