由流程向导生成的功能是一打开功能,就显示一个流程的信息,有时候需要一打开功能,就显示多个流程的信息,例如下面的界面
order
在这个功能中,可以新加一条业务数据、新建一个流程、启动流程、流转等
并且定义了事件,在启动和流转之后,将该流程的处理环节和处理人回写到业务数据中并修改单据状态

1.新建

可以直接在grid列表中新建一条数据,这里设置了单据状态默认值为“未审批”,用来做流程的业务数据,当然需要自己执行“启动流转”,或者双击列表数据操作后面会介绍

2.新建流程

在listActivity.w文件中,通过按钮调用,调用justep.Shell.showPage方法,打开流程的启动界面,代码如下


	Model.prototype.button1Click = function(event) {
		var url = "$UI/demo/listProcess/process/listProcess/mainActivity.a";
		justep.Shell.showPage({
			url : url,
			title : "订单"
		});
	};

这样就实现了在列表流程中新建一个流程,跟直接从功能树列表中打开流程功能一样的

3.启动流程

在listActivity.w文件中放一个process组件,调用这个组件的start方法,启动流程
不需要设置process组件的data属性,autoClose、autoStart、autoSave、autoFilter都设置为false
代码如下,第3个参数传列表data的行ID


		var dList = this.comp("mainData");
		if (dList.getValue("fStatus") == "未审批") {
			this.comp("process1").start(null, null, dList.getCurrentRowID(), null);
			dList.refreshData();
		} else {
			alert("流转已经启动");
		}

因为已经启动了的流程不能再次启动,所以,为避免重复启动,添加了适当的判断代码

4.处理流程

处理流程就是对流程进行流转、回退等操作,方法是点击处理流程按钮时,调用justep.Shell.showPage方法打开流程当前环节对应的w文件,在界面上进行流转、回退等操作。
例如:流程的当前环节如果是订单申请(orderReportActivity),就打开/UI2/demo/listProcess/process/listProcess/orderReportActivity.w文件
流程的当前环节如果是订单审核(reviewedActivity),就打开/UI2/demo/listProcess/process/listProcess/reviewedActivity.w

那么,如何获得流程的当前环节等信息呢

这就需要,访问sa_task表,这里是定义了一个action(taskDataAction),在action中用KSQL设置过滤返回数据,设置过滤条件为
(SA_Task.sKindID=’tkTask’ or SA_Task.sKindID=’tkExecutor’ or SA_Task.sKindID IS NULL)
and (SA_Task.sStatusID=’tesReady’ or SA_Task.sStatusID=’tesExecuting’)
and (SA_Task.sTypeID IS NULL or SA_Task.sTypeID <> ‘WORKREMIND’)
注意还有sData1的过滤,需要从页面中传当前记录的rowid,因此action中要有一个参数String sData1

action对应的java代码如下:

	public static Table taskData(String sData1){
		String ksql="Select task,task.sEURL,task.sActivityName from SA_Task task where task.sData1 = '"+sData1+"' and (task.sKindID='tkTask' or task.sKindID='tkExecutor' or task.sKindID IS NULL)  " +
				"and (task.sStatusID='tesReady' or task.sStatusID='tesExecuting')  " +
				"and (task.sTypeID IS NULL or task.sTypeID <> 'WORKREMIND')";
		Table table =  KSQL.select(ksql, null, "/system/data", null);

		return table;
		
	}


经过上面的设置,返回的Table里面就是当前流程的当前环节的记录了。当然如果流程复杂,当前环节有多个,又都流转给了当前登录者或所在的机构,返回的Table里面的记录就不只一条了。需要先执行executeTaskAction

 

调用executeTaskAction的代码如下:

	Model.prototype.executeTask = function(taskID,executorFID){
		var executor= "";
		var params = new biz.Request.ActionParam();
		params.setString("task", taskID);
		params.setString("executor", executorFID);
		var options = {};
		options.context = this.getContext();
		options.action = "executeTaskAction";
		options.parameters = params;
		options.directExecute = true;
		options.callback = function(options) {
			if (options.state) {
				executor = options.response;
			} else {
				options.ignoreError = false;
			}
		};
		biz.Request.sendBizRequest(options);
		return executor;
	};

处理流程的代码如下(调用了执行executeTaskAction的js函数)

		var dList = this.comp("mainData");
		var sData1 = dList.getCurrentRowID();
		
		var context = this.getContext();
		var currentPersonID = context.getCurrentPersonID();
		var personMemberFIDs = context.getAllPersonMemberFIDs();
		var taskData = this.comp("taskData");

		// 定义action参数,请求taskDataAction获取当前环节的数据信息
		var param = new biz.Request.ActionParam();
		param.setString("sData1", sData1);
		biz.Request.sendBizRequest({
			"context" : context,
			"action" : "taskDataAction",
			"parameters" : param,
			"callback" : function(callbackData) {
				if (callbackData.state) {
					taskData.clear();
					taskData.loadData(callbackData.response);
					taskData.first();
				} else
					alert("任务数据获取失败");
			}
		});
		
		// 当有数据返回时获取对已经的任务进行处理
		var title,taskID,url,status,executorFID,executorPersonID =null;
		//一人或一个部门执行的
		if (taskData.getCount()===1) {
			title = taskData.getValue("sActivityName");// 获得当前环节名称,作为页面的标题
			taskID = taskData.getValue("task");// 获得任务ID,url中的参数
			url = taskData.getValue("sEURL");// 获得当前环节的url
			url = url + "?task=" + taskID + "&_pagePattern=write";// _pagePattern=write是必须的,表示要处理这个任务						
			executorPersonID = taskData.getValue("sExecutorPersonID");
			if (executorPersonID === currentPersonID) {// 如果执行者是否当前人
				justep.Shell.showPage({
					url : url,
					title : title
				}); // 调用justep.Shell.showPage方法打开流程当前环节对应的w文件
			}else {
				status = taskData.getValue("sStatusID");
				executorFID = taskData.getValue("sExecutorFID");
				if (status === "tesReady" && (personMemberFIDs.toString().indexOf(executorFID) > -1)) {// 判断执行者是否是当前操作者的所有人员成员所在的组织
					var executor =	this.executeTask(taskID,executorFID);
					justep.Shell.showPage({
						url : url,
						title : title,
						executor : executor || ""
					});
				} else {
					alert("任务应由其他人处理");
				}
			}
		}
		//多人或者多门户执行的
		else if(taskData.getCount() > 1 ){
			var tasks = taskData.find(['sExecutorPersonID'],[currentPersonID],false,false,false);
			//当前的人的任务
			if(tasks && tasks.length === 1){
				taskID = tasks[0].val("task");// 获得任务ID,url中的参数
				executorFID = tasks[0].val("sExecutorFID");
				var executor =	this.executeTask(taskID,executorFID);	//
				title = tasks[0].val("sActivityName");
				url = tasks[0].val("sEURL");// 获得当前环节的url
				url = url + "?task=" + taskID + "&_pagePattern=write";// _pagePattern=write是必须的,表示要处理这个任务
				justep.Shell.showPage({
					url : url,
					title : title,
					executor : executor || ""
				}); // 调用justep.Shell.showPage方法打开流程当前环节对应的w文件
			}
			else{
				//当前人所在的组织的任务
				var me = this;
				taskData.each(function(param){
					status = param.row.val("sStatusID");
					executorFID = param.row.val("sExecutorFID");					
					if(status === "tesReady" && (personMemberFIDs.toString().indexOf(executorFID) > -1)){	
						taskID = param.row.val("task");
						title = param.row.val("sActivityName");
						url = param.row.val("sEURL");// 获得当前环节的url
						url = url + "?task=" + taskID + "&_pagePattern=write";// _pagePattern=write是必须的,表示要处理这个任务						
						param.cancel = true;
					}
				});
				var executor =	me.executeTask(taskID,executorFID);
				justep.Shell.showPage({
						url : url,
						title : title,
						executor : executor || ""
				});
			}
		} else {
			alert("流转未启动、已完成");
		}
		

上面的代码只处理了返回的Table里面的一条记录,如果超过一条记录,请酌情处理
url中的参数,等同于从待办任务中打开功能时传递的参数

5.打开已结束的流程

对于已经结束的流程打开的方法不同于处理流程打开页面的方法。
处理流程打开页面的方法的方法是传入任务ID,系统根据任务ID,计算出业务数据ID,通过将process组件的autoFilter属性为true,让系统使用业务数据ID过滤数据。
已经结束的流程没有当前任务ID了,所以不使用上面的方法,而是使用直接传入业务数据ID,直接过滤的方式

新建listActivityDetail.w文件,可以继承自/UI2/demo/listProcess/process/listProcess/mainActivity.w文件,将process组件的autoFilter属性设置为false,bizData组件的autoLoad属性设置为false。

listActivity.w文件中打开已经结束的流程的代码如下

var dList = this.comp("mainData");
var url = "$UI/demo/listProcess/process/listProcess/listActivityDetial.a?_pagePattern=readonly";
			justep.Shell.showPage({
				url : url,
				process:"/demo/listProcess/process/listProcess/listProcessProcess",
				activity:"listActivity",
				title : "已完成订单",
				rowid : dList.getCurrentRowID()		
			});

其中参数rowid就是当前业务数据的ID,作为参数传给listActivityDetail.w

listActivityDetail.w文件的model的onParamsReceive事件里面获取参数rowid,进行数据过滤代码如下

	Model.prototype.modelParamsReceive = function(event){
	   this.sData1 = this.getContext().getRequestParameter("rowid");//获得传入的业务数据ID
	   var data = this.comp("mainData");
	   data.setFilter("filter1", "DE_Order = '"+this.sData1+"'");//给data设置过滤条件
	   data.refreshData();//刷新数据
	};

在listActivityDetail.w中查看流程和流程记录可以调用process组件中提供的API

this.comp("process").showChart(this.process, this.sData1);//查看流程图
this.comp("process").processRecord(null,this.process, this.sData1);//查看流程记录

由于两个API都需要传process和sData1的值,所以这里通过实例变量去设置的
实例遍历的定义代码如下:

	var Model = function(){
		this.callParent();
		this.sData1 = "";
		this.process = this.getContext().getCurrentProcess();
	};

6.定义流程事件,回写业务数据

如果流程每个环节都要执行的可以将代码应该该流程的事件中,不用在每个环节上的事件中实现
这列在流程启动和流转后去进行业务数据的会写可以在onAfterStart和onAfterAdvance中处理

	public static void listProcessProcessAfterStart() {
		updateBizRecord();
	}

	public static void listProcessProcessAfterAdvance() {
		
		updateBizRecord();
	}

	public static void updateBizRecord() {
		String sExecutorNames = "", sActivityNames = "", fStatus;
		//判断是否流转都最后,如果是状态设置为已完成,不是设置为审批中
		if (!ProcessUtils.isFlowToEnd()) {
			ProcessControl flowControl  = (ProcessControl)ContextHelper.getActionContext().getParameter("control");
			for (ProcessControlItem to : flowControl.getFlowTos()) {
				for (OrgUnit ect : to.getExecutors()) {
					sExecutorNames = sExecutorNames + CommonUtils.getNameOfFile(ect.getFName()) + " ";
				}
				sActivityNames = to.getTask().getActivityName();
			}
			fStatus = "审批中";
		}else{
			fStatus = "已完成";
		}
		String key = ProcessUtils.getProcessData1();
		String sConceptName = ProcessUtils.getProcessData2();
		String sDataModel = ProcessUtils.getProcessData3();
		String ksql = "update " + sConceptName + " o set o.fExecutePerson='" + sExecutorNames + "',o.fExecuteActivity='" + sActivityNames 
				+ "',o.fStatus='" + fStatus + "' where o='" + key +"'";
		KSQL.executeUpdate(ksql, null, sDataModel, null);		
	}

实现更新业务数据,需要知道业务数据的概念、ID及数据模块,因此使用sData2存放业务数据的概念,使用sData3存放数据模块,再加上系统自动将业务数据ID存入sData1,通过在启动规则中设置sData2和sData3就可以实现更新业务数据了。

启动规则的设置如下
start

7.双击列表中的记录,进行处理

至此,在业务数据中已经记录了流程的状态,根据这个状态,可以实现双击列表中的某条记录,对其进行相应的处理。
例如:对于没有启动的流程——流程状态为空,执行启动流程;
对于已经启动了,还未结束的流程——流程状态为审批中,执行处理流程,打开当前环节对应的页面;
对于已经流转结束的流程——流程状态为已完成,打开listActivityDetail.w文件。显示业务数据。

代码如下,在本例中使用了fStatus存放流程状态

	Model.prototype.grid1RowDblClick = function(event) {
		var dList = this.comp("mainData");
		if (dList.getValue("fStatus") == "未审批") {
			this.startFlow();
		} else if (dList.getValue("fStatus") == "已完成") {
			// alert("流转已经完成,使用新页面显示");
			var url = "$UI/demo/listProcess/process/listProcess/listActivityDetial.a?_pagePattern=readonly";
			justep.Shell.showPage({
				url : url,
				process:"/demo/listProcess/process/listProcess/listProcessProcess",
				activity:"listActivity",
				title : "已完成订单",
				rowid : dList.getCurrentRowID()		
			});

		} else {
			this.advanceFlow();
		}
	};
	Model.prototype.startFlow = function() {
		var dList = this.comp("mainData");
		if (dList.getValue("fStatus") == "未审批") {
			this.comp("process1").start(null, null, dList.getCurrentRowID(), null);
			dList.refreshData();
		} else {
			alert("流转已经启动");
		}
	};
		
	Model.prototype.executeTask = function(taskID,executorFID){
		var executor= "";
		var params = new biz.Request.ActionParam();
		params.setString("task", taskID);
		params.setString("executor", executorFID);
		var options = {};
		options.context = this.getContext();
		options.action = "executeTaskAction";
		options.parameters = params;
		options.directExecute = true;
		options.callback = function(options) {
			if (options.state) {
				executor = options.response;
			} else {
				options.ignoreError = false;
			}
		};
		biz.Request.sendBizRequest(options);
		return executor;
	};

	Model.prototype.advanceFlow = function() {
		var dList = this.comp("mainData");
		var sData1 = dList.getCurrentRowID();
		
		var context = this.getContext();
		var currentPersonID = context.getCurrentPersonID();
		var personMemberFIDs = context.getAllPersonMemberFIDs();
		var taskData = this.comp("taskData");

		// 定义action参数,请求taskDataAction获取当前环节的数据信息
		var param = new biz.Request.ActionParam();
		param.setString("sData1", sData1);
		biz.Request.sendBizRequest({
			"context" : context,
			"action" : "taskDataAction",
			"parameters" : param,
			"callback" : function(callbackData) {
				if (callbackData.state) {
					taskData.clear();
					taskData.loadData(callbackData.response);
					taskData.first();
				} else
					alert("任务数据获取失败");
			}
		});
		
		// 当有数据返回时获取对已经的任务进行处理
		var title,taskID,url,status,executorFID,executorPersonID =null;
		//一人或一个部门执行的
		if (taskData.getCount()===1) {
			title = taskData.getValue("sActivityName");// 获得当前环节名称,作为页面的标题
			taskID = taskData.getValue("task");// 获得任务ID,url中的参数
			url = taskData.getValue("sEURL");// 获得当前环节的url
			url = url + "?task=" + taskID + "&_pagePattern=write";// _pagePattern=write是必须的,表示要处理这个任务						
			executorPersonID = taskData.getValue("sExecutorPersonID");
			if (executorPersonID === currentPersonID) {// 如果执行者是否当前人
				justep.Shell.showPage({
					url : url,
					title : title
				}); // 调用justep.Shell.showPage方法打开流程当前环节对应的w文件
			}else {
				status = taskData.getValue("sStatusID");
				executorFID = taskData.getValue("sExecutorFID");
				if (status === "tesReady" && (personMemberFIDs.toString().indexOf(executorFID) > -1)) {// 判断执行者是否是当前操作者的所有人员成员所在的组织
					var executor =	this.executeTask(taskID,executorFID);
					justep.Shell.showPage({
						url : url,
						title : title,
						executor : executor || ""
					});
				} else {
					alert("任务应由其他人处理");
				}
			}
		}
		//多人或者多门户执行的
		else if(taskData.getCount() > 1 ){
			var tasks = taskData.find(['sExecutorPersonID'],[currentPersonID],false,false,false);
			//当前的人的任务
			if(tasks && tasks.length === 1){
				taskID = tasks[0].val("task");// 获得任务ID,url中的参数
				executorFID = tasks[0].val("sExecutorFID");
				var executor =	this.executeTask(taskID,executorFID);	//
				title = tasks[0].val("sActivityName");
				url = tasks[0].val("sEURL");// 获得当前环节的url
				url = url + "?task=" + taskID + "&_pagePattern=write";// _pagePattern=write是必须的,表示要处理这个任务
				justep.Shell.showPage({
					url : url,
					title : title,
					executor : executor || ""
				}); // 调用justep.Shell.showPage方法打开流程当前环节对应的w文件
			}
			else{
				//当前人所在的组织的任务
				var me = this;
				taskData.each(function(param){
					status = param.row.val("sStatusID");
					executorFID = param.row.val("sExecutorFID");					
					if(status === "tesReady" && (personMemberFIDs.toString().indexOf(executorFID) > -1)){	
						taskID = param.row.val("task");
						title = param.row.val("sActivityName");
						url = param.row.val("sEURL");// 获得当前环节的url
						url = url + "?task=" + taskID + "&_pagePattern=write";// _pagePattern=write是必须的,表示要处理这个任务						
						param.cancel = true;
					}
				});
				var executor =	me.executeTask(taskID,executorFID);
				justep.Shell.showPage({
						url : url,
						title : title,
						executor : executor || ""
				});
			}
		} else {
			alert("流转未启动、已完成");
		}
		
	};

其中3和4中的启动流程和处理流程的代码就是startFlow和advanceFlow方法

8.流转后,刷新列表数据

流转后,当前环节页面自动关闭,显示出列表流程的页面,此时会触发/UI2/demo/listProcess/process/listProcess/listActivity.w中model的onActive事件,在这个事件中刷新列表数据,代码如下

	Model.prototype.modelActive = function(event){
      var dList = this.comp("mainData");
      dList.refreshData();
	};

本例的文件如下,BIZ和UI2解压后直接覆盖到对应的demo中,然后生成数据库表分配功能权限即可运行
BIZ   UI2