# FdProcedureCheckCommentServiceImpl.java

    package cloud.wconnect.workperformance.service.fdprocedurecheck.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.workperformance.cons.fdprocedurecheck.FdProcedureCheckErrorI18nConstant;
    import cloud.wconnect.workperformance.cons.fdprocedurecheck.FdProcedureCheckHandledResultEnum;
    import cloud.wconnect.workperformance.entity.fdprocedurecheck.FdProcedureCheckComment;
    import cloud.wconnect.workperformance.mapper.fdprocedurecheck.FdProcedureCheckCommentMapper;
    import cloud.wconnect.workperformance.pojo.dto.fdprocedurecheck.FdProcedureCheckCommentDTO;
    import cloud.wconnect.workperformance.service.fdprocedurecheck.IFdProcedureCheckCommentService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import jakarta.annotation.Resource;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;

    import java.text.MessageFormat;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     * FD Procedure Check 备注 服务实现类
     * </p>
     *
     * @author zc
     * @since 2023-10-05
     */
    @Service
    @DS("work_performance")
    public class FdProcedureCheckCommentServiceImpl extends ServiceImpl<FdProcedureCheckCommentMapper, FdProcedureCheckComment> implements IFdProcedureCheckCommentService {
        @Resource
        private UserInternalService userInternalService;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 获取评论数量
         *
         * @param propertyId 资产 id
         * @param fdIds      FD Procedure Check ids
         * @return 评论数量
         * @author zc
         * @date 2023/10/6
         */
        @Override
        public Map<Long, Long> getCommentsCountByFdIds(int propertyId, List<Long> fdIds) {
            return list(new QueryWrapper<FdProcedureCheckComment>().lambda()
                    .in(FdProcedureCheckComment::getFdId, fdIds)
                    .eq(FdProcedureCheckComment::getPropertyId, propertyId)
                    .select(FdProcedureCheckComment::getFdId)).stream()
                    .collect(Collectors.groupingBy(FdProcedureCheckComment::getFdId,
                            Collectors.counting()));
        }

        /**
         * 删除 FD Procedure Check 下的评论
         *
         * @param fdId FD Procedure Check id
         * @author zc
         * @date 2023/10/6
         */
        @Override
        public void deleteByFdId(long fdId) {
            remove(new QueryWrapper<FdProcedureCheckComment>().lambda()
                    .eq(FdProcedureCheckComment::getFdId, fdId));
        }

        /**
         * 获取评论
         *
         * @param tenantId   租户 id
         * @param propertyId 资产 id
         * @param fdId       FD Procedure Check id
         * @return FdProcedureCheckCommentDTO 集合
         * @author zc
         * @date 2023/10/7
         */
        @Override
        public List<FdProcedureCheckCommentDTO> list(int tenantId, int propertyId, long fdId) {
            List<FdProcedureCheckComment> commentList = list(new QueryWrapper<FdProcedureCheckComment>().lambda()
                    .eq(FdProcedureCheckComment::getFdId, fdId)
                    .eq(FdProcedureCheckComment::getPropertyId, propertyId)
                    .orderByDesc(FdProcedureCheckComment::getId));
            if (CollectionUtils.isEmpty(commentList)) {
                return Collections.emptyList();
            }

            Set<Integer> userIds = commentList.stream().map(FdProcedureCheckComment::getCreatedBy)
                    .filter(item -> item > BaseConstant.ZERO).collect(Collectors.toSet());
            Map<Integer, UserDTO> userId2UserDTO = userInternalService.getUserMapByIds(tenantId, userIds);
            return beanMapper.mapList(commentList, FdProcedureCheckCommentDTO.class, item -> {
                UserDTO userDTO = userId2UserDTO.getOrDefault(item.getCreatedBy(), new UserDTO());
                item.setCreatedName(userDTO.getName());
                item.setAvatar(userDTO.getAvatar());
            });
        }

        /**
         * 新增评论
         *
         * @param propertyId 资产 id
         * @param fdId       FD Procedure Check id
         * @param operatorId 操作人 id
         * @param commentDTO 评论内容
         * @author zc
         * @date 2023/10/7
         */
        @Override
        public void save(int propertyId, long fdId, int operatorId, FdProcedureCheckCommentDTO commentDTO) {
            save(FdProcedureCheckComment.builder()
                    .propertyId(propertyId)
                    .fdId(fdId)
                    .comment(commentDTO.getComment())
                    .createdBy(operatorId)
                    .createdTime(DateTimeUtils.nowTimestamp())
                    .build());
        }

        /**
         * 校验是否存在
         *
         * @param id 评论 id
         * @return FdProcedureCheckComment
         * @author zc
         * @date 2023/10/7
         */
        @Override
        public FdProcedureCheckComment checkExist(long id) {
            FdProcedureCheckComment comment = getById(id);
            if (Objects.isNull(comment)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The comment cannot be found; id: " + id);
            }
            return comment;
        }

        /**
         * 校验归属
         *
         * @param propertyId 资产 id
         * @param fdId       FD Procedure Check id
         * @param comment    评论数据
         * @author zc
         * @date 2023/10/7
         */
        @Override
        public void checkBelong(int propertyId, long fdId, FdProcedureCheckComment comment) {
            if (!comment.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The comment does not belong to this property; propertyId:{0}; commentPropertyId:{1}",
                                propertyId, comment.getPropertyId()));
            }
            if (!comment.getFdId().equals(fdId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The comment does not belong to this FD Procedure check data; fdProcedureCheckId:{0}; commentFdId:{1}",
                                fdId, comment.getFdId()));
            }
        }

        /**
         * 校验评论是否可以删除
         *
         * @param handleResult FD Procedure Check 数据处理结果
         * @param comment      评论数据
         * @param operatorId   操作人 id
         * @author zc
         * @date 2023/10/7
         */
        @Override
        public void checkCanDelete(int handleResult, FdProcedureCheckComment comment, int operatorId) {
            // 只能删除自己创建的评论数据
            if (!comment.getCreatedBy().equals(operatorId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The comment is not created by the current login user; operatorId:{0}; createdBy:{1}",
                                operatorId, comment.getCreatedBy()));
            }

            // handleResult = 1: revise 时，必须至少保留一条评论数据
            if (handleResult == FdProcedureCheckHandledResultEnum.REVISE.getStatus()) {
                long count = count(new QueryWrapper<FdProcedureCheckComment>().lambda()
                        .eq(FdProcedureCheckComment::getFdId, comment.getFdId())
                        .ne(FdProcedureCheckComment::getId, comment.getId())
                        .eq(FdProcedureCheckComment::getPropertyId, comment.getPropertyId()));
                if (count == BaseConstant.LONG_ZERO) {
                    throw new BadRequestException(FdProcedureCheckErrorI18nConstant.REVISE_STATUS_MUST_LEAVE_ONE_COMMENT,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "The fdHandleResult is revise, so at least one must be kept");
                }
            }
        }
    }