From 2e665e9f3d652cc306f545046069c2e1e49294f2 Mon Sep 17 00:00:00 2001 From: xingheng Date: Mon, 22 Sep 2025 15:44:15 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=86=E9=85=8D?= =?UTF-8?q?=EF=BC=88=E5=B0=B1=E8=BF=91=E6=89=BE=E9=87=87=E9=9B=86=E7=AE=B1?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=AE=8C=E6=88=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppApi/IOModuleApiController.cs | 74 ++++++----- .../ZZDT_EC/ec_cable/ec_CableBLL.cs | 119 ++++++++++-------- .../ZZDT_EC/ec_cable/ec_CableEntity.cs | 3 +- 3 files changed, 113 insertions(+), 83 deletions(-) diff --git a/Learun.Application.Web/AppApi/IOModuleApiController.cs b/Learun.Application.Web/AppApi/IOModuleApiController.cs index 95e49413..8582a605 100644 --- a/Learun.Application.Web/AppApi/IOModuleApiController.cs +++ b/Learun.Application.Web/AppApi/IOModuleApiController.cs @@ -1,4 +1,5 @@ using DocumentFormat.OpenXml.Drawing.Spreadsheet; +using DocumentFormat.OpenXml.Spreadsheet; using Learun.Application.Organization; using Learun.Application.TwoDevelopment.ZZDT_EC; using Learun.Application.TwoDevelopment.ZZDT_EC.Frame; @@ -47,7 +48,7 @@ namespace Learun.Application.Web.AppApi /// - /// 找到某一个预分配箱子 附近的某一个箱子 + /// 找到某一个预分配箱子 附近的某一个箱子。且io类型能匹配上 /// /// /// @@ -55,9 +56,10 @@ namespace Learun.Application.Web.AppApi /// Digital,4-20mA,10v,pt100,pulse /// - private ec_PanelEntity FindPanelNearby(string curPanelId, List frameLists, List allPanel, + 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); @@ -88,7 +90,7 @@ namespace Learun.Application.Web.AppApi return -1;//无效的x off导致的 } if (double.TryParse(nearPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_YOff)?.PropertyValue, - , out double YOffValue)) + out double YOffValue)) { } @@ -129,7 +131,7 @@ namespace Learun.Application.Web.AppApi return null;//无效的x off导致的 } if (double.TryParse(curPanelProps.FirstOrDefault(x => x.PropertyName == GlobalObject.propName_YOff)?.PropertyValue, -, out double AssignPanelYValue)) + out double AssignPanelYValue)) { } @@ -141,33 +143,49 @@ namespace Learun.Application.Web.AppApi 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); - #endregion - #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; + 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); - } - //根据电缆上的信号,去找匹配的排序第一位(已经按照距离排序过)的箱子 - switch (IOTypeOnCable.ToUpper()) - { - case "DIGITAL": - //其他就近箱子的 allowIOTypes里有DI DO - break; - default: - break; - } + if (0.1 == minDistance && DISTANCE > 0) + { + minDistance = DISTANCE; nearestPanel = panel; + } + else if (DISTANCE < minDistance && DISTANCE > 0) + { + minDistance = DISTANCE; nearestPanel = panel; + } + #endregion + } + + + } return nearestPanel; } @@ -421,7 +439,7 @@ namespace Learun.Application.Web.AppApi bool nearbyFound = false; foreach (var cable in cablesNotMatchIO) { - var nearPanel = FindPanelNearby(cable.PanelID, allFrames, allPanel, allPanelProp, cable.PreAssignIOType); + var nearPanel = FindPanelNearby(cable, allFrames, allPanel, allPanelProp, cable.PreAssignIOType); if (nearPanel == null) { nearbyFound = false; diff --git a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs index 46cc3663..b79e078b 100644 --- a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs +++ b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs @@ -1,4 +1,5 @@ using DocumentFormat.OpenXml.Drawing.Spreadsheet; +using DocumentFormat.OpenXml.Spreadsheet; using Learun.Util; using Learun.Util.SqlSugar; using SqlSugar; @@ -7,6 +8,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data; using System.Linq; +using System.Windows; namespace Learun.Application.TwoDevelopment.ZZDT_EC { @@ -314,70 +316,27 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC foreach (var set in sets) { #region 判断下io匹配程度 - if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输入.ToString() && cable.PreAssignIOType.ToLower() == "digital") + var setNew = SetIOMatchPanel(cable.PreAssignIOType, set, IOsOnPanel); + + if (IOsOnPanel.Contains(setNew.IOType.ToString())) { - set.IOType = GlobalEnum.IOType.DI; - } - else if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输出.ToString() && cable.PreAssignIOType.ToLower() == "digital") - { - set.IOType = GlobalEnum.IOType.DO; - } - else if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输入.ToString() && cable.PreAssignIOType == "4~20mA") - { - set.IOType = GlobalEnum.IOType.AI; - } - else if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输出.ToString() && cable.PreAssignIOType == "4~20mA") - { - set.IOType = GlobalEnum.IOType.AO; - } - else if (cable.PreAssignIOType == "10v") - { - set.IOType = GlobalEnum.IOType.TenVolt; - } - else if (cable.PreAssignIOType == GlobalEnum.signalType.PT100.ToString()) - { - set.IOType = GlobalEnum.IOType.PT100; - } - else if (cable.PreAssignIOType.ToUpper() == GlobalEnum.signalType.PULSE.ToString()) - { - set.IOType = GlobalEnum.IOType.PULSE; - } - else if (cable.PreAssignIOType == GlobalEnum.signalType.PT100.ToString()) - { - set.IOType = GlobalEnum.IOType.PT100; - } - //下面是通讯的 - else - { - - } - - if (IOsOnPanel.Contains(set.IOType.ToString())) - { - set.IOTypeMatch = true; + setNew.IOTypeMatch = true; } else { - set.IOTypeMatch = false; - cable.IOTypesNotMatchedList.Add(set.IOType.ToString());//从电缆上就能知道哪些io是匹配补上的 + setNew.IOTypeMatch = false; + cable.IOTypesNotMatchedList.Add(setNew.IOType.ToString());//从电缆上就能知道哪些io是匹配补上的 } #endregion - var wires = Wires.Where(x => x.CableSetID == set.CableSetID); - set.Wires = wires.ToList(); + var wires = Wires.Where(x => x.CableSetID == setNew.CableSetID); + setNew.Wires = wires.ToList(); + cable.Sets.Add(setNew); } - cable.Sets = sets; - //if (cable.Sets.Any(x => !x.IOTypeMatch)) - //{ - // cable.IOTypeMatch = true; - //} - //else - //{ - // cable.IOTypeMatch = false; - //} + //cable.Sets = sets; } - //分组 + //排序 preAssignedCables = preAssignedCables.OrderBy(x => x.PreAssignIOType).ToList(); @@ -397,7 +356,59 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC else { ec_CableService.DeleteEntity(ProjectId, CableID); } } + /// + /// 预分配的电缆上的io,是否和电缆上的io能匹配 + /// + /// + public static ec_CableSetEntity SetIOMatchPanel(string signalOnCable, ec_CableSetEntity set, List IOsOnPanel) + { + //var IOsOnPanel = panelObj.allowedIOTypes.Split(',').ToList(); + //剩下的感觉都可以是set上的参数? + + + #region 判断下io匹配程度 + if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输入.ToString() && signalOnCable.ToLower() == "digital") + { + set.IOType = GlobalEnum.IOType.DI; + } + else if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输出.ToString() && signalOnCable.ToLower() == "digital") + { + set.IOType = GlobalEnum.IOType.DO; + } + else if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输入.ToString() && signalOnCable == "4~20mA") + { + set.IOType = GlobalEnum.IOType.AI; + } + else if (set.PreAssignInOrOut == GlobalEnum.inOrOut.输出.ToString() && signalOnCable == "4~20mA") + { + set.IOType = GlobalEnum.IOType.AO; + } + else if (signalOnCable == "10v") + { + set.IOType = GlobalEnum.IOType.TenVolt; + } + else if (signalOnCable == GlobalEnum.signalType.PT100.ToString()) + { + set.IOType = GlobalEnum.IOType.PT100; + } + else if (signalOnCable.ToUpper() == GlobalEnum.signalType.PULSE.ToString()) + { + set.IOType = GlobalEnum.IOType.PULSE; + } + else if (signalOnCable == GlobalEnum.signalType.PT100.ToString()) + { + set.IOType = GlobalEnum.IOType.PT100; + } + //下面是通讯的 + else + { + } + + #endregion + + return set; + } /// /// 保存实体数据(新增、修改) /// 主键 diff --git a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs index bea6c0f0..f9bf1f49 100644 --- a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs +++ b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs @@ -147,7 +147,8 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC /// - /// From连接处的工程位号信息。同时,也表达下预分配电缆panelid对应的柜子信息。 + /// From连接处的工程位号信息。 + /// 同时,也表达下预分配电缆panelid对应的柜子信息。 /// [SugarColumn(IsIgnore = true)] public ec_PanelEntity ToPanel { set; get; } From 6f194c726a63424060616b002841612086cdd927 Mon Sep 17 00:00:00 2001 From: xingheng Date: Wed, 24 Sep 2025 18:39:10 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BA=86=E8=87=AA=E5=8A=A8=E5=88=86=E9=85=8D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppApi/IOModuleApiController.cs | 323 ++++++++++++++---- .../AppApi/PlotLayoutApiController.cs | 2 +- .../ZZDT_EC/ec_cable/ec_CableBLL.cs | 2 +- .../ZZDT_EC/ec_cable/ec_CableEntity.cs | 13 +- ...signTimeResolveAssemblyReferencesInput.cache | Bin 5422 -> 5543 bytes .../Debug/Views/DialogAutoArrangeLayout.g.cs | 159 --------- .../obj/Debug/Views/DialogTest2.g.cs | 125 ------- .../obj/Debug/Views/SWSDialogWindow.g.cs | 39 +++ .../obj/Debug/Views/SWSDialogWindow.g.i.cs | 39 +++ newFront/c#前端/SWS.Share/ConstString.cs | 13 + newFront/c#前端/SWS.Share/Enum.cs | 22 ++ newFront/c#前端/SWS.Share/SWS.Share.csproj | 2 + .../obj/Debug/Views/CustomDialogWindow.g.cs | 24 ++ .../obj/Debug/Views/CustomDialogWindow.g.i.cs | 24 ++ 14 files changed, 431 insertions(+), 356 deletions(-) delete mode 100644 newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogAutoArrangeLayout.g.cs delete mode 100644 newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogTest2.g.cs create mode 100644 newFront/c#前端/SWS.Share/ConstString.cs create mode 100644 newFront/c#前端/SWS.Share/Enum.cs diff --git a/Learun.Application.Web/AppApi/IOModuleApiController.cs b/Learun.Application.Web/AppApi/IOModuleApiController.cs index b21f47ae..ad0ae97d 100644 --- a/Learun.Application.Web/AppApi/IOModuleApiController.cs +++ b/Learun.Application.Web/AppApi/IOModuleApiController.cs @@ -45,8 +45,16 @@ namespace Learun.Application.Web.AppApi #endregion - - + /// + /// 根据模板自动创建端子排 + /// + /// + /// + /// + private ec_PanelStripEntity CreatePanelStripByProfile2(string projId, string TSname, string panelId, GlobalEnum.IOType iOType) + { + return new ec_PanelStripEntity(); + } /// /// 找到某一个预分配箱子 附近的某一个箱子。且io类型能匹配上 /// @@ -185,7 +193,7 @@ namespace Learun.Application.Web.AppApi } - } + } return nearestPanel; } @@ -436,27 +444,25 @@ namespace Learun.Application.Web.AppApi { //有不匹配的,但是用户允许继续 //如果选是,则在之后的自动分配过程中会自动寻找匹配的采集箱,原则上从就近的开始找,如果没有匹配的采集箱,则提示“未找到具有XX类型的采集箱,请新增后再次分配,是否取消自动分配进程?” - bool nearbyFound = false; + foreach (var cable in cablesNotMatchIO) { var nearPanel = FindPanelNearby(cable, allFrames, allPanel, allPanelProp, cable.PreAssignIOType); - if (nearPanel == null) - { - nearbyFound = false; - //必要的数据存入redis,以便后续步骤使用 - redisObj.Remove("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch); - redisObj.Write>("IOModule_AutoAssign2Ch_" + projId, cablesNeedAssigned, CacheId.IOModule_AutoAssign2Ch); - return Fail($"在附近未找到具有{cable.PreAssignIOType}类型的采集箱,请新增后再次分配,是否取消自动分配进程?"); - //之后插件端进行选择。 - //如果不想新增,则选择否,继续自动分配,没有分配到的信号在备注上填写由于何种原因没有被分配,弹出未被分配的信号列表供查看。 - //也就是这里要等所有循环结束后才能return结果,而不是目前一个nearByFound = false时就退出了。 - } - else - { - nearbyFound = true; - } - } + 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时就退出了。 + } } @@ -501,64 +507,252 @@ namespace Learun.Application.Web.AppApi ICache redisObj = CacheFactory.CaChe(); var cablesNeedAssigned = redisObj.Read>("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch); - //#region 1.2 开始自动分配(不保存到数据库) - #region 先分组 1.2.2 - var cablesGrouped = cablesNeedAssigned.OrderBy(x => x.PanelID).ThenBy(x => x.PreAssignIOType).ThenBy(x => x.System).ToList(); + var setTb = ProjectSugar.TableName(projId); + var allSettings = SqlSugarHelper.Db.Queryable().AS(setTb).ToList(); + //IO_CardProfile - foreach (var item in cablesNeedAssigned) + var signalTb = ProjectSugar.TableName(projId); + var allSignals = SqlSugarHelper.Db.Queryable().AS(signalTb).ToList(); + var allUsedCH = allSignals.Where(x => !string.IsNullOrEmpty(x.ChannelID)).Select(x => x.ChannelID).Distinct().ToList(); + + //1.2 流程图 分组原则为同一信号类型、同一系统的为一组 + var cablesGrouped = cablesNeedAssigned.OrderBy(x => x.PanelID).ThenBy(x => x.PreAssignIOType).ThenBy(x => x.System).ToList(); + 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.PanelID).Distinct(); + 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()); + //感觉逻辑上用panel来循环会更合理 + foreach (var curPanelId in allPanelIds) { - if (item.Sets == null || item.Sets.Count() == 0) + int newTSSeq = 10001; + + var curStrips = allStrips[curPanelId]; + var cablesOnThisPanel = cablesGrouped.Where(x => x.PanelID == curPanelId).ToList(); + if (cablesOnThisPanel == null || cablesOnThisPanel.Count == 0) { - //也归类到未成功 + continue;//next panel } - else + //var lastCableSystemAndIOType = cablesOnThisPanel.First().System + cablesOnThisPanel.First().PreAssignIOType;//用于判断是否是同一个组 + var lastUsedStrip = (ec_PanelStripEntity)null; + foreach (var cable in cablesOnThisPanel) { - foreach (var set in item.Sets) + //1.2.2 分组原则为同一信号类型、同一系统的为一组,系统属性从电缆的from端上的设备中取设备的系统,同组的优先放到同一个箱子的同一个模块里面, + //如果一组放完后发现模块还有多余的通道可以放则下一个系统继续从这个模块开始分配。 + //???总感觉这句话,总结后:可以无脑用上一个模块,直到模块满了再用下一个模块。 + #region 判断是否是同一组 + //bool sameGroup = true; + //if (lastCableSystemAndIOType != cable.System + cable.PreAssignIOType) + //{ + // sameGroup = false;//换组了 + //} + #endregion + //1.2 流程图 读取有提前选好箱子的信号 + GlobalEnum.IOType ioTypeOnCable = default; + var setsSpared = cable.Sets.Where(x => string.IsNullOrEmpty(x.PreAssignGroup_Desc) || string.IsNullOrEmpty(x.PreAssignInOrOut)).ToList(); + var setsIn = cable.Sets.Where(x => x.PreAssignInOrOut == SWS.Share.Enum.inOrOut.输入.ToString()).ToList(); + var setsOut = cable.Sets.Where(x => x.PreAssignInOrOut == SWS.Share.Enum.inOrOut.输出.ToString()).ToList(); + + #region 1.2.4 同一根电缆,如果带公共端的报警信号,必须接到一个模块里面 + if (cable.PreAssignIOType.ToLower() == GlobalEnum.signalType.Digital.ToString().ToLower()) { - set.ConnectionInfo = $"采集箱:{item.ToPanel.TagNumber}/模块(端子排):{"test_ts"}/通道:{"test_ch"}"; - set.AssignedTerms = set.Wires.Select(x => x.PreAssignChannelTermNo).ToList();// new List() { "test_term1", "test_term2" };//假数据 + + if (setsIn.Count > 0 && setsOut.Count > 0) + { + //from cjj 25 09 23 wechat:一根电缆可能会出现既有输入也有输出,如果碰到就放到两个端子排里面,公共端不会出现一个输出,一个输入的 + continue; + } + //todo } + #endregion + + #region input + ec_PanelStripEntity curStrip = null; + var matchedStrips = curStrips.Where(x => x.IO_TYPE == ioTypeOnCable.ToString()).ToList(); + if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnCable.ToString()) + { + //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 + matchedStrips.Insert(0, lastUsedStrip); + } + if (setsIn.Count + setsSpared.Count() > 10) + { + //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 + //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, + //如果不够4个就留4个以下即可。 + } + else + { + string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称 + switch (cable.PreAssignIOType.ToLower()) + { + case "digital": + //数字量 + ioTypeOnCable = GlobalEnum.IOType.DI; + break; + case "4~20ma": + //模拟量4-20mA + ioTypeOnCable = GlobalEnum.IOType.AI; + break; + case "10v": + ioTypeOnCable = GlobalEnum.IOType.TenVolt; + break; + case "pt100": + ioTypeOnCable = GlobalEnum.IOType.PT100; + break; + case "pulse": + ioTypeOnCable = GlobalEnum.IOType.PULSE; + break; + default: + //通讯类 485 422啥的 + continue; + break; + } + + //1.2 流程图 箱子里是否已经存在端子排(io匹配) + + bool alreadyInsertNewTs = false; + if (matchedStrips == null || matchedStrips.Count == 0) + { + //没有端子排 + //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得 + var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + alreadyInsertNewTs = true; + matchedStrips.Add(newTS); + } + + #region 1.2 流程图 空的通道数够不够 + if (cable.CableClass == SWS.Share.Enum.cableClass.homerun.ToString()) + { + //1.2.3(2)如果模块是通讯信号(像RS485这种就是通讯信号),则不用管预留空白通道这个事情,看到有空的通道就放。 + //当前这个端子排就是可用的 + + curStrip = matchedStrips.First(); + + + } + else + { + //1.2.3 (1) 非通讯,如果空的通道大于整个模块的5%,则可以利用,利用到小于5%了则停止利用,如果本身空通道数占的比例就小于5%,则不利用。 + + curStrip = FindNextAvailableTS(matchedStrips, allUsedCH); + + if (curStrip == null) + { + var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + alreadyInsertNewTs = true; + matchedStrips.Add(newTS); + curStrip = newTS; + + } + } + var usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + var notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + #endregion + #region 1.2 流程图 按规则先放几个信号进去 + if (notUsedChs.Count < setsIn.Count + setsSpared.Count()) + { + //不够放,又要新建? + if (alreadyInsertNewTs) + { + //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 + continue; + } + else + { + //相当于前面5%的判断过了,但是呢放不下所有需要的set + var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + alreadyInsertNewTs = true; + matchedStrips.Add(newTS); + curStrip = newTS; + usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + if (notUsedChs.Count < setsIn.Count + setsSpared.Count()) + { + //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 + continue; + } + } + } + lastUsedStrip = curStrip; + //能放下 + for (int i = 0; i < setsIn.Count; i++) + { + var set = setsIn[i]; + var ch = notUsedChs[i]; + set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}"; + //更新全局已使用通道 + allUsedCH.Add(ch.ChannelID); + } + var chOffIdx = setsIn.Count; + for (int i = 0; i < setsSpared.Count(); i++) + { + var set = setsSpared[i]; + var ch = notUsedChs[chOffIdx + i]; + set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}/冗余"; + //更新全局已使用通道 + allUsedCH.Add(ch.ChannelID); + } + #endregion + } + #endregion + #region output + if (setsOut.Count + setsSpared.Count() > 10) + { + //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 + //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, + //如果不够4个就留4个以下即可。 + + } + else + { + //空白通道原则 + //如5*2*0.75规格的电缆,电缆对就是5对,但可能它只预分配了2个电缆对,即只有2个信号被预分配了, + //但考虑模块通道的时候是考虑5对,而不是只考虑已经预分配的2个电缆对 + + //目前还剩多少 + //空的通道够不够 + int sparedChCount = 0; + } + #endregion } } - //var curPanel = new ec_PanelEntity(); - //curPanel = panelsNeed.FirstOrDefault(x => x.PanelID == cablesNeedAssigned[0].PanelID);//先定位到第一个电缆所在的箱子 - //curPanel.strips = stripsNeed.Where(x => x.PanelID == curPanel.PanelID).ToList(); - //var curStrip = new ec_PanelStripEntity(); - #endregion - //for (var i = 0; i < cablesNeedAssigned.Count; i++) - //{ - // #region 是否有端子排 1.2.1 - // if (curPanel.PanelID != cablesNeedAssigned[i].PanelID) - // { - // curPanel = panelsNeed.FirstOrDefault(x => x.PanelID == cablesNeedAssigned[0].PanelID);//切换箱子 - // curPanel.strips = stripsNeed.Where(x => x.PanelID == curPanel.PanelID).ToList(); - // } - // foreach (var set in cablesNeedAssigned[i].Sets) - // { - // var availableStrips = curPanel.strips.Where(x => x.IO_TYPE.ToUpper() == set.IOType.ToString().ToUpper()).ToList(); - - // if (availableStrips != null && availableStrips.Count > 0) - // { - // //已经存在端子排 - // } - // else - // { - // //没有端子排,根据信号数里自动新建端子排,通道数里根据端子io模板的默认值获得 - // //????????????????????????????????? - // } - // } - // //可能要换一下循环主体,评估下是按照cable循环好,还是按strip循环好 - // #endregion - - //} - //#endregion return Success(cablesNeedAssigned); } + /// + /// 找到下一个可用的端子排 + /// + /// 所有的端子排 + /// 使用过的channelId + /// + private ec_PanelStripEntity FindNextAvailableTS(List TSs, List allUsedCH) + { + foreach (var TS in TSs) + { + var usedChs = TS.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + var notUsedChs = TS.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + double sparedRate = notUsedChs.Count * 1.0 / TS.Channels.Count * 1.0; + if (sparedRate < 0.05) + { + //没有空闲通道 next + } + else + { + return TS;//找到了 + } + } + + return null;//都没有 + } /// /// 根据step2的预分配结果,进行实际的分配,修改数据库。 /// @@ -750,9 +944,8 @@ namespace Learun.Application.Web.AppApi } } /// - /// 通过预设模式,批量创建端子排 通道 端子 - /// - /// + /// 通过预设模式,批量创建端子排 通道 端子。此时strip数里 set数里已经根据profile给定好了。 + /// /// [HttpPost] [HandlerApiLogin(FilterMode.Enforce)] diff --git a/Learun.Application.Web/AppApi/PlotLayoutApiController.cs b/Learun.Application.Web/AppApi/PlotLayoutApiController.cs index 2624e147..a164e741 100644 --- a/Learun.Application.Web/AppApi/PlotLayoutApiController.cs +++ b/Learun.Application.Web/AppApi/PlotLayoutApiController.cs @@ -130,7 +130,7 @@ namespace Learun.Application.Web.AppApi area = AREA, Scale = BasePointProp_scale == null ? 1 : (double.TryParse(BasePointProp_scale.PropertyValue, out double scale) ? scale : 1) }; - + layoutTag.Scale = 1.0 / layoutTag.Scale; // 这里的比例是放大多少倍,所以取倒数。 diff --git a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs index b79e078b..8c3d554e 100644 --- a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs +++ b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableBLL.cs @@ -309,7 +309,7 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC - cable.ToPanel = panelObj;//暂用一下topanel属性,相当于电缆预分配的采集箱背后的Panel对象。 + cable.AssignedPanel = panelObj; var IOsOnPanel = panelObj.allowedIOTypes.Split(',').ToList(); //剩下的感觉都可以是set上的参数? diff --git a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs index f9bf1f49..d66ffd38 100644 --- a/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs +++ b/Learun.Framework.Module/Learun.Application.Module/Learun.Application.TwoDevelopment/ZZDT_EC/ec_cable/ec_CableEntity.cs @@ -87,6 +87,7 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC } + /// /// 编辑调用 /// @@ -109,7 +110,7 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC /// /// [SugarColumn(IsIgnore = true)] - public List Sets { set; get; } + public List Sets { set; get; } = new List(); /// /// 平行电缆数据 @@ -147,13 +148,15 @@ namespace Learun.Application.TwoDevelopment.ZZDT_EC /// - /// From连接处的工程位号信息。 - /// 同时,也表达下预分配电缆panelid对应的柜子信息。 + /// From连接处的工程位号信息。 /// [SugarColumn(IsIgnore = true)] public ec_PanelEntity ToPanel { set; get; } - - + /// + /// 根据算出来的实际分配的箱子,当然也能和panelid不同,而是就近的另外一个采集箱 + /// + [SugarColumn(IsIgnore = true)] + public ec_PanelEntity AssignedPanel { set; get; } #endregion } } diff --git a/newFront/c#前端/CAD.Extend/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/newFront/c#前端/CAD.Extend/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache index 5158d93ab33e713b280e1a839a1003d869bf247a..bc671bf59591d1b8e534cc555b5fe2e22b470098 100644 GIT binary patch delta 1039 zcmZ3dwOo6GxU4P%1B0ovRZLN8L4J(0zl&>(fq`Ybi>Iz@PHOUGMRwtd_FR%ycoax0 z=q2aprDdi^;!z|s@sX-j3nM-ilckurCfhNtliET^S%XvqAthX!FEW)gN;TtCr!={m z#Z$5zkDEX$xF$2Q8cUWDR8`1oBpHQQ)iqWH$#lFbG}&||lkuwPWYd&P#jD~eo3>;u z9u=;VK{#a@`K2~bWdFn@H4R_5$xPnJl_b@JUx_1kgk&~Oixk;qHXq}j&Lo+LQwbx# zqoPYMOOG82!i(&kly3mGLHa4TUKp8P?WdvcX<5I%$0 Lg*Sf?wqpbUR$e>c delta 925 zcmZ3ky-sU_xTrn@1B0%sRg6ofu4_(ea!FBUa$?TpiEP5si3J6E$@zI{ndwGYsl_qgrFkBydFe3P+0jKI%*aroDkI+6FUF~;!Z$rdFC`}@ z5R0iY6A!8i)?kyEe1M5-vKr$$p*4&+rK6d2COa^B307cJvH1W~Bcot77Ad94wJe^3 z`8Z^_CUdhI3+CaJZDutR48kh=fmJ~;9;=Kuo33Cq78!5BSS+GSlf~J!1w*mQ)UqoJ zdSS>M6p-3{nf()!P#^ZdQs7~q%)}in)Ph@j7I&avGKRqu*<>~=@Jwg&A~DuOT;idz z9*JS*K> z7WEczr=?-YeiT%id_s_S@Qrm+?z{8j2Qv` Cd^-LB diff --git a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogAutoArrangeLayout.g.cs b/newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogAutoArrangeLayout.g.cs deleted file mode 100644 index 3fd1d88d..00000000 --- a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogAutoArrangeLayout.g.cs +++ /dev/null @@ -1,159 +0,0 @@ -#pragma checksum "..\..\..\Views\DialogAutoArrangeLayout.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "D381518E6A709FE4FD61B7B59C0FE6A02830580BBED56CC9959DA9E027AC6A01" -//------------------------------------------------------------------------------ -// -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 -// -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 -// -//------------------------------------------------------------------------------ - -using Microsoft.Xaml.Behaviors; -using Microsoft.Xaml.Behaviors.Core; -using Microsoft.Xaml.Behaviors.Input; -using Microsoft.Xaml.Behaviors.Layout; -using Microsoft.Xaml.Behaviors.Media; -using Prism.DryIoc; -using Prism.Interactivity; -using Prism.Ioc; -using Prism.Mvvm; -using Prism.Regions; -using Prism.Regions.Behaviors; -using Prism.Services.Dialogs; -using Prism.Unity; -using SWS.CustomControl; -using SWS.Electrical; -using System; -using System.Diagnostics; -using System.Windows; -using System.Windows.Automation; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Media.Effects; -using System.Windows.Media.Imaging; -using System.Windows.Media.Media3D; -using System.Windows.Media.TextFormatting; -using System.Windows.Navigation; -using System.Windows.Shapes; -using System.Windows.Shell; -using Telerik.Windows.Controls; -using Telerik.Windows.Controls.Animation; -using Telerik.Windows.Controls.Behaviors; -using Telerik.Windows.Controls.Carousel; -using Telerik.Windows.Controls.ComboBox; -using Telerik.Windows.Controls.Data.PropertyGrid; -using Telerik.Windows.Controls.DragDrop; -using Telerik.Windows.Controls.GridView; -using Telerik.Windows.Controls.LayoutControl; -using Telerik.Windows.Controls.Legend; -using Telerik.Windows.Controls.MultiColumnComboBox; -using Telerik.Windows.Controls.Primitives; -using Telerik.Windows.Controls.RadialMenu; -using Telerik.Windows.Controls.TransitionEffects; -using Telerik.Windows.Controls.TreeListView; -using Telerik.Windows.Controls.TreeView; -using Telerik.Windows.Controls.Wizard; -using Telerik.Windows.Data; -using Telerik.Windows.DragDrop; -using Telerik.Windows.DragDrop.Behaviors; -using Telerik.Windows.Input.Touch; -using Telerik.Windows.Shapes; - - -namespace SWS.Electrical.Views { - - - /// - /// DialogAutoArrangeLayout - /// - public partial class DialogAutoArrangeLayout : System.Windows.Controls.UserControl, System.Windows.Markup.IComponentConnector { - - - #line 122 "..\..\..\Views\DialogAutoArrangeLayout.xaml" - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - internal SWS.CustomControl.customWindowTitleBar titleBar; - - #line default - #line hidden - - - #line 237 "..\..\..\Views\DialogAutoArrangeLayout.xaml" - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - internal System.Windows.Controls.DataGrid dgTag; - - #line default - #line hidden - - - #line 340 "..\..\..\Views\DialogAutoArrangeLayout.xaml" - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - internal System.Windows.Controls.DataGrid dgErrTag; - - #line default - #line hidden - - private bool _contentLoaded; - - /// - /// InitializeComponent - /// - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] - public void InitializeComponent() { - if (_contentLoaded) { - return; - } - _contentLoaded = true; - System.Uri resourceLocater = new System.Uri("/SWS.Electrical;component/views/dialogautoarrangelayout.xaml", System.UriKind.Relative); - - #line 1 "..\..\..\Views\DialogAutoArrangeLayout.xaml" - System.Windows.Application.LoadComponent(this, resourceLocater); - - #line default - #line hidden - } - - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] - void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) { - switch (connectionId) - { - case 1: - this.titleBar = ((SWS.CustomControl.customWindowTitleBar)(target)); - return; - case 2: - this.dgTag = ((System.Windows.Controls.DataGrid)(target)); - - #line 243 "..\..\..\Views\DialogAutoArrangeLayout.xaml" - this.dgTag.LoadingRow += new System.EventHandler(this.dgTag_LoadingRow); - - #line default - #line hidden - return; - case 3: - this.dgErrTag = ((System.Windows.Controls.DataGrid)(target)); - - #line 346 "..\..\..\Views\DialogAutoArrangeLayout.xaml" - this.dgErrTag.LoadingRow += new System.EventHandler(this.dgTag_LoadingRow); - - #line default - #line hidden - return; - } - this._contentLoaded = true; - } - } -} - diff --git a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogTest2.g.cs b/newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogTest2.g.cs deleted file mode 100644 index c297cebe..00000000 --- a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/DialogTest2.g.cs +++ /dev/null @@ -1,125 +0,0 @@ -#pragma checksum "..\..\..\Views\DialogTest2.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "6D6B0D2E8B29B2F4DE2F7CF02D2382F69B7F06455C4BC9504C7F76B8C7D980B6" -//------------------------------------------------------------------------------ -// -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 -// -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 -// -//------------------------------------------------------------------------------ - -using Microsoft.Xaml.Behaviors; -using Microsoft.Xaml.Behaviors.Core; -using Microsoft.Xaml.Behaviors.Input; -using Microsoft.Xaml.Behaviors.Layout; -using Microsoft.Xaml.Behaviors.Media; -using Prism.DryIoc; -using Prism.Interactivity; -using Prism.Ioc; -using Prism.Mvvm; -using Prism.Regions; -using Prism.Regions.Behaviors; -using Prism.Services.Dialogs; -using Prism.Unity; -using SWS.CustomControl; -using SWS.Electrical.Views; -using System; -using System.Diagnostics; -using System.Windows; -using System.Windows.Automation; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Media.Effects; -using System.Windows.Media.Imaging; -using System.Windows.Media.Media3D; -using System.Windows.Media.TextFormatting; -using System.Windows.Navigation; -using System.Windows.Shapes; -using System.Windows.Shell; -using Telerik.Windows.Controls; -using Telerik.Windows.Controls.Animation; -using Telerik.Windows.Controls.Behaviors; -using Telerik.Windows.Controls.Carousel; -using Telerik.Windows.Controls.ComboBox; -using Telerik.Windows.Controls.Data.PropertyGrid; -using Telerik.Windows.Controls.DragDrop; -using Telerik.Windows.Controls.GridView; -using Telerik.Windows.Controls.LayoutControl; -using Telerik.Windows.Controls.Legend; -using Telerik.Windows.Controls.MultiColumnComboBox; -using Telerik.Windows.Controls.Primitives; -using Telerik.Windows.Controls.RadialMenu; -using Telerik.Windows.Controls.TransitionEffects; -using Telerik.Windows.Controls.TreeListView; -using Telerik.Windows.Controls.TreeView; -using Telerik.Windows.Controls.Wizard; -using Telerik.Windows.Data; -using Telerik.Windows.DragDrop; -using Telerik.Windows.DragDrop.Behaviors; -using Telerik.Windows.Input.Touch; -using Telerik.Windows.Shapes; - - -namespace SWS.Electrical.Views { - - - /// - /// DialogTest2 - /// - public partial class DialogTest2 : System.Windows.Controls.UserControl, System.Windows.Markup.IComponentConnector { - - - #line 33 "..\..\..\Views\DialogTest2.xaml" - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - internal SWS.CustomControl.customWindowTitleBar titleBar; - - #line default - #line hidden - - private bool _contentLoaded; - - /// - /// InitializeComponent - /// - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] - public void InitializeComponent() { - if (_contentLoaded) { - return; - } - _contentLoaded = true; - System.Uri resourceLocater = new System.Uri("/SWS.Electrical;component/views/dialogtest2.xaml", System.UriKind.Relative); - - #line 1 "..\..\..\Views\DialogTest2.xaml" - System.Windows.Application.LoadComponent(this, resourceLocater); - - #line default - #line hidden - } - - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] - void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) { - switch (connectionId) - { - case 1: - this.titleBar = ((SWS.CustomControl.customWindowTitleBar)(target)); - return; - } - this._contentLoaded = true; - } - } -} - diff --git a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.cs b/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.cs index 5c322115..98d42d44 100644 --- a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.cs +++ b/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.cs @@ -9,6 +9,23 @@ // //------------------------------------------------------------------------------ +using Microsoft.Xaml.Behaviors; +using Microsoft.Xaml.Behaviors.Core; +using Microsoft.Xaml.Behaviors.Input; +using Microsoft.Xaml.Behaviors.Layout; +using Microsoft.Xaml.Behaviors.Media; +using Prism.DryIoc; +using Prism.Interactivity; +using Prism.Ioc; +using Prism.Mvvm; +using Prism.Regions; +using Prism.Regions.Behaviors; +using Prism.Services.Dialogs; +using Prism.Unity; +using SWS.CustomControl; +using SWS.Electrical; +using SWS.Electrical.Views; +using SWS.Model; using System; using System.Diagnostics; using System.Windows; @@ -29,6 +46,28 @@ using System.Windows.Media.TextFormatting; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Shell; +using Telerik.Windows.Controls; +using Telerik.Windows.Controls.Animation; +using Telerik.Windows.Controls.Behaviors; +using Telerik.Windows.Controls.Carousel; +using Telerik.Windows.Controls.ComboBox; +using Telerik.Windows.Controls.Data.PropertyGrid; +using Telerik.Windows.Controls.DragDrop; +using Telerik.Windows.Controls.GridView; +using Telerik.Windows.Controls.LayoutControl; +using Telerik.Windows.Controls.Legend; +using Telerik.Windows.Controls.MultiColumnComboBox; +using Telerik.Windows.Controls.Primitives; +using Telerik.Windows.Controls.RadialMenu; +using Telerik.Windows.Controls.TransitionEffects; +using Telerik.Windows.Controls.TreeListView; +using Telerik.Windows.Controls.TreeView; +using Telerik.Windows.Controls.Wizard; +using Telerik.Windows.Data; +using Telerik.Windows.DragDrop; +using Telerik.Windows.DragDrop.Behaviors; +using Telerik.Windows.Input.Touch; +using Telerik.Windows.Shapes; namespace SWS.Electrical.Views { diff --git a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.i.cs b/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.i.cs index 5c322115..98d42d44 100644 --- a/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.i.cs +++ b/newFront/c#前端/SWS.Electrical/obj/Debug/Views/SWSDialogWindow.g.i.cs @@ -9,6 +9,23 @@ // //------------------------------------------------------------------------------ +using Microsoft.Xaml.Behaviors; +using Microsoft.Xaml.Behaviors.Core; +using Microsoft.Xaml.Behaviors.Input; +using Microsoft.Xaml.Behaviors.Layout; +using Microsoft.Xaml.Behaviors.Media; +using Prism.DryIoc; +using Prism.Interactivity; +using Prism.Ioc; +using Prism.Mvvm; +using Prism.Regions; +using Prism.Regions.Behaviors; +using Prism.Services.Dialogs; +using Prism.Unity; +using SWS.CustomControl; +using SWS.Electrical; +using SWS.Electrical.Views; +using SWS.Model; using System; using System.Diagnostics; using System.Windows; @@ -29,6 +46,28 @@ using System.Windows.Media.TextFormatting; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Shell; +using Telerik.Windows.Controls; +using Telerik.Windows.Controls.Animation; +using Telerik.Windows.Controls.Behaviors; +using Telerik.Windows.Controls.Carousel; +using Telerik.Windows.Controls.ComboBox; +using Telerik.Windows.Controls.Data.PropertyGrid; +using Telerik.Windows.Controls.DragDrop; +using Telerik.Windows.Controls.GridView; +using Telerik.Windows.Controls.LayoutControl; +using Telerik.Windows.Controls.Legend; +using Telerik.Windows.Controls.MultiColumnComboBox; +using Telerik.Windows.Controls.Primitives; +using Telerik.Windows.Controls.RadialMenu; +using Telerik.Windows.Controls.TransitionEffects; +using Telerik.Windows.Controls.TreeListView; +using Telerik.Windows.Controls.TreeView; +using Telerik.Windows.Controls.Wizard; +using Telerik.Windows.Data; +using Telerik.Windows.DragDrop; +using Telerik.Windows.DragDrop.Behaviors; +using Telerik.Windows.Input.Touch; +using Telerik.Windows.Shapes; namespace SWS.Electrical.Views { diff --git a/newFront/c#前端/SWS.Share/ConstString.cs b/newFront/c#前端/SWS.Share/ConstString.cs new file mode 100644 index 00000000..cb1ed962 --- /dev/null +++ b/newFront/c#前端/SWS.Share/ConstString.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWS.Share +{ + public class ConstString + { + + } +} diff --git a/newFront/c#前端/SWS.Share/Enum.cs b/newFront/c#前端/SWS.Share/Enum.cs new file mode 100644 index 00000000..e3553f51 --- /dev/null +++ b/newFront/c#前端/SWS.Share/Enum.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWS.Share +{ + public class Enum + { + public enum inOrOut + { + 输入 = 0, + 输出 = 1 + } + public enum cableClass + { + conventional = 0, + homerun = 1 + } + } +} diff --git a/newFront/c#前端/SWS.Share/SWS.Share.csproj b/newFront/c#前端/SWS.Share/SWS.Share.csproj index 91be2f35..851b7bba 100644 --- a/newFront/c#前端/SWS.Share/SWS.Share.csproj +++ b/newFront/c#前端/SWS.Share/SWS.Share.csproj @@ -43,6 +43,8 @@ + + diff --git a/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.cs b/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.cs index 73b12740..ff9ac670 100644 --- a/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.cs +++ b/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.cs @@ -9,6 +9,8 @@ // //------------------------------------------------------------------------------ +using SWS.Commons.Helper.Converter; +using SWS.CustomControl; using System; using System.Diagnostics; using System.Windows; @@ -29,6 +31,28 @@ using System.Windows.Media.TextFormatting; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Shell; +using Telerik.Windows.Controls; +using Telerik.Windows.Controls.Animation; +using Telerik.Windows.Controls.Behaviors; +using Telerik.Windows.Controls.Carousel; +using Telerik.Windows.Controls.ComboBox; +using Telerik.Windows.Controls.Data.PropertyGrid; +using Telerik.Windows.Controls.DragDrop; +using Telerik.Windows.Controls.GridView; +using Telerik.Windows.Controls.LayoutControl; +using Telerik.Windows.Controls.Legend; +using Telerik.Windows.Controls.MultiColumnComboBox; +using Telerik.Windows.Controls.Primitives; +using Telerik.Windows.Controls.RadialMenu; +using Telerik.Windows.Controls.TransitionEffects; +using Telerik.Windows.Controls.TreeListView; +using Telerik.Windows.Controls.TreeView; +using Telerik.Windows.Controls.Wizard; +using Telerik.Windows.Data; +using Telerik.Windows.DragDrop; +using Telerik.Windows.DragDrop.Behaviors; +using Telerik.Windows.Input.Touch; +using Telerik.Windows.Shapes; namespace SWS.WPF.Views { diff --git a/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.i.cs b/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.i.cs index 73b12740..ff9ac670 100644 --- a/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.i.cs +++ b/newFront/c#前端/SWS.WPF/obj/Debug/Views/CustomDialogWindow.g.i.cs @@ -9,6 +9,8 @@ // //------------------------------------------------------------------------------ +using SWS.Commons.Helper.Converter; +using SWS.CustomControl; using System; using System.Diagnostics; using System.Windows; @@ -29,6 +31,28 @@ using System.Windows.Media.TextFormatting; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Shell; +using Telerik.Windows.Controls; +using Telerik.Windows.Controls.Animation; +using Telerik.Windows.Controls.Behaviors; +using Telerik.Windows.Controls.Carousel; +using Telerik.Windows.Controls.ComboBox; +using Telerik.Windows.Controls.Data.PropertyGrid; +using Telerik.Windows.Controls.DragDrop; +using Telerik.Windows.Controls.GridView; +using Telerik.Windows.Controls.LayoutControl; +using Telerik.Windows.Controls.Legend; +using Telerik.Windows.Controls.MultiColumnComboBox; +using Telerik.Windows.Controls.Primitives; +using Telerik.Windows.Controls.RadialMenu; +using Telerik.Windows.Controls.TransitionEffects; +using Telerik.Windows.Controls.TreeListView; +using Telerik.Windows.Controls.TreeView; +using Telerik.Windows.Controls.Wizard; +using Telerik.Windows.Data; +using Telerik.Windows.DragDrop; +using Telerik.Windows.DragDrop.Behaviors; +using Telerik.Windows.Input.Touch; +using Telerik.Windows.Shapes; namespace SWS.WPF.Views { From dc7269290ff2f7a6c86e5d3b97289d34658f8193 Mon Sep 17 00:00:00 2001 From: xingheng Date: Fri, 26 Sep 2025 11:04:02 +0800 Subject: [PATCH 3/4] 09 25 --- .../AppApi/IOModuleApiController.cs | 415 +++++++++++++----- 1 file changed, 300 insertions(+), 115 deletions(-) diff --git a/Learun.Application.Web/AppApi/IOModuleApiController.cs b/Learun.Application.Web/AppApi/IOModuleApiController.cs index ad0ae97d..7d3e611a 100644 --- a/Learun.Application.Web/AppApi/IOModuleApiController.cs +++ b/Learun.Application.Web/AppApi/IOModuleApiController.cs @@ -422,10 +422,22 @@ namespace Learun.Application.Web.AppApi cablesNeedAssigned = cablesNeedAssigned.Where(x => CableIds.Contains(x.CableID)).ToList(); #endregion //涉及到哪些箱子 - var allPanel = SqlSugarHelper.Db.Queryable().AS(panelTable). + 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) @@ -514,6 +526,11 @@ namespace Learun.Application.Web.AppApi var signalTb = ProjectSugar.TableName(projId); var allSignals = SqlSugarHelper.Db.Queryable().AS(signalTb).ToList(); var allUsedCH = allSignals.Where(x => !string.IsNullOrEmpty(x.ChannelID)).Select(x => x.ChannelID).Distinct().ToList(); + //??这里有问题。通道是否被占用,需要看signal和set双重(在io分配界面) + //1. 信号有, 电缆set有,占了 + //2.信号no,电缆set有,占了 + //3.信号有,电缆setno,没占 + //4.信号no,电缆setno,没占 //1.2 流程图 分组原则为同一信号类型、同一系统的为一组 var cablesGrouped = cablesNeedAssigned.OrderBy(x => x.PanelID).ThenBy(x => x.PreAssignIOType).ThenBy(x => x.System).ToList(); @@ -523,7 +540,7 @@ namespace Learun.Application.Web.AppApi var allPanelIds = cablesGrouped.Select(x => x.PanelID).Distinct(); var stripBll = new ec_PanelStripBLL(); - var allStrips = stripBll.GetList("{ProjectId:\"" + projId + "\"}",OnlySelf:false) + 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()); @@ -552,11 +569,10 @@ namespace Learun.Application.Web.AppApi // sameGroup = false;//换组了 //} #endregion - //1.2 流程图 读取有提前选好箱子的信号 - GlobalEnum.IOType ioTypeOnCable = default; + //1.2 流程图 读取有提前选好箱子的信号 var setsSpared = cable.Sets.Where(x => string.IsNullOrEmpty(x.PreAssignGroup_Desc) || string.IsNullOrEmpty(x.PreAssignInOrOut)).ToList(); - var setsIn = cable.Sets.Where(x => x.PreAssignInOrOut == SWS.Share.Enum.inOrOut.输入.ToString()).ToList(); - var setsOut = cable.Sets.Where(x => x.PreAssignInOrOut == SWS.Share.Enum.inOrOut.输出.ToString()).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()) @@ -571,154 +587,316 @@ namespace Learun.Application.Web.AppApi } #endregion + #region inputNew + var resIn = AutoAssignCore(GlobalEnum.inOrOut.输入, setsIn, setsSpared); + #endregion #region input - ec_PanelStripEntity curStrip = null; - var matchedStrips = curStrips.Where(x => x.IO_TYPE == ioTypeOnCable.ToString()).ToList(); - if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnCable.ToString()) - { - //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 - matchedStrips.Insert(0, lastUsedStrip); - } - if (setsIn.Count + setsSpared.Count() > 10) - { - //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 - //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, - //如果不够4个就留4个以下即可。 - } - else + //ec_PanelStripEntity curStrip = null; + //var matchedStrips = curStrips.Where(x => x.IO_TYPE == ioTypeOnCable.ToString()).ToList(); + //if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnCable.ToString()) + //{ + // //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 + // matchedStrips.Insert(0, lastUsedStrip); + //} + //if (setsIn.Count == 0 ) + //{ + // //相当于没有 + //} + //else if (setsIn.Count + setsSpared.Count() > 10) + //{ + // //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 + // //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, + // //如果不够4个就留4个以下即可。 + //} + //else + //{ + // string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称 + // switch (cable.PreAssignIOType.ToLower()) + // { + // case "digital": + // //数字量 + // ioTypeOnCable = GlobalEnum.IOType.DI; + // break; + // case "4~20ma": + // //模拟量4-20mA + // ioTypeOnCable = GlobalEnum.IOType.AI; + // break; + // case "10v": + // ioTypeOnCable = GlobalEnum.IOType.TenVolt; + // break; + // case "pt100": + // ioTypeOnCable = GlobalEnum.IOType.PT100; + // break; + // case "pulse": + // ioTypeOnCable = GlobalEnum.IOType.PULSE; + // break; + // default: + // //通讯类 485 422啥的 + // continue; + // break; + // } + + // //1.2 流程图 箱子里是否已经存在端子排(io匹配) + + // bool alreadyInsertNewTs = false; + // if (matchedStrips == null || matchedStrips.Count == 0) + // { + // //没有端子排 + // //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得 + // var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + // alreadyInsertNewTs = true; + // matchedStrips.Add(newTS); + // } + + // #region 1.2 流程图 空的通道数够不够 + // if (cable.CableClass == SWS.Share.Enum.cableClass.homerun.ToString()) + // { + // //1.2.3(2)如果模块是通讯信号(像RS485这种就是通讯信号),则不用管预留空白通道这个事情,看到有空的通道就放。 + // //当前这个端子排就是可用的 + + // curStrip = matchedStrips.First(); + + + // } + // else + // { + // //1.2.3 (1) 非通讯,如果空的通道大于整个模块的5%,则可以利用,利用到小于5%了则停止利用,如果本身空通道数占的比例就小于5%,则不利用。 + + // curStrip = FindNextAvailableTS(matchedStrips, allUsedCH); + + // if (curStrip == null) + // { + // var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + // alreadyInsertNewTs = true; + // matchedStrips.Add(newTS); + // curStrip = newTS; + + // } + // } + // var usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + // var notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + // #endregion + // #region 1.2 流程图 按规则先放几个信号进去 + // if (notUsedChs.Count < setsIn.Count + setsSpared.Count()) + // { + // //不够放,又要新建? + // if (alreadyInsertNewTs) + // { + // //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 + // continue; + // } + // else + // { + // //相当于前面5%的判断过了,但是呢放不下所有需要的set + // var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + // alreadyInsertNewTs = true; + // matchedStrips.Add(newTS); + // curStrip = newTS; + // usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + // notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + // if (notUsedChs.Count < setsIn.Count + setsSpared.Count()) + // { + // //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 + // continue; + // } + // } + // } + // lastUsedStrip = curStrip; + // //能放下 + // for (int i = 0; i < setsIn.Count; i++) + // { + // var set = setsIn[i]; + // var ch = notUsedChs[i]; + // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}"; + // //更新全局已使用通道 + // allUsedCH.Add(ch.ChannelID); + // } + // var chOffIdx = setsIn.Count; + // for (int i = 0; i < setsSpared.Count(); i++) + // { + // var set = setsSpared[i]; + // var ch = notUsedChs[chOffIdx + i]; + // set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}/冗余"; + // //更新全局已使用通道 + // allUsedCH.Add(ch.ChannelID); + // } + // #endregion + //} + #endregion + #region output + var resOut = AutoAssignCore(GlobalEnum.inOrOut.输出, setsOut, setsSpared); + + + #endregion + + //in 和 out都会执行这个 + bool AutoAssignCore(GlobalEnum.inOrOut inOrOut, List sets, List sets_Spared) { + GlobalEnum.IOType ioTypeOnC = default; + ec_PanelStripEntity curStrip = null; + var matchedStrips = curStrips.Where(x => x.IO_TYPE == ioTypeOnC.ToString()).ToList(); + if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnC.ToString()) + { + //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 + matchedStrips.Insert(0, lastUsedStrip); + } string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称 switch (cable.PreAssignIOType.ToLower()) { case "digital": //数字量 - ioTypeOnCable = GlobalEnum.IOType.DI; + if (inOrOut == GlobalEnum.inOrOut.输入) + { + ioTypeOnC = GlobalEnum.IOType.DI; + } + else + { + ioTypeOnC = GlobalEnum.IOType.DO; + } break; case "4~20ma": //模拟量4-20mA - ioTypeOnCable = GlobalEnum.IOType.AI; + if (inOrOut == GlobalEnum.inOrOut.输入) + { + ioTypeOnC = GlobalEnum.IOType.AI; + } + else + { + ioTypeOnC = GlobalEnum.IOType.AO; + } + break; case "10v": - ioTypeOnCable = GlobalEnum.IOType.TenVolt; + ioTypeOnC = GlobalEnum.IOType.TenVolt; break; case "pt100": - ioTypeOnCable = GlobalEnum.IOType.PT100; + ioTypeOnC = GlobalEnum.IOType.PT100; break; case "pulse": - ioTypeOnCable = GlobalEnum.IOType.PULSE; + ioTypeOnC = GlobalEnum.IOType.PULSE; break; default: //通讯类 485 422啥的 - continue; - break; + return false; } - - //1.2 流程图 箱子里是否已经存在端子排(io匹配) - - bool alreadyInsertNewTs = false; - if (matchedStrips == null || matchedStrips.Count == 0) + if (sets.Count == 0) { - //没有端子排 - //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得 - var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); - alreadyInsertNewTs = true; - matchedStrips.Add(newTS); + //相当于没有 } - - #region 1.2 流程图 空的通道数够不够 - if (cable.CableClass == SWS.Share.Enum.cableClass.homerun.ToString()) - { - //1.2.3(2)如果模块是通讯信号(像RS485这种就是通讯信号),则不用管预留空白通道这个事情,看到有空的通道就放。 - //当前这个端子排就是可用的 - - curStrip = matchedStrips.First(); + //else if (sets.Count + setsSpared.Count() > 10) + //{ - } + //} else { - //1.2.3 (1) 非通讯,如果空的通道大于整个模块的5%,则可以利用,利用到小于5%了则停止利用,如果本身空通道数占的比例就小于5%,则不利用。 + var totalSets = sets.Count + setsSpared.Count(); + //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 + //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, + //如果不够4个就留4个以下即可。 - curStrip = FindNextAvailableTS(matchedStrips, allUsedCH); - if (curStrip == null) + //1.2 流程图 箱子里是否已经存在端子排(io匹配) + + bool alreadyInsertNewTs = false; + if (matchedStrips == null || matchedStrips.Count == 0) { - var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); + //没有端子排 + //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得 + var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnC.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnC); alreadyInsertNewTs = true; matchedStrips.Add(newTS); - curStrip = newTS; - } - } - var usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); - var notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); - #endregion - #region 1.2 流程图 按规则先放几个信号进去 - if (notUsedChs.Count < setsIn.Count + setsSpared.Count()) - { - //不够放,又要新建? - if (alreadyInsertNewTs) + + #region 1.2 流程图 空的通道数够不够 + if (cable.CableClass == SWS.Share.Enum.cableClass.homerun.ToString()) { - //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 - continue; + //1.2.3(2)如果模块是通讯信号(像RS485这种就是通讯信号),则不用管预留空白通道这个事情,看到有空的通道就放。 + //当前这个端子排就是可用的 + + curStrip = matchedStrips.First(); + + } else { - //相当于前面5%的判断过了,但是呢放不下所有需要的set - var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnCable.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnCable); - alreadyInsertNewTs = true; - matchedStrips.Add(newTS); - curStrip = newTS; - usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); - notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); - if (notUsedChs.Count < setsIn.Count + setsSpared.Count()) + //1.2.3 (1) 非通讯,如果空的通道大于整个模块的5%,则可以利用,利用到小于5%了则停止利用,如果本身空通道数占的比例就小于5%,则不利用。 + + curStrip = FindNextAvailableTS(matchedStrips, allUsedCH); + + if (curStrip == null) { - //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 - continue; + var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnC.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnC); + alreadyInsertNewTs = true; + matchedStrips.Add(newTS); + curStrip = newTS; + + } + } + var usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + var notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + #endregion + #region 1.2 流程图 按规则先放几个信号进去 + if (notUsedChs.Count < totalSets) + { + //不够放,又要新建? + if (alreadyInsertNewTs) + { + //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 + return false; + } + else + { + //相当于前面5%的判断过了,但是呢放不下所有需要的set + var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnC.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnC); + alreadyInsertNewTs = true; + matchedStrips.Add(newTS); + curStrip = newTS; + usedChs = curStrip.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + notUsedChs = curStrip.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + if (notUsedChs.Count < sets.Count + setsSpared.Count()) + { + //压根就有问题,说明电缆的set太多了,就算是新建的模块,一个channel都没有使用的情况下,都塞不下。 + return false; + } + } + } + lastUsedStrip = curStrip; + //能放下 + if (cable.Sets.Count > 10) + { + //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道,如果不够4个就留4个以下即可 + + } + else + { + for (int i = 0; i < sets.Count; i++) + { + var set = sets[i]; + var ch = notUsedChs[i]; + set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}"; + //更新全局已使用通道 + allUsedCH.Add(ch.ChannelID); + } + var chOffIdx = sets.Count; + for (int i = 0; i < setsSpared.Count(); i++) + { + var set = setsSpared[i]; + var ch = notUsedChs[chOffIdx + i]; + set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}/冗余"; + //更新全局已使用通道 + allUsedCH.Add(ch.ChannelID); } } - } - lastUsedStrip = curStrip; - //能放下 - for (int i = 0; i < setsIn.Count; i++) - { - var set = setsIn[i]; - var ch = notUsedChs[i]; - set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}"; - //更新全局已使用通道 - allUsedCH.Add(ch.ChannelID); - } - var chOffIdx = setsIn.Count; - for (int i = 0; i < setsSpared.Count(); i++) - { - var set = setsSpared[i]; - var ch = notUsedChs[chOffIdx + i]; - set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}/冗余"; - //更新全局已使用通道 - allUsedCH.Add(ch.ChannelID); - } - #endregion - } - #endregion - #region output - if (setsOut.Count + setsSpared.Count() > 10) - { - //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 - //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, - //如果不够4个就留4个以下即可。 - } - else - { - //空白通道原则 - //如5*2*0.75规格的电缆,电缆对就是5对,但可能它只预分配了2个电缆对,即只有2个信号被预分配了, - //但考虑模块通道的时候是考虑5对,而不是只考虑已经预分配的2个电缆对 + #endregion - //目前还剩多少 - //空的通道够不够 - int sparedChCount = 0; + + + } + return true; } - #endregion + } } @@ -737,17 +915,24 @@ namespace Learun.Application.Web.AppApi { foreach (var TS in TSs) { - var usedChs = TS.Channels.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); - var notUsedChs = TS.Channels.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); - double sparedRate = notUsedChs.Count * 1.0 / TS.Channels.Count * 1.0; + var validChs = TS.Channels.Where(x => x.lock_flg == 0).ToList();//过滤掉锁定的通道 + var usedChs = validChs.Where(x => allUsedCH.Contains(x.ChannelID)).Select(x => x.ChannelID).ToList(); + var notUsedChs = validChs.Where(x => !usedChs.Contains(x.ChannelID)).ToList(); + + + double sparedRate = notUsedChs.Count * 1.0 / validChs.Count * 1.0; if (sparedRate < 0.05) { //没有空闲通道 next } else { + TS.Channels = validChs.OrderBy(X => X.Channel_Seq).ToList(); + var seq = TSs.IndexOf(TS); return TS;//找到了 } + + } From dc8b37ca6e4e7188b9f3338340e0acd918d06014 Mon Sep 17 00:00:00 2001 From: xingheng Date: Sun, 28 Sep 2025 10:43:45 +0800 Subject: [PATCH 4/4] TEMP --- .../AppApi/IOModuleApiController.cs | 109 ++++++++++-------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/Learun.Application.Web/AppApi/IOModuleApiController.cs b/Learun.Application.Web/AppApi/IOModuleApiController.cs index 7d3e611a..a0b332ad 100644 --- a/Learun.Application.Web/AppApi/IOModuleApiController.cs +++ b/Learun.Application.Web/AppApi/IOModuleApiController.cs @@ -53,6 +53,9 @@ namespace Learun.Application.Web.AppApi /// private ec_PanelStripEntity CreatePanelStripByProfile2(string projId, string TSname, string panelId, GlobalEnum.IOType iOType) { + var setTb = ProjectSugar.TableName(projId); + var allSettings = SqlSugarHelper.Db.Queryable().AS(setTb).ToList(); + //IO_CardProfile return new ec_PanelStripEntity(); } /// @@ -525,7 +528,16 @@ namespace Learun.Application.Web.AppApi 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(); + + var allUsedCH = allSignals.Where(x => !string.IsNullOrEmpty(x.ChannelID)).Select(x => x.ChannelID).Distinct().ToList(); + allUsedCH.AddRange(allConnedTerms); //??这里有问题。通道是否被占用,需要看signal和set双重(在io分配界面) //1. 信号有, 电缆set有,占了 //2.信号no,电缆set有,占了 @@ -588,7 +600,11 @@ namespace Learun.Application.Web.AppApi #endregion #region inputNew - var resIn = AutoAssignCore(GlobalEnum.inOrOut.输入, setsIn, setsSpared); + if (setsIn.Count > 0) + { + var resIn = AutoAssignCore(GlobalEnum.inOrOut.输入, setsIn, setsSpared); + } + #endregion #region input //ec_PanelStripEntity curStrip = null; @@ -724,23 +740,19 @@ namespace Learun.Application.Web.AppApi //} #endregion #region output - var resOut = AutoAssignCore(GlobalEnum.inOrOut.输出, setsOut, setsSpared); + if (setsOut.Count > 0) + { + var resOut = AutoAssignCore(GlobalEnum.inOrOut.输出, setsOut, setsSpared); + + } - #endregion + #endregion //in 和 out都会执行这个 bool AutoAssignCore(GlobalEnum.inOrOut inOrOut, List sets, List sets_Spared) { GlobalEnum.IOType ioTypeOnC = default; - ec_PanelStripEntity curStrip = null; - var matchedStrips = curStrips.Where(x => x.IO_TYPE == ioTypeOnC.ToString()).ToList(); - if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnC.ToString()) - { - //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 - matchedStrips.Insert(0, lastUsedStrip); - } - string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称 switch (cable.PreAssignIOType.ToLower()) { case "digital": @@ -779,23 +791,22 @@ namespace Learun.Application.Web.AppApi //通讯类 485 422啥的 return false; } + + ec_PanelStripEntity curStrip = null; + var matchedStrips = curStrips.Where(x => x.IO_TYPE == ioTypeOnC.ToString()).ToList(); + if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnC.ToString()) + { + //1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。 + matchedStrips.Insert(0, lastUsedStrip); + } + string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称 if (sets.Count == 0) { //相当于没有 } - //else if (sets.Count + setsSpared.Count() > 10) - //{ - - - //} else { var totalSets = sets.Count + setsSpared.Count(); - //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。 - //意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道, - //如果不够4个就留4个以下即可。 - - //1.2 流程图 箱子里是否已经存在端子排(io匹配) bool alreadyInsertNewTs = false; @@ -822,7 +833,7 @@ namespace Learun.Application.Web.AppApi { //1.2.3 (1) 非通讯,如果空的通道大于整个模块的5%,则可以利用,利用到小于5%了则停止利用,如果本身空通道数占的比例就小于5%,则不利用。 - curStrip = FindNextAvailableTS(matchedStrips, allUsedCH); + curStrip = FindNextAvailableTS(cable.Sets.Count,totalSets, matchedStrips, allUsedCH); if (curStrip == null) { @@ -846,7 +857,7 @@ namespace Learun.Application.Web.AppApi return false; } else - { + { //相当于前面5%的判断过了,但是呢放不下所有需要的set var newTS = CreatePanelStripByProfile2(projId, "TS_" + ioTypeOnC.ToString() + "_" + newTSSeq++, curPanelId, ioTypeOnC); alreadyInsertNewTs = true; @@ -862,31 +873,23 @@ namespace Learun.Application.Web.AppApi } } lastUsedStrip = curStrip; - //能放下 - if (cable.Sets.Count > 10) + + for (int i = 0; i < sets.Count; i++) { - //另外如果电缆对数大于10对,即像12*2*0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道,如果不够4个就留4个以下即可 - + var set = sets[i]; + var ch = notUsedChs[i]; + set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}"; + //更新全局已使用通道 + allUsedCH.Add(ch.ChannelID); } - else + var chOffIdx = sets.Count; + for (int i = 0; i < setsSpared.Count(); i++) { - for (int i = 0; i < sets.Count; i++) - { - var set = sets[i]; - var ch = notUsedChs[i]; - set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}"; - //更新全局已使用通道 - allUsedCH.Add(ch.ChannelID); - } - var chOffIdx = sets.Count; - for (int i = 0; i < setsSpared.Count(); i++) - { - var set = setsSpared[i]; - var ch = notUsedChs[chOffIdx + i]; - set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}/冗余"; - //更新全局已使用通道 - allUsedCH.Add(ch.ChannelID); - } + var set = setsSpared[i]; + var ch = notUsedChs[chOffIdx + i]; + set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排):{curStrip.StripName}/通道:{ch.ChannelName}/冗余"; + //更新全局已使用通道 + allUsedCH.Add(ch.ChannelID); } #endregion @@ -908,10 +911,11 @@ namespace Learun.Application.Web.AppApi /// /// 找到下一个可用的端子排 /// + /// 电缆总set /// 所有的端子排 /// 使用过的channelId /// - private ec_PanelStripEntity FindNextAvailableTS(List TSs, List allUsedCH) + private ec_PanelStripEntity FindNextAvailableTS(int setCount,int setPreAssigned, List TSs, List allUsedCH) { foreach (var TS in TSs) { @@ -921,14 +925,25 @@ namespace Learun.Application.Web.AppApi double sparedRate = notUsedChs.Count * 1.0 / validChs.Count * 1.0; - if (sparedRate < 0.05) + if (sparedRate < 0.05 || notUsedChs.Count < setPreAssigned) { //没有空闲通道 next + //或者空闲通道不够放下这个电缆的所有set } else { TS.Channels = validChs.OrderBy(X => X.Channel_Seq).ToList(); var seq = TSs.IndexOf(TS); + + if (setCount > 10) + { + //另外如果电缆对数大于10对,即像12 * 2 * 0.75这种,无论它预分配了多少根电缆对,永远预留4个以下的空白通道。意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道,如果不够4个就留4个以下即可。 + if (notUsedChs.Count < 4) + { + //没有足够的空闲通道 next + continue; + } + } return TS;//找到了 }