diff --git a/YLErpDAL/Modules/SystemModule/ApprovalProcessService.cs b/YLErpDAL/Modules/SystemModule/ApprovalProcessService.cs index 12a3c245..ae140dd0 100644 --- a/YLErpDAL/Modules/SystemModule/ApprovalProcessService.cs +++ b/YLErpDAL/Modules/SystemModule/ApprovalProcessService.cs @@ -712,25 +712,7 @@ namespace YLErp.Modules.SystemModule InitGroupId = UserBLL.GetApprovalProcessGroup(userId) }; - // ===== 临时诊断日志(定位触发条件是否生效,验证后删除)===== - try - { - var tn = trade?.TradeNumber ?? "?"; - var initNotional = trade?.OriginalStockEqvNotional ?? 0; - System.Diagnostics.Debug.WriteLine($"[ApplyTriggerOnStart] trade={tn}, 期初名义本金={initNotional}, 起点order={start.order}, 起点triggerCondition={start.triggerCondition ?? "(空)"}, 节点数={tradeProcess.Count}"); - foreach (var n in tradeProcess) - { - System.Diagnostics.Debug.WriteLine($" 节点 order={n.order}, node={n.node}, roleId={n.roleId}, triggerCondition={n.triggerCondition ?? "(空)"}"); - } - } - catch { } - var target = ConditionEvaluator.FindFirstTriggeredNode(tradeProcess, start, ctx); - try - { - System.Diagnostics.Debug.WriteLine($"[ApplyTriggerOnStart] FindFirstTriggeredNode 结果 = {(target == null ? "null(全不满足,直接通过)" : "order=" + target.order)}"); - } - catch { } if (target == null) { diff --git a/YLErpDAL/Modules/TradeModule/DealModule/TradeCloseService.cs b/YLErpDAL/Modules/TradeModule/DealModule/TradeCloseService.cs index 0729bb42..887a8964 100644 --- a/YLErpDAL/Modules/TradeModule/DealModule/TradeCloseService.cs +++ b/YLErpDAL/Modules/TradeModule/DealModule/TradeCloseService.cs @@ -126,8 +126,8 @@ namespace YLErp.Modules.TradeModule.DealModule td.CheckStatus = Convert.ToInt32(TradeCheckEnum.StatusOfOld); - //检查是否有交易审批流程 - if (valuedateBLL.SystemDate.CloseReApprove == 1 && hasTradeProcess) + //检查是否有交易审批流程(需求②:平仓/行权按交易状态查对应流程,而非只查开仓流程) + if (valuedateBLL.SystemDate.CloseReApprove == 1 && TradeProcessCountByCategory(td) > 0) { // 如果有审批组 InitTradeProcessOrder(td, UserId); diff --git a/YLErpDAL/Modules/TradeModule/DealModule/TradeExerciseService.cs b/YLErpDAL/Modules/TradeModule/DealModule/TradeExerciseService.cs index 28e318c7..d9307b5b 100644 --- a/YLErpDAL/Modules/TradeModule/DealModule/TradeExerciseService.cs +++ b/YLErpDAL/Modules/TradeModule/DealModule/TradeExerciseService.cs @@ -107,7 +107,8 @@ namespace YLErp.Modules.TradeModule.DealModule td.OptDate = DateTime.Now; td.TradeStatus = ConsTrade.行权待复核; td.CheckStatus = Convert.ToInt32(TradeCheckEnum.StatusOfOld); - if (valuedateBLL.SystemDate.CloseReApprove == 1 && hasTradeProcess) + // 需求②:行权按交易状态查对应流程,而非只查开仓流程 + if (valuedateBLL.SystemDate.CloseReApprove == 1 && TradeProcessCountByCategory(td) > 0) { //如果有审批组 InitTradeProcessOrder(td,UserId); diff --git a/YLErpDAL/Modules/TradeModule/DealModule/TradeUnwindService.cs b/YLErpDAL/Modules/TradeModule/DealModule/TradeUnwindService.cs index 94fe5d3e..ac4e4429 100644 --- a/YLErpDAL/Modules/TradeModule/DealModule/TradeUnwindService.cs +++ b/YLErpDAL/Modules/TradeModule/DealModule/TradeUnwindService.cs @@ -294,8 +294,8 @@ namespace YLErp.Modules.TradeModule.DealModule } var result = new TradeUnwindResultModel(td); - //存在审批流程时,走审批成功流程 - if (valuedateBLL.SystemDate.CloseReApprove == 1 && HasTradeProcess()) + //存在审批流程时,走审批成功流程(需求②:按交易状态查对应流程) + if (valuedateBLL.SystemDate.CloseReApprove == 1 && TradeProcessCountByCategory(td) > 0) { result.ApprovalProcess = true; @@ -462,8 +462,8 @@ namespace YLErp.Modules.TradeModule.DealModule throw new ServiceException("平仓费不一致!复核不通过"); } } - //存在审批流程时,走审批成功流程 - if (valuedateBLL.SystemDate.CloseReApprove == 1 && HasTradeProcess()) + //存在审批流程时,走审批成功流程(需求②:按交易状态查对应流程) + if (valuedateBLL.SystemDate.CloseReApprove == 1 && TradeProcessCountByCategory(td) > 0) { var reqModel = new TradeOpenReqModel { diff --git a/YLErpDAL/Modules/TradeModule/TradeBLL.cs b/YLErpDAL/Modules/TradeModule/TradeBLL.cs index 993be3a9..5daff142 100644 --- a/YLErpDAL/Modules/TradeModule/TradeBLL.cs +++ b/YLErpDAL/Modules/TradeModule/TradeBLL.cs @@ -3081,6 +3081,8 @@ namespace YLErp.BLL //如果是审批组 var approvalprocessQuery = db.approvalprocess.Where(a => a.processType == "TradeProcess"); var tradeOpenProcessOrder = approvalprocessQuery.Count(); + // 需求②:了结流程节点数(用于平仓/行权/互换交易展示正确的审批进度) + var closeProcessOrder = db.approvalprocess.Count(a => a.processType == "CloseProcess"); var branch = approvalprocessQuery.FirstOrDefault(x => x.approvalGroupId != 0);//审批流程有分支情况 var firstBranch = approvalprocessQuery.Where(x => (x.node == 1 && x.approvalGroupId == 0) || x.node == 0);//分支一总流程 var secondBranch = approvalprocessQuery.Where(x => (x.node == 2 && x.approvalGroupId == 0) || x.node == 0);//分支二总流程 @@ -3288,7 +3290,7 @@ namespace YLErp.BLL IQueryable query = null; if (branch == null) { - query = GetTradeLinqQuery(predicate, approvalprocessQuery, tradeOpenProcessOrder, 0); + query = GetTradeLinqQuery(predicate, approvalprocessQuery, tradeOpenProcessOrder, 0, closeProcessOrder); } else { @@ -3304,8 +3306,8 @@ namespace YLErp.BLL { nodeArr.Add(approvalConditionSecend.node); } - query = GetTradeLinqQuery(predicate, firstBranch, firstCount, 1, branchIndex, nodeArr); - var secondQuery = GetTradeLinqQuery(predicate, secondBranch, secondCount, 2, branchIndex, nodeArr); + query = GetTradeLinqQuery(predicate, firstBranch, firstCount, 1, branchIndex, nodeArr, closeProcessOrder); + var secondQuery = GetTradeLinqQuery(predicate, secondBranch, secondCount, 2, branchIndex, nodeArr, closeProcessOrder); query = query.Union(secondQuery); } @@ -3319,7 +3321,7 @@ namespace YLErp.BLL query = query.OrderByDescending(s => s.OptDate); return query; } - private IQueryable GetTradeLinqQuery(Expression> predicate, IQueryable approvalprocessQuery, int tradeOpenProcessOrder, int branchOrder) + private IQueryable GetTradeLinqQuery(Expression> predicate, IQueryable approvalprocessQuery, int tradeOpenProcessOrder, int branchOrder, int closeProcessOrder = 0) { var query = from source in db.trade.Where(predicate) join process in approvalprocessQuery on source.ProcessOrderId equals process.order into pro @@ -3371,7 +3373,7 @@ namespace YLErp.BLL OptId = source.OptId, OptName = source.OptName, OptDate = source.OptDate, - ProcessStatus = source.ProcessStatus == "审批中" ? source.ProcessStatus + " 流程" + (branchOrder != 0 && source.ProcessOrderId > branchOrder ? source.ProcessOrderId - 2 : source.ProcessOrderId - 1) + "/" + tradeOpenProcessOrder : source.ProcessStatus, + ProcessStatus = source.ProcessStatus == "审批中" ? source.ProcessStatus + " 流程" + (branchOrder != 0 && source.ProcessOrderId > branchOrder ? source.ProcessOrderId - 2 : source.ProcessOrderId - 1) + "/" + (source.TradeStatus == "平仓待复核" || source.TradeStatus == "行权待复核" || source.TradeStatus == "互换待复核" ? (closeProcessOrder > 0 ? closeProcessOrder : tradeOpenProcessOrder) : tradeOpenProcessOrder) : source.ProcessStatus, ProcessOrderId = source.ProcessOrderId, ProcessOrderBranch = source.ProcessOrderBranch, ProcessRoleId = proce.roleId, @@ -3393,7 +3395,7 @@ namespace YLErp.BLL }; return query; } - private IQueryable GetTradeLinqQuery(Expression> predicate, IQueryable approvalprocessQuery, int tradeOpenProcessOrder, int node, int branchOrder, List nodeArr) + private IQueryable GetTradeLinqQuery(Expression> predicate, IQueryable approvalprocessQuery, int tradeOpenProcessOrder, int node, int branchOrder, List nodeArr, int closeProcessOrder = 0) { var tradeStatus = new string[] { "平仓待复核", "行权待复核", "互换待复核" }; var query = from source in db.trade.Where(predicate) @@ -3447,7 +3449,7 @@ namespace YLErp.BLL OptId = source.OptId, OptName = source.OptName, OptDate = source.OptDate, - ProcessStatus = source.ProcessStatus == "审批中" ? source.ProcessStatus + " 流程" + (branchOrder != 0 && source.ProcessOrderId > branchOrder ? source.ProcessOrderId - 2 : source.ProcessOrderId - 1) + "/" + tradeOpenProcessOrder : source.ProcessStatus, + ProcessStatus = source.ProcessStatus == "审批中" ? source.ProcessStatus + " 流程" + (branchOrder != 0 && source.ProcessOrderId > branchOrder ? source.ProcessOrderId - 2 : source.ProcessOrderId - 1) + "/" + (source.TradeStatus == "平仓待复核" || source.TradeStatus == "行权待复核" || source.TradeStatus == "互换待复核" ? (closeProcessOrder > 0 ? closeProcessOrder : tradeOpenProcessOrder) : tradeOpenProcessOrder) : source.ProcessStatus, ProcessOrderId = source.ProcessOrderId, ProcessOrderBranch = source.ProcessOrderBranch, ProcessRoleId = proce.roleId, diff --git a/YLErpDAL/Modules/TradeModule/TradeServiceBase.cs b/YLErpDAL/Modules/TradeModule/TradeServiceBase.cs index 634f5a0d..0c9237f1 100644 --- a/YLErpDAL/Modules/TradeModule/TradeServiceBase.cs +++ b/YLErpDAL/Modules/TradeModule/TradeServiceBase.cs @@ -57,18 +57,13 @@ namespace YLErp.Modules.TradeModule /// /// 按交易推断流程类别(开仓/了结)获取审批节点(需求②)。 - /// 了结类(平仓待复核/行权待复核/互换待复核)优先取 CloseProcess;若未配置则回退 TradeProcess,避免卡单。 + /// 了结类(平仓待复核/行权待复核/互换待复核)取 CloseProcess;开仓类取 TradeProcess。 + /// 未配置对应流程时返回空列表(由调用方决定是否直接通过)。 /// public List TradeProcessByCategory(trade td) { var category = ResolveProcessCategory(td); - var orders = DbContext.approvalprocess.Where(t => t.processType == category).OrderBy(o => o.order).ToList(); - // 兼容回退:了结流程未配置时,回退到开仓流程。 - if (category == ProcessCategoryConst.Close && orders.Count == 0) - { - return TradeProcess(); - } - return orders; + return DbContext.approvalprocess.Where(t => t.processType == category).OrderBy(o => o.order).ToList(); } /// @@ -85,9 +80,17 @@ namespace YLErp.Modules.TradeModule /// public void InitTradeProcessOrder(trade td,int userId) { + var tradeProcess = TradeProcessByCategory(td); + // 该交易类别未配置审批流程 → 直接审批通过,无需审核 + if (tradeProcess == null || tradeProcess.Count == 0) + { + td.ProcessOrderId = ProcessTradeLog.审批通过; + td.ProcessStatus = ProcessTradeStatus.通过审批.ToString(); + td.ProcessOptDate = DateTime.Now; + return; + } td.ProcessOrderId = ProcessTradeLog.审批中; td.ProcessStatus = ProcessTradeStatus.审批中.ToString(); - var tradeProcess = TradeProcessByCategory(td); var groupId = UserBLL.GetApprovalProcessGroup(userId); bool approvalBranch = tradeProcess.Any(x => x.approvalGroupId != 0);//审批流程有分支情况 if (td.ProcessOrderId == 1) @@ -196,16 +199,16 @@ namespace YLErp.Modules.TradeModule ProcessCategory = ResolveProcessCategory(td), InitGroupId = UserBLL.GetApprovalProcessGroup(userId) }; - // 了结场景:取本次影响的名义本金(trade_cash.UnwindStockEqvNotional 绝对值) + // 了结场景:当次平仓名义本金 = 期初名义本金 × 平仓比例(UnwindPercentRate),取绝对值 if (td != null && ctx.ProcessCategory == ProcessCategoryConst.Close) { var tc = DbContext.trade_cash .Where(t => t.TradeId == td.id && t.ValidState == ConsGlobal.InValid && !t.IsDeleted) .OrderByDescending(t => t.id) .FirstOrDefault(); - if (tc != null && tc.UnwindStockEqvNotional.HasValue) + if (tc != null && tc.UnwindPercentRate.HasValue && td.OriginalStockEqvNotional.HasValue) { - ctx.CurrentNotional = Math.Abs(tc.UnwindStockEqvNotional.Value); + ctx.CurrentNotional = Math.Abs(td.OriginalStockEqvNotional.Value * tc.UnwindPercentRate.Value); } } return ctx; diff --git a/YLErpWeb/Views/AccountOpeningProcess/Index.cshtml b/YLErpWeb/Views/AccountOpeningProcess/Index.cshtml index 86f3dded..f26e55d0 100644 --- a/YLErpWeb/Views/AccountOpeningProcess/Index.cshtml +++ b/YLErpWeb/Views/AccountOpeningProcess/Index.cshtml @@ -84,7 +84,7 @@
- 添加条件 + 添加条件
@@ -214,7 +214,7 @@
- 添加条件 + 添加条件
@@ -344,7 +344,7 @@
-
+
{{tok.connector=='or'?'或':'且'}} (   ) @@ -375,7 +375,7 @@
- 添加条件 + 添加条件
@@ -436,7 +436,7 @@
-
+
{{tok.connector=='or'?'或':'且'}} (   ) @@ -513,7 +513,7 @@
审核节点 - +
审核角色 @@ -537,7 +537,7 @@
-
+
{{tok.connector=='or'?'或':'且'}} (   ) @@ -568,7 +568,7 @@
- 添加条件 + 添加条件
@@ -576,7 +576,7 @@
分支{{child.node}}条件 - +
申请人 @@ -605,7 +605,7 @@
审核节点 - +
审核角色 @@ -629,7 +629,7 @@
-
+
{{tok.connector=='or'?'或':'且'}} (   ) diff --git a/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js b/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js index ba04f6a0..b86af4fd 100644 --- a/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js +++ b/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js @@ -70,12 +70,12 @@ var app = new Vue({ // 需求①:节点触发条件字段(期初名义本金 / 本次交易名义本金) // 开仓流程只能选期初名义本金;了结流程两个都可选 conditionFields: [ - { value: 'initialNotional', text: '交易的期初名义本金' }, + { value: 'initialNotional', text: '期初名义本金' }, { value: 'currentNotional', text: '本次交易名义本金' } ], // 开仓流程可选字段(仅期初) conditionFieldsOpen: [ - { value: 'initialNotional', text: '交易的期初名义本金' } + { value: 'initialNotional', text: '期初名义本金' } ], conditionOps: [ { value: 'gt', text: '>' }, @@ -128,6 +128,7 @@ var app = new Vue({ if (thisObj.selected === '1') { thisObj.isOpen = true; thisObj.isTrade = false; + thisObj.isClose = false; thisObj.isCredit = false; thisObj.isOutCash = false; thisObj.isClient = false; @@ -148,6 +149,7 @@ var app = new Vue({ } else if (thisObj.selected === '3') { thisObj.isOpen = false; thisObj.isTrade = false; + thisObj.isClose = false; thisObj.isCredit = true; thisObj.isOutCash = false; thisObj.isClient = false; @@ -155,6 +157,7 @@ var app = new Vue({ else if (thisObj.selected === '4') { thisObj.isOpen = false; thisObj.isTrade = false; + thisObj.isClose = false; thisObj.isCredit = false; thisObj.isOutCash = true; thisObj.isClient = false; @@ -162,6 +165,7 @@ var app = new Vue({ else if (thisObj.selected === '5') { thisObj.isOpen = false; thisObj.isTrade = false; + thisObj.isClose = false; thisObj.isCredit = false; thisObj.isOutCash = false; thisObj.isClient = true; @@ -169,6 +173,7 @@ var app = new Vue({ else { thisObj.isOpen = false; thisObj.isTrade = false; + thisObj.isClose = false; thisObj.isCredit = false; thisObj.isOutCash = false; thisObj.isClient = false; @@ -273,7 +278,10 @@ var app = new Vue({ approvalCondition: 1, node: 1, parentNode: thisObj.node, - approvalGroupId: 0 + approvalGroupId: 0, + conditionConfig: '', + triggerCondition: '', + _trigger: { tokens: [] } } var item2 = { id: 0, @@ -283,7 +291,10 @@ var app = new Vue({ approvalCondition: 1, node: 2, parentNode: thisObj.node, - approvalGroupId: 0 + approvalGroupId: 0, + conditionConfig: '', + triggerCondition: '', + _trigger: { tokens: [] } } if (selectType == "2") { //交易 thisObj.tradeItems.splice(thisObj.node, 0, item, item2); @@ -376,12 +387,9 @@ var app = new Vue({ return; } - if (selectType === "1") { //客户开户 - thisObj.delOpenProcess(openItem); - return; - } - else if (selectType === "2") { //交易 - thisObj.delTradeProcess(openItem); + if (selectType === "1" || selectType === "2" || selectType === "5" || selectType === "6") { + // 客户开户/交易/客户信息/交易了结:统一走通用删除(支持多分支) + thisObj.commonDeleteProcess(openItem); return; } @@ -401,89 +409,6 @@ var app = new Vue({ }); return; } - else if (selectType === "5") { //客户信息 - thisObj.delClientProcess(openItem); - return; - } - }, - delOpenProcess(openItem) { - var thisObj = this; - if (openItem.approvalCondition != 0) {//删除分支下,所有东西 - var childNodes = thisObj.openItems.filter(x => x.node != 0); - thisObj.openItems = thisObj.openItems.concat(childNodes).filter(function (v) { - return thisObj.openItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1 - }); - thisObj.initOpenItemIndex(); - } else if (openItem.node != 0) {//删除分支下某节点 - var index = thisObj.openItems.indexOf(openItem); - thisObj.openItems.splice(index, 1); - var childNodes = thisObj.openItems.filter(x => x.node == openItem.node && x.Index >= openItem.Index); - childNodes.forEach(item => { - item.parentNode = item.parentNode - 1; - item.Index = item.Index - 1; - }); - } else {//删除非分支下某节点 - var index = thisObj.openItems.indexOf(openItem); - thisObj.openItems.splice(index, 1); - var nodes = thisObj.openItems.filter(x => x.Index >= openItem.Index); - nodes.forEach(item => { - item.Index = item.Index - 1; - }); - thisObj.initOpenItemIndex(); - } - }, - delTradeProcess(tradeItem) { - var thisObj = this; - thisObj.getRuleType(); - if (tradeItem.approvalCondition != 0) {//删除分支下,所有东西 - var childNodes = thisObj.tradeItems.filter(x => x.node != 0); - thisObj.tradeItems = thisObj.tradeItems.concat(childNodes).filter(function (v) { - return thisObj.tradeItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1 - }); - thisObj.initTradeItemIndex(); - } else if (tradeItem.node != 0) {//删除分支下某节点 - var index = thisObj.tradeItems.indexOf(tradeItem); - thisObj.tradeItems.splice(index, 1); - var childNodes = thisObj.tradeItems.filter(x => x.node == tradeItem.node && x.Index >= tradeItem.Index); - childNodes.forEach(item => { - item.parentNode = item.parentNode - 1; - item.Index = item.Index - 1; - }); - } else {//删除非分支下某节点 - var index = thisObj.tradeItems.indexOf(tradeItem); - thisObj.tradeItems.splice(index, 1); - var nodes = thisObj.tradeItems.filter(x => x.Index >= tradeItem.Index); - nodes.forEach(item => { - item.Index = item.Index - 1; - }); - thisObj.initTradeItemIndex(); - } - }, - delClientProcess(clientItem) { - var thisObj = this; - if (clientItem.approvalCondition != 0) {//删除分支下,所有东西 - var childNodes = thisObj.clientItems.filter(x => x.node != 0); - thisObj.clientItems = thisObj.clientItems.concat(childNodes).filter(function (v) { - return thisObj.clientItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1 - }); - thisObj.initClientItemIndex(); - } else if (clientItem.node != 0) {//删除分支下某节点 - var index = thisObj.clientItems.indexOf(clientItem); - thisObj.clientItems.splice(index, 1); - var childNodes = thisObj.clientItems.filter(x => x.node == clientItem.node && x.Index >= clientItem.Index); - childNodes.forEach(item => { - item.parentNode = item.parentNode - 1; - item.Index = item.Index - 1; - }); - } else {//删除非分支下某节点 - var index = thisObj.clientItems.indexOf(clientItem); - thisObj.clientItems.splice(index, 1); - var nodes = thisObj.clientItems.filter(x => x.Index >= clientItem.Index); - nodes.forEach(item => { - item.Index = item.Index - 1; - }); - thisObj.initClientItemIndex(); - } }, addOpenProcess(index, child, node) { var thisObj = this; @@ -494,7 +419,10 @@ var app = new Vue({ approvalCondition: 0, node: node, parentNode: child ? index : 0, - approvalGroupId: 0 + approvalGroupId: 0, + conditionConfig: '', + triggerCondition: '', + _trigger: { tokens: [] } } var childNodes = thisObj.openItems.filter(x => x.Index > index); childNodes.forEach(item => { @@ -542,7 +470,10 @@ var app = new Vue({ approvalCondition: 0, node: node, parentNode: child ? index : 0, - approvalGroupId: 0 + approvalGroupId: 0, + conditionConfig: '', + triggerCondition: '', + _trigger: { tokens: [] } } var childNodes = thisObj.clientItems.filter(x => x.Index > index); childNodes.forEach(item => { @@ -1032,44 +963,134 @@ var app = new Vue({ clientFilterChild(node) { return this.clientItems.filter(x => x.node == node && x.approvalCondition == 0); }, - initTradeItemIndex() { - var thisObj = this; - var newSortTradeItems = []; - var mainTradeItems = thisObj.tradeItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index); - var childTradeItem = thisObj.tradeItems.filter(x => x.node != 0); - var childTradeItemSort = childTradeItem.sort((a, b) => a.Index - b.Index); - var firstChildIndex = childTradeItemSort.length > 0 ? childTradeItemSort[0].Index : -1; - var j = 1; - for (var i = 0; i < mainTradeItems.length; i++) { - if (mainTradeItems[i].Index >= firstChildIndex) { - if (childTradeItemSort.length > 0) { - mainTradeItems[i].Index = childTradeItemSort[childTradeItemSort.length - 1].Index + j; + // ===== 需求③:多分支支持(参考中粮版)通用方法 ===== + // 通用分支重编号:动态把分支节点编号为 1,2,3...N(不再写死 1/2) + commonInitIndex(targetProp) { + const that = this; + const newSortedItems = []; + const mainItems = that[targetProp].filter(x => x.node == 0).sort((a, b) => a.Index - b.Index); + const childItems = that[targetProp].filter(x => x.node != 0); + const sortedChildItems = childItems.sort((a, b) => a.Index - b.Index); + const firstChildIndex = sortedChildItems.length > 0 ? sortedChildItems[0].Index : -1; + let j = 1; + for (let i = 0; i < mainItems.length; i++) { + if (mainItems[i].Index >= firstChildIndex) { + if (sortedChildItems.length > 0) { + mainItems[i].Index = sortedChildItems[sortedChildItems.length - 1].Index + j; j++; } else { - mainTradeItems[i].Index = i + 1; + mainItems[i].Index = i + 1; } - } - newSortTradeItems.push(mainTradeItems[i]); + newSortedItems.push(mainItems[i]); } - var firstChildTradeItems = childTradeItem.filter(x => x.node == 1); - var secondChildTradeItems = childTradeItem.filter(x => x.node == 2); - firstChildTradeItems.forEach((x, index) => { //分支index不用再排序 - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; + + // 为分支条件的 node 重新排序(1,2,3...N)——多分支的核心 + let tempNode = 1; + childItems.forEach((i) => { + if (i.approvalCondition != 0) { + i.node = tempNode++; } - newSortTradeItems.push(x); }); - secondChildTradeItems.forEach((x, index) => { - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortTradeItems.push(x); + + // 按分支 node 分组,重建每个分支下的子节点 Index/parentNode + for (let i = 0; i < childItems.length; i++) { + var filteredChildItems = childItems.filter(x => x.node == i + 1); + filteredChildItems.forEach((i, index) => { + if (i.approvalCondition == 0) { + i.Index = firstChildIndex + index; + i.parentNode = firstChildIndex + index - 1; + } + newSortedItems.push(i); + }); + } + that[targetProp] = newSortedItems.sort((a, b) => a.Index - b.Index); + }, + // 通用添加分支条件:push 一个 node:999 占位的分支节点,再重编号 + commonAddCondition(item) { + const that = this; + const typeToPropMap = { + 'OpenProcess': 'openItems', + 'ClientProcess': 'clientItems', + 'TradeProcess': 'tradeItems', + 'CloseProcess': 'closeItems' + }; + const typeToInitFnMap = { + 'OpenProcess': that.initOpenItemIndex, + 'ClientProcess': that.initClientItemIndex, + 'TradeProcess': that.initTradeItemIndex, + 'CloseProcess': that.initCloseItemIndex + }; + const prop = typeToPropMap[item.Type]; + const initFn = typeToInitFnMap[item.Type]; + that[prop].push({ + id: 0, + Type: item.Type, + Index: item.Index, + SelectValue: 0, + approvalCondition: 1, + node: 999, + parentNode: item.Index, + ApprovalRules: '', + approvalGroupId: 0, + conditionConfig: '', + triggerCondition: '', + _trigger: { tokens: [] } }); - thisObj.tradeItems = newSortTradeItems.sort((a, b) => a.Index - b.Index); - thisObj.initRuleType(); + initFn(); + }, + // 添加条件入口("添加条件"按钮调用) + addCondition(item) { + this.commonAddCondition(item); + }, + // 通用删除分支/节点 + commonDeleteProcess(item) { + const that = this; + const typeToPropMap = { + 'OpenProcess': 'openItems', + 'ClientProcess': 'clientItems', + 'TradeProcess': 'tradeItems', + 'CloseProcess': 'closeItems' + }; + const typeToInitFnMap = { + 'OpenProcess': that.initOpenItemIndex, + 'ClientProcess': that.initClientItemIndex, + 'TradeProcess': that.initTradeItemIndex, + 'CloseProcess': that.initCloseItemIndex + }; + const prop = typeToPropMap[item.Type]; + const initFn = typeToInitFnMap[item.Type]; + + // 删除的不是分支条件节点(普通审批节点) + if (item.approvalCondition == 0) { + const index = that[prop].indexOf(item); + that[prop].splice(index, 1); + const nodes = that[prop].filter(x => x.Index >= item.Index); + nodes.forEach(item => { + item.Index = item.Index - 1; + }); + initFn(); + return; + } + + // 分支条件数量<=2 时,删除整个分支组 + var conditionBranchesLen = that[prop].filter(i => i.approvalCondition != 0 && i.node != 0).length; + if (item.approvalCondition != 0 && conditionBranchesLen <= 2) { + var childNodes = that[prop].filter(x => x.node != 0); + that[prop] = that[prop].filter(x => childNodes.indexOf(x) === -1); + initFn(); + return; + } + + // 分支条件数量>2 时,只删除该分支(同 node 的全部节点) + if (item.node != 0 && item.approvalCondition != 0) { + that[prop] = that[prop].filter(x => x.node != item.node); + initFn(); + } + }, + initTradeItemIndex() { + this.commonInitIndex('tradeItems'); + this.initRuleType(); }, // ===== 需求①:节点触发条件 结构化编辑器(token 数组,支持每行独立且/或 + 括号)===== // _trigger = { tokens: [ {type:'condition',condition:{field,op,value}}, {type:'operator',connector:'and'|'or'}, {type:'lparen'|'rparen'} ] } @@ -1247,42 +1268,8 @@ var app = new Vue({ return this.closeItems.filter(x => x.node == node && x.approvalCondition == 0); }, initCloseItemIndex() { - var thisObj = this; - var newSortItems = []; - var mainItems = thisObj.closeItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index); - var childItem = thisObj.closeItems.filter(x => x.node != 0); - var childItemSort = childItem.sort((a, b) => a.Index - b.Index); - var firstChildIndex = childItemSort.length > 0 ? childItemSort[0].Index : -1; - var j = 1; - for (var i = 0; i < mainItems.length; i++) { - if (mainItems[i].Index >= firstChildIndex) { - if (childItemSort.length > 0) { - mainItems[i].Index = childItemSort[childItemSort.length - 1].Index + j; - j++; - } else { - mainItems[i].Index = i + 1; - } - } - newSortItems.push(mainItems[i]); - } - var firstChildItems = childItem.filter(x => x.node == 1); - var secondChildItems = childItem.filter(x => x.node == 2); - firstChildItems.forEach((x, index) => { - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortItems.push(x); - }); - secondChildItems.forEach((x, index) => { - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortItems.push(x); - }); - thisObj.closeItems = newSortItems.sort((a, b) => a.Index - b.Index); - thisObj.initRuleType(); + this.commonInitIndex('closeItems'); + this.initRuleType(); }, closeShowProcess(index, child, obj) { var thisObj = this; @@ -1329,33 +1316,6 @@ var app = new Vue({ thisObj.closeItems.splice(index, 0, item); thisObj.initCloseItemIndex(); }, - closeDelProcess(closeItem) { - var thisObj = this; - thisObj.getCloseRuleType(); - if (closeItem.approvalCondition != 0) {//删除分支下,所有东西 - var childNodes = thisObj.closeItems.filter(x => x.node != 0); - thisObj.closeItems = thisObj.closeItems.concat(childNodes).filter(function (v) { - return thisObj.closeItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1 - }); - thisObj.initCloseItemIndex(); - } else if (closeItem.node != 0) {//删除分支下某节点 - var index = thisObj.closeItems.indexOf(closeItem); - thisObj.closeItems.splice(index, 1); - var childNodes = thisObj.closeItems.filter(x => x.node == closeItem.node && x.Index >= closeItem.Index); - childNodes.forEach(item => { - item.parentNode = item.parentNode - 1; - item.Index = item.Index - 1; - }); - } else {//删除非分支下某节点 - var index = thisObj.closeItems.indexOf(closeItem); - thisObj.closeItems.splice(index, 1); - var nodes = thisObj.closeItems.filter(x => x.Index >= closeItem.Index); - nodes.forEach(item => { - item.Index = item.Index - 1; - }); - thisObj.initCloseItemIndex(); - } - }, closeSelectChangeType(index, value) { var thisObj = this; for (var j = 0; j < thisObj.closeItems.length; j++) { @@ -1442,92 +1402,23 @@ var app = new Vue({ } }, initOpenItemIndex() { - var thisObj = this; - var newSortOpenItems = []; - var mainOpenItems = thisObj.openItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index); - var childOpenItem = thisObj.openItems.filter(x => x.node != 0); - var childOpenItemSort = childOpenItem.sort((a, b) => a.Index - b.Index); - var firstChildIndex = childOpenItemSort.length > 0 ? childOpenItemSort[0].Index : -1; - var j = 1; - for (var i = 0; i < mainOpenItems.length; i++) { - if (mainOpenItems[i].Index >= firstChildIndex) { - if (childOpenItemSort.length > 0) { - mainOpenItems[i].Index = childOpenItemSort[childOpenItemSort.length - 1].Index + j; - j++; - } else { - mainOpenItems[i].Index = i + 1; - } - - } - newSortOpenItems.push(mainOpenItems[i]); - } - var firstChildOpenItems = childOpenItem.filter(x => x.node == 1); - var secondChildOpenItems = childOpenItem.filter(x => x.node == 2); - firstChildOpenItems.forEach((x, index) => { //分支index不用再排序 - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortOpenItems.push(x); - }); - secondChildOpenItems.forEach((x, index) => { - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortOpenItems.push(x); - }); - thisObj.openItems = newSortOpenItems.sort((a, b) => a.Index - b.Index); + this.commonInitIndex('openItems'); }, initClientItemIndex() { - var thisObj = this; - var newSortClientItems = []; - var mainClientItems = thisObj.clientItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index); - var childClientItem = thisObj.clientItems.filter(x => x.node != 0); - var childClientItemSort = childClientItem.sort((a, b) => a.Index - b.Index); - var firstChildIndex = childClientItemSort.length > 0 ? childClientItemSort[0].Index : -1; - var j = 1; - for (var i = 0; i < mainClientItems.length; i++) { - if (mainClientItems[i].Index >= firstChildIndex) { - if (childClientItemSort.length > 0) { - mainClientItems[i].Index = childClientItemSort[childClientItemSort.length - 1].Index + j; - j++; - } else { - mainClientItems[i].Index = i + 1; - } - - } - newSortClientItems.push(mainClientItems[i]); - } - var firstChildClientItems = childClientItem.filter(x => x.node == 1); - var secondChildClientItems = childClientItem.filter(x => x.node == 2); - firstChildClientItems.forEach((x, index) => { //分支index不用再排序 - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortClientItems.push(x); - }); - secondChildClientItems.forEach((x, index) => { - if (x.approvalCondition == 0) { - x.Index = firstChildIndex + index; - x.parentNode = firstChildIndex + index - 1; - } - newSortClientItems.push(x); - }); - thisObj.clientItems = newSortClientItems.sort((a, b) => a.Index - b.Index); + this.commonInitIndex('clientItems'); }, initRuleTypeFor(items, prefix) { var thisObj = this; var length = items.length; for (var i = 0; i < length; i++) { var ruleId = "#" + prefix + items[i].Index + items[i].node; - var $selectize = $(ruleId).get(0); + var el = $(ruleId).get(0); + if (!el || !el.selectize) continue; // DOM 尚未渲染或未初始化 selectize,跳过 if (items[i].ApprovalRules != null && items[i].ApprovalRules.length > 0) { var ruleArr = items[i].ApprovalRules.split(','); - $selectize.selectize.setValue(ruleArr); - } else if ($selectize) { - $selectize.selectize.setValue([]); + el.selectize.setValue(ruleArr); + } else { + el.selectize.setValue([]); } } }, diff --git a/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css b/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css index 5c2176c8..30516b45 100644 --- a/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css +++ b/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css @@ -50,7 +50,7 @@ html { flex-direction: column; align-items: center; width: 100%; - padding: 0 50px; + /*padding: 0 50px;*/ position: relative; font-size: 12px; } @@ -568,3 +568,11 @@ html { color: #ff7875 !important; opacity: 1; } + +/* 需求③:多分支连线。多个 .col-box 时,中间列(非首非尾)的右覆盖线宽度置 0,避免连线断裂 */ +.col-box:not(:first-child):not(:last-child) .top-right-cover-line { + width: 0; +} +.col-box:not(:first-child):not(:last-child) .bottom-right-cover-line { + width: 0; +}