# BadGuestApproveLogServiceImpl.java

    package cloud.wconnect.frontoffice.service.badguest.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.badguest.BlacklistApproveStatusEnum;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuest;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveConfig;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLevel;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLog;
    import cloud.wconnect.frontoffice.mapper.badguest.BadGuestApproveLogMapper;
    import cloud.wconnect.frontoffice.pojo.vo.badguest.BgApproveLevelVO;
    import cloud.wconnect.frontoffice.pojo.vo.badguest.BgApproveLogVO;
    import cloud.wconnect.frontoffice.service.badguest.IBadGuestApproveConfigService;
    import cloud.wconnect.frontoffice.service.badguest.IBadGuestApproveLevelService;
    import cloud.wconnect.frontoffice.service.badguest.IBadGuestApproveLogService;
    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>
     * 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-03-21
     */
    @Service
    @DS("logbook")
    public class BadGuestApproveLogServiceImpl extends ServiceImpl<BadGuestApproveLogMapper, BadGuestApproveLog> implements IBadGuestApproveLogService {

        @Autowired
        @Lazy
        private IBadGuestApproveLevelService approveLevelService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private UserInternalService userInternalService;
        @Lazy
        @Autowired
        private IBadGuestApproveConfigService approveConfigService;
        @Autowired
        private BadGuestApproveLogMapper approveLogMapper;

        /**
         * 查询黑名单数据指定批次指定审批层级的审批通过记录
         *
         * @param batchIds     黑名单数据批次id集合
         * @param approveLevel 审批级别
         * @return java.util.Map<java.lang.Long, java.util.List < cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLog>>
         * @author lichen
         * @date 2025/6/11
         */
        @Override
        public Map<Long, List<BadGuestApproveLog>> listApprovedLogs(List<Long> batchIds, BadGuestApproveLevel approveLevel) {
            //查询待审核数据 在当前节点下对应的审核日志信息
            LambdaQueryWrapper<BadGuestApproveLog> badGuestApproveLogQueryWrapper = new LambdaQueryWrapper<>();
            badGuestApproveLogQueryWrapper.eq(BadGuestApproveLog::getPropertyId, approveLevel.getPropertyId());
            badGuestApproveLogQueryWrapper.eq(BadGuestApproveLog::getApproveIndex, approveLevel.getApproveIndex());
            badGuestApproveLogQueryWrapper.eq(BadGuestApproveLog::getIsApproved, true);
            badGuestApproveLogQueryWrapper.in(BadGuestApproveLog::getBatchId, batchIds);
            List<BadGuestApproveLog> badGuestApproveLogList = list(badGuestApproveLogQueryWrapper);
            //数据为空时，直接return
            if (CollectionUtils.isEmpty(badGuestApproveLogList)) return Collections.emptyMap();
            //key = 业务数据id value = 当前节点的审批人集合
            return badGuestApproveLogList.stream().collect(groupingBy(BadGuestApproveLog::getGuestId));
        }

        @Override
        public List<BadGuestApproveLog> getCurrentLogs(BadGuest oriBadGuest) {
            LambdaQueryWrapper<BadGuestApproveLog> approveLogQueryWrapper = new LambdaQueryWrapper<>();
            approveLogQueryWrapper.eq(BadGuestApproveLog::getPropertyId, oriBadGuest.getPropertyId());
            approveLogQueryWrapper.eq(BadGuestApproveLog::getGuestId, oriBadGuest.getId());
            approveLogQueryWrapper.eq(BadGuestApproveLog::getApproveIndex, oriBadGuest.getApproveIndex());
            approveLogQueryWrapper.eq(BadGuestApproveLog::getBatchId, oriBadGuest.getBatchId());
            approveLogQueryWrapper.eq(BadGuestApproveLog::getIsApproved, true);
            return list(approveLogQueryWrapper);
        }

        @Override
        public Set<Integer> getCurrentLogUsers(BadGuest oriBadGuest) {
            List<BadGuestApproveLog> currentLogs = getCurrentLogs(oriBadGuest);
            //数据为空时，直接return
            if (CollectionUtils.isEmpty(currentLogs)) return Collections.emptySet();
            //key = 业务数据id value = 当前节点的审批人集合
            return currentLogs.stream().map(BadGuestApproveLog::getApproveBy).collect(Collectors.toSet());
        }

        /**
         * 查询审批日志树
         *
         * @param badGuest    黑名单信息
         * @param propertyDTO 资产dto
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.view.badguest.BgApproveLevelVO>
         * @author lichen
         * @date 2023/7/3
         */
        @Override
        public List<BgApproveLevelVO> listApproveRecord(BadGuest badGuest, PropertyDTO propertyDTO) {
            //查询审批层级
            List<BadGuestApproveLevel> levelList = approveLevelService.listByPropertyId(propertyDTO.getId());
            List<Long> levelIds = levelList.stream().map(BadGuestApproveLevel::getId).collect(toList());
            Map<Long, BadGuestApproveLevel> levelId2ApproveLevel = levelList.stream().collect(Collectors.toMap(BadGuestApproveLevel::getId, Function.identity()));

            //查询当前批次的审批日志
            List<BadGuestApproveLog> badGuestApproveLog = approveLogMapper.listByBatchIdAndBadGuestId(Lists.newArrayList(badGuest));
            List<Integer> approveByList = badGuestApproveLog.stream().map(BadGuestApproveLog::getApproveBy).collect(toList());

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

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

            if (badGuest.getApproveStatus() == BlacklistApproveStatusEnum.APPROVED.getStatus()) {
                if (CollectionUtils.isEmpty(badGuestApproveLog)) return Collections.emptyList();
                return createApprovedLog(badGuestApproveLog, levelId2ApproveLevel, userId2UserDto, propertyDTO);
            } else if (badGuest.getApproveStatus() == BlacklistApproveStatusEnum.REJECTED.getStatus()) {
                if (CollectionUtils.isEmpty(badGuestApproveLog)) return Collections.emptyList();
                return createRejectedLog(badGuestApproveLog, levelId2ApproveLevel, userId2UserDto, propertyDTO);
            } else if (badGuest.getApproveStatus() == BlacklistApproveStatusEnum.APPROVEING.getStatus()) {
                return createApprovingLog(badGuest, badGuestApproveLog, levelList, levelId2ApproveLevel, levelId2ApproveConfigs, userId2UserDto, propertyDTO);
            } else if (badGuest.getApproveStatus() == BlacklistApproveStatusEnum.PENDING.getStatus()) {
                return Collections.emptyList();
            } else {
                return createCancellationLog(badGuestApproveLog, levelId2ApproveLevel, userId2UserDto, propertyDTO);

            }
        }

        /**
         * 作废状态的审批树
         *
         * @param badGuestApproveLog   黑名单审批日志
         * @param levelId2ApproveLevel 审批层级集合
         * @param userId2UserDto       用户集合
         * @param propertyDTO          资产DTO
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.badguest.BgApproveLevelVO>
         * @author lichen
         * @date 2025/6/4
         */
        private List<BgApproveLevelVO> createCancellationLog(List<BadGuestApproveLog> badGuestApproveLog, Map<Long, BadGuestApproveLevel> levelId2ApproveLevel,
                                                             Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            if(CollectionUtils.isEmpty(badGuestApproveLog)) return Collections.emptyList();
            /**
             * 审批日志中出现过的所有审批层级集合
             */
            List<BadGuestApproveLevel> levelList = badGuestApproveLog.stream().map(log -> {
                //获取当前资产配置的最新审批层级
                BadGuestApproveLevel latestApproveLevel = levelId2ApproveLevel.get(log.getLevelId());
                if (Objects.nonNull(latestApproveLevel)) return latestApproveLevel;
                //审批层级被删除，生成审批层级对象
                return BadGuestApproveLevel.builder()
                        .id(log.getLevelId())
                        .approveIndex(log.getApproveIndex())
                        .propertyId(log.getPropertyId())
                        .build();
            }).distinct().sorted(Comparator.comparing(BadGuestApproveLevel::getApproveIndex)).collect(toList());

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

            return beanMapper.mapList(levelList, BgApproveLevelVO.class, (entity, vo) -> {
                List<BadGuestApproveLog> logs = levelId2ApproveLog.get(entity.getId());
                if(logs.stream().anyMatch(log -> !log.getIsApproved())){
                    //存在任意一个人审批拒绝，则层级的审批状态设置为拒绝
                    vo.setApproveStatus(BlacklistApproveStatusEnum.REJECTED.getStatus());
                }else{
                    //所有审批人都同意，则层级的审批状态设置为通过
                    vo.setApproveStatus(BlacklistApproveStatusEnum.APPROVED.getStatus());
                }

                vo.setUsers(convert(logs, userId2UserDto, propertyDTO));
            });
        }

        /**
         * 创建审批中的审批树
         *
         * @param badGuest               黑名单数据
         * @param badGuestApproveLog     黑名单审批日志
         * @param levelList              审批层级集合
         * @param levelId2ApproveLevel   审批层级集合
         * @param levelId2ApproveConfigs 审批配置集合
         * @param userId2UserDto         用户集合
         * @param propertyDTO            资产DTO
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.badguest.BgApproveLevelVO>
         * @author lichen
         * @date 2023/9/9
         */
        private List<BgApproveLevelVO> createApprovingLog(BadGuest badGuest, List<BadGuestApproveLog> badGuestApproveLog, List<BadGuestApproveLevel> levelList,
                                                          Map<Long, BadGuestApproveLevel> levelId2ApproveLevel, Map<Long, List<BadGuestApproveConfig>> levelId2ApproveConfigs,
                                                          Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            List<BgApproveLevelVO> levelVOList = Lists.newArrayListWithCapacity(levelList.size());

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

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

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

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

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

        /**
         * 审批配置人员转化为VO类
         *
         * @param currentApproveLevelUnApprover 当前未审批的人员
         * @param userId2UserDto                用户集合
         * @param approveStatus                 审批状态
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.badguest.BgApproveLogVO>
         * @author lichen
         * @date 2023/9/9
         */
        private List<BgApproveLogVO> convertApproveConfigToApproveUserLog(List<BadGuestApproveConfig> currentApproveLevelUnApprover,
                                                                          Map<Integer, UserDTO> userId2UserDto, int approveStatus) {
            return currentApproveLevelUnApprover.stream().map(approveConfig -> {
                BgApproveLogVO approveUserVO = new BgApproveLogVO();
                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());
        }

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

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

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

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

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

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

            return beanMapper.mapList(levelList, BgApproveLevelVO.class, (entity, vo) -> {
                vo.setApproveStatus(BlacklistApproveStatusEnum.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.badguest.BgApproveLogVO>
         * @author lichen
         * @date 2023/9/9
         */
        private List<BgApproveLogVO> convert(List<BadGuestApproveLog> logList, Map<Integer, UserDTO> userId2UserDto, PropertyDTO propertyDTO) {
            InternationalizationDateTimeDTO internationalizationDateTimeDTO = propertyDTO.getInternationalization().getDateTime();
            String longDate = internationalizationDateTimeDTO.getLongDate();
            String hourClock = internationalizationDateTimeDTO.getHourClock();
            String timezone = propertyDTO.getTimezone();
            String language = propertyDTO.getLanguage();

            return logList.stream().map(approveLog -> {
                BgApproveLogVO approveUserVO = new BgApproveLogVO();
                approveUserVO.setUserId(approveLog.getApproveBy());
                approveUserVO.setApproveStatus(approveLog.getIsApproved() ? BlacklistApproveStatusEnum.APPROVED.getStatus() : BlacklistApproveStatusEnum.REJECTED.getStatus());
                approveUserVO.setApproveOpinion(approveLog.getApproveOpinion());
                approveUserVO.setApproveTime(approveLog.getApproveTime());

                //设置审核时间
                if (approveLog.getApproveTime() > 0) {
                    String approveTimeStr = InternationalizationUtils.formatDateTime(approveLog.getApproveTime(), longDate, hourClock, timezone, language);
                    approveUserVO.setApproveTimeStr(approveTimeStr);
                }

                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());
        }
    }