注:整体环境搭建:activiti自定义流程之整合(一):整体环境配置
基础环境搭建完毕,接下来就该正式着手代码编写了,在说代码之前,我觉得有必要先说明一下activit自定义流程的操作。
抛开自定义的表单不谈,通过之前的了解,我们知道一个新的流程开始,是在启动流程实例(processIntence)的时候,而流程实例依赖于流程定义(processDefinition),流程定义又依赖于流程模型(model)。
我们用到的自定义表单需要在创建模型,画模型图的时候就指定表单的名称formKey,需要保证这个formKey和我们创建的表单名称一致。
表单并不在创建模型的时候使用,而是在部署的时候用到,因此只要是在部署流程定义之前创建自定义表单,那么无论是先创建模型还是先创建表单,只要名称一致就行。
那么我这里就先创建表单,因为我觉得这样的话,在创建模型时可以预览,更能保证创建模型的正确性(虽然模型也可以修改);
与之前的自定义表单稍有不同的是,在这个整合的例子中,我用的是angularjs,同时预览时也用到了jquery中的dialog对话框的功能,也就需要比之前导入更多前端的js,他们如下图所示。
需要注意的是,dialog的样式在jquery-ui.js中控制,这个也是网上下载的。
前端首页index.html代码如下,因为angular js为单页面应用,因此实际上只有一个html声明,所有的js以及css文件也都需要在index.html中一开始就导入进来:
<!DOCTYPE html> <html ng-app="activitiApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="./activi_css/activi.css" rel="stylesheet"/> <script type="text/javascript"> var _root='http://form/index.php?s=/',_controller = 'index'; </script> <script src="./angular-1.4.0-rc.2/angular.js"></script> <script src='./angular-1.4.0-rc.2/angular-ui-router.js'></script> <script src='./activi_js/app.js'></script> <script src='./activi_js/createCtr.js'></script> <script src='./activi_js/modelCtr.js'></script> <script src='./activi_js/processCtr.js'></script> <script src='./activi_js/taskCtr.js'></script> <script src='./activi_js/findFirstTaskCtr.js'></script> <script src='./activi_js/loginCtr.js'></script> <script src='./activi_js/hisTaskCtr.js'></script> <script src='./activi_js/completeTaskCtr.js'></script> <script src='./activi_js/completeTaskTo1Ctr.js'></script> <script src="./my_js/updateFormCtr.js"></script> <script src="./my_js/formListCtr.js"></script> <!-- 导入form相关的js --> <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <link href="form_css/bootstrap/css/bootstrap.css?2023" rel="stylesheet" type="text/css" /> <link href="form_css/site.css?2023" rel="stylesheet" type="text/css" />--> <link href="form_css/jquery-ui.css" rel="stylesheet" type="text/css" /> <link href="my_css/a.css" rel="stylesheet" type="text/css" /> <script type="text/javascript"> var _root='http://form/index.php?s=/',_controller = 'index'; </script> <script src="form_js/jquery-1.7.2.min.js?2023"></script> <script src="form_js/common.js"></script> <script src="form_js/jquery-ui.js"></script> <script src="form_js/jquery.form.js"></script> <script src="form_js/ajax.js"></script> <script src="form_js/common/plugins/validate/jquery.validate.pack.js"></script> <script src="form_js/jquery.datetimepicker.js"></script> <script src="form_js/ueditor/ueditor.config.js?2023"></script> <script src="form_js/ueditor/ueditor.all.js?2023"> </script> <script src="form_js/ueditor/lang/zh-cn/zh-cn.js?2023"></script> <script src="form_js/ueditor/formdesign/leipi.formdesign.v4.js?2023"></script> <!-- 导入form相关的js --> </head> <body style="width:100%;height:400px;margin:0;background-color:#fff"> <div style="height:70px;width:100%;border:1px solid #ccf"> <img id="rdiv" src="./images/activiti.png" style="width:30%;height:98%"/> <a href="script:;" ng-show="userName!=undefined" style="margin-right:10px;float:right;margin-top:25px;" ng-click="logOut();"> [退出登陆] </a> <font ng-show="userName!=undefined" style="margin-right:10px;float:right;margin-top:25px;">当前登陆用户:{{userName}}</font> </div> <div style="width:100%;position: absolute;height:auto"> <div style="height:630px;width:12%;font-size:36px;position:relative;float:left;border:1px solid #ccf" ng-show="userName!=undefined"> <table style="width:100%;text-align:center;margin-top:0px" cellSpacing="5px" cellPadding="0px"> <tr> <td style="background-color:#aac;"><a href="#/create">创建模型</a></td> </tr> <tr> <td style="background-color:#acd;"> <a href="#/modelList">模型列表</a></td> </tr> <tr> <td style="background-color:#aac;"><a href="#/processList">流程列表</a></td> </tr> <tr> <td style="background-color:#acd;"><a href="#/findFirstTask">我的申请</a></td> </tr> <tr> <td style="background-color:#aac;"><a href="#/taskList">我的任务</a></td> </tr> <tr> <td style="background-color:#acd;"><a href="#/hisTask">历史任务</a></td> </tr> <tr> <td style="background-color:#aac;"><a href="#/createForm">创建表单</a></td> </tr> <tr> <td style="background-color:#acd;"><a href="#/formList">表单列表</a></td> </tr> </table> </div> <div ui-view="view" ></div> </div> </body> </html>
Angular js 控制路由跳转app.js代码:
var app=angular.module('activitiApp',['ui.router']); app.run(function($rootScope) { $rootScope.logOut=function(){ $http.post("./loginOut.do").success(function(loginOutResult){ $rootScope.userName=undefined; $location.path("/login"); }); } }); app.config(function($stateProvider,$urlRouterProvider){ $stateProvider .state('createForm', { url: "/createForm", views: { 'view': { templateUrl: 'my_views/updateForm.html', controller: 'updateFormCtr' } } }); });
新增form表单的页面updateForm.html代码如下,要注意的是,这个页面也是有ueditor插件中的index.html改变过来的:
<div id="formDiv" style="margin-top:20px;margin-left:50px;height:550px;width:70%;font-size:18px;position:relative;float:left;"> <div class="container"> <form method="post" id="saveform" name="saveform" action="/index.php?s=/index/parse.html"> <input type="hidden" name="fields" id="fields" value="0"> <div style="width:98%;height:500px;margin-top:20px;border:3px solid grey"> <p style="margin-top:10px;font-size:30px" >表单名称:<input type="text" id="formType"></input></p> <hr style="height:5px;border:none;border-top:5px ridge green;"/> <p style="margin-top:10px;font-size:30px" >表单设计:</p> <div > <p style="left:30px"> <button type="button" ng-click="leipiFormDesign.exec('text');" class="btn btn-info">文本框</button> <button type="button" ng-click="leipiFormDesign.exec('textarea');" class="btn btn-info">多行文本</button> <button type="button" ng-click="leipiFormDesign.exec('select');" class="btn btn-info">下拉菜单</button> <button type="button" ng-click="leipiFormDesign.exec('radios');" class="btn btn-info">单选框</button> <button type="button" ng-click="leipiFormDesign.exec('checkboxs');" class="btn btn-info">复选框</button> <button type="button" ng-click="leipiFormDesign.exec('listctrl');" class="btn btn-info">列表控件</button> <button type="button" ng-click="leipiFormDesign.findForm();" class="btn btn-info">form</button> </p> </div> <!-- afsddddddddd --> <div > <script id="myFormDesign" type="text/plain" style="width:99.8%;"> </script> </div> </div> <!-- afsddddddddd --> <div class="row"> </div><!--end row--> </form> </div><!--end container--> </div>
对应的js代码updateFormCtr.js,这里尤其需要注意的是leipiFormDesign.exec这个方法原本是ueditor插件中的,如果不做修改直接拿过来的话,在上便的页面中是无法调用的,angularjs需要注意作用域的问题,因此在对应的js中需要改成$scope. leipiFormDesign;除此之外,在保存和预览时基本没有什么变化,dialog对话框也是在后续流程中使用到:
angular.module('activitiApp') .controller('updateFormCtr', ['$rootScope','$scope','$http','$location','$state', function($rootScope,$scope,$http,$location,$state){ $http.post("createFlush.do").success(function(result){ if(result.isLogin==="yes"){ $rootScope.userName=result.userName; }else{ $location.path("/login"); } }); //预览 UE.registerUI('button_preview',function(editor,uiName){ if(!this.options.toolleipi) { return false; } //注册按钮执行时的command命令,使用命令默认就会带有回退操作 editor.registerCommand(uiName,{ execCommand:function(){ try { $scope.leipiFormDesign.fnReview(); } catch ( e ) { alert('leipiFormDesign.fnReview 预览异常'); } } }); //创建一个button var btn = new UE.ui.Button({ //按钮的名字 name:uiName, //提示 title:"预览", //需要添加的额外样式,指定icon图标,这里默认使用一个重复的icon cssRules :'background-position: -420px -19px;', //点击时执行的命令 onclick:function () { //这里可以不用执行命令,做你自己的操作也可 editor.execCommand(uiName); } }); //因为你是添加button,所以需要返回这个button return btn; }); //保存 UE.registerUI('button_save',function(editor,uiName){ if(!this.options.toolleipi) { return false; } //注册按钮执行时的command命令,使用命令默认就会带有回退操作 editor.registerCommand(uiName,{ execCommand:function(){ try { $scope.leipiFormDesign.fnCheckForm('save'); } catch ( e ) { alert('leipiFormDesign.fnCheckForm("save") 保存异常'); } } }); //创建一个button var btn = new UE.ui.Button({ //按钮的名字 name:uiName, //提示 title:"保存表单", //需要添加的额外样式,指定icon图标,这里默认使用一个重复的icon cssRules :'background-position: -481px -20px;', //点击时执行的命令 onclick:function () { //这里可以不用执行命令,做你自己的操作也可 editor.execCommand(uiName); } }); //因为你是添加button,所以需要返回这个button return btn; }); //整合设计器 var leipiEditor = UE.getEditor('myFormDesign',{ toolleipi:true,//是否显示,设计器的 toolbars textarea: 'design_content', //这里可以选择自己需要的工具按钮名称,此处仅选择如下五个 toolbars:[[ ]], //关闭字数统计 wordCount:false, //关闭elementPath elementPathEnabled:false, //默认的编辑区域高度 initialFrameHeight:260 //,iframeCssUrl:"css/bootstrap/css/bootstrap.css" //引入自身 css使编辑器兼容你网站css //更多其他参数,请参考ueditor.config.js中的配置项 }); $scope.leipiFormDesign = { findForm : function(){ window.location.href="my_views/formList.html"; }, /*执行控件*/ exec : function (method) { leipiEditor.execCommand(method); }, /* Javascript 解析表单 template 表单设计器里的Html内容 fields 字段总数 */ parse_form:function(template,fields) { //正则 radios|checkboxs|select 匹配的边界 |--| 因为当使用 {} 时js报错 var preg = /(\|-<span(((?!<span).)*leipiplugins=\"(radios|checkboxs|select)\".*?)>(.*?)<\/span>-\||<(img|input|textarea|select).*?(<\/select>|<\/textarea>|\/>))/gi,preg_attr =/(\w+)=\"(.?|.+?)\"/gi,preg_group =/<input.*?\/>/gi; if(!fields) fields = 0; var template_parse = template,template_data = new Array(),add_fields=new Object(),checkboxs=0; var pno = 0; template.replace(preg, function(plugin,p1,p2,p3,p4,p5,p6){ var parse_attr = new Array(),attr_arr_all = new Object(),name = '', select_dot = '' , is_new=false; var p0 = plugin; var tag = p6 ? p6 : p4; //alert(tag + " \n- t1 - "+p1 +" \n-2- " +p2+" \n-3- " +p3+" \n-4- " +p4+" \n-5- " +p5+" \n-6- " +p6); if(tag == 'radios' || tag == 'checkboxs') { plugin = p2; }else if(tag == 'select') { plugin = plugin.replace('|-',''); plugin = plugin.replace('-|',''); } plugin.replace(preg_attr, function(str0,attr,val) { if(attr=='name') { if(val=='leipiNewField') { is_new=true; fields++; val = 'data_'+fields; } name = val; } if(tag=='select' && attr=='value') { if(!attr_arr_all[attr]) attr_arr_all[attr] = ''; attr_arr_all[attr] += select_dot + val; select_dot = ','; }else { attr_arr_all[attr] = val; } var oField = new Object(); oField[attr] = val; parse_attr.push(oField); }) /*alert(JSON.stringify(parse_attr));return;*/ if(tag =='checkboxs') /*复选组 多个字段 */ { plugin = p0; plugin = plugin.replace('|-',''); plugin = plugin.replace('-|',''); var name = 'checkboxs_'+checkboxs; attr_arr_all['parse_name'] = name; attr_arr_all['name'] = ''; attr_arr_all['value'] = ''; attr_arr_all['content'] = '<span leipiplugins="checkboxs" title="'+attr_arr_all['title']+'">'; var dot_name ='', dot_value = ''; p5.replace(preg_group, function(parse_group) { var is_new=false,option = new Object(); parse_group.replace(preg_attr, function(str0,k,val) { if(k=='name') { if(val=='leipiNewField') { is_new=true; fields++; val = 'data_'+fields; } attr_arr_all['name'] += dot_name + val; dot_name = ','; } else if(k=='value') { attr_arr_all['value'] += dot_value + val; dot_value = ','; } option[k] = val; }); if(!attr_arr_all['options']) attr_arr_all['options'] = new Array(); attr_arr_all['options'].push(option); //if(!option['checked']) option['checked'] = ''; var checked = option['checked'] !=undefined ? 'checked="checked"' : ''; attr_arr_all['content'] +='<input type="checkbox" name="'+option['name']+'" value="'+option['value']+'" '+checked+'/>'+option['value']+' '; if(is_new) { var arr = new Object(); arr['name'] = option['name']; arr['leipiplugins'] = attr_arr_all['leipiplugins']; add_fields[option['name']] = arr; } }); attr_arr_all['content'] += '</span>'; //parse template = template.replace(plugin,attr_arr_all['content']); template_parse = template_parse.replace(plugin,'{'+name+'}'); template_parse = template_parse.replace('{|-',''); template_parse = template_parse.replace('-|}',''); template_data[pno] = attr_arr_all; checkboxs++; }else if(name) { if(tag =='radios') /*单选组 一个字段*/ { plugin = p0; plugin = plugin.replace('|-',''); plugin = plugin.replace('-|',''); attr_arr_all['value'] = ''; attr_arr_all['content'] = '<span leipiplugins="radios" name="'+attr_arr_all['name']+'" title="'+attr_arr_all['title']+'">'; var dot=''; p5.replace(preg_group, function(parse_group) { var option = new Object(); parse_group.replace(preg_attr, function(str0,k,val) { if(k=='value') { attr_arr_all['value'] += dot + val; dot = ','; } option[k] = val; }); option['name'] = attr_arr_all['name']; if(!attr_arr_all['options']) attr_arr_all['options'] = new Array(); attr_arr_all['options'].push(option); //if(!option['checked']) option['checked'] = ''; var checked = option['checked'] !=undefined ? 'checked="checked"' : ''; attr_arr_all['content'] +='<input type="radio" name="'+attr_arr_all['name']+'" value="'+option['value']+'" '+checked+'/>'+option['value']+' '; }); attr_arr_all['content'] += '</span>'; }else { attr_arr_all['content'] = is_new ? plugin.replace(/leipiNewField/,name) : plugin; } template = template.replace(plugin,attr_arr_all['content']); template_parse = template_parse.replace(plugin,'{'+name+'}'); template_parse = template_parse.replace('{|-',''); template_parse = template_parse.replace('-|}',''); if(is_new) { var arr = new Object(); arr['name'] = name; arr['leipiplugins'] = attr_arr_all['leipiplugins']; add_fields[arr['name']] = arr; } template_data[pno] = attr_arr_all; } pno++; }) var parse_form = new Object({ 'fields':fields,//总字段数 'template':template,//完整html 'parse':template_parse,//控件替换为{data_1}的html 'data':template_data,//控件属性 'add_fields':add_fields//新增控件 }); return JSON.stringify(parse_form); }, /*type = save 保存设计 versions 保存版本 close关闭 */ fnCheckForm : function ( type ) { var formType=document.getElementById("formType").value; if(leipiEditor.queryCommandState( 'source' )) leipiEditor.execCommand('source');//切换到编辑模式才提交,否则有bug if(leipiEditor.hasContents()){ leipiEditor.sync();/*同步内容*/ //--------------以下仅参考----------------------------------------------------------------------------------------------------- var type_value='',formid=0,fields=$("#fields").val(),formeditor=''; if( typeof type!=='undefined' ){ type_value = type; } console.log(document.getElementById("formType")); //获取表单设计器里的内容 formeditor=leipiEditor.getContent(); //解析表单设计器控件 var parse_form = this.parse_form(formeditor,fields); //异步提交数据 $.ajax({ type: 'POST', url : './addForm.do', dataType : 'html', async:false, //contentType: 'application/json;charset=utf-8', data : {'type' : type_value,'formid':formid,'parse_form':parse_form,"formType":formType}, success : function(data){ alert("保存成功"); window.location.href ="#/formList"; } }); } else { alert('表单内容不能为空!') $('#submitbtn').button('reset'); return false; } } , /*预览表单*/ fnReview : function (){ console.log("111"); if(leipiEditor.queryCommandState( 'source' )) leipiEditor.execCommand('source');/*切换到编辑模式才提交,否则部分浏览器有bug*/ if(leipiEditor.hasContents()){ console.log("222"); leipiEditor.sync(); /*同步内容*/ //--------------以下仅参考------------------------------------------------------------------- /*设计form的target 然后提交至一个新的窗口进行预览*/ var type_value='',formid=0,fields=$("#fields").val(),formeditor=''; var formType=document.getElementById("formType").value; if( typeof type!=='undefined' ){ type_value = type; } console.log("333"); //获取表单设计器里的内容 formeditor=leipiEditor.getContent(); //解析表单设计器控件 var parse_form = this.parse_form(formeditor,fields); var forms=JSON.parse(parse_form); console.log(forms); console.log(typeof forms); console.log(forms.template); var forms1=forms.template; win_parse=window.open('','','width=800,height=400,alwaysRaised=yes,top=100,left=200'); //win_parse=window.open('','mywin',"menubar=0,toolbar=0,status=0,resizable=1,left=0,top=0,scrollbars=1,width=" +(screen.availWidth-10) + ",height=" + (screen.availHeight-50) + "\""); var str='<div style="width:500px;height:300px;border:1px solid grey">'+forms1+'</div>'; win_parse.document.write(forms1); win_parse.focus(); } else { alert('表单内容不能为空!'); return false; } } }; }])
相对于前台而言,后台在这里就没有什么变化了,可以参考之前的自定义表单,代码便不再罗列。