限于作者能力有限,修改步骤中可能没有描述到位,还望见谅。
流程改写步骤
一、注意点
1、修改 K2 流程节点时,复制就行,最好不要自己从头生成,容易出错。
2、流程提交 70% 都是一样的 , 修改关键配置和代码即可
3、后台代码命名
XXXX_Apply 流程提交 (通过对 IsXXX 进行流程控制)
XXXX_Approval 流程审批 (流程流向下一个节点显示 )
4、K2流程标志的字符串 要和 代码里面书写的 一致
K2 流程琐碎细节
流程节点修改,最好在原来的节点上做减法 、加法!
K2通过审批节点添加
Outcome = Approval 通过审批
控制 K2 流程跳转
IsSikpEVP 是否跳过常务副总审批
OA 流程远程登录 ~
192.168.5.25
hitgen\K2admin
K2pass!
不能点击 部署 , 智能重新生成
根据实际情况进行删减,将复制过来的文件,进行增加、删除
梳理一个节点的过程:
二、流程创建步骤
1、查找其他流程相类似的节点,对节点复制粘贴
2、添加流程线
3、添加流程节点控制逻辑 IsXXX(True | False 控制跳过与否 )
4、添加当前审批对象,这里 Activity 内容是自动生成。
5、根据业务 添加审批通过 流程线条
6、根据业务 添加返回修改 流程线条
7、根据业务 需要添加 关闭流程线条
8、根据业务 添加流程代码,Succeeding Rule 代码不需要修改 , Destination Rule 代码需要修改 当前审批人节点代码
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using SourceCode.Workflow.Common.Extenders;
using SourceCode.KO;
using hostContext = Project_5af490bcef394335bd3a744dd0a102d7.DestinationRuleContext_d04c9817ea4c4af4ad63b1287b7aa3c9;
using System.Collections.Generic;
using Flysinfo.HitGen.K2Common;
namespace ExtenderProject_5af490bcef394335bd3a744dd0a102d7
{
public partial class DestinationRule_d04c9817ea4c4af4ad63b1287b7aa3c9 : IWorkflowContext<hostContext>
{
... ...
}
#endregion
private void Flysinfo_DestinationRule_ExecuteCode(object sender, EventArgs e)
{
try
{
//动态添加审批人 举个栗子: DeptLeader 部门负责人 HR HR人员 其他代码不用修改
string[] Approvers = K2.ProcessInstance.DataFields["DeptLeader"].Value.ToString().Split(\';\');
string SecurityLabel = K2.StringTable["SecurityLabel"] + "";
List<string> list = new List<string>();
foreach (string Approver in Approvers)
{
if (!list.Contains(Approver))
{
K2.Destinations.Add(DestinationType.User, SecurityLabel + Approver);
list.Add(Approver);
}
}
//AtLeast
string strDbConn = K2.StringTable["dbHitGenConnection"] + "";
string strActivityName = K2.ActivityInstance.Activity.Name;
string strProcessName = K2.ProcessInstance.Process.Name;
ProcessOperation ProcessOpe = new ProcessOperation();
int intAtLeast = ProcessOpe.GetActivityPassRule(strDbConn, strProcessName, strActivityName, list.Count);
K2.ProcessInstance.DataFields["AtLeast"].Value = intAtLeast;
}
catch (Exception ex)
{ }
}
private void DestinationRule_ExecuteCode(object sender, EventArgs e)
{
... ...
9、K2 流程的编译、部署
文件前面提示 ❌ , 表示没有包含在里面
右键 Include in Build 包含在项目里面
步骤 : 修改 K2 流程,点击包含到项目, 然后部署即可 ,项目就可以直接运行 ,如果有需要的修改就进行修改 。
三、数据库修改部分
修改数据库 TB_K2Base_ActivityInfo 里面的流程节点 。这里根据业务需求进行相应节点的增加、删除 。
-- 删除/修改原有错误节点数据
delete from TB_K2Base_ActivityInfo where id=401 or (processname=\'固定资产申请\' and activityName=\'上司审批\')
-- 插入数据
插入流程节点,形成新的审批流程
插入数据节点的 SQL 语句 , 注意这里的节点需要一 一对应起来 。
INSERT INTO [TB_K2Base_ActivityInfo]( [ProcessName], [ActivityName], [Cn_ActivityName], [En_ActivityName], [ActivityDescription], [IsSendMail], [IsSendMessage], [IsSendLync], [IsCountersign], [AtLeast], [IsDelete], [Creator], [CreatedTime], [Modifier], [ModifiedTime], [IsShow], [Sort], [IsCCAuthor], [IsConfigApprover], [IsCross], [IsSign], [IsGoBack], [IsSingnActivity], [IsMobileApproval]) VALUES ( N\'固定资产申请\', N\'上司审批\', N\'上司审批\', N\'上司审批\', N\'\', \'1\', \'1\', \'1\', \'0\', .00, \'0\', NULL, \'2019-10-24 10:17:30.760\', NULL, \'2019-10-24 10:17:30.760\', \'1\', 30, \'0\', NULL, NULL, NULL, NULL, NULL, \'1\');
INSERT INTO [TB_K2Base_ActivityInfo]( [ProcessName], [ActivityName], [Cn_ActivityName], [En_ActivityName], [ActivityDescription], [IsSendMail], [IsSendMessage], [IsSendLync], [IsCountersign], [AtLeast], [IsDelete], [Creator], [CreatedTime], [Modifier], [ModifiedTime], [IsShow], [Sort], [IsCCAuthor], [IsConfigApprover], [IsCross], [IsSign], [IsGoBack], [IsSingnActivity], [IsMobileApproval]) VALUES ( N\'固定资产申请\', N\'BumenShenpi\', N\'部门领导审批\', N\'部门领导审批\', N\'\', \'1\', \'1\', \'1\', \'0\', .00, \'0\', NULL, \'2019-10-24 10:17:30.760\', NULL, \'2019-10-24 10:17:30.760\', \'1\', 30, \'0\', NULL, NULL, NULL, NULL, NULL, \'1\');
在数据库里面显示效果为:
四、编程代码部分
4_1 前端代码:
“提交”和“保存草稿”按钮
<div class="btnBox" id="divApplyOperate">
<input type="hidden" id="hidContentID" value="" runat="server" />
<input type="hidden" id="hidSaveType" value="save" runat="server" />
<input type="button" class="btn" value="提交" id="applyBtn" onclick="submitForm(\'apply\')" />
<input type="button" class="btn" value="保存草稿" id="saveBtn" onclick="submitForm(\'save\')" runat="server" />
<input type="button" id="btnExit" class="btn" value="取消" onclick="CloseWin()" />
<asp:Button ID="btnApply" CssClass="btn" runat="server" Text="提交" Style="display: none" OnClick="btnApply_Click" />
<asp:Button ID="btnSave" CssClass="btn" runat="server" Text="保存草稿" Style="display: none" OnClick="btnSave_Click" />
</div>
前端 JS 部分
function submitForm(status) {
var passValidate = $("#subForm").form("validate");
if (!passValidate) {
return;
}
$.messager.progress();
if (status == "apply") {
$(\'#\' + \'<%=btnApply.ClientID%>\').click();
}
else {
$(\'#\' + \'<%=btnSave.ClientID%>\').click();
}
}
4_2 后端代码 :
保存草稿后台业务逻辑
关键数据库 : ContentCommon 流程日志表 ,后面的审批等等都是更新这张表 ,其中 contentModel.ContentId 这个是 contentCommon 的主键
protected void btnSave_Click(object sender, EventArgs e)
{
ContentCommon contentModel = new ContentCommon();
contentModel.ContentId = new Guid(hidContentID.Value);
// 是否为草稿状态
contentModel.IsDraft = true;
if (SaveInfo(contentModel))
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'保存成功。\');CloseWin();</script>");
}
else
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'保存失败。\');</script>");
}
}
流程提交 Apply
private string strProcessName = "Flysinfo.HitGen.K2\\HR\\外部培训";
private string strShortProcessName = "外部培训";
通过 IsXXX 控制流程流向,所以流向:
当前登录人 —— 上级领导审批 —— 部门负责人审批 —— 常务副总 —— 采购经理 ——
财务总监 —— CEO
大致判断控制思路:
一、项目申报部 或安全工程部 或行政部 同事
1、如果部门领导就是常务副总,IsSkipEVP = True ,跳过常务副总节点
2、如果当前登录人就是部门领导,IsTiaoguoBumenShenpi = True ,跳过部门领导
二、信息管理部同事
1、指定上级,IsTiaoGuoShangSiShenPi = False ,默认不能跳过。
三、最后判断
1、如果当前登录人上级是 CEO ,同时当前登录人为 CFO,IsTiaoGuoCFOShenPi = true跳过 CFO 审批
protected void btnApply_Click(object sender, EventArgs e)
{
// 存放流程历史版本表 ContentCommon ,流程运行,不断对该表进行更新
ContentCommon contentModel = new ContentCommon();
contentModel.ContentId = new Guid(hidContentID.Value);
//字典用于存放 K2流程里面字符串的键值对
Dictionary<string, object> dic = new Dictionary<string, object>();
var CurrentUser = CurrentUserInfo;
// 根据当前登录人,获取下一位领导 ,递归获取
string secondLeader = GetSecondLeader(CurrentLoginName);
// 获取下一位审批节点
string strEVP = GetNextApprover(strShortProcessName, "常务副总审批");
string manager = "";
// 如果当前申请人所属部门为项目申报部 或安全工程部 或行政部
if (CurrentUser.DepartmentName == "项目申报部" || CurrentUser.DepartmentName == "安全工程部” || CurrentUser.DepartmentName == "行政部")
{
if (string.IsNullOrEmpty(strEVP))
{
Response.Write("系统未找到 常务副总,请联系IT设置后再次提交!");
Response.End();
}
// 得到部门领导
string dptLeader = GetSecondLeader(CurrentLoginName, strEVP);
// 如果当前部门领导 就是 常务副总 ,那么设置默认跳过常务副总
if (dptLeader == secondLeader)
{
dic.Add("IsSkipEVP", true);
}
else
{
dic.Add("IsSkipEVP", false);
}
dic.Add("EVP", secondLeader);
// 将部门领导添加到“部门审批节点上”
dic.Add("BumenShenpi", dptLeader);
// 如果当前登录人就是部门领导 , true ,跳过部门领导审批
dic.Add("IsTiaoguoBumenShenpi", CurrentLoginName == dptLeader);
// 部门领导添加到上一级
manager = dptLeader;
}
else
{
// 如果当前是信息管理部同事,且账号域为下面三个人
if ( CurrentUserInfo.DomainAccount == "hitgen\\hao.liu" || CurrentUserInfo.DomainAccount == "hitgen\\dw.qiu" || CurrentUserInfo.DomainAccount == "hitgen\\hh.zhong")
{
//取出发起者的上级
string leader = CurrentUserInfo.Manager;
//指定上司审批人
dic.Add("ZhiDingShenPiRen", leader);
// 设置不跳过上级审批人
dic.Add("IsTiaoGuoShangSiShenPi", false);
}
else
{
//默认跳过上级审批
dic.Add("IsTiaoGuoShangSiShenPi", true);
}
// 跳过常务副总审批
dic.Add("IsSkipEVP", true);
// 上级赋值为第二位领导
manager = secondLeader;
dic.Add("EVP", secondLeader);
dic.Add("BumenShenpi", secondLeader);//上司
dic.Add("IsTiaoguoBumenShenpi", CurrentLoginName == secondLeader);
}
//判断节点审批人
//采购经理
string CaiGou = GetNextApprover(strShortProcessName, "采购经理审批").Trim();
if (string.IsNullOrEmpty(CaiGou))
{
Response.Write("系统未找到 采购经理,请联系IT设置后再次提交!");
Response.End();
}
dic.Add("CaiGouJingLi", CaiGou);
//财务总监
string CFO = GetNextApprover(strShortProcessName, "财务总监审批").Trim();
if (string.IsNullOrEmpty(CFO))
{
Response.Write("系统未找到 财务总监,请联系IT设置后再次提交!");
Response.End();
}
dic.Add("CaiWuZongJian", CFO);
//CEO
string CEO = GetNextApprover(strShortProcessName, "CEO审批").Trim();
if (string.IsNullOrEmpty(CEO))
{
Response.Write("系统未找到 CEO,请联系IT设置后再次提交!");
Response.End();
}
dic.Add("CEO", CEO);
//是否跳过
//上司是CEO
if (manager == CEO)
{
// 如果当前登录人上级是 CEO ,同时当前登录人为 CFO,跳过 CFO 审批
if (CFO == CurrentLoginName)//当前人是CFO
{
dic.Add("IsTiaoGuoCFOShenPi", true);//跳过CFO
}
else
{
dic.Add("IsTiaoGuoCFOShenPi", false);//不跳过CFO
}
// 只要上级是CEO ,就跳过上级审批
dic.Add("IsTiaoGuoShangSiShenPi", true);//跳过上司
}
else
{
如果上级不是 CEO 但是上级是CFO ,跳过上级,但是不跳过 CFO
if (CFO == manager)//上司是CFO
{
dic.Add("IsTiaoGuoShangSiShenPi", true);//跳过上司
dic.Add("IsTiaoGuoCFOShenPi", false);//不跳过CFO
}
else
{
dic.Add("IsTiaoGuoCFOShenPi", false);//不跳过CFO
}
}
// 都要经过CEO审批
dic.Add("IsCEO", true);
dic.Add("Creator", CurrentLoginName);
dic.Add("strStatus", "complete");
dic.Add("Author", CurrentLoginName);
string taskurl = WebHelper.GetTaskUrl("/_layouts/15/HitGen/Pages/FixedAssets/FixedAssetsApproval.aspx");
dic.Add("TaskUrl", taskurl);
dic.Add("EditTaskUrl", WebHelper.GetEditTaskUrl("/_layouts/15/HitGen/Pages/FixedAssets/FixedAssetsApply.aspx"));
int processInsID = 0;
try
{
int count = InstanceHelper.attachmentInstance.GetCount(t => t.ContentId == contentModel.ContentId);
if (string.IsNullOrEmpty(this.Page.Request.QueryString["SN"]))
{
#region 发起流程
processInsID = ClientHelper.StartProcess(strProcessName, OrderNum.Text + "--申请人:" + CurrentUserInfo.EmpName, dic, CurrentLoginName);
InstanceHelper.k2ActionLogInstance.AddEntity(new K2ActionLog()
{
Action = "提交申请",
ActivityName = "Initialization",
ApprovalTime = System.DateTime.Now,
Cn_ActivityName = "提交申请",
Opinion = "提交",
ProcessInsId = processInsID,
ProcessName = strProcessName,
UserId = CurrentLoginName,
UserFullName = CurrentUserInfo.EmpName
});
#endregion
contentModel.ProcessInsId = processInsID;
}
else
{
// 如果 _k2inf 为空,表示流程已经经过处理
K2TaskInf _k2inf = ClientHelper.QueryTaskBySerialNumber(this.Page.Request.QueryString["SN"], CurrentLoginName, "", "");
if (_k2inf == null)
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'该条任务已处理。\');</script>");
return;
}
// 返回修改
ClientHelper.SubmitTask(this.Page.Request.QueryString["SN"], "Approval", dic, CurrentLoginName, "", "");
InstanceHelper.k2ActionLogInstance.AddEntity(new K2ActionLog()
{
Action = "提交申请",
ActivityName = "Initialization",
ApprovalTime = System.DateTime.Now,
Cn_ActivityName = "返回修改",
Opinion = "提交",
ProcessInsId = Convert.ToInt32(this.Page.Request.QueryString["SN"].ToString().Split(new char[] { \'_\' }, StringSplitOptions.RemoveEmptyEntries)[0]),
ProcessName = strProcessName,
UserId = CurrentLoginName,
UserFullName = CurrentUserInfo.EmpName
});
}
contentModel.IsDraft = false;
if (SaveInfo(contentModel))
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'提交成功。\');window.location.href=\"" + WebConfigHelper.SiteUrl + "_layouts/15/HitGen/WorkSpace/MyApply.aspx\";</script>");
}
else
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'提交失败。\');</script>");
}
}
catch (Exception ex)
{
if (processInsID > 0)
{
ClientHelper.DeleteProcessInstances(processInsID);
}
InstanceHelper.sysExceptionInstance.AddEntity(new SysException()
{
CreateTime = System.DateTime.Now,
Description = ex.Message.ToString() + (ex.InnerException != null ? ex.InnerException.Message : "") + processInsID.ToString(),
Module = hidProcessName.Value
});
}
}
Approve
显示流程的下一个审批节点 ~
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
K2TaskInf _k2inf = null;
if (!string.IsNullOrEmpty(this.Page.Request.QueryString["SN"]))
{
_k2inf = ClientHelper.QueryTaskBySerialNumber(this.Page.Request.QueryString["SN"], CurrentLoginName, "", "");
if (_k2inf == null)
{
int ProcessInsId = Convert.ToInt32(this.Page.Request.QueryString["SN"].ToString().Split(new char[] { \'_\' }, StringSplitOptions.RemoveEmptyEntries)[0]);
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'该条任务已处理。\');window.location.href=\"" + WebConfigHelper.SiteUrl + "_layouts/15/HitGen/Pages/FixedAssets/FixedAssetsView.aspx?ProcessInsId=" + ProcessInsId + "\";</script>");
return;
}
}
Dictionary<string, object> diction = GetProcInstDataFields(_k2inf.ProcessInstanceID);
// 这里的判断变量在申请里面已经定义
bool IsSkipEVP = Convert.ToBoolean(diction["IsSkipEVP"]);
bool IsTiaoGuoCFOShenPi = Convert.ToBoolean(diction["IsTiaoGuoCFOShenPi"]);
bool isSkipCPO = Convert.ToBoolean(diction["IsSkipCPO"]);
bool IsCEO = Convert.ToBoolean(diction["IsCEO"]);
bool IsTiaoGuoShangSiShenPi = Convert.ToBoolean(diction["IsTiaoGuoShangSiShenPi"]);
//
switch (_k2inf.ActivityName)
{
// 部门直接领导审批
case "BumenShenpi":
if (IsSkipEVP == false)
{
nextActivityName = "常务副总审批";
}
else if (IsSkipEVP && IsTiaoGuoCFOShenPi == false)
{
nextActivityName = "采购经理审批";
}
else if (IsSkipEVP && IsTiaoGuoCFOShenPi && IsCEO)
{
nextActivityName = "CEO审批";
}
break;
case "上司审批":
if (IsTiaoGuoShangSiShenPi == false)
{
nextActivityName = "BumenShenpi";
}
break;
case "常务副总审批":
if (IsTiaoGuoCFOShenPi)
{
nextActivityName = "CEO审批";
}
else
{
nextActivityName = "采购经理审批";
}
break;
case "采购经理审批":
if (isSkipCPO)
{
nextActivityName = "财务总监审批";
}
else
{
nextActivityName = "高级供应链总监审批";
}
break;
case "高级供应链总监审批":
nextActivityName = "财务总监审批";
break;
case "财务总监审批":
nextActivityName = "CEO审批";
break;
case "CEO审批":
nextActivityName = "";
break;
default:
break;
}
hidProcessName.Value = litProcessName.Text = CacheManager.GetProcessInfos().Find(t => t.K2ProcessName == strProcessName).Cn_ProcessName;
int _procInstID = Convert.ToInt32(this.Page.Request.QueryString["SN"].Split(new char[] { \'_\' }, StringSplitOptions.RemoveEmptyEntries)[0]);
var contentCommon = InstanceHelper.contentCommonInstance.LoadSingleEntite(t => t.ProcessInsId == _procInstID);
bindApplyUser(contentCommon.Creator);
bindForm(contentCommon);
}
}
用于提交审核流程时,控制下一个节点包含数据,是否结束 ~
protected void btnSubmitApproval_Click(object sender, EventArgs e)
{
string Sn = Context.Request.QueryString["SN"] + "";
string SharedUser = Context.Request.QueryString["AllocatedUser"] + "";
string strAction = rbAction.SelectedValue;
string strOpinion = txtOpion.Value;
string strActionDisplay = rbAction.Items[rbAction.SelectedIndex].Text;
K2TaskInf _k2inf = ClientHelper.QueryTaskBySerialNumber(Sn, CurrentLoginName, SharedUser, "");
if (_k2inf == null)
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'该条任务已处理。\');</script>");
return;
}
Guid contentId = new Guid(hidContentId.Value);
PurFixedAssets model = bll.LoadSingleEntite(t => t.ContentId == contentId);
var contentCommon = InstanceHelper.contentCommonInstance.LoadSingleEntite(p => p.ContentId == contentId);
try
{
if (_k2inf != null)
{
string approveProces = strAction == "1" ? "Approval" : (strAction == "0" ? "Decline" : "Close");
Dictionary<string, object> dic = new Dictionary<string, object>();
var CurrentUser = CurrentUserInfo;
//dic.Add("IsCEO", this.IsDanHangDaYu.Value == "1" || this.IsZongJiaDaYu.Value == "1");
string nextApprover = "", strTips = "";
Dictionary<string, object> dics = GetProcInstDataFields(_k2inf.ProcessInstanceID);
bool IsSkipEVP = Convert.ToBoolean(dics["IsSkipEVP"]);
bool IsTiaoGuoCFOShenPi = Convert.ToBoolean(dics["IsTiaoGuoCFOShenPi"]);
bool IsCEO = Convert.ToBoolean(dics["IsCEO"]);
if (approveProces == "Approval")
{
Emails emails = new Emails();
switch (_k2inf.ActivityName)
{
case "BumenShenpi":
if (IsSkipEVP == true && IsTiaoGuoCFOShenPi == false && IsCEO == true)
{
nextApprover = "noend";
contentCommon.Status = "Completed";
InstanceHelper.contentCommonInstance.UpdateEntity(contentCommon);
contentCommon.Status = "Complete";
bll.UpdateEntity(model);
}
break;
case "上司审批":
nextApprover = "noend";
model.Manager = CurrentUser.EmpName;
model.Date1 = DateTime.Now;
bll.UpdateEntity(model);
break;
case "常务副总审批":
nextApprover = "noend";
break;
case "采购经理审批":
nextApprover = "noend";
decimal? totalAmount = model.Amount;
if (totalAmount <= 3000)//
{
nextApprover = GetNextApprover(strShortProcessName, "高级供应链总监审批");
dic.Add("IsSkipCPO", true);
dic.Add("CPO", nextApprover);
strTips = "高级供应链总监";
}
model.PurchaseManager = CurrentUserInfo.DomainAccount;
model.PurchaseManagerName = CurrentUserInfo.EmpName;
model.PurchaseManagerDate = DateTime.Now;
bll.UpdateEntity(model);
break;
case "高级供应链总监审批":
nextApprover = "noend";
model.PurchaseManager = CurrentUserInfo.DomainAccount;
model.PurchaseManagerName = CurrentUserInfo.EmpName;
model.PurchaseManagerDate = DateTime.Now;
bll.UpdateEntity(model);
break;
case "财务总监审批":
//if (this.IsDanHangDaYu.Value == "1" || this.IsZongJiaDaYu.Value=="1")
//{
// nextApprover = "noend";
// //dic.Add("IsCEO", false);//需要CEO审批
//}
//else
//{
// //dic.Add("IsCEO",false);//不需要CEO审批
// nextApprover = "end";
// contentCommon.Status = "Complete";
// InstanceHelper.contentCommonInstance.UpdateEntity(contentCommon);
//}
nextApprover = "noend";
model.PurchaserCode = this.Purchaser.Value;
model.PurchaserName = this.PurchaserName.Value;
model.Finance = CurrentUser.EmpName;
model.Date2 = DateTime.Now;
bll.UpdateEntity(model);
break;
case "CEO审批":
nextActivityName = "";
nextApprover = "end";
contentCommon.Status = "Complete";
InstanceHelper.contentCommonInstance.UpdateEntity(contentCommon);
model.CEO = CurrentUser.EmpName;
model.Date4 = DateTime.Now;
bll.UpdateEntity(model);
var emp = CacheManager.GetEmployeeInfos().Find(p => p.DomainAccount == model.PurchaserCode);
sendEmail(contentCommon.Title + "已完成", emp == null ? "" : emp.MailAlias, "你是指定的采购人员,需要你进行\'下单\'和\'确认收货\'操作!<a href=\"" + WebConfigHelper.SiteUrl + "_layouts/15/HitGen/Pages/FixedAssets/FixedAssetsView.aspx?ProcessInsId=" + contentCommon.ProcessInsId + "\">点击查看详情>></a> <a href=\"" + WebConfigHelper.SiteUrl + "_layouts/15/HitGen/Pages/FixedAssets/FixedAssetsList.aspx\">点击查看列表>></a>", "PurFixedAssets", null);
break;
default: break;
}
if (string.IsNullOrWhiteSpace(nextApprover))
{
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'系统未找到 " + strTips + ",请联系IT设置后再次提交!\');</script>");
return;
}
}
ClientHelper.SubmitTask(Sn, approveProces, dic, CurrentLoginName, SharedUser, "");
#region 写日志
var obj = new K2ActionLog();
obj.Action = strActionDisplay;
obj.ActivityName = _k2inf.ActivityName;
var ActivityInfo = InstanceHelper.workSpaceInstance.GetProcessInfoAndActivity(_k2inf.ProcessName, _k2inf.ActivityName);
obj.Cn_ActivityName = ActivityInfo.Cn_ActivityName;
obj.ApprovalTime = DateTime.Now;
obj.Opinion = strOpinion;
obj.ProcessInsId = _k2inf.ProcessInstanceID;
obj.ProcessName = _k2inf.ProcessName;
obj.UserId = CurrentLoginName;
obj.UserFullName = CurrentUser.EmpName;
InstanceHelper.k2ActionLogInstance.AddEntity(obj);
#endregion
if (approveProces == "Approval")
{
contentCommon.FirstApprover = CurrentUser.EmpName;
InstanceHelper.contentCommonInstance.UpdateEntity(contentCommon);
}
}
}
catch (Exception ex)
{
InstanceHelper.sysExceptionInstance.AddEntity(new SysException()
{
CreateTime = System.DateTime.Now,
Description = ex.Message.ToString(),
Module = hidProcessName.Value
});
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'审批失败,请联系系统管理员\');</script>");
return;
}
Page.ClientScript.RegisterStartupScript(this.Page.GetType(), Guid.NewGuid().ToString(), "<script>alert(\'提交成功。\');window.location.href=\"" + WebConfigHelper.SiteUrl + "_layouts/15/HitGen/WorkSpace/MyFinish.aspx\";</script>");
}
}
K2 安装
K2 安装包
K2 客户端只能在VS2010上创建项目,所以还要配合K2装一个VS2010 ;以上两项准备工作就绪后,基本就要开工了 ;
举个栗子
创建新的K2项目
创建新的流程开发模块 进行流程开发
常用工具控件说明:
节点关联线:流程各节点之间的关联线
客户端节点:流程的基本元素
服务器端节点:流程的完成标识节点
发起流程的时候其实是有代码来通知K2,流程已经发起,下一步通知Supplier节点进行审批。流程创建好之后,回返回一个ProcInstID ,K2自动生成的,后续和K2的交互就要依赖这个ID。
发起流程之后会到Supplier这个节点,这个节点要干的事情有以下几项,
获取节点审批人,需要在Supplier这个节点加载时初始化时写一段与WebService交互的代码,先把WebServices引入
完成节点事件配置
设置QS节点,和上边Supplier节点设置一样,需要在初始化时拷贝获取审批人代码,ServerEvent节点拷贝发送邮件代码。和Supplier区别在于,这个节点有审批人会介入,需要配置两个操作,批准、拒绝 。
添加动作(审批通过、拒绝等),执行这个节点的操作(这个节点直接审批通过即可),添加一个Default client Event,具体如下图所示
Event Name:事件名称(默认是ClientEvent)
Web Page:当前节点所在页面的网页地址,其中加重的部分为全局变量(之后会讲到)
选中Append serial number to url(s)系统会自动生成当前节点的序列号作为参数SN的值,序列号规则是工作流【实例编号+节点编号】
点击【next】为当前节点配置行为即【Actions】
定制行为,来控制节点的具体流向 ~
配置输出流向线 (默认输出流向线和银行行为一 一 对应 )
网上收录
节点标椎配置器
当前处理人规则
如果节点处理人只有一个我们就选择【One at a time】
如果引入竞争机制也就是多人处理一个节点,我们要选择【All at once】
需要注意:只要有一个人处理了节点,节点就会流转到下一个节点。
Escalations 催办设置
这个步骤我们在实际的项目开发中也会经常用到,就是如果处理人迟迟没有对节点进行处理,
我们需要采取催办的方式来提醒,便于及时的处理节点信息。具体如图示:
为节点添加事件代码
为节点添加客户端代码,来定义当流程走向该节点触发的事件信息。如图示:
图示一:右键点击【ClientEvent】,选择【Event Item】进入节点代码设置界面,如图示二
图示二:我们可以通过工具箱添加【code】来定义当前节点事件,本实例添加了一个发送邮件的节点的事件。
图示三:双击【SendEmail】填写当前节点的事件代码,本实例的代码完成的功能是当流程走向该节点,给处理人
发送邮件,处理人收到邮件以后对自己要处理的流程节点进行操作。
四 K2项目部署
流程开发完毕,我们需要把流程部署到K2服务器上,操作很简单右键点击我们开发的项目选择【部署】即可。
以上简单介绍了一下K2如何应用于NET开发环境,K2是个商业化的软件。我希望通过我的简单介绍能帮助使用K2工具
的开发人员尽快上手,更好的为企业的流程化管理服务。
k2服务器即K2 WORKSPACE管理介绍:
k2 管理平台统一管理基于K2开发的所有流程的跟踪调试以及基本配置信息。
具体完成的操作有以下几个部分:
1 配置K2环境相关属性。包括全局变量等
2 管理K2工作流服务器基本配置。包括服务器权限以及部署在服务器上所有流程的管理。
3 查看K2工作流当前运行状态以及报表数据。
windows 搜索 “k2 workspace”
k2工作平台的管理可以帮助我们有效的对流程进行跟踪,帮助我们更好的了解流程的运行状况,对流程进行全方面的管理。