using DOAN.Infrastructure.Helper; using DOAN.Model.JobKanban; using DOAN.Model.mes.echarts; 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 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, IWorkorderProgressService { private ProProducttypeSpecService _proProducttypeSpecService = new ProProducttypeSpecService(); public List GetRoutes() { return Context.Queryable().Where(it => it.Status == 1).ToList(); } public List GetGroups() { return Context.Queryable().Where(it => it.Status == 1).ToList(); } public List GetWorkOrderList(string group_code, string line_code, DateTime handleDate) { handleDate = handleDate.ToLocalTime().Date; return Context.Queryable().Where(it => it.GroupCode == group_code) .Where(it => it.LineCode == line_code) .Where(it => it.WorkorderDate == handleDate) .ToList(); } public List GetReportWorkRecord(string group_code, string line_code, DateTime handleDate) { return Context.Queryable().LeftJoin((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>(); } /// /// 获取工单列表 未完成 /// /// /// /// public List GetWorkOrderListNoFinish(DateTime today, string line_code, string group_code) { today = today.ToLocalTime().Date; var query1 = Context.Queryable() .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) ; var ProWorkorderDto4List = Context.Queryable(query1) .LeftJoin((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() .Where(it => it.Workorder == workorder); return Context.Queryable(query) .LeftJoin((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() .Where(it => it.WorkorderDate == today) .Where(it => it.LineCode == line_code) .Where(it => it.GroupCode == group_code) .Count(); kanbanInfo.RemainTasKNum = Context.Queryable() .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) .Count(); return kanbanInfo; } public async Task StartWorkOrder(string workorder) { var result = 0; // 获取同一天 同一组 同一线 的所有工单 把状态2 设为init 1 var handleWorkorder = Context.Queryable().Where(it => it.Workorder == workorder).First(); UseTran2(() => { Context.Updateable().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().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() // .LeftJoin((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() // .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(responseJson); // 解析接口响应 if (responseDto != null && responseDto.Code == "200") { // 首检记录发送成功,记录到本地数据库 //TODO 记录首检日志 } else { } } } } catch (Exception ex) { throw; } } /// /// 暂停工单 /// /// /// 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() .SetColumns(it => it.Status == 4) .SetColumns(it => it.EndTime == DateTime.Now) .Where(it => it.Workorder == workorder).ExecuteCommand(); }); return result; } /// /// 恢复工单 /// /// /// public int RecoverWorkOrder(string workorder) { int result = 0; UseTran2(() => { ProWorkorderStatus proWorkorderStatus = new ProWorkorderStatus(); proWorkorderStatus.FkWorkorderCode = workorder; proWorkorderStatus.Status = 5; proWorkorderStatus.ChangeTime = DateTime.Now; proWorkorderStatus.CreatedTime = DateTime.Now; Context.Insertable(proWorkorderStatus).ExecuteCommand(); result = Context.Updateable() .SetColumns(it => it.Status == 5) .SetColumns(it => it.EndTime == DateTime.Now) .Where(it => it.Workorder == workorder).ExecuteCommand(); }); return result; } /// /// 工单完成 /// /// /// 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() .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() .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() .Where(it => it.Workorder == workOrder) .Where(it => it.LabelContext == LabelContext) .SetColumns(it => it.Status == 1) .ExecuteCommand(); } /// /// 防错并且报工 /// /// /// /// public int ErrorProofingAndReportingWork(string workorder, string labelContext) { var checked_workorder = Context.Queryable().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().Where(it => it.FkWorkorder == workorder).First(); var result = 0; if (ExistReportwork != null) { reportWork.FinishedNum = ExistReportwork.FinishedNum + 1; result += Context.Updateable().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().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; }*/ return result; } public int FinishWorkorder(string workorder, int finish_num) { var result = 0; result = Context.Updateable() .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().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().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 GetWorkOrderScanCodeInfo(string workorder) { return Context.Queryable().SplitTable(tabs => tabs.Take(1)).Where(it => it.Workorder == workorder).ToList(); } /// /// 根据工单号 查询每个工单号进度 /// /// /// private MaterialPreparationProgress SearchMaterialPreparationProgress(string Workorder) { var progress = new MaterialPreparationProgress(); //TODO 查询工单总任务数 progress.WorkOrder = Workorder; progress.Preparation_all_num = Context.Queryable() .Where(it => it.FkWorkorder == Workorder) .Count(); progress.Preparationed_num = Context.Queryable().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().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("今日各组实时完工数与计划完工柱状图", "获取今日各组实时每小时完工数柱状图"); //横轴 8:00 20:00 每60分钟累加一次 // 1.获取这个班组工作时间 GroupShift Shifts = Context.Queryable().LeftJoin((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; // 定义一个表示8小时的时间间隔 TimeSpan eightOClock = new TimeSpan(Shifts.StartTime.Value.Hour, Shifts.StartTime.Value.Minute, Shifts.StartTime.Value.Second); // 将今天的日期与8点的时间间隔相加 DateTime todayAtEight = today + eightOClock; DateTime[] dateTimeArray = new DateTime[intervals]; for (int i = 0; i < intervals; i++) { TimeSpan spanItem = new TimeSpan(0, 60 * i, 0);// 60分钟间隔 DateTime TodayItem = todayAtEight + spanItem; dateTimeArray[i] = TodayItem; } EchartsXAxis XAxis = new EchartsXAxis(); XAxis.Data = dateTimeArray.Select(it => it.ToString("HH:mm")).ToList(); echartsOptions.XAxis = XAxis; //2 系列值-这组 今日实时完成数(60分钟) EchartsSeries echartsSeries = new EchartsSeries(); echartsSeries.Name = groupCode + "组今日实时完成数(每60分钟)"; echartsSeries.Type = "bar"; List echartsSeriesDatas = new List(); //UNIX_TIMESTAMP(timestamp) 把 timestamp 转换为自 Unix 纪元以来的秒数。 //FLOOR(... / 600) 将该时间戳除以600(10分钟的秒数),然后向下取整到最接近的整数。 //*600 再次乘以600,以获得每个10分钟周期开始的时间戳。 //FROM_UNIXTIME(...) 将处理后的时间戳转换回日期时间格式,以便在结果集中显示。 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 ) / 600 ) ORDER BY time_period"; DataTable result = Context.Ado.GetDataTable(sql, new { groupCode = groupCode, }); int sum = 0; foreach (DataRow row in result.Rows) { // DateTime value =(DateTime)row["time_period"]; DateTime value = row["time_period"] != DBNull.Value ? Convert.ToDateTime(row["time_period"]) : DateTime.MinValue; int count = Convert.ToInt32(row["count"]); // sum = sum + count; EchartsSeriesData echartsSeriesData = new EchartsSeriesData() { Name = value.ToString("HH:mm"), Value = count }; echartsSeriesDatas.Add(echartsSeriesData); } int currentNum = Array.IndexOf(XAxis.Data.ToArray(), echartsSeriesDatas.Select(it => it.Name).LastOrDefault()); for (int i = 0; i < currentNum; i++) { int point = 0; foreach (var item in echartsSeriesDatas) { if (item.Name == XAxis.Data[i]) { continue; } point++; } if (point == echartsSeriesDatas.Count()) { // 获取前一个时间段产量 decimal productNum = 0; if (i >= 1) { productNum = echartsSeriesDatas.Where(it => it.Name == XAxis.Data[i - 1]).Select(it => it.Value).FirstOrDefault(); } else { productNum = 0; } echartsSeriesDatas.Add(new EchartsSeriesData() { Name = XAxis.Data[i], Value = productNum }); } } echartsSeries.Data = echartsSeriesDatas.OrderBy(it => it.Name).ToList(); echartsOptions.Series.Add(echartsSeries); //3 系列值-这组 今日计划累计完成数(每60分钟) //获取今天这个组的所有工单 List ProWorkorderList = Context.Queryable().Where(it => it.GroupCode == groupCode && it.WorkorderDate == DateTime.Today).ToList(); if (ProWorkorderList.Count() == 0) { return null; } //求出总产量需要多少s int allSecends = 0; foreach (var item in ProWorkorderList) { int num = (item.DeliveryNum ?? 0) * (item.Beat ?? 0); allSecends = num + allSecends; } // 将节拍转为每60分钟产量 int allproduct = ProWorkorderList.Sum(it => it.DeliveryNum ?? 0); int productOfeachTenMin = allproduct / (allSecends / (60 * 60)); EchartsSeries echartsSeries02 = new EchartsSeries(); echartsSeries02.Name = groupCode + "组今日计划完成数(每60分钟)"; echartsSeries02.Type = "bar"; List echartsSeriesData02s = new List(); //int all_plan_product = 0; for (int i = 0; i < dateTimeArray.Length; i++) { EchartsSeriesData echartsSeriesData = new EchartsSeriesData(); echartsSeriesData.Name = dateTimeArray[i].ToString("HH:mm"); echartsSeriesData.Value = productOfeachTenMin; echartsSeriesData02s.Add(echartsSeriesData); //all_plan_product = all_plan_product + productOfeachTenMin; } echartsSeries02.Data = echartsSeriesData02s; echartsOptions.Series.Add(echartsSeries02); return echartsOptions; } }