diff --git a/QcMgr/Tnb.QcMgr.Entities/Dto/SpcData.cs b/QcMgr/Tnb.QcMgr.Entities/Dto/SpcData.cs index 705cfb5a..e5af3a8a 100644 --- a/QcMgr/Tnb.QcMgr.Entities/Dto/SpcData.cs +++ b/QcMgr/Tnb.QcMgr.Entities/Dto/SpcData.cs @@ -3,10 +3,108 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Spire.Xls.Core.Spreadsheet.Charts; namespace Tnb.QcMgr.Entities { public class SpcDataInput { + /// + /// 主表id + /// + public string? mainid { get; set; } + /// + /// 检验时间 + /// + public string? checktime { get; set; } + + /// + /// 批次 + /// + public string? batch { get; set; } + + /// + /// 数据 + /// + public float[] data { get; set; } + + /// + /// 检查数量 + /// + public int? checknum { get; set; } + + /// + /// 不良品数量 + /// + public int? defectivenum { get; set; } + } + public class XRchart + { + public List xcharts { get; set; } + public List rcharts { get; set; } + } + public class XRxchart + { + public float? x { get; set; } + public float? jc { get; set; } + public float? usl { get; set; } + public float? cl { get; set; } + public float? lsl { get; set; } + public float? uclx { get; set; } + public float? clx { get; set; } + public float? lclx { get; set; } + } + public class XRrchart + { + public float? r { get; set; } + public float? uclr { get; set; } + public float? clr { get; set; } + public float? lclr { get; set; } + } + public class XSchart + { + public List xcharts { get; set; } + public List scharts { get; set; } + } + public class XSxchart + { + public float? x { get; set; } + public float? bzc { get; set; } + public float? usl { get; set; } + public float? cl { get; set; } + public float? lsl { get; set; } + public float? uclx { get; set; } + public float? clx { get; set; } + public float? lclx { get; set; } + } + public class XSschart + { + public float? s { get; set; } + public float? ucls { get; set; } + public float? cls { get; set; } + public float? lcls { get; set; } + } + + public class XMRchart + { + public List xmrxcharts { get; set; } + public List xmrmrcharts { get; set; } + } + public class XMRxchart + { + public float? x { get; set; } + public float? usl { get; set; } + public float? cl { get; set; } + public float? lsl { get; set; } + public float? uclx { get; set; } + public float? clx { get; set; } + public float? lclx { get; set; } + } + public class XMRmrschart + { + public float? mr { get; set; } + public float? uclmr { get; set; } + public float? clmr { get; set; } + public float? lclmr { get; set; } } } diff --git a/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcConfig.cs b/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcConfig.cs index 9312eb96..4cf90a08 100644 --- a/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcConfig.cs +++ b/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcConfig.cs @@ -28,7 +28,7 @@ namespace Tnb.QcMgr.Entities /// /// 子组容量 /// - public string? subcapacity { get; set; } + public int? subcapacity { get; set; } /// /// 控制图键 @@ -38,7 +38,7 @@ namespace Tnb.QcMgr.Entities /// /// 控制图值 /// - public decimal? spcdata { get; set; } + public float? spcdata { get; set; } } diff --git a/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcH.cs b/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcH.cs index f0e96a3d..2a81b63e 100644 --- a/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcH.cs +++ b/QcMgr/Tnb.QcMgr.Entities/Entity/QcSpcH.cs @@ -98,17 +98,17 @@ namespace Tnb.QcMgr.Entities /// /// 规格上限 /// - public decimal? uplimit { get; set; } + public float? uplimit { get; set; } /// /// 目标值 /// - public decimal? target { get; set; } + public float? target { get; set; } /// /// 规格下限 /// - public decimal? lowerlimit { get; set; } + public float? lowerlimit { get; set; } /// /// 子组容量 diff --git a/QcMgr/Tnb.QcMgr.Interfaces/IQcSpcService.cs b/QcMgr/Tnb.QcMgr.Interfaces/IQcSpcService.cs index 1d6b2afb..77097e46 100644 --- a/QcMgr/Tnb.QcMgr.Interfaces/IQcSpcService.cs +++ b/QcMgr/Tnb.QcMgr.Interfaces/IQcSpcService.cs @@ -20,6 +20,8 @@ namespace Tnb.QcMgr.Interfaces /// 保存spcd数据 /// /// - public Task SaveData(SpcDataInput SpcDataInput); + public Task SaveData(List SpcDataInput); + + public Task GetSpcData(string id); } } diff --git a/QcMgr/Tnb.QcMgr/QcSpcService.cs b/QcMgr/Tnb.QcMgr/QcSpcService.cs new file mode 100644 index 00000000..297b6ca7 --- /dev/null +++ b/QcMgr/Tnb.QcMgr/QcSpcService.cs @@ -0,0 +1,302 @@ +using System; +using System.ArrayExtensions; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Aspose.Cells.Drawing; +using JNPF.Common.Core.Manager; +using JNPF.Common.Enums; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.FriendlyException; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.QcMgr.Entities; +using Tnb.QcMgr.Entities.Entity; +using Tnb.QcMgr.Interfaces; + +namespace Tnb.QcMgr +{ + /// + /// spc模块 + /// + [ApiDescriptionSettings(Tag = ModuleConsts.Tag, Area = ModuleConsts.Area, Order = 800)] + public class QcSpcService : IQcSpcService, IDynamicApiController, ITransient + { + private readonly ISqlSugarRepository _repository; + private readonly IUserManager _userManager; + public QcSpcService(ISqlSugarRepository repository, IUserManager userManager) + { + _repository = repository; + _userManager = userManager; + } + /// + /// 获取spcd数据 + /// + /// + /// + [HttpPost] + public async Task GetSpcItems(string id) + { + var datas= await _repository.AsSugarClient().Queryable().Where(p => p.mainid == id).ToListAsync(); + List SpcDataInputs=new List(); + datas.ForEach(p => + { + SpcDataInput SpcDataInput = new SpcDataInput(); + SpcDataInput.mainid = p.mainid; + SpcDataInput.checktime = p.checktime; + SpcDataInput.batch = p.batch; + SpcDataInput.data = Array.ConvertAll(p.data!.Split(","),float.Parse); + SpcDataInput.checknum = p.checknum; + SpcDataInput.defectivenum = p.defectivenum; + SpcDataInputs.Add(SpcDataInput); + }); + return SpcDataInputs; + } + /// + /// 保存spcd + /// + /// + /// + [HttpPost] + public async Task SaveData(List SpcDataInput) + { + var db = _repository.AsSugarClient(); + try + { + if (!string.IsNullOrEmpty(SpcDataInput.First().mainid)) + await db.Deleteable(p => p.mainid == SpcDataInput.First().mainid).ExecuteCommandAsync(); + List QcSpcDs = new List(); + + + SpcDataInput.ForEach(p => + { + QcSpcD QcSpcD=new QcSpcD(); + QcSpcD.mainid = p.mainid; + QcSpcD.checktime = p.checktime; + QcSpcD.batch = p.batch; + QcSpcD.data = string.Join(",", p.data); + QcSpcD.checknum = p.checknum; + QcSpcD.defectivenum = p.defectivenum; + QcSpcD.create_id = _userManager.UserId; + QcSpcD.create_time=DateTime.Now; + QcSpcDs.Add(QcSpcD); + }); + await db.Ado.BeginTranAsync(); + await db.Insertable(QcSpcDs).ExecuteCommandAsync(); + await db.Ado.CommitTranAsync(); + } + catch (Exception) + { + await db.Ado.RollbackTranAsync(); + throw Oops.Oh(ErrorCode.COM1000); + } + } + /// + /// 获取spc图表 + /// + /// + /// + [HttpPost] + public async Task GetSpcData(string id) + { + var QcSpcH = await _repository.AsSugarClient().Queryable().Where(p => p.id == id).FirstAsync(); + var QcSpcDs = await _repository.AsSugarClient().Queryable().Where(p => p.mainid == id).ToListAsync(); + var cinfigs = await _repository.AsSugarClient().Queryable().ToListAsync(); + if (QcSpcH.graphtype == "X-R控制图") + { + XRchart XRchart = new XRchart(); + XRchart.xcharts = new List(); + XRchart.rcharts = new List(); + foreach (var QcSpcD in QcSpcDs) + { + List datas = Array.ConvertAll(QcSpcD.data!.Split(",", StringSplitOptions.RemoveEmptyEntries), float.Parse).ToList(); + XRxchart xchart = new XRxchart(); + xchart.x = datas.Average(); + xchart.jc = datas.Max() - datas.Min(); + xchart.usl = QcSpcH.uplimit; + xchart.cl = QcSpcH.target; + xchart.lsl = QcSpcH.lowerlimit; + XRrchart rchart = new XRrchart(); + rchart.r = datas.Max() - datas.Min(); + XRchart.xcharts.Add(xchart); + XRchart.rcharts.Add(rchart); + } + var xAverage = XRchart.xcharts.Select(p => p.x).Average(); + var num = XRchart.xcharts.Select(p => p.jc).Average() * cinfigs.Where(p => p.spctype == "X-R图" && p.spckey == "A2" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + XRchart.xcharts.ForEach(p => + { + p.uclx = xAverage + num; + p.clx = xAverage; + p.lclx = xAverage - num; + }); + var D4 = cinfigs.Where(p => p.spctype == "X-R图" && p.spckey == "D4" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + var D3 = cinfigs.Where(p => p.spctype == "X-R图" && p.spckey == "D3" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + var rAverage = XRchart.rcharts.Select(p => p.r).Average(); + XRchart.rcharts.ForEach(p => + { + p.uclr = rAverage * D4; + p.clr = rAverage; + p.lclr = rAverage * D3; + }); + return XRchart; + } + if (QcSpcH.graphtype == "X-S控制图") + { + XSchart XSchart = new XSchart(); + XSchart.xcharts = new List(); + XSchart.scharts = new List(); + foreach (var QcSpcD in QcSpcDs) + { + List datas = Array.ConvertAll(QcSpcD.data!.Split(",", StringSplitOptions.RemoveEmptyEntries), float.Parse).ToList(); + XSxchart xchart = new XSxchart(); + xchart.x = datas.Average(); + xchart.bzc = CalculateStdDev(datas); + xchart.usl = QcSpcH.uplimit; + xchart.cl = QcSpcH.target; + xchart.lsl = QcSpcH.lowerlimit; + XSschart schart = new XSschart(); + schart.s = CalculateStdDev(datas); + XSchart.xcharts.Add(xchart); + XSchart.scharts.Add(schart); + } + var xAverage = XSchart.xcharts.Select(p => p.x).Average(); + var num = XSchart.xcharts.Select(p => p.bzc).Average() * cinfigs.Where(p => p.spctype == "X-S图" && p.spckey == "A3" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + XSchart.xcharts.ForEach(p => + { + p.uclx = xAverage + num; + p.clx = xAverage; + p.lclx = xAverage - num; + }); + var B4 = cinfigs.Where(p => p.spctype == "X-S图" && p.spckey == "B4" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + var B3 = cinfigs.Where(p => p.spctype == "X-S图" && p.spckey == "B3" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + var sAverage = XSchart.scharts.Select(p => p.s).Average(); + XSchart.scharts.ForEach(p => + { + p.ucls = sAverage * B4; + p.cls = sAverage; + p.lcls = sAverage * B3; + }); + return XSchart; + } + if (QcSpcH.graphtype == "X中位数-R图") + { + XRchart XRchart = new XRchart(); + XRchart.xcharts = new List(); + XRchart.rcharts = new List(); + foreach (var QcSpcD in QcSpcDs) + { + List datas = Array.ConvertAll(QcSpcD.data!.Split(",", StringSplitOptions.RemoveEmptyEntries), float.Parse).ToList(); + XRxchart xchart = new XRxchart(); + xchart.x = CalculateMedian(datas); + xchart.jc = datas.Max() - datas.Min(); + xchart.usl = QcSpcH.uplimit; + xchart.cl = QcSpcH.target; + xchart.lsl = QcSpcH.lowerlimit; + XRrchart rchart = new XRrchart(); + rchart.r = datas.Max() - datas.Min(); + XRchart.xcharts.Add(xchart); + XRchart.rcharts.Add(rchart); + } + var xAverage = XRchart.xcharts.Select(p => p.x).Average(); + var num = XRchart.xcharts.Select(p => p.jc).Average() * cinfigs.Where(p => p.spctype == "中位数图" && p.spckey == "A2" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + XRchart.xcharts.ForEach(p => + { + p.uclx = xAverage + num; + p.clx = xAverage; + p.lclx = xAverage - num; + }); + var D4 = cinfigs.Where(p => p.spctype == "中位数图" && p.spckey == "D4" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + var D3 = cinfigs.Where(p => p.spctype == "中位数图" && p.spckey == "D3" && p.subcapacity == QcSpcH.samplesize).Select(p => p.spcdata).First(); + var rAverage = XRchart.rcharts.Select(p => p.r).Average(); + XRchart.rcharts.ForEach(p => + { + p.uclr = rAverage * D4; + p.clr = rAverage; + p.lclr = rAverage * D3; + }); + return XRchart; + } + if (QcSpcH.graphtype == "X-MR控制图") + { + XMRchart XMRchart = new XMRchart(); + XMRchart.xmrxcharts = new List(); + XMRchart.xmrmrcharts = new List(); + foreach (var QcSpcD in QcSpcDs) + { + List datas = Array.ConvertAll(QcSpcD.data!.Split(",", StringSplitOptions.RemoveEmptyEntries), float.Parse).ToList(); + XMRxchart xchart = new XMRxchart(); + xchart.x = datas.Average(); + xchart.usl = QcSpcH.uplimit; + xchart.cl = QcSpcH.target; + xchart.lsl = QcSpcH.lowerlimit; + if (XMRchart.xmrxcharts.Count > 0) + { + XMRmrschart rchart = new XMRmrschart(); + rchart.mr = Math.Abs((float)(xchart.x - XMRchart.xmrxcharts.Last().x)!); + XMRchart.xmrmrcharts.Add(rchart); + } + XMRchart.xmrxcharts.Add(xchart); + } + var xAverage = XMRchart.xmrxcharts.Select(p => p.x).Average(); + var mrAverage = XMRchart.xmrmrcharts.Select(p => p.mr).Average(); + XMRchart.xmrxcharts.ForEach(p => + { + p.uclx = xAverage + (float)(2.66 * mrAverage)!; + p.clx = xAverage; + p.lclx = xAverage - (float)(2.66 * mrAverage)!; + }); + XMRchart.xmrmrcharts.ForEach(p => + { + p.uclmr = (float)(mrAverage * 3.267)!; + p.clmr = mrAverage; + p.lclmr = 0; + }); + return XMRchart; + } + return null; + } + //标准差计算 + private static float CalculateStdDev(IEnumerable values) + { + double ret = 0; + if (values.Count() > 0) + { + // 计算平均数 + double avg = values.Average(); + // 计算各数值与平均数的差值的平方,然后求和 + double sum = values.Sum(d => Math.Pow(d - avg, 2)); + // 除以数量,然后开方 + ret = Math.Sqrt(sum / values.Count()); + } + return (float)ret; + } + //中位数计算 + private static float CalculateMedian(IEnumerable values) + { + float ret = 0; + var floats = values.OrderBy(d => d).ToArray(); + if (floats.Count() % 2 == 0) + { + ret = (floats[floats.Count() / 2 - 1] + floats[(floats.Count() + 2) / 2 - 1]) / 2; + } + else + { + ret = floats[(floats.Count() + 1) / 2 - 1]; + } + return ret; + } + //移动极差平均值计算 + private static float CalculateMovRange(IEnumerable values) + { + List floats = new List(); + var arr=values.ToArray(); + for (int i = 0; i < arr.Length-1; i++) + { + floats.Add(Math.Abs((arr[i + 1] - arr[i]))); + } + return floats.Average(); + } + } +}