This commit is contained in:
xingheng 2025-09-26 11:04:02 +08:00
parent ba7bbd2f2e
commit dc7269290f

View File

@ -422,10 +422,22 @@ namespace Learun.Application.Web.AppApi
cablesNeedAssigned = cablesNeedAssigned.Where(x => CableIds.Contains(x.CableID)).ToList();
#endregion
//涉及到哪些箱子
var allPanel = SqlSugarHelper.Db.Queryable<ec_PanelEntity>().AS(panelTable).
List<ec_PanelEntity> allPanel = SqlSugarHelper.Db.Queryable<ec_PanelEntity>().AS(panelTable).
InnerJoin<ec_enginedataEntity>((a, b) => a.EngineerDataID == b.EngineDataID).AS<ec_enginedataEntity>(tagTable).
InnerJoin<ec_objecttypeEntity>((a, b, c) => b.ObjectTypeID == c.ObjectTypeID).AS<ec_objecttypeEntity>(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<ec_enginedata_propertyEntity>().AS(propTable)
@ -514,6 +526,11 @@ namespace Learun.Application.Web.AppApi
var signalTb = ProjectSugar.TableName<ec_Wire_GroupEntity>(projId);
var allSignals = SqlSugarHelper.Db.Queryable<ec_Wire_GroupEntity>().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.32如果模块是通讯信号像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<ec_CableSetEntity> sets, List<ec_CableSetEntity> 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.32如果模块是通讯信号像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.32如果模块是通讯信号像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;//找到了
}
}