791 lines
29 KiB
C#
791 lines
29 KiB
C#
using DOAN.Common.SocketHelper;
|
||
using DOAN.Infrastructure.Helper;
|
||
using DOAN.Model.JobKanban;
|
||
using DOAN.Model.mes.echarts;
|
||
using DOAN.Model.MES.andon;
|
||
using DOAN.Model.MES.base_;
|
||
using DOAN.Model.MES.group;
|
||
using DOAN.Model.MES.mm;
|
||
using DOAN.Model.MES.product;
|
||
using DOAN.Model.MES.product.Dto;
|
||
using DOAN.Model.MES.recipe;
|
||
using DOAN.Model.Mobile;
|
||
using DOAN.Service.JobKanban.IService;
|
||
using DOAN.Service.MES.mm.line;
|
||
using DOAN.Service.MES.product;
|
||
using DOAN.ServiceCore.MyMatchPush;
|
||
using Infrastructure.Attribute;
|
||
using Mapster;
|
||
using NPOI.SS.Formula.Functions;
|
||
using Org.BouncyCastle.Asn1;
|
||
using SqlSugar.SplitTableExtensions;
|
||
using System.Data;
|
||
using System.Net.Http;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace DOAN.Service.JobKanban;
|
||
|
||
[AppService(ServiceType = typeof(IWorkorderProgressService), ServiceLifetime = LifeTime.Transient)]
|
||
public class WorkorderProgressService : BaseService<ProWorkorder>, IWorkorderProgressService
|
||
{
|
||
private ProProducttypeSpecService _proProducttypeSpecService = new ProProducttypeSpecService();
|
||
|
||
private readonly SocketGatewayServer _socketGateway;
|
||
public WorkorderProgressService(SocketGatewayServer socketGateway)
|
||
{
|
||
_socketGateway = socketGateway;
|
||
}
|
||
|
||
public List<BaseWorkRoute> GetRoutes()
|
||
{
|
||
return Context.Queryable<BaseWorkRoute>().Where(it => it.Status == 1).ToList();
|
||
}
|
||
|
||
public List<BaseGroup> GetGroups()
|
||
{
|
||
return Context.Queryable<BaseGroup>().Where(it => it.Status == 1).ToList();
|
||
}
|
||
|
||
public List<ProWorkorder> GetWorkOrderList(string group_code, string line_code, DateTime handleDate)
|
||
{
|
||
handleDate = handleDate.ToLocalTime().Date;
|
||
|
||
return Context.Queryable<ProWorkorder>().Where(it => it.GroupCode == group_code)
|
||
.Where(it => it.LineCode == line_code)
|
||
.Where(it => it.WorkorderDate == handleDate)
|
||
.ToList();
|
||
}
|
||
|
||
|
||
public List<ProReportwork> GetReportWorkRecord(string group_code, string line_code, DateTime handleDate)
|
||
{
|
||
return Context.Queryable<ProWorkorder>().LeftJoin<ProReportwork>((w, r) => w.Workorder == r.FkWorkorder)
|
||
.Where((w, r) => w.GroupCode == group_code)
|
||
.Where((w, r) => w.LineCode == line_code)
|
||
.Where((w, r) => w.WorkorderDate == handleDate)
|
||
.Select((w, r) => new
|
||
{
|
||
FkWorkorder = w.Workorder,
|
||
DispatchNum = w.DeliveryNum,
|
||
FinishedNum = r.FinishedNum,
|
||
})
|
||
.ToList().Adapt<List<ProReportwork>>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取工单列表 未完成
|
||
/// </summary>
|
||
/// <param name="today"></param>
|
||
/// <param name="LineCode"></param>
|
||
/// <returns></returns>
|
||
public List<ProWorkorderDto4> GetWorkOrderListNoFinish(DateTime today, string line_code, string group_code)
|
||
{
|
||
today = today.ToLocalTime().Date;
|
||
var query1 = Context.Queryable<ProWorkorder>()
|
||
.Where(it => it.WorkorderDate == today)
|
||
.Where(it => it.LineCode == line_code)
|
||
.Where(it => it.GroupCode == group_code)
|
||
.Where(it => it.Status == 1 || it.Status == 2 || it.Status == 4)
|
||
;
|
||
|
||
|
||
var ProWorkorderDto4List = Context.Queryable(query1)
|
||
.LeftJoin<ProReportwork>((q, r) => q.Workorder == r.FkWorkorder)
|
||
.Select((q, r) => new ProWorkorderDto4
|
||
{
|
||
FinishNum = r.FinishedNum
|
||
}, true)
|
||
.MergeTable()
|
||
.OrderBy(it => it.Sort)
|
||
.ToList();
|
||
if (ProWorkorderDto4List.Count > 0)
|
||
foreach (var item in ProWorkorderDto4List)
|
||
item.progress = SearchMaterialPreparationProgress(item.Workorder);
|
||
|
||
|
||
return ProWorkorderDto4List;
|
||
}
|
||
|
||
public ProWorkorderDto4 GetWorkOrderDetail(string workorder)
|
||
{
|
||
var query = Context.Queryable<ProWorkorder>()
|
||
.Where(it => it.Workorder == workorder);
|
||
|
||
|
||
return Context.Queryable(query)
|
||
.LeftJoin<ProReportwork>((q, r) => q.Workorder == r.FkWorkorder)
|
||
.Select((q, r) => new ProWorkorderDto4
|
||
{
|
||
FinishNum = r.FinishedNum
|
||
}, true).First();
|
||
}
|
||
|
||
public KanbanInfo GetKanbanNum(DateTime today, string line_code, string group_code)
|
||
{
|
||
var kanbanInfo = new KanbanInfo();
|
||
today = today.ToLocalTime().Date;
|
||
kanbanInfo.TotalTaskNum = Context.Queryable<ProWorkorder>()
|
||
.Where(it => it.WorkorderDate == today)
|
||
.Where(it => it.LineCode == line_code)
|
||
.Where(it => it.GroupCode == group_code)
|
||
.Count();
|
||
|
||
kanbanInfo.RemainTasKNum = Context.Queryable<ProWorkorder>()
|
||
.Where(it => it.WorkorderDate == today)
|
||
.Where(it => it.LineCode == line_code)
|
||
.Where(it => it.GroupCode == group_code)
|
||
.Where(it => it.Status == 1 || it.Status == 2 || it.Status == 4)
|
||
.Count();
|
||
|
||
return kanbanInfo;
|
||
}
|
||
|
||
public async Task<int> StartWorkOrder(string workorder)
|
||
{
|
||
var result = 0;
|
||
// 获取同一天 同一组 同一线 的所有工单 把状态2 设为init 1
|
||
var handleWorkorder =
|
||
Context.Queryable<ProWorkorder>().Where(it => it.Workorder == workorder).First();
|
||
UseTran2(() =>
|
||
{
|
||
Context.Updateable<ProWorkorder>().SetColumns(it => it.Status == 1)
|
||
.Where(it => it.Status == 2)
|
||
.Where(it => it.WorkorderDate == handleWorkorder.WorkorderDate)
|
||
.Where(it => it.GroupCode == handleWorkorder.GroupCode)
|
||
.Where(it => it.LineCode == handleWorkorder.LineCode)
|
||
.ExecuteCommand();
|
||
|
||
|
||
result = Context.Updateable<ProWorkorder>().SetColumns(it => it.Status == 2)
|
||
.SetColumns(it => it.StartTime == DateTime.Now)
|
||
.Where(it => it.Workorder == workorder).ExecuteCommand();
|
||
|
||
|
||
});
|
||
//新增QMS首检
|
||
try
|
||
{
|
||
QMSFirstInspection(handleWorkorder);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
}
|
||
|
||
//TODO 拼接MQTT消息,发送给设备,工单信息和配方信息
|
||
var spec = handleWorkorder.Specification;
|
||
|
||
//var RecipeMesg = Context.Queryable<PfRefProductRecipe>()
|
||
// .LeftJoin<PfRecipeVersion>((rpr, r) => rpr.RecipeCode == r.RecipeCode)
|
||
// .Where((rpr, r) => SqlFunc.Like(spec, rpr.RecipeCode + "%"))
|
||
// .Where((rpr, r) => r.Status == 1)
|
||
// .Select((rpr, r) => new
|
||
// {
|
||
// RecipeCode = r.RecipeCode,
|
||
// Version = r.Version,
|
||
// ParamList = SqlFunc.Subqueryable<PfRecipeParameters>()
|
||
// .Where(it => it.RecipeCode == r.RecipeCode && it.Version == r.Version)
|
||
// .ToList(),
|
||
// // 添加匹配长度用于排序
|
||
// MatchLength = rpr.RecipeCode.Length
|
||
// })
|
||
// .MergeTable()
|
||
// .OrderByDescending(x => x.MatchLength) // 按匹配长度降序排列
|
||
// .First(); // 取第一个(匹配最长的)
|
||
|
||
|
||
// 合并两个对象为匿名对象
|
||
var combinedObject = new
|
||
{
|
||
WorkorderInfo = handleWorkorder,
|
||
// RecipeInfo = RecipeMesg
|
||
};
|
||
|
||
|
||
string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(combinedObject, Newtonsoft.Json.Formatting.Indented);
|
||
//插入配方派发日志
|
||
//if (RecipeMesg != null && !string.IsNullOrEmpty(RecipeMesg.RecipeCode))
|
||
//{
|
||
// PfRecipeIssueLog pfRecipeIssueLog = new PfRecipeIssueLog();
|
||
// pfRecipeIssueLog.RecipeCode = RecipeMesg.RecipeCode;
|
||
// pfRecipeIssueLog.Version = RecipeMesg.Version;
|
||
// pfRecipeIssueLog.IssueTime = DateTime.Now;
|
||
// pfRecipeIssueLog.Workorder = handleWorkorder.Workorder;
|
||
// pfRecipeIssueLog.Productcode = handleWorkorder.ProductionCode;
|
||
// pfRecipeIssueLog.Productname = handleWorkorder.ProductionName;
|
||
// pfRecipeIssueLog.CreatedBy = "PDA";
|
||
// pfRecipeIssueLog.CreatedTime = DateTime.Now;
|
||
// Context.Insertable(pfRecipeIssueLog).ExecuteCommand();
|
||
|
||
//}
|
||
|
||
|
||
MqttHelper _mqttHelper = new MqttHelper("192.168.50.163", 1883);
|
||
|
||
// 连接
|
||
|
||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2)); // 总超时10秒
|
||
var connectTask = _mqttHelper.ConnectAsync();
|
||
var timeoutTask = Task.Delay(5000, cts.Token); // 5秒连接超时
|
||
|
||
var completedTask = await Task.WhenAny(connectTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
throw new TimeoutException("连接MQTT服务器超时");
|
||
}
|
||
await connectTask; // 确保没有异常
|
||
|
||
// 发送多条消息
|
||
string line = handleWorkorder.LineCode == null ? "-1" : handleWorkorder.LineCode;
|
||
await _mqttHelper.PublishMessageAsync("MES/Workorder/Start/handleWorkorder/" + line, jsonString);
|
||
|
||
// 断开连接
|
||
await _mqttHelper.DisconnectAsync();
|
||
return result;
|
||
}
|
||
|
||
//新增每天首检,按规格号查对应的产品类型,如果产品类型是今天首次做,就触发首检,记录发送首检记录
|
||
//暂时是每次开工都首检
|
||
private async Task QMSFirstInspection(ProWorkorder handleWorkorder)
|
||
{
|
||
try
|
||
{
|
||
if (handleWorkorder != null && !string.IsNullOrEmpty(handleWorkorder.Specification))
|
||
{
|
||
var queryType = _proProducttypeSpecService.Queryable()
|
||
.Where(it => it.Specification == handleWorkorder.Specification)
|
||
.First();
|
||
if (queryType != null && !string.IsNullOrEmpty(queryType.ProductionType))
|
||
{
|
||
//查询记录表,看今天这个产品类型是否已经首检
|
||
//构造首检信息
|
||
InspectionRecordDto inspectionRecordDto = new InspectionRecordDto();
|
||
inspectionRecordDto.assemblyModel = queryType.Specification;
|
||
inspectionRecordDto.type = queryType.ProductionType;
|
||
inspectionRecordDto.triggerTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||
inspectionRecordDto.inspectionTimes = "1";
|
||
inspectionRecordDto.inspectionStatus = "未巡检";
|
||
//调用QMS接口,发送首检记录
|
||
string qmsApiUrl = "https://aliwork.zitoo.com.cn/ganxiang/patrol-info"; // QMS接口地址
|
||
// 序列化DTO为JSON请求体
|
||
string requestJson = JsonConvert.SerializeObject(inspectionRecordDto);
|
||
var content = new StringContent(requestJson, Encoding.UTF8, "application/json");
|
||
HttpClient httpClient = new HttpClient();
|
||
// 发送POST请求(接口通常为POST,若为GET需调整)
|
||
HttpResponseMessage response = await httpClient.PostAsync(qmsApiUrl, content);
|
||
string responseJson = await response.Content.ReadAsStringAsync();
|
||
QmsFirstInspectionResponseDto responseDto = JsonConvert.DeserializeObject<QmsFirstInspectionResponseDto>(responseJson);
|
||
// 解析接口响应
|
||
if (responseDto != null && responseDto.Code == "200")
|
||
{
|
||
// 首检记录发送成功,记录到本地数据库
|
||
//TODO 记录首检日志
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂停工单
|
||
/// </summary>
|
||
/// <param name="workorder"></param>
|
||
/// <returns></returns>
|
||
public int PauseWorkOrder(string workorder)
|
||
{
|
||
int result = 0;
|
||
UseTran2(() =>
|
||
{
|
||
ProWorkorderStatus proWorkorderStatus = new ProWorkorderStatus();
|
||
proWorkorderStatus.FkWorkorderCode = workorder;
|
||
proWorkorderStatus.Status = 4;
|
||
proWorkorderStatus.ChangeTime = DateTime.Now;
|
||
proWorkorderStatus.CreatedTime = DateTime.Now;
|
||
|
||
Context.Insertable(proWorkorderStatus).ExecuteCommand();
|
||
|
||
|
||
result = Context.Updateable<ProWorkorder>()
|
||
.SetColumns(it => it.Status == 4)
|
||
.SetColumns(it => it.EndTime == DateTime.Now)
|
||
.Where(it => it.Workorder == workorder).ExecuteCommand();
|
||
|
||
});
|
||
return result;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 恢复工单,
|
||
/// </summary>
|
||
/// <param name="workorder"></param>
|
||
/// <returns></returns>
|
||
//public int RecoverWorkOrder(string workorder)
|
||
//{
|
||
// int result = 0;
|
||
// UseTran2(() =>
|
||
// {
|
||
// ProWorkorderStatus proWorkorderStatus = new ProWorkorderStatus();
|
||
// proWorkorderStatus.FkWorkorderCode = workorder;
|
||
// proWorkorderStatus.Status = 5; //状态5改为取消工单
|
||
// proWorkorderStatus.ChangeTime = DateTime.Now;
|
||
// proWorkorderStatus.CreatedTime = DateTime.Now;
|
||
|
||
// Context.Insertable(proWorkorderStatus).ExecuteCommand();
|
||
|
||
|
||
// result = Context.Updateable<ProWorkorder>()
|
||
// .SetColumns(it => it.Status == 5) //状态5改为取消工单
|
||
// .SetColumns(it => it.EndTime == DateTime.Now)
|
||
// .Where(it => it.Workorder == workorder).ExecuteCommand();
|
||
|
||
// });
|
||
// return result;
|
||
//}
|
||
/// <summary>
|
||
/// 工单完成
|
||
/// </summary>
|
||
/// <param name="workorder"></param>
|
||
/// <returns></returns>
|
||
|
||
public int FinishWorkOrder(string workorder)
|
||
{
|
||
int result = 0;
|
||
UseTran2(() =>
|
||
{
|
||
ProWorkorderStatus proWorkorderStatus = new ProWorkorderStatus();
|
||
proWorkorderStatus.FkWorkorderCode = workorder;
|
||
proWorkorderStatus.Status = 3;
|
||
proWorkorderStatus.ChangeTime = DateTime.Now;
|
||
proWorkorderStatus.CreatedTime = DateTime.Now;
|
||
|
||
|
||
Context.Insertable(proWorkorderStatus).ExecuteCommand();
|
||
|
||
result = Context.Updateable<ProWorkorder>()
|
||
.SetColumns(it => it.Status == 3)
|
||
.SetColumns(it => it.EndTime == DateTime.Now)
|
||
.Where(it => it.Workorder == workorder).ExecuteCommand();
|
||
|
||
});
|
||
return result;
|
||
}
|
||
|
||
|
||
public ProWorkorder GetProductingWorkorder(string line_code, DateTime handleDate)
|
||
{
|
||
//TODO 这个日期有问题??????
|
||
if (handleDate.Kind == DateTimeKind.Utc)
|
||
handleDate = handleDate.ToLocalTime().Date;
|
||
else
|
||
handleDate = handleDate.Date;
|
||
|
||
|
||
return Context.Queryable<ProWorkorder>()
|
||
.Where(it => it.LineCode == line_code)
|
||
.Where(it => it.WorkorderDate == handleDate)
|
||
.Where(it => it.Status == 2)
|
||
//.Select(it=>it.Workorder)
|
||
.First();
|
||
}
|
||
|
||
public int AddLabelLog(string labelContext, string workOrder)
|
||
{
|
||
var log = new ProReportworkDetail();
|
||
log.Id = XueHua;
|
||
log.ProductionLabelCode = labelContext;
|
||
log.Workorder = workOrder;
|
||
// log.Status = 1;
|
||
log.CreatedTime = DateTime.Now;
|
||
log.CreatedBy = "终检台";
|
||
|
||
return Context.Insertable(log).SplitTable().ExecuteCommand();
|
||
}
|
||
|
||
|
||
public int LabelWorkOrderMatch(string LabelContext, string workOrder)
|
||
{
|
||
return Context.Updateable<ProLabelTraceLog>()
|
||
.Where(it => it.Workorder == workOrder)
|
||
.Where(it => it.LabelContext == LabelContext)
|
||
.SetColumns(it => it.Status == 1)
|
||
.ExecuteCommand();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 防错并且报工
|
||
/// </summary>
|
||
/// <param name="workorder"></param>
|
||
/// <param name="labelContext"></param>
|
||
/// <returns></returns>
|
||
public int ErrorProofingAndReportingWork(string workorder, string labelContext)
|
||
{
|
||
var checked_workorder = Context.Queryable<ProWorkorder>().Where(it => it.Workorder == workorder)
|
||
.First();
|
||
//if (!labelContext.Contains(checked_workorder.Specification))
|
||
// 产品不属于这个工单里
|
||
if (labelContext.IndexOf(checked_workorder.Specification, StringComparison.OrdinalIgnoreCase) < 0)
|
||
{
|
||
return -1;
|
||
}
|
||
// 增加标签长度判断 36个字符
|
||
//if (labelContext.Length != 40)
|
||
//{
|
||
// return -2;
|
||
//}
|
||
|
||
// 记录条码
|
||
var detail = new ProReportworkDetail();
|
||
detail.Id = XueHua;
|
||
detail.Workorder = workorder;
|
||
detail.ProductionLabelCode = labelContext;
|
||
detail.CreatedBy = "MES";
|
||
detail.CreatedTime = DateTime.Now;
|
||
Context.Insertable(detail).SplitTable().ExecuteCommand();
|
||
|
||
// 累加报工数
|
||
var reportWork = new ProReportwork();
|
||
reportWork.Id = XueHua;
|
||
reportWork.FkWorkorder = workorder;
|
||
reportWork.DispatchNum = checked_workorder.DeliveryNum;
|
||
reportWork.FinishedNum = 1;
|
||
reportWork.GroupCode = checked_workorder.GroupCode;
|
||
reportWork.LineCode = checked_workorder.LineCode;
|
||
reportWork.CreatedTime = DateTime.Now;
|
||
reportWork.CreatedBy = "kanban";
|
||
reportWork.UpdatedBy = "kanban";
|
||
reportWork.UpdatedTime = DateTime.Now;
|
||
var ExistReportwork = Context.Queryable<ProReportwork>().Where(it => it.FkWorkorder == workorder).First();
|
||
var result = 0;
|
||
if (ExistReportwork != null)
|
||
{
|
||
reportWork.FinishedNum = ExistReportwork.FinishedNum + 1;
|
||
result += Context.Updateable<ProReportwork>().Where(it => it.FkWorkorder == workorder)
|
||
.SetColumns(it => new ProReportwork()
|
||
{
|
||
UpdatedBy = reportWork.UpdatedBy,
|
||
UpdatedTime = reportWork.UpdatedTime,
|
||
FinishedNum = reportWork.FinishedNum
|
||
}
|
||
)
|
||
.ExecuteCommand();
|
||
}
|
||
else
|
||
{
|
||
reportWork.FinishedNum = 1;
|
||
result += Context.Insertable(reportWork).ExecuteCommand();
|
||
}
|
||
|
||
// TODO 线边库出库(产线触摸屏)
|
||
/* try
|
||
{
|
||
// 计算Bom表
|
||
string InvCode = checked_workorder.ProductionCode;
|
||
// 查看需要的子件
|
||
var bomList = Context.Queryable<BaseMaterialBom>().Where(it => it.InvCode == InvCode).ToList();
|
||
foreach(BaseMaterialBom bom in bomList)
|
||
{
|
||
int quantity = 0;
|
||
if (int.TryParse(bom.Iusequantity, out int res))
|
||
{
|
||
quantity = res;
|
||
}
|
||
MmLineInventoryService mmLineInventoryService = new MmLineInventoryService();
|
||
mmLineInventoryService.outboundLineMaterial(2,reportWork.LineCode, bom.SubInvCode, checked_workorder.Workorder, reportWork.LineCode, quantity);
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
throw;
|
||
}*/
|
||
|
||
|
||
// 当前工单上一个小时的完成率低于90%,给出提示信息;
|
||
|
||
|
||
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
public int FinishWorkorder(string workorder, int finish_num)
|
||
{
|
||
var result = 0;
|
||
|
||
result = Context.Updateable<ProWorkorder>()
|
||
.Where(it => it.Workorder == workorder)
|
||
.SetColumns(it => it.EndTime == DateTime.Now.ToLocalTime())
|
||
.SetColumns(it => it.Status == 3)
|
||
.ExecuteCommand();
|
||
return result;
|
||
}
|
||
|
||
public (int, int) GetWorkOrderProgress(string workorder)
|
||
{
|
||
var result = Context.Queryable<ProReportwork>().Where(it => it.FkWorkorder == workorder)
|
||
.Select(it => new { it.DispatchNum, it.FinishedNum }).First();
|
||
if (result == null)
|
||
{
|
||
return (0, 0);
|
||
}
|
||
|
||
(int, int) tuple = (result.DispatchNum ?? 0, result.FinishedNum ?? 0);
|
||
return tuple;
|
||
}
|
||
|
||
public (DateTime, float) GetWorkOrderTime(string workorder)
|
||
{
|
||
var result = Context.Queryable<ProWorkorder>().Where(it => it.Workorder == workorder)
|
||
.Select(it => new { it.StartTime, it.Beat, it.DeliveryNum }).First();
|
||
|
||
(DateTime, float) tuple = (result.StartTime ?? DateTime.MinValue,
|
||
(result.Beat * result.DeliveryNum ?? 0) / 3600);
|
||
return tuple;
|
||
}
|
||
|
||
|
||
//查询工单下的扫描条码信息
|
||
public List<ProReportworkDetail> GetWorkOrderScanCodeInfo(string workorder)
|
||
{
|
||
return Context.Queryable<ProReportworkDetail>().SplitTable(tabs => tabs.Take(1)).Where(it => it.Workorder == workorder).ToList();
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 根据工单号 查询每个工单号进度
|
||
/// </summary>
|
||
/// <param name="Workorder"></param>
|
||
/// <returns></returns>
|
||
private MaterialPreparationProgress SearchMaterialPreparationProgress(string Workorder)
|
||
{
|
||
var progress = new MaterialPreparationProgress();
|
||
//TODO 查询工单总任务数
|
||
progress.WorkOrder = Workorder;
|
||
progress.Preparation_all_num = Context.Queryable<MmPreparationTask>()
|
||
.Where(it => it.FkWorkorder == Workorder)
|
||
.Count();
|
||
|
||
progress.Preparationed_num = Context.Queryable<MmPreparationTask>().Where(it => it.FkWorkorder == Workorder)
|
||
.Where(it => it.PreparationStatus == 2)
|
||
.Count();
|
||
if (progress.Preparationed_num == progress.Preparation_all_num)
|
||
progress.PreparationStatus = 2;
|
||
else if (progress.Preparationed_num < progress.Preparation_all_num) progress.PreparationStatus = 1;
|
||
|
||
if (progress.Preparation_all_num == 0) progress.PreparationStatus = 0;
|
||
|
||
|
||
return progress;
|
||
}
|
||
public bool SwitchWorkOrderCheckLabel(string pre_workorder)
|
||
{
|
||
var result = Context.Queryable<ProInspectionLabel>().Where(it => it.Workorder == pre_workorder)
|
||
.Select(it => it.EndLabel).First();
|
||
if (!string.IsNullOrEmpty(result))
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public EchartsOptions GetHourlyProduction(string groupCode)
|
||
{
|
||
EchartsOptions echartsOptions = new EchartsOptions();
|
||
echartsOptions.Title = new EchartsTitle("今日各组实时完工数与计划完工柱状图", "获取今日各组实时每小时完工数柱状图");
|
||
|
||
// 1. 获取班组工作时间
|
||
GroupShift Shifts = Context.Queryable<GroupSchedule>().LeftJoin<GroupShift>((sc, sh) => sc.FkShift == sh.Id)
|
||
.Where((sc, sh) => sc.ScheduleDate == DateTime.Today && sc.GroupCode == groupCode).Select((sc, sh) => sh).First();
|
||
if (Shifts == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 处理每小时间隔
|
||
int intervals = (int)Math.Ceiling((Shifts.EndTime - Shifts.StartTime).Value.TotalMinutes / 60);
|
||
intervals++;
|
||
|
||
DateTime today = DateTime.Today;
|
||
TimeSpan startTimeSpan = new TimeSpan(Shifts.StartTime.Value.Hour, Shifts.StartTime.Value.Minute, Shifts.StartTime.Value.Second);
|
||
DateTime todayAtStart = today + startTimeSpan;
|
||
|
||
DateTime[] dateTimeArray = new DateTime[intervals];
|
||
for (int i = 0; i < intervals; i++)
|
||
{
|
||
TimeSpan spanItem = new TimeSpan(0, 60 * i, 0);
|
||
DateTime TodayItem = todayAtStart + spanItem;
|
||
dateTimeArray[i] = TodayItem;
|
||
}
|
||
|
||
EchartsXAxis XAxis = new EchartsXAxis();
|
||
XAxis.Data = dateTimeArray.Select(it => it.ToString("HH:mm")).ToList();
|
||
echartsOptions.XAxis = XAxis;
|
||
|
||
// 2. 获取实际完成数(保持不变)
|
||
EchartsSeries actualSeries = new EchartsSeries();
|
||
actualSeries.Name = groupCode + "组今日实时完成数(每60分钟)";
|
||
actualSeries.Type = "bar";
|
||
List<EchartsSeriesData> actualSeriesDatas = new List<EchartsSeriesData>();
|
||
|
||
string year = DateTime.Today.Year.ToString("D4");
|
||
string month = DateTime.Today.Month.ToString("D2");
|
||
string day = "01";
|
||
|
||
string sql = "SELECT FROM_UNIXTIME( FLOOR( UNIX_TIMESTAMP( d.created_time ) / 3600 ) * 3600 ) AS time_period, COUNT(*) AS count FROM " +
|
||
$"pro_workorder AS r RIGHT JOIN pro_reportwork_detail_{year}{month}{day} AS d ON r.workorder = d.workorder " +
|
||
"WHERE r.workorder_date = CURDATE() AND r.group_code= @groupCode " +
|
||
" GROUP BY FLOOR( UNIX_TIMESTAMP( d.created_time ) / 3600 ) ORDER BY time_period"; // 修正:应该是3600而不是600
|
||
|
||
DataTable result = Context.Ado.GetDataTable(sql, new { groupCode = groupCode });
|
||
|
||
foreach (DataRow row in result.Rows)
|
||
{
|
||
DateTime value = row["time_period"] != DBNull.Value ? Convert.ToDateTime(row["time_period"]) : DateTime.MinValue;
|
||
int count = Convert.ToInt32(row["count"]);
|
||
|
||
EchartsSeriesData seriesData = new EchartsSeriesData()
|
||
{
|
||
Name = value.ToString("HH:mm"),
|
||
Value = count
|
||
};
|
||
actualSeriesDatas.Add(seriesData);
|
||
}
|
||
|
||
// 补全缺失的时间点数据为0
|
||
CompleteMissingTimePoints(ref actualSeriesDatas, XAxis.Data.ToList());
|
||
actualSeries.Data = actualSeriesDatas.OrderBy(it => it.Name).ToList();
|
||
echartsOptions.Series.Add(actualSeries);
|
||
|
||
// 3. 修正计划完成数计算
|
||
List<ProWorkorder> ProWorkorderList = Context.Queryable<ProWorkorder>()
|
||
.Where(it => it.GroupCode == groupCode && it.WorkorderDate == DateTime.Today).ToList();
|
||
if (ProWorkorderList.Count() == 0)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 计算总产量
|
||
int totalProduct = ProWorkorderList.Sum(it => it.DeliveryNum ?? 0);
|
||
|
||
// 计算总工作时间段数量
|
||
int totalHours = intervals;
|
||
|
||
// 计算每个时间段的计划产量(均匀分配)
|
||
int plannedProductPerHour = totalProduct / totalHours;
|
||
|
||
// 处理不能整除的情况,最后一个时间段加上余数
|
||
int remainder = totalProduct % totalHours;
|
||
|
||
EchartsSeries plannedSeries = new EchartsSeries();
|
||
plannedSeries.Name = groupCode + "组今日计划完成数(每60分钟)";
|
||
plannedSeries.Type = "bar";
|
||
List<EchartsSeriesData> plannedSeriesDatas = new List<EchartsSeriesData>();
|
||
|
||
for (int i = 0; i < dateTimeArray.Length; i++)
|
||
{
|
||
EchartsSeriesData seriesData = new EchartsSeriesData();
|
||
seriesData.Name = dateTimeArray[i].ToString("HH:mm");
|
||
|
||
// 均匀分配计划产量
|
||
int plannedValue = plannedProductPerHour;
|
||
if (i == dateTimeArray.Length - 1)
|
||
{
|
||
plannedValue += remainder; // 最后一个时间段加上余数
|
||
}
|
||
|
||
seriesData.Value = plannedValue;
|
||
plannedSeriesDatas.Add(seriesData);
|
||
}
|
||
|
||
plannedSeries.Data = plannedSeriesDatas;
|
||
echartsOptions.Series.Add(plannedSeries);
|
||
|
||
return echartsOptions;
|
||
}
|
||
|
||
// 辅助方法:补全缺失的时间点
|
||
private void CompleteMissingTimePoints(ref List<EchartsSeriesData> seriesDatas, List<string> allTimePoints)
|
||
{
|
||
var existingTimePoints = seriesDatas.Select(s => s.Name).ToHashSet();
|
||
|
||
foreach (string timePoint in allTimePoints)
|
||
{
|
||
if (!existingTimePoints.Contains(timePoint))
|
||
{
|
||
seriesDatas.Add(new EchartsSeriesData()
|
||
{
|
||
Name = timePoint,
|
||
Value = 0 // 缺失的时间点设为0
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public int GetLastHourCompletionRate(string workorder)
|
||
{
|
||
var workorderInfo = Context.Queryable<ProWorkorder>().Where(it => it.Workorder == workorder)
|
||
.Select(it => new { it.Workorder, it.Beat ,it.LineCode}).First();
|
||
if (workorderInfo == null)
|
||
{
|
||
return 0;
|
||
}
|
||
DateTime oneHourAgo = DateTime.Now.AddHours(-1);
|
||
int finishedCount = Context.Queryable<ProReportworkDetail>().SplitTable(tabs => tabs.Take(1))
|
||
.Where(it => it.CreatedTime >= oneHourAgo)
|
||
.Where(it => it.Workorder == workorder)
|
||
.Count();
|
||
int totalCount =workorderInfo.Beat??0*60*60;
|
||
if (totalCount == 0)
|
||
{
|
||
return 0;
|
||
}
|
||
float completionRate = finishedCount / totalCount;
|
||
if (completionRate <= 0.9f)
|
||
{
|
||
|
||
// 触发andon
|
||
//触发报警逻辑
|
||
AndonFaultRecord record = new AndonFaultRecord();
|
||
record.LineCode = workorderInfo.LineCode;
|
||
record.FaultDict = "生产异常报警";
|
||
record.FaultContext = $"工单号:{workorderInfo.Workorder},当前工单上一个小时的完成率低于90%,为{completionRate:F1}%";
|
||
record.AskPerson = "system";
|
||
record.CreatedTime = DateTime.Now;
|
||
//发送报警信息
|
||
string message = $"产线:{record.LineCode},\n故障类型:{record.FaultDict},\n故障内容:{record.FaultContext},\n报警人:{record.AskPerson}";
|
||
//发送手表
|
||
Watchup.StartPush(message, _socketGateway);
|
||
|
||
record.Id = SnowFlakeSingle.Instance.NextId().ToString();
|
||
record.StartTime = DateTime.Now;
|
||
record.Status = 1;
|
||
record.CreatedBy = "system";
|
||
record.CreatedTime = DateTime.Now;
|
||
int result = Context.Insertable(record).ExecuteCommand();
|
||
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
} |