using DocumentFormat.OpenXml.Drawing.Spreadsheet; using DocumentFormat.OpenXml.Math; using DocumentFormat.OpenXml.Spreadsheet; using Learun.Application.Organization; using Learun.Application.TwoDevelopment.ZZDT_EC; using Learun.Application.TwoDevelopment.ZZDT_EC.Frame; using Learun.Cache.Base; using Learun.Cache.Factory; using Learun.Loger; using Learun.Util; using Learun.Util.SqlSugar; using log4net.Config; using Microsoft.Practices.ObjectBuilder2; using Newtonsoft.Json; using NPOI.POIFS.Crypt; using NPOI.SS.Formula.Functions; using OfficeOpenXml; using OfficeOpenXml.Style; using Org.BouncyCastle.Bcpg.OpenPgp; using Pipelines.Sockets.Unofficial.Arenas; using SqlSugar; using System; using System.Collections.Generic; using System.Data.Entity.Infrastructure; using System.Diagnostics; using System.IO; using System.Linq; using System.Web.Http; using System.Windows; using System.Windows.Input; using static Learun.Application.TwoDevelopment.ZZDT_EC.IO_WorkFlowService; using static Learun.Application.Web.Areas.ZZDT_EC.Controllers.ec_objecttypeController; namespace Learun.Application.Web.AppApi { /// /// IO模块(By YuXH) /// [HandlerApiLogin(FilterMode.Ignore)] public class IOModuleApiController : WebApiControllerBase { #region 模块对象 private ec_CableBLL ec_CableBLL = new ec_CableBLL(); private ec_PanelBLL ec_PanelBLL = new ec_PanelBLL(); private ec_PanelStripBLL ec_PanelStripBLL = new ec_PanelStripBLL(); private ec_PanelStripTermBLL ec_PanelStripTermBLL = new ec_PanelStripTermBLL(); private ec_PanelChannelBLL ec_PanelChannelBLL = new ec_PanelChannelBLL(); #endregion #region 信号相关 #endregion /// /// 根据模板自动创建端子排 /// /// /// /// /// /// private ec_PanelStripEntity CreatePanelStripByProfile2(string projId, ec_PanelEntity panelObj, int seq, GlobalEnum.IOType iOType) { var setTb = ProjectSugar.TableName(projId); var allSettings = SqlSugarHelper.Db.Queryable().AS(setTb).ToList(); allSettings = allSettings.FindAll(x => x.SettingName.StartsWith(GlobalObject.projSetting_IOCardProfile + iOType.ToString())); //IO_CardProfile //IO_CardProfile_DO_TermNoPerCh //IO_CardProfile_DO_CHNoPerStrip //IO_CardProfile_DO_ChNamePrefix //IO_CardProfile_DO_ChNameStartIndex var sName = GlobalObject.projSetting_IOCardProfile + iOType.ToString() + "_TermNoPerCh"; var TermNoPerCh = allSettings.FirstOrDefault(x => x.SettingName == sName)?.SettingValue; sName = GlobalObject.projSetting_IOCardProfile + iOType.ToString() + "_CHNoPerStrip"; var CHNoPerStrip = allSettings.FirstOrDefault(x => x.SettingName == sName)?.SettingValue; sName = GlobalObject.projSetting_IOCardProfile + iOType.ToString() + "_ChNamePrefix"; var ChNamePrefix = allSettings.FirstOrDefault(x => x.SettingName == sName)?.SettingValue; if (int.TryParse(TermNoPerCh, out int iTermNoPerCh)) { //err } if (int.TryParse(CHNoPerStrip, out int iCHNoPerStrip)) { //err } var newTs = new ec_PanelStripEntity() { IO_TYPE = iOType.ToString(), PanelID = panelObj.PanelID, Panel_Strip_Seq = seq, StripName = "TS_" + iOType.ToString() + "_" + seq, TagNumber = "CreatePanelStripByProfile2" }; newTs.Create(); for (int i = 0; i < iCHNoPerStrip; i++) { var newCh = new ec_PanelChannelEntity() { ChannelName = ChNamePrefix + (i + 1).ToString(), Channel_Seq = i + 1, StripID = newTs.StripID, }; newCh.Create(); newTs.Channels.Add(newCh); } return newTs; } /// /// 找到某一个预分配箱子 附近的某一个箱子。且io类型能匹配上 /// /// /// /// 所有柜子的属性 /// Digital,4-20mA,10v,pt100,pulse /// private ec_PanelEntity FindPanelNearby(ec_CableEntity cableObj, List frameLists, List allPanel, Dictionary> allPanelProps, string IOTypeOnCable) { var curPanelId = cableObj.PanelID; double GetPanelXYDistance2Target(string panelId, double targetX, double targetY) { var nearPanel = allPanel.FirstOrDefault(x => x.PanelID == panelId); var nearPanelProps = allPanelProps[nearPanel.EngineerDataID]; var X = nearPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_Frame)?.PropertyValue; X = X.Split(new string[] { GlobalObject.enum_separator }, StringSplitOptions.None)[0];//插件端对于下拉列表 都是 name || nameEN var validFrme2 = frameLists.FirstOrDefault(f => f.Num == X); if (validFrme2 == null) { return -1;//无效的肋位号导致的 } var XValue = validFrme2.Value; if (XValue < 400)//null也没事 { // 小于400,我几乎可以认为此时肋位号用的是m这个单位。因为如果用的是mm,400mm的肋位号似乎也太小了。 XValue = 1000 * XValue; // 转成mm } if (double.TryParse(nearPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_FrameOff)?.PropertyValue, out double XOffValue)) { } else { return -1;//无效的x off导致的 } if (double.TryParse(nearPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_YOff)?.PropertyValue, out double YOffValue)) { } else { return -1;//无效的y off导致的 } var distance = Math.Sqrt(Math.Pow(targetX - XValue - XOffValue, 2) + Math.Pow(targetY - YOffValue, 2)); return distance; } var curPanel = allPanel.FirstOrDefault(x => x.PanelID == curPanelId); var curPanelProps = allPanelProps[curPanel.EngineerDataID]; //当前预分配的箱子的位置 var AssignPanelX = curPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_Frame)?.PropertyValue; AssignPanelX = AssignPanelX.Split(new string[] { GlobalObject.enum_separator }, StringSplitOptions.None)[0];//插件端对于下拉列表 都是 name || nameEN var validFrme = frameLists.FirstOrDefault(X => X.Num == AssignPanelX); if (validFrme == null) { return null;//无效的肋位号导致的 } var AssignPanelXValue = validFrme.Value; if (AssignPanelXValue < 400)//null也没事 { // 小于400,我几乎可以认为此时肋位号用的是m这个单位。因为如果用的是mm,400mm的肋位号似乎也太小了。 AssignPanelXValue = 1000 * AssignPanelXValue; // 转成mm } if (double.TryParse(curPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_FrameOff)?.PropertyValue, out double AssignPanelXOffValue)) { } else { return null;//无效的x off导致的 } if (double.TryParse(curPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_YOff)?.PropertyValue, out double AssignPanelYValue)) { } else { return null;//无效的y off导致的 } double minDistance = 0.1; ec_PanelEntity nearestPanel = null; foreach (var panel in allPanel.Where(x => x.PanelID != curPanelId)) { #region io var IOMatched = true; var IOsOnPanel = panel.allowedIOTypes.Split(',').ToList(); //剩下的感觉都可以是set上的参数? foreach (var set in cableObj.Sets) { #region 判断下io匹配程度 var setNew = ec_CableBLL.SetIOMatchPanel(cableObj.PreAssignIOType, set, IOsOnPanel); if (IOsOnPanel.Contains(setNew.IOType.ToString())) { setNew.IOTypeMatch = true; } else { setNew.IOTypeMatch = false; IOMatched = false; //不匹配 break; } #endregion } #endregion if (IOMatched) { //如果io匹配了,再找附近的 #region distance //拿到每一个的xy属性 //然后和预分配箱子进行对比 var DISTANCE = GetPanelXYDistance2Target(panel.PanelID, AssignPanelXValue + AssignPanelXOffValue, AssignPanelYValue); if (0.1 == minDistance && DISTANCE > 0) { minDistance = DISTANCE; nearestPanel = panel; } else if (DISTANCE < minDistance && DISTANCE > 0) { minDistance = DISTANCE; nearestPanel = panel; } #endregion } } return nearestPanel; } /// /// IO分配主界面查询,查询所有的位置 - 采集箱 - 模块 - 通道 /// /// /// public IHttpActionResult GetPanelTree(string projectId) { //2023 05 22,从用户所在的role的lr base authorize里去查 //UserInfo userInfo = LoginUserInfo.Get(); //UserRelationIBLL userRelationIBLL = new UserRelationBLL(); //var roles = userRelationIBLL.GetObjectIds(userInfo.userId, 1, projectId); var stopWatch = new Stopwatch(); var Locations = GetLocList(projectId); if (Locations == null) { return Fail("系统设置中找不到“系统柜位置”这一项内容。联系管理员"); } var ec_PanelStripTermService = new ec_PanelStripTermBLL(); var ec_WireTerminalService = new ec_WireTerminalService(); var ec_Wire_GroupService = new ec_Wire_GroupBLL(); stopWatch.Start(); var Panels = ec_PanelBLL.GetList("{ProjectId:\"" + projectId + "\"}").OrderBy(x => x.TagNumber).ToList(); stopWatch.Stop(); this.Logger.Info($"Panel查询 {stopWatch.ElapsedMilliseconds}" + "\r\n"); stopWatch.Start(); var Strips = ec_PanelStripBLL.GetList("{ProjectId:\"" + projectId + "\"}").OrderBy(x => x.Panel_Strip_Seq).OrderBy(x => x.StripName); stopWatch.Stop(); this.Logger.Info($"Strip查询 {stopWatch.ElapsedMilliseconds}" + "\r\n"); stopWatch.Start(); var Channels = ec_PanelChannelBLL.GetList("{ProjectId:\"" + projectId + "\"}"); stopWatch.Stop(); this.Logger.Info($"Channel查询 {stopWatch.ElapsedMilliseconds}" + "\r\n"); stopWatch.Start(); var AllTerms = ec_PanelStripTermService.GetList("{ProjectId:\"" + projectId + "\"}"); stopWatch.Stop(); this.Logger.Info($"Term查询 {stopWatch.ElapsedMilliseconds}" + "\r\n"); stopWatch.Start(); var AllWTs = ec_WireTerminalService.GetList("{ProjectId:\"" + projectId + "\"}", true); stopWatch.Stop(); this.Logger.Info($"WireTerminal查询 {stopWatch.ElapsedMilliseconds}" + "\r\n"); stopWatch.Start(); var AllSignals = ec_Wire_GroupService.GetList("{ProjectId:\"" + projectId + "\"}", true); stopWatch.Stop(); this.Logger.Info($"Signals查询 {stopWatch.ElapsedMilliseconds}" + "\r\n"); stopWatch.Start(); List treeList = new List(); foreach (var Loc in Locations) { TreeModel nodeCatalogue = new TreeModel(); nodeCatalogue.id = Loc.DataItemDetailID; nodeCatalogue.text = Loc.DataItemName; nodeCatalogue.value = Loc.DataItemName; nodeCatalogue.nodeType = "0"; nodeCatalogue.showcheck = false; nodeCatalogue.checkstate = 0; nodeCatalogue.isexpand = false; nodeCatalogue.parentId = Loc.UpDataItemDetailID; nodeCatalogue.NodeExtData = Loc; treeList.Add(nodeCatalogue); var listPanel = Panels.Where(x => x.Panel_Loc_ID == Loc.DataItemDetailID && x.systempanel == GlobalEnum.specialType.系统柜.ToString()).ToList(); if (listPanel != null && listPanel.Count > 0) { foreach (var Panel in listPanel) { TreeModel nodeFile = new TreeModel(); nodeFile.id = Panel.PanelID; nodeFile.text = Panel.TagNumber; nodeFile.value = Panel.EngineerDataID; nodeFile.nodeType = "1"; nodeFile.showcheck = false; nodeFile.checkstate = 0; nodeFile.isexpand = false; nodeFile.parentId = Panel.Panel_Loc_ID; //后面会根据变为tree nodeFile.NodeExtData = Panel; //判断下是不是有效的类型 treeList.Add(nodeFile); var StripsInPanel = Strips.Where(x => x.PanelID == Panel.PanelID).ToList(); if (StripsInPanel != null && StripsInPanel.Count > 0) { //StripsInPanel = StripsInPanel.OrderBy(x => x.Panel_Strip_Seq).ToList(); foreach (var Strip in StripsInPanel) { #region 带上汇总信息 var ChannelsInStrip = Channels.Where(x => x.StripID == Strip.StripID).ToList();//("{ProjectId:\"" + projectId + "\",StripID:\"" + Strip.StripID + "\",PanelID:\"" + Strip.PanelID + "\"}"); //Strip.Channels = ChannelsInStrip.ToList(); foreach (var Channel in ChannelsInStrip) { var Terms = AllTerms.Where(x => x.StripID == Strip.StripID && x.ChannelID == Channel.ChannelID).ToList();//ec_PanelStripTermService.GetList("{ProjectId:\"" + projectId + "\",StripID:\"" + Strip.StripID + "\",ChannelID:\"" + Channel.ChannelID + "\"}"); //wire termianl var conns = AllWTs.Where(x => Terms.Select(y => y.TermID).ToList().Contains(x.TermID)).ToList(); //.GetList(("{ProjectId:\"" + projectId + "\",PanelID:\"" + Strip.PanelID + "\",StripID:\"" + Strip.StripID + "\"}")); bool bUsed = false; if (conns != null && conns.Count() > 0) { bUsed = true; } //foreach (ec_PanelStripTermEntity term in Terms) //{ // var conn = conns.FirstOrDefault(x => x.TermID == term.TermID); // if (conn != null) // { // bUsed = true; // break; // } //} if (bUsed) { //wire group var signal = AllSignals.FirstOrDefault(x => x.ChannelID == Channel.ChannelID);//.GetList("{ProjectId:\"" + projectId + "\",StripID:\"" + Strip.StripID + "\",ChannelID:\"" + Channel.ChannelID + "\"}").FirstOrDefault(); if (signal != null) { Strip.ChannelsUsed += 1; } else { Strip.ChannelsUsedNoSignal += 1; } } else { Strip.ChannelsSpared += 1; } } #endregion TreeModel nodeStrip = new TreeModel(); nodeStrip.id = Strip.StripID; nodeStrip.text = Strip.StripName; nodeStrip.value = Strip.Panel_Strip_Seq; nodeStrip.nodeType = "1"; nodeStrip.showcheck = false; nodeStrip.checkstate = 0; nodeStrip.isexpand = false; nodeStrip.parentId = Strip.PanelID; nodeStrip.NodeExtData = Strip; treeList.Add(nodeStrip); } } } } } stopWatch.Stop(); this.Logger.Info($"循环位置耗时 {stopWatch.ElapsedMilliseconds}" + "\r\n"); return Success(treeList.ToTree()); } /// /// 根据ID拿。只查询ec panel表本身 /// /// /// /// [HttpGet] public IHttpActionResult GetPanel(string PanelID, string projId) { var res = ec_PanelBLL.GetEntity(projId, PanelID); return Success(res); } /// /// 根据EngineerDataID拿。包括set wire,以及from to信息 /// /// /// /// /// /// [HttpGet] public IHttpActionResult GetCableByEngID(string EngineerDataID, string projId, bool OnlySelf = false, bool PreAssign = false) { if (PreAssign) { var res = ec_CableBLL.GetCablePreAssign(projId, EngineerDataID); return Success(res); } else { var res = ec_CableBLL.GetCableByEngID(projId, EngineerDataID, OnlySelf); return Success(res); } } ICache redisObj = CacheFactory.CaChe(); /// /// 导出分配结果 /// /// /// 是否为真实结果。step2时为false,step3后为true [HttpGet] public void AutoAssignCable2Channel_ResExport(string projectId, bool flg) { var BLL = new ec_Wire_GroupBLL(); var bytes = new byte[] { }; try { ExcelPackage.LicenseContext = LicenseContext.NonCommercial; using (var package = new ExcelPackage())//新建 { var sheet = package.Workbook.Worksheets.Add("test"); sheet.Cells[1, 1].Value = "test"; bytes = package.GetAsByteArray(); } } catch (Exception ex) { log4net.LogManager.GetLogger("ERROR").Error("ec_PanelChannelBLL,IOModuleExportExcel 监控系统表导出" + ex.Message + ex.StackTrace); bytes = System.Text.Encoding.UTF8.GetBytes(ex.Message + ex.StackTrace); } var stream = new MemoryStream(bytes); FileDownHelper.DownLoad(stream, $"自动分配结果{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx");//自动化平台导出excel } /// /// 自动分配通道(点表信号自动分配)。 /// /// /// /// /// 需要分配的电缆cableid,不是enginedataId,逗号分开 /// [HttpPost] public IHttpActionResult AutoAssignCable2Channel_step1(string projId, bool AcceptNearbyPanel, [FromBody] List CableIds) { #region 数据准备 var frameBll = new FrameBll(); var allFrames = frameBll.GetFrameList(projId); var cbll = new ec_CableBLL(); var panelTable = ProjectSugar.TableName(projId); var stripTable = ProjectSugar.TableName(projId); var tagTable = ProjectSugar.TableName(projId); var propTable = ProjectSugar.TableName(projId); var typeTable = ProjectSugar.TableName(projId); #endregion #region 先要知道有哪些待分配的信号 端子排 if (CableIds == null || CableIds.Count == 0) { return Success("OK"); } var cablesNeedAssigned = cbll.GetCablesPreAssign(projId, CableIds, true); cablesNeedAssigned = cablesNeedAssigned.Where(x => CableIds.Contains(x.CableID)).ToList(); #endregion //涉及到哪些箱子 List allPanel = SqlSugarHelper.Db.Queryable().AS(panelTable). InnerJoin((a, b) => a.EngineerDataID == b.EngineDataID).AS(tagTable). InnerJoin((a, b, c) => b.ObjectTypeID == c.ObjectTypeID).AS(typeTable). Where((a, b, c) => c.specialType == GlobalEnum.specialType.系统柜). Select((a, b, c) => new ec_PanelEntity { allowedIOTypes = a.allowedIOTypes, DefaultBreakerType = a.DefaultBreakerType, EngineerDataID = a.EngineerDataID, MaxStripNumber = a.MaxStripNumber, ObjectTypeName = c.ObjectTypeName, PanelID = a.PanelID, Panel_Loc_ID = a.Panel_Loc_ID, TagNumber = b.TagNumber, }). ToList();//这里要过滤一下,根据object type里的specialType,而不是所有的panel var allPanelProp = SqlSugarHelper.Db.Queryable().AS(propTable) .Where(x => allPanel.Select(xx => xx.EngineerDataID).Contains(x.EngineDataID)) .ToList().GroupBy(x => x.EngineDataID).ToDictionary(x => x.Key, x => x.ToList()); var panelsNeed = allPanel.Where(x => cablesNeedAssigned.Select(xx => xx.PanelID).Contains(x.PanelID)).ToList();//用户指定的预分配的箱子 var stripsNeed = SqlSugarHelper.Db.Queryable().AS(stripTable). Where(x => panelsNeed.Select(xx => xx.PanelID).Contains(x.PanelID)). ToList(); #region 1.1判断(信号预分配选择的采集箱可能并没有该电缆需要的信号类型) var cablesNotMatchIO = cablesNeedAssigned.Where(x => x.IOTypesNotMatchedList.Count > 0).ToList(); // GetCablesPreAssign 查询时已经处理过io是否匹配了 if (cablesNotMatchIO != null && cablesNotMatchIO.Count > 0) { if (AcceptNearbyPanel)//允许进行 { //有不匹配的,但是用户允许继续 //如果选是,则在之后的自动分配过程中会自动寻找匹配的采集箱,原则上从就近的开始找,如果没有匹配的采集箱,则提示“未找到具有XX类型的采集箱,请新增后再次分配,是否取消自动分配进程?” foreach (var cable in cablesNotMatchIO) { var nearPanel = FindPanelNearby(cable, allFrames, allPanel, allPanelProp, cable.PreAssignIOType); cable.AssignedPanel = nearPanel; } var cableNotFoundNearPanel = cablesNotMatchIO.FindAll(x => x.AssignedPanel == null); if (cableNotFoundNearPanel != null && cableNotFoundNearPanel.Count > 0) { redisObj.Remove("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch); redisObj.Write>("IOModule_AutoAssign2Ch_" + projId, cablesNeedAssigned, CacheId.IOModule_AutoAssign2Ch); return Fail($"在电缆{string.Join(",", cableNotFoundNearPanel.Select(x => x.TagNumber))}附近未找到具有IO类型匹配的采集箱,请新增后再次分配,是否取消自动分配进程?"); //之后插件端进行选择。 //如果不想新增,则选择否,继续自动分配,没有分配到的信号在备注上填写由于何种原因没有被分配,弹出未被分配的信号列表供查看。 //也就是这里要等所有循环结束后才能return结果,而不是目前一个nearByFound = false时就退出了。 } } else { //如果选否,则不继续自动分配,中断进程,等添加完正确的模块后再继续自动分配 var cableNamesNotMatched = string.Join(",", cablesNotMatchIO.Select(x => x.TagNumber).ToList()); var panelIOMissing = new List(); foreach (ec_CableEntity cableNotMatchIO in cablesNotMatchIO) { panelIOMissing.Add(cableNotMatchIO.PanelID + "缺失IO: " + string.Join(",", cableNotMatchIO.IOTypesNotMatchedList)); } return Fail($"预分配结果中,以下电缆【{cableNamesNotMatched}】的IO类型和其预分配采集箱的IO类型无法匹配。等添加完正确的模块后再继续自动分配。\r\n" + $"需要添加的正确模块有:{string.Join(",", panelIOMissing)}"); } } else { //没有不匹配的,可以继续进行 } //必要的数据存入redis,以便后续步骤使用 redisObj.Remove("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch); redisObj.Write>("IOModule_AutoAssign2Ch_" + projId, cablesNeedAssigned, CacheId.IOModule_AutoAssign2Ch); return Success("OK"); #endregion } /// /// 根据step1的初步采集箱判断情况,来进行分配预览。 /// /// /// [HttpPost] public IHttpActionResult AutoAssignCable2Channel_step2(string projId) { ICache redisObj = CacheFactory.CaChe(); var cablesNeedAssigned = redisObj.Read>("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch); var signalTb = ProjectSugar.TableName(projId); var allSignals = SqlSugarHelper.Db.Queryable().AS(signalTb).ToList(); var connTb = ProjectSugar.TableName(projId); var termTb = ProjectSugar.TableName(projId); var allConnedTerms = SqlSugarHelper.Db.Queryable().AS(connTb) .InnerJoin((a, b) => a.TermID == b.TermID).AS(termTb) .Select((a, b) => b.ChannelID).Distinct().ToList(); //包括2部分,1是已经被信号占用的通道,2是已经被接线端子占用的通道 var allUsedCHBySignalOrSet = allSignals.Where(x => !string.IsNullOrEmpty(x.ChannelID)).Select(x => x.ChannelID).Distinct().ToList(); allUsedCHBySignalOrSet.AddRange(allConnedTerms); //??这里有问题。通道是否被占用,需要看signal和set双重(在io分配界面) //1. 信号有, 电缆set有,占了 //2.信号no,电缆set有,占了 //3.信号有,电缆setno,没占 //4.信号no,电缆setno,没占 //1.2 流程图 分组原则为同一信号类型、同一系统的为一组 var cablesGrouped = cablesNeedAssigned.OrderBy(x => x.AssignedPanel?.PanelID).ThenBy(x => x.PreAssignIOType).ThenBy(x => x.System).ToList(); var cNotPanel = cablesGrouped.FindAll(x => x.AssignedPanel == null); cablesGrouped = cablesNeedAssigned.FindAll(x => x.AssignedPanel != null); //cablesGrouped = cablesGrouped.Where(x => x.Sets != null && x.Sets.Count() > 0 && x.AssignedPanel != null).ToList();//过滤掉没有set的,或者没有找到箱子的 //cablesGrouped = cablesGrouped.Where(x => x.Sets.Where(xx => !string.IsNullOrEmpty(xx.PreAssignGroup_Desc)).Count() > 0).ToList();//过滤掉set没有分配信号的 var allPanelIds = cablesGrouped.Select(x => x.AssignedPanel).Select(x => x.PanelID).Distinct().ToList(); var stripBll = new ec_PanelStripBLL(); var allStrips = stripBll.GetList("{ProjectId:\"" + projId + "\"}", OnlySelf: false) .Where(x => allPanelIds.Contains(x.PanelID)) .GroupBy(x => x.PanelID) .ToDictionary(x => x.Key, x => x.ToList());//带出strip下的channel foreach (var c in cNotPanel) { foreach (var set in c.Sets) { set.ConnectionInfo = "err:没有找到合适的采集箱"; } } foreach (var curPanelId in allPanelIds) { int newTSSeq = 10001; var existedStrips = allStrips[curPanelId];//已经存在的所有模块 var cablesOnThisPanel = cablesGrouped.Where(x => x.AssignedPanel.PanelID == curPanelId).ToList(); if (cablesOnThisPanel == null || cablesOnThisPanel.Count == 0) continue;//next panel var lastUsedStrip = (ec_PanelStripEntity)null; foreach (var cable in cablesOnThisPanel) { //1.2.2 分组原则为同一信号类型、同一系统的为一组,系统属性从电缆的from端上的设备中取设备的系统,同组的优先放到同一个箱子的同一个模块里面, //如果一组放完后发现模块还有多余的通道可以放则下一个系统继续从这个模块开始分配。 //???总感觉这句话,总结后:可以无脑用上一个模块,直到模块满了再用下一个模块。 #region 判断是否是同一组 //bool sameGroup = true; //if (lastCableSystemAndIOType != cable.System + cable.PreAssignIOType) //{ // sameGroup = false;//换组了 //} #endregion //1.2 流程图 读取有提前选好箱子的信号 var setsSpared = cable.Sets.Where(x => string.IsNullOrEmpty(x.PreAssignGroup_Desc) || string.IsNullOrEmpty(x.PreAssignInOrOut)).ToList(); var setsIn = cable.Sets.Where(x => !string.IsNullOrEmpty(x.PreAssignGroup_Desc) && x.PreAssignInOrOut == SWS.Share.Enum.inOrOut.输入.ToString()).ToList(); var setsOut = cable.Sets.Where(x => !string.IsNullOrEmpty(x.PreAssignGroup_Desc) && x.PreAssignInOrOut == SWS.Share.Enum.inOrOut.输出.ToString()).ToList(); #region 1.2.4 同一根电缆,如果带公共端的报警信号,必须接到一个模块里面 if (cable.PreAssignIOType.ToLower() == GlobalEnum.signalType.Digital.ToString().ToLower()) { if (setsIn.Count > 0 && setsOut.Count > 0) { foreach (var set in setsIn) { set.ConnectionInfo = "err:digital类型的电缆,无法同时配置输入和输出。"; } foreach (var set in setsOut) { set.ConnectionInfo = "err:digital类型的电缆,无法同时配置输入和输出。"; } continue; //from cjj 25 09 23 wechat:一根电缆可能会出现既有输入也有输出,如果碰到就放到两个端子排里面,公共端不会出现一个输出,一个输入的 } } #endregion #region inputNew if (setsIn.Count > 0) { var resIn = AutoAssignCore(GlobalEnum.inOrOut.输入, setsIn); } #endregion #region output else if (setsOut.Count > 0) { var resOut = AutoAssignCore(GlobalEnum.inOrOut.输出, setsOut); } else { //all zero foreach (var set in cable.Sets.Where(x => !setsSpared.Select(c => c.CableSetID).Contains(x.CableSetID))) { set.ConnectionInfo = "err:信号描述为空"; } foreach (var set in setsSpared) { set.ConnectionInfo = "err:电缆无任一set被分配"; } } #endregion //in 和 out都会执行这个 bool AutoAssignCore(GlobalEnum.inOrOut inOrOut, List sets) { GlobalEnum.IOType ioTypeOnC = default; switch (cable.PreAssignIOType.ToLower()) { case "digital": //数字量 if (inOrOut == GlobalEnum.inOrOut.输入) { ioTypeOnC = GlobalEnum.IOType.DI; } else { ioTypeOnC = GlobalEnum.IOType.DO; } break; case "4~20ma": //模拟量4-20mA if (inOrOut == GlobalEnum.inOrOut.输入) { ioTypeOnC = GlobalEnum.IOType.AI; } else { ioTypeOnC = GlobalEnum.IOType.AO; } break; case "10v": ioTypeOnC = GlobalEnum.IOType.TenVolt; break; case "pt100": ioTypeOnC = GlobalEnum.IOType.PT100; break; case "pulse": ioTypeOnC = GlobalEnum.IOType.PULSE; break; default: //通讯类 485 422啥的 return false; } var matchedStrips = existedStrips.Where(x => x.IO_TYPE == ioTypeOnC.ToString()).ToList();//这个电缆下符合的模块 if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnC.ToString()) { //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 matchedStrips.Remove(lastUsedStrip); matchedStrips.Insert(0, lastUsedStrip);//??????? } if (matchedStrips == null || matchedStrips.Count == 0) { #region NewTS //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得 var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC); matchedStrips.Add(newTS); #endregion } string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称 if (sets.Count == 0) return false; //1.2 流程图 箱子里是否已经存在端子排(io匹配) List usedChs = new List(); List notUsedChs = new List(); #region 1.2 流程图 按规则先放几个信号进去(放不下就延到下一个模块) //if (cable.Sets.Count > 10) //{ // //另外如果电缆对数大于10对,即像12 * 2 * 0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道,如果不够4个就留4个以下即可。 // #region FindNextAvailableTS(可能多个) // //还分2种情况判断模块是否符合: // //case1,. 占满可用通道后,还剩至少一个预分配的set和spared的set。 //这种时候要spared不用考虑 // //case2,. 占满可用通道后(或者没占满通道,预分配set已经没了),只剩下spared的set。 //这种时候要确保spared也能放下 // bool NeedNextTS = false; // do // { // #region FindNextAvailableTS // var availableTS = new List(); // foreach (var TS in matchedStrips) // { // var allCh = TS.Channels; // //被占用的(wt里有或者信号里或有),或者被锁定的,都算占用 // usedChs = allCh.Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList(); // notUsedChs = allCh.Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList(); // if (notUsedChs.Count < sets.Count) // { // //case1,能顺利接完,set还有多 // //这种时候不需要考虑spared // } // else // { // //case2,占满可用通道后(或者没占满通道,预分配set已经没了),只剩下spared的set // //想办法留出4个 // //这种时候要确保spared也能放下 // if (notUsedChs.Count < sets.Count + setsSpared.Count) // { // //放不下,换下一个模块 // continue; // } // var sparedSetFor10 = notUsedChs.Count - sets.Count - setsSpared.Count;//16-9-5=2 // if (sparedSetFor10 > 4) // { // //固定流出后面4个,相当于不要了 // var last4 = allCh.Skip(allCh.Count - 4).ToList(); // usedChs = allCh.Take(allCh.Count - 4).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList(); // usedChs.AddRange(last4); // notUsedChs = allCh.Take(allCh.Count - 4).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList(); // } // else // { // //不够4个,就留多少是多少 // var lastN = allCh.Skip(allCh.Count - sparedSetFor10).ToList(); // usedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList(); // usedChs.AddRange(lastN); // notUsedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList(); // } // } // //1.2 流程图 空的通道数够不够 // double sparedRate = notUsedChs.Count * 1.0 / allCh.Count * 1.0; // if (sparedRate < 0.05) // { // //没有空闲通道 next // //或者空闲通道不够放下这个电缆的所有set // } // else // { // TS.Channels = allCh.OrderBy(X => X.Channel_Seq).ToList();//不能像之前一样过滤掉,否则下一个电缆进来时,总数就不对了。 // TS.ChannelsSpared = notUsedChs.Count; // TS.ChannelsUsed = usedChs.Count; // availableTS.Add(TS);//所有5%以上空闲通道的模块 // break; // } // } // #endregion // #region NewTS // if (availableTS.Count() == 0) // { // //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得 // var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC); // //matchedStrips.Add(newTS); // var allCh = newTS.Channels; // notUsedChs = newTS.Channels.ToList(); // newTS.ChannelsSpared = notUsedChs.Count; // newTS.ChannelsUsed = 0; // usedChs = new List();//新建的没有被占用的 // availableTS.Add(newTS); // if (notUsedChs.Count < sets.Count) // { // //case1,能顺利接完,set还有多 // //这种时候不需要考虑spared // } // else // { // //case2,占满可用通道后(或者没占满通道,预分配set已经没了),只剩下spared的set // //想办法留出4个 // //这种时候要确保spared也能放下 // if (notUsedChs.Count < sets.Count + setsSpared.Count) // { // //放不下,换下一个模块 // continue; // } // var sparedSetFor10 = notUsedChs.Count - sets.Count - setsSpared.Count;//16-9-5=2 // if (sparedSetFor10 > 4) // { // //固定流出后面4个,相当于不要了 // var last4 = allCh.Skip(allCh.Count - 4).ToList(); // usedChs = allCh.Take(allCh.Count - 4).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList(); // usedChs.AddRange(last4); // notUsedChs = allCh.Take(allCh.Count - 4).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList(); // } // else // { // //不够4个,就留多少是多少 // var lastN = allCh.Skip(allCh.Count - sparedSetFor10).ToList(); // usedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList(); // usedChs.AddRange(lastN); // notUsedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList(); // } // } // } // #endregion // lastUsedStrip = availableTS.Last(); // if (notUsedChs.Count < sets.Count) // { // //case1,分配完后,还有多的set和可能的spared // //先这部分填完 // //到5%为止的数量 // var countOnThisTS = Math.Round(0.5 + notUsedChs.Count * 0.95); // for (int i = 0; i < countOnThisTS; i++) // { // var set = sets[i]; // var ch = notUsedChs[i]; // if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2") // { // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}"; // } // else // { // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}"; // } // ch.FakeGroupDesc = set.PreAssignGroup_Desc; // ch.FakeSignalType = set.IOType.ToString(); // ch.lock_flg = 1; // set.IsConned = true; // //更新全局已使用通道 // allUsedCHBySignalOrSet.Add(ch.ChannelID); // } // //set会剩 // NeedNextTS = true; // } // else // { // //case2,分配完后,没有多的set了,可能还有spared // //上面已经判断过了,确保spared也是够的 // var countMin = Math.Min(sets.Count, notUsedChs.Count); // for (int i = 0; i < countMin; i++) // { // var set = sets[i]; // var ch = notUsedChs[i]; // if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2") // { // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}"; // } // else // { // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}"; // } // ch.FakeGroupDesc = set.PreAssignGroup_Desc; // ch.FakeSignalType = set.IOType.ToString(); // ch.lock_flg = 1; // set.IsConned = true; // //更新全局已使用通道 // allUsedCHBySignalOrSet.Add(ch.ChannelID); // } // #region spared // for (int i = 0; i < setsSpared.Count(); i++) // { // var set = setsSpared[i]; // var ch = notUsedChs[countMin + i]; // if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2") // { // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余"; // } // else // { // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余"; // } // ch.FakeGroupDesc = "预留"; // ch.lock_flg = 1; // //更新全局已使用通道 // allUsedCHBySignalOrSet.Add(ch.ChannelID); // } // NeedNextTS = false; // #endregion // } // sets = sets.Where(x => !x.IsConned).ToList();//移除已经分配过的set // } while (NeedNextTS); // #endregion //} //else //{ //5%的空白通道 #region FindNextAvailableTS(可能多个) //还分2种情况判断模块是否符合: //case1,. 占满可用通道后,还剩至少一个预分配的set和spared的set。 //这种时候要spared不用考虑 //case2,. 占满可用通道后(或者没占满通道,预分配set已经没了),只剩下spared的set。 //这种时候要确保spared也能放下 //case3, 刚好,只有spared可能多 bool NeedNextTS = false; #region FindNextAvailableTS int idx = 0; while (idx < matchedStrips.Count) { NeedNextTS = false; var TS = matchedStrips[idx]; var allCh = TS.Channels; var allChCount = allCh.Count; if (allChCount == 0) { NeedNextTS = true; //同时又是最后一个了 if (idx == matchedStrips.Count - 1) { var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC); if (newTS.Channels.Count() < setsSpared.Count + 1)//1代表至少要放一个set { //有问题了 panel的io模板,估计会导致无限循环了 break; } matchedStrips.Add(newTS); } idx++; continue;//本模块没有一个ch } //被占用的(wt里有或者信号里或有),或者被锁定的,都算占用 usedChs = allCh.Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList(); notUsedChs = allCh.Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList(); var ChNeedConn = 0; var SparedNeedConn = 0; if (cable.CableClass.ToLower() == SWS.Share.Enum.cableClass.homerun.ToString()) { //1.2.3(2)如果模块是通讯信号(像RS485这种就是通讯信号),则不用管预留空白通道这个事情,看到有空的通道就放。 if (allChCount < sets.Count) { //case1,能顺利接完,set还有多,还要再do循环一次,多余的set和spared都要放到下一个模块 NeedNextTS = true; ChNeedConn = allChCount; SparedNeedConn = 0; } else if (allChCount == sets.Count) { //case3,刚好,只有spared可能多 ChNeedConn = allChCount; SparedNeedConn = 0; //homerun不用考虑预留一个set去配合后续的spared } else { ChNeedConn = sets.Count; SparedNeedConn = 0; } } else { //1.2 流程图 空的通道数够不够 double sparedRate = notUsedChs.Count * 1.0 / allChCount * 1.0; if (sparedRate < 0.05) { NeedNextTS = true; //同时又是最后一个了 if (idx == matchedStrips.Count - 1) { var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC); if (newTS.Channels.Count() < setsSpared.Count + 1)//1代表至少要放一个set { //有问题了 panel的io模板,估计会导致无限循环了 break; } matchedStrips.Add(newTS); } idx++; continue;//本模块可用的模块小于5% } //没有空闲通道 next //或者空闲通道不够放下这个电缆的所有set //算一下5%是多少个通道 var trueAvailableChs = notUsedChs.Count - (allChCount - FindMaxNumberChannel(allChCount));//真正能用的(没接过的,然后去掉5%) if (trueAvailableChs < sets.Count) { //case1,能顺利接完,set还有多,还要再do循环一次,多余的set和spared都要放到下一个模块 NeedNextTS = true; ChNeedConn = trueAvailableChs; SparedNeedConn = 0; } else if (trueAvailableChs == sets.Count) { //case3,刚好,只有spared可能多 if (setsSpared.Count > 0) { //自己的感觉(非客户word需求里的原话):spared不能自己单独占用一个模块 NeedNextTS = true; ChNeedConn = trueAvailableChs - 1;//留一个给spared SparedNeedConn = 0; } else { ChNeedConn = trueAvailableChs; SparedNeedConn = 0; } } else { //maxCh > sets.Count //case2,占满可用通道后(或者没占满通道,预分配set已经没了),只剩下spared的set if (setsSpared.Count == 0) { //ok ChNeedConn = sets.Count; SparedNeedConn = 0; } //这种时候要确保spared也能放下 else if (trueAvailableChs < sets.Count + setsSpared.Count) { //自己的感觉(非客户word需求里的原话):spared不能自己单独占用一个模块 ChNeedConn = sets.Count - 1;//留一个给spared NeedNextTS = true; SparedNeedConn = 0; } else { //ok,set和spared都能放下 ChNeedConn = sets.Count; SparedNeedConn = setsSpared.Count; } } } //到这里,说明本模块至少都是可用的 TS.Channels = allCh.OrderBy(X => X.Channel_Seq).ToList();//不能像之前一样过滤掉,否则下一个电缆进来时,总数就不对了。 lastUsedStrip = TS; #region conn for (int i = 0; i < ChNeedConn; i++) { var set = sets[i]; var ch = notUsedChs[i]; if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2") { set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}"; } else { set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}"; } ch.FakeGroupDesc = set.PreAssignGroup_Desc; ch.FakeSignalType = set.IOType.ToString(); ch.lock_flg = 1; set.IsConned = true; //更新全局已使用通道 allUsedCHBySignalOrSet.Add(ch.ChannelID); } #endregion #region spared for (int i = 0; i < SparedNeedConn; i++) { var set = setsSpared[i]; var ch = notUsedChs[ChNeedConn + i]; if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2") { set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余"; } else { set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余"; } ch.lock_flg = 1; //更新全局已使用通道 allUsedCHBySignalOrSet.Add(ch.ChannelID); } #endregion //shi否要继续 TS.ChannelsSpared = notUsedChs.Where(x => x.lock_flg != 1).Count(); TS.ChannelsUsed = allChCount - TS.ChannelsSpared;// usedChs.Count + (notUsedChs.Where(x => x.lock_flg == 1).Count()); if (NeedNextTS) { sets = sets.Where(x => !x.IsConned ?? false).ToList();//移除已经分配过的set //同时又是最后一个了 if (idx == matchedStrips.Count - 1) { var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC); if (newTS.Channels.Count() < setsSpared.Count + 1)//1代表至少要放一个set { //有问题了 panel的io模板,估计会导致无限循环了 break; } matchedStrips.Add(newTS); } idx++; continue;// 需要下一个模块接着放本电缆 // 手动递增索引,避免无限循环 } else { break; } } #endregion #endregion //} #endregion return true; } } } return Success(cablesNeedAssigned); } /// /// 找到满足5%空闲通道的最大数 /// /// 模块的所有通道数 /// /// /// static int FindMaxNumberChannel(int ChCount) { if (ChCount < 1) { throw new ArgumentException("模块数量必须大于等于1", nameof(ChCount)); } // 从A-1开始向下寻找 for (int i = 0; i < ChCount; i++) { // 检查是否大于5% if ((double)i / ChCount < 0.05 && (double)(i + 1) / ChCount > 0.05) { return ChCount - i; } } return ChCount; } /// /// 根据step2的预分配结果,进行实际的分配,修改数据库。 /// /// /// 传入有效的cable即可,未成功分配的cable不需要 /// [HttpPost] public IHttpActionResult AutoAssignCable2Channel_step3(string projId, [FromBody] List cables) { //大原则:同一根电缆的信号不能跨采集箱,跨模块可以。 return Success(cables); } /// /// 把电缆分配到空余的模块的通道上。 /// /// /// /// [HttpPost] public IHttpActionResult AssignCable2Channel(string projId, bool execute = false) { var asyncContent = Request.Content.ReadAsStringAsync().Result; var cableIds = asyncContent.ToObject>(); return Success("res"); } /// /// 查询所有需要预分配的电缆 /// /// /// [HttpGet] public IHttpActionResult GetCablePreAssignPreview(string projId) { var bll = new ec_CableBLL(); var res = bll.GetCablesPreAssign(projId, null); return Success(res); } /// /// 查询所有的电缆 /// /// /// true或false /// [HttpGet] public IHttpActionResult GetCables(string projId, bool homerun = true) { var res = ec_CableBLL.GetCables(projId, homerun);//这有个问题 如果一开始不知道要关联到那个通道 就不会有ec cable出来 return Success(res); } /// /// PanelStrip参考库 /// /// /// false时,带上下面的通道和端子。true时,就是返回端子排自己 /// [HttpGet] public IHttpActionResult GetPanelStrips(string projId, bool OnlySelf = false) { var res = ec_PanelStripBLL.GetList("{ProjectId:\"" + projId + "\",OnlySelf:\"" + OnlySelf + "\"}"); return Success(res); } /// /// 在IO分配界面,从左侧目录树中选择一个“端子排”后,进行查询 /// /// /// /// false时,带上下面的通道和端子。true时,就是返回端子排自己 /// [HttpGet] public IHttpActionResult GetPanelStrip(string StripID, string projId, bool OnlySelf = false, bool HaveChannel = true) { var res = ec_PanelStripBLL.GetEntity(projId, StripID, OnlySelf, HaveChannel); return Success(res); } /// /// 新增或者修改。 /// 新建相当于强行,因为正常流程是和engineerdata一起新建出来的。 /// 改的话,只是改location和端子排数量这些。常规属性依旧通过objectTypeAPI去做 /// /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SavePanel(ec_PanelEntity entity, string projId) { try { ec_PanelBLL.SaveEntity(projId, entity.PanelID, entity); return Success("OK"); } catch (System.Exception E) { return Fail(E.Message); } } /// /// SaveConnections 专用 /// private class Connections { public string ID { get; set; } public List Conns { get; set; } } /// /// 处理 接线关系,同时对cableset和wire的个别属性进行修改 /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SaveConnections(string projId) { try { var asyncContent = Request.Content.ReadAsStringAsync().Result; var entity = asyncContent.ToObject(); var res = entity.Conns; new ec_WireTerminalBLL().SaveConnections(projId, ref res); return Success(res); } catch (System.Exception E) { return Fail(E.Message); } } /// /// /// /// /// [HttpGet] public IHttpActionResult GetConnections(string projId, string ID) { try { var res = new ec_WireTerminalService().GetEntity(projId, ID); return Success(res); } catch (System.Exception E) { return Fail(E.Message); } } /// /// /// /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SaveCable(ec_CableEntity entity, string projId) { try { if (!string.IsNullOrEmpty(entity.CableID)) { ec_CableBLL.SaveEntity(projId, entity.CableID, entity); } return Success("OK"); } catch (System.Exception E) { return Fail(E.Message); } } /// /// 通过预设模式,批量创建端子排 通道 端子。此时strip数里 set数里已经根据profile给定好了。 /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult CreatePanelStripByProfile(string projId) { try { var asyncContent = Request.Content.ReadAsStringAsync().Result; var entity = asyncContent.ToObject(); string NewID = ""; ec_PanelStripBLL.SaveEntity(projId, "", entity, out NewID); var res = ec_PanelStripBLL.GetEntity(projId, NewID); return Success(res); } catch (System.Exception e) { return Fail(e.Message); } } ///// ///// 通过预设模式,批量创建端子排 端子(不需要了,因为预设模式只有对IO有通道的那边才有用) ///// ///// ///// //[HttpPost] //[HandlerApiLogin(FilterMode.Enforce)] //public IHttpActionResult CreatePanelStripByProfileNoChannel(string projId, ec_PanelStripEntity entity) //{ // try // { // string NewID = ""; // ec_PanelStripBLL.SaveEntity(projId, "", entity, out NewID, false); // var res = ec_PanelStripBLL.GetEntity(projId, NewID); // return Success(res); // } // catch (System.Exception e) // { // return Fail(e.Message); // } //} /// /// GetCableByEngID先去判断这个cable是否已经有了IO Module这边的记录 /// 电缆-端子连接,从图面上选择一个电缆对象 /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult CreateCableByProfile(string projId) { try { var asyncContent = Request.Content.ReadAsStringAsync().Result; var entity = asyncContent.ToObject(); ec_CableBLL.SaveEntity(projId, entity.CableID, entity); var res = ec_CableBLL.GetCableByEngID(projId, entity.EngineerDataID); return Success(res); } catch (System.Exception e) { return Fail(e.Message); } } /// /// 批量保存电缆的set wire 名字等 /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SaveCables(string projId) { try { var asyncContent = Request.Content.ReadAsStringAsync().Result; var entitys = asyncContent.ToObject>(); foreach (var entity in entitys) { ec_CableBLL.SaveEntity(projId, entity.CableID, entity); } return Success(entitys); } catch (System.Exception e) { return Fail(e.Message); } } /// /// 创建、修改 端子排和端子(一般是为非监测设备的端子排) /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SavePanelStripNoChannel(string projId, ec_PanelStripEntity entity) { try { string NewID = ""; ec_PanelStripBLL.SaveEntity(projId, entity.StripID, entity, out NewID, false); var res = ec_PanelStripBLL.GetEntity(projId, NewID, false, false); return Success(res); } catch (System.Exception e) { return Fail(e.Message); } } /// /// 保存端子排 通道 端子的信息(不管信号和接线关系)。 /// 迁移通道也是这里。 /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SavePanelStrip(string projId, ec_PanelStripEntity entity) { XmlConfigurator.Configure(); var log = log4net.LogManager.GetLogger("Debug"); //参数就是config里logger节点的名字 try { //var asyncContent = Request.Content.ReadAsStringAsync().Result; //var entity = asyncContent.ToObject(); ec_PanelStripBLL.SaveEntity(projId, entity.StripID, entity, out string NewID); var res = ec_PanelStripBLL.GetEntity(projId, NewID); return Success(res); } catch (System.Exception e) { log.Debug($"★★★{DateTime.Now.ToString()}★★★{e}★★★"); return Fail(e.Message); } } /// /// /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SavePanelStripTerm(ec_PanelStripTermEntity entity, string projId) { try { ec_PanelStripTermBLL.SaveEntity(projId, entity.TermID, entity); return Success("OK"); } catch (System.Exception e) { return Fail(e.Message); } } /// /// /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SavePanelChannel(ec_PanelChannelEntity entity, string projId) { try { var newId = ec_PanelChannelBLL.SaveEntity(projId, entity.ChannelID, entity); foreach (var term in entity.Terms) { ec_PanelStripTermBLL.SaveEntity(projId, term.TermID, term); } var res = ec_PanelChannelBLL.GetEntity(projId, newId); return Success(res); } catch (System.Exception e) { return Fail(e.Message); } } /// /// 调端子排所属Panel /// /// 端子排ID /// PanelID /// 项目ID [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SwitchPanelStrip(string StripID, string PanelID, string ProjectId) { try { ec_PanelStripBLL.SwitchPanelStrip(StripID, PanelID, ProjectId); return Success("OK"); } catch (System.Exception e) { return Fail(e.Message); } } /// /// 调换电缆的from/to信息 /// /// Cable的工程ID /// 项目ID [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SwitchCableFromTo(string ProjectId) { try { var asyncContent = Request.Content.ReadAsStringAsync().Result; var entityCol = asyncContent.ToObject>(); var res = new ec_enginedata_relService().SwitchCableFromTo(entityCol, ProjectId); if (res) { return Success("OK"); } else { return Fail("From/To 交换出现问题。"); } } catch (System.Exception e) { return Fail(e.Message); } } /// /// 比如 移动通道时,进行保存 /// /// /// /// [Obsolete] [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult SavePanelChannels(List entitys, string projId) { try { foreach (var entity in entitys) { var newId = ec_PanelChannelBLL.SaveEntity(projId, entity.ChannelID, entity); foreach (var term in entity.Terms) { ec_PanelStripTermBLL.SaveEntity(projId, term.TermID, term); } } return Success("OK"); } catch (System.Exception e) { return Fail(e.Message); } } /// /// 根据某个数据字典的编号来。默认有个id=1的枚举 /// /// /// private List GetLocList(string ProjectId) { var ec_dataitemBLL = new ec_dataitemBLL(); var settings = new ec_projectSettingsBLL(); var ListFlg = settings.GetEntity(GlobalObject.projSetting_enumlist_IORackPosition, ProjectId); if (ListFlg != null) { List frameLists = new List(); frameLists.Add(new ec_dataitemdetailEntity() { DataItemName = "默认", DataItemCode = "默认", DataItemDetailID = "1", UpDataItemDetailID = "", DataItemID = "" }); //{ Name = "默认", Desc = "默认", Id = "1", ParentID = "" }); var ListName = ec_dataitemBLL.GetList("{ProjectId:\"" + ProjectId + "\",keyword:\"" + ListFlg.SettingValue + "\"}").FirstOrDefault(); if (ListName == null) { return null; } else { frameLists[0].DataItemID = ListName.DataItemID; } var res = ec_dataitemBLL.GetDetailList(ListFlg.SettingValue, "", ProjectId, false); //区域 foreach (var item in res) { //frameLists.Add(new ec_dataitemdetailEntity() //{ // Name = item.DataItemName, // ParentID = item.UpDataItemDetailID, // Desc = item.DataItemCode, // Id = item.DataItemDetailID, // DataItemId = item.DataItemID //}); frameLists.Add(item); } return frameLists; } else { return null; } } /// /// 位置。缺省都放到“默认”下 /// /// /// [HttpGet] public IHttpActionResult GetLocationList(string ProjectId) { var RES = GetLocList(ProjectId); if (RES != null) { return Success(RES); } else { return Fail("未找到合适的数据字典,可以当做位置"); } } /// /// 根据id来删除 /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult DeletePanel(string PanelID, string ProjectId) { new ec_enginedataBLL().DeleteEntity(PanelID, ProjectId); return Success("删除成功!"); } /// /// 根据id来删除 /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult DeleteCableProfile(string CableID, string ProjectId) { ec_CableBLL.DeleteEntity(ProjectId, CableID); return Success("OK"); } /// /// 根据id来删除 /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult DeletePanelStrip(string StripID, string ProjectId) { ec_PanelStripBLL.DeleteEntity(ProjectId, StripID); return Success("删除成功!"); } /// /// 根据id来删除 /// /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] public IHttpActionResult DeletePanelChannel(string ChannelID, string ProjectId) { ec_PanelChannelBLL.DeleteEntity(ProjectId, ChannelID); return Success("OK"); } } /// /// /// //public class Panel_Location //{ /// /// /// //public string ParentID { get; set; } /// /// /// //public string Id { set; get; } /// /// 所在数据字典的ID /// // public string DataItemId { set; get; } /// /// /// //public string Name { get; set; } /// /// 数据字典里的code /// //public string Desc { get; set; } //} }