
【场景】审批路线合并节点的处理人、处理意见
【说明】审批路线目前套打严格按照工作流流程界面的数据打印,如果只是简单调整人名、过滤,只需要简单修改每一行数据包;
一旦效果跟工作流流程界面的需求差异非常大时,只能自行实现工作流审批路线的数据获取进行处理,最终套打配置的过滤、动态字段、签章逻辑都需要在插件中自行计算实现
工作流数据逻辑[【套打】套打中审批路线、流程节点二开指南](https://vip.kingdee.com/link/s/lJxHn)
【案例】采购合同,前加签、处理人、后加签 合并为一行打印
(0)数据准备

没有配置插件前的打印效果

(1)配置插件调整审批路线的数据,仅提供思路和案例,部分细节需要自行调整;部分接口需要工作流模块的同事提供

```csharp
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.NotePrint;
using Kingdee.BOS.NotePrinting.Framework.Object;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Orm.Metadata.DataEntity;
using Kingdee.BOS.Util;
using Kingdee.BOS.Workflow.Kernel;
using Kingdee.BOS.Workflow.Models.Chart;
using Kingdee.BOS.Workflow.Models.NotePrint;
using Kingdee.BOS.Workflow.ServiceHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DynamicFormPlugIn.NotePrint
{
[System.ComponentModel.Description("审批路线二开调整")]
[Kingdee.BOS.Util.HotUpdate]
public class NotePrintPlugIn_WorkFlowApproveLine : AbstractDynamicFormPlugIn
{
public override void OnPrepareNotePrintData(PreparePrintDataEventArgs e)
{
if (!string.Equals(e.NotePrintTplId, "6690568e-3a24-464d-aa7b-deb6bfdbe874", StringComparison.OrdinalIgnoreCase))
return;
if (e.DataObjects == null)
return;
//工作流数据源默认以workflow作为数据源前缀
if (!e.DataSourceId.StartsWith("workflow."))
return;
string workflowBillId = e.BillIds.FirstOrDefault();
if (workflowBillId.IsNullOrEmptyOrWhiteSpace())
return;
string[] dataSourceArgs = e.DataSourceId.Split('.');
if (dataSourceArgs.Length < 2)
return;
//流程设计Id,判断是审批路线取数还是流程节点取数
string procDefId = dataSourceArgs[1];
if (procDefId.Equals("approveLine"))
{
//审批路线取数
var dataObjs = GetWorkFlowData(workflowBillId, e.DynamicObjectType);
e.DataObjects = dataObjs.ToArray();
}
else
{
//流程节点取数
}
}
/*
* 套打的审批路线 数据包信息非常少,如果只是替换名字的逻辑可以直接使用
* 如果需要将多个节点合并,判断是否加签处理,都需要完全二开把审批路线替换掉
* 这里关联的工作流干预接口需要自行根据业务场景调整
*/
/// <summary>
/// 审批路线-处理人签章
/// </summary>
internal const string KeyESignature = "FReceiverESignature";
/// <summary>
/// 审批路线-处理人签章是否有权
/// </summary>
internal const string KeyESignaturePermission = "FESignaturePermission";
/// <summary>
/// 获取工作流审批路线 套打使用的数据包
/// </summary>
/// <param name="billId"></param>
/// <param name="workFlowObjType"></param>
/// <returns></returns>
private DynamicObjectCollection GetWorkFlowData(string billId, DynamicObjectType workFlowObjType)
{
// <0>根据单据内码、表单标识 获取流程实例id
string formId = this.View.BillBusinessInfo.GetForm().Id;
string processId = Kingdee.BOS.Workflow.ServiceHelper.WorkflowChartServiceHelper.GetProcInstIdByBillInst(Context, formId, billId);
if (processId.IsNullOrEmptyOrWhiteSpace())
return null;
// <1> todo 重新审核是否加载审批路线数据
// <2> 获取待办列表和已办的所有信息
List<ApproveRouteInfoObj> approveRouteInfoAdapterList = new List<ApproveRouteInfoObj>();
List<ChartActivityInfo> routeCollection = Kingdee.BOS.Workflow.ServiceHelper.WorkflowChartServiceHelper.GetProcessRouter(Context, processId);
NotePrintEsignatureValidation validation = Kingdee.BOS.Workflow.ServiceHelper.ProcManageServiceHelper.GetEsignatureValidationByBillId(Context, formId, billId);
foreach (ChartActivityInfo activityDetail in routeCollection)
{
var curApproveRouteList = CollectApproveRouteInfo(activityDetail);
// <3> todo 自行实现过滤审批路线的逻辑
//if (!string.IsNullOrWhiteSpace(DataSource.FilterString))
//{
// curApproveRouteList = GetApproveRouteInfoByFilter(DataSource.FilterString, curApproveRouteList);
//}
if (curApproveRouteList == null)
continue;
approveRouteInfoAdapterList.AddRange(curApproveRouteList);
}
var result = FillDynamicObject(validation, approveRouteInfoAdapterList, workFlowObjType);
return result;
}
/// <summary>
/// 根据工作流审批路线信息生成套打对象
/// </summary>
/// <param name="activityDetail"></param>
/// <returns></returns>
private List<ApproveRouteInfoObj> CollectApproveRouteInfo(ChartActivityInfo activityDetail)
{
List<ApproveRouteInfoObj> approveRouteInfoList = new List<ApproveRouteInfoObj>();
ApproveRouteInfo approveRouteInfoMain = new ApproveRouteInfo()
{
ActivityName = activityDetail.ActivityName,
SourceActivityName = activityDetail.SourceActivityName,
ActivityId = activityDetail.ActivityId,
};
switch ((int)activityDetail.ActivityStateType)
{
case 1:
case 3:
case 5:
case 6:
approveRouteInfoMain.StatuDesc = "完成";
break;
case 2:
approveRouteInfoMain.StatuDesc = "当前";
break;
case 4:
approveRouteInfoMain.StatuDesc = "出错";
break;
default:
approveRouteInfoMain.StatuDesc = string.Empty;
break;
}
for (int j = 0; j < activityDetail.ActionDetails.Count; j++)
//第一次添加审批明细的时候在节点的同一行记录里,剩余的在新增行添加
{
//已完成节点里面只展现已完成的待办任务信息
if (activityDetail.ActivityStateType != MapStateResult.Idled && !activityDetail.ActionDetails[j].IsCompleted)
{
continue;
}
ChartActionInfo action = activityDetail.ActionDetails[j];
#region ApproveRouteInfoDetail
ApproveRouteInfoObj approveRouteInfoAdapter = CopyApproveRouteInfo(approveRouteInfoMain, activityDetail, action);
var approveRouteInfo = approveRouteInfoAdapter.ApproveRouteInfo;
approveRouteInfo.Title = action.Title;
approveRouteInfo.ReceiverName = action.ReceiverName;
approveRouteInfo.ActionResult = action.ActionResult;
approveRouteInfo.DisPosition = action.DisPosition;
approveRouteInfo.CompletedTime = action.CompleteTime;
approveRouteInfo.ConsignNames = action.ConsignNames;
approveRouteInfo.ActionResultId = action.ActionResultId;
approveRouteInfo.Receivers = action.Receivers;
#endregion ApproveRouteInfo
//绑定工作流实体和套打实体的关系
approveRouteInfoList.Add(approveRouteInfoAdapter);
}
return approveRouteInfoList;
}
/// <summary>
/// 得到一个计算用的审批路线对象
/// </summary>
/// <param name="srcInfo"></param>
/// <param name="activityInfo"></param>
/// <param name="actionInfo"></param>
/// <returns></returns>
private ApproveRouteInfoObj CopyApproveRouteInfo(ApproveRouteInfo srcInfo, ChartActivityInfo activityInfo, ChartActionInfo actionInfo)
{
ApproveRouteInfo tgtInfo = new ApproveRouteInfo()
{
ActivityName = srcInfo.ActivityName,
SourceActivityName = srcInfo.SourceActivityName,
ActivityId = srcInfo.ActivityId,
StatuDesc = srcInfo.StatuDesc,
};
return new ApproveRouteInfoObj()
{
ApproveRouteInfo = tgtInfo,
ActivityInfo = activityInfo,
ActionInfo = actionInfo
};
}
/// <summary>
/// 根据套打对象生成打印的数据包
/// </summary>
/// <param name="validation"></param>
/// <param name="objList"></param>
/// <param name="approveType"></param>
/// <returns></returns>
private DynamicObjectCollection FillDynamicObject(NotePrintEsignatureValidation validation, List<ApproveRouteInfoObj> objList, DynamicObjectType approveType)
{
HashSet<string> activityInstIdSet = new HashSet<string>();
List<Tuple<DynamicObject, long>> esignUserDataList = new List<Tuple<DynamicObject, long>>();
bool useEsignature; //当前流程节点是否启用电子签章审批
string strUserId; //处理人字符串
long userId; //处理人内码
Dictionary<string, WorkflowNodeApproveInfo> nodeAprove = new Dictionary<string, WorkflowNodeApproveInfo>();
Dictionary<string, DynamicObject> instObj = new Dictionary<string, DynamicObject>();
Func<ApproveRouteInfo, ApproveRouteInfoObj, DynamicObject> fillWorkflowAct = (approveRouteInfo, infoObj) =>
{
DynamicObject workFlowDataObj = null;
useEsignature = validation != null &&
validation.UseEsignatureActIdFowrad.ContainsKey(approveRouteInfo.ActivityId);
//第一次添加审批明细的时候在节点的同一行记录里,剩余的在新增行添加
//调整代码结构后,使用节点Id+动作实例Id去重
string activityKey = string.Format("{0}_{1}", approveRouteInfo.ActivityId, infoObj.ActivityInfo.ActInstId);
//不是开始节点,检查是待办还是不是待办;有审批意见的待办才打印
if (approveRouteInfo.ActivityId != 0)
{
if (approveRouteInfo.ActionResultId.IsNullOrEmptyOrWhiteSpace())
return workFlowDataObj;
}
/*
* 核心实现逻辑:
* 将同一个节点的同一个实例的信息合并到一起
*
*/
List<long> addSignedReceivers = AssignmentServiceHelper.GetAddSignedReceiverIdByAssignId(this.Context, infoObj.ActionInfo.AssignId);
strUserId = approveRouteInfo.Receivers.Split(',')[0];
if (!long.TryParse(strUserId, out userId))
return workFlowDataObj;
WorkflowNodeApproveInfo nodeApproveInfo = null;
if(!nodeAprove.TryGetValue(activityKey, out nodeApproveInfo))
{
nodeApproveInfo = new WorkflowNodeApproveInfo();
nodeAprove[activityKey] = nodeApproveInfo;
}
WorkflowApproveItem approveItem = new WorkflowApproveItem()
{
UserId = userId,
UserName = approveRouteInfo.ReceiverName,
DisPosition = approveRouteInfo.DisPosition,
};