开发常见问题及解答
1 表单
1.1表单的类型
说明:
表单类型分为普通,查询表单,普通(映射)表单。
(1)普通,常规的表单配置
(2)查询表单,主要为视图列表配置查询头,要与视图配置结合使用
(3)映射表单,可以调用应用软件在同一个数据库中不属于平台生成的数据表,通过字段的映射,对该表进行数据查询,修改,添加,删除操作
1.2控件属性
1.2.1刷新
说明:
控件刷新属性,是指当控件的内容发生改变时,触发包含当前控件的表单的刷新事件,以通知表单中其它具有重计算属性的控件进行刷新。
1.2.2重计算
说明:
控件重计算属性,是指当控件配置选择重计算时,则包含当前控件的表单,其刷新事件被触发时,当前控件的脚本将被重新运算,以实现与最新数据同步
1.2.3手机
说明:
控件手机属性,是指当控件配置选择手机时,通过MYAPPS智能客户端访问平台应用,则此控件将在智能客户端上显示,否则不显示。
1.2.4值脚本
说明:
控件值脚本,是指可能通过脚本来决定控件的值。
示例1:表单字段计算
/* 这里我们用单价与数量,计算金额为例进行讲解。 * 表单中有一个字段“单价”,数字类型;有一个字段“数量”,数字类型;有一个字段“金额”,数字类型。 * 单价和数量两个字段都选择了“刷新”属性,金额字段选择了“重计算”属性。 * 其中,金额字段写有值脚本。 */ var price = getItemValueAsDouble("单价"); var count = getItemValueAsDouble("数量"); price * count; |
示例2:汇总子表单字段值
/* 这里我们以汇总子表“金额”字段为例进行讲解。 * 主表有一字段为“总金额”,数字类型;子表有一字段为“金额”,数字类型。 * 子表包含元素控件选择了“刷新”属性,总金额字段选择了“重计算”属性。 * 其中,总金额字段写有值脚本。 */ //此函数有两个参数,第一个参数:子表单名称;第二个参数:汇总字段名称。 sumSubDocument("子表明细","金额"); |
示例3:子表单记录计数
/*这里我们以获取子表记录数为例。*/ countSubDocument("子表单名称"); |
示例4:自动编号
/*方法1, 创建数据但未保存时,会出现断号的情况。生成TLK0001、TLK0002、TLK0003......*/ var number = getItemValue("字段名"); if(number ==null || number.trim().length()<=0){ number = countNext2("TLK",false,false,false,4); } number;
/*方法2, 创建数据但未保存时,会出现断号的情况。生成TLK201101050001、TLK201101050002、TLK201101050003......*/ var number = getItemValue("字段名"); if(number ==null || number.trim().length()<=0){ number = countNext2("TLK",true,true,true,4); } number; |
1.2.5选项脚本
说明:
控件选项脚本,是指通过脚本来创建出控件的可选择项,支持固定选项、动态生成选项。
示例:
/*方法1:固定选项列表,选项名与选项值相同。*/ ";选项1;选项2;选项3;选项4";
/*方法2:固定选项列表,选项名与选项值不相同。*/ var opts=createOptions(); opts.add("",""); opts.add("选项1","1"); opts.add("选项2","2"); opts.add("选项3","3"); opts.add("选项4","4"); opts;
/*方法3:动态生成选项列表,从基础表中获取数据动态生成选项。*/ //获取所有区域 var opts=createOptions(); opts.add("",""); var dql = "$formname='/片区信息表'"; var datas =queryByDQL(dql); if(datas!=null && datas.size()>0){ for(var iter = datas.iterator();iter.hasNext();){ var doc = iter.next(); opts.add(doc.getItemValueAsString("片区"),doc.getItemValueAsString('片区代码')); } } opts;
/*方法4:动态生成选项列表,从基础表中动态生成选项。 * 从基础表中动态生成选项列表。选项名与选项值取不同字段的值。 */ var dql = "$formname='/片区信息表'"; var key = new Array(); key[0] = "片区代码"; key[1] = "片区"; getOptionsByDQL(dql,key,true);
/*方法5:动态生成选项列表,从基础表中动态生成选项。 * 选项名与选项值取同一个字段的值。 */ var dql = "$formname='/片区信息表'"; getOptionsByDQL(dql,"片区",true); |
1.2.6校验脚本
说明:
控件校验脚本,是指通过脚本来对表单控件内容进行校验。
示例1:判断是否为空
/*这里我们以校验“名称”字段是否填写内容为例。*/ var value = getItemValueAsString("名称"); var rtn = ""; if (value==null || value.trim().length()<=0){ rtn = "名称字段必须填写!"; } rtn; |
示例2:判断是否为数字
/*这里我们以校验“数量”字段填写内容是否为数字为例。*/ var value = getItemValueAsString("数量"); var rtn = ""; if (!isNumberText(value)){ rtn = "字段内容必需为数字!"; } rtn; |
示例3:判断是否为邮件地址
/*这里我们以校验“email”字段填写内容是否为Email地址为例。*/ var value = getItemValueAsString("email"); var rtn = ""; if (!isMailAddressText(value)){ rtn = "非法的Email地址!"; } rtn; |
示例4:判断是否为正数
/*这里我们以校验“数量”字段填写内容是否为正数为例。*/ var value = getItemValueAsDouble("数量"); var rtn = ""; if (!isPositive(value)){ rtn = "数量必需大于0!"; } rtn; |
示例5:表单中的2个字段进行比较
/*这里我们以校验“总额”字段与“实际金额”字段比较为例。*/ var total_amount = getItemValueAsDouble("总额"); var amount = getItemValueAsDouble("实际金额"); var rtn = ""; if (total_amount< amount){ rtn = "实际金额不能大于总额!"; } rtn; |
示例6:获取参数表中的值,并进行比较
/*这里我们以校验“总额”参数与“实际金额”参数比较为例。*/ var total_amount = getParameterAsDouble("总额"); var amount = getParameterAsDouble("实际金额"); var rtn = ""; if (total_amount< amount){ rtn = "实际金额不能大于总额!"; } rtn; |
示例7:判断记录是否已存在
/*这里我们以校验“任务编号”是否已存在为例。*/ var code = getItemValueAsString("任务编号"); var dql = "$formname='fm_task' and code='"+code + "' and $id<>'" + getId() + "'"; var datas = queryByDQL(dql); var rtn = ""; if (datas!=null && datas.size()>0){ rtn = "任务编号"+code+"已经存在!"; } rtn; |
1.2.7隐藏脚本
说明:
控件隐藏脚本,是指当脚本返回值为true时,控件隐藏,当返回值为false时,控件显示。
示例1:判断当前用户部门,并决定是否隐藏
/*这里我们以非“总经办”的用户不可查看“合同总额”字段信息为例。我们在“合同总额”字段隐藏脚本。1表示一级部门*/ var deptid = getDeptIdByNameAndLevel("总经办",1); var dpts = getWebUser().getDepartments(); var isHidden = true; if (dpts!=null && dpts.size()>0){ for (var it = dpts.iterator();it.hasNext();){ var dptVO = it.next(); if (deptid.equals(dptVO.getId())){ isHidden = false; break; } } } isHidden; |
示例2:判断当前用户角色,并决定是否隐藏
/*这里我们以非“总经理”的角色用户不可查看“合同总额”字段信息为例。我们在“合同总额”字段隐藏脚本填写脚本。*/ var roleid = getRoleIdByName("总经理"); var roles = getWebUser().getRoles(); var isHidden = true; if (roles!=null && roles.size()>0){ for (var it = roles.iterator();it.hasNext();){ var roleVO = it.next(); if (roleid.equals(roleVO.getId())){ isHidden = false; break; } } } isHidden; |
示例3:判断当前表单另一字段值,并决定是否隐藏
/*这里我们以表单“任务类型”字段值状态为例。我们在“开发者”字段隐藏脚本填写脚本。当为非开发任务时,隐藏“开发者”*/ var type = getItemValueAsString("任务类型"); var isHidden = true; if ("开发任务".equals(type)){ isHidden = false; } isHidden; |
示例4:判断当前表单处于新建还是编辑状态,并决定是否隐藏
/*这里我们以表单为编辑状态时显示字段值信息为例。“建单人”字段隐藏脚本。*/ var doc = getCurrentDocument(); doc.getIstmp(); |
1.2.8打印时隐藏脚本
说明:
控件打印时隐藏脚本,当脚本返回值为true,文档打印时隐藏控件内容;脚本返回值为false,文档打印时显示控件内容。
1.2.9只读脚本
说明:
控件只读脚本,当脚本返回值为true,表单字段只读;当脚本返回值为false,表单字段可编辑。
示例:只作者可编辑
var doc = getCurrentDocument(); var user = getWebUser(); var isReadOlny = true; if (user.getId().equals(doc.getAutho().getId())){ isReadOlny = false; } isReadOlny; |
1.3操作
1.3.1基本操作类型
前台效果图 | 名称 | 简述 |
| 查询 | 用于对应视图的查询表单功能。 |
| 保存 | 执行保存操作。 |
| 保存 | 执行保存并触发流程 |
| 保存并返回 | 执行保存操作后返回上一级页面。 |
| 保存并新建 | 执行保存操作后并创建新的操作,而且会带有原来的数据。 |
| 保存并新建 | 执行保存操作后并创建新的操作,但不会带有原来的数据。 |
| 保存 | 执行保存操作后不进行数据校验。 |
| 保存并复制 | 执行保存操作后并进行复制。 |
| 保存并关闭窗口 | 执行保存操作后关闭窗口。 |
| 返回 | 返回上一级页面。 |
| 打印 | 数据表进行打印。 |
| 带流程历史打印 | 打印数据表时并带有流程历史。 |
| 流程处理 | 提交给下一个流程进行进一步处理。 |
| 脚本处理 | 对脚本进行处理。 |
| 关闭窗口 | 把当前的窗口关闭。 |
| 编辑审批人 | 对数据信息进行操作、修改的人。 |
| PDF导出 | 数据信息以PDF格式进行导出。 |
| 文件下载 | 下载相关文件,文件路径如:”/uploads/aaa.txt”,那么在发布项目的uploads目录下的aaa.txt文件会被下载。 |
| 电子签章 | 对电子文档进行电子签章。 |
| 动态打印 | 数据进行嵌套打印。用户可根据自己的需求设计打印界面及其字段实现自定义打印。 |
| 跳转 | 跳转到对应的表单 |
| 流程启动 | 触发流程 |
1.3.2动作执行前脚本
说明:
表单按钮动作执行前脚本,是指按钮的动作执行前触发此脚本。通常也可以用来进行校验操作。当此脚本返回值为:字符串对象、Alert对象(通过createAlert函数创建)、Confirm对象(可通过createConfirm函数创建)。
示例1:执行前显示Alert窗口
/*这里我们以“提交”按钮动作执行前脚本为例。*/ var code = getItemValueAsString("任务编号"); if (code ==null || code.trim().length()<=0){ createAlert("任务编号不能为空!"); } |
示例2:执行前显示Confirm窗口
/*这里我们以“提交”按钮动作执行前脚本为例。*/ createConfirm("确定要提交文档?"); |
1.3.3动作执行后脚本
说明:
表单按钮动作执行后脚本,是指按钮的动作执行后触发此脚本。
示例1:保存当前文档,并根据当前表单的内容创建另一文档
/*这里我们以“保存”按钮动作执行后脚本为例。*/ var formProcess = getFormProcess(); //查询出表单 var form = formProcess.doViewByFormName("fm_purchase_materials",getApplication()); var process = getDocumentProcess(); var doc = process.doNew(form,getWebUser(),createParamsTable()); doc.findItem("title").setValue(getItemValueAsString("标题")); doc.findItem("type").setValue(getItemValueAsString("类型")); doc.findItem("count").setValue(getItemValueAsString("数量")); doc.setIstmp(false); process.doCreate(doc); |
示例2:保存当前文档,并发送邮件通知
/*这里我们以“保存”按钮动作执行后脚本为例。*/ var from=getItemValueAsString("from"); var to=getItemValueAsString("to"); var host=getItemValueAsString("host"); var user=getItemValueAsString("user"); var password=getItemValueAsString("password"); var bbc=getItemValueAsString("bbc"); var subject=getItemValueAsString("subject"); var body=getItemValueAsString("body"); sendMail(from, to, subject, body, host, user, password, bbc, fasle); |
示例3:保存当前文档,自动生成编号
/*自动编号,此种生成方式编号会连号,让编号利用率到最高。当点击保存按钮,数据保存成功后,生成TLK201101001、TLK201101002、TLK201101003......*/ //保存动作执行后脚本 var doc = getCurrentDocument(); var value = doc.getItemValueAsString("code1"); if(value == null || value.trim().length() <= 0){ value = countNext2("TLK",true,true,false,4); doc.findItem("code1").setValue(value); var process = getDocProcess(getApplication()); //Document操作类 process.doUpdate(doc); } |
2视图
2.1视图的类型
说明:
视图的类型分为:普通,日历视图,树形视图,地图视图,甘特视图
(1) 普通,常规的视图配置
(2) 日历视图,类似挂历或备忘录的形式陈列表单数据,通过映射字段映射表单的日期字段,根据该日期字段以每日,每周,每月显示数据(具体实例请参考myApps功能示例/视图示例/日历视图)。
月视图:
周视图:
日视图:
(3) 树形视图,以树形结构显示表单内容,字段中的层级关系通过视图列中映射字段设置来定义的,节点点击打开类型为对应视图和链接(具体实例请参考myApps功能示例/视图示例/树形视图(列表)或者树形视图(表单))。
前台显示效果:
(4) 地图视图,为用户提供地图位置,显示位置信息。使用百度地图的插件,需在可连互联网环境才能正常使用,通过映射字段映射地图控件(具体实例请参考myApps功能示例/视图示例/地图视图)。
前台显示效果:
(5) 甘特视图,能更直观的统计每日,周,月,季的工作进展情况和完成进度,它通过映射字段对应表单需要的字段(具体实例请参考myApps功能示例/视图示例/甘特视图示例)。
前台显示效果:
2.2筛选条件定义
示例1:在视图中列出单个数据表内容
通过视图基本信息中设置相关表单,即可对应单个表单的数据表,分别可以通过设计,代码(DQL),代码(SQL)来进行对列的条件过滤。(具体实例请参考myApps功能示例/视图示例/视图示例design、DQL和SQL)
以上实例中通过查询条件对应绑定查询表单里字段,根据查询表单字段内容对视图数据表进行筛选。
// DQL语句 /*获取查询表单“字段1”和“字段2”的值,当查询表单中“字段1”和“字段2”的值等于“视图示例_dql”中“字段1”和“字段2”的值时,显示数据表为查询表单中中“字段1”和“字段2”对应内容的数据。*/ var value1 = getItemValue("字段1"); var value2 = getItemValue("字段2"); var where = (value1 != null && value1.trim().length() > 0)?" and 字段1='"+ value1+"'":""; where += (value2 != null && value2.trim().length() > 0)?" and 字段2='"+ value2 + "'":""; "$formname='视图示例_dql' " + where;
//SQL语句 /*获取查询表单“字段1”的值,当查询表单中“字段1”的值等于“视图示例_sql”中“字段1”的值时,显示数据表为查询表单中“字段1”对应内容的数据。 字段名不是以item_起头的,就要定义一个别名,别名是以item_起头,因为如果不是以item_起头,数据项的值将无法获取到值。*/ var sql = ""; var value = getItemValue("字段1"); if (value!=null && value.trim().length() > 0){ sql = " and ITEM_字段1='"+value+"'"; } "SELECT * FROM TLK_视图示例_sql where istmp=0 "+sql;
//SQL语句实现,映射表单数据查询 /*查询映射表单tb_mapping中name与title字段内容。*/ var sql = "select d.*,m.name,m.title from t_document d"; sql +=" inner join tb_mapping m on d.mappingid=m.keyname"; sql; |
示例2:在视图中显示多个数据表(多表查询)的内容
/*通过过滤中代码(SQL)来实现多个数据表(多表查询)的内容,主要通过主子表来实现多表单的数据查询,查询子表单中finished与date字段的数据。*/ var sql="SELECT d.*,sub.item_finished,sub.item_date from tlk_fm_task d"; sql +=" inner join tlk_fm_task_sub sub on d.id=sub.parent"; sql; |
示例3:SQL语句实现已办数据查询
var sql="select * from tlk_会议记录 doc where '"+getWebUser().getId(); sql +="' in (select u.ACTORID from T_ACTORHIS a,t_relationhis r"; sql +=" where r.docid=doc.id and a.nodehis_id=r.id"; sql +=" AND r.flowid in "; sql +="(SELECT flowid FROM t_flowstatert WHERE docid=doc.id )) "; sql; |
示例4:实现待办数据查询
//DQL实现 var dql ="$formname='formname' and $state.actors.actorid='" +getWebUser().getId() + "'"; dql;
//SQL实现 var sql="select d.* from tlk_tablename d"; sql +=" where (d.id in (select states.docid"; sql +=" from t_flowstatert states, t_actorrt actors"; sql +=" where states.id = actors.flowstatert_id"; sql +=" and actors.actorid ='" +getWebUser().getId() +"'))"; sql; |
2.3定义列
说明:
定义列的显示,我们可以通过两种方式来实现:FIELD和SCRIPT;
(1)FIELD,视图中默认的方式,根据视图查询的表单,选择对应表单的列;
(2)SCRIPT,通过代码来显示数据。
2.3.1获取表单字段值
说明:
获取相关表单字段的值,实现的方式有两种类型:FIELD和SCRIPT
(1) FIELD,视图中默认的方式,根据视图查询的表单,选择对应表单的列
(2) SCRIPT,通过代码来显示数据,具体示例如下:
var value = getItemValue("地区"); value; |
2.3.2值转换
说明:
通过视图列配置来实现值转换,需要使用iScript代码的方式来实现 (具体实例请参考myApps功能示例/视图示例/数据转换)
/*获取当前文档“地区”字段的值,当值等于010时显示北京,当值等于020是显示广州,当值等于021时显示上海。“地区”列的值脚本。*/ var doc = getCurrentDocument(); var value = doc.getItemValueAsString("地区"); var rtn=''; if(value=="010") rtn="北京 "; else if(value=='020') rtn="广州 "; else if(value=='021') rtn="上海 "; else rtn= value; rnt; |
前台显示的效果是:
2.3.3获取其它表单字段值
说明:
/*列上通过SCRIPT代码实现。这里我们以根据物料编辑获取物料名称为例。*/ var code = getItemValueAsString("code"); var dql = "$formname='物料表单' and code='" + code + "'"; var doc = findByDQL(dql); doc.getItemValueAsString("name"); |
2.3.4在列上显示操作
说明:
列上通过SCRIPT代码实现,当点击列名为中“编辑”按钮时,进入当前行中的表单。
示例:编辑操作按钮
var doc = getCurrentDocument(); var rtn = "<input type='Button' value='编辑' "; rtn+="οnclick='javascript:document.forms[0].action=\""; rtn+=getContextPath(); rtn+="/portal/dynaform/document/view.action"; rtn+= "?_docid=" + doc.getId() + "&_formid=" + doc.getFormid(); rtn+= "&r_edit=true\";"; rtn+= "document.forms[0].submit();'/>"; rtn; |
效果如下:
2.3.5在列上显示图片
示例:
/*列通过SCRIPT代码实现,获取相关表单“地区”字段的值,当值等于010和020和021时,显示服务器上相关图片,否者显示另一种相关图片。“结果”列的值脚本。*/ var value = getItemValue("地区"); var rtn=""; if(value=="010" || value=="020" || value=="021"){ rtn="<img src='/obpm/resource/image/backstatelabel.gif'/>"; }else{ rtn="<img src='/obpm/resource/image/terminate1.gif'/>"; } rtn; |
2.3.6在列上显示超链接
说明:
列通过SCRIPT代码实现(具体实例请参考myApps功能示例/视图示例/多样式列视图示例)
示例:列链接到其它网址
/*以字符串的形式获取相关表单“task_type”字段的值,当字段值为0时,显示打开百度并在当前页面中链接到百度地址,当字段值为1时,显示打开百度并在当前页面中链接到谷歌地址。*/ var value = getItemValueAsString("task_type"); var rtn = ""; if ("0".equals(value)){ rtn = "<a href='http://www.baidu.com'>打开百度</a>"; }else if ("1".equals(value)){ rtn = "<a href='http://www.google.com'>打开谷歌</a>"; } rtn; |
2.4操作
2.4.1基本操作类型
说明:操作的类型有:查询,创建,删除,批量提交,导出EXCEL,导入EXCEL,清空所有数据,文件下载,批量签章
(1) 查询:对应视图的查询表单功能
(2) 创建:创建关联表单新数据
(3) 删除:删除所选记录
(4) 批量审批:对数据信息进行大量的审批提交(表单有绑定流程)
(5) 导出EXCEL:导出视图数据的EXCEL文件
(6) 导入EXCEL:根据导入映射的配置,导入相关数据
(7) 清空所有数据:清空所选表单的数据
(8) 文件下载:下载相关文件,通过文件名称脚本,指向下载文件的相对路径,例如”/uploads/aaa.txt”,下载服务器上uploads文件夹下名为aaa.txt的文件
(9) 批量签章:对所有表单进行签章
2.4.2动作前执行脚本
说明:
视图按钮动作执行前脚本,是指按钮的动作执行前触发此脚本。通常做动作执行前校验操作。
示例:校验是否勾选了记录
/*这里我们以删除按钮动作执行前脚本为例。删除之前需要选择被删除记录。*/ var selects = getParameterAsArray("_selects"); var rtn = ""; if (selects ==null || selects.length<0){ rtn = "请选择记录!"; } rtn; |
2.4.3动作后执行脚本
说明:
视图按钮动作执行后脚本,是指按钮的动作执行后触发此脚本。
示例:更新选中记录相关的信息
/*这里在按钮执行后脚本里来更新选中的记录信息。*/ var docids = getParameterAsArray("_selects"); var process = getDocProcess(getApplication()); //Document操作类 for(var i=0;i<docids.length;i++){ var doc = process.doView(docids[i]); doc.findItem("am_apply_status").setValue('己成生'); process.doUpdate(doc ); } |
3流程
3.1状态标签
说明:
状态标签是节点状态的显示,前台中一般显示在进入流程中表单的右上角。表单中可以根据获取到流程的状态来决定表单中某字段的值。表单通过脚本获取状态标签:
//方法1: var doc = getCurrentDocument(); var statelabel = doc.getStateLabel(); statelabel;
//方法2: var statelabel = getStateLabel(); statelabel; |
示例:“软件缺陷管理系统模板”,表单中“指派给”字段是通过流程状态获取的值,其值根据状态变化而变化,这里的用户变量“users”的值是获得某个指定角色下的所有用户,是一个集合,需要通过遍历(如:var iter = users.getDatas().iterator(); iter.hasNext();)后返回选项值,因此控件使用了下拉框,脚本写在该控件属性中的选项脚本。
/*当流程状态标签值为空和“FindBug”和“TestBug”时获取Developer角色下的所有用户,否者当值为“FixBug”状态时获取Tester角色下的所有用户,当值为“AssignBug”时获取Developer角色下的所有用户。*/ var opts = createOptions(); opts.add("",""); var doc = getCurrentDocument(); var process =createProcess("cn.myapps.core.user.ejb.UserProcess"); var users = null; var statelabel = doc.getStateLabel(); if(statelabel == null || statelabel == 'FindBug' || statelabel == 'TestBug'){ users = process.doQueryByRoleId("11de-a80d-a8e5d7bb-b638-55c259677fcd"); }else if(statelabel == 'FixBug'){ users = process.doQueryByRoleId("11de-a80d-b3e7fd0d-b638-55c259677fcd"); }else if(statelabel == "AssignBug"){ users = process.doQueryByRoleId("11de-a80d-a8e5d7bb-b638-55c259677fcd"); } if (users!=null && users.rowCount > 0){ for(var iter = users.getDatas().iterator(); iter.hasNext();) { var user = iter.next(); var userno = user.getLoginno(); var username = user.getName(); opts.add(username,userno); } } opts; |
3.2会签
说明:
传统意义上的会签是指撰拟公文的过程中,主办单位主动与有关单位协商并核签的一种办文程序,一般当公文的内容涉及本单位的多个部门或与其他单位有关时,需要进行会签。
流程会签,是指当前环节需要会签,则需要等待当前环节的所有审批人都审批完成,当前环节才算完结,流程才流转到下一环节。
3.3分支
说明:
分支是A->{B,C,D}->E(这里的A,B,C,D,E指的是流程中左侧图标的手动节点,箭头指的是流程中左侧图标的关联节点), A执行完以后,可以根据需求对B,C,D多个流程节点进行选择和判断。对B,C,D分支节点进行多和单的节点选择(这个是在流程节点属性的审批设置中对审批送出设置和审批到达设置中进行选择设定);判断流程的走向,一般是在流程的关联节点上进行设置。具体示例请参考myApps功能示例/流程示例/流程分支示例, 这里建单人创建文档后提交流程,流程根据表单中“字段2”的值进行路径的判断。大于100走“分支1.1”,小于100走“分支2.1”,根据逻辑这是个单选。因此分别在关联节点和建单人以及分支节点上进行审批设置。
3.4并发流程
说明:
并发流程是A->{B,C,D}->E(这里的A,B,C,D,E指的是流程中左侧图标的手动节点,箭头指的是流程中左侧图标的关联节点), A执行完以后,让B,C,D来执行,他们的执行没有先后顺序,只有他们三个全部执行完以后,才能到下个流程节点E。这里的流程节点属性设置中,其中,在A节点审批设置审批送出节点设置“当下步有多个审批节点时,可以选择多个节点”,E节点中审批到达节点设置“当上步有多个审批节点时,所有节点完成,流程可以到达”
3.5调用子流程
说明:
子流程作为父流程中的一种特殊的活动出现。子流程在父流程中,所处的只是一个节点,因此在进行流程处理时,子流程只当做一个流程的节点来看待。调用子流程只是当前流程处理到子流程节点这个环节时,主流程会通知流程引擎,流程引擎开始启动并调用子流程。
3.6绑定表单并设置权限
说明:
流程中在手动节点的基本信息中进行对应的表单绑定,可表单字段进行“只读”,“修改”,“隐藏”的权限控制。默认情况下所有表单字段都是“修改”的权限,因此:
(1)绑定表单,需要修改其中某些字段的“修改”的权限,按照流程的实际需求;
(2)解除绑定,将表单所有字段权限改为“修改”即可。
4报表
4.1交叉报表
说明:
交叉表单是报表中常见的类型,可以配置行和列数据汇总。它的视图查询模式可分为sql.dql,form
(1) sql:通过ISCRIPT语句实现,具体可以参考视图中的代码(SQL)
(2) dql:通过ISCRIPT语句实现,具体可以参考视图中的代码(DQL)
(3) form:通过ISCRIPT语句实现,具体可以参考视图中的设计
4.2列表
说明:
列表通过视图设计实现,其实现方式有:
(1) 将视图基本信息只读设置为“是”
(2) 将试图列信息中的是否汇总标记上,对列进行汇总
4.3自定义报表(Beta)
说明:
用户根据自己的需求定义表单的统计方式,目前实现了图表视图和仪表版;表格视图,矩阵视图和汇总视图正在开发中。
用户在后台通过菜单的自定义链接(内部)来调用自定义报表界面,链接地址如下:
/portal/share/report/oReport/oReport.jsp
5脚本语言iScript
5.1常见效果实现
5.1.1执行SQL
说明:
执行SQL分别可通过queryByDSName(dsName,sql)、insertByDSName(dsName,sql)、updateByDSName(dsName,sql)和deleteByDSName(dsName,sql)四个方法实现。
示例1:执行SQL查询
//省份。用户首先需要创建"kd"数据源。 var opts = createOptions(); opts.add("",""); try{ var appid = getApplication(); var sql = "select cityid,cityname from cityinfo where rootid=0"; var datas = queryByDSName("kd",sql); if(datas!=null){ for(var iterator = datas.iterator();iterator.hasNext();){ var map1 = iterator.next(); //取值 var name= map1.get("cityname"); var value = map1.get("cityid"); opts.add(name,value); } } }catch(e){} opts; |
示例2:执行SQL插入
var doc = getCurrentDocument(); var sql = "insert into cityinfo(cityid,cityname,rootid) "; sql +=" values('"+doc.getItemValue("citycode")+"','"; sql +=doc.getItemValue("cityname")+"', "; sql +=doc.getItemValue("cityroot")+")"; insertByDSName("kd",sql); |
示例3:执行SQL更新
var doc = getCurrentDocument(); var sql = "update cityinfo set cityid = "; sql +="'"+doc.getItemValue("citycode")+"', cityname='"; sql +=doc.getItemValue("cityname")+"', rootid ="; sql +=doc.getItemValue("cityroot"); updateByDSName("kd",sql); |
示例4:执行SQL删除
var docid = getId(); var sql = "delete from tlk_施工物料明细 where PARENT='"+docid+"'"; deleteByDSName("kd",sql); |
5.1.2通过SQL查询
示例:根据当前文档ID查询子表记录。
var value = ""; var docid = getId(); var sql = "select * from tlk_fm_ticket_sub parent = '" + docid + "'"; var subdocs1 = queryBySQL(sql); if(subdocs1 != null && subdocs1.size() > 0) { var temp = null; var temp1 = ""; var temp2 = ""; for (var iter1 = subdocs1.iterator(); iter1.hasNext();) { var subdoc1 = iter1.next(); temp1 = subdoc1.getLastmodified(); if(temp1 > temp2) { temp2 = temp1; temp = subdoc1; } } value = temp.getItemValueAsString("finishdegree"); }else{ value = "0%"; } value; |
5.1.3通过DQL查询
示例:根据当前文档ID查询子表记录。
var value = ""; var docid = getId(); var w1 = " and $parent.$id = '" + docid + "'"; var dql1 = "$formname = 'fm_ticket_sub'" + w1; var subdocs1 = queryByDQL(dql1); if(subdocs1 != null && subdocs1.size() > 0) { var temp = null; var temp1 = ""; var temp2 = ""; for (var iter1 = subdocs1.iterator(); iter1.hasNext();) { var subdoc1 = iter1.next(); temp1 = subdoc1.getLastmodified(); if(temp1 > temp2) { temp2 = temp1; temp = subdoc1; } } value = temp.getItemValueAsString("finishdegree"); }else{ value = "0%"; } value; |
5.1.4通过SQL统计
示例:根据SQL语句统计对应数据表的数据记录数
var sql = "select count(*) from tlk_queryByDQLDomain子表"; var t_count = countBySQL(sql); var rtn = ""; if(t_count > 0) { rtn = "表中存在记录。"; } rtn; |
5.1.5通过DQL统计
示例:根据DQL语句统计对应表单的数据记录数。
var dql = "$formname='queryByDQLDomain子表'"; var t_count = countByDQL(dql); var rtn = ""; if(t_count > 0) { rtn = "表中存在记录。"; } rtn; |
5.1.6流程节点审批人脚本
示例:流程节点审批人脚本,获取执行人的上级。这里主要是用于部门主管审批时的脚本代码。
//执行人的上级。这里主要是用于部门主管审批时的脚本代码。 var userid = getItemValue("toperson");//用户选择框 var userProcess = createProcess("cn.myapps.core.user.ejb.UserProcess"); var user = userProcess.doView(userid); var reportto = user.getSuperior(); if(reportto != null){ reportto; }else{ user; } |
5.1.7视图选择框确定脚本
示例:视图框确定脚本,自动生成子表记录,刷新子表
//视图框确定脚本,刷新子表 var did = getId(); var parentId = getParameterAsText("_selects"); //获取视图选择框对应的doc var parentDoc = findDocument(parentId); if(parentDoc!=null && parentId !=null && parentId.trim().length()>0){ //获取视图选择框对应的doc的子doc var subDocs1 = parentDoc.getChilds("施工物料明细"); var process = getDocumentProcess(); var domain = getDomainid(); var application = getApplication();
//如果子doc不为空,遍历子doc,取出每个子doc的值并保存到另一张子doc中。 if(subDocs1!=null){ var sql = "delete from tlk_施工物料明细 where PARENT='"+did+"'"; deleteByDSName("rims",sql); var formProcess = getFormProcess(); var form = formProcess.doViewByFormName("施工物料明细",application); for(var iter = subDocs1.iterator(); iter.hasNext();){ var subdoc = iter.next(); var uuid = newPackages.cn.myapps.util.sequence.Sequence(); var doc = process.doNew(subform,getWebUser(),createParamsTable()); doc.setIstmp(false); doc.setParent(did); doc.addStringItem("施工物料名称",subdoc.getItemValueAsString("施工物料名称")); doc.addStringItem("数量",subdoc.getItemValueAsString("数量")); doc.addStringItem("单位",subdoc.getItemValueAsString("单位")); doc.addStringItem("申请人",subdoc.getItemValueAsString("申请人")); process.doCreate(doc); } } } var rtn = "<script>"; rtn += "var subfrms = getFormFieldByName('包含元素名称');"; rtn += "if (subfrms){ "; rtn += "subfrms.document.location.reload();"; rtn +="}"; rtn +="</script>"; rtn; |
5.1.8是否允许编辑文档
示例:只作者可编辑脚本
//表单打开前执行脚本 var user= getWebUser(); var doc = getCurrentDocument(); var author = doc.getAuthor(); var flag = true; if (author!=null && !user.getId().equals(author.getId())){ flag=false; } flag; |
5.1.9计算脚本
示例:通过计算脚本控件生成查看按钮
var doc = getCurrentDocument(); var contractnumber=doc.getItemValueAsString("合同编号"); var value=""; var dql = "$formname='fm_twgb_contract'"; dql += " and 合同编号 ='" + contractnumber + "'"; var contractdocs = queryByDQL(dql); if(contractdocs!=null && contractdocs.size()>0){ var contractdoc = contractdocs.get(0); var docUrl = getContextPath()+ "/portal/dynaform/document/view.action?_docid="; docUrl += contractdoc.getId()+"&formid="+contractdoc.getFormid() ; value = "<input type=button value='查看' οnclick='window.showModalDialog(\""; value += docUrl+"\",\"\",\"resizable=yes;help=no;status=no;"; value += "font-size:9pt;dialogWidth:850px;dialogHeight:600px;status:no;scroll:no;\")'>"; } value; |
5.1.10创建Document
示例:通过iScript脚本以从当前文档获取数据直接创建文档。
var formProcess = getFormProcess(); var form = formProcess.doViewByFormName("fm_purchase_materials",getApplication()); //查询出表单 var process = getDocumentProcess(); var doc = process.doNew(form,getWebUser(),createParamsTable()); doc.findItem("title").setValue(getItemValueAsString("标题")); doc.findItem("type").setValue(getItemValueAsString("类型")); doc.findItem("count").setValue(getItemValueAsString("数量")); doc.setIstmp(false); process.doCreate(doc); |
6 DQL语法
语法格式:
$formname=’表单名’ [AND filter1……]
说明:
$formname:标识查询的表单;
AND filter1……:表示带过滤条件查询。
示例1:在表单控件校验脚本中的应用:
var doc = getCurrentDocument(); var dql = "$formname='表单1' AND code='TASK0001' AND $id <>'"+doc.getId()+"'"; var datas = queryByDQL(dql); var rtn = ""; if (datas.size()>0){ rtn = "系统中已经存在编号为:TASK0001 的记录!"; } rtn; |
示例2:在视图中DQL模式内容的应用:
var value1 = getItemValue("_申请单号"); var value2 = getItemValue("_请假类别"); var where = ( value1 != null && value1.trim().length() > 0) ? " and _申请单号 like '"+ value1+"%'" : ""; where += ( value2 != null && value2.trim().length() > 0) ? " and _请假类别='" + value2 + "'" : ""; "$formname=' TLK_请假申请4' " + where; |
总结:
DQL语句中使用到了code字段与$id字段进行过滤。其中,$id表示使用系统字段ID;code字段为用户通过表单配置的字段名。在DQL语句中凡使用系统字段都需要在字段名前加”$”符号,用户配置字段可直接使用。
上面的例子是通过脚本的形式返回一个DQL语句的字符串,系统会根据这个DQL语句进行查询。
7其它问题
7.1表单系统保留字段
系统字段 | 描述 |
ID | 记录唯一标识字段 |
PARENT | 存储父记录ID标识字段 |
LASTMODIFIED | 最后修改时间 |
FORMNAME | 对应模板表单名称 |
STATE | 流程当前状态记录ID |
AUDITDATE | 最近一次的审批时间 |
AUTHOR | 最近一次的审批人ID |
CREATED | 创建记录时间 |
FORMID | 表单ID |
ISTMP | 是否为临时记录 |
FLOWID | 流程ID |
VERSIONS | 版本 |
SORTID | 排序ID |
APPLICATIONID | 软件ID |
STATEINT | 流程当前状态值 |
STATELABEL | 流程当前状态标签 |
LASTFLOWOPERATION | 最近一次的审批操作类别 |
AUDITORNAMES | 当前审批人名称列表 |
AUDITORLIST | 当前审批人ID列表 |
MAPPINGID | 表单映射ID |
7.2定时任务
说明:
任务可以让系统在特定日期特定时间执行指定的任务内容,并通过终止条件结束任务。
示例1:定时清理数据
/*方法1:定时清理符合SQL清除条件的数据*/ var sql = "delete from tlk_qs_user_enterprice_info where istmp=0 and "; sql += " item_username in(select tlk_qs_user_enterprice_info.item_username "; sql += " from tlk_qs_user_enterprice_info where istmp=0 and not exists("; sql += "select t_qe.item_username from t_user,"; sql += " tlk_qs_user_enterprice_info t_qe where t_user.id=t_qe.item_username))"; var process = newPackages.cn.myapps.core.dynaform.dts.datasource.ejb.DataSourceProcessBean(); process.remove("del",sql,getApplication());
/*方法2:定时清理符合SQL清除条件的数据*/ //2.4版本及之后可使用 var sql = "delete from tlk_qs_user_enterprice_info where istmp=0 and "; sql += " item_username in(select tlk_qs_user_enterprice_info.item_username "; sql += " from tlk_qs_user_enterprice_info where istmp=0 and not exists("; sql += "select t_qe.item_username from t_user,"; sql += " tlk_qs_user_enterprice_info t_qe where t_user.id=t_qe.item_username))"; deleteByDSName("del",sql); |
示例2:定时发送提醒邮件
var sql = "select id from tlk_task where item_sendable='待发'"; //kd数据源名称,需要通过"软件->高级工具->数据源"创建一个kd数据源。 var datas = queryByDSName("kd",sql); if (datas!=null && datas.size()>0){ for (var i=0;i<datas.size();){ var docid = datas.get("id"); var doc = findDocument(docid); var from=doc.getItemValueAsString("from"); var to=doc.getItemValueAsString("to"); var host=doc.getItemValueAsString("host"); var user=doc.getItemValueAsString("user"); var password=doc.getItemValueAsString("password"); var bbc=doc.getItemValueAsString("bbc"); var subject=doc.getItemValueAsString("subject"); var body=doc.getItemValueAsString("body"); sendMail(from, to, subject, body, host, user, password, bbc, fasle); } } |
7.3 WebService
通过MYAPPS提供的WebService客户端接口来调用MYAPPS平台文档创建接口。
代码片断:
String formName = "fm_task";//表单名称 HashMap parameters = new HashMap(); parameters.put("title", "任务1"); parameters.put("startDate", "2011-01-18"); parameters.put("endDate", "2011-01-31"); parameters.put("type", "开发任务"); parameters.put("desc", "[任务]-[开发任务]-[2011-01-18]-[2011-01-31]"); // Default应用 String applicationId = "11de-9d0c-38898b6e-ac35-a50fa32293ae"; // 企业域下指定用户的ID,这里使用testuser用户的ID String domainUserId = "11de-c13a-0cf76f8b-a3db-1bc87eaaad4c"; try { service.createDocumentByDomainUser(formName, parameters, domainUserId, applicationId); } catch (DocumentServiceFault e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } |