ASP.NET MVC5+EF6+EasyUI 后台管理系统(53)-工作流设计-我的批阅
前言:由于工作原因工作流一直没时间更新,虽然没有更新,但是批阅和申请差不多,改变一下数据的状态字段就行,有几个园友已经率先完成了
说句实话,一个工作流用文章表达很难,我起初以为这是一个很简单的工作流程,但是要花很多时间考虑很多业务场景,这也是导致停滞不前的原因。
最近空出点时时间更新了皮肤,让系统看起来奇葩一点,顺便也把工作流梳理了一遍,最后跑通了整个流程的多个场景完成从提交表单到审批驳回结束流程
事隔已久需要重新梳理流程,辣么开始吧(由于我自己更新了皮肤,截图与之前有点不一样,但是除UI层之外其他还是一样的)
1.开始代码之前需要更新个枚举,这样不容易出错
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Apps.Models.Enum { public enum FlowStateEnum { /// <summary> /// 驳回 /// </summary> Reject =0, /// <summary> /// 通过 /// </summary> Pass = 1, /// <summary> /// 进行中 /// </summary> Progress =2, /// <summary> /// 关闭 /// </summary> Closed = 3 } public enum FlowRuleEnum { /// <summary> /// 上级 /// </summary> Lead =1, /// <summary> /// 人员 /// </summary> Person = 2, /// <summary> /// 自选 /// </summary> Customer = 3, /// <summary> /// 职位 /// </summary> Position = 4, /// <summary> /// 部门 /// </summary> Department =5, } public enum FlowFormLevelEnum { /// <summary> /// 普通 /// </summary> Ordinary = 1, /// <summary> /// 重要 /// </summary> Major = 2, /// <summary> /// 紧急 /// </summary> Urgent =3 } }
有时间就要把那些123换成枚举值
2.审批列表
通过 起草新申请 将获得这个页面的列表
[HttpPost] public JsonResult GetListByUserId(GridPager pager, string queryStr) { List<Flow_FormContentModel> list = formContentBLL.GeExaminetListByUserId(ref pager, queryStr, GetUserId()); var json = new { total = pager.totalRows, rows = (from r in list select new Flow_FormContentModel() { Id = r.Id, Title = r.Title, UserId = r.UserId, FormId = r.FormId, FormLevel = r.FormLevel, CreateTime = r.CreateTime, TimeOut = r.TimeOut, CurrentStep = formContentBLL.GetCurrentFormStep(r), CurrentState = formContentBLL.GetCurrentFormState(r), Action = "<a href='#' title='管理' onclick='ManageFlow(\"" + r.Title + "\",\"" + r.FormId + "\",\"" + r.Id + "\")'>管理</a> | <a href='#' title='图例' onclick='LookFlow(\"" + r.FormId + "\")'>图例</a>" }).ToArray() }; return Json(json); }
public List<Flow_FormContentModel> GeExaminetListByUserId(ref GridPager pager, string queryStr, string userId) { IQueryable<Flow_FormContent> queryData = null; if (!string.IsNullOrWhiteSpace(queryStr)) { queryData = m_Rep.GeExamineListByUserId(db, userId).Where(a => a.Title.Contains(queryStr)); } else { queryData = m_Rep.GeExamineListByUserId(db, userId); } pager.totalRows = queryData.Count(); queryData = LinqHelper.SortingAndPaging(queryData, pager.sort, pager.order, pager.page, pager.rows); return CreateModelList(ref queryData); }
public List<Flow_FormContentModel> GeExaminetListByUserId(ref GridPager pager, string queryStr, string userId) { IQueryable<Flow_FormContent> queryData = null; if (!string.IsNullOrWhiteSpace(queryStr)) { queryData = m_Rep.GeExamineListByUserId(db, userId).Where(a => a.Title.Contains(queryStr)); } else { queryData = m_Rep.GeExamineListByUserId(db, userId); } pager.totalRows = queryData.Count(); queryData = LinqHelper.SortingAndPaging(queryData, pager.sort, pager.order, pager.page, pager.rows); return CreateModelList(ref queryData); } private List<Flow_FormContentModel> CreateModelList(ref IQueryable<Flow_FormContent> queryData) { List<Flow_FormContentModel> modelList = (from r in queryData select new Flow_FormContentModel { Id = r.Id, Title = r.Title, UserId = r.UserId, FormId = r.FormId, FormLevel = r.FormLevel, CreateTime = r.CreateTime, AttrA = r.AttrA, AttrB = r.AttrB, AttrC = r.AttrC, AttrD = r.AttrD, AttrE = r.AttrE, AttrF = r.AttrF, AttrG = r.AttrG, AttrH = r.AttrH, AttrI = r.AttrI, AttrJ = r.AttrJ, AttrK = r.AttrK, AttrL = r.AttrL, AttrM = r.AttrM, AttrN = r.AttrN, AttrO = r.AttrO, AttrP = r.AttrP, AttrQ = r.AttrQ, AttrR = r.AttrR, AttrS = r.AttrS, AttrT = r.AttrT, AttrU = r.AttrU, AttrV = r.AttrV, AttrW = r.AttrW, AttrX = r.AttrX, AttrY = r.AttrY, AttrZ = r.AttrZ, CustomMember = r.CustomMember, TimeOut = r.TimeOut }).ToList(); return modelList; }
@using Apps.Web.Core; @using Apps.Common; @using Apps.Models.Sys; @using Apps.Models.Enum; @using Apps.Locale; @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Index_Layout.cshtml"; List<permModel> perm = (List<permModel>)ViewBag.Perm; if (perm == null) { perm = new List<permModel>(); } } <table id="List"></table> <div id="modalwindow" class="easyui-window" data-options="modal:true,closed:true,minimizable:false,shadow:false"></div> @Html.Partial("~/Views/Shared/_Partial_AutoGrid.cshtml") <script type="text/javascript"> $(function () { $('#List').datagrid({ url: '@Url.Action("GetListByUserId")', width: SetGridWidthSub(10), methord: 'post', height: SetGridHeightSub(39), fitColumns: true, sortName: 'CreateTime', sortOrder: 'desc', idField: 'Id', pageSize: 15, pageList: [15, 20, 30, 40, 50], pagination: true, striped: true, //奇偶行是否区分 singleSelect: true,//单选模式 rownumbers: true,//行号 columns: [[ { field: 'Id', title: '@BaseRes.TitleID', width: 80, hidden: true }, { field: 'Title', title: '标题', width: 280, sortable: true }, { field: 'UserId', title: '发起用户', width: 80, sortable: true, hidden: true }, { field: 'FormId', title: '对应表单', width: 80, sortable: true, hidden: true }, { field: 'FormLevel', title: '公文级别', width: 80, sortable: true,align:'center', formatter: function (value) { if(value==@((int)FlowFormLevelEnum.Ordinary)){return "<span>普通</span>";} if(value==@((int)FlowFormLevelEnum.Major)){return "<span class='color-yellow'>重要/span>";} if(value==@((int)FlowFormLevelEnum.Urgent)){return "<span class='color-red'>紧急</span>";} return ""; } }, { field: 'CreateTime', title: '@BaseRes.TitleCreateTime', width: 110, sortable: true}, { field: 'TimeOut', title: '截至时间', width: 80, sortable: true, formatter: function (value) { return SubStrYMD(value) } }, { field: 'CurrentStep', title: '当前环节', width: 80, sortable: true, align: 'center' }, { field: 'CurrentState', title: '当前状态', width: 80, sortable: true, align: 'center', formatter: function (value, row, index) { var _pass = "<span class='color-green fa fa-circle'></span>"; var _progress = "<span class='color-blue fa fa-circle'></span>"; var _reject = "<span class='color-red fa fa-circle'></span>"; var _close = "<span class='color-gray fa fa-circle'></span>"; if(value==@((int)FlowStateEnum.Pass)){ return _pass;} if(value==@((int)FlowStateEnum.Progress)){ return _progress;} if(value==@((int)FlowStateEnum.Reject)){ return _reject;} return _close; } }, { field: 'Action', title: '操作', width: 80, sortable: true, align: 'center' } ]] }); }); //ifram 返回 function frameReturnByClose() { $("#modalwindow").window('close'); } function frameReturnByReload(flag) { if (flag) $("#List").datagrid('load'); else $("#List").datagrid('reload'); } function frameReturnByMes(mes) { $.messageBox5s('@BaseRes.Tip', mes); } function LookFlow(formId) { $("#modalwindow").html("<iframe width='100%' height='100%' scrolling='auto' frameborder='0' src='@Url.Action("Details")?id=" + formId + "&Ieguid=" + GetGuid() + "'></iframe>"); $("#modalwindow").window({ title: '图例', width: 500, height: 380, iconCls: 'fa fa-list' }).window('open'); } function ManageFlow(title, formId, id) { var href = "@Url.Action("Edit")?formId=" + formId + "&id=" + id + "&Ieguid=" + GetGuid() + ""; if(isExitsFunction(window.parent.addTab)) { window.parent.addTab(title, href, 'fa fa-pencil'); }else { window.open(href); } } </script>
依次添加没有难度
3.审批页面
审批页面基本和我的申请的编辑一致
4.先看看审批的代码执行流程图:
审批有点难度,需要覆盖上面图示流程。以下代码
[HttpPost] [SupportFilter] public JsonResult Edit(string Remark, string TheSeal, string FormId, int Flag, string ContentId,string UserList) { string stepCheckId = formContentBLL.GetCurrentStepCheckId(FormId, ContentId); if (stepCheckId == "") { return Json(JsonHandler.CreateMessage(0, BaseRes.EditFail)); } Flow_FormContentStepCheckStateModel stepCheckStateModel = stepCheckStateBLL.GetByStepCheckId(stepCheckId); if (stepCheckStateModel.UserId != GetUserId()) { return Json(JsonHandler.CreateMessage(0, "越权操作!")); } stepCheckStateModel.Reamrk = Remark; stepCheckStateModel.TheSeal = TheSeal; stepCheckStateModel.CheckFlag = Flag; if (stepCheckStateBLL.Edit(ref errors, stepCheckStateModel)) { //获取当前步骤 Flow_FormContentStepCheckModel stepCheckModel = stepCheckBLL.GetById(stepCheckStateModel.StepCheckId); //获得当前的步骤模板 Flow_StepModel currentStepModel = stepBLL.GetById(stepCheckModel.StepId); //驳回直接终止审核 if(Flag==(int)FlowStateEnum.Reject) { stepCheckModel.State = Flag; stepCheckModel.StateFlag = false; stepCheckBLL.Edit(ref errors, stepCheckModel); //重置所有步骤的状态 stepCheckBLL.ResetCheckStateByFormCententId(ContentId, (int)FlowStateEnum.Progress, (int)FlowStateEnum.Progress); LogHandler.WriteServiceLog(GetUserId(), "Id" + stepCheckStateModel.Id + ",StepCheckId" + stepCheckStateModel.Reamrk, "成功", "修改", "Flow_FormContentStepCheckState"); return Json(JsonHandler.CreateMessage(1, BaseRes.CheckSucceed)); } else if (currentStepModel.IsAllCheck) { //启用会签 //获得同步骤的同批审核人 List<Flow_FormContentStepCheckStateModel> stepCheckStateList = stepCheckStateBLL.GetListByStepCheckId(ref setNoPagerAscById, stepCheckStateModel.StepCheckId); //查看自己是否是最后一个审核人 bool complete = stepCheckStateList.Where(a => a.CheckFlag == (int)FlowStateEnum.Progress).Count() == 1; if (complete) { stepCheckModel.State = Flag; stepCheckModel.StateFlag = true; stepCheckBLL.Edit(ref errors, stepCheckModel); } else { //让审核人继续执行这个步骤直到完成 LogHandler.WriteServiceLog(GetUserId(), "Id" + stepCheckStateModel.Id + ",StepCheckId" + stepCheckStateModel.Reamrk, "成功", "修改", "Flow_FormContentStepCheckState"); return Json(JsonHandler.CreateMessage(1, BaseRes.CheckSucceed)); } } else { //不是会签,任何一个审批都通过 stepCheckModel.State = Flag; stepCheckModel.StateFlag = true; stepCheckBLL.Edit(ref errors, stepCheckModel); } if (!stepCheckModel.IsEnd) { List<Flow_FormContentStepCheckModel> stepCheckList = stepCheckBLL.GetListByFormId(FormId, ContentId); int j = 0; for (int i = stepCheckList.Count() - 1; i >= 0; i--) { if (stepCheckId == stepCheckList[i].Id) { j = i; } } //查看是否还有下一步步骤 if(j-1<=stepCheckList.Count()) { //查有第二步骤,查看是否是自选 Flow_StepModel stepModel = stepBLL.GetById(stepCheckList[j + 1].StepId); if (stepModel.FlowRule==(int)FlowRuleEnum.Customer) { foreach (string userId in UserList.Split(',')) { //批量建立步骤审核人表 CreateCheckState(stepCheckList[j + 1].Id, userId); } } else { //批量建立审核人员表 foreach (string userId in GetStepCheckMemberList(stepCheckList[j + 1].StepId)) { //批量建立步骤审核人表 CreateCheckState(stepCheckList[j + 1].Id, userId); } } } } LogHandler.WriteServiceLog(GetUserId(), "Id" + stepCheckStateModel.Id + ",StepCheckId" + stepCheckStateModel.Reamrk, "成功", "修改", "Flow_FormContentStepCheckState"); return Json(JsonHandler.CreateMessage(1, BaseRes.CheckSucceed)); } else { string ErrorCol = errors.Error; LogHandler.WriteServiceLog(GetUserId(), "Id" + stepCheckStateModel.Id + ",StepCheckId" + stepCheckStateModel.Reamrk + "," + ErrorCol, "失败", "修改", "Flow_FormContentStepCheckState"); return Json(JsonHandler.CreateMessage(0, BaseRes.CheckFail + ErrorCol)); } }
USE [AppsDB] GO /****** Object: StoredProcedure [dbo].[P_Flow_ResetCheckStepState] Script Date: 2016/1/13 21:48:59 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: <Author,,Name> -- Create date: <Create Date,,> -- Description: <Description,,> -- ============================================= ALTER PROCEDURE [dbo].[P_Flow_ResetCheckStepState] @ContentId varchar(50), @CheckState int, @CheckFlag int AS BEGIN --重新设置当前表单步骤的状态 update Flow_FormContentStepCheck set State=@CheckState where ContentId=@ContentId --根据表单步骤设置其子下步骤分解的状态 declare FormContentStepCheckState_Cursor cursor scroll for select Id from Flow_FormContentStepCheckState where StepCheckId in ( select Id from Flow_FormContentStepCheck where ContentId=@ContentId ) open FormContentStepCheckState_Cursor declare @tempId varchar(50) fetch next from FormContentStepCheckState_Cursor into @tempId while @@FETCH_STATUS=0 begin update Flow_FormContentStepCheckState set CheckFlag=@CheckFlag where Id=@tempId fetch next from FormContentStepCheckState_Cursor into @tempId end close FormContentStepCheckState_Cursor deallocate FormContentStepCheckState_Cursor END
涉及重置所有步骤的状态存储过程。
代码分析:
1.获取当前步骤
2.获得当前的步骤模板
3.驳回直接终止审核(重置所有步骤的状态)
4.会签,获得同步骤的同批审核人
作者:YmNets
出处:http://ymnets.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://ymnets.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。