wenmo8 发布的文章

在很多开发的场景中,很多情况下我们需要考虑抽象、以及模块化等方面的内容,其目的就是为了使得开发的时候关注的变化内容更加少一些,整体开发更加简单化,从而减少开发的复杂度,在Winform开发的时候,往往可以通过定义基类模块、用户控件的方式实现这个目的,而在Web开发的时候,我们是否也可以利用这些特性呢?特别在MVC的视图模板里面的HTML,是否可以利用这些特点,实现变化部分的隔离,从而减少整个页面的复杂度,同时又可以提高模块的重用性呢?本篇随笔介绍在Asp.NET的MVC视图处理上,使用@RenderPage实现页面内容模块化的隔离,减少复杂度。

1、回顾Winform的界面处理方式

举工作流表单处理为例说明,由于在处理流程的时候,对于表单的处理,大多数情况下的规则和处理逻辑差不多,因此可以把这些不变的内容抽离到基类界面里面,对于Winform方式,我们通过继承不同的业务窗体对象就可以实现了,如下处理方式所示。

由于基类确定了,封装了大多数的处理规则,那么在子类界面的时候,需要处理的只是和业务界面有关的赋值或者读取值的操作了,我们对于不同的业务表单,做起来就很容易了,只需要把变化的部分内容放在子窗体即可。

例如对于出差申请和会议室使用申请的表单,它们的窗体界面继承关系如下所示。

这个就是Winform界面处理的方式, 对于在Bootstrap开发框架的前端视图中,如何以类似的规则处理这些界面的分离操作呢?

答案是使用@RenderPage实现页面内容模块化的隔离。

2、使用@RenderPage实现页面内容模块化的隔离

一般在开始的时候,我们注意到了,在MVC视图中使用母版的操作中,已经隔离了页面布局相同部分,子窗体只需要定义不同部分的视图代码即可。

而进一步,我们还可以在子页面中使用@RenderPage来区分隔离不同业务界面的内容的。

例如对于创建表单界面的视图内容。

上面视图分为了几个部分的内容,一个是创建表单的界面处理,其中涉及到的选择用户界面,是一个弹出的用户选择框,由于选择用户处理是一个常见的操作,我们需要把它抽离到一个视图页面里面,可以在需要的时候,直接通过使用@RenderPage实现页面内容模块化。

@RenderPage("~/Views/Apply/SelectUser.cshtml")

当用户单击【选择流程处理人】的按钮的时候,弹出一个DIV层,这个就是我们刚才使用@RenderPage实现的选择用户界面了,这种处理方式比较弹性化,在需要的时候,包含进来即可,不用把大段大段的代码重复复制过来,方便了维护代码。

同样,对于查看表单界面来说,虽然它的界面内容比新建业务表单的界面复杂很多,但是使用的是一样的处理方式。

刚才我们看到了,在Winform界面里面,使用的是下面的视图继承的方式。

而在MVC视图界面里面,采用的是@RenderPage实现页面内容的模块化。

这样主视图和子视图虽然同名,但是它们是在不同的控制器名下,这样我们在父页面视图的ViewDetail.cshtml就可以封装一些常见的处理界面内容,而留下部分和具体业务表单相关的展示内容放在子页面的ViewDetail.cshtml里面即可。

在页面地址中,得到完整的页面访问路径是:/Reimbursement/ViewDetail?id=8f32231d-852e-9f16-6e5a-79031c8ec995,这个URL其实就是访问具体业务视图下的内容,但是业务视图已经引用了父页面共同的部分。

我们来看看具体业务表单中的视图页面代码,如下所示。

其中的不变的业务界面内容(理解为父窗体也可以),我们通过引用页面的方式把它包含进来。

<!--此处放置业务表单的数据呈现,方便隔离,减少复杂性-->@RenderPage("~/Views/Apply/ViewDetail.cshtml", new { applyId = Request["id"] })

这样就把它们分开维护了,共同的部分就在这个 Views/Apply/ViewDetail.cshtml 视图页面里面了。

而这个共同的部分,则可以封装常规的事件处理,和界面展示,如下是界面视图的截图说明。

其中我们还可以看到通用选择用户的视图层界面

@RenderPage("~/Views/Apply/SelectUser.cshtml")

最后我们来看看两个不同的视图界面效果,以烘托一下隔离界面也不影响整体效果,但是可以降低代码的维护复杂性。

新建业务流程表单如下界面所示。

查看具体流程表单明细的界面如下所示。

在前面随笔《
在Bootstrap开发框架中使用dataTable直接录入表格行数据
》中介绍了在Web页面中使用Jquery DataTable插件进行对数据直接录入操作,这种处理能够给用户提供较好的数据录入体验,本篇继续上篇的内容,继续介绍这个直接录入的处理操作,主要涉及到控件的初始化和数据源的绑定等操作内容,随着对这个处理的深入了解,我发现可以控制的内容也更加丰富,能够更好的实现各种所需的效果。

1、直接录入数据的界面分析

在之前介绍的数据直接录入处理的时候,界面效果如下所示。

上面的界面处理明细数据的时候,可以直接使用新增记录,直接在录入框中输入数据,然后保存起来,保存后数据变为只读,如果需要修改,还可以单击编辑按钮进行修改。

而这些明细的数据,也仅仅存在JS的对象里面,还没有保存到后台数据库中,我们可以在最后保存(如上界面的确定按钮)处理中再获取全部添加的数据进行提交即可。

以上的明细数据录入,只是提供了一些基本的输入控件进行输入,没有进行过多的定制处理,而往往使用的时候,我们发现,有些数据是需要下拉列表的,有些是需要使用日期选择的等等,那么我们就需要考虑更深层次的控件显示问题了。

如我们要实现更丰富的效果处理,甚至包括一些控件之间的联动的处理,那么我们应该如何操作呢?

下拉列表,动态数据界面展示

日期输入框显示

以上一些是我们常规的录入方式,对于有一些比较多样化的操作,我们尽可能为用户提供方便,提供下拉控件给用户选择,毕竟选择比录入更加方便、规范化。

如可以在复杂界面中,使用弹出层进行查询选择

如部门和用户之间的数据联动效果如下所示。

以上种种效果,能够满足我们常规的数据选择录入的方便,从而方便客户直接录入数据处理。

2、直接录入数据的控件初始化

我们从上文可以了解到,对于新增一套记录,就是动态构建一些HTML的控件,然后进行初始化即可,如对于这个下拉列表的界面效果。

它的实现主要就是在编辑或者新增的时候,对HTML控件的处理,如下代码所示。

    //编辑行
    functioneditRow(oTable, nRow) {var aData =oTable.fnGetData(nRow);var jqTds = $('>td', nRow);var i = 0;var feeType = aData[0];
jqTds[i].innerHTML
= '<select id="txtFeeType" class="form-control input-small" value="' + aData[0] + '"></select>';
i
++; jqTds[i].innerHTML = '<input id="txtOccurTime" class="form-control input-small" value="' + aData[1] + '">';
i
++; jqTds[i].innerHTML = '<input id="txtFeeAmount" type="number" class="form-control input-small" value="' + aData[2] + '">';
i
++; jqTds[i].innerHTML = '<input id="txtFeeDescription" type="text" class="form-control input-small" value="' + aData[3] + '">';
i
++; jqTds[i].innerHTML = '<a class="btn btn-xs green edit" href="" title="保存">保存</a>';
i
++; jqTds[i].innerHTML = '<a class="btn btn-xs red cancel" href="" title="取消"><span class="glyphicon glyphicon-share-alt "></span></a>';//绑定数据字典,并更新值 BindDictItem("txtFeeType", "费用类型", function() {
$(
"#txtFeeType").val(feeType).trigger("change");
});
//初始化日期控件 $("#txtOccurTime").datepicker({
language:
'zh-CN', //语言 autoclose: true, //选择后自动关闭 clearBtn: true,//清除按钮 format: "yyyy-mm-dd"//日期格式 });
}

我们可以在下拉列表的时候,使用select2插件,通过BindDictItem的通用JS函数,可以绑定数据库的字典类型,并通过记录对应列的值,可以给该控件进行赋值。

 $("#txtFeeType").val(feeType).trigger("change");

由于每个控件都有一个对应的ID,那么我们使用它们的时候,就很方便,如初始化日期插件,可以使用DateTime Picker插件进行处理。

        //初始化日期控件
        $("#txtOccurTime").datepicker({
language:
'zh-CN', //语言 autoclose: true, //选择后自动关闭 clearBtn: true,//清除按钮 format: "yyyy-mm-dd"//日期格式 });

最终达到了日期选择效果。

使用弹出层进行查询选择的操作过程也很简单。

                    jqTds[i].innerHTML = '<input id="txtAssetName" type="text" class="form-control input-small" onclick="SelectAssets(this)" value="' + aData[i] + '">';//资产名称

也就是为这个控件增加onclick函数,在选择单击输入的时候,弹出一个层进行处理即可。而这个独立的通用层,则使用一个单独的视图,在页面里面引用即可,提高重用性。

@RenderPage("~/Views/Asset/SelectAsset.cshtml")

而通过在页面里面处理返回结果,则可以实现主界面内容控件的更新。

//选择结果
functionSelectResult() {var dict ={};
addAssetKeyList.forEach(
function(key, index, array) {var display =addAssetDisplayList[index];
dict[key]
=display;
});
//转换选择为JSON字符串 var json =JSON.stringify(dict);
$(
"#selectAsset").modal("hide");//留给调用的界面实现这个函数,实现数据的返回出来 ProcAssetJson =json;
OnSelectAsset(json);
}

而选择后,可以对控件内容以及关联的数据进行动态更新。

        //选择资产后调用
        functionOnSelectAsset(json) {
ProcAssetJson
= json;//存储到ProcAssetJson,方便下次打开界面初始化数据 if (json != '') {var dict =JSON.parse(json);if (dict != null) {for (var key indict) {var display =dict[key];
assetInput.val(display);
//更新数据 $.getJSON("/Asset/FindByCode?code=" + key, function(info) {if (info != null) {
$(
"#txtAssetCode").val(info.Code);//$("#txtKeepAddr").val(info.KeepAddr); $("#txtUnit").val(info.Unit);
$(
"#txtPrice").val(info.Price);
$(
"#txtTotalQty").val(info.Qty);
$(
"#txtTotalAmount").val(info.OriginValue);
}
});
};
}
}
}

下面就是弹出界面层,并提供用户选择内容的界面

对于部门和用户之间的数据联动的处理,也是通过Select2控件的联动更新处理实现的。以下是Select2联动处理脚本,可以实现多个控件之间的联动操作

//部门编号后,用户列表编号
$("#txtLyDept").on("change", function(e) {var deptNameId = $("#txtLyDept").val();if (deptNameId != null) {var id = deptNameId.substring(deptNameId.lastIndexOf("|") + 1);
BindSelect(
"txtUsePerson", "/User/GetUserDictJson2?deptId=" + id, '', function() {
$(
"#txtUsePerson").val(userid).trigger("change");
});
//存储位置 BindSelect("txtKeepAddr", "/StoreAddress/GetDictJson?deptId=" + id, '', function() {
$(
"#txtKeepAddr").val(keepAddr).trigger("change");
});
}
});

界面效果如下所示。

由于我们在控件的ID上约定了以txt开头,那么我们通过这个约定规则动态获取控件的值也是很方便的,这样为我们保存控件的数据提供很好的便捷处理。

//保存行数据,切换到普通模式
var inputLength = 10;//输入的字段数
functionsaveRow(oTable, nRow) {//var jqInputs = $('input', nRow);
    var jqInputs = $("[id^='txt']", nRow);//id以txt开始([id^='txt']), id以txt结束([id$='txt'])

    //更新行中每个input的值
    for (var i = 0; i < inputLength; i++) {
oTable.fnUpdate(jqInputs[i].value, nRow, i,
false);
iLen
=i;
}

oTable.fnUpdate(
'<a class="btn btn-xs green edit" href="" title="编辑"><span class="glyphicon glyphicon-edit"></span></a>', nRow, inputLength, false);
oTable.fnUpdate(
'<a class="btn btn-xs red delete" href="" title="删除"><span class="glyphicon glyphicon-remove"></span></a>', nRow, inputLength + 1, false);
oTable.fnDraw();
}

我们如果需要保存数据到数据库里面,那么就需要先构建好对应的JS数据对象,然后调用ajax进行数据的提交处理。构建JS数据对象如下代码所示(根据自己所需定制数据内容)。

            //获取表格的数据,并返回对象列表
            functionGetData() {var list =[];var trs =table.fnGetNodes();for (var i = 0; i < trs.length; i++) {var data = table.fnGetData(trs[i]);//获取指定行的数据

                    //构建对象
                    var obj ={
AssetName: data[
0],
AssetCode: data[
1],
LyDept: data[
2],
UsePerson: data[
3],
KeepAddr: data[
4],
Unit: data[
5],
Price: data[
6],
TotalQty: data[
7],
TotalAmount: data[
8],
Note: data[
9]
};
list.push(obj);
}
returnlist;
};

在很早之前的随笔里面,已经介绍了WInform框架中工作流模块的功能,不过由于工作流模块中界面处理部分比较麻烦,一直没有在Bootstrap框架中进行集成,最近由于项目的关系,花了不少精力,把工作流模块重新梳理迁移到Bootstrap框架上,本篇随笔主要介绍基于Metronic的Bootstrap开发框架的工作模块功能。

1、工作流的设计模型

在我们开始介绍工作流模块功能之前,我们需要了解下工作流模块的设计模型,以便我们更好深入了解各个部分的功能。

我们知道,我们在Office里面创建任何文档,都有一个模板的概念,这样我们方便利用一些现成的数据和布局,工作流也一样,有一个流程模板的概念。每个流程模板,本身会预定义了一系列的处理流程,以便在流程实例里面进行不同的处理,因此流程模板还包含了多个流程步骤对象。每个流程实例,除了他们自己的流程数据和字段信息外,它本身还有一个表单设计的问题,如费用审批,可能包含填写的费用清单数据等,所以流程实例还应该包含了流程的业务表单对象。

在工作流处理表中,首先我们区分流程模板和流程实例两个部分,这个其实就是类似模板和具体文档的概念,我们一份模板可以创建很多个类似的文档,文档样式结构类似的。同理,流程模板实例为流程实例后,就是具体的一个流程表单信息了,其中流程模板和流程实例表单都包括了各个流程步骤。在流程实例的层次上,我们运行的时候,需要记录一些日志方便跟踪,如流程步骤的处理日志,流程实例表单的处理日志等这些信息。

一旦流程实例根据模板创建后,流程先根据模板初始化后,在处理过程还可以动态增加一些审批步骤,使得我们的处理更加弹性化。

当然,为了更好的处理流程的相关信息,还需要记录流程处理人,流程会签人、流程阅办人,以及常用审批意见等相关辅助表,以便对流程的各个处理信息进行合理处理和展示。

对于一个流程处理操作,我们知道一般有审批通过、拒绝、退回到某步骤、转发到内部阅读、阅读,以及包括起草者能撤销表单呢等操作,当然如果还有一些具体的业务,可能还会有一些流程的处理才操作,不过基本上也可以归结为上面几种,只是他们每步处理的数据内容不同而已。因此审批的操作步骤分类如下所示。

在流程审批中,一般还有一种流程处理就是会签的操作,会签处理是几个审批步骤中审批人同时处理是否通过的,一般同时通过即为通过。

会签是指创建一个或多个子流程供相关人员进行审批,等待全部人员完成处理后再次回到主流程上,然后决定是否继续流转到下一个流程步骤上去,一般的申请单的主流程如下所示。

这里设置的会签处理就是其中一个步骤,一旦会签处理步骤发起会签,就会构建多个可供审批的子流程了,如下所示。

在会签发起的步骤,指定参与具体流程会签审批的人员,然后流程则会流转到不同人员进行相关的处理【待办事项】。

我在工作流中定义会签完成后,由会签发起人审核(会签结果审核),决定是否进入下一步流程,在审核过程中决定如何处理这个申请单。

2、工作流模块介绍

1)流程环节管理

从上面的基础知识介绍中,我们知道,流程环节是构成流程模板和流程实例的基本单元,我们需要定义不同类型的流程处理环节,如审批、会签、阅办等等,不同类型的流程环节,在流程步骤的处理环节中是不一样的,我们也为这些不同的环节定义不同的审批界面。

首先我们在Bootstrap框架的系统菜单中选择【工作流管理】【工作流维护】【流程环节管理】菜单,就可以进入对应的流程环节管理界面。

在流程环节管理界面中,会列出系统所有定义好的流程环节,我们也可以定义自己的流程步骤。

在系统主界面里面,我们一般已经预定义了一些常规的如审批、会签、阅办、归档等类型,我们如果需要定义特殊的审批界面,我们就可以在这里定义一些不同的流程环节,也可以对已有的环节进行一定的修改处理。

2)流程模板管理

通过第一步的流程环节定义,我们接下来就基于流程环节,定义流程模板的内容了,流程模板是我们开展一些工作流的基础,也就是说,我们先有特定流程的模板,然后才有具体的流程示例。

流程模板我们定义的时候,需要指定它的具体名称,另外有几个字段是必须注意的,就是它的对应业务表名和创建流程URL、查看流程URL这几个信息。

指定这些内容,我们在指定的视图页面中处理不同的流程信息,创建在Create视图、查看在ViewDetail视图,其中还会包含一个index视图列出该类型的申请单,这几个列表都可以使用代码生成工具快速生成,具体代码的生成过程,我会在随后的文章中及进行详细介绍。

这样的自动化,可以迅速提高我们开发工作流业务的效率,并且和整个系统风格保持统一。这个就是我们整个开发框架系列的精髓所在,以工具提高效率,统一过程。

再次回到流程模板的处理来,我们刚才只是定义了流程模板的一些基础信息,对于这个流程模板,我们还需要确定它的流程步骤,这个才是工作流的灵魂所在,动态化的流程步骤,可以满足我们大多数变化流程的需要。

流程步骤的定义,如下界面所示,可以指定流程处理人,通过选定角色、部门或者具体人员都可以,如果没有选择具体的处理人,那么默认会以当前用户部门的人员供选择。

如但用户选择人员的时候,弹出层可以根据组织机构、角色进行用户的筛选和选择。

3)业务受理列表

业务受理列表,是根据我们数据库中定义的流程模板,动态列出申请单的创建入口,提供一个统一的入口方便我们处理。

一下是我们工作流模块中定义好的一些流程模板,可以供创建业务表单。

这些业务表单入口,单击后就可以创建对应类型的申请单了,我们以刚才介绍的请假申请为例,单击后进入请假申请单的Create视图界面,创建新的申请。

其他的业务申请单也是类似,我们只需要使用代码生成工具Database2Sharp对具体业务表单的工作流模块代码进行生成后,就可以配置使用,并且可以创建对应的业务表单的了。

对于一些具有明细表单的操作,也有案例可以供参考。

4)我的审批工作

我的审批工作是列出和我相关的审批表单,包括已办、待办、 发起的几种类型的分类,其中每个种类型又可以继续细化不同表单类型,方便我们快速选择查看,如下列表所示。

通过快速定位所需要的类型申请单,我们可以很好的完成一些待办工作,以及可以查看自己参与的流程申请单的处理情况等等。

双击其中的申请单,可以查看具体的申请详细信息,包括流程审批信息和业务表单信息等。

而如果是流程处理中的申请单,我们可以在相关的处理按钮中执行我们自己的审批操作。

5)所有申请单

所有申请单是提供一个给流程管理员的一个入口,方便对一些错误或者不需要的申请单进行删除等维护操作。

这里面列出的是系统所有的申请单,这个页面一般不暴露给普通用户,而是作为后台数据管理的一个页面,对不需要的数据进行删除操作的。

6)我的草稿

我的草稿是提供一个界面维护我自己的申请单草稿的,界面效果如下所示。

在我们创建申请单的时候,有时候录入数据后暂时想存起来而不提交的话,保存为草稿就可以,下次则可以直接从草稿中继续申请单的处理。

本篇继续《
基于Metronic的Bootstrap开发框架--工作流模块功能介绍
》,继续介绍基于Metronic的Bootstrap开发框架的工作模块功能,介绍工作流模块中相关业务表单的界面设计和管理操作,以及在业务表单中设计到的审批、发起会签、会签确认、会签、撤销、领导批示分阅、阅办等常规操作,以及一些明细表单的数据录入展示。

1、工作流主页视图

在工作流模块中,我们可以把一些待办或者已办的事项放在首页里面,方便登陆后直接可以参考最新的一些信息,如下界面所示。

而在工作流的业务表单模块中,我们可以提供了很多相关的业务表单管理界面,可以通过对应的功能菜单进入对应的工作流业务表单列表,以下是工作流模块提供的一些常见业务表单。

2、工作流业务表单

1)付款申请

付款申请列表管理如下所示,可以根据相关条件进行筛选查看相关申请单。

我们可以在新增入口创建一个新的付款申请单,如下界面所示。

在选择流程处理人中,单击按钮会弹出一个用户选择按钮供选择,如下界面所示。

在申请单的创建界面左下角,有一个【存为草稿】的按钮,单击可以保存该申请单到草稿里面,方便下次打开提交申请单,这个保存草稿是一个通用的操作,在各个申请单都有这样的按钮供选择。

提交申请单成功后,会返回对应申请单列表的主界面,会发现申请单处于【处理中】的状态,双击可以打开该申请单进行详细信息的查看。

在查看信息的顶部有对应的流程处理按钮,如果用户是流程参与人,那么可以执行相关的处理。

审批是一个通用的常规处理操作,弹出界面需要录入处理意见,以及下一步流程的处理人员,如下界面所示。

同样,如果不通过该申请,那么可以选择【退回拟稿人处理】和【退回上一步处理】两个其他处理。

【退回拟稿人处理】是直接拒绝该申请单,让用户重新修改后可以再次提交的,【退回上一步处理】则是退回上一个步骤,如果过程涉及很多步骤,也就仅仅倒回一步。

当然,这个处理过程中,我们可以动态增加一个流程步骤,也就是【增加一步审批】,然后指定增加步骤的处理人即可,如下界面所示。

在查看明细的审批的处理按钮中,如果我们是流程发起人,那么我们可以撤销该申请单,撤销界面如下所示。

而流程日志以及打印功能是常规的处理操作,流程日志列出整个申请单处理流程的日志,以及申请单处理的历史信息和系统日志,如下界面所示。

对于有些流程处理步骤设置环节为会签的,那么会执行相关的会签操作。

会签是指创建一个或多个子流程供相关人员进行审批,等待全部人员完成处理后再次回到主流程上,然后决定是否继续流转到下一个流程步骤上去,一般的申请单的主流程如下所示。

这里设置的会签处理就是其中一个步骤,一旦会签处理步骤发起会签,就会构建多个可供审批的子流程了,如下所示。

例如对于进入发起会签的申请单,我们可以看到功能按钮中有一个【发起会签】的功能,如下所示。

发起会签的时候,我们需要指定相应会签的人员,如下是发起会签的审批界面。

而如果我们是会签人员列表中的用户,我们查看对应的申请单明细的时候,就会发现有【会签】的功能按钮,如下界面所示。

会签是所有人员全部批准通过才会确认通过,这个可以在会签结果审核界面进行处理即可,会签的审批界面如下所示。

所有参与会签人员提交意见后,发起会签的人员会看到【会签确认】的功能按钮,如下所示。

会签确认是有发起人决定是否通过该项会签,并进行下一步处理的功能,它是一个标准的审批功能。

完成后,我们查看对应的申请单,可以看到对应步骤的会签处理信息,都会呈现在这个表单明细里面,如下所示。

【批示分阅】步骤则是我们希望给相关人员传阅了解申请单的一个处理过程,同样它是一个选择多个用户参与传阅的处理,如下是【批示分阅】审批步骤。

完成后,整个申请单信息如下界面所示。

以上就是付款申请单,涉及到常规审批过程、会签过程(包括发起会签、会签、会签确认)、领导批示分阅、阅办等过程,一般情况下,我们可能涉及到一个或者几个处理过程,而这些过程我们是在流程模板里面进行定义的。

一旦定义好后,新生成的申请就以流程模板的步骤为参考申请对应的流程步骤,同时我们也可以在审批过程中,动态增加一些流程步骤,这样的弹性设置在一些临时需要增加一些审批步骤是非常方便的。

2)报销申请

在报销申请单处理中,往往提交 一些主表信息外,也会涉及到一些报销明细的录入,我们这里提供了一个表格直接录入数据的方式,减少用户维护数据的复杂性,非常方便。

上面明细清单信息,可以通过新增记录按钮,增加一条空白的记录,然后部分字段可以通过列表方式进行选择,保存提交申请单的时候,会自动把明细数据一并保存的。

保存申请单后,系统直接跳到【我的审批工作】界面,如下界面所示。

或者我们也可以查看报销申请单的列表界面。

查看具体报销申请单信息界面如下所示,其右上角的审批、撤销、流程日志、打印等功能按钮也会根据情况显示出来。

而这里的明细清单,则以表格方式进行列出,非常直观友好。

3)资产领用

介绍了一个报销申请的流程,我们再来介绍一个资产管理中的资产领用申请单,这也是一个比较有代表意义的流程申请单,具有明细处理的信息。

创建资产领用申请单界面如下所示,其中涉及了很多下拉列表联动选择的操作,明细的录入也是通过直接编辑表格的方式进行录入。

查看界面如下所示。

和其他流程表单不同的是,这个申请单中,在流程没有完成之前,明细清单可以在各个步骤进行编辑修改、删除等操作,由最后一个审批人进行维护并提交明细,流程完成后则不能继续编辑表单中的明细信息。

同时在流程完成后,会同时修改主资产信息的部分字段,从而完成了整个闭环的处理操作。

当然工作流模块中还有很多范例的表单,如开始列出的菜单中包含的内容。

不过由于其他界面上也比较类似,也就不再一一赘述,关键这些业务表单也是通过代码生成工具直接生成对应的Create、ViewDetail、Index视图代码和控制器代码的,因此这些业务表单的信息就不在一一介绍。

整个工作流模块,各个页面的职责比较清晰,基本上Create就是新建或者重新编辑、ViewDetail就是查看明细信息、index就是对应表单的列表界面显示,而其中涉及到的选择流程用户、选择资产等特殊操作,我们是定义一些共同的页面视图即可完成,在需要使用到的地方加入对应的页面即可,提高视图页面和脚本的重用性。

在前面随笔《
基于Metronic的Bootstrap开发框架--工作流模块功能介绍
》和《
基于Metronic的Bootstrap开发框架--工作流模块功能介绍(2)
》中介绍了Bootstrap开发框架的工作模块功能,前面文章也提及,通过代码生成工具直接生成对应的Create、ViewDetail、Index视图代码和控制器代码,本篇随笔介绍如何使用使用代码生成工具Database2Sharp快速生成工作流模块控制器和视图代码的过程。

1、工作流界面功能

工作流模块如果要增加一个业务表单的处理,那么界面包括了列表界面,创建和编辑申请单界面,查看申请单明细这几个界面,以及对应后台控制器的代码。其他共用的界面和代码,则是在整个工作流模块中通用的,不需要变化。

我们来关注下如果增加一个业务表单的情况下,需要的列表界面,创建和编辑申请单界面,查看申请单明细这几个界面。

这些使用代码生成工具Database2Sharp快速生成工作流模块界面,是集成了我们整个工作流处理方式,包括列表界面可以分页查询数据、编辑表单中选择用户、处理附件,以及查看明细界面中集成的各种流程处理步骤,包括审批、会签、退回、拒绝、查看流程日志、打印表单等等常规处理步骤。

2、使用代码生成工具Database2Sharp快速生成工作流界面

和常规的代码生成工具生成代码一样,我们打开代码生成工具,然后展开数据库表后,通过菜单的【Boostrap的Web界面代码生成】生成对应的代码即可。

通过选中对应的数据库表,就可以继续一步步处理了,最后确认代码生成即可。

生成代码后,我们可以看到在对应的目录有两个目录,MVCWebUI和WorkflowWebUI目录,如下所示。

两个目录MVCWebUI和WorkflowWebUI,其中MVCWebUI包含了常规Bootstrap框架的页面视图和控制器代码文件,如下所示。

而WorkflowWebUI目录则是我们这里需要重点关注的工作流视图页面代码文件,如下所示。

上面各个目录是对应我们业务表的内容,目录下面是有几个工作流模块中包括了列表界面,创建和编辑申请单界面,查看申请单明细这几个界面。

3、在项目中集成工作流界面代码

这几个工作流界面我们连同他们的目录一同复制到项目的视图目录里面即可,同时把常规Bootstrap界面中控制器复制到项目的控制器目录即可。

上面红框中就是我们一些工作流业务表单的视图目录,因此我们需要看看目录下面的几个文件。

集成这些页面代码后,我们还需要做一些基础的处理才能使用起来,就是需要定义一个业务表单信息。

1)流程模板定义

流程模板是我们开展一些工作流的基础,也就是说,我们先有特定流程的模板,然后才有具体的流程示例。

流程模板需要指定它的具体名称,另外有几个字段是必须注意的,就是它的对应业务表名和创建流程URL、查看流程URL这几个信息。

定义流程模板基本信息后,我们需要为这个流程模板设置对应的步骤,如下所示是增加一些流程步骤。

2)修改列表界面的表单ID

定义一个新的流程模板后,由于我们在流程管理界面中需要创建对应的申请单,那么我们需要知道这个流程模板的表单ID,因此需要在上面生成的工作流index.cshtml页面里面修改一个表单ID

创建定义完毕流程模板后,我们打开对应的表单记录,找到对应的表单ID

然后修改对应列表界面的formId为这个流程模板ID即可。

至此,这样整个界面就可以跑起来,而且也可以在列表页面里面直接创建对应表单的流程,类似下面的创建申请单界面。

创建业务申请单,那么也可以在业务受理列表里面创建。