zhuangpei-mesbackend/DOAN.Service/JobKanban/WorkorderProgressService.cs
2026-02-05 14:19:22 +08:00

791 lines
29 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 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;
}
}
}