审批工作流—ccflow
- 目录
- 概述
- 需求:
- 设计思路
- 实现思路分析
- 1.java 代码分析
- 参考资料和推荐阅读
Survive by day and develop by night.
talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive.
happy for hardess to solve denpendies.
目录
概述
审批工作流—ccflow
需求:
设计思路
实现思路分析
1.java 代码分析
Ccflow的审批有多种方式,可以根据实际需要,选择相应的审批方式。
系统的来说,审批有两部分组成:功能按钮、审批意见栏或者审批组件组成。
先介绍下与审批相关的功能按钮:
-
退回:如果审批不通过,或者文件、表单内容错误、或是其他问题,可以进行退回,进行修改内容或是重新提交等操作。
-
在cc中,退回分为以下几种模式:不能退回、退回到指定节点(步骤)、退回任意节点(步骤)、只能退回上一个节点。
-
挂起:相当于暂停的意思,分为永久挂起和定时挂起;挂起后,也可以解除。
-
抄送:相当于email的抄送,在政府单位中也可以叫做知会、阅知等词语。就是想当前的工作抄送给另一个人,让其知道。
-
加签:如果感觉自己需要参考其他人的意见,就使用加签,将工作附加给另一个人处理。
-
移交:如果感觉工作不是自己负责的范围内,或者自己的权限不够,可以使用移交,将工作移交给其他人处理。
审批意见栏:
- 使用审核组件:审核组件是cc的流程表单设计器自带的组件,直接拖拽到表单中就可以使用。邮件审核组件,可以进行功能编辑与权限控制,如下图:
流程运行中的效果图如下:
审核组件可以在多种表单中使用,例如:自由表单、SDK表单、树表单、自定义表单等。
- 在表单中自定义审批意见栏。可以按照自己的想法或需求进行设计。
CCFLOW源码解读系列01-----发起流程
1、发起流程、
发起流程时主要做了两件事:一是写入业务数据表,二是新建一条审批流程记录。
发起流程的方法
public static Int64 Node_CreateStartNodeWork(string flowNo, Hashtable htWork = null, DataSet workDtls = null,
string flowStarter = null, string title = null, Int64 parentWorkID = 0, string parentFlowNo = null, int parentNDFrom = 0
系统中一般这样调用、
Hashtable ht = new Hashtable();
long startFlowId = Dev2Interface.Node_CreateStartNodeWork(fk_Flow, ht, null, currentUserName, titl
传入的主要参数有:
流程的编号fk_Flow,编号是从001开始的,工作流系统中有一个默认的流程,编号是001,你可以在上面修改,也可以新建,新建后的流程编号是002.
键值对,ht主要是用于修改业务表。
currentUserName 用户名,主要用于初始化发起人信息,如果传NULL,则会默认用当前登录用户。
titile 流程名,如果传Null,则会默认生成一条流程。
进入方法,会看到初始化了几个实例 :
一是流程对象 Flow 记录了流程的编号、创建时间、名称,
Flow fl = new Flow(flowNo);
/// <summary>
/// 流程
/// </summary>
/// <param name="_No">编号</param>
public Flow(string _No)
{
this.No = _No;
if (SystemConfig.IsDebug)
{
int i = this.RetrieveFromDBSources();
if (i == 0)
throw new Exception("流程编号不存在");
}
else
{
this.Retrieve();
}
}
二是 节点对象 Node 存放每个节点的信息,通过流程的开始节点ID初始化节点类
Node nd = new Node(fl.StartNodeID);
让我们看看流程开始节点是如何找到的,如下,开始节点等于流程号+01 再转成Int 也就是说流程编号为002的开始节点为201。
public int StartNodeID
{
get
{
return int.Parse(this.No + "01");
}
}
三是操作员 Emp
/// <summary>
/// 操作员
/// </summary>
/// <param name="no">编号</param>
public Emp(string no)
{
if (no == null || no.Length == 0)
throw new Exception("@要查询的操作员编号为空。");
this.No = no.Trim();
this.Retrieve();
}
三是工作对象 work 随着该对象被创建,对象GenerWorkFlow也被创建出来,对应的表wf_generworkflow 中增加了一条记录
Work wk = fl.NewWork(flowStarter);
public Work NewWork(string empNo)
{
Emp emp = new Emp(empNo);
return NewWork(emp, null);
}
/// <summary>
/// 产生一个开始节点的新工作
/// </summary>
/// <param name="emp">发起人</param>
/// <param name="paras">参数集合,如果是CS调用,要发起子流程,要从其他table里copy数据,就不能从request里面取,可以传递为null.</param>
/// <returns>返回的Work.</returns>
public Work NewWork(Emp emp, Hashtable paras)
{
// 检查是否可以发起该流程?
if (Glo.CheckIsCanStartFlow_InitStartFlow(this) == false)
throw new Exception("err@您违反了该流程的【" + this.StartLimitRole + "】限制规则。" + this.StartLimitAlert);
GenerWorkFlow gwf = new GenerWorkFlow();
........................
wf_generworkflow表中修改的字段如下,WorkID是启动流程的唯一标识,也是最终要返回的ID,可以绑定在业务表上的。设置了当前流程的状态:WFState.Blank。
#region 给 generworkflow 初始化数据. add 2015-08-06
gwf.FK_Flow = this.No;
gwf.FK_FlowSort = this.FK_FlowSort;
gwf.SysType = this.SysType;
gwf.FK_Node = nd.NodeID;
gwf.WorkID = wk.OID;
gwf.WFState = WFState.Blank;
gwf.FlowName = this.Name;
gwf.FK_Node = nd.NodeID;
gwf.NodeName = nd.Name;
gwf.Starter = WebUser.No;
gwf.StarterName = WebUser.Name;
gwf.FK_Dept = BP.Web.WebUser.FK_Dept;
gwf.DeptName = BP.Web.WebUser.FK_DeptName;
接下来又对 GenerWorkerList对象进行了修正,
#region 为开始工作创建待办
GenerWorkFlow gwf = new GenerWorkFlow();
gwf.WorkID = wk.OID;
int i = gwf.RetrieveFromDBSources();
gwf.FlowName = fl.Name;
gwf.FK_Flow = flowNo;
gwf.FK_FlowSort = fl.FK_FlowSort;
gwf.SysType = fl.SysType;
gwf.FK_Dept = emp.FK_Dept;
gwf.DeptName = emp.FK_DeptText;
gwf.FK_Node = fl.StartNodeID;
gwf.NodeName = nd.Name;
//默认是空白流程
//gwf.WFSta = WFSta.Etc;
gwf.WFState = WFState.Blank;
//保存到草稿
if (fl.DraftRole == DraftRole.SaveToDraftList)
{
gwf.WFState = WFState.Draft;
}
else if (fl.DraftRole == DraftRole.SaveToTodolist)
{
//保存到待办
// gwf.WFSta = WFSta.Runing;
gwf.WFState = WFState.Runing;
}
if (DataType.IsNullOrEmpty(title))
{
gwf.Title = BP.WF.WorkFlowBuessRole.GenerTitle(fl, wk);
}
else
{
gwf.Title = title;
}
gwf.Starter = emp.No;
gwf.StarterName = emp.Name;
gwf.RDT = DataType.CurrentDataTime;
if (htWork != null && htWork.ContainsKey("PRI") == true)
{
gwf.PRI = int.Parse(htWork["PRI"].ToString());
}
if (htWork != null && htWork.ContainsKey("SDTOfNode") == true)
{
/*节点应完成时间*/
gwf.SDTOfNode = htWork["SDTOfNode"].ToString();
}
if (htWork != null && htWork.ContainsKey("SDTOfFlow") == true)
{
/*流程应完成时间*/
gwf.SDTOfNode = htWork["SDTOfFlow"].ToString();
}
gwf.PWorkID = parentWorkID;
gwf.PFlowNo = parentFlowNo;
gwf.PNodeID = parentNDFrom;
if (i == 0)
{
gwf.Insert();
}
else
{
gwf.Update();
}
四是创建了工作者列表GenerWorkerList,写入的表是wf_generworkerlist
/ 产生工作列表.
GenerWorkerList gwl = new GenerWorkerList();
gwl.WorkID = wk.OID;
if (gwl.RetrieveFromDBSources() == 0)
{
gwl.FK_Emp = emp.No;
gwl.FK_EmpText = emp.Name;
gwl.FK_Node = nd.NodeID;
gwl.FK_NodeText = nd.Name;
gwl.FID = 0;
gwl.FK_Flow = fl.No;
gwl.FK_Dept = emp.FK_Dept;
gwl.FK_DeptT = emp.FK_DeptText;
gwl.SDT = "无";
gwl.DTOfWarning = DataType.CurrentDataTime;
gwl.IsEnable = true;
gwl.IsPass = false;
// gwl.Sender = WebUser.No;
gwl.PRI = gwf.PRI;
gwl.Insert();
}
最后,整个启动流程的方法会将OID返回:
return wk.OID;
可以返回的ID绑定在自定义的业务表中。
参考资料和推荐阅读
1.https://blog.csdn.net/jflows/article/details/4669731
欢迎阅读,各位老铁,如果对你有帮助,点个赞加个关注呗!~
如有侵权,请私信联系删除之。