实现一个类似于钉钉审批人员选择的功能。
这里使用zTree实现组织架构树。
实体类需要有id,pId实现上下级关系。
company.java getter/setter略。
private int company_id;//公司idprivate String company_name;//公司名称private String remark;//备注信息private String foundTime;//成立时间private int company_pid;//上级idprivate int user_id;private String name;private int dept_id;private String dept_name;private int id;private int pid;private List<Company> companyChildren=new ArrayList<>();private List<Dept> deptChildren=new ArrayList<>();private String pCName;//上级名称private List<Company> children = new ArrayList<>();
dept.java
private int dept_id; //部门idprivate String dept_name;//部门名称private String name;//部门别名private int company_id;//所属公司idprivate String remark;//备注信息private int dept_pid;//上级部门idprivate String company_name;private int id;private int pid;private List<Dept> deptChildren=new ArrayList<>();private List<Job> jobChildren=new ArrayList<>();private List<Dept> children=new ArrayList<>();private String pName;//上级部门
job.java
private int job_id;//idprivate String job_name ;//职务名称private int job_pid;//上级idprivate int dept_id;//所属公司private int status;private String name;private int id;private int pid;private int c_id;//公司idprivate String c_name;//公司名private int c_pid;//公司上级idprivate int d_id;//部门idprivate String d_name;//部门名private int d_pid;//部门上级idprivate String d_pName;//部门上级名称private String j_pName;//上级职位private String remark;//备注信息private List<Dept> jobDeptChildren=new ArrayList<>();private List<Job> jobChildren=new ArrayList<>();private List<User> userChildren=new ArrayList<>();private List<Job> children=new ArrayList<>();
user.java 根据自己的需求写吧,字段太多这里就不写了。
框架使用SSM,数据库MySQL。使用mybatis实现一对多。
companyMapper.java
List<Company> queryZtreeCompanyListByPid();
companyMapper.xml
<!-- 总公司 --><resultMap id="companyTop" type="com.ys.entity.Company"><result column="id" property="id" javaType="java.lang.Integer"/><result column="name" property="name" javaType="java.lang.String"/><result column="pid" property="pid" javaType="java.lang.Integer"/><result column="foundTime" property="foundTime" javaType="java.lang.String"/><!-- 总公司 - 部门 --><collection column="id" property="deptChildren" javaType="java.util.ArrayList" select="queryDeptByCompanyId"></collection><!-- 总公司 - 分公司 --><collection column="id" property="companyChildren" javaType="java.util.ArrayList" select="queryCompanyChildren"></collection></resultMap><!-- 总公司-部门 --><resultMap type="com.ys.entity.Dept" id="companyChildrenDept"><result column="id" property="id" javaType="java.lang.Integer"/><result column="name" property="name" javaType="java.lang.String"/><result column="id" property="id" javaType="java.lang.Integer"/><result column="company_id" property="company_id" javaType="java.lang.Integer"/><!--部门-子部门 --><collection column="{id=id,company_id=company_id}" property="deptChildren" javaType="java.util.ArrayList" select="queryDeptChildrenByDeptId"></collection><!--部门-职位 --><collection column="id" property="jobChildren" javaType="java.util.ArrayList" select="queryDeptChildrenJobByDeptId"></collection></resultMap><!-- 部门-职位 --><resultMap type="com.ys.entity.Job" id="deptChildrenJob"><result column="id" property="id" javaType="java.lang.Integer"/><result column="name" property="name" javaType="java.lang.String"/><result column="pid" property="pid" javaType="java.lang.Integer"/><result column="dept_id" property="dept_id" javaType="java.lang.Integer"/><!--职位 - 人员 --><collection column="id" property="userChildren" javaType="java.util.ArrayList" select="queryjobChildrenUserByJobId"></collection></resultMap><!--职位 - 人员 --><resultMap type="com.ys.entity.User" id="jobChildrenUser"><result column="id" property="id" javaType="java.lang.Integer"/><result column="name" property="name" javaType="java.lang.String"/><result column="userName" property="userName" javaType="java.lang.String"/><result column="jobNumber" property="jobNumber" javaType="java.lang.Integer"/><result column="touxiang" property="touxiang" javaType="java.lang.String"/></resultMap><!-- 总公司 --><select id="queryZtreeCompanyListByPid" resultMap="companyTop">select company_id as id , company_name as name , company_pid as pid ,foundTime from sys_company where company_pid=0</select><!-- 总公司 - 部门 --><select id="queryDeptByCompanyId" resultMap="companyChildrenDept">select dept_id as id,dept_name as name,dept_pid as pid ,company_id from sys_dept where dept_pid=0 and company_id=#{id}</select><!-- 部门-子部门 --><select id="queryDeptChildrenByDeptId" resultMap="companyChildrenDept">select dept_id as id,dept_name as name,dept_pid as pid ,company_id from sys_dept where dept_pid=#{id} and company_id=#{company_id}</select><!-- 部门-职位 --><select id="queryDeptChildrenJobByDeptId" resultMap="deptChildrenJob">select job_id as id ,job_name as name, job_pid as pid ,dept_id from sys_job where dept_id=#{id}</select><!--职位 - 人员 --><select id="queryjobChildrenUserByJobId" resultMap="jobChildrenUser">select user_id as id,name,userName,jobNumber,touxiang from sys_user where job_id=#{id}</select><!-- 分公司 --><resultMap id="companyChildren" type="com.ys.entity.Company"><result column="id" property="id" javaType="java.lang.Integer"/><result column="name" property="name" javaType="java.lang.String"/><result column="pid" property="pid" javaType="java.lang.Integer"/><result column="foundTime" property="foundTime" javaType="java.lang.String"/><!-- 分公司-部门 --><collection column="{id=id,pid=pid}" property="deptChildren" javaType="java.util.ArrayList" select="queryDeptByCompanyChildrenId"></collection></resultMap><!-- 分公司 --><select id="queryCompanyChildren" resultMap="companyChildren">select company_id as id , company_name as name , company_pid as pid ,foundTime from sys_company where company_pid=#{id} and company_pid!=0</select><!-- 分公司 - 部门 --><select id="queryDeptByCompanyChildrenId" resultMap="companyChildrenDept">select dept_id as id,dept_name as name,dept_pid as pid ,company_id from sys_dept where company_id=#{id} and dept_pid=(select dept_id from sys_dept where dept_pid=0 and company_id=#{pid})</select>
这里是一对多的查询,网上有很多类似的讲解很容易理解。
接着是companyService.java
public List<Company> queryZtreeCompanyListByPid(){return mapper.queryZtreeCompanyListByPid();}
companyController.java
@RequestMapping(value="queryCompanyOneToMany",method={RequestMethod.GET,RequestMethod.POST})@ResponseBodypublic List<Company> queryZtreeCompanyListByPid(){return service.queryZtreeCompanyListByPid();}
接下来是JSP,前端框架是layui 。引入zTree的JS/CSS、layui的JS/CSS。
<link type="text/css" rel="stylesheet" href="${ctxStatic}/zTree/css/metroStyle/metroStyle.css"/>
<!-- zTree的核心库 -->
<script type="text/javascript" src="${ctxStatic}/zTree/js/jquery.ztree.core.min.js"></script>
<!-- zTree的复选框 -->
<script type="text/javascript" src="${ctxStatic}/zTree/js/jquery.ztree.excheck.min.js"></script>
<script type="text/javascript" src="${ctxStatic}/zTree/js/jquery.ztree.exedit.min.js"></script>
<style type="text/css">
.layui-form-pane .layui-form-label{width:130px;
}.auItem{min-width:550px;
}
.approval{width:85px;
}
.approval p{width:100%;height:59px;cursor:pointer;overflow:hidden;text-align: center;
}
.approval p img{min-width:50px;min-height:50px;width:55px;height:55px;border: 2px solid #00c0ef;
}
.approval p:hover img:first-child{display:none;
}
.add img{min-width:50px;min-height:50px;width:55px;height:55px;cursor: pointer;
}
.approval span,.add span{display: block;text-align:center;font-size:14px;
}
</style>
<fieldset class="layui-elem-field"><legend>审批人</legend><div class="layui-field-box"><!-- 添加审批人 --><div class="layui-form-item auItem"><div class="layui-inline approvalUsers"></div><div class="layui-inline add"><img src="${ctxStatic}/images/addUser.png" class="layui-circle"><span>添加</span></div></div></div>
</fieldset>
然后是JS代码。
function openTree2(){var index2=layer.open({type: 1,title: "审批人",closeBtn: 2,shadeClose: false,area: ['300px','80%'],content: '<div class="zTreeDemoBackground left"><ul id="ztree2" class="ztree"> </ul></div>', btn: ['确定', '取消'],yes:function (index2,value) {getChildNodes2();layer.close(index2);},success:function(){
// layer.alert('',{skin: 'layui-layer-molv',icon:7,closeBtn: 1,anim:3,btn:['知道了','关闭']});if(window.sessionStorage.getItem("layFlag")=="false" || window.sessionStorage.getItem("layFlag")==undefined){var con= layer.confirm('多选审批人请务必顺序选择!', {btn: ['不再提示','关闭'] //按钮,icon:7,anim:3 }, function(){window.sessionStorage.setItem("layFlag","true");layer.close(con);}, function(){window.sessionStorage.setItem("layFlag","false");});}}});var zTreeObj;//树属性的定义 var setting = {//页面上的显示效果 view: { selectedMulti: false}, check : { enable: true,chkboxType: { "Y": "", "N": "" }},callback:{beforeCheck: zTreeBeforeCheck,//选中之前 判断onCheck: zTreeOnCheck,getChildNodes2:getChildNodes2}};var checkNode2;function zTreeBeforeCheck(treeId, treeNode) {if(treeNode.jobNumber==undefined || treeNode.jobNumber==null || treeNode.jobNumber==0){layer.msg('此节点不是用户节点,不可选中!',{icon:2,time:2000,shift:6});return false;}else{if(treeNode.id==$('#userId').val()){layer.msg('审批人不能选择自己!',{icon:2,time:2000,shift:6});return false;} }};function zTreeOnCheck(event, treeId, treeNode) {var treeObj = $.fn.zTree.getZTreeObj("ztree2");var nodes = treeObj.getCheckedNodes(true);checkNode2=nodes;};var zNodes;$.ajax({async:false,cache:false,type:'post',dataType:'json',url:getPath+'queryCompanyOneToMany',success:function(data){deleteEmptyProperty(data);zNodes=data;}});function deleteEmptyProperty(object){for (var i in object) {var value = object[i];if (typeof value === 'object') {if (Array.isArray(value)) {if (value.length == 0) {//alert(object[i]);delete object[i];continue;}else{ var a=[];if(i=='jobChildren'){for (var j = 0; j < object[i].length; j++) {a.push(object[i][j]);}delete object[i];}else if(i=='userChildren'){for (var j = 0; j < object[i].length; j++) {a.push(object[i][j]);}delete object[i]; }else if(i=='deptChildren'){for (var j = 0; j < object[i].length; j++) {a.push(object[i][j]);}delete object[i]; }else if(i=='companyChildren'){for (var j = 0; j < object[i].length; j++) {a.push(object[i][j]);}delete object[i]; }else if(i=='jobDeptChildren'){for (var j = 0; j < object[i].length; j++) {a.push(object[i][j]);}delete object[i];}if(a.length>0&&object["children"]!=undefined){for (var k = 0; k < object["children"].length; k++) {a.push(object["children"][k]);}object["children"]=a;}else if(a.length>0 && object["children"]==undefined){object["children"]=a;} }}deleteEmptyProperty(value);if (isEmpty(value)) {delete object[i];}} else {if (value === '' || value === null || value === undefined) {delete object[i];} else {}}}}function isEmpty(object) {for (var name in object) {return false;}return true;}$(function() { $.fn.zTree.init($("#ztree2"), setting, zNodes); var treeObj = $.fn.zTree.getZTreeObj("ztree2");treeObj.expandAll(true);});function getChildNodes2(){if(checkNode2.length>0){var html="";var length=$('.approvalUsers div').length+1;//console.log((length+checkNode.length));if((length+checkNode2.length)<12){for (var i = 0; i < checkNode2.length; i++) {var img=(checkNode2[i].touxiang=='' || checkNode2[i].touxiang==null || checkNode2[i].touxiang==undefined) ? getPath+"static/images/NoImg.png" : checkNode2[i].touxiang;if($('.approvalUsers div').length==0){html+='<div class="layui-inline approval" id="approval'+(length+i)+'">'+'<p>'+'<img src="'+img+'" class="layui-circle">'+'<img src="'+getPath+'static/images/removeUser.png" class="layui-circle">'+'</p>'+'<span>'+checkNode2[i].name+'</span>'+'<input type="hidden" name="approval_user_id'+(length+i)+'" value="'+checkNode2[i].id+'" lay-verify="required">'+'</div>';}else{var inputV=[];$('.approvalUsers div').each(function(){inputV.push(Number($(this).find('input').val()));});if(inputV.length>0 && $.inArray(checkNode2[i].id,inputV)!=-1){layer.msg('审批人已存在,不可添加',{icon:5,shift:6,time:1000},function(){html="";return false;});break;}else{html+='<div class="layui-inline approval" id="approval'+(length+i)+'">'+'<p>'+'<img src="'+img+'" class="layui-circle">'+'<img src="'+getPath+'static/images/removeUser.png" class="layui-circle">'+'</p>'+'<span>'+checkNode2[i].name+'</span>'+'<input type="hidden" name="approval_user_id'+(length+i)+'" value="'+checkNode2[i].id+'" lay-verify="required">'+'</div>';}}}if(html!=""){$('.approvalUsers').append(html); }if($('.approvalUsers div').length==10){$('.add').hide();}}else{layer.msg('人数溢出,最多可添加'+(11-length)+'人!',{icon:5,shift:6,time:2000});}}};
};$('.add').click(function(){openTree2();
})
$(document).on('click','.approval p img',function(){removeApprovalUser($(this));
});
function removeApprovalUser(_this){var div=_this.parent().parent();var length=div.parent().find('div').length+1;div.remove(); var name=div.find('input').attr('name');var index=Number(name.substring(name.length-1,name.length));for(var i=index+1,j=length;i<j;i++){var img=$("#approval"+i+"").find('p img:eq(0)').attr('src');var thisName=$("#approval"+i+"").find('span').text();var inputVal=$("#approval"+i+"").find('input').val();$("#approval"+i+"").replaceWith('<div class="layui-inline approval" id="approval'+(i-1)+'">'+'<p>'+'<img src="'+img+'" class="layui-circle">'+'<img src="'+getPath+'static/images/removeUser.png" class="layui-circle">'+'</p>'+'<span>'+thisName+'</span>' +'<input type="hidden" name="approval_user_id'+(i-1)+'" value="'+inputVal+'" lay-verify="required">'+'</div>');}if(length<12){$('.add').show();}
};
这里审批人可以多选,最终以顺序显示,最多为十个人,可以根据实际情况更改代码。
其中 deleteEmptyProperty(object) 函数用于处理后台返回的集合数据,这个数据是不能直接显示为树结构的,需要对其结构处理。更改为zTree可以实现分级的结构 ,这里以children分级实现,并对集合数据做去空处理,最终显示为树结构,然后做勾选判断。
最终效果