009_DI-Elec/Learun.Application.Web/AppApi/IOModuleApiController.cs

1384 lines
59 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using 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;
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 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.Linq;
using System.Web.Http;
using static Learun.Application.TwoDevelopment.ZZDT_EC.IO_WorkFlowService;
namespace Learun.Application.Web.AppApi
{
/// <summary>
/// IO模块By YuXH
/// </summary>
[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
/// <summary>
/// 根据模板自动创建端子排
/// </summary>
/// <param name="projId"></param>
/// <param name="panelId"></param>
/// <param name="iOType"></param>
private ec_PanelStripEntity CreatePanelStripByProfile2(string projId, string TSname, string panelId, GlobalEnum.IOType iOType)
{
return new ec_PanelStripEntity();
}
/// <summary>
/// 找到某一个预分配箱子 附近的某一个箱子。且io类型能匹配上
/// <param name="curPanelId"/>
/// <param name="frameLists"/>
/// <param name="allPanel"/>
/// <param name="allPanelProps">所有柜子的属性</param>
/// <param name="IOTypeOnCable">Digital,4-20mA,10v,pt100,pulse</param>
/// </summary>
private ec_PanelEntity FindPanelNearby(ec_CableEntity cableObj, List<FrameBll.FrameList> frameLists, List<ec_PanelEntity> allPanel,
Dictionary<string, List<ec_enginedata_propertyEntity>> 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这个单位。因为如果用的是mm400mm的肋位号似乎也太小了。
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这个单位。因为如果用的是mm400mm的肋位号似乎也太小了。
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;
}
/// <summary>
/// IO分配主界面查询查询所有的位置 - 采集箱 - 模块 - 通道
/// </summary>
/// <param name="projectId"></param>
/// <returns></returns>
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<TreeModel> treeList = new List<TreeModel>();
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());
}
/// <summary>
/// 根据ID拿。只查询ec panel表本身
/// </summary>
/// <param name="PanelID"></param>
/// <param name="projId"></param>
/// <returns></returns>
[HttpGet]
public IHttpActionResult GetPanel(string PanelID, string projId)
{
var res = ec_PanelBLL.GetEntity(projId, PanelID);
return Success(res);
}
/// <summary>
/// 根据EngineerDataID拿。包括set wire以及from to信息
/// </summary>
/// <param name="EngineerDataID"></param>
/// <param name="projId"></param>
/// <param name="OnlySelf"></param>
/// <param name="PreAssign"></param>
/// <returns></returns>
[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();
/// <summary>
/// 自动分配通道(点表信号自动分配)。
///
/// </summary>
/// <param name="projId"></param>
/// <param name="AcceptNearbyPanel"></param>
/// <param name="CableIds">需要分配的电缆cableid,不是enginedataId逗号分开</param>
/// <returns></returns>
[HttpPost]
public IHttpActionResult AutoAssignCable2Channel_step1(string projId, bool AcceptNearbyPanel, [FromBody] List<string> CableIds)
{
#region
var frameBll = new FrameBll();
var allFrames = frameBll.GetFrameList(projId);
var cbll = new ec_CableBLL();
var panelTable = ProjectSugar.TableName<ec_PanelEntity>(projId);
var stripTable = ProjectSugar.TableName<ec_PanelStripEntity>(projId);
var tagTable = ProjectSugar.TableName<ec_enginedataEntity>(projId);
var propTable = ProjectSugar.TableName<ec_enginedata_propertyEntity>(projId);
var typeTable = ProjectSugar.TableName<ec_objecttypeEntity>(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
//涉及到哪些箱子
var 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.).
ToList();//这里要过滤一下根据object type里的specialType而不是所有的panel
var allPanelProp = SqlSugarHelper.Db.Queryable<ec_enginedata_propertyEntity>().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<ec_PanelStripEntity>().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<List<ec_CableEntity>>("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<string>();
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<List<ec_CableEntity>>("IOModule_AutoAssign2Ch_" + projId, cablesNeedAssigned, CacheId.IOModule_AutoAssign2Ch);
return Success("OK");
#endregion
}
/// <summary>
/// 根据step1的初步采集箱判断情况来进行分配预览。
/// </summary>
/// <param name="projId"></param>
/// <returns></returns>
[HttpPost]
public IHttpActionResult AutoAssignCable2Channel_step2(string projId)
{
ICache redisObj = CacheFactory.CaChe();
var cablesNeedAssigned = redisObj.Read<List<ec_CableEntity>>("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch);
var setTb = ProjectSugar.TableName<ec_projectSettingsEntity>(projId);
var allSettings = SqlSugarHelper.Db.Queryable<ec_projectSettingsEntity>().AS(setTb).ToList();
//IO_CardProfile
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();
//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)
{
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
}
//var lastCableSystemAndIOType = cablesOnThisPanel.First().System + cablesOnThisPanel.First().PreAssignIOType;//用于判断是否是同一个组
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 流程图 读取有提前选好箱子的信号
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())
{
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.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
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
}
}
return Success(cablesNeedAssigned);
}
/// <summary>
/// 找到下一个可用的端子排
/// </summary>
/// <param name="TSs">所有的端子排</param>
/// <param name="allUsedCH">使用过的channelId</param>
/// <returns></returns>
private ec_PanelStripEntity FindNextAvailableTS(List<ec_PanelStripEntity> TSs, List<string> 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;//都没有
}
/// <summary>
/// 根据step2的预分配结果进行实际的分配修改数据库。
/// </summary>
/// <param name="projId"></param>
/// <param name="cables">传入有效的cable即可未成功分配的cable不需要</param>
/// <returns></returns>
[HttpPost]
public IHttpActionResult AutoAssignCable2Channel_step3(string projId, [FromBody] List<ec_CableEntity> cables)
{
//大原则:同一根电缆的信号不能跨采集箱,跨模块可以。
return Success(cables);
}
/// <summary>
/// 把电缆分配到空余的模块的通道上。
/// </summary>
/// <param name="projId"></param>
/// <param name="execute"></param>
/// <returns></returns>
[HttpPost]
public IHttpActionResult AssignCable2Channel(string projId, bool execute = false)
{
var asyncContent = Request.Content.ReadAsStringAsync().Result;
var cableIds = asyncContent.ToObject<List<string>>();
return Success("res");
}
/// <summary>
/// 查询所有需要预分配的电缆
/// </summary>
/// <param name="projId"></param>
/// <returns></returns>
[HttpGet]
public IHttpActionResult GetCablePreAssignPreview(string projId)
{
var bll = new ec_CableBLL();
var res = bll.GetCablesPreAssign(projId, null);
return Success(res);
}
/// <summary>
/// 查询所有的电缆
/// </summary>
/// <param name="projId"></param>
/// <param name="homerun">true或false</param>
/// <returns></returns>
[HttpGet]
public IHttpActionResult GetCables(string projId, bool homerun = true)
{
var res = ec_CableBLL.GetCables(projId, homerun);//这有个问题 如果一开始不知道要关联到那个通道 就不会有ec cable出来
return Success(res);
}
/// <summary>
/// PanelStrip参考库
/// </summary>
/// <param name="projId"></param>
/// <param name="OnlySelf">false时带上下面的通道和端子。true时就是返回端子排自己</param>
/// <returns></returns>
[HttpGet]
public IHttpActionResult GetPanelStrips(string projId, bool OnlySelf = false)
{
var res = ec_PanelStripBLL.GetList("{ProjectId:\"" + projId + "\",OnlySelf:\"" + OnlySelf + "\"}");
return Success(res);
}
/// <summary>
/// 在IO分配界面从左侧目录树中选择一个“端子排”后进行查询
/// </summary>
/// <param name="StripID"></param>
/// <param name="projId"></param>
/// <param name="OnlySelf">false时带上下面的通道和端子。true时就是返回端子排自己</param>
/// <returns></returns>
[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);
}
/// <summary>
/// 新增或者修改。
/// 新建相当于强行因为正常流程是和engineerdata一起新建出来的。
/// 改的话只是改location和端子排数量这些。常规属性依旧通过objectTypeAPI去做
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
/// <returns></returns>
[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);
}
}
/// <summary>
/// SaveConnections 专用
/// </summary>
private class Connections
{
public string ID { get; set; }
public List<ec_WireTerminalEntity> Conns { get; set; }
}
/// <summary>
/// 处理 接线关系同时对cableset和wire的个别属性进行修改
/// </summary>
/// <param name="projId"></param>
/// <returns></returns>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult SaveConnections(string projId)
{
try
{
var asyncContent = Request.Content.ReadAsStringAsync().Result;
var entity = asyncContent.ToObject<Connections>();
var res = entity.Conns;
new ec_WireTerminalBLL().SaveConnections(projId, ref res);
return Success(res);
}
catch (System.Exception E)
{
return Fail(E.Message);
}
}
/// <summary>
///
/// </summary>
/// <param name="projId"></param>
/// <returns></returns>
[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);
}
}
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
/// <returns></returns>
[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);
}
}
/// <summary>
/// 通过预设模式,批量创建端子排 通道 端子。此时strip数里 set数里已经根据profile给定好了。
/// </summary>
/// <param name="projId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult CreatePanelStripByProfile(string projId)
{
try
{
var asyncContent = Request.Content.ReadAsStringAsync().Result;
var entity = asyncContent.ToObject<ec_PanelStripEntity>();
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);
}
}
///// <summary>
///// 通过预设模式,批量创建端子排 端子(不需要了因为预设模式只有对IO有通道的那边才有用)
///// </summary>
///// <param name="entity"></param>
///// <param name="projId"></param>
//[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);
// }
//}
/// <summary>
/// GetCableByEngID先去判断这个cable是否已经有了IO Module这边的记录
/// 电缆-端子连接,从图面上选择一个电缆对象
/// </summary>
/// <param name="projId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult CreateCableByProfile(string projId)
{
try
{
var asyncContent = Request.Content.ReadAsStringAsync().Result;
var entity = asyncContent.ToObject<ec_CableEntity>();
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);
}
}
/// <summary>
/// 批量保存电缆的set wire 名字等
/// </summary>
/// <param name="projId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult SaveCables(string projId)
{
try
{
var asyncContent = Request.Content.ReadAsStringAsync().Result;
var entitys = asyncContent.ToObject<List<ec_CableEntity>>();
foreach (var entity in entitys)
{
ec_CableBLL.SaveEntity(projId, entity.CableID, entity);
}
return Success(entitys);
}
catch (System.Exception e)
{
return Fail(e.Message);
}
}
/// <summary>
/// 创建、修改 端子排和端子(一般是为非监测设备的端子排)
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
[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);
}
}
/// <summary>
/// 保存端子排 通道 端子的信息(不管信号和接线关系)。
/// 迁移通道也是这里。
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
[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_PanelStripEntity>();
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);
}
}
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
[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);
}
}
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
[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);
}
}
/// <summary>
/// 调端子排所属Panel
/// </summary>
/// <param name="StripID">端子排ID</param>
/// <param name="PanelID">PanelID</param>
/// <param name="ProjectId">项目ID</param>
[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);
}
}
/// <summary>
/// 调换电缆的from/to信息
/// </summary>
/// <param name="CableID">Cable的工程ID</param>
/// <param name="ProjectId">项目ID</param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult SwitchCableFromTo(string ProjectId)
{
try
{
var asyncContent = Request.Content.ReadAsStringAsync().Result;
var entityCol = asyncContent.ToObject<List<string>>();
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);
}
}
/// <summary>
/// 比如 移动通道时,进行保存
/// </summary>
/// <param name="entity"></param>
/// <param name="projId"></param>
/// <returns></returns>
[Obsolete]
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult SavePanelChannels(List<ec_PanelChannelEntity> 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);
}
}
/// <summary>
/// 根据某个数据字典的编号来。默认有个id=1的枚举
/// </summary>
/// <param name="ProjectId"></param>
/// <returns></returns>
private List<ec_dataitemdetailEntity> 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<ec_dataitemdetailEntity> frameLists = new List<ec_dataitemdetailEntity>();
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;
}
}
/// <summary>
/// 位置。缺省都放到“默认”下
/// </summary>
/// <param name="ProjectId"></param>
/// <returns></returns>
[HttpGet]
public IHttpActionResult GetLocationList(string ProjectId)
{
var RES = GetLocList(ProjectId);
if (RES != null)
{
return Success(RES);
}
else
{
return Fail("未找到合适的数据字典,可以当做位置");
}
}
/// <summary>
/// 根据id来删除
/// </summary>
/// <param name="keyValue"></param>
/// <param name="ProjectId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult DeletePanel(string PanelID, string ProjectId)
{
new ec_enginedataBLL().DeleteEntity(PanelID, ProjectId);
return Success("删除成功!");
}
/// <summary>
/// 根据id来删除
/// </summary>
/// <param name="CableID"></param>
/// <param name="ProjectId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult DeleteCableProfile(string CableID, string ProjectId)
{
ec_CableBLL.DeleteEntity(ProjectId, CableID);
return Success("OK");
}
/// <summary>
/// 根据id来删除
/// </summary>
/// <param name="keyValue"></param>
/// <param name="ProjectId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult DeletePanelStrip(string StripID, string ProjectId)
{
ec_PanelStripBLL.DeleteEntity(ProjectId, StripID);
return Success("删除成功!");
}
/// <summary>
/// 根据id来删除
/// </summary>
/// <param name="ChannelID"></param>
/// <param name="ProjectId"></param>
[HttpPost]
[HandlerApiLogin(FilterMode.Enforce)]
public IHttpActionResult DeletePanelChannel(string ChannelID, string ProjectId)
{
ec_PanelChannelBLL.DeleteEntity(ProjectId, ChannelID);
return Success("OK");
}
}
/// <summary>
///
/// </summary>
//public class Panel_Location
//{
/// <summary>
///
/// </summary>
//public string ParentID { get; set; }
/// <summary>
///
/// </summary>
//public string Id { set; get; }
/// <summary>
/// 所在数据字典的ID
/// </summary>
// public string DataItemId { set; get; }
/// <summary>
///
/// </summary>
//public string Name { get; set; }
/// <summary>
/// 数据字典里的code
/// </summary>
//public string Desc { get; set; }
//}
}