# AdRequestCommentServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.AttachmentUtil;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.S3Utils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.frontoffice.cons.S3BucketFunctionCons;
    import cloud.wconnect.frontoffice.entity.adjustment.AdRequestComment;
    import cloud.wconnect.frontoffice.mapper.adjustment.AdRequestCommentMapper;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.AdRequestCommentDTO;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.AdjCommentCountDTO;
    import cloud.wconnect.frontoffice.pojo.vo.adjustment.AdRequestCommentVO;
    import cloud.wconnect.frontoffice.service.adjustment.IAdRequestCommentService;
    import cloud.wconnect.frontoffice.service.adjustment.IAdjSenderService;
    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.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;
    import java.util.concurrent.Executor;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-03-30
     */
    @Service
    @DS("logbook")
    public class AdRequestCommentServiceImpl extends ServiceImpl<AdRequestCommentMapper, AdRequestComment> implements IAdRequestCommentService {

        @Autowired
        private AdRequestCommentMapper adRequestCommentMapper;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private UserInternalService userInternalService;
        @Value("${aws-s3.region}")
        private String region;
        @Value("#{${aws-s3.function-bucket}}")
        private Map<String, Map<String, Object>> bucketMap;
        @Autowired
        private Executor executor;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private IAdjSenderService senderService;

        @Override
        public Map<Long, Long> getCounts(List<Long> adjIds) {
            if (CollectionUtils.isEmpty(adjIds)) {
                return Collections.emptyMap();
            }
            List<AdjCommentCountDTO> countList = adRequestCommentMapper.getCounts(adjIds);
            if (CollectionUtils.isEmpty(countList)) return Collections.emptyMap();
            return countList.stream()
                    .collect(Collectors.toMap(AdjCommentCountDTO::getArId, AdjCommentCountDTO::getCommentCount));
        }

        /**
         * 删除备注
         *
         * @param adjIds adjId集合
         * @author lichen
         * @date 2026/2/11
         */
        @Override
        public void removeByAdjIds(List<Long> adjIds) {
            if (CollectionUtils.isEmpty(adjIds)) return;
            remove(new LambdaQueryWrapper<AdRequestComment>().in(AdRequestComment::getArId, adjIds));
        }

        /**
         * 校验备注是否存在
         *
         * @param cid 备注id
         * @return void
         * @author lichen
         * @date 2023/9/27
         */
        @Override
        public AdRequestComment checkExist(long cid) {
            AdRequestComment comment = getById(cid);
            if (Objects.isNull(comment)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "Adjustment Requests comment not found, commentId=" + cid);
            }
            return comment;
        }

        /**
         * 修改备注
         *
         * @param oriComment 修改前的备注
         * @param commentDTO 修改后的备注
         * @return void
         * @author lichen
         * @date 2023/11/6
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(AdRequestComment oriComment, AdRequestCommentDTO commentDTO) {
            AdRequestComment adRequestComment = new AdRequestComment();
            adRequestComment.setId(commentDTO.getId());
            adRequestComment.setContent(commentDTO.getContent());
            adRequestComment.setAttachments(commentDTO.getAttachments());
            updateById(adRequestComment);

            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                //修改前的s3Key集合
                List<String> updateBeforeS3Keys = AttachmentUtil.getKeysByAbbrAttachmentArrayJson(oriComment.getAttachments(), objectMapper);
                //修改后的s3Key集合
                List<String> updateAfterS3Keys = AttachmentUtil.getKeysByAbbrAttachmentArrayJson(commentDTO.getAttachments(), objectMapper);
                //删除的附件 = 修改前的附件集合 - 修改后的附件集合
                List<String> delS3Keys = Lists.newArrayList(updateBeforeS3Keys);
                delS3Keys.removeAll(updateAfterS3Keys);
                S3Utils.batchDeleteFile(region, bucketMap.get(S3BucketFunctionCons.ADJUSTMENT), delS3Keys);

                // 发送修改备注消息
                senderService.publishSaveComment(oriComment.getPropertyId(), oriComment.getArId());
            });
        }

        /**
         * 保存备注
         *
         * @param propertyId 资产id
         * @param adjId      adjustment Id
         * @param commentDTO 备注
         * @param userId     用户id
         * @return void
         * @author lichen
         * @date 2025/12/27
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void save(int propertyId, Long adjId, AdRequestCommentDTO commentDTO, int userId) {
            AdRequestComment adRequestComment = new AdRequestComment();
            adRequestComment.setPropertyId(propertyId);
            adRequestComment.setArId(adjId);
            adRequestComment.setContent(commentDTO.getContent());
            adRequestComment.setCreatedBy(userId);
            adRequestComment.setCreatedTime(DateTimeUtils.nowTimestamp());
            adRequestComment.setAttachments(commentDTO.getAttachments());
            save(adRequestComment);

            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                senderService.publishSaveComment(propertyId, adjId);
            });
        }

        /**
         * 根据adjustmentId查询备注
         *
         * @param tenantId   租户id
         * @param propertyId 资产id
         * @param adjId      adjustment Id
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.adjustment.AdRequestCommentVO>
         * @author lichen
         * @date 2023/9/27
         */
        @Override
        public List<AdRequestCommentVO> listVOByAdjustmentId(Integer tenantId, int propertyId, long adjId) {

            //查询评论
            LambdaQueryWrapper<AdRequestComment> adRequestCommentQueryWrapper = new LambdaQueryWrapper<>();
            adRequestCommentQueryWrapper.eq(AdRequestComment::getPropertyId, propertyId);
            adRequestCommentQueryWrapper.eq(AdRequestComment::getArId, adjId);
            adRequestCommentQueryWrapper.orderByDesc(AdRequestComment::getId);
            List<AdRequestComment> commentList = list(adRequestCommentQueryWrapper);

            if (CollectionUtils.isEmpty(commentList)) return Collections.emptyList();

            //查询用户信息
            Set<Integer> userIds = commentList.stream().map(AdRequestComment::getCreatedBy).collect(Collectors.toSet());
            Map<Integer, UserDTO> userId2DTO = userInternalService.getUserMapByIds(tenantId, userIds);

            return beanMapper.mapList(commentList, AdRequestCommentVO.class, (comment, vo) -> {
                Integer createdBy = vo.getCreatedBy();

                UserDTO userDTO = userId2DTO.getOrDefault(createdBy, new UserDTO());
                vo.setCreatedName(userDTO.getName());
                vo.setAvatar(userDTO.getAvatar());
            });
        }

        /**
         * 删除备注
         *
         * @param comment 备注
         * @return void
         * @author lichen
         * @date 2023/9/27
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void deleteById(AdRequestComment comment) {
            boolean result = removeById(comment.getId());
            if (result) {
                //删除附件
                List<String> delS3Keys = AttachmentUtil.getKeysByAbbrAttachmentArrayJson(comment.getAttachments(), objectMapper);
                S3Utils.batchDeleteFile(region, bucketMap.get(S3BucketFunctionCons.ADJUSTMENT), delS3Keys);

                TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                    senderService.publishSaveComment(comment.getPropertyId(), comment.getArId());
                });
            }
        }

        /**
         * 根据adjustmentId查询备注
         *
         * @param adjIds adjustment Id集合
         * @return java.util.List<cloud.wconnect.frontoffice.entity.adjustment.AdRequestComment>
         * @author lichen
         * @date 2023/9/27
         */
        @Override
        public List<AdRequestComment> listByAdjustmentId(List<Long> adjIds) {
            if (CollectionUtils.isEmpty(adjIds)) return Collections.emptyList();
            return list(new LambdaQueryWrapper<AdRequestComment>()
                    .in(AdRequestComment::getArId, adjIds)
                    .orderByDesc(AdRequestComment::getId));
        }
    }