1. 前端组件

1.1. 前端基础组件

请参见前端UI组件开发规范以及示例,提供lived demo。

1.2. 动态脚本链入

不修改系统页面,动态引入二次开发编写的JavaScript文件。

下面的过程,我们以新建协同为例,不修改系统的jsp或js文件,通过一个动态引入的js文件,达到替换系统的协同发送按钮的目的。

1.2.1. 确定页面的ModelAndView

可以访问对应页面,请求中加入ctp_dump_modelAndView参数确定ModelAndView的名称

http://127.0.0.1/seeyon/collaboration/collaboration.do?method=newColl&rescode=F01_newColl&ctp_dump_modelAndView=true

查看Response的Header,ModelAndView.name即为View的名称。

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ModelAndView.name: apps/collaboration/newCollaboration
Pragma: No-cache
Cache-Control: no-store
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=UTF-8
Content-Language: zh-CN
Vary: Accept-Encoding

推荐使用Fiddler工具。

至此,我们确定新建协同页面的ModelAndView为apps/collaboration/newCollaboration。

1.2.2. 建立自定义的JavaScript文件

  1. 在webapps/seeyon的extend/js目录下,建立与ModelAndView名称相同的子目录,如

    apps/collaboration/newCollaboration
    

    请注意大小写

  2. 创建任意名称的js文件,如

    webapps/seeyon/extend/js/apps/collaboration/newCollaboration/replaceButton.js
    

    新建的js文件在重启后生效

1.2.3. 编写控制逻辑

利用IE的开发人员工具或直接查看源代码,我们可以确定新建协同的发送按钮Id为sendId,因此,我们这样编写replaceButton.js

// 在原有的按钮后面添加我们自己定义的发送按钮
$('#sendId').after('<input id="btnCustomSend" type="button" value="发送"/>');
// 隐藏原发送按钮
$('#sendId').hide();

1.3. Form开发规范

1.3.1. Form布局规范

左树右表下编辑

img

实例

请参考:http://[host]:[port]/[context]/samples/layout.do?method=formall_l_r_demo

Form校验

属性

如要校验某种类型,要求input存在class为validate,并具备validate属性进行校验规则配置,validate属性值的格式要求是json对象定义字符串(不含

大括号)。

例如:

<input name="username" type="text" class="validate" validate="type:'string',maxLength:20,minLength:6"/>

在调用jquery扩展插件的formobj、jsonSubmit或validate方法时,会执行校验过程,例如:

$("#validDomain").jsonSubmit(); 
$("#validDomain").formobj();
$("#validDomain").validate();

以下所说的属性,全部都是json字符串的属性。

主属性是验证某一个类型必须存在的属性,副属性可选,不是必须存在的属性。

目前一共可以验证13种类型,再加上最后一种给定自定义正则表达式的自定义验证类型。

name属性或displayName在显示错误信息的时候要用到,但是也可以选择不给出(此时作为输入框的name属性必须存在)

Table Form校验规则

类型 主属性和可选值 副属性和可选值(空白表示无)
1、非空 notNull:true或nullable:true
2、包含空格的非空 notNullWithoutTrim:true
3、数字(小数) isNumber:true或type:number或type:1或type:2 max或maxValue(必须是数字,如果两个都给出,只使用前者) min或minValue(必须是数字,如果两个都给出,只使用前者) integerDigits整数位-数(必须是数字) decimalDigits或dotNumber小数位数(必须是数字,如果两个都给出,只使用前者)
4、数字(整形) isInteger:true max或maxValue(必须是数字,如果两个都给出,只使用前者) min或minValue(必须是数字,如果两个都给出,只使用前者)
5、电子邮件 isEmail:true或type:email
6、字符串 isWord:true或type:string或type:8或type:9 character:,将所有你认为是特殊字符的字符放进去,例如character:!@#$%^*()。 (如果特殊字符中存在中划线-的话,必须放在第一个)(如果特殊字符中存在脱字符^的话,必须不能放在第一个)
7、不允许为默认值 isDeaultValue:true、deaultValue:一个给定的值
8、固定电话号码 type:telephone
9、手机号码 type:mobilePhone
10、日期类型(要求格式:yyyy-MM-dd) type:3
11、日期时间类型(要求格式:yyyy-MM-dd HH:mm:ss) type:4
12、最大长度 maxLength:一个数字
13、最小长度 minLength:一个数字
14、自定义正则表达式 regExp:一个自定义的正则表达式,例如/[\d+]/
15、自定义校验函数 主属性:func:一个自己定义的函数(必须是全局函数,可以是匿名函数) (该函数可以没有返回值(js中没有返回值的话默认为null),返回null或false表示校验未通过)
16、自定义错误提示 主属性:errorMsg:一个字符串,例如:请输入数字!
17、js设置校验规则 请看下方的MxtCheckMsg方法 -

实例

请参考:http://[host]:[port]/[context]/samples/test.do?method=testValidate

1.3.2. Form回填

特点/使用方式

该组件用于新建、更新功能使用同一个页面,同时减少前端代码写入量。

不管是用js填入,还是使用jstl填入,如果手工回填的话,需要书写很多繁琐的代码。

例如:

如果是一个text,需要设置value属性。

如果是一个checkbox或者radio,需要设置checked属性。

如果是一个select,需要找到对应的option,设置selected属性。

若是我们每一处都写一些这样繁琐的代码,实在是太耗费精力了。

自动form回填就是这样一个为大家解决麻烦的组件,使用它,就可以自动为表单元素设置值,而不再需要自己写那些繁琐的js。

使用这个组件,大家需要做的就是在前台include一个jsp页面,在后台提供对应数据,然后就不需要再花费多余的心思。

  1. 若要使用该功能,前台只需同时也必须引入该文件。

    <%@ include file="/WEB-INF/jsp/common/common.jsp"%/>
    
  2. 这是前台代码示例。

    里面有两个div(也可以是form),每个div都有几个输入框或checkbox或select 注意div的Id和每一个表单元素的Id。 在同一个容器里,每一个表单元素的Id必须唯一。

    <div id="area1">
        用户名:<input type="text" id="username"/>
        密码:<input type="text" id="userage"/>
        爱好:<input type="checkbox" id="aihao1" value="1"/>(1)<input type="checkbox" id="aihao2" value="2"/>(2)<input type="checkbox" id="aihao3" value="3"/>(3)
        性别:<input type="radio" id="sex1" value="1"/>(男)<input type="radio" id="sex2" value="2"/>(女)
        星级:<select id="qiuji">
            <option value="1">地球</option>
            <option value="2">月球</option>
            <option value="3">火星</option>
        </select>
        实力:<select id="shili" multiple="true">
            <option value="1"></option>
            <option value="2"></option>
            <option value="3"></option>
        </select>
    </div>
    <div id="area22">
        用户名:<input type="text" id="username"/>
        密码:<input type="text" id="userage"/>
        爱好:<input type="checkbox" id="aihao1" value="1"/>(1)<input type="checkbox" id="aihao2" value="2"/>(2)<input type="checkbox" id="aihao3" value="3"/>(3)
        性别:<input type="radio" id="sex1" value="1"/>(男)<input type="radio" id="sex2" value="2"/>(女)
        星级:<select id="qiuji">
            <option value="1">地球</option>
            <option value="2">月球</option>
            <option value="3">火星</option>
        </select>
        实力:<select id="shili" multiple="true">
            <option value="1"></option>
            <option value="2"></option>
            <option value="3"></option>
        </select>
    </div>
    
  3. 这是后台代码示例。 与前台两个div对应,这里有两个Map。 前台有多少个容器,就需要多少个Map

    每一个Map都必须要通过调用request对象的setAttribute方法,添加到request对象中。

    调用setAttribute时,key的值必须要以ff开头,后面紧跟前台对应的容器Id(这里是div的Id)。

    向Map中put键值对时,key必须是容器中对应的表单元素的Id。

    如果表单元素是多选(例如checkbox、select),多个值之间用逗号分隔开。

        Map<String, String> test = new HashMap<String, String>();
        test.put("username", "zho'ulj");
        test.put("userage", "16\"'");
        test.put("aihao2", "2");
        test.put("aihao3", "3");
        test.put("sex2", "2");
        test.put("qiuji", "2,3");
        test.put("shili", "1,2,3");
        request.setAttribute("ffarea1", test);
        Map<String, String> test2 = new HashMap<String, String>();
        test2.put("username", "岳不群!");
        test2.put("userage", "16\"'");
        test2.put("aihao2", "2");
        test2.put("aihao3", "3");
        test2.put("sex2", "2");
        test2.put("qiuji", "2,3");
        test2.put("shili", "1,2,3");
        request.setAttribute("ffarea22", test2);
    
  4. 如果需要对比如Ajax调用返回的数据对象进行手动回填,可以调用jquery插件的fillform方法,例如:

        tBS.testAjaxMethod(param, {success:
               function(obj){
                  $("#myform").fillform(obj);
               }
            });
    

实例

请参考:http://[host]:[port]/[context]/samples/test.do?method=testFillForm

1.3.3. Form提交

特点/使用方式

该组件主要作为CTP平台form提交的标准方式,禁止使用普通的form提交

使用该组件可以极大的简化前后台代码的提交和获取参数的方式。

使用限制:

  1. 除radio外,同一个容器(或分区)内表单元素(包括checkbox)不能有相同的name或id。
  2. select如果是多选的话,后台会转换成List类型的对象。 该组件通过jQuery插件的方式提供,调用jsonSubmit方法即可。

主要有四种提交方式(前台),四种获取参数的方式(后台)

普通提交(无分区、无分组)、分组提交(无分区)、分区提交(无分组)、分区分组式提交

  1. 若要使用该功能,前台只需同时也必须引入该文件。

    <%@ include file="/WEB-INF/jsp/common/common.jsp"%/>
    
  2. 普通提交方式

    前台调用jsonSubmit方法提交参数。

    后台调用ParamUtil.getJsonParams()获取参数。

    getJsonParams方法返回一个Map类型的对象。

    其key是json对象的属性名,value是json对象的属性值。

    如果json对象的属性值是一个数组的话,Map的value就是一个List。

    前台Html

    <form id="form1" name="form1" method="post" action="test.do?method=testJsonSubmit2">
        <table>
            <tbody>
                <tr><td colspan="2"><label>表单<font color="red">无分区无分组</font>提交</label></td></tr>
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
            </tbody>
        </table>
    </form>
    

    前台js代码:

    $("#form1").jsonSubmit({debug:false});
    参数中的debug属性在正式开发的时候不需要给出,或者需要设置为false

    后台代码:

    Map params = ParamUtil.getJsonParams();
    for(Object entryObj : params.entrySet()){
        if(entryObj instanceof Map.Entry){
            Map.Entry entry = (Map.Entry)entryObj;
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
    
  3. 分组提交方式

    所谓的分组,其实就是一个容器内有多个name或id相同的输入框。 前台的提交方式与普通方式没有区别,都是调用jsonSubmit方法。 后台获取参数的方式有区别,使用ParamUtil.getJsonParamsGroup()方法。 getJsonParamsGroup方法返回的是一个List类型的对象。 List中的每一个元素都是一个Map。 该Map的内容与getJsonParams返回的Map内容相同。

    前台Html

    <form id="form4" name="form4" method="post" action="test.do?method=testJsonSubmit4">
        <table>
            <tbody>
                <tr><td colspan="2"><label>表单<font color="red">无分区分组</font>提交</label></td></tr>
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
                <tr>
                    <td><input id="savebtn4" type="button" value="提交paramGroup"/></td>
                    <td></td>
                </tr>
            </tbody>
        </table>
    </form>
    

    前台js代码:

    $("#form4").jsonSubmit({debug:false});
    参数中的debug属性在正式开发的时候不需要给出,或者需要设置为false

    后台代码:

    List groups1 =ParamUtil.getJsonParamsGroup();
    for(Object o : groups1){
        if(o instanceof Map){
            Map map = (Map)o;
            for(Object entryObj : map.entrySet()){
                if(entryObj instanceof Map.Entry){
                    Map.Entry entry = (Map.Entry)entryObj;
                    System.out.println(entry.getKey() + ":" + entry.getValue());
                }
            }
        }
    }
    
  4. 分区提交方式:

    前台的提交方式有区别,方法名不变,都是jsonSubmit方法。 不过参数有改变,{domains:["domain31","domain32"],debug:false} 多了一个domains属性,其值必须是一个数组,数组中的每一个元素必须是要提交的多个容器的id。 后台获取参数的方式也不同了,使用ParamUtil.getJsonDomain("domain31")方法。 getJsonDomain方法的参数需要给出前台给出的容器Id。 如果有多个domain,必须调用多次getJsonDomain方法来获取到所有的domain。 getJsonDomain的返回值也是一个Map。 该Map的内容与getJsonParams返回的Map内容相同。

前台html:

   <form id="form3" name="form3" method="post" action="test.do?method=testJsonSubmit3">
       <table id="domain31">
           <tbody>
               <tr>
                   <td><label>用户名</label></td>
                   <td><input type="text" name="username"/></td>
               </tr>
               <tr>
                   <td><label>密码</label></td>
                   <td><input type="password" name="passwork"/></td>
               </tr>
           </tbody>
       </table>
       <table id="domain32">
           <tbody>
               <tr>
                   <td><label>用户名</label></td>
                   <td><input type="text" name="username"/></td>
               </tr>
               <tr>
                   <td><label>密码</label></td>
                   <td><input type="password" name="passwork"/></td>
               </tr>
               <tr>
                   <td><input id="savebtn3" type="button" value="提交domain"/></td>
                   <td></td>
               </tr>
           </tbody>
       </table>
   </form>

前台js代码:

   $("#form4").jsonSubmit({domains:["domain31","domain32"],debug:false});
   参数中的debug属性在正式开发的时候不需要给出,或者需要设置为false;
   domains属性值必须是一个数组,数组中的每一个元素必须要要提交的多个容器的id。

后台代码:

   Map domain1 =ParamUtil.getJsonDomain("domain31");
   for(Object entryObj : domain1.entrySet()){
       if(entryObj instanceof Map.Entry){
           Map.Entry entry = (Map.Entry)entryObj;
           System.out.println(entry.getKey() + ":" + entry.getValue());
       }
   }
   Map domain2 =ParamUtil.getJsonDomain("domain32");
   for(Object entryObj : domain2.entrySet()){
       if(entryObj instanceof Map.Entry){
           Map.Entry entry = (Map.Entry)entryObj;
           System.out.println(entry.getKey() + ":" + entry.getValue());
       }
   }
  1. 分区分组式提交

    这种方式其实是前面两种方式的组合: 分区分组是提交,首先是分区是提交。 每个分区中,可能存在分组,也可能不存在分组。 前台的提交方式与分区式提交相同,都是jsonSubmit方法。 参数也相同,都是{domains:["domain31","domain32"],debug:false} 多了一个domains属性,其值必须是一个数组,数组中的每一个元素必须是要提交的多个容器的id。 对于存在分组的分区,后台获取参数的方式:List groups1 =ParamUtil.getJsonDomainGroup("domain51"); 参数就是前台分区的id,其返回值是一个List,其中的每一个元素是一个Map。 对于不存在分组的分区,后台获取参数的方式与分区式提交后台获取参数的方式相同。 都是Map domain2 = ParamUtil.getJsonDomain("domain52");

    前台html:

    <form id="form5" name="form5" method="post" action="test.do?method=testJsonSubmit5">
        <table id="domain51">
            <tbody>
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
    
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
            </tbody>
        </table>
        <table id="domain52">
            <tbody>
                <tr>
                    <td><label>用户名</label></td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td><label>密码</label></td>
                    <td><input type="password" name="passwork"/></td>
                </tr>
                <tr>
                    <td><input id="savebtn5" type="button" value="提交domainGroup2"/></td>
                    <td></td>
                </tr>
            </tbody>
        </table>
    </form>
    

    前台js代码:

    $("#form4").jsonSubmit({domains:["domain51","domain52"],debug:false});
    参数中的debug属性在正式开发的时候不需要给出,或者需要设置为false;
    domains属性值必须是一个数组,数组中的每一个元素必须要要提交的多个容器的id。
    

    后台代码:

    List groups1 = ParamUtil.getJsonDomainGroup("domain51");
    for(Object o : groups1){
        if(o instanceof Map){
            Map map = (Map)o;
            for(Object entryObj : map.entrySet()){
                if(entryObj instanceof Map.Entry){
                    Map.Entry entry = (Map.Entry)entryObj;
                    System.out.println(entry.getKey() + ":" + entry.getValue());
                }
            }
        }
    }
    Map domain2 = ParamUtil.getJsonDomain("domain52");
    for(Object entryObj : domain2.entrySet()){
        if(entryObj instanceof Map.Entry){
            Map.Entry entry = (Map.Entry)entryObj;
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
    
  2. 如果需要获取页面中某个分区中的数据对象进行Ajax提交或其它处理,可以调用jquery插件的formobj方法,比如:

    var obj = $("mydomain").formobj();
    tBS.testAjaxSubmit(obj,{success:
       function(retObj){
          alert("success");
       }
    });
    

Table 13.2.

属性名 属性值与说明
domains 必须是一个数组,分区式提交时该参数必须给出,里面每一个元素都必须是其中一个分区的id。
debug 当该属性的值是true时,会在提交之前将生成的json字符串alert出来,以便调试。
beforeSubmit 该属性的值必须是一个函数,当该函数的返回值等于false时,不会提交该form。

jsonSubmit方法的参数说明

该方法只接收一个参数,以Object的方式给出,我们可以给它添加属性。

模拟异步提交方式,可使用callback参数指定回调函数实现,如:$("#mydiv").jsonSubmit({callback : function() { alert('回调函数'); }});

实例

请参考:http://[host]:[port]/[context]/samples/test.do?method=testJsonSubmit

1.3.4. 表单数据清除

框架提供clearform函数用于清除某个区域内的表单输入域的值,代码例子如下:

<script>
$(document).ready(function() {
    $("#mybtn").click(function() {
      $("#mydomain").clearform();
    });
});
</script>
<input type="button" id="mybtn">
<div id="mydomain">
<input type="text"><input type="checkbox"><input type="radio"><textarea></textarea>
</div>

1.3.5. 表单控件批量禁用/启用

框架提供disable和enable函数用于批量禁用和启用某个区域的控件,代码例子如下:

<script>
  $(document).ready(function() {
    $("#mybtn").toggle(function() {
      $("#mycal1").disable();
      $("#testRegion").disable();
    }, function() {
      $("#mycal1").enable();
      $("#testRegion").enable();
    });
  });
</script>
<input type="button" id="mybtn" value="禁用/启用">
<div id="testRegion">
    <a href="javascript:void(0)" class="common_button common_button_gray">按钮1</a><a href="javascript:void(0)"
        class="common_button common_button_gray">按钮2</a> <input type="text" class="comp"
        comp="type:'calendar',ifFormat:'%m-%Y-%d'"> <input type="checkbox"><input type="radio">
</div>

1.4. 选人组件

框架目前提供了简单的选人界面包装,可以通过下面的HTML定义选人组件

<input type="text" id="spc1" name="spc1" class="comp" comp="type:'selectPeople',mode:'open',value:'Department | -884316703172445_1,Member | 1730833917365171641',text:'开发中心、人员2'"/>

通过javascript函数调用选人界面的方法如下:

$.selectPeople({
params : {
  text : '开发中心、人员1',
  value : 'Department | -884316703172445_1,Member | 1730833917365171641'
},
callback : function(ret) {
  alert(ret.value + ":" + ret.text);
}
});

支持的comp属性或$.selectPeople函数的params参数如下:

属性 必填 说明 实例
type 'selectPeople' type:'selectPeople'
panels 要显示的面板 Account,Department、Team、Post、Level、Role、Outworker、RelatePeople组合,逗号分隔
selectType 可选择的类型,即模型中的前7个,逗号分隔 Account、Department、Team、Post、Level、Role、Member,Email,Mobile
value 值为SPD字符串 value:'Member|123456,Department | 23456'
也可以是JS变量 value:expr1 options:{maxSize:1,showOriginal:true,showAccountShortname:true}
text 选人显示值 如'开发中心、人员2'
mode 选人弹出方式,缺省以div方式打开;mode:'open'时以模态对话框方式打开
showMe 是否显示当前登录者:true | false
maxSize 最多选择项目的个数 缺省-1,表示不限制
minSize 最少选择项目的个数 ,缺省为1
elements Element[] 原有数据,默认为null
showOriginalElement true | false 是否回显原有数据,默认为true
hiddenSaveAsTeam true | false 是否隐藏“另存为组”,默认为false
hiddenMultipleRadio true | false 是否隐藏“多层”按钮,默认为false
includeElements Element[] 备选的数据范围,用于在指定范围内选人
excludeElements Element[] 不在备选项中显示 默认为null
isNeedCheckLevelScope true | false 是否进行职务级别范围验证 默认true
onlyLoginAccount true | false 是否只显示登录单位 默认false
showAccountShortname yes | no | auto 是否只一直显示登录简称 默认auto
showConcurrentMember true | false 是否显示兼职人员(只外单位) true
hiddenPostOfDepartment true | false 是否隐藏部门下的岗位 默认false
hiddenRoleOfDepartment true | false 是否隐藏部门下的角色 默认false
onlyCurrentDepartment true | false 是否仅显示当前部门 默认false
showDeptPanelOfOutworker true | false 当是外部人员时,显示部门面板 默认false
unallowedSelectEmptyGroup true | false不允许选择空的组、部门, 默认false
showTeamType "1,2,3" 需要显示的组类型1-个人,2-系统,3-项目, 默认null,表示所有
hiddenOtherMemberOfTeam true | false 是否隐藏组下的外单人员,默认false
hiddenAccountIds "1,2,3" 隐藏的单位,将不在单位下拉中出现
isCanSelectGroupAccount true | false 是否可以选择集团单位,默认true
showAllOuterDepartment true | false 是否显示所有的外部部门,默认false
hiddenRootAccount true | false 是否隐藏集团单位,默认false
hiddenGroupLevel true | false 是否隐藏集团职务级别,默认false
showDepartmentsOfTree "部门Id," 部门树上可以显示的部门
showFixedRole true | false 显示固定角色,默认false
hiddenAddExternalAccount true | false 显示增加外部单位连接,默认false
showDepartmentMember4Search true | false 部门查询可用时,是否显示部门下面的成员,默认false,不显示
isAllowContainsChildDept true | false 在部门面板选择部门时,是否允许同时选择父部门和子部门,默认为false,不允许
isConfirmExcludeSubDepartment true | false 选择部门时,是否提示“是否包含子部门”,默认false即包含子部门
returnValueNeedType true | false 返回值是否需要带类型,默认true,如果false则只返回Id,只用于单一选择

实体类型

名称 代号 描述
单位 Account
部门 Department
岗位 Post
职务级别 Level
Team
人员 Member
角色 Role
外部人员 Outworker 在组织模型中不存在该类型,它其实是特殊的部门和人员
关联人员 RelatePeople 它其实是人员
外部单位 ExchangeAccount 只用于公文交换
其他 组织模型可自行扩展,但必须有相应的解析器 -

要重新刷新选人组件,重新设置value和text,可以调用:

$("#spc1").comp({value:'newval', text:'newtext'});

将会取代之前comp属性中设置的value和text参数值

1.5. 文件管理组件

文件管理组件针对的目标是文件,仅仅完成文件的操作,而不涉及内容。

内容管理模块的目标是内容,内容的载体可能是文件,也可能是页面,或数据库中的数据;内容管理涉及到权限、共享、发布、存档...等操作。

物理存储有文件和文件夹的真实名称和路径,内容管理模块可能对应有逻辑意义的档案名和类属名。

文件管理组件除了为内容管理组件提供底层的支持,还要为协 同附件等功能提供服务,所以在文件存储映射上应以物理存储为准。

1.5.1. 应用范围

协同、公文系统各应用的office正文、附件、图片/Flash的管理

应用的office正文、附件、图片必须使用该组件进行统一存储

文档管理/知识管理应用的用户上载文件的管理

1.5.2. 附件管理

附件组件的使用分为前端和后端,前两部分配合使用才能实现完整的附件相关功能。前端负责界面展现,后端负责附件的保存、获取相关逻辑。在开发时需要分别编写前、后端代码。

附件上传分为下面几种方式:

  • 标准方式:即附件的显示、保存等功能不需要调用者关系,组件会完成所有功能。调用者只按要求调用几个接口即可。使用方法参考下面3.2.1
  • 扩展方式:即组件只完成部分功能,剩余功能需要调用者来处理。适用于上传、解析后不在使用该文件。即上传后对该文件直接解析处理,并不返回调用页,在调用者处理完后返回自己期望的页面。
  • 一页多个上传组件:即一个页面做多处需要上传文件,每处上传的属性和显示的位置不同。标准方式和扩展方式都支持。
  • js动态创建方式:上面三种都依赖与页面完整加载,对于页面不重新加载,而是通过js操作的需使用此方式。例如行为动态生成,每行都包含一个上传组件,需要通过js方法动态生成。

标准方式

前端

调用过程:

1、声明一个附件上传组件;

2、在对应的菜单或者按钮上调用 insertAttachment() 方法

3、在自己的页面中submit form 时必须使用分区方式提交。

<div id="attachmentTR" style="display:none;">${ctp:i18n("common.attachment.label")}:(<span id="attachmentNumberDiv"></span>)</div>
<div class="comp" comp="type:'fileupload',applicationCategory:'1',canDeleteOriginalAtts:false,originalAttsNeedClone:false"
 attsdata='${ attachmentsJSON}'>
<input type="button" onclick="insertAttachment()" value="上传附件">
  • 如果要显示附件数量,请在需要显示附件数量的位置放置: 样式可以改, 里面的id不能修改.
  • 注意comp属性值为:"type:'fileupload'" ,
  • 如果一页只有一个上传组件调用insertAttachment()显示上传界面,如果有多个上传组件需要调用insertAttachmentPoi(attachmentTrId属性的值)方法,该方法需要和attachmentTrId属性配合使用。支持如下属性:
属性 说明 实例
type 指当前为上传文件组件,值为固定值 type:'fileupload
attsdata 指原有的附件,如:业务模块的修改页面,或协同保存待发—新建等功能, 需要把原有的附件显示。 使用下面接口获取原有附件: /* 返回附件列表的json字符串 为前端显示附件获取一个主题下的所有附件信息,包括二级主题, 如:协同的附件和协同回复的附件 / public String getAttListJSON(Long reference); attsdata='${ attachmentsJSON}'
applicationCategory 应用分类,统一在ApplicationCategoryEnum定义 applicationCategory:'1'
canDeleteOriginalAtts 指能否删除原有的附件,如转发协同不能删除原有附件 canDeleteOriginalAtts:false
originalAttsNeedClone 是否需要复制原有附件,常用在模板调用 originalAttsNeedClone:false
extensions 允许上传的文件类型,用文件会后缀表示,多个类型用逗号分隔(,) extensions:'txt,jpg'
maxSize 上传文件的大小限制,单位为字节 maxSize:10240000
isEncrypt 对上传的文件是否加密,true为加密;false为不加密 isEncrypt:false
quantity 最多上传文件个数,不使用该参数事默认是5 quantity:1
attachmentTrId 一页支持多个附件上传组件,和insertAttachmentPoi('poi77')方法配合使用 在方法中传入该属性的值。 attachmentTrId:poi77
callMethod 在不改变使用过程的情况下,在上传附件后回调该方法。 此属性依赖takeOver属性,takeOver值为false 注意!方法名必须用引号括起来作为字符串。具体返回值请参考扩展方式中的说明。 callMethod:'testCallBack' takeOver:false
takeOver 是否接管附件上传(即弹出窗口关闭)之后的逻辑。 该属性和callMethod配合使用,如果不使用回调方法,可以不使用该属性; 否则属性值应为false takeOver:false

实例

请参考:http://[host]:[port]/[context]/demo/filemanagement/filecomp.jsp

后端

后端负责对附件信息的存储。应用于附件的关联关系存储在附件表中。

在action的方法中需调用附件组件的接口方法:AttachmentManager 的 create(ApplicationCategoryEnum category, Long reference, Long subReference)

为了保证多次上传和删除附件,需要在调用create之前先调用deleteByReference(Long reference)或者 deleteByReference(Long reference, Long subReference)

    /**
     * 该方法必须和 comp=type:'fileupload' 配合使用
     * @param category         所属应用分类
     * @param reference        主题Id,如协同的Id
     * @param subReference      二级主题Id,如协同的回复Id,如果当前是给协同上传附件,则该subReference 与 reference相同
     * @return 附件类型任意组合 如:"012"、"12"、"01"、"02"; 其中 0-文件附件 1-图片 2-关联文 ,排列无序
     * @see com.seeyon.ctp.common.filemanager.Constants.ATTACHMENT_TYPE_FILE
     * @see com.seeyon.v3x.common.filemanager.Constants.isUploadLocaleFile(String)
     * @throws Exception
     */
    public String create(ApplicationCategoryEnum category, Long reference, Long subReference) throws Exception;
-------------------------------
例如:
  public String create(ApplicationCategoryEnum category, Long reference, 
      Long subReference) throws Exception; 
      deleteByReference(colSummary.getId());
      String attaFlag = this.attachmentManager.create(ApplicationCategoryEnum.collaboration, 
                        colSummary.getId(), colSummary.getId()); 
      if(com.seeyon.v3x.common.filemanager.Constants.isUploadLocaleFile(attaFlag)){ 
               colSummary.setHasAttachments(true); 
       }

扩展方式

扩展过程目的是为后端返回文件对象,后端程序获得文件对象后可自行解析处理。

假设有如下场景:

需要把通讯录导入到系统中。处理逻辑为:

  • 上传通讯录文件
  • 解析通讯录文件
  • 持久化解析后的数据
  • 返回页面,告知用户成功或失败信息。

从上面过程看,从第二步开始与附件上传的标准过程不同,需要调用者来处理。

前端

前端调用过程分为4步:

<script type="text/javascript">
<!--
……
//附件上传后回调方法
function testCallBack(fileid){
  //处理文件逻辑的action
  location.href="/t1/fileController.do?fileid="+fileid;  
}
//-->
</script>
    <div class="comp" comp="type:'fileupload',callMethod:'testCallBack'"> 
    <input type="button" onclick="insertAttachment()" value="上传附件">

增加回调方法,回调时会传入文件的id,需要把该id传入到目标action中。

在此方法中请求处理文件的action,若属性firstSave为ture,则fileid为包含Attachment 的js ArrayList。`Attachment属性如下:this.id = id; this.reference = reference; this.subReference = subReference; this.category = category; this.type = type; this.filename = filename; this.mimeType = mimeType; this.createDate = createDate; this.size = size; this.fileUrl = fileUrl; this.description = description || ""; this.needClone = needClone; this.extension = extension; this.icon = icon; this.isCanTransform = isCanTransform == 'true' ? true : false; this.onlineView = onlineView == null ? true : onlineView; this.extReference = ""; this.extSubReference = ""; this.showArea="";

声明文件上传标记。注意comp属性值为:"type:'fileupload'"

如果一页只有一个上传组件调用insertAttachment()显示上传界面, 如果有多个上传组件需要调用insertAttachmentPoi(attachmentTrId属性的值)方法,该方法需要和attachmentTrId属性配合使用。

支持属性:

属性 说明 实例
type 指当前为上传文件组件,值为固定值 type:'fileupload
callMethod 回调方法名。注意!方法名必须用引号括起来作为字符串。 callMethod:'testCallBack'
attsdata 指原有的附件,如:协同保存待发—新建,需要把原有的附件显示 attsdata='${ attachmentsJSON}'
applicationCategory 应用分类,统一在ApplicationCategoryEnum定义 applicationCategory:'1'
canDeleteOriginalAtts 指能否删除原有的附件,如转发协同不能删除原有附件 canDeleteOriginalAtts:false
originalAttsNeedClone 是否需要复制原有附件,常用在模板调用 originalAttsNeedClone:false
extensions 允许上传的文件类型,用文件会后缀表示,多个类型用逗号分隔(,) extensions:'txt,jpg'
maxSize 上传文件的大小限制,单位为字节 maxSize:10240000
isEncrypt 对上传的文件是否加密,true为加密;false为不加密 isEncrypt:false
quantity 最多上传文件个数,不使用该参数事默认是5 quantity:1
firstSave 是否先保存附件表信息,ture为先保存,false或者无该属性为后保存。 并且为ture时,回调方法得到的参数值为包含Attachment 的js 数组,否则为逗号(,)分隔的文件ID字符串。 这种情况下后端应该调用附件更新接口,目的是关联业务数据域附件数据。 firstSave:true
attachmentTrId 一页支持多个附件上传组件,和insertAttachmentPoi('poi77')方法配合使用 在方法中传入该属性的值。 attachmentTrId:poi77
showReplaceOrAppend 是否显示“追加”、“覆盖”radio。即,在上传页面中会提供如下元素, 业务模块根据下面元素确定相关逻辑。 showReplaceOrAppend:true

实例

请参考:http://[host]:[port]/[context]/demo/filemanagement/filecomp.jsp

后端

后端存在两种情况:

  1. 不保存附件信息,即获取到上传文件后,获取到文件数据后该文件不再使用,不需要作为附件存储起来。
  2. 保存附件信息。
不保存附件信息

通过以下方式可以得到刚上传的文件:

    public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView modelAndView = new ModelAndView("apps/file/selfupload");
        File file=fileManager.getFile(Long.parseLong(request.getParameter("fileid")),new Date());

        //对得到的文件进行处理
        //…… 
        modelAndView.addObject("filename", file.getName());
        modelAndView.addObject("filelength", file.length());
        return modelAndView;
    }

获取前端传来的文件id,并调用 fileManager getFile(Long fileId, Date createDate) 方法获取该文件,时间为当前即可。在此处处理该文件。

保存附件信息

在后端业务操作中调用如下接口,用来关联附件也业务数据:

 /**
     * 根据文件标识新引用
     * @param fileUrl 文件标识
     * @param referenceId 业务id
     */
    public  void updateReference(Long fileUrl, Long referenceId);

    /**
     * 根据文件标识更新引用及子引用
     * @param fileUrl 文件标识
     * @param referenceId 业务主ID
     * @param subReference 业务子ID
     */
    public  void updateReferenceSubReference(Long fileUrl, Long referenceId, Long subReference);
1 与该业务ID相关的所有附件都在同一处显示,使用该接口更新。
2 与该业务ID相关的所有附件都在同多处显示,每处根据子ID进行区分,使用该接口更新。

js动态创建方式

通过调用js方法:dymcCreateFileUpload() 来实现。对于不需要的特性输入null即可。

/**
 * locationElementid, 位置id,放置上传组件的位置,比如div的id("dyncid"):<div id="dyncid"> </div>
 * applicationCategory, 应用模块id
 * extensions, 文件扩展名,逗号分隔的字符串
 * quantity, 最多上传的文件数
 * isEncrypt, 是否加密
 * callMethod, 回调方法名
 * attachmentTrId, 对赢得文件上传的id
 * firstSave,是否先保存附件表信息,默认false:后保存。
 * atts 附件数据
 * canDeleteOriginalAtts 是否可删除附件
 * takeOver 是否接管附件上传(即弹出窗口关闭)之后的逻辑。 该属性和callMethod配合使用,如果不使用回调方法,可以不使用该属性; 否则属性值应为false
 * maxSize 上传文件的大小限制,单位为字节
    */
    function dymcCreateFileUpload(locationElementid,applicationCategory,extensions,quantity,isEncrypt,callMethod, attachmentTrId,firstSave,canDeleteOriginalAtts,atts,takeOver,maxSize){
附件相关的js 方法

对于以上方式不能满足交互需要,可以使用下面接口灵活控制附件相关特性。

/**
 * 获取当前组件提交的附件数据。对于一页存在多个上传组件,每个组件所在区域单独处理附件时(即只处理本区域附件,其他区域附件不处理),
 * 使用该方法,可以把该组件上传的附件数据,存放到以组件ID为domainid的区域内。
 * inputDomainId 上传组件id
    */
    function saveAttachmentPart(inputDomainId ){
附件列表
前端

与附件上传过程使用相同的组件,请参考附件上传。

后端

主要负责获取附件数据,根据业务id获取对应的附件列表,返回类型要求是JSON字符串。

接口方法为:attachmentManager.getAttListJSON(主数据Id)

注意:同一主题的所有附件一次性抽取,通过subRefenerce区分,

如:计划主题与计划回复 的附件一次按照计划Id 抽取

示例:

          ModelAndView modelAndView = new ModelAndView("apps/file/inituploadfile");
        ……
        modelAndView.addObject("attachmentsJSON", attachmentManager.getAttListJSON(2L));
        return modelAndView;

1.6. 关联文档

关联文档开发包括两种角色,调用者和内容开发者。调用者通过简单接口使用关联文档组件;内容开发者提供可关联的内容部分,需根据关联文档框架规范进行开发。

1.6.1. 调用关联文档

关联文档调用分为下面几种方式:

  • 标准方式:即jsp页面中放入标签,通过加载jsp来生成相应内容。
  • js动态创建方式:对于页面不重新加载,而是通过js操作的需使用此方式。例如动态生成,每行都包含一个关联文档组件,需要通过js方法动态生成。

标准方式

前端页面调用方法

调用过程包含下面两步:

<div class="div-float">关联文档:<span id="attachment2NumberDivposition1"></span></div> 
<div class="comp" comp="type:'assdoc',attachmentTrId:'position1', modids:'1'" attsdata='${ attachmentsJSON}'>
           <input type="button" onclick="quoteDocument('position1')" value="关联文档">
  • 关联文档数量的显示,id值的柜式为:固定部分(attachment2NumberDiv )+组件位置部分(即 attachmentTrId 属性值),例如:id="attachment2NumberDivposition1"
  • 添加关联文档显示区,即在需要显示关联文档的地方添加 type:'assdoc' 的组件
属性 说明 实例
type 指当前为关联文档组件,值为固定值 type:'assdoc'
attachmentTrId 如果一页包含多个关联文档,需要使用该属性指定当前组件的位置id attachmentTrId:'position1',
modids 应用id字符串为逗号(,)分隔,id值为全系统统一编号 modids:'1' 1 = Collaboration;2= Form;3 = Knowledge management ;4= Official document ;5 = Plan;6= Meeting;7= Bulletin;8 = News;9 = Discussion
attsdata 指原有的关联文档,如:业务模块的修改页面,或协同保存待发—新建等功能, 需要把原有的关联文档显示。 使用下面接口获取原有附件: /* 返回关联文档列表的json字符串 为前端显示附件获取一个主题下的所有附件信息,包括二级主题, 如:协同的附件和协同回复的附件 / public String getAttListJSON(Long reference); attsdata='${ attachmentsJSON}'
callMethod 回调方法名。注意!方法名必须用引号括起来作为字符串。 callMethod:'testCallBack'
embedInput 需要在组件位置生成一个hidden input,id、name为 该属性值。不需要该input时不需要设置该属性。 embedInput:'field001'

打开关联文档窗口的接口,调用quoteDocument(poi) 打开关联文档窗口。

poi为组件的位置属性值

后端保存、获取

后端保存与获取和附件保存、获取方式相同。使用同一套接口可以一次保存附件和关联文档的数据,获取也是如此。即:如果当前提交既有附件又有关联文档,只需要调用一次保存接口。

js动态创建方式

通过调用js方法:dymcCreateAssdoc()来实现。对于不需要的特性输入null即可。

/**
 * locationElementid, 位置id,放置关联组件的位置,比如div的id("dyncid"):<div id="dyncid"> </div>
 * attachmentTrId, 同一页多个关联组件的区分id
 * atts 关联文档数据
    */
    function dymcCreateAssdoc(locationElementid, attachmentTrId,modids,atts)

1.6.2. 关联内容开发

主要包含下面步骤:

  1. 获取业务内容并展现

  2. 展现页面中要包含checkbox,并且checkbox的 onclick 响应事件中应调用接口:parent.quoteDocumentSelected(this, subject, ${applicationCategoryType.name}, id);同时需要提供一个js方法,用来取消选择。该方法名固定为deselectItem(fileUrl),方法主要是根据传进来的业务id值来取消选择。例如:

   function deselectItem(fileUrl){
       $("input[value='"+fileUrl+"']").attr("checked", false);
   }
  1. 注册关联内容到关联文档框架,让框架自动识别该部分内容

quoteDocumentSelected 接口说明

接口说明:

/**
 * checkbox回调方法
 * obj, checkbox对象 this
 * subject, 标题
 * documentType, 应用类型
 * url,关联内容的id
    */
    function quoteDocumentSelected(obj, subject, documentType, url)


例如:quoteDocumentSelected(this, subject, ${applicationCategoryType.name}, id)

注册关联内容到框架

关联内容的请求url、应用编号等注册,在模块(插件)的spring中配置如下bean

    <bean id="test1" class="com.seeyon.ctp.common.assdoc.AssdocDefinition">
        <property name="appId" value="1" />
        <property name="url" value="http://www.baidu.com" />
    </bean>
  • 定义class="com.seeyon.ctp.common.assdoc.AssdocDefinition" 的bean

  • 设置应用编号属性,name="appId",value为如下的应用编号`

    1 = Collaboration

    2 = Form

    3 = Knowledge management

    4 = Official document

    5 = Plan

    6 = Meeting

    7 = Bulletin

    8 = News

    9 = Discussion

  • 设置该应用关联列表的url.

1.7. 正文编辑器

提供可视化的HTML编辑支持。

定义:

新建协同所使用的全功能编辑器

<textarea id="editor1" class="comp" comp="type:'editor',contentType:'html'">正文</textarea>

处理协同所使用的最简版编辑器

<textarea id="content_deal_comment" name="content_deal_comment"  comp="type:'editor',contentType:'html',height:'220px',toolbarSet:'VerySimple',autoResize:false,showToolbar:false"></textarea>

可配置参数如下:

参数 说明
toolbarSet 工具栏类型:可选值为Basic(缺省)、VerySimple(协同回复区域)、Bbs(讨论使用)
autoResize 自动根据窗口调整大小
showToolbar 是否显示工具栏
height 高度,缺省100%

方法:

方法 备注 示例
getEditorContent 获取正文编辑器的内容(HTML格式) $("#fckedit").getEditorContent()
getEditorText 获取正文编辑器的文本(去除HTML标记) $("#fckedit").getEditorText()
setEditorContent 设置正文编辑器的内容 $("#fckedit").setEditorContent(html)

1.8. 大图查看(支持放大缩小、原图查看功能)

  1. 可以兼容到IE7

  2. 支持左右按钮切换图片、ESC退出

  3. 支持滚轮缩放图片的大小

  4. 支持图片放大后拖拽

  5. 新增一个原图查看功能

    可以直接将 DEMO下载请鼠标右键-链接地址另存为放在v5的seeyon目录运行。

results matching ""

    No results matching ""