套打.二开案例.审批路线合并节点的处理人、处理意见
【场景】审批路线合并节点的处理人、处理意见
【说明】审批路线目前套打严格按照工作流流程界面的数据打印,如果只是简单调整人名、过滤,只需要简单修改每一行数据包;
一旦效果跟工作流流程界面的需求差异非常大时,只能自行实现工作流审批路线的数据获取进行处理,最终套打配置的过滤、动态字段、签章逻辑都需要在插件中自行计算实现
工作流数据逻辑[【套打】套打中审批路线、流程节点二开指南](https://wenku.my7c.com/link/s/lJxHn)
【案例】采购合同,前加签、处理人、后加签 合并为一行打印
(0)数据准备
![image.webp](/download/0100e187970717a64ba8aca8cf19649d7293.webp)
没有配置插件前的打印效果
![image.webp](/download/0100c057dc7d127c409f8301264e0a496081.webp)
(1)配置插件调整审批路线的数据,仅提供思路和案例,部分细节需要自行调整;部分接口需要工作流模块的同事提供
![image.webp](/download/0100829c08dc33c1441bba1d275bc9921df4.webp)
```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,
};
// 判断是否加签人
bool returnObj = false;
if (addSignedReceivers.Contains(userId))
{
if (!nodeApproveInfo.ApproveItem.Any())
{
//如果没有处理人意见,那么就是前加签
nodeApproveInfo.BeforeApprove.Add(approveItem);
}
else
{
//如果有处理人意见,那么就是后加签
nodeApproveInfo.AfterApprove.Add(approveItem);
workFlowDataObj = instObj[activityKey];
}
}
else
{
//处理人意见
nodeApproveInfo.ApproveItem.Add(approveItem);
if(instObj.TryGetValue(activityKey, out workFlowDataObj))
{
}
else
{
workFlowDataObj = new DynamicObject(approveType);
instObj[activityKey] = workFlowDataObj;
if (!activityInstIdSet.Contains(activityKey))
{
workFlowDataObj["ac_approve_FActivityName"] = approveRouteInfo.ActivityName;
workFlowDataObj["ac_approve_FActivityStatu"] = approveRouteInfo.StatuDesc;
workFlowDataObj["ac_approve_FStartActivity"] = approveRouteInfo.SourceActivityName;
workFlowDataObj["ac_approve_FTargetActivity"] = approveRouteInfo.ActivityName;
activityInstIdSet.Add(activityKey);
}
workFlowDataObj["ac_approve_FActionName"] = approveRouteInfo.Title;
workFlowDataObj["ac_approve_FReceiverName"] = approveRouteInfo.ReceiverName;
workFlowDataObj["ac_approve_FActionResult"] = approveRouteInfo.ActionResult;
workFlowDataObj["ac_approve_FDisposition"] = approveRouteInfo.DisPosition;
workFlowDataObj["ac_approve_FCompletedTime"] = approveRouteInfo.CompletedTime;
workFlowDataObj["ac_approve_FConsignNames"] = approveRouteInfo.ConsignNames;
workFlowDataObj["ac_approve_" + KeyESignaturePermission] = "0";
returnObj = true;
}
}
if (workFlowDataObj != null)
{
// 根据加签信息调整处理人,处理意见结果
workFlowDataObj["ac_approve_FReceiverName"] = nodeApproveInfo.GetAllUserName();
workFlowDataObj["ac_approve_FDisposition"] = nodeApproveInfo.GetAllUserDisPosition();
}
if (returnObj)
return workFlowDataObj;
return null;
#region 电子签章逻辑
//if (useEsignature && approveRouteInfo.ActionResultId != null &&
// validation.UseEsignatureActIdFowrad[approveRouteInfo.ActivityId].Contains(
// approveRouteInfo.ActionResultId)) //启用电子签章且为正向节点(避免驳回也打印电子签章)
//{
// if (approveRouteInfo.Receivers == null)
// return;
// strUserId = approveRouteInfo.Receivers.Split(',')[0];
// if (!long.TryParse(strUserId, out userId))
// return;
// workFlowDataObj["ac_approve_" + KeyESignaturePermission] = "1";
// string ormKey = "ac_approve_" + KeyESignature;
// if (workFlowDataObj.DynamicObjectType.Properties.ContainsKey(ormKey) && infoObj.ActionInfo != null && !infoObj.ActionInfo.MobileEsignature.IsEmpty())
// {
// workFlowDataObj[ormKey] = infoObj.ActionInfo.MobileEsignature;
// }
// esignUserDataList.Add(new Tuple<DynamicObject, long>(workFlowDataObj, userId));
//}
#endregion
};
foreach (var approveRouteInfoAdapter in objList)
{
DynamicObject workFlowDataObj = fillWorkflowAct(approveRouteInfoAdapter.ApproveRouteInfo, approveRouteInfoAdapter);
if (workFlowDataObj == null)
continue;
approveRouteInfoAdapter.DataObject = workFlowDataObj;
}
// todo 没有动态字段的逻辑,如果需要的话只能自行计算
//CalcDynamicField(objList);
DynamicObjectCollection result = new DynamicObjectCollection(approveType);
foreach (var obj in objList)
{
if (obj.DataObject == null)
continue;
result.Add(obj.DataObject);
}
// todo 处理人签章逻辑,需要的话根据当前节点用户id加载用户图片
//AppendApproveLineESignature(esignUserDataList);
return result;
}
public class WorkflowNodeApproveInfo
{
public List<WorkflowApproveItem> BeforeApprove = new List<WorkflowApproveItem>();
public List<WorkflowApproveItem> ApproveItem = new List<WorkflowApproveItem>();
public List<WorkflowApproveItem> AfterApprove = new List<WorkflowApproveItem>();
public string GetAllUserName()
{
StringBuilder builder = new StringBuilder();
if (BeforeApprove.Any())
{
builder.Append("前加签:");
builder.Append(string.Join(";", BeforeApprove.Select(x => x.UserName)));
builder.AppendLine();
}
if (ApproveItem.Any())
{
builder.Append("常规处理:");
builder.Append(string.Join(";", ApproveItem.Select(x => x.UserName)));
builder.AppendLine();
}
if (AfterApprove.Any())
{
builder.Append("后加签:");
builder.Append(string.Join(";", AfterApprove.Select(x => x.UserName)));
builder.AppendLine();
}
return builder.ToString();
}
public string GetAllUserDisPosition()
{
StringBuilder builder = new StringBuilder();
if (BeforeApprove.Any())
{
builder.Append("前加签:");
builder.Append(string.Join(";", BeforeApprove.Select(x => x.DisPosition)));
builder.AppendLine();
}
if (ApproveItem.Any())
{
builder.Append("常规处理:");
builder.Append(string.Join(";", ApproveItem.Select(x => x.DisPosition)));
builder.AppendLine();
}
if (AfterApprove.Any())
{
builder.Append("后加签:");
builder.Append(string.Join(";", AfterApprove.Select(x => x.DisPosition)));
builder.AppendLine();
}
return builder.ToString();
}
}
public class WorkflowApproveItem
{
public long UserId;
public string UserName;
public string DisPosition;
}
}
}
```
(2)效果
![image.webp](/download/01004ae1313bc34447a58830241b4e782588.webp)
套打.二开案例.审批路线合并节点的处理人、处理意见
【场景】审批路线合并节点的处理人、处理意见【说明】审批路线目前套打严格按照工作流流程界面的数据打印,如果只是简单调整人名、过滤,只...
点击下载文档
上一篇:针对各单据的单据体明细列表里列表的显示隐藏列设置方案下一篇:报表秀秀疑问
本文2024-09-16 18:20:07发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-21474.html
您需要登录后才可以发表评论, 登录登录 或者 注册
最新文档
热门文章