| | |
| | | package com.vci.frameworkcore.compatibility.impl; |
| | | |
| | | import com.vci.dto.OrgDepartmentDTO; |
| | | import com.vci.corba.common.PLException; |
| | | import com.vci.corba.common.data.UserEntityInfo; |
| | | import com.vci.corba.framework.data.DeptInfo; |
| | | import com.vci.corba.omd.data.BusinessObject; |
| | | import com.vci.frameworkcore.compatibility.OrgDeptQueryServiceI; |
| | | import com.vci.frameworkcore.lcstatuspck.FrameworkDataLCStatus; |
| | | import com.vci.frameworkcore.model.OrgDeptForPlatform1; |
| | | import com.vci.frameworkcore.model.SmRoleForPlatform1; |
| | | import com.vci.frameworkcore.pagemodel.OrgDepartmentVO; |
| | | import com.vci.frameworkcore.pagemodel.SmRoleVO; |
| | | import com.vci.model.OrgDeptForPlatform1; |
| | | import com.vci.po.OrgDeptPO; |
| | | import com.vci.pagemodel.OrgDepartmentVO; |
| | | import com.vci.omd.utils.ObjectTool; |
| | | import com.vci.starter.poi.bo.ReadExcelOption; |
| | | import com.vci.starter.poi.bo.WriteExcelData; |
| | | import com.vci.starter.poi.bo.WriteExcelOption; |
| | | import com.vci.starter.poi.constant.ExcelLangCodeConstant; |
| | | import com.vci.starter.poi.util.ExcelUtil; |
| | | import com.vci.starter.revision.bo.TreeWrapperOptions; |
| | | import com.vci.starter.revision.service.RevisionModelUtil; |
| | | import com.vci.starter.web.constant.QueryOptionConstant; |
| | | import com.vci.starter.web.exception.VciBaseException; |
| | | import com.vci.starter.web.pagemodel.DataGrid; |
| | | import com.vci.starter.web.pagemodel.PageHelper; |
| | | import com.vci.starter.web.pagemodel.Tree; |
| | | import com.vci.starter.web.pagemodel.TreeQueryObject; |
| | | import com.vci.starter.web.util.BeanUtil; |
| | | import com.vci.starter.web.util.VciBaseUtil; |
| | | import com.vci.starter.web.pagemodel.*; |
| | | import com.vci.starter.web.util.*; |
| | | import com.vci.starter.web.wrapper.VciQueryWrapperForDO; |
| | | import com.vci.web.service.WebBoServiceI; |
| | | import com.vci.web.util.Func; |
| | | import com.vci.web.util.PlatformClientUtil; |
| | | import com.vci.web.util.WebUtil; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.poi.hssf.util.HSSFColor; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.io.File; |
| | | import java.util.*; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | private WebBoServiceI boService; |
| | | |
| | | /** |
| | | * 平台调用客户端 |
| | | */ |
| | | @Autowired |
| | | private PlatformClientUtil platformClientUtil; |
| | | |
| | | /** |
| | | * 对象操作工具类 |
| | | */ |
| | | @Autowired |
| | | private RevisionModelUtil revisionModelUtil; |
| | | |
| | | /** |
| | | * 必填列 |
| | | */ |
| | | private ArrayList<Integer> ColumnNameisRed = new ArrayList<Integer>(); |
| | | |
| | | /** |
| | | * 日志 |
| | | */ |
| | | private Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | /** |
| | | * 根据部门主键获取部门的信息 |
| | |
| | | * @throws VciBaseException 参数为空或者数据库存在问题的时候会抛出异常 |
| | | */ |
| | | @Override |
| | | public OrgDepartmentVO getDeptByDeptOid(String deptOid) |
| | | throws VciBaseException { |
| | | public OrgDepartmentVO getDeptByDeptOid(String deptOid) throws VciBaseException { |
| | | if(StringUtils.isBlank(deptOid)){ |
| | | return null; |
| | | } |
| | | OrgDeptForPlatform1 deptForPlatform1 = boService.selectByOid(deptOid, OrgDeptForPlatform1.class); |
| | | return deptDO2VO(deptForPlatform1); |
| | | Map<String, String> conditionMap = new HashMap<>(); |
| | | conditionMap.put("pluid",deptOid); |
| | | VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(conditionMap, OrgDeptForPlatform1.class); |
| | | List<OrgDeptForPlatform1> deptForPlatform1s = boService.selectByQueryWrapper(queryWrapper, OrgDeptForPlatform1.class); |
| | | if(Func.isEmpty(deptForPlatform1s)){ |
| | | return null; |
| | | } |
| | | return deptDO2VO(deptForPlatform1s.get(0)); |
| | | } |
| | | |
| | | /** |
| | | * 根据父部门主键获取部门名称部门的信息 |
| | | * @param parentDeptOid 父部门主键 |
| | | * @param conditionMap 部门名称 |
| | | * @return 部门的显示对象,如果部门不存在则返回null,不会抛出异常 |
| | | * @throws VciBaseException 参数为空或者数据库存在问题的时候会抛出异常 |
| | | */ |
| | | @Override |
| | | public List<OrgDepartmentVO> getDeptByDeptpOidAndCondition(String parentDeptOid,Map<String,String> conditionMap) throws VciBaseException { |
| | | if(Func.isEmpty(conditionMap)){ |
| | | conditionMap = new HashMap(); |
| | | } |
| | | VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(conditionMap,OrgDeptForPlatform1.class); |
| | | //父主键为空查顶层 |
| | | if(Func.isBlank(parentDeptOid)){ |
| | | queryWrapper.isNull("plparentuid"); |
| | | }else{ |
| | | queryWrapper.eq("plparentuid",parentDeptOid); |
| | | } |
| | | List<OrgDeptForPlatform1> roleForPlatform1s = boService.selectByQueryWrapper(queryWrapper, OrgDeptForPlatform1.class); |
| | | if(Func.isEmpty(roleForPlatform1s)){ |
| | | return null; |
| | | } |
| | | return deptDO2VOs(roleForPlatform1s); |
| | | } |
| | | |
| | | /** |
| | | * 根据父部门名称路径获取和部门名称部门的信息(主要用于导入时根据部门命令全路径和名称或编号查重) |
| | | * @return 部门的显示对象,如果部门不存在则返回null,不会抛出异常 |
| | | * @throws VciBaseException 参数为空或者数据库存在问题的时候会抛出异常 |
| | | */ |
| | | @Override |
| | | public List<OrgDepartmentVO> getDeptAllFullName() throws VciBaseException { |
| | | //查询部门信息,主要查询部门名称组成全路径 |
| | | String sql = "SELECT PLUID, PLNAME, PLNUM, PLSTATUS, level, substr(sys_connect_by_path(PLNAME, '/'), 2) AS FULL_NAME_PATH " + |
| | | "FROM PLDEPT " + |
| | | "START WITH PLPARENTUID IS NULL " + |
| | | "CONNECT BY PRIOR PLUID = PLPARENTUID"; |
| | | List<BusinessObject> cbos = boService.queryByOnlySql(sql); |
| | | List<OrgDepartmentVO> departmentVOList = new ArrayList<>(); |
| | | if(!CollectionUtils.isEmpty(cbos)){ |
| | | cbos.stream().forEach(cbo->{ |
| | | //部门主键 |
| | | String deptOid = ObjectTool.getNewBOAttributeValue(cbo,"PLUID"); |
| | | //部门名称 |
| | | String deptName = ObjectTool.getNewBOAttributeValue(cbo, "PLNAME"); |
| | | //部门编号 |
| | | String deptNum = ObjectTool.getNewBOAttributeValue(cbo, "PLNUM"); |
| | | //部门层级 |
| | | String deptLevel = ObjectTool.getNewBOAttributeValue(cbo, "level"); |
| | | //部门名称全路径 |
| | | String fullDeptNamePath = ObjectTool.getNewBOAttributeValue(cbo, "FULL_NAME_PATH"); |
| | | //部门状态 |
| | | String deptStatus = ObjectTool.getNewBOAttributeValue(cbo, "PLSTATUS"); |
| | | OrgDepartmentVO orgDepartmentVO = new OrgDepartmentVO(deptNum,deptName,Short.valueOf(deptStatus),fullDeptNamePath,Integer.valueOf(deptLevel)); |
| | | orgDepartmentVO.setOid(deptOid); |
| | | departmentVOList.add(orgDepartmentVO); |
| | | }); |
| | | } |
| | | return departmentVOList; |
| | | } |
| | | |
| | | /** |
| | |
| | | OrgDepartmentVO departmentVO = new OrgDepartmentVO(); |
| | | if(deptForPlatform1!=null){ |
| | | departmentVO.setOid(deptForPlatform1.getPluid()); |
| | | // 除部门主键外的唯一标识,长度为Dept:+8位可通过该参数反推回部门主键的hash编码 |
| | | //departmentVO.setUniqueId("Dept:"+Func.oidEnHash(deptForPlatform1.getPluid())); |
| | | departmentVO.setId(deptForPlatform1.getPlnum()); |
| | | departmentVO.setName(deptForPlatform1.getPlname()); |
| | | departmentVO.setStatus(deptForPlatform1.getPlstatus()); |
| | | if(0 == deptForPlatform1.getPlstatus()){ |
| | | departmentVO.setLcStatus(FrameworkDataLCStatus.ENABLED.getValue()); |
| | | departmentVO.setStatusText(FrameworkDataLCStatus.ENABLED.getValue()); |
| | | }else{ |
| | | departmentVO.setLcStatus(FrameworkDataLCStatus.DISABLED.getValue()); |
| | | departmentVO.setStatusText(FrameworkDataLCStatus.DISABLED.getValue()); |
| | | } |
| | | departmentVO.setSpecialties(deptForPlatform1.getPlspecialties()); |
| | | departmentVO.setCode(deptForPlatform1.getPlcode()); |
| | | departmentVO.setPkFatherDepartment(deptForPlatform1.getPlparentuid()); |
| | | departmentVO.setDescription(deptForPlatform1.getPldesc()); |
| | | departmentVO.setCheckInTime(deptForPlatform1.getPlcreatetime()); |
| | | departmentVO.setCreateTime(new Date(deptForPlatform1.getPlcreatetime())); |
| | | departmentVO.setCreator(deptForPlatform1.getPlcreateuser()); |
| | | departmentVO.setLastModifyTime(deptForPlatform1.getPlupdatetime()); |
| | | departmentVO.setLastModifyTime(new Date(deptForPlatform1.getPlupdatetime())); |
| | | departmentVO.setLastModifier(deptForPlatform1.getPlupdateuser()); |
| | | } |
| | | return departmentVO; |
| | | } |
| | | |
| | | /** |
| | | * 批量获取部门的信息 (根据部门主键) |
| | | * @param deptOidCollections 部门主键的集合,可以超过1000个 |
| | |
| | | depts.addAll(roleForPlatform1s); |
| | | } |
| | | }); |
| | | return deptDO2VOs(depts); |
| | | return deptDO2VOs(depts); |
| | | } |
| | | |
| | | /** |
| | | * 获取部门的列表,默认会以部门名称升序排列,部门的编辑页面列表不要使用这个接口 |
| | | * @param queryMap 查询条件 |
| | |
| | | if(pageHelper == null){ |
| | | pageHelper = new PageHelper(-1); |
| | | } |
| | | //根据部门编号排序 |
| | | pageHelper.addDefaultAsc("plnum"); |
| | | VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(queryMap,OrgDeptForPlatform1.class,pageHelper); |
| | | List<OrgDeptForPlatform1> deptForPlatform1s = boService.selectByQueryWrapper(queryWrapper, OrgDeptForPlatform1.class); |
| | |
| | | } |
| | | return dataGrid; |
| | | } |
| | | |
| | | /** |
| | | * 根据部门主键获取部门的姓名 |
| | | * @param deptOid 部门主键 |
| | |
| | | if(queryMap == null){ |
| | | queryMap = new HashMap<>(); |
| | | } |
| | | List<OrgDeptForPlatform1> roles = new ArrayList<>(); |
| | | List<OrgDeptForPlatform1> deptForPlatform1s = new ArrayList<>(); |
| | | if(userOid.contains(",")){ |
| | | Map<String, String> finalQueryMap = queryMap; |
| | | WebUtil.switchCollectionForOracleIn(WebUtil.str2List(userOid)).stream().forEach(userOids->{ |
| | |
| | | VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(conditionMap,OrgDeptForPlatform1.class); |
| | | List<OrgDeptForPlatform1> roleForPlatform1s = boService.selectByQueryWrapper(queryWrapper, OrgDeptForPlatform1.class); |
| | | if(!CollectionUtils.isEmpty(roleForPlatform1s)){ |
| | | roles.addAll(roleForPlatform1s); |
| | | deptForPlatform1s.addAll(roleForPlatform1s); |
| | | } |
| | | }); |
| | | }else { |
| | |
| | | VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(queryMap,OrgDeptForPlatform1.class); |
| | | List<OrgDeptForPlatform1> roleForPlatform1s = boService.selectByQueryWrapper(queryWrapper, OrgDeptForPlatform1.class); |
| | | if(!CollectionUtils.isEmpty(roleForPlatform1s)){ |
| | | roles.addAll(roleForPlatform1s); |
| | | deptForPlatform1s.addAll(roleForPlatform1s); |
| | | } |
| | | return deptDO2VOs(roles); |
| | | return deptDO2VOs(deptForPlatform1s); |
| | | } |
| | | /** |
| | | |
| | | /** |
| | | * 根据用户主键获取关联的部门 |
| | | * @param userOid 用户主键 |
| | | * @param queryMap 查询条件,如果需要使用用户的属性来查询可以使用pkUser.xxxx |
| | | * @return 部门的显示对象 |
| | | */ |
| | | @Override |
| | | public OrgDepartmentVO listDeptByUserOid(String userOid, |
| | | public List<OrgDepartmentVO> listDeptByUserOid(String userOid, |
| | | Map<String, String> queryMap) { |
| | | List<OrgDepartmentVO> departmentVOS = listDeptByUserOid(userOid, queryMap, false); |
| | | if(CollectionUtils.isEmpty(departmentVOS)){ |
| | | return null; |
| | | return new ArrayList<>(); |
| | | } |
| | | return departmentVOS.get(0); |
| | | return departmentVOS; |
| | | } |
| | | |
| | | /** |
| | | * 获取未关联某个用户的部门 |
| | | * @param userOid 用户主键 |
| | |
| | | * 批量根据用户的主键来获取部门 |
| | | * @param userOidCollection 用户主键集合 |
| | | * @param queryMap 查询条件,如果需要使用用户的属性来查询可以使用pkUser.xxxx |
| | | * @return 部门的显示对象,key是用户主键,value是这个用户关联的部门 |
| | | * @return 部门的显示对象,key是用户主键,value是关联的部门 |
| | | */ |
| | | @Override |
| | | public Map<String, List<OrgDepartmentVO>> batchListDeptByUserOids( |
| | |
| | | if(!CollectionUtils.isEmpty(deptVOs)){ |
| | | deptVOList.addAll(deptVOs); |
| | | String sql = "select pluseruid,pldeptuid from pluserdept where pluseruid in (" + WebUtil.toInSql(userOids.toArray(new String[0])) + ")"; |
| | | List<com.vci.client.bof.ClientBusinessObject> cbos = boService.queryBySql(sql, null); |
| | | List<BusinessObject> cbos = boService.queryBySql(sql, null); |
| | | if(!CollectionUtils.isEmpty(cbos)){ |
| | | cbos.stream().forEach(cbo->{ |
| | | String userOid = cbo.getAttributeValue("pluseruid"); |
| | | String userOid = ObjectTool.getNewBOAttributeValue(cbo,"pluseruid"); |
| | | List<String> deptOids = userDeptOidMap.getOrDefault(userOid,new ArrayList<>()); |
| | | deptOids.add(cbo.getAttributeValue("pldeptuid")); |
| | | deptOids.add(ObjectTool.getNewBOAttributeValue(cbo,"pldeptuid")); |
| | | userDeptOidMap.put(userOid,deptOids); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | if(!CollectionUtils.isEmpty(deptVOList)){ |
| | | Map<String, OrgDepartmentVO> deptVOMap = deptVOList.stream().collect(Collectors.toMap(s -> s.getOid(), t -> t)); |
| | | //这儿应该对deptVOList做一次去重处理,因为肯定会有重复的部门被查出来 |
| | | Map<String, OrgDepartmentVO> deptVOMap = deptVOList.stream() |
| | | .collect(Collectors.toMap(OrgDepartmentVO::getOid, Function.identity(), (existing, replacement) -> existing)); |
| | | Map<String, List<OrgDepartmentVO>> userDeptVOMap = new HashMap<>(); |
| | | userDeptOidMap.forEach((userOid,deptOids)->{ |
| | | List<OrgDepartmentVO> deptVOS = new ArrayList<>(); |
| | |
| | | } |
| | | return new HashMap<>(); |
| | | } |
| | | /** |
| | | |
| | | /** |
| | | * 批量根据用户的主键来获取部门名称(/间隔方式) |
| | | * @param userOidCollection 用户主键集合 |
| | | * @param queryMap 查询条件,如果需要使用用户的属性来查询可以使用pkUser.xxxx |
| | | * @return 部门的显示对象,key是用户主键,value是关联的部门(包含父节点如当前部门为人力资源部则值为:550/人力资源部) |
| | | */ |
| | | @Override |
| | | public Map<String,Map<String,String>> batchMapDeptNameByUserOids(Collection<String> userOidCollection, Map<String, String> queryMap) { |
| | | if(CollectionUtils.isEmpty(userOidCollection)){ |
| | | return new HashMap<>(); |
| | | } |
| | | Map<String,Map<String,String>> deptOidNameMap = new HashMap<>(); |
| | | Map<String,Map<String,String>> userDeptOidMap = new HashMap<>(); |
| | | WebUtil.switchCollectionForOracleIn(userOidCollection).stream().forEach(userOids->{ |
| | | //1、要先根据用户主键获取到关联的部门主键 |
| | | String sql = "select pluseruid,pldeptuid from pluserdept where pluseruid in (" + WebUtil.toInSql(userOids.toArray(new String[0])) + ")"; |
| | | List<BusinessObject> cbos = boService.queryBySql(sql, null); |
| | | if(!CollectionUtils.isEmpty(cbos)){ |
| | | cbos.stream().forEach(cbo->{ |
| | | //角色主键 |
| | | String userOid = ObjectTool.getNewBOAttributeValue(cbo,"pluseruid"); |
| | | //部门主键 |
| | | String deptUid = ObjectTool.getNewBOAttributeValue(cbo, "pldeptuid"); |
| | | //2、然后根据部门主键获取到由部门名称/组成的值 |
| | | //避免多次查询,或者循环查询 |
| | | if(deptOidNameMap.containsKey(deptUid)){ |
| | | userDeptOidMap.put(userOid,deptOidNameMap.get(deptUid)); |
| | | }else { |
| | | if(Func.isNotEmpty(deptUid)){ |
| | | //2.1、查询部门oid,当前部门包含父部门 |
| | | String queryDeptSql = "select pluid,plname from pldept START with pluid = '" + |
| | | deptUid + "' connect by prior plparentuid = pluid"; |
| | | List<BusinessObject> cboDepts = boService.queryBySql(queryDeptSql, null); |
| | | if(!CollectionUtils.isEmpty(cboDepts)){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (int i = cboDepts.size()-1; i >=0; i--) { |
| | | String deptName = ObjectTool.getNewBOAttributeValue(cboDepts.get(i),"plname"); |
| | | sb.append(deptName); |
| | | sb.append("/"); |
| | | } |
| | | //2.2、避免同一部门多次查询,这里存储在一个公共集合中,便于重复使用 |
| | | //删除最后一个斜杠 |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | Map<String,String> tempMap = new HashMap<>(); |
| | | tempMap.put(deptUid,sb.toString()); |
| | | deptOidNameMap.put(deptUid,tempMap); |
| | | userDeptOidMap.put(userOid,tempMap); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | return userDeptOidMap; |
| | | } |
| | | |
| | | /** |
| | | * 获取某个部门的直属下级部门 |
| | | * @param pkFatherDepartmment 部门的主键 |
| | | * @param queryMap 查询条件 |
| | |
| | | List<OrgDeptForPlatform1> depts = boService.selectByQueryWrapper(queryWrapperForDO, OrgDeptForPlatform1.class); |
| | | return deptDO2VOs(depts); |
| | | } |
| | | |
| | | /** |
| | | * 获取某个部门的所有层级的下级部门 |
| | | * @param pkFatherDepartmment 部门的主键 |
| | |
| | | queryWrapperForDO.in("pluid","select pluid from pldept start with " + (StringUtils.isBlank(pkFatherDepartmment)?" (plparentuid is null or plparentuid = '') ":"plparentuid = '" + pkFatherDepartmment.trim() + "'") + "connect by PRIOR pluid=plparentuid"); |
| | | return deptDO2VOs(boService.selectByQueryWrapper(queryWrapperForDO, OrgDeptForPlatform1.class)); |
| | | } |
| | | |
| | | /** |
| | | * 参照树形数据的部门信息 |
| | | * @param treeQueryObject 树形查询的条件 |
| | |
| | | public List<Tree> refTreeDept(TreeQueryObject treeQueryObject) { |
| | | String pkFatherDepartmment=treeQueryObject.getParentOid(); |
| | | Map<String, String> conditionMap = treeQueryObject.getConditionMap(); |
| | | Map<String, String> extandParamsMap = treeQueryObject.getExtandParamsMap(); |
| | | if(conditionMap==null){ |
| | | conditionMap=new HashMap<String, String>(); |
| | | } |
| | |
| | | VciQueryWrapperForDO queryWrapperForDO = new VciQueryWrapperForDO(conditionMap,OrgDeptForPlatform1.class); |
| | | orgDepartmentVOList = deptDO2VOs(boService.selectByQueryWrapper(queryWrapperForDO,OrgDeptForPlatform1.class)); |
| | | } |
| | | TreeWrapperOptions treeWrapperOptions = new TreeWrapperOptions("pkFatherDepartment"); |
| | | TreeWrapperOptions treeWrapperOptions = new TreeWrapperOptions(); |
| | | BeanUtil.convert(treeQueryObject,treeWrapperOptions); |
| | | return revisionModelUtil.doList2Trees(orgDepartmentVOList,treeWrapperOptions,dept->{ |
| | | return dept.getId() + " " + dept.getName() + (FrameworkDataLCStatus.DISABLED.getValue().equals(dept.getLcStatus())?"【停用】":""); |
| | | treeWrapperOptions.setParentFieldName("pkFatherDepartment"); |
| | | List<Tree> trees = revisionModelUtil.doList2Trees(orgDepartmentVOList, treeWrapperOptions, dept -> { |
| | | return dept.getId() + " " + dept.getName() + (FrameworkDataLCStatus.DISABLED.getValue().equals(dept.getLcStatus()) ? "【停用】" : ""); |
| | | }); |
| | | //extandParamsMap中添加"showAllDepartmentNode"为"true"时,并且parentOid为空,返回结果中会包含“所有部门”这个节点 |
| | | if(Func.isBlank(pkFatherDepartmment) && (Func.isNotEmpty(extandParamsMap) && Boolean.parseBoolean(extandParamsMap.getOrDefault("showAllDepartmentNode","false")))){ |
| | | List<Tree> treeList = new ArrayList<>(); |
| | | Tree tree = new Tree(); |
| | | tree.setLeaf(false); |
| | | tree.setParentId(null); |
| | | //没有实际作用只是界面上渲染使用 |
| | | tree.setOid(UUID.randomUUID().toString()); |
| | | tree.setParentName(null); |
| | | Map<String, String> map = new HashMap<>(); |
| | | map.put("name","所有部门"); |
| | | map.put("ALLDept","ALLDept"); |
| | | tree.setAttributes(map); |
| | | tree.setChildren(trees); |
| | | treeList.add(tree); |
| | | return treeList; |
| | | } |
| | | return trees; |
| | | } |
| | | |
| | | /** |
| | | * 参照树形表格的部门信息,上级部门的是表格中的树形列 |
| | | * @param treeQueryObject 树形查询的条件 |
| | |
| | | return dataGrid; |
| | | } |
| | | |
| | | /** |
| | | * 保存部门用户关联信息,带查重功能 |
| | | * @param userOIds 用户id |
| | | * @param deptId 部门id |
| | | * @return |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public boolean saveUsersDept(String[] userOIds, String deptId) throws PLException { |
| | | //先进性查重处理 |
| | | List<String> repeatUserOidList = new ArrayList<>(); |
| | | //循环进行查重,避免in大于1000 |
| | | WebUtil.switchCollectionForOracleIn(Arrays.asList(userOIds)).stream().forEach(userOId->{ |
| | | String sql = "select pluseruid,pldeptuid from pluserdept where pldeptuid = '" + deptId |
| | | + "' and " + "pluseruid in ("+WebUtil.toInSql(userOId.toArray(new String[0]))+")"; |
| | | List<BusinessObject> cbos = boService.queryBySql(sql, null); |
| | | if(!CollectionUtils.isEmpty(cbos)){ |
| | | cbos.stream().forEach(cbo->{ |
| | | repeatUserOidList.add(ObjectTool.getNewBOAttributeValue(cbo,"pluseruid")); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | //从即将要执行保存的用户oid中移除当前用户已经存在关联关系的oid |
| | | //移除重复的 |
| | | List<String> tempList = new ArrayList<>(Arrays.asList(userOIds)); |
| | | tempList.removeAll(repeatUserOidList); |
| | | userOIds = tempList.toArray(new String[tempList.size()]); |
| | | if(Func.isNotEmpty(userOIds)){ |
| | | platformClientUtil.getFrameworkService().saveUserDept(userOIds, deptId,new UserEntityInfo(WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId(),null)); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 增加部门信息 |
| | | * @param orgDepartmentDTO |
| | | * @return |
| | | */ |
| | | @Override |
| | | public boolean addDept(OrgDepartmentDTO orgDepartmentDTO) throws PLException { |
| | | //判空 |
| | | VciBaseUtil.alertNotNull( |
| | | orgDepartmentDTO,"添加的部门对象", |
| | | orgDepartmentDTO.getName(),"部门名"); |
| | | //部门名和编号判重 |
| | | Map<String, String> conditionMap = new HashMap<>(); |
| | | conditionMap.put("plname",QueryOptionConstant.OR + orgDepartmentDTO.getName()); |
| | | if(Func.isNotBlank(orgDepartmentDTO.getId())){ |
| | | conditionMap.put("plnum",QueryOptionConstant.OR + orgDepartmentDTO.getId()); |
| | | } |
| | | List<OrgDepartmentVO> departmentVOS = getDeptByDeptpOidAndCondition(orgDepartmentDTO.getPkFatherDepartment(), conditionMap); |
| | | if(Func.isNotEmpty(departmentVOS)){ |
| | | throw new VciBaseException("同一父节点下该部门名称或编号已经存在,请修改!"); |
| | | } |
| | | SessionInfo loginUser = WebThreadLocalUtil.getCurrentUserSessionInfoInThread(); |
| | | String userId = loginUser.getUserId(); |
| | | |
| | | //生成存储的corba对象 |
| | | orgDepartmentDTO.setCreateTime(new Date()); |
| | | orgDepartmentDTO.setCreator(userId); |
| | | orgDepartmentDTO.setLastModifier(userId); |
| | | orgDepartmentDTO.setStatus((short) 0); |
| | | DeptInfo deptInfo = changeOrgDeptDTOToDeptInfo(orgDepartmentDTO); |
| | | UserEntityInfo userEntityInfo = new UserEntityInfo(userId, ""); |
| | | String oid = platformClientUtil.getFrameworkService().saveDepartment(deptInfo, userEntityInfo); |
| | | if (Func.isEmpty(oid)) { |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 修改部门信息 |
| | | * @param orgDepartmentDTO |
| | | * @return |
| | | */ |
| | | @Override |
| | | public boolean updateDept(OrgDepartmentDTO orgDepartmentDTO) throws PLException { |
| | | //判空 |
| | | VciBaseUtil.alertNotNull( |
| | | orgDepartmentDTO,"修改的部门对象", |
| | | orgDepartmentDTO.getOid(),"用户主键", |
| | | orgDepartmentDTO.getId(),"用户名" |
| | | ); |
| | | //按oid查询数据库中已存在的,确保修改的部门存在 |
| | | OrgDepartmentVO dbDepartmentVO = getDeptByDeptOid(orgDepartmentDTO.getOid()); |
| | | if(Func.isEmpty(dbDepartmentVO)){ |
| | | throw new VciBaseException("修改的部门不存在!"); |
| | | } |
| | | //部门名和编号判重,避免新家部门重复 |
| | | Map<String, String> conditionMap = new HashMap<>(); |
| | | conditionMap.put("plname",QueryOptionConstant.OR + orgDepartmentDTO.getName()); |
| | | if(Func.isNotBlank(orgDepartmentDTO.getId())){ |
| | | conditionMap.put("plnum",QueryOptionConstant.OR + orgDepartmentDTO.getId()); |
| | | } |
| | | List<OrgDepartmentVO> repeatDepartmentVOS = getDeptByDeptpOidAndCondition(orgDepartmentDTO.getPkFatherDepartment(), conditionMap); |
| | | repeatDepartmentVOS = repeatDepartmentVOS.stream().filter(item -> { |
| | | if((item.getName().equals(orgDepartmentDTO.getName()) || item.getId().equals(orgDepartmentDTO.getId())) && |
| | | !item.getOid().equals(orgDepartmentDTO.getOid())){ |
| | | return true; |
| | | } |
| | | return false; |
| | | }).collect(Collectors.toList()); |
| | | if(Func.isNotEmpty(repeatDepartmentVOS) ){ |
| | | throw new VciBaseException("同一父节点下该部门名称或编号已经存在,请修改!"); |
| | | } |
| | | OrgDepartmentDTO departmentDTO = new OrgDepartmentDTO(); |
| | | BeanUtil.convert(dbDepartmentVO,departmentDTO); |
| | | departmentDTO.setCode(orgDepartmentDTO.getCode()); |
| | | departmentDTO.setId(orgDepartmentDTO.getId()); |
| | | departmentDTO.setSpecialties(orgDepartmentDTO.getSpecialties()); |
| | | departmentDTO.setDescription(orgDepartmentDTO.getDescription()); |
| | | departmentDTO.setName(orgDepartmentDTO.getName()); |
| | | String loginUserId = WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId(); |
| | | orgDepartmentDTO.setLastModifier(loginUserId); |
| | | DeptInfo deptInfo = changeOrgDeptDTOToDeptInfo(departmentDTO); |
| | | boolean updateBoolean = platformClientUtil.getFrameworkService().updateDepartment(deptInfo, new UserEntityInfo(loginUserId, null)); |
| | | return updateBoolean; |
| | | } |
| | | |
| | | /** |
| | | * Dto对象转corb对象 |
| | | * @param orgDepartmentDTO |
| | | * @return |
| | | */ |
| | | public DeptInfo changeOrgDeptDTOToDeptInfo(OrgDepartmentDTO orgDepartmentDTO) { |
| | | DeptInfo departmentInfo = new DeptInfo(); |
| | | departmentInfo.id = orgDepartmentDTO.getOid() == null ? "" : orgDepartmentDTO.getOid(); |
| | | departmentInfo.name = orgDepartmentDTO.getName() == null ? "" : orgDepartmentDTO.getName(); |
| | | departmentInfo.num = orgDepartmentDTO.getId() == null ? "" : orgDepartmentDTO.getId(); |
| | | departmentInfo.code = orgDepartmentDTO.getCode() == null ? "" : orgDepartmentDTO.getCode(); |
| | | departmentInfo.specialties = orgDepartmentDTO.getSpecialties() == null ? "" : orgDepartmentDTO.getSpecialties(); |
| | | departmentInfo.status = orgDepartmentDTO.getStatus() == 0 ? 0 : orgDepartmentDTO.getStatus(); |
| | | departmentInfo.description = orgDepartmentDTO.getDescription() == null ? "" : orgDepartmentDTO.getDescription(); |
| | | departmentInfo.parentId = orgDepartmentDTO.getPkFatherDepartment() == null ? "" : orgDepartmentDTO.getPkFatherDepartment(); |
| | | departmentInfo.createUser = orgDepartmentDTO.getCreator() == null ? "" : orgDepartmentDTO.getCreator(); |
| | | departmentInfo.createTime = orgDepartmentDTO.getCreateTime().getTime(); |
| | | departmentInfo.updateTime = System.currentTimeMillis(); |
| | | departmentInfo.updateUser = orgDepartmentDTO.getLastModifier() == null ? "" : orgDepartmentDTO.getLastModifier(); |
| | | //departmentInfo.grantor = orgDepartmentDTO.getGrantor() == null ? "" : orgDepartmentDTO.getGrantor(); |
| | | return departmentInfo; |
| | | } |
| | | |
| | | /** |
| | | * 删除部门 |
| | | * @param ids |
| | | * @return |
| | | */ |
| | | @Override |
| | | public boolean deleteDept(String[] ids) throws PLException { |
| | | VciBaseUtil.alertNotNull(ids,"要删除的部门主键"); |
| | | //TODO:考虑是否需要添加删除前判断部门下是否配置有用户,这种情况应该不允许删除 |
| | | //TODO: 应该是不具备连带删除的功能,部门删除后用户关联的无用部门还在,考虑后期是否需要做,数据量不大可以不做连带删除 |
| | | return platformClientUtil.getFrameworkService().deleteDepartment( |
| | | ids, |
| | | new UserEntityInfo(WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId(), null) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 下载导入部门的excel模板。 |
| | | * @param downloadFileName |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String downloadImportTemplate(String downloadFileName) { |
| | | //界面没传名称,使用默认名称 |
| | | downloadFileName = Func.isBlank(downloadFileName) ? "部门导入模板_" + Func.format(new Date(),"yyyy-MM-dd HHmmss.sss"):downloadFileName; |
| | | // 设置表单列名 |
| | | List<String> columns = new ArrayList<>(Arrays.asList("名称", "编号", "代号", "专业", "父部门名称全路径(/间隔)", "描述")); |
| | | //设置必填列 |
| | | ColumnNameisRed.clear(); |
| | | ColumnNameisRed.add(0); |
| | | ColumnNameisRed.add(1); |
| | | //写excel |
| | | String excelPath = LocalFileUtil.getDefaultTempFolder() + File.separator + downloadFileName + ".xls"; |
| | | try { |
| | | new File(excelPath).createNewFile(); |
| | | } catch (Throwable e) { |
| | | throw new VciBaseException(LangBaseUtil.getErrorMsg(e), new String[]{excelPath}, e); |
| | | } |
| | | //设置列 |
| | | List<WriteExcelData> excelDataList = new ArrayList<>(); |
| | | for (int index = 0; index < columns.size(); index++) { |
| | | //判断是否为必填列,给必填列设置颜色 |
| | | if(ColumnNameisRed.contains(index)){ |
| | | WriteExcelData excelData = new WriteExcelData(0, index, columns.get(index)); |
| | | excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex())); |
| | | excelDataList.add(excelData); |
| | | }else{ |
| | | excelDataList.add(new WriteExcelData(0,index, columns.get(index))); |
| | | } |
| | | } |
| | | WriteExcelOption excelOption = new WriteExcelOption(excelDataList); |
| | | ExcelUtil.writeDataToFile(excelPath, excelOption); |
| | | return excelPath; |
| | | } |
| | | |
| | | /** |
| | | * 导入部门 |
| | | * @param file |
| | | * @return |
| | | * @throws VciBaseException |
| | | */ |
| | | @Override |
| | | public BaseResult importDept(File file) throws Exception { |
| | | VciBaseUtil.alertNotNull(file,"excel文件"); |
| | | if(!file.exists()){ |
| | | throw new VciBaseException("导入的excel文件不存在,{0}",new String[]{file.getPath()}); |
| | | } |
| | | try{ |
| | | //1、读取excel中的数据,组成对象 |
| | | ReadExcelOption excelOption = new ReadExcelOption(); |
| | | //当前登录的用户账号 |
| | | //String loginUserId = WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId(); |
| | | String loginUserId = "developer"; |
| | | UserEntityInfo userEntityInfo = new UserEntityInfo(loginUserId,null); |
| | | List<OrgDeptPO> poList = ExcelUtil.readDataObjectFromExcel(file, OrgDeptPO.class,excelOption,(value, po, fieldName)->{}); |
| | | //去除都是空的情况 |
| | | if(CollectionUtils.isEmpty(poList)){ |
| | | return BaseResult.fail(ExcelLangCodeConstant.IMPORT_CONTENT_NULL,new String[]{}); |
| | | } |
| | | |
| | | //2、必填判空、判重(数据库判重和excel中判重),组装成保存用的数据对象 |
| | | List<DeptInfo> deptInfoList = new ArrayList<>(); |
| | | //2.1、用以存储excel中重复的数据,两个不可重复的字段)(Name不能为空,Name、Code同一父部门下唯一) |
| | | Map<String,String> repeatNameMap = new HashMap<>(); |
| | | Map<String,String> repeatNumMap = new HashMap<>(); |
| | | Map<String,String> indexMap = new HashMap<>(); |
| | | //2.2、存储用户手输的oid和实际存储oid的映射关系 |
| | | Map<String, String> oidMap = new HashMap<>(); |
| | | //查询系统中部门,其中包含了部门名称树属性 |
| | | List<OrgDepartmentVO> dbOrgDepartmentVOList = this.getDeptAllFullName(); |
| | | //遍历成map对象:key为DeptName的全路径:value为Dept对象(用户处理部门父组件) |
| | | Map<String, String> dbOrgDepartFullNameOidMap = dbOrgDepartmentVOList.stream().collect(Collectors.toMap(OrgDepartmentVO::getFullDeptNamePath, OrgDepartmentVO::getOid)); |
| | | //用来判断处parentName既不在库中存在,又不在poNames存在的情况 |
| | | List<String> poNames = poList.stream().map(OrgDeptPO::getName).collect(Collectors.toList()); |
| | | poList.stream().forEach(po->{ |
| | | String parentFullNamePath = Func.isBlank(po.getParentFullNamePath()) ? "":po.getParentFullNamePath(); |
| | | //部门名称判空,通常通过po中的注解就可实现 |
| | | if(Func.isBlank(po.getName())){ |
| | | throw new VciBaseException("第【"+po.getRowIndex()+"】行,depterror,Reason:Name cannot be empty"); |
| | | }else if(parentFullNamePath.equals(repeatNameMap.getOrDefault(po.getName(), null))/*excel中同一部门下Name相等*/){ |
| | | //同一部门下名称判重 |
| | | throw new VciBaseException("第【"+po.getRowIndex()+"】行,deptnameerror,Reason: Names under the same department cannot be duplicated"); |
| | | }else if(Func.isNotBlank(po.getNum()) && parentFullNamePath.equals(repeatNumMap.getOrDefault(po.getNum(),null))/*excel中同一部门下编号存在 */){ |
| | | throw new VciBaseException("第【"+po.getRowIndex()+"】行,deptnumerror,Reason: The number cannot be duplicated"); |
| | | }else{ |
| | | //2.2、查询数据库中的数据(查重ID和NUM),比较麻烦需要根据ParentName全路径查询(所有只能单条查询进行判重) |
| | | //同一部门下(parentName相等),name或者num相等 |
| | | List<OrgDepartmentVO> repeatOrgDept = dbOrgDepartmentVOList.stream().filter(item -> { |
| | | //同一部门名称全路径下,部门名称相等、部门编号不为空并且和系统中存在相等的编号 |
| | | boolean isNameOrNumRepeat = po.getName().equals(item.getName()) || (Func.isNotBlank(po.getNum()) && po.getNum().equals(item.getId())); |
| | | /*当parentFullNamePath为""时item.getFullDeptNamePath().contains(parentFullNamePath)永远为true, |
| | | 所以需要特殊处理直接判断顶层的部门是否存在重复*/ |
| | | if(((Func.isBlank(parentFullNamePath) && item.getTreelevel() == 1) |
| | | || (Func.isNotBlank(parentFullNamePath) && item.getFullDeptNamePath().contains(parentFullNamePath))) |
| | | && isNameOrNumRepeat) { |
| | | return true; |
| | | } |
| | | return false; |
| | | }).collect(Collectors.toList()); |
| | | //只要不为空就说明当前行数据在系统中重复 |
| | | if(Func.isNotEmpty(repeatOrgDept)){ |
| | | throw new VciBaseException("第【"+po.getRowIndex()+"】行,deptname or deptnum error,Reason: The name or number already exists in the system"); |
| | | } |
| | | } |
| | | //存储校验通过的数据,以便后续excel查重 |
| | | repeatNameMap.put(po.getName(),parentFullNamePath); |
| | | if(Func.isNotBlank(po.getNum())){ |
| | | repeatNumMap.put(po.getNum(),parentFullNamePath); |
| | | } |
| | | indexMap.put(po.getName(),po.getRowIndex()); |
| | | //校验数据就该组装成DTO数据对象了 |
| | | OrgDepartmentDTO dto = new OrgDepartmentDTO(); |
| | | BeanUtil.convert(po,dto); |
| | | dto.setOid(po.getId()); |
| | | dto.setId(po.getNum()); |
| | | dto.setDescription(po.getDesc()); |
| | | dto.setSpecialties(po.getSpecialties()); |
| | | dto.setCreateTime(new Date()); |
| | | dto.setCreator(loginUserId); |
| | | dto.setLastModifier(loginUserId); |
| | | dto.setStatus((short) 0); |
| | | //给导入的数据设置的主键 |
| | | String oid = VciBaseUtil.getPk().toUpperCase(Locale.ROOT); |
| | | dto.setOid(oid); |
| | | /*处理部门名称全路径转换为PkFatherDepartment(部门主键): |
| | | 情况1、直属父部门是系统中已存在(判断方式:部门名称全路径在dbOrgDepartmentVOList中存在,fullDeptNamePath全等于parentFullNamePath)。 |
| | | 情况2、直属父部门不是系统中已存在的,但是直属父部门的的上级部门是系统中已存在的(涉及到oid和parentoid对应关系处理比较麻烦)。 |
| | | 情况3、直属父部门和其上级部门都是excel中新构建的。(涉及到oid和parentoid对应关系处理比较麻烦)*/ |
| | | String dbDeptoid = dbOrgDepartFullNameOidMap.getOrDefault(parentFullNamePath, null); |
| | | //情况1可以直接设置parentOid。 |
| | | if(Func.isNotEmpty(dbDeptoid) || "".equals(parentFullNamePath)){ |
| | | //设置父部门主键 |
| | | dto.setPkFatherDepartment(dbDeptoid); |
| | | }else{ |
| | | //处理父路径名既不存在于数据库又不存在于当前excel |
| | | String lastParentFullName = parentFullNamePath.substring(parentFullNamePath.lastIndexOf("/") + 1);//父路径名的最后一个部门名称 |
| | | if(Func.isBlank(dbOrgDepartFullNameOidMap.getOrDefault(parentFullNamePath,null)) |
| | | && !poNames.contains(lastParentFullName) |
| | | ){ |
| | | throw new VciBaseException("当前导入的部门数据中,第【" + indexMap.get(po.getName()) + "】行,父部门设置存在问题!"); |
| | | } |
| | | //情况2和3需要通过映射关系设置parentoid,所以这里先标记后续再做处理。 |
| | | dto.setPkFatherDepartment("Pending:" + parentFullNamePath); |
| | | } |
| | | //存储parentOid:oid映射关系 |
| | | String key = Func.isBlank(parentFullNamePath) ? po.getName():parentFullNamePath + "/"+po.getName(); |
| | | oidMap.put(key,oid); |
| | | |
| | | DeptInfo deptInfo = this.changeOrgDeptDTOToDeptInfo(dto); |
| | | deptInfoList.add(deptInfo); |
| | | }); |
| | | //3、处理oid和parentOid的映射关系:针对新加的数据是父部门 |
| | | deptInfoList.stream().forEach(info -> { |
| | | try { |
| | | //parentId不为空并且没有Pending:相关的字符串,说明是需要处理oid映射parentOid的 |
| | | if (info.parentId.contains("Pending:")){ |
| | | //系统中已存在的父部门OID,需要移除掉Dept:标识 |
| | | String key = info.parentId.replace("Pending:",""); |
| | | String parentId = oidMap.get(key); |
| | | info.parentId = parentId; |
| | | } |
| | | //4、保存操作 |
| | | platformClientUtil.getFrameworkService().saveDepartment( |
| | | info, |
| | | userEntityInfo |
| | | ); |
| | | } catch (PLException e) { |
| | | e.printStackTrace(); |
| | | throw new VciBaseException("保存时出现错误!,原因:"+VciBaseUtil.getExceptionMessage(e)); |
| | | } |
| | | }); |
| | | }catch (Exception e){ |
| | | if(logger.isErrorEnabled()){ |
| | | logger.error("读取excel内容时或保存用户信息时出现了错误,具体原因:",e.getMessage()); |
| | | } |
| | | e.printStackTrace(); |
| | | return BaseResult.fail(LangBaseUtil.getErrorMsg(e),new String[]{},e); |
| | | } |
| | | return BaseResult.success("部门导入成功!"); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有部门的信息 |
| | | * @return key:部门由名称组成的路径(/间隔),value对应最小层级的部门信息 |
| | | */ |
| | | @Override |
| | | public Map<String, OrgDepartmentVO> getDeptAllTreeMap() { |
| | | List<OrgDepartmentVO> orgDepartmentVOList = listAllLevelChildrenDeptByParentOid(null, null); |
| | | Map<String, OrgDepartmentVO> stringOrgDepartmentVOMap = convertToMap(orgDepartmentVOList); |
| | | return stringOrgDepartmentVOMap; |
| | | } |
| | | |
| | | /** |
| | | * 获取部门由名称组成的路径(/间隔),value对应最小层级的部门信息 |
| | | * @param orgDepartmentVOList |
| | | * @return |
| | | */ |
| | | private Map<String, OrgDepartmentVO> convertToMap(List<OrgDepartmentVO> orgDepartmentVOList) { |
| | | Map<String, OrgDepartmentVO> map = new HashMap<>(); |
| | | for (OrgDepartmentVO orgDepartmentVO : orgDepartmentVOList) { |
| | | String key = buildKey(orgDepartmentVO, orgDepartmentVOList); |
| | | map.put(key, orgDepartmentVO); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | private String buildKey(OrgDepartmentVO orgDepartmentVO, List<OrgDepartmentVO> orgDepartmentVOList) { |
| | | StringBuilder keyBuilder = new StringBuilder(); |
| | | OrgDepartmentVO current = orgDepartmentVO; |
| | | while (current != null) { |
| | | keyBuilder.insert(0, current.getName()); |
| | | keyBuilder.insert(0, "/"); |
| | | current = getParentDepartment(current.getPkFatherDepartment(), orgDepartmentVOList); |
| | | } |
| | | keyBuilder.deleteCharAt(0); |
| | | return keyBuilder.toString(); |
| | | } |
| | | |
| | | private OrgDepartmentVO getParentDepartment(String pkFatherDepartment, List<OrgDepartmentVO> orgDepartmentVOList) { |
| | | for (OrgDepartmentVO orgDepartmentVO : orgDepartmentVOList) { |
| | | if (pkFatherDepartment != null && pkFatherDepartment.equals(orgDepartmentVO.getOid())) { |
| | | return orgDepartmentVO; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |