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

2065 lines
98 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.Math;
using DocumentFormat.OpenXml.Spreadsheet;
using Learun.Application.Organization;
using Learun.Application.TwoDevelopment.ZZDT_EC;
using Learun.Application.TwoDevelopment.ZZDT_EC.Frame;
using Learun.Cache.Base;
using Learun.Cache.Factory;
using Learun.Loger;
using Learun.Util;
using Learun.Util.SqlSugar;
using log4net.Config;
using Microsoft.Practices.ObjectBuilder2;
using Newtonsoft.Json;
using NPOI.POIFS.Crypt;
using NPOI.SS.Formula.Functions;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Pipelines.Sockets.Unofficial.Arenas;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web.Http;
using System.Windows;
using System.Windows.Input;
using static Learun.Application.TwoDevelopment.ZZDT_EC.IO_WorkFlowService;
using static Learun.Application.Web.Areas.ZZDT_EC.Controllers.ec_objecttypeController;
namespace Learun.Application.Web.AppApi
{
/// <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="panelObj"></param>
/// <param name="seq"></param>
/// <param name="TSname"></param>
/// <param name="iOType"></param>
private ec_PanelStripEntity CreatePanelStripByProfile2(string projId, ec_PanelEntity panelObj, int seq, GlobalEnum.IOType iOType)
{
var setTb = ProjectSugar.TableName<ec_projectSettingsEntity>(projId);
var allSettings = SqlSugarHelper.Db.Queryable<ec_projectSettingsEntity>().AS(setTb).ToList();
allSettings = allSettings.FindAll(x => x.SettingName.StartsWith(GlobalObject.projSetting_IOCardProfile + iOType.ToString()));
//IO_CardProfile
//IO_CardProfile_DO_TermNoPerCh
//IO_CardProfile_DO_CHNoPerStrip
//IO_CardProfile_DO_ChNamePrefix
//IO_CardProfile_DO_ChNameStartIndex
var sName = GlobalObject.projSetting_IOCardProfile + iOType.ToString() + "_TermNoPerCh";
var TermNoPerCh = allSettings.FirstOrDefault(x => x.SettingName == sName)?.SettingValue;
sName = GlobalObject.projSetting_IOCardProfile + iOType.ToString() + "_CHNoPerStrip";
var CHNoPerStrip = allSettings.FirstOrDefault(x => x.SettingName == sName)?.SettingValue;
sName = GlobalObject.projSetting_IOCardProfile + iOType.ToString() + "_ChNamePrefix";
var ChNamePrefix = allSettings.FirstOrDefault(x => x.SettingName == sName)?.SettingValue;
if (int.TryParse(TermNoPerCh, out int iTermNoPerCh))
{
//err
}
if (int.TryParse(CHNoPerStrip, out int iCHNoPerStrip))
{
//err
}
var newTs = new ec_PanelStripEntity()
{
IO_TYPE = iOType.ToString(),
PanelID = panelObj.PanelID,
Panel_Strip_Seq = seq,
StripName = "TS_" + iOType.ToString() + "_" + seq,
TagNumber = "CreatePanelStripByProfile2"
};
newTs.Create();
for (int i = 0; i < iCHNoPerStrip; i++)
{
var newCh = new ec_PanelChannelEntity()
{
ChannelName = ChNamePrefix + (i + 1).ToString(),
Channel_Seq = i + 1,
StripID = newTs.StripID,
};
newCh.Create();
newTs.Channels.Add(newCh);
}
return newTs;
}
/// <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="projectId"></param>
/// <param name="flg">是否为真实结果。step2时为falsestep3后为true</param>
[HttpGet]
public void AutoAssignCable2Channel_ResExport(string projectId, bool flg)
{
ICache redisObj = CacheFactory.CaChe();
var cablesNeedAssigned = redisObj.Read<List<ec_CableEntity>>("IOModule_AutoAssign2Ch_" + projectId, CacheId.IOModule_AutoAssign2Ch);
var PanelAssigned = redisObj.Read<List<ec_PanelEntity>>("IOModule_AutoAssign2ChByPanel_" + projectId, CacheId.IOModule_AutoAssign2Ch);
var bytes = new byte[] { };
try
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var package = new ExcelPackage())//新建
{
var sheet = package.Workbook.Worksheets.Add("已经分配的");
sheet.Cells[1, 1].Value = "电缆位号";
sheet.Cells[1, 2].Value = "电缆对";
sheet.Cells[1, 3].Value = "信号类型";
sheet.Cells[1, 4].Value = "预分配箱子";
sheet.Cells[1, 5].Value = "实际分配箱子";
sheet.Cells[1, 6].Value = "实际分配端子排";
sheet.Cells[1, 7].Value = "备注";
int rowIdx = 2;
#region ByCable
foreach (var cable in cablesNeedAssigned)
{
sheet.Cells[rowIdx, 1].Value = cable.TagNumber;
rowIdx++;
foreach (var set in cable.Sets)
{
sheet.Cells[rowIdx, 2].Value = set.CableSetName;
sheet.Cells[rowIdx, 7].Value = set.ConnectionInfo;
rowIdx++;
}
rowIdx = rowIdx + 2;
}
#endregion
#region ByPanel
sheet = package.Workbook.Worksheets.Add("模块视角");
sheet.Cells[1, 1].Value = "采集箱位号";
sheet.Cells[1, 2].Value = "模块名字";
sheet.Cells[1, 3].Value = "IO类型";
sheet.Cells[1, 4].Value = "通道名字";
sheet.Cells[1, 5].Value = "通道顺序";
sheet.Cells[1, 6].Value = "关联电缆";
sheet.Cells[1, 7].Value = "关联Set";
sheet.Cells[1, 8].Value = "关联信号";
sheet.Cells[1, 9].Value = "备注";
rowIdx = 2;
foreach (var p in PanelAssigned)
{
var newTS = p.strips.FindAll(x => x.Channels.Any(y => !string.IsNullOrEmpty(y.ConnectionInfo)));
foreach (var ts in newTS)
{
foreach (var ch in ts.Channels)
{
sheet.Cells[rowIdx, 1].Value = p.TagNumber;
sheet.Cells[rowIdx, 2].Value = ts.StripName;
sheet.Cells[rowIdx, 3].Value = ts.IO_TYPE;
sheet.Cells[rowIdx, 4].Value = ch.ChannelName;
sheet.Cells[rowIdx, 5].Value = ch.Channel_Seq;
sheet.Cells[rowIdx, 6].Value = ch.assignCable;
sheet.Cells[rowIdx, 7].Value = ch.assignCableSet;
sheet.Cells[rowIdx, 8].Value = ch.ConnectionInfo;
rowIdx++;
}
}
rowIdx = rowIdx + 2;
}
#endregion
package.Save();
bytes = package.GetAsByteArray();
}
}
catch (Exception ex)
{
log4net.LogManager.GetLogger("ERROR").Error("ec_PanelChannelBLLIOModuleExportExcel 监控系统表导出" + ex.Message + ex.StackTrace);
bytes = System.Text.Encoding.UTF8.GetBytes(ex.Message + ex.StackTrace);
}
var stream = new MemoryStream(bytes);
FileDownHelper.DownLoad(stream, $"自动分配结果{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx");//自动化平台导出excel
}
/// <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
//涉及到哪些箱子
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)
.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 signalTb = ProjectSugar.TableName<ec_Wire_GroupEntity>(projId);
var allSignals = SqlSugarHelper.Db.Queryable<ec_Wire_GroupEntity>().AS(signalTb).ToList();
var connTb = ProjectSugar.TableName<ec_WireTerminalEntity>(projId);
var termTb = ProjectSugar.TableName<ec_PanelStripTermEntity>(projId);
var allConnedTerms = SqlSugarHelper.Db.Queryable<ec_WireTerminalEntity>().AS(connTb)
.InnerJoin<ec_PanelStripTermEntity>((a, b) => a.TermID == b.TermID).AS<ec_PanelStripTermEntity>(termTb)
.Select((a, b) => b.ChannelID).Distinct().ToList();
//包括2部分1是已经被信号占用的通道2是已经被接线端子占用的通道
var allUsedCHBySignalOrSet = allSignals.Where(x => !string.IsNullOrEmpty(x.ChannelID)).Select(x => x.ChannelID).Distinct().ToList();
allUsedCHBySignalOrSet.AddRange(allConnedTerms);
//??这里有问题。通道是否被占用需要看signal和set双重在io分配界面
//1. 信号有, 电缆set有占了
//2.信号no电缆set有占了
//3.信号有电缆setno没占
//4.信号no电缆setno没占
//1.2 流程图 分组原则为同一信号类型、同一系统的为一组
var cablesGrouped = cablesNeedAssigned.OrderBy(x => x.AssignedPanel?.PanelID).ThenBy(x => x.PreAssignIOType).ThenBy(x => x.System).ToList();
var cNotPanel = cablesGrouped.FindAll(x => x.AssignedPanel == null);
cablesGrouped = cablesNeedAssigned.FindAll(x => x.AssignedPanel != null);
//cablesGrouped = cablesGrouped.Where(x => x.Sets != null && x.Sets.Count() > 0 && x.AssignedPanel != null).ToList();//过滤掉没有set的或者没有找到箱子的
//cablesGrouped = cablesGrouped.Where(x => x.Sets.Where(xx => !string.IsNullOrEmpty(xx.PreAssignGroup_Desc)).Count() > 0).ToList();//过滤掉set没有分配信号的
var allPanelIds = cablesGrouped.Select(x => x.AssignedPanel).Select(x => x.PanelID).Distinct().ToList();
var stripBll = new ec_PanelStripBLL();
var allStrips = stripBll.GetList("{ProjectId:\"" + projId + "\"}", OnlySelf: false)
.Where(x => allPanelIds.Contains(x.PanelID))
.GroupBy(x => x.PanelID)
.ToDictionary(x => x.Key, x => x.ToList());//带出strip下的channel
var PanelResultPreview = new List<ec_PanelEntity>();//为了看by panel的预览情况有时候光by cable看不出问题
foreach (var c in cNotPanel)
{
foreach (var set in c.Sets)
{
set.ConnectionInfo = "err没有找到合适的采集箱";
}
}
foreach (var curPanelId in allPanelIds)
{
int newTSSeq = 10001;
var existedStrips = allStrips[curPanelId];//已经存在的所有模块
var cablesOnThisPanel = cablesGrouped.Where(x => x.AssignedPanel.PanelID == curPanelId).ToList();
if (cablesOnThisPanel == null || cablesOnThisPanel.Count == 0) continue;//next panel
var lastUsedStrip = (ec_PanelStripEntity)null;
var lastUsedPanel = new ec_PanelEntity();
lastUsedPanel.strips = allStrips[curPanelId];//已经存在的所有模块
foreach (var cable in cablesOnThisPanel)
{
//1.2.2 分组原则为同一信号类型、同一系统的为一组系统属性从电缆的from端上的设备中取设备的系统同组的优先放到同一个箱子的同一个模块里面
//如果一组放完后发现模块还有多余的通道可以放则下一个系统继续从这个模块开始分配。
//???总感觉这句话,总结后:可以无脑用上一个模块,直到模块满了再用下一个模块。
#region
//bool sameGroup = true;
//if (lastCableSystemAndIOType != cable.System + cable.PreAssignIOType)
//{
// sameGroup = false;//换组了
//}
#endregion
//1.2 流程图 读取有提前选好箱子的信号
var setsSpared = cable.Sets.Where(x => string.IsNullOrEmpty(x.PreAssignGroup_Desc) || string.IsNullOrEmpty(x.PreAssignInOrOut)).ToList();
var setsIn = cable.Sets.Where(x => !string.IsNullOrEmpty(x.PreAssignGroup_Desc) && x.PreAssignInOrOut == SWS.Share.Enum.inOrOut..ToString()).ToList();
var setsOut = cable.Sets.Where(x => !string.IsNullOrEmpty(x.PreAssignGroup_Desc) && x.PreAssignInOrOut == SWS.Share.Enum.inOrOut..ToString()).ToList();
#region 1.2.4
if (cable.PreAssignIOType.ToLower() == GlobalEnum.signalType.Digital.ToString().ToLower())
{
if (setsIn.Count > 0 && setsOut.Count > 0)
{
foreach (var set in setsIn)
{
set.ConnectionInfo = "errdigital类型的电缆无法同时配置输入和输出。";
}
foreach (var set in setsOut)
{
set.ConnectionInfo = "errdigital类型的电缆无法同时配置输入和输出。";
}
continue;
//from cjj 25 09 23 wechat:一根电缆可能会出现既有输入也有输出,如果碰到就放到两个端子排里面,公共端不会出现一个输出,一个输入的
}
}
#endregion
#region inputNew
if (setsIn.Count > 0)
{
var resIn = AutoAssignCore(GlobalEnum.inOrOut., setsIn);
}
#endregion
#region output
else if (setsOut.Count > 0)
{
var resOut = AutoAssignCore(GlobalEnum.inOrOut., setsOut);
}
else
{
//all zero
foreach (var set in cable.Sets.Where(x => !setsSpared.Select(c => c.CableSetID).Contains(x.CableSetID)))
{
set.ConnectionInfo = "err信号描述为空";
}
foreach (var set in setsSpared)
{
set.ConnectionInfo = "err电缆无任一set被分配";
}
}
#endregion
//in 和 out都会执行这个
bool AutoAssignCore(GlobalEnum.inOrOut inOrOut, List<ec_CableSetEntity> sets)
{
GlobalEnum.IOType ioTypeOnC = default;
switch (cable.PreAssignIOType.ToLower())
{
case "digital":
//数字量
if (inOrOut == GlobalEnum.inOrOut.)
{
ioTypeOnC = GlobalEnum.IOType.DI;
}
else
{
ioTypeOnC = GlobalEnum.IOType.DO;
}
break;
case "4~20ma":
//模拟量4-20mA
if (inOrOut == GlobalEnum.inOrOut.)
{
ioTypeOnC = GlobalEnum.IOType.AI;
}
else
{
ioTypeOnC = GlobalEnum.IOType.AO;
}
break;
case "10v":
ioTypeOnC = GlobalEnum.IOType.TenVolt;
break;
case "pt100":
ioTypeOnC = GlobalEnum.IOType.PT100;
break;
case "pulse":
ioTypeOnC = GlobalEnum.IOType.PULSE;
break;
default:
//通讯类 485 422啥的
return false;
}
var matchedStrips = existedStrips.Where(x => x.IO_TYPE == ioTypeOnC.ToString()).ToList();//这个电缆下符合的模块
if (matchedStrips != null && lastUsedStrip != null && lastUsedStrip.IO_TYPE == ioTypeOnC.ToString())
{
//1.2.2 优先使用上一个模块,直到模块满了再用下一个模块。
matchedStrips.Remove(lastUsedStrip);
matchedStrips.Insert(0, lastUsedStrip);//
}
if (matchedStrips == null || matchedStrips.Count == 0)
{
#region NewTS
//1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得
var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC);//当前采集箱无模块,需要新建
matchedStrips.Add(newTS);
#endregion
}
string PanelName = cable.AssignedPanel.TagNumber;//当前电缆预分配的箱子名称
if (sets.Count == 0) return false;
//1.2 流程图 箱子里是否已经存在端子排io匹配
List<ec_PanelChannelEntity> usedChs = new List<ec_PanelChannelEntity>();
List<ec_PanelChannelEntity> notUsedChs = new List<ec_PanelChannelEntity>();
#region 1.2
#region old
//if (cable.Sets.Count > 10)
//{
// //另外如果电缆对数大于10对即像12 * 2 * 0.75这种无论它预分配了多少根电缆对永远预留4个以下的空白通道。意思就是一个模块里面够4个或4个以上空白通道就留4个空白通道如果不够4个就留4个以下即可。
// #region FindNextAvailableTS可能多个
// //还分2种情况判断模块是否符合
// //case1. 占满可用通道后还剩至少一个预分配的set和spared的set。 //这种时候要spared不用考虑
// //case2. 占满可用通道后或者没占满通道预分配set已经没了只剩下spared的set。 //这种时候要确保spared也能放下
// bool NeedNextTS = false;
// do
// {
// #region FindNextAvailableTS
// var availableTS = new List<ec_PanelStripEntity>();
// foreach (var TS in matchedStrips)
// {
// var allCh = TS.Channels;
// //被占用的(wt里有或者信号里或有或者被锁定的都算占用
// usedChs = allCh.Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList();
// notUsedChs = allCh.Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
// if (notUsedChs.Count < sets.Count)
// {
// //case1能顺利接完set还有多
// //这种时候不需要考虑spared
// }
// else
// {
// //case2,占满可用通道后或者没占满通道预分配set已经没了只剩下spared的set
// //想办法留出4个
// //这种时候要确保spared也能放下
// if (notUsedChs.Count < sets.Count + setsSpared.Count)
// {
// //放不下,换下一个模块
// continue;
// }
// var sparedSetFor10 = notUsedChs.Count - sets.Count - setsSpared.Count;//16-9-5=2
// if (sparedSetFor10 > 4)
// {
// //固定流出后面4个相当于不要了
// var last4 = allCh.Skip(allCh.Count - 4).ToList();
// usedChs = allCh.Take(allCh.Count - 4).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList();
// usedChs.AddRange(last4);
// notUsedChs = allCh.Take(allCh.Count - 4).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
// }
// else
// {
// //不够4个就留多少是多少
// var lastN = allCh.Skip(allCh.Count - sparedSetFor10).ToList();
// usedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList();
// usedChs.AddRange(lastN);
// notUsedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
// }
// }
// //1.2 流程图 空的通道数够不够
// double sparedRate = notUsedChs.Count * 1.0 / allCh.Count * 1.0;
// if (sparedRate < 0.05)
// {
// //没有空闲通道 next
// //或者空闲通道不够放下这个电缆的所有set
// }
// else
// {
// TS.Channels = allCh.OrderBy(X => X.Channel_Seq).ToList();//不能像之前一样过滤掉,否则下一个电缆进来时,总数就不对了。
// TS.ChannelsSpared = notUsedChs.Count;
// TS.ChannelsUsed = usedChs.Count;
// availableTS.Add(TS);//所有5%以上空闲通道的模块
// break;
// }
// }
// #endregion
// #region NewTS
// if (availableTS.Count() == 0)
// {
// //1.2 流程图 根据信号数里自动新建端子排,端子排通道数里根据箱子模板中的默认值获得
// var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC);
// //matchedStrips.Add(newTS);
// var allCh = newTS.Channels;
// notUsedChs = newTS.Channels.ToList();
// newTS.ChannelsSpared = notUsedChs.Count;
// newTS.ChannelsUsed = 0;
// usedChs = new List<ec_PanelChannelEntity>();//新建的没有被占用的
// availableTS.Add(newTS);
// if (notUsedChs.Count < sets.Count)
// {
// //case1能顺利接完set还有多
// //这种时候不需要考虑spared
// }
// else
// {
// //case2,占满可用通道后或者没占满通道预分配set已经没了只剩下spared的set
// //想办法留出4个
// //这种时候要确保spared也能放下
// if (notUsedChs.Count < sets.Count + setsSpared.Count)
// {
// //放不下,换下一个模块
// continue;
// }
// var sparedSetFor10 = notUsedChs.Count - sets.Count - setsSpared.Count;//16-9-5=2
// if (sparedSetFor10 > 4)
// {
// //固定流出后面4个相当于不要了
// var last4 = allCh.Skip(allCh.Count - 4).ToList();
// usedChs = allCh.Take(allCh.Count - 4).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList();
// usedChs.AddRange(last4);
// notUsedChs = allCh.Take(allCh.Count - 4).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
// }
// else
// {
// //不够4个就留多少是多少
// var lastN = allCh.Skip(allCh.Count - sparedSetFor10).ToList();
// usedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList();
// usedChs.AddRange(lastN);
// notUsedChs = allCh.Take(allCh.Count - sparedSetFor10).Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
// }
// }
// }
// #endregion
// lastUsedStrip = availableTS.Last();
// if (notUsedChs.Count < sets.Count)
// {
// //case1分配完后还有多的set和可能的spared
// //先这部分填完
// //到5%为止的数量
// var countOnThisTS = Math.Round(0.5 + notUsedChs.Count * 0.95);
// for (int i = 0; i < countOnThisTS; i++)
// {
// var set = sets[i];
// var ch = notUsedChs[i];
// if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2")
// {
// set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}";
// }
// else
// {
// set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}";
// }
// ch.FakeGroupDesc = set.PreAssignGroup_Desc;
// ch.FakeSignalType = set.IOType.ToString();
// ch.lock_flg = 1;
// set.IsConned = true;
// //更新全局已使用通道
// allUsedCHBySignalOrSet.Add(ch.ChannelID);
// }
// //set会剩
// NeedNextTS = true;
// }
// else
// {
// //case2分配完后没有多的set了可能还有spared
// //上面已经判断过了确保spared也是够的
// var countMin = Math.Min(sets.Count, notUsedChs.Count);
// for (int i = 0; i < countMin; i++)
// {
// var set = sets[i];
// var ch = notUsedChs[i];
// if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2")
// {
// set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}";
// }
// else
// {
// set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}";
// }
// ch.FakeGroupDesc = set.PreAssignGroup_Desc;
// ch.FakeSignalType = set.IOType.ToString();
// ch.lock_flg = 1;
// set.IsConned = true;
// //更新全局已使用通道
// allUsedCHBySignalOrSet.Add(ch.ChannelID);
// }
// #region spared
// for (int i = 0; i < setsSpared.Count(); i++)
// {
// var set = setsSpared[i];
// var ch = notUsedChs[countMin + i];
// if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2")
// {
// set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余";
// }
// else
// {
// set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余";
// }
// ch.FakeGroupDesc = "预留";
// ch.lock_flg = 1;
// //更新全局已使用通道
// allUsedCHBySignalOrSet.Add(ch.ChannelID);
// }
// NeedNextTS = false;
// #endregion
// }
// sets = sets.Where(x => !x.IsConned).ToList();//移除已经分配过的set
// } while (NeedNextTS);
// #endregion
//}
//else
//{
//5%的空白通道
#endregion
#region FindNextAvailableTS
//还分2种情况判断模块是否符合
//case1. 占满可用通道后还剩至少一个预分配的set和spared的set。 //这种时候要spared不用考虑
//case2. 占满可用通道后或者没占满通道预分配set已经没了只剩下spared的set。 //这种时候要确保spared也能放下
//case3, 刚好只有spared可能多
bool NeedNextTS = false;
#region FindNextAvailableTS
var trueAvailableChs = 0;
var sparedButCanNotUsedChs = 0;//需要特意预留的通道,
int idx = 0;
while (idx < matchedStrips.Count)
{
NeedNextTS = false;
var TS = matchedStrips[idx];
var allCh = TS.Channels;
if (allCh.Count == 0)
{
NeedNextTS = true;
//同时又是最后一个了
if (idx == matchedStrips.Count - 1)
{
var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC);//当前ts无ch需要新建
if (newTS.Channels.Count() < setsSpared.Count + 1)//1代表至少要放一个set
{
//有问题了 panel的io模板估计会导致无限循环了
break;
}
matchedStrips.Add(newTS);
}
idx++; continue;//本模块没有一个ch否则后面 5% 会除以0
}
//被占用的(wt里有或者信号里或有或者被锁定的都算占用
usedChs = allCh.Where(x => allUsedCHBySignalOrSet.Contains(x.ChannelID) || x.lock_flg == 1).ToList();
notUsedChs = allCh.Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
trueAvailableChs = 0;
var ChNeedConn = 0;
var SparedNeedConn = 0;
//分3种情况确认具体要接的ch个数和是否需要下一个ts
if (cable.CableClass.ToLower() == SWS.Share.Enum.cableClass.homerun.ToString())
{
//1.2.32 如果模块是通讯信号像RS485这种就是通讯信号则不用管预留空白通道这个事情看到有空的通道就放。
#region
trueAvailableChs = notUsedChs.Count;
#endregion
if (trueAvailableChs < sets.Count)
{
//case1能顺利接完set还有多,还要再do循环一次,多余的set和spared都要放到下一个模块
NeedNextTS = true;
ChNeedConn = trueAvailableChs; SparedNeedConn = 0;
}
else if (trueAvailableChs == sets.Count)
{
//case3,刚好只有spared可能多
ChNeedConn = trueAvailableChs;
SparedNeedConn = 0; //homerun不用考虑预留一个set去配合后续的spared
}
else
{
ChNeedConn = sets.Count;
SparedNeedConn = 0;
}
}
else
{
#region (
//1.2 流程图 空的通道数够不够
if (cable.Sets.Count > 10)
{
//1.2.3 空白通道原则另外如果电缆对数大于10对即像12*2*0.75这种无论它预分配了多少根电缆对永远预留4个以下的空白通道。
if (notUsedChs.Count < 4)
{
//可以认为这个ts不可用了
trueAvailableChs = 0;
sparedButCanNotUsedChs = notUsedChs.Count;
notUsedChs.ForEach(x => x.lock_flg = 1);//全部标记为不可用
}
else
{
//all 16used 7notused9 砍去4
// 1. 计算起始索引
int startIndex = Math.Max(0, notUsedChs.Count - 4);
// 2. 计算要截取的数量(从起始索引到末尾的元素数)
int takeCount = notUsedChs.Count - startIndex;
// 3. 截取最后4个元素
var lastFour = notUsedChs.GetRange(startIndex, takeCount);//最后4个给不可用并且这4个也要被标记为不能使用
lastFour.ForEach(x => x.lock_flg = 1);//标记为不可用
usedChs.AddRange(lastFour);
notUsedChs = allCh.Where(x => !usedChs.Select(c => c.ChannelID).Contains(x.ChannelID)).ToList();
trueAvailableChs = notUsedChs.Count;
sparedButCanNotUsedChs = 4;
}
}
else
{
//5%
double sparedRate = notUsedChs.Count * 1.0 / allCh.Count * 1.0;
if (sparedRate < 0.05)
{
NeedNextTS = true;
trueAvailableChs = 0;
sparedButCanNotUsedChs = notUsedChs.Count;
notUsedChs.ForEach(x => x.lock_flg = 1);//全部标记为不可用
}
else
{
sparedButCanNotUsedChs = allCh.Count - FindMaxNumberChannel(allCh.Count);
// 1. 计算起始索引
int startIndex = Math.Max(0, notUsedChs.Count - sparedButCanNotUsedChs);
// 2. 计算要截取的数量(从起始索引到末尾的元素数)
int takeCount = notUsedChs.Count - startIndex;
// 3. 截取最后4个元素
var lastFour = notUsedChs.GetRange(startIndex, takeCount);//最后4个给不可用并且这4个也要被标记为不能使用
lastFour.ForEach(x => x.lock_flg = 1);//标记为不可用
trueAvailableChs = notUsedChs.Count - sparedButCanNotUsedChs;//真正能用的没接过的然后去掉5%
}
}
#endregion
if (trueAvailableChs < sets.Count)
{
//case1能顺利接完set还有多,还要再do循环一次,多余的set和spared都要放到下一个模块
NeedNextTS = true;
ChNeedConn = trueAvailableChs; SparedNeedConn = 0;
}
else if (trueAvailableChs == sets.Count)
{
//case3,刚好只有spared可能多
if (setsSpared.Count > 0)
{
if (sets.Count == 1)
{
//避免死循环
ChNeedConn = 1;
NeedNextTS = false;
SparedNeedConn = trueAvailableChs - 1;
}
else
{
//自己的感觉非客户word需求里的原话spared不能自己单独占用一个模块
NeedNextTS = true;
ChNeedConn = trueAvailableChs - 1;//留一个给spared
SparedNeedConn = 0;
}
}
else
{
ChNeedConn = trueAvailableChs; SparedNeedConn = 0;
}
}
else
{
//maxCh > sets.Count
//case2,占满可用通道后或者没占满通道预分配set已经没了只剩下spared的set
if (setsSpared.Count == 0)
{
//ok
ChNeedConn = sets.Count; SparedNeedConn = 0;
}
//这种时候要确保spared也能放下
else if (trueAvailableChs < sets.Count + setsSpared.Count)
{
if (sets.Count == 1)
{
//避免死循环
ChNeedConn = 1;
NeedNextTS = false;
SparedNeedConn = trueAvailableChs - 1;
}
else
{
//自己的感觉非客户word需求里的原话spared不能自己单独占用一个模块
ChNeedConn = sets.Count - 1;//留一个给spared。如果sets.COUNT只有1个这种情况就会死循环了
NeedNextTS = true;
SparedNeedConn = 0;
}
}
else
{
//ok,set和spared都能放下
ChNeedConn = sets.Count;
SparedNeedConn = setsSpared.Count;
}
}
}
//到这里,说明本模块至少都是可用的
TS.Channels = allCh.OrderBy(X => X.Channel_Seq).ToList();//不能像之前一样过滤掉,否则下一个电缆进来时,总数就不对了。
lastUsedStrip = TS;
#region conn
for (int i = 0; i < ChNeedConn; i++)
{
var set = sets[i];
var ch = notUsedChs[i];
ch.assignCable = cable.TagNumber;
ch.assignCableSet = set.CableSetName + " / " + set.CableSetSeq;
ch.ConnectionInfo = $"信号:{set.PreAssignGroup_Desc}/信号类型:{set.PreAssignIOTypeDetail}/传感器:{set.PreAssignSensorCode}";
if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2")
{
set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}";
}
else
{
set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}";
}
ch.FakeGroupDesc = set.PreAssignGroup_Desc;
ch.FakeSignalType = set.IOType.ToString();
ch.lock_flg = 1;
set.IsConned = true;
//更新全局已使用通道
allUsedCHBySignalOrSet.Add(ch.ChannelID);
}
#endregion
#region spared
for (int i = 0; i < SparedNeedConn; i++)
{
var set = setsSpared[i];
var ch = notUsedChs[ChNeedConn + i];
ch.assignCable = cable.TagNumber;
ch.assignCableSet = set.CableSetName + " / " + set.CableSetSeq + "/冗余";
ch.ConnectionInfo = $"信号:{set.PreAssignGroup_Desc}/信号类型:{set.PreAssignIOTypeDetail}/传感器:{set.PreAssignSensorCode}";
if (lastUsedStrip.TagNumber == "CreatePanelStripByProfile2")
{
set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(自动创建){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余";
}
else
{
set.ConnectionInfo = $"采集箱:{PanelName}/模块(端子排)(原本存在){lastUsedStrip.StripName}/通道:{ch.ChannelName}/冗余";
}
ch.lock_flg = 1;
//更新全局已使用通道
allUsedCHBySignalOrSet.Add(ch.ChannelID);
}
#endregion
#region
if (sparedButCanNotUsedChs > 0)
{
Console.WriteLine("");
}
#endregion
//shi否要继续
TS.ChannelsSpared = notUsedChs.Where(x => x.lock_flg != 1).Count();
TS.ChannelsUsed = allCh.Count - TS.ChannelsSpared;// usedChs.Count + (notUsedChs.Where(x => x.lock_flg == 1).Count());
//var xx = lastUsedPanel.strips;
#region panel record
if (ChNeedConn > 0 || SparedNeedConn > 0)
{
//记录本模块被使用过
var idx2 = lastUsedPanel.strips.FindIndex(ts => ts.StripID == lastUsedStrip.StripID);
if (idx2 != -1)
{
lastUsedPanel.strips[idx2] = lastUsedStrip;
}
else
{
lastUsedPanel.strips.Add(lastUsedStrip);
}
}
#endregion
if (NeedNextTS)
{
sets = sets.Where(x => !x.IsConned ?? false).ToList();//移除已经分配过的set
//同时又是最后一个了
if (idx == matchedStrips.Count - 1)
{
var newTS = CreatePanelStripByProfile2(projId, cable.AssignedPanel, newTSSeq++, ioTypeOnC);//还有set需要接需要新建
if (newTS.Channels.Count() < setsSpared.Count + 1)//1代表至少要放一个set
{
//有问题了 panel的io模板估计会导致无限循环了
break;
}
matchedStrips.Add(newTS);
}
idx++; continue;// 需要下一个模块接着放本电缆
// 手动递增索引,避免无限循环
}
else
{
break;
}
}
#endregion
#endregion
//}
#endregion
return true;
}
}
PanelResultPreview.Add(lastUsedPanel);
}
//必要的数据存入redis以便后续步骤使用
redisObj.Remove("IOModule_AutoAssign2Ch_" + projId, CacheId.IOModule_AutoAssign2Ch);
redisObj.Write<List<ec_CableEntity>>("IOModule_AutoAssign2Ch_" + projId, cablesNeedAssigned, CacheId.IOModule_AutoAssign2Ch);
redisObj.Remove("IOModule_AutoAssign2ChByPanel_" + projId, CacheId.IOModule_AutoAssign2Ch);
redisObj.Write<List<ec_PanelEntity>>("IOModule_AutoAssign2ChByPanel_" + projId, PanelResultPreview, CacheId.IOModule_AutoAssign2Ch);
return Success(cablesNeedAssigned);
}
/// <summary>
/// 找到满足5%空闲通道的最大数
/// </summary>
/// <param name="ChCount">模块的所有通道数</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="InvalidOperationException"></exception>
static int FindMaxNumberChannel(int ChCount)
{
if (ChCount < 1)
{
throw new ArgumentException("模块数量必须大于等于1", nameof(ChCount));
}
// 从A-1开始向下寻找
for (int i = 0; i < ChCount; i++)
{
// 检查是否大于5%
if ((double)i / ChCount < 0.05 && (double)(i + 1) / ChCount > 0.05)
{
return ChCount - i;
}
}
return ChCount;
}
/// <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; }
//}
}