业务流.全流程跟踪.源单和下游单显示不同的原因和二开方案

栏目:云星空知识作者:金蝶来源:金蝶云社区发布:2024-09-16浏览:1

业务流.全流程跟踪.源单和下游单显示不同的原因和二开方案

【场景】采购订单下推采购入库单,采购订单下推付款申请单 采购订单的全流程图 ![1679457091489.webp](/download/0100d2265faa09cf4711b5eb786447efaa6c.webp) 但是采购入库单看不到应付单,应付单看不到采购入库单 【原理】在系统的理解中,子单据只能看到当前对象的关联流程,比如看到以这个单下推的后续节点,以及跟这个单关联的上游;对于上游还做了什么其他业务是会被屏蔽调的; 如上图案例:采购订单推了入库单给库存模块的业务员,推了应付单给另一个模块的业务员; 本质上库存模块的业务员是不能关注应付单的信息(避免越权之类的场景) 目前系统上就是这么设计的; 【案例】目前仅二开实现在采购入库单,全流程跟踪能够查看应付单 实现方案:在采购入库单中,打开采购订单的全流程跟踪图; 核心逻辑 <1>找到需要打开流程图的源单内码和源单标识 <2>打开流程图 ```csharp using Kingdee.BOS; using Kingdee.BOS.Business.Bill.Operation; using Kingdee.BOS.BusinessEntity.BillTrack; using Kingdee.BOS.BusinessEntity.BusinessFlow; using Kingdee.BOS.Core; using Kingdee.BOS.Core.Bill.PlugIn; using Kingdee.BOS.Core.BusinessFlow.ServiceArgs; using Kingdee.BOS.Core.DynamicForm; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Core.Metadata; using Kingdee.BOS.Core.Metadata.EntityElement; using Kingdee.BOS.Core.SqlBuilder; using Kingdee.BOS.Orm.DataEntity; using Kingdee.BOS.ServiceHelper; using Kingdee.BOS.Util; using System; using System.Collections.Generic; using System.Linq; namespace Tmp.BusinessFlow.Tool.Operation { [Kingdee.BOS.Util.HotUpdate] public class TrackAllWithSpecBill : AbstractBillPlugIn { /* * 根据当前操作的单据内码,找到目标单的单据内码 */ public Context Context { get { return this.View.Context; } } /// <summary> /// 重写查看流程图事件 /// </summary> /// <returns></returns> public override void BarItemClick(BarItemClickEventArgs e) { if(!e.BarItemKey.EqualsIgnoreCase("tb_ShowSpecBillTrack")) { return; } /* * 根据当前单据内码,切换到目标 * <1>直接源单,根据link直接获取 * <2>跨级源单,通过下推携带到目标单;或者通过加载全流程实例获取 * https://wenku.my7c.com/article/71661049120113152?productLineId=1 * 演示 单据界面,根据link获取上有单据加载源单内码 */ if (this.View == null || this.View.Model.DataObject == null) return; var billBusinessInfo = this.View.BillBusinessInfo; DynamicObject billObj = this.View.Model.DataObject; //<1>根据link计算源单内码和源单标识 if(billBusinessInfo.GetForm().LinkSet.LinkEntitys== null || billBusinessInfo.GetForm().LinkSet.LinkEntitys.Count <=0) { return; } var linkSetEntity = this.View.BillBusinessInfo.GetForm().LinkSet.LinkEntitys[0]; var linkEntity = billBusinessInfo.GetEntity(linkSetEntity.Key); var entity = billBusinessInfo.GetEntity(linkSetEntity.ParentEntityKey); List<DynamicObject> entityObjs = new List<DynamicObject>(); if(entity is HeadEntity) { entityObjs.Add(billObj); } else if(entity is EntryEntity) { DynamicObjectCollection entityObjColl = billObj[entity.EntryName] as DynamicObjectCollection; if (entityObjColl == null) return; foreach(var entityRowObj in entityObjColl) { entityObjs.Add(entityRowObj); } } if (entityObjs.Count <= 0) return; string stableId = null; List<long> billIds = new List<long>(); foreach(var entityRow in entityObjs) { DynamicObjectCollection linkObjColl = entityRow[linkEntity.EntryName] as DynamicObjectCollection; if (linkObjColl == null || linkObjColl.Count <= 0) continue; foreach(var linkRow in linkObjColl) { string sTableName = linkRow["STableName"].ToString(); if(stableId != null && sTableName != stableId) { continue; } stableId = sTableName; long sBillId = ObjectUtils.Object2Int64(linkRow["SBillId"]); billIds.Add(sBillId); } } //static TableDefine LoadTableDefine(Context ctx, string tableNumber) var td = BusinessFlowServiceHelper.LoadTableDefine(this.View.Context, stableId); string formId = td.FormId; //<2>显示业务流程图 var viewParameter = GetBillFlows(formId, billIds); if (viewParameter == null || viewParameter.Instances.Count == 0) { return; } this.ShowBusinessFlow(viewParameter); } /// <summary> /// 计算流程图 /// </summary> /// <param name="formId"></param> /// <param name="billIds"></param> /// <returns></returns> private ViewBusinessFlowParameter GetBillFlows(string formId, List<long> billIds) { if (formId == null || billIds == null || billIds.Count <= 0) { return null; } //目标单元数据 FormMetadata metaData = MetaDataServiceHelper.Load(this.Context, formId) as FormMetadata; TrackAllHelper helper = new TrackAllHelper(this.Context, metaData.BusinessInfo); var result = helper.LoadBillView(billIds); return result; } private void ShowBusinessFlow(ViewBusinessFlowParameter viewParameter) { // 交换区数据 this.View.Session[FormConst.ConvParamKey_ViewBusinessFlowParameter] = viewParameter; this.View.Session["FormOperation"] = null; DynamicFormShowParameter param = new DynamicFormShowParameter(); param.FormId = FormIdConst.BOS_TrackResultForm; param.ParentPageId = this.View.PageId; param.OpenStyle.ShowType = TrackHelper.GetShowType(this.View); this.View.ShowForm(param); } } /// <summary> /// 全流程跟踪帮助类 /// 把此抽出来作为公有方法,供移动,和全流程跟踪刷新使用 /// </summary> public class TrackAllHelper { private BusinessInfo BillBusinessInfo; private Context Context; public TrackAllHelper(Context ctx, BusinessInfo businessInfo) { Context = ctx; BillBusinessInfo = businessInfo; } /// <summary> /// 加载单据内码关联的所有分录内码 /// </summary> /// <param name="billIds"></param> /// <returns></returns> private Dictionary<string, List<Tuple<long, long>>> LoadBillIds(List<long> billIds) { billIds = billIds.Distinct().ToList(); Dictionary<string, List<Tuple<long, long>>> allEntityIds = new Dictionary<string, List<Tuple<long, long>>>(); //记录实体 单据头内码 List<Tuple<long, long>> billIdTuples = new List<Tuple<long, long>>(); foreach (var billId in billIds) { billIdTuples.Add(new Tuple<long, long>(billId, billId)); } Entity headEntity = BillBusinessInfo.Entrys.FirstOrDefault((entity) => entity is HeadEntity); allEntityIds.Add(headEntity.Key.ToUpperInvariant(), billIdTuples); var pkArray = billIds.Select(x => (object)x).ToArray(); DynamicObject[] billObjs = BusinessDataServiceHelper.Load(Context, pkArray, BillBusinessInfo.GetDynamicObjectType()); if (billObjs == null || billObjs.Length <= 0) return allEntityIds; //记录实体 单据体内码 foreach (var entity in BillBusinessInfo.Entrys) { //仅支持单据体 if (entity is HeadEntity || entity is SubHeadEntity || entity is SubEntryEntity) continue; string strEntityPropertyName = entity.DynamicProperty.Name; var entryIdTuples = new List<Tuple<long, long>>(); foreach (var billObj in billObjs) { DynamicObjectCollection objCollections = billObj[strEntityPropertyName] as DynamicObjectCollection; if (objCollections == null || objCollections.Count <= 0) continue; foreach (DynamicObject row in objCollections) { object id = row["Id"]; if (id == null) { continue; } long entryId = Convert.ToInt64(id); if (entryId == 0) { continue; } entryIdTuples.Add(new Tuple<long, long>(Convert.ToInt64(billObj["Id"]), entryId)); } } allEntityIds.Add(entity.Key.ToUpperInvariant(), entryIdTuples); } return allEntityIds; } /// <summary> /// 获取Link实体关联的实体 /// </summary> /// <param name="metaData"></param> /// <returns></returns> public static List<Entity> GetLinkEntitys(BusinessInfo billBusinessInfo) { List<Entity> linkEntities = new List<Entity>(); if (billBusinessInfo.GetForm().LinkSet == null || (billBusinessInfo.GetForm().LinkSet.LinkEntitys == null)) return linkEntities; billBusinessInfo.GetForm().LinkSet.LinkEntitys.ForEach(linkEntity => { string linkEntryKey = ""; Entity entity = null; linkEntryKey = linkEntity.ParentEntityKey; entity = billBusinessInfo.GetEntity(linkEntryKey); if (entity != null) { linkEntities.Add(entity); } }); return linkEntities; } /// <summary> /// 加载单据内码关联所有实体的分 /// </summary> /// <param name="billIds"></param> /// <returns></returns> public ViewBusinessFlowParameter LoadBillView(List<long> billIds) { Dictionary<string, List<Tuple<long, long>>> allEntityIds = LoadBillIds(billIds); Entity headEntity = BillBusinessInfo.Entrys.FirstOrDefault((entity) => entity is HeadEntity); ViewBusinessFlowParameter viewParam = new ViewBusinessFlowParameter(); viewParam.BillInfo = new ViewBusinessFlowBillInfo(BillBusinessInfo.GetForm().Id); List<BusinessFlowInstance> instances = this.LoadAllInstances(allEntityIds, headEntity, billIds); if (instances.IsEmpty() == false) { var queryChangeEntityParamValue = SystemParameterServiceHelper.GetParamter(Context, 0, 0, "BF_SystemParameter", "FQueryChangeEntity"); var isEnableCrossEntityQuery = ObjectUtils.Object2Bool(queryChangeEntityParamValue); if (isEnableCrossEntityQuery) { this.ChangeEntityQuery(viewParam, ref instances); } } viewParam.Instances.AddRange(instances); return viewParam; } /// <summary> /// 加载单据全部实体的全部业务流程实例 /// </summary> /// <param name="allEntityIds"></param> /// <param name="headEntity"></param> /// <param name="billIds"></param> /// <param name="billInfo">同步输出本次发起联查的单据体内码</param> /// <returns></returns> private List<BusinessFlowInstance> LoadAllInstances(Dictionary<string, List<Tuple<long, long>>> allEntityIds, Entity headEntity, List<long> billIds, BusinessInfo info = null) { List<BusinessFlowInstance> instances = new List<BusinessFlowInstance>(); string formId = info == null ? BillBusinessInfo.GetForm().Id : info.GetForm().Id; // 逐个单据体寻找其业务流程实例 foreach (var item in allEntityIds) { Entity entity = info == null ? BillBusinessInfo.GetEntity(item.Key) : info.GetEntity(item.Key); List<long> entryIds = new List<long>(); if (this.IsHeadEntity(entity)) { entryIds.AddRange(billIds); } else { item.Value.ForEach((t) => entryIds.Add(t.Item2)); } var entityInstances = this.LoadInstancesByEntryIds(formId, entity.Key, entryIds.ToArray()); var validateInstance = this.RemoveJointlessNodes(formId, entity.Key, entryIds.ToArray(), entityInstances); instances.AddRange(validateInstance); } return instances; } #region 加载并合并流程实例 /// <summary> /// 改为公共方法,使业务流程图也能使用 /// </summary> /// <param name="viewParam"></param> /// <param name="entityInstances"></param> private void ChangeEntityQuery(ViewBusinessFlowParameter viewParam, ref List<BusinessFlowInstance> entityInstances) { if (entityInstances.IsEmpty()) return; var currentInstances = new List<BusinessFlowInstance>(); var reachedInstIds = new HashSet<string>(); var reachedNodes = new HashSet<string>(); var reachedTableName = new HashSet<string>();//搜索过的表名 foreach (var item in entityInstances) { currentInstances.Add(item); } //跨实体查询,实例之间并不存在连接或对应关系,故这里可以根据表单批量处理,而不是逐个处理 while (currentInstances.Count > 0) { //得到需要搜索的节点,按节点表名进行分组 var groupNodesByTbName = new Dictionary<string, List<long>>(); foreach (var instItem in currentInstances) { reachedInstIds.Add(instItem.Id); List<RouteTreeNode> lstNodes = this.GetAllNodes(instItem.FirstNode); //所有的节点 foreach (RouteTreeNode node in lstNodes) { if (node.Id != null && !reachedNodes.Contains(node.Id.CId)) //节点没有搜索过 { List<long> lstId = new List<long>(); if (groupNodesByTbName.ContainsKey(node.Id.Tbl)) { lstId = groupNodesByTbName[node.Id.Tbl]; } else { groupNodesByTbName[node.Id.Tbl] = lstId; } lstId.Add(node.Id.EId); reachedNodes.Add(node.Id.CId); } } } currentInstances.Clear(); //对节点进行搜索 var groupNodesByTbDefine = new Dictionary<TableDefine, List<long>>(); foreach (var currentNode in groupNodesByTbName) { var tbDefine = BusinessFlowServiceHelper.LoadTableDefine(Context, currentNode.Key); groupNodesByTbDefine[tbDefine] = currentNode.Value; reachedTableName.Add(currentNode.Key); } foreach (var currentNode in groupNodesByTbDefine) { var crossInstances = this.GetInstances(currentNode, reachedTableName); //得到跨实体流程 foreach (var itemInst in crossInstances) { if (reachedInstIds.Contains(itemInst.Id)) continue; currentInstances.Add(itemInst); } } //存在跨实体数据则使用根节点作为焦点 if (currentInstances.Count > 0) { viewParam.IsRootForceFormId = true; entityInstances.AddRange(currentInstances); } } } /// <summary> /// 得到所有节点 /// </summary> /// <param name="parentNote"></param> /// <returns></returns> private List<RouteTreeNode> GetAllNodes(RouteTreeNode parentNote, int parentDepth = 0) { List<RouteTreeNode> allNode = new List<RouteTreeNode>(); allNode.Add(parentNote); foreach (var child in parentNote.ChildNodes) { int currDepth = parentDepth; RecursionLimitUtils.Run(ref currDepth, 200, "TrackAllFlows->GetAllNodes"); var childs = this.GetAllNodes(child, currDepth); allNode.AddRange(childs); } return allNode; } /// <summary> /// /// </summary> /// <param name="item"></param> /// <returns></returns> private List<BusinessFlowInstance> GetInstances(KeyValuePair<TableDefine, List<long>> item, HashSet<string> reachedTableName) { //构建实体key和列名集合 var tbDefine = item.Key; var entityKeyAndColumnKey = new Dictionary<string, string>(); var businessInfo = FormMetaDataCache.GetCachedFormMetaData(Context, tbDefine.FormId).BusinessInfo; Entity noteEntity = businessInfo.GetEntity(tbDefine.EntityKey); //节点对应的实体 var tuple = this.GetFilterCondition(businessInfo, noteEntity, item.Value); var pkName = businessInfo.GetForm().PkFieldName; var headTbDefine = BusinessFlowServiceHelper.LoadTableDefine(Context, tbDefine.FormId, businessInfo.Entrys[0].Key, false); if (headTbDefine != null) { if (!reachedTableName.Contains(headTbDefine.TableNumber)) { entityKeyAndColumnKey[businessInfo.Entrys[0].Key] = pkName; //单据头 } } //构建参数 var queryParam = new QueryBuilderParemeter(); queryParam.FormId = businessInfo.GetForm().Id; queryParam.FilterClauseWihtKey = tuple.Item1; queryParam.SelectItems.Add(new SelectorItemInfo(pkName)); foreach (var entry in businessInfo.Entrys) { if (entry is EntryEntity && entry.Key != noteEntity.Key) { var entryTableDefine = BusinessFlowServiceHelper.LoadTableDefine(Context, tbDefine.FormId, entry.Key, false); if (entryTableDefine == null) continue; if (reachedTableName.Contains(entryTableDefine.TableNumber)) continue; var columnKey = string.Format("{0}_{1}", entry.Key, entry.EntryPkFieldName); entityKeyAndColumnKey[entry.Key] = columnKey; queryParam.SelectItems.Add(new SelectorItemInfo(columnKey)); } } List<BusinessFlowInstance> lstInstances = new List<BusinessFlowInstance>(); if (entityKeyAndColumnKey.Count > 0) { //得到查询数据 DynamicObjectCollection objs; if (tuple.Item2 == null) { objs = QueryServiceHelper.GetDynamicObjectCollection(Context, queryParam); } else { objs = QueryServiceHelper.GetDynamicObjectCollection(Context, queryParam, new List<SqlParam>() { tuple.Item2 }); } //构建查询节点数据 var allEntityIds = new Dictionary<string, List<Tuple<long, long>>>(); foreach (var dic in entityKeyAndColumnKey) { var lstTuple = new List<Tuple<long, long>>(); allEntityIds[dic.Key] = lstTuple; foreach (var obj in objs) { var billId = ObjectUtils.Object2Int64(obj[pkName]); var entityId = ObjectUtils.Object2Int64(obj[dic.Value]); if (entityId == 0) continue; var tItem = Tuple.Create<long, long>(billId, entityId); if (!lstTuple.Contains(tItem)) { lstTuple.Add(tItem); } } } var lstBillId = allEntityIds.First().Value.Select(x => x.Item1).ToList(); lstInstances = this.LoadAllInstances(allEntityIds, businessInfo.Entrys[0], lstBillId, businessInfo); } return lstInstances; } /// <summary> /// 得到过滤条件 /// </summary> /// <param name="businessInfo"></param> /// <param name="entity"></param> /// <param name="entityIds"></param> /// <returns></returns> private Tuple<string, SqlParam> GetFilterCondition(BusinessInfo businessInfo, Entity entity, List<long> entityIds) { string pkKey = ""; SqlParam param = null; if (this.IsHeadEntity(entity)) { pkKey = businessInfo.GetForm().PkFieldName; } else { pkKey = string.Concat(entity.Key, "_", entity.EntryPkFieldName); } var ids = entityIds.Distinct().ToArray(); var count = ids.Count(); var filter = string.Empty; if (count == 1) { filter = string.Format(" {0} = {1} ", pkKey, ids[0]); } else if (count <= 20) // 批量较小,直接采用IN语句 { filter = string.Format(" {0} IN ({1}) ", pkKey, string.Join(",", ids)); } else // 数目较大,采用表变量 { string paramName = "@FID"; string tSql = StringUtils.GetSqlWithCardinality(count, paramName, 1, false); filter = string.Format(" EXISTS ( {0} WHERE b.FID = {1} ))", tSql, pkKey); param = new SqlParam(paramName, KDDbType.udt_inttable, ids); } return Tuple.Create<string, SqlParam>(filter, param); ; } /// <summary> /// 加载单据体关联的全部业务流程实例 /// </summary> /// <param name="formId">单据</param> /// <param name="entityKey">单据体</param> /// <param name="entityIds">单据体内码</param> /// <returns></returns> private List<BusinessFlowInstance> LoadInstancesByEntryIds(string formId, string entityKey, long[] entityIds) { LoadInstancesByEntityIdArgs args = new LoadInstancesByEntityIdArgs(formId, entityKey, entityIds); args.LoadByMasterId = true; // 加载全部流程实例 BusinessFlowInstanceCollection instances = BusinessFlowDataServiceHelper.LoadInstancesByEntityId(Context, args); if (instances == null || instances.Count == 0) { return new List<BusinessFlowInstance>(); } else { List<BusinessFlowInstance> list = MergeInstances(instances); return list; } } /// <summary> /// 把业务流程实例按照MasterId进行合并 /// </summary> /// <param name="instances"></param> /// <returns></returns> private List<BusinessFlowInstance> MergeInstances(BusinessFlowInstanceCollection instances) { List<BusinessFlowInstance> mergeInstances = new List<BusinessFlowInstance>(); // 对全部实例按照MasterId进行分组 Dictionary<string, List<BusinessFlowInstance>> dict = new Dictionary<string, List<BusinessFlowInstance>>(); foreach (var instance in instances) { List<BusinessFlowInstance> lst = null; if (!dict.TryGetValue(instance.MasterId, out lst)) { lst = new List<BusinessFlowInstance>(); dict[instance.MasterId] = lst; } lst.Add(instance); } foreach (var group in dict) // 对每组实例进行合并处理 { List<BusinessFlowInstance> groupInstances = group.Value; BusinessFlowInstance instance = this.JoinGroupRouteTree(groupInstances); if (instance != null) { mergeInstances.Add(instance); } } return mergeInstances; } /// <summary> /// 对一组实例的首尾节点进行合并,合并结果返回,其他实例丢弃 /// </summary> /// <param name="groupInstances"></param> /// <param name="firstNodes"></param> private BusinessFlowInstance JoinGroupRouteTree(List<BusinessFlowInstance> groupInstances) { //连接到首实例的子节点集合 List<RouteTreeNode> joinChildNodes = new List<RouteTreeNode>(); BusinessFlowInstance firstInstance = null; RouteTreeNode groupFirstNode = null; // 一组实例的首节点 for (int i = 0; i < groupInstances.Count; i++) // 逐个实例,分析其首节点,是否被其他实例包含 { BusinessFlowInstance childInstance = groupInstances[i]; RouteTreeNode childNode = childInstance.FirstNode; if (childNode == null) { continue; // 这个实例无首节点,是个废实例,直接忽略 } if (childInstance.Id.EqualsIgnoreCase(childInstance.MasterId)) // Id==MasterId { firstInstance = childInstance; groupFirstNode = childNode; continue; // 首实例,其节点不可能是其他实例的尾节点 } for (int j = 0; j < groupInstances.Count; j++) // 对其他实例进行比较,找出本实例的直接上级,找到后,进行拼接 { if (j == i) { continue; // 同实例,不比较 } BusinessFlowInstance instanceB = groupInstances[j]; RouteTreeNode firstNodeB = instanceB.FirstNode; if (firstNodeB == null) { continue; } this.JoinRouteTreeNode(childNode, firstNodeB, ref joinChildNodes); } } //把需要连接的节点和所有子孙节点加入到主节点的子孙节点中 if (joinChildNodes.Count > 0 && groupFirstNode != null) { foreach (var subJoinNode in joinChildNodes) { groupFirstNode.AllChildNodes.Add(subJoinNode); if (subJoinNode.AllChildNodes != null && subJoinNode.AllChildNodes.Count > 0) { groupFirstNode.AllChildNodes.AddRange(subJoinNode.AllChildNodes); } } } return firstInstance; } /// <summary> /// 把子流程的首节点,合并到父流程的尾节点中 /// </summary> /// <param name="childInstanceNode">子实例</param> /// <param name="parentInstanceNode">父实例</param> private void JoinRouteTreeNode(RouteTreeNode childInstanceNode, RouteTreeNode parentInstanceNode, ref List<RouteTreeNode> joinChildNodes) { // 在父实例中找子实例的首节点 List<RouteTreeNode> parentInstLastNodes = new List<RouteTreeNode>(); parentInstanceNode.SearchChildNodes(childInstanceNode.Id, ref parentInstLastNodes); foreach (var parentInstLastNode in parentInstLastNodes) // 对匹配的尾节点循环 { foreach (var childInstNode in childInstanceNode.ChildNodes) { var existNode = parentInstLastNode.ChildNodes.FirstOrDefault((item) => item.Id.CId.EqualsIgnoreCase(childInstNode.Id.CId)); if (existNode != null) { continue; } parentInstLastNode.ChildNodes.Add(childInstNode); // 把子节点,拼接到尾节点,延伸尾节点;通过此方式覆盖子实例 childInstNode.ParentNode = parentInstLastNode; // 把子节点的父节点指向到父实例的尾节点上,使首尾能够衔接;可以继续反查 joinChildNodes.Add(childInstNode); } } } #endregion 加载并合并流程实例 /// <summary> /// 从流程实例中,移除与发起联查单据无关的路线节点 /// </summary> /// <param name="formId"></param> /// <param name="entityKey"></param> /// <param name="entityIds"></param> /// <param name="instances"></param> /// <returns></returns> private List<BusinessFlowInstance> RemoveJointlessNodes(string formId, string entityKey, long[] entityIds, List<BusinessFlowInstance> instances) { List<BusinessFlowInstance> list = new List<BusinessFlowInstance>(); if (instances == null || instances.Count == 0) return list; string tableNumber = this.LoadTableNumber(formId, entityKey); foreach (var instance in instances) { // 无首节点 if (instance.FirstNode == null) continue; // 仅首节点:下推过,但是下游单据被删除了 if (instance.FirstNode.ChildNodes.Count == 0) continue; _removeedNodes.Clear(); var isLeft = RemoveJointlessChildNodes(instance.FirstNode, tableNumber, entityIds); if (!isLeft) continue; if (_removeedNodes.Count() > 0) { HandlerLeftNodes(instance.FirstNode); } list.Add(instance); } return list; } private void HandlerLeftNodes(RouteTreeNode parendNode, int parentDepth = 0) { if (parendNode.ChildNodes != null && parendNode.ChildNodes.Count > 0) { List<RouteTreeNode> childNodes = new List<RouteTreeNode>(parendNode.ChildNodes); foreach (var childNode in childNodes) { if (_removeedNodes.Contains(childNode)) { parendNode.ChildNodes.Remove(childNode); } else { int currDepth = parentDepth; RecursionLimitUtils.Run(ref currDepth, 200, "TrackAllFlows->HandlerLeftNodes"); HandlerLeftNodes(childNode, currDepth); } } } //这个不能注释掉,此数据在鼠标放在节点上显示控制字段的值提示时有用到。 if (parendNode.AllChildNodes != null && parendNode.AllChildNodes.Count > 0) { List<RouteTreeNode> childNodes = new List<RouteTreeNode>(parendNode.AllChildNodes); foreach (var childNode in childNodes) { if (_removeedNodes.Contains(childNode)) { parendNode.AllChildNodes.Remove(childNode); } //else //{ // HandlerLeftNodes(childNode); //} } } } List<RouteTreeNode> _removeedNodes = new List<RouteTreeNode>(); /// <summary> /// 递归搜索节点及其子节点,移除全部与目标单据无关的路线 /// </summary> /// <param name="parendNode"></param> /// <param name="tableNumber"></param> /// <param name="entityIds"></param> /// <returns></returns> /// <remarks> /// 如果节点本身为目标单据,保留; /// 如果节点子节点为目标单据,本节点保留,本节点的其他分支继续搜索 /// </remarks> private bool RemoveJointlessChildNodes(RouteTreeNode parendNode, string tableNumber, long[] entityIds, int parentDepth = 0) { if (parendNode.Id.Tbl.EqualsIgnoreCase(tableNumber) && entityIds.Contains(parendNode.Id.EId)) {// 本节点为目标单据,无需往后找,本节点需要保留 return true; } // 本节点非目标节点,且无子节点 => 本节点需要被移除 if (parendNode.ChildNodes == null || parendNode.ChildNodes.Count == 0) return false; // 本节点不是目标单据,则逐个子节点进行判断,如果子节点与目标单据无关,则移除,全部节点均移除后,本节点移除 List<RouteTreeNode> childNodes = new List<RouteTreeNode>(parendNode.ChildNodes); foreach (var childNode in childNodes) { int currDepth = parentDepth; //RecursionLimitUtils.Run(ref currDepth, 200, "TrackAllFlows->RemoveJointlessChildNodes"); var isRemove = RemoveJointlessChildNodes(childNode, tableNumber, entityIds, currDepth); if (!isRemove) {// 子节点递归搜索,未发现与本节点的关系,则移除 parendNode.ChildNodes.Remove(childNode);//只移除了父节点下的子节点,但祖先下的节点并没有移除,在跨实体的时候依然会被访问。 parendNode.AllChildNodes.Remove(childNode); _removeedNodes.Add(childNode); //记录下已被移除的节点,等退出循环后再对所有剩下的节点循环处理 } } if (parendNode.ChildNodes.Count == 0) {// 本节点的子节点已经被移除完了,说明本节点与目标单据无关,也需要被移除 return false; } else { return true; // 本节点的子节点与目标单据有关而被保留,本节点也需要保留 } } /// <summary> /// /// </summary> /// <param name="formId"></param> /// <param name="entityKey"></param> /// <returns></returns> private string LoadTableNumber(string formId, string entityKey) { TableDefine tableDefine = BusinessFlowServiceHelper.LoadTableDefine(Context, formId, entityKey); if (tableDefine == null) { return ""; } return tableDefine.TableNumber; } /// <summary> /// /// </summary> /// <param name="entity"></param> /// <returns></returns> private bool IsHeadEntity(Entity entity) { bool isHeadEntity = (entity is HeadEntity) || (entity is SubHeadEntity); return isHeadEntity; } } } ``` 【效果】 ![1679457477982.webp](/download/010004c7aae802364cdbbedac6940718b5d4.webp)

RecursionLimitUtils需要引用那个包?

业务流.全流程跟踪.源单和下游单显示不同的原因和二开方案

【场景】采购订单下推采购入库单,采购订单下推付款申请单采购订单的全流程图![1679457091489.webp](/download/0100d2265faa09cf4711b5eb78...
点击下载文档
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息