# CompRoomApproveLogServiceImpl.java

    package cloud.wconnect.frontoffice.service.comproom.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationDateTimeDTO;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.frontoffice.cons.ApproveStatusEnum;
    import cloud.wconnect.frontoffice.entity.comproom.CompRoomApproveConfig;
    import cloud.wconnect.frontoffice.entity.comproom.CompRoomApproveLevel;
    import cloud.wconnect.frontoffice.entity.comproom.CompRoomApproveLog;
    import cloud.wconnect.frontoffice.entity.comproom.RqCompRoomForm;
    import cloud.wconnect.frontoffice.mapper.comproom.CompRoomApproveLogMapper;
    import cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveLevelVO;
    import cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveUserVO;
    import cloud.wconnect.frontoffice.service.comproom.ICompRoomApproveConfigService;
    import cloud.wconnect.frontoffice.service.comproom.ICompRoomApproveLevelService;
    import cloud.wconnect.frontoffice.service.comproom.ICompRoomApproveLogService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;

    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    import static java.util.stream.Collectors.groupingBy;
    import static java.util.stream.Collectors.toList;

    /**
     * <p>
     * comp room审批日志表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-08-21
     */
    @Service
    @DS("logbook")
    public class CompRoomApproveLogServiceImpl extends ServiceImpl<CompRoomApproveLogMapper, CompRoomApproveLog> implements ICompRoomApproveLogService {

        @Autowired
        private CompRoomApproveLogMapper compRoomApproveLogMapper;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        @Lazy
        private ICompRoomApproveLevelService approveLevelService;
        @Autowired
        @Lazy
        private ICompRoomApproveConfigService approveConfigService;
        @Autowired
        private BeanMapper beanMapper;

        /**
         * 查询comp room的审批日志
         *
         * @param compRoomList comp room集合
         * @return java.util.List<cloud.wconnect.frontoffice.entity.comproom.CompRoomApproveLog>
         * @author lichen
         * @date 2023/8/21
         */
        @Override
        public List<CompRoomApproveLog> listByBatchIdAndCompRoomId(List<RqCompRoomForm> compRoomList) {
            if (CollectionUtils.isEmpty(compRoomList)) return Collections.emptyList();
            return compRoomApproveLogMapper.listByBatchIdAndCompRoomId(compRoomList);
        }

        /**
         * 查询comp room数据当前审批层级的审批日志
         *
         * @param compRoom comp room数据
         * @return java.util.List<cloud.wconnect.frontoffice.entity.comproom.CompRoomApproveLog>
         * @author lichen
         * @date 2023/8/21
         */
        @Override
        public List<CompRoomApproveLog> listCurrentApproveIndexLog(RqCompRoomForm compRoom) {
            return list(new LambdaQueryWrapper<CompRoomApproveLog>()
                    .eq(CompRoomApproveLog::getPropertyId, compRoom.getPropertyId())
                    .eq(CompRoomApproveLog::getBatchId, compRoom.getBatchId())
                    .eq(CompRoomApproveLog::getCompRoomId, compRoom.getId())
                    .eq(CompRoomApproveLog::getApproveIndex, compRoom.getApproveIndex()));
        }

        /**
         * 查询审批日志
         *
         * @param compRoom    comp room数据
         * @param propertyDTO 资产dto
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveLevelVO>
         * @author lichen
         * @date 2023/8/22
         */
        @Override
        public List<CompRoomApproveLevelVO> listApproveLogTree(RqCompRoomForm compRoom, PropertyDTO propertyDTO) {
            //查询审批层级
            List<CompRoomApproveLevel> levelList = approveLevelService.listByPropertyId(propertyDTO.getId());
            List<Integer> levelIds = levelList.stream().map(CompRoomApproveLevel::getId).collect(toList());
            Map<Integer, CompRoomApproveLevel> levelId2ApproveLevel = levelList.stream().collect(Collectors.toMap(CompRoomApproveLevel::getId, Function.identity()));

            //查询comp room当前批次的审批日志
            List<CompRoomApproveLog> compRoomApproveLogs = listByBatchIdAndCompRoomId(Lists.newArrayList(compRoom));
            List<Integer> approveByList = compRoomApproveLogs.stream().map(CompRoomApproveLog::getApproveBy).collect(toList());

            //查询审批层级人员
            List<CompRoomApproveConfig> compRoomApproveConfigs = approveConfigService.listByLevelIds(propertyDTO.getId(), levelIds);
            List<Integer> configApproveByList = compRoomApproveConfigs.stream().map(CompRoomApproveConfig::getUserId).collect(toList());
            Map<Integer, List<CompRoomApproveConfig>> levelId2ApproveConfigs = compRoomApproveConfigs.stream().collect(groupingBy(CompRoomApproveConfig::getLevelId));

            //查询用户信息
            List<Integer> userIds = Lists.newArrayList(approveByList);
            userIds.addAll(configApproveByList);
            Map<Integer, UserDTO> userId2UserDto = userInternalService.getUserMapByIds(propertyDTO.getTenantId(), userIds);

            if (compRoom.getApproveStatus() == ApproveStatusEnum.APPROVED.getStatus()) {
                if (CollectionUtils.isEmpty(compRoomApproveLogs)) return Collections.emptyList();
                return createApprovedLog(compRoomApproveLogs, levelId2ApproveLevel, userId2UserDto, propertyDTO);
            } else if (compRoom.getApproveStatus() == ApproveStatusEnum.REJECTED.getStatus()) {
                if (CollectionUtils.isEmpty(compRoomApproveLogs)) return Collections.emptyList();
                return createRejectedLog(compRoomApproveLogs, levelId2ApproveLevel, userId2UserDto, propertyDTO);
            } else if (compRoom.getApproveStatus() == ApproveStatusEnum.APPROVEING.getStatus()) {
                return createApprovingLog(compRoom, compRoomApproveLogs, levelList, levelId2ApproveLevel, levelId2ApproveConfigs, userId2UserDto, propertyDTO);
            } else {
                //pending的数据返回空
                return Collections.emptyList();
            }
        }

        /**
         * 查询在当前节点下comp room数据审批通过的日志
         *
         * @param batchIds     批次id集合
         * @param approveLevel 审批级别
         * @return java.util.Map<java.lang.Long, java.util.List < cloud.wconnect.frontoffice.entity.comproom.CompRoomApproveLog>>
         * @author lichen
         * @date 2023/8/22
         */
        @Override
        public Map<Long, List<CompRoomApproveLog>> listApprovedLogByBatchIdsAndApproveIndex(List<Long> batchIds, CompRoomApproveLevel approveLevel) {
            //查询待审核数据 在当前节点下对应的审核日志信息
            LambdaQueryWrapper<CompRoomApproveLog> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CompRoomApproveLog::getPropertyId, approveLevel.getPropertyId());
            queryWrapper.in(CompRoomApproveLog::getBatchId, batchIds);
            queryWrapper.eq(CompRoomApproveLog::getApproveIndex, approveLevel.getApproveIndex());
            queryWrapper.eq(CompRoomApproveLog::getIsApproved, true);
            List<CompRoomApproveLog> approveLogList = list(queryWrapper);
            //数据为空时，直接return
            if (CollectionUtils.isEmpty(approveLogList)) return Collections.emptyMap();
            //key = 业务数据id value = 当前节点的审批人集合
            return approveLogList.stream().collect(groupingBy(CompRoomApproveLog::getCompRoomId));
        }

        /**
         * 创建审批通过的日志树
         *
         * @param compRoomApproveLogs        审批日志
         * @param latestLevelId2ApproveLevel 当前资产设置的审批层级集合
         * @param userId2UserDto             用户集合
         * @param propertyDTO                资产DTO
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveLevelVO>
         * @author lichen
         * @date 2023/8/22
         */
        private List<CompRoomApproveLevelVO> createApprovedLog(List<CompRoomApproveLog> compRoomApproveLogs, Map<Integer, CompRoomApproveLevel> latestLevelId2ApproveLevel,
                                                               Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            /**
             * 审批日志中出现过的所有审批层级集合
             */
            List<CompRoomApproveLevel> levelList = compRoomApproveLogs.stream().map(log -> {
                //获取当前资产配置的最新审批层级
                CompRoomApproveLevel latestApproveLevel = latestLevelId2ApproveLevel.get(log.getLevelId());
                if (Objects.nonNull(latestApproveLevel)) return latestApproveLevel;
                //审批层级被删除，生成审批层级对象
                return CompRoomApproveLevel.builder()
                        .id(log.getLevelId())
                        .approveIndex(log.getApproveIndex())
                        .propertyId(log.getPropertyId())
                        .build();
            }).distinct().sorted(Comparator.comparing(CompRoomApproveLevel::getApproveIndex)).collect(toList());

            //审批日志按照审批层级id分组。key=审批层级id value=审批人
            Map<Integer, List<CompRoomApproveLog>> levelId2ApproveLog = compRoomApproveLogs.stream().collect(groupingBy(CompRoomApproveLog::getLevelId));

            return beanMapper.mapList(levelList, CompRoomApproveLevelVO.class, (entity, vo) -> {
                vo.setApproveStatus(ApproveStatusEnum.APPROVED.getStatus());
                vo.setUsers(convert(levelId2ApproveLog.get(entity.getId()), userId2UserDto, propertyDTO));
            });
        }

        /**
         * 把审批日志转换为vo类
         *
         * @param logList        审批日志集合
         * @param userId2UserDto 用户集合
         * @param propertyDTO    资产DTO
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproverLogVO>
         * @author lichen
         * @date 2023/8/22
         */
        private List<CompRoomApproveUserVO> convert(List<CompRoomApproveLog> logList, Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            InternationalizationDateTimeDTO dateTime = propertyDTO.getInternationalization().getDateTime();
            String longDate = dateTime.getLongDate();
            String hourClock = dateTime.getHourClock();
            String language = propertyDTO.getLanguage();
            String timezone = propertyDTO.getTimezone();

            return logList.stream().map(approveLog -> {
                CompRoomApproveUserVO approveUserVO = new CompRoomApproveUserVO();
                approveUserVO.setUserId(approveLog.getApproveBy());
                approveUserVO.setApproveStatus(approveLog.getIsApproved() ? ApproveStatusEnum.APPROVED.getStatus() : ApproveStatusEnum.REJECTED.getStatus());
                approveUserVO.setApproveOpinion(approveLog.getApproveOpinion());
                approveUserVO.setApproveTime(approveLog.getApproveTime());
                approveUserVO.setApproveTimeStr(InternationalizationUtils.formatDateTime(approveLog.getApproveTime(), longDate, hourClock, timezone, language));

                UserDTO userDTO = userId2UserDto.get(approveLog.getApproveBy());
                if (Objects.nonNull(userDTO)) {
                    approveUserVO.setName(userDTO.getName());
                    approveUserVO.setAccount(userDTO.getAccount());
                    approveUserVO.setEmail(userDTO.getEmail());
                    approveUserVO.setPhone(userDTO.getPhone());
                }
                return approveUserVO;
            }).collect(toList());
        }

        /**
         * 创建审批拒绝的日志树
         *
         * @param compRoomApproveLogs        审批日志
         * @param latestLevelId2ApproveLevel 当前资产设置的审批层级集合
         * @param userId2UserDto             用户集合
         * @param propertyDTO                资产DTO
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveLevelVO>
         * @author lichen
         * @date 2023/8/22
         */
        private List<CompRoomApproveLevelVO> createRejectedLog(List<CompRoomApproveLog> compRoomApproveLogs, Map<Integer, CompRoomApproveLevel> latestLevelId2ApproveLevel,
                                                               Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            /**
             * 审批日志中出现过的所有审批层级集合
             */
            List<CompRoomApproveLevel> levelList = compRoomApproveLogs.stream().map(log -> {
                //获取当前资产配置的最新审批层级
                CompRoomApproveLevel latestApproveLevel = latestLevelId2ApproveLevel.get(log.getLevelId());
                if (Objects.nonNull(latestApproveLevel)) return latestApproveLevel;
                //审批层级被删除，生成审批层级对象
                return CompRoomApproveLevel.builder()
                        .id(log.getLevelId())
                        .approveIndex(log.getApproveIndex())
                        .propertyId(log.getPropertyId())
                        .build();
            }).distinct().sorted(Comparator.comparing(CompRoomApproveLevel::getApproveIndex)).collect(toList());

            //审批日志按照审批层级id分组。key=审批层级id value=审批人
            Map<Integer, List<CompRoomApproveLog>> levelId2ApproveLog = compRoomApproveLogs.stream().collect(groupingBy(CompRoomApproveLog::getLevelId));

            /**
             * 查询出审批拒绝的的层级
             */
            Integer rejectedApproveIndex = compRoomApproveLogs.stream().filter(log -> !log.getIsApproved()).findFirst().get().getApproveIndex();

            return beanMapper.mapList(levelList, CompRoomApproveLevelVO.class, (entity, vo) -> {
                if (vo.getApproveIndex().equals(rejectedApproveIndex)) {
                    vo.setApproveStatus(ApproveStatusEnum.REJECTED.getStatus());
                } else {
                    vo.setApproveStatus(ApproveStatusEnum.APPROVED.getStatus());
                }
                vo.setUsers(convert(levelId2ApproveLog.get(entity.getId()), userId2UserDto, propertyDTO));
            });
        }

        /**
         * 创建审批中的日志树
         *
         * @param compRoom               comp room数据
         * @param compRoomApproveLogs    审批日志
         * @param levelList              审批层级集合
         * @param levelId2ApproveLevel   审批层级集合
         * @param levelId2ApproveConfigs 审批配置集合
         * @param userId2UserDto         用户集合
         * @param propertyDTO            资产DTO
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveLevelVO>
         * @author lichen
         * @date 2023/8/24
         */
        private List<CompRoomApproveLevelVO> createApprovingLog(RqCompRoomForm compRoom,
                                                                List<CompRoomApproveLog> compRoomApproveLogs,
                                                                List<CompRoomApproveLevel> levelList,
                                                                Map<Integer, CompRoomApproveLevel> levelId2ApproveLevel,
                                                                Map<Integer, List<CompRoomApproveConfig>> levelId2ApproveConfigs,
                                                                Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            List<CompRoomApproveLevelVO> levelVOList = Lists.newArrayListWithCapacity(levelList.size());

            //当前审批索引
            Integer currentApproveIndex = compRoom.getApproveIndex();
            //当前审批层级
            CompRoomApproveLevel currentApproveLevel = levelList.stream()
                    .filter(item -> item.getApproveIndex().equals(currentApproveIndex)).findFirst().get();

            /**
             * 过滤出小于当前审批索引的审批日志
             * 这部分审批日志已经审批通过，生成审批通过的树
             */
            List<CompRoomApproveLog> approvedLogs = compRoomApproveLogs.stream().filter(log -> log.getApproveIndex() < currentApproveIndex).collect(toList());
            List<CompRoomApproveLevelVO> approvedLogVOList = createApprovedLog(approvedLogs, levelId2ApproveLevel, userId2UserDto, propertyDTO);

            /**
             * 当前审批层级的人包括:审批日志中的人 + 未审批的人
             */
            List<CompRoomApproveUserVO> approveingUserVOS = Lists.newArrayList();
            //过滤出等于当前审批索引的审批日志
            List<CompRoomApproveLog> approveingLogs = compRoomApproveLogs.stream().filter(log -> log.getApproveIndex().equals(currentApproveIndex)).collect(toList());
            List<Integer> currentApproveLevelalreadyApproveUser = approveingLogs.stream().map(CompRoomApproveLog::getApproveBy).collect(toList());//已经审批过的人
            approveingUserVOS.addAll(convert(approveingLogs, userId2UserDto, propertyDTO));
            //当前审批层级未审批的人
            List<CompRoomApproveConfig> currentApproveLevelUnApprover = levelId2ApproveConfigs.get(currentApproveLevel.getId())
                    .stream().filter(item -> !currentApproveLevelalreadyApproveUser.contains(item.getUserId())).collect(toList());
            approveingUserVOS.addAll(convertApproveConfigToApproveUserLog(currentApproveLevelUnApprover, userId2UserDto, BaseConstant.ZERO));
            //生成当前审批层级的vo
            CompRoomApproveLevelVO approveingLogVO = beanMapper.map(currentApproveLevel, CompRoomApproveLevelVO.class, vo -> {
                vo.setApproveStatus(compRoom.getApproveStatus());
                vo.setUsers(approveingUserVOS);
            });

            /**
             * 未审批的审批层级：大于当前审批索引的审批层级集合
             */
            List<CompRoomApproveLevel> unApproveLevelList = levelList.stream().filter(item -> item.getApproveIndex() > currentApproveIndex).collect(toList());
            List<CompRoomApproveLevelVO> unApproveLevelVOList = beanMapper.mapList(unApproveLevelList, CompRoomApproveLevelVO.class, (entity, vo) -> {
                vo.setApproveStatus(BaseConstant.ZERO);
                //获取审批配置人员
                List<CompRoomApproveConfig> compRoomApproveConfigs = levelId2ApproveConfigs.get(entity.getId());
                //设置审批配置人员
                vo.setUsers(convertApproveConfigToApproveUserLog(compRoomApproveConfigs, userId2UserDto, BaseConstant.ZERO));
            });

            levelVOList.addAll(approvedLogVOList);
            levelVOList.add(approveingLogVO);
            levelVOList.addAll(unApproveLevelVOList);
            levelVOList.sort(Comparator.comparing(CompRoomApproveLevelVO::getApproveIndex));
            return levelVOList;
        }

        /**
         * 审批配置 转换成 审批人员VO
         *
         * @param approveConfigs
         * @param userId2UserDto
         * @param approveStatus
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveUserVO>
         * @author lichen
         * @date 2023/8/24
         */
        private List<CompRoomApproveUserVO> convertApproveConfigToApproveUserLog(List<CompRoomApproveConfig> approveConfigs, Map<Integer, UserDTO> userId2UserDto,
                                                                                 Integer approveStatus) {
            return approveConfigs.stream().map(approveConfig -> {
                CompRoomApproveUserVO approveUserVO = new CompRoomApproveUserVO();
                approveUserVO.setUserId(approveConfig.getUserId());
                approveUserVO.setApproveStatus(approveStatus);
                UserDTO userDTO = userId2UserDto.get(approveConfig.getUserId());
                if (Objects.nonNull(userDTO)) {
                    approveUserVO.setName(userDTO.getName());
                    approveUserVO.setAccount(userDTO.getAccount());
                    approveUserVO.setEmail(userDTO.getEmail());
                    approveUserVO.setPhone(userDTO.getPhone());
                }
                return approveUserVO;
            }).collect(toList());
        }
    }