| | |
| | | } |
| | | |
| | | /** |
| | | * 根据父部门主键获取和部门名称部门的信息 |
| | | * 根据父部门主键获取部门名称部门的信息 |
| | | * @param parentDeptOid 父部门主键 |
| | | * @param conditionMap 部门名称 |
| | | * @return 部门的显示对象,如果部门不存在则返回null,不会抛出异常 |
| | | * @throws VciBaseException 参数为空或者数据库存在问题的时候会抛出异常 |
| | | */ |
| | | @Override |
| | | public List<OrgDepartmentVO> getDeptByDeptPOidAndCondition(String parentDeptOid,Map<String,String> conditionMap) throws VciBaseException { |
| | | public List<OrgDepartmentVO> getDeptByDeptpOidAndCondition(String parentDeptOid,Map<String,String> conditionMap) throws VciBaseException { |
| | | if(Func.isEmpty(conditionMap)){ |
| | | conditionMap = new HashMap(); |
| | | } |
| | |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | |
| | | if(deptForPlatform1!=null){ |
| | | departmentVO.setOid(deptForPlatform1.getPluid()); |
| | | // 除部门主键外的唯一标识,长度为Dept:+8位可通过该参数反推回部门主键的hash编码 |
| | | departmentVO.setUniqueId("Dept:"+Func.oidEnHash(deptForPlatform1.getPluid())); |
| | | //departmentVO.setUniqueId("Dept:"+Func.oidEnHash(deptForPlatform1.getPluid())); |
| | | departmentVO.setId(deptForPlatform1.getPlnum()); |
| | | departmentVO.setName(deptForPlatform1.getPlname()); |
| | | departmentVO.setStatus(deptForPlatform1.getPlstatus()); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 保存部门角色关联信息,带查重功能 |
| | | * 保存部门用户关联信息,带查重功能 |
| | | * @param userOIds 用户id |
| | | * @param deptId 部门id |
| | | * @return |
| | |
| | | if(Func.isNotBlank(orgDepartmentDTO.getId())){ |
| | | conditionMap.put("plnum",QueryOptionConstant.OR + orgDepartmentDTO.getId()); |
| | | } |
| | | List<OrgDepartmentVO> departmentVOS = getDeptByDeptPOidAndCondition(orgDepartmentDTO.getPkFatherDepartment(), conditionMap); |
| | | List<OrgDepartmentVO> departmentVOS = getDeptByDeptpOidAndCondition(orgDepartmentDTO.getPkFatherDepartment(), conditionMap); |
| | | if(Func.isNotEmpty(departmentVOS)){ |
| | | throw new VciBaseException("同一父节点下该部门名称或编号已经存在,请修改!"); |
| | | } |
| | |
| | | if(Func.isNotBlank(orgDepartmentDTO.getId())){ |
| | | conditionMap.put("plnum",QueryOptionConstant.OR + orgDepartmentDTO.getId()); |
| | | } |
| | | List<OrgDepartmentVO> repeatDepartmentVOS = getDeptByDeptPOidAndCondition(orgDepartmentDTO.getPkFatherDepartment(), conditionMap); |
| | | 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())){ |
| | |
| | | //TODO: 应该是不具备连带删除的功能,部门删除后用户关联的无用部门还在,考虑后期是否需要做,数据量不大可以不做连带删除 |
| | | return platformClientUtil.getFrameworkService().deleteDepartment( |
| | | ids, |
| | | new UserEntityInfo("developer"/*WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId()*/, null) |
| | | new UserEntityInfo(WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId(), null) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有部门的信息 |
| | | * @return key:部门由名称组成的路径(/间隔),value对应最小层级的部门信息 |
| | | */ |
| | | @Override |
| | | public Map<String, OrgDepartmentVO> getDeptAllTreeMap() { |
| | | List<OrgDepartmentVO> orgDepartmentVOList = listAllLevelChildrenDeptByParentOid(null, null); |
| | | Map<String, OrgDepartmentVO> stringOrgDepartmentVOMap = convertToMap(orgDepartmentVOList); |
| | | return stringOrgDepartmentVOMap; |
| | | } |
| | | |
| | | /** |
| | |
| | | //界面没传名称,使用默认名称 |
| | | downloadFileName = Func.isBlank(downloadFileName) ? "部门导入模板_" + Func.format(new Date(),"yyyy-MM-dd HHmmss.sss"):downloadFileName; |
| | | // 设置表单列名 |
| | | List<String> columns = new ArrayList<>(Arrays.asList("ID", "名称", "编号", "代号", "专业", "父ID(部门唯一标识ID)", "描述")); |
| | | List<String> columns = new ArrayList<>(Arrays.asList("名称", "编号", "代号", "专业", "父部门名称全路径(/间隔)", "描述")); |
| | | //设置必填列 |
| | | ColumnNameisRed.clear(); |
| | | //ColumnNameisRed.add(0); |
| | | ColumnNameisRed.add(0); |
| | | ColumnNameisRed.add(1); |
| | | //写excel |
| | | String excelPath = LocalFileUtil.getDefaultTempFolder() + File.separator + downloadFileName + ".xls"; |
| | |
| | | if(CollectionUtils.isEmpty(poList)){ |
| | | return BaseResult.fail(ExcelLangCodeConstant.IMPORT_CONTENT_NULL,new String[]{}); |
| | | } |
| | | /*部门导入几个比较重要的情景: |
| | | 1、当前导入的数据是一个部门树结构(要判断用户手输的ID是否存在重复,输了就要判断是否在当前表格中重复, |
| | | 并且保存时不能使用用户手输的ID,要根据手输ID和实际存储OID做对应映射, |
| | | 并且不破坏表格中部门树结构,如果没手输ID就只需要关注parentId这个属性, |
| | | 并且需要注意如果有的ID有,有的没有那就需要注意,既存在和系统中, |
| | | 关联的部门树,又存在和当前表格中关联的部门树)。 |
| | | 2、当前导入的数据父id关联了已存在的部门oid(要查询父id这个部门是否存在,) |
| | | 解决思路:最好是将表格中可能是部门树的给遍历成树,然后再做查重啥的处理 |
| | | */ |
| | | |
| | | //2、必填判空、判重(数据库判重和excel中判重),组装成保存用的数据对象 |
| | | List<DeptInfo> deptInfoList = new ArrayList<>(); |
| | | //2.1、用以存储excel中重复的数据,三个不可重复的字段)(Name不能为空,Name、Code同一父部门下唯一) |
| | | List<String> repeatIdList = 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 parentId = Func.isBlank(po.getParentId()) ? "":po.getParentId(); |
| | | String parentFullNamePath = Func.isBlank(po.getParentFullNamePath()) ? "":po.getParentFullNamePath(); |
| | | //部门名称判空,通常通过po中的注解就可实现 |
| | | if(Func.isEmpty(po.getName())){ |
| | | if(Func.isBlank(po.getName())){ |
| | | throw new VciBaseException("第【"+po.getRowIndex()+"】行,depterror,Reason:Name cannot be empty"); |
| | | }else if(parentId.equals(repeatNameMap.getOrDefault(po.getName(), null))/*excel中同一部门下Name相等*/){ |
| | | }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.isNotEmpty(po.getId()) && repeatIdList.equals(po.getId())){ |
| | | throw new VciBaseException("第【"+po.getRowIndex()+"】行,deptiderror,Reason: The primary key cannot be duplicated"); |
| | | }else if(Func.isNotEmpty(po.getNum()) && parentId.equals(repeatNumMap.getOrDefault(po.getNum(),null))/*excel中同一部门下编号存在 */){ |
| | | }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),比较麻烦需要根据ParentID查询(所有只能单条查询进行判重) |
| | | //组装查重条件:同一部门下(parentId相等),name或者num相等 |
| | | HashMap<String, String> conditionMap = new HashMap<>(); |
| | | conditionMap.put("plname",QueryOptionConstant.OR + po.getName()); |
| | | conditionMap.put("plnum",QueryOptionConstant.OR + po.getNum()); |
| | | String pId = Func.isBlank(po.getParentId()) ? null:po.getParentId(); |
| | | List<OrgDepartmentVO> repeatOrgDept = this.getDeptByDeptPOidAndCondition(pId, conditionMap); |
| | | //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(),Func.isBlank(po.getParentId()) ? "":po.getParentId()); |
| | | repeatIdList.add(po.getId()); |
| | | repeatNumMap.put(po.getNum(),po.getParentId()); |
| | | 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(); |
| | |
| | | dto.setId(po.getNum()); |
| | | dto.setDescription(po.getDesc()); |
| | | dto.setSpecialties(po.getSpecialties()); |
| | | dto.setPkFatherDepartment(po.getParentId()); |
| | | dto.setCreateTime(new Date()); |
| | | dto.setCreator(loginUserId); |
| | | dto.setLastModifier(loginUserId); |
| | | dto.setStatus((short) 0); |
| | | //2.2、过程中处理主键转换问题最好是一条一条的处理ID是否存在还有ParentID是否存在的问题 |
| | | //先判断是已存在的部门ID,还是不存在的部门ID,已存在系统中的ID就是为Dept:开头的 |
| | | String pId = Func.isBlank(dto.getPkFatherDepartment()) ? "":dto.getPkFatherDepartment(); |
| | | //是已存在系统中的部门id |
| | | if(pId.contains("Dept:")){ |
| | | //解析出真实的oid |
| | | String deParentId = Func.oidDeHash(pId.replace("Dept:", "").trim()); |
| | | //解析出来的deParentId必须得在库中存在 |
| | | if(Func.isBlank(deParentId) || Func.isEmpty(this.getDeptByDeptOid(deParentId))){ |
| | | throw new VciBaseException("第【"+ po.getRowIndex() +"】行,deptparentiderror,Reason:Parent ID resolution error or does not exist in the system"); |
| | | //给导入的数据设置的主键 |
| | | 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()) + "】行,父部门设置存在问题!"); |
| | | } |
| | | //替换掉临时使用的部门唯一标识,但是为了方便后续判断,还是需要加上Dept:标识 |
| | | dto.setPkFatherDepartment("Dept:"+deParentId); |
| | | //情况2和3需要通过映射关系设置parentoid,所以这里先标记后续再做处理。 |
| | | dto.setPkFatherDepartment("Pending:" + parentFullNamePath); |
| | | } |
| | | //用户手输了部门oid,但是避免oid不规范需要,用规范oid进行替换,如果没输入保存时会自动生成oid |
| | | String excelOid = dto.getOid(); |
| | | if(Func.isNotBlank(excelOid)){ |
| | | String pkOid = VciBaseUtil.getPk().toUpperCase(Locale.ROOT); |
| | | dto.setOid(pkOid); |
| | | //oid映射关系,后续用来更新parentId |
| | | oidMap.put(excelOid,pkOid); |
| | | } |
| | | //存储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、处理id和parentId的映射关系:将用户手输的父ID转换成实际存储的ID并保存进库 |
| | | //3、处理oid和parentOid的映射关系:针对新加的数据是父部门 |
| | | deptInfoList.stream().forEach(info -> { |
| | | //3.1、对最终处理好的部门数据保存 |
| | | try { |
| | | //parentId不为空并且没有Dept:相关的字符串,说明是用户手输的ParentId(导入的数据就是一个树结构) |
| | | if (Func.isNotBlank(info.parentId) && !info.parentId.contains("Dept:")) { |
| | | //转换ParentId为实际要存储的部门ID |
| | | info.parentId = oidMap.get(info.parentId); |
| | | }else if(info.parentId.contains("Dept:")){ |
| | | //parentId不为空并且没有Pending:相关的字符串,说明是需要处理oid映射parentOid的 |
| | | if (info.parentId.contains("Pending:")){ |
| | | //系统中已存在的父部门OID,需要移除掉Dept:标识 |
| | | info.parentId = info.parentId.replace("Dept:",""); |
| | | String key = info.parentId.replace("Pending:",""); |
| | | String parentId = oidMap.get(key); |
| | | info.parentId = parentId; |
| | | } |
| | | //4、保存操作 |
| | | platformClientUtil.getFrameworkService().saveDepartment( |
| | | info, |
| | | userEntityInfo |
| | |
| | | return BaseResult.success("部门导入成功!"); |
| | | } |
| | | |
| | | public Map<String, OrgDepartmentVO> convertToMap(List<OrgDepartmentVO> orgDepartmentVOList) { |
| | | /** |
| | | * 获取所有部门的信息 |
| | | * @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); |