# LogbookServiceImpl.java

    package cloud.wconnect.frontoffice.service.logbook.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.ListPagedDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.frontoffice.entity.logbook.Logbook;
    import cloud.wconnect.frontoffice.entity.logbook.LogbookResolveResult;
    import cloud.wconnect.frontoffice.mapper.logbook.LogbookMapper;
    import cloud.wconnect.frontoffice.pojo.dto.logbook.*;
    import cloud.wconnect.frontoffice.pojo.query.logbook.LogbookQuery;
    import cloud.wconnect.frontoffice.pojo.query.logbook.PrintQuery;
    import cloud.wconnect.frontoffice.service.logbook.ILogbookResolveResultService;
    import cloud.wconnect.frontoffice.service.logbook.ILogbookService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
    import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author yyt
     * @since 2023-03-18
     */
    @Service
    @DS("logbook")
    public class LogbookServiceImpl extends ServiceImpl<LogbookMapper, Logbook> implements ILogbookService {

        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private ILogbookResolveResultService logbookResolveResultService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private UserInternalService userInternalService;

        /**
         * 新增 logbook
         *
         * @param propertyId 资产 id
         * @param logbookDTO logbook 内容
         * @param userId     操作人
         * @author yyt
         * @date 2023/3/18
         */
        @Override
        public Logbook saveLogbook(int propertyId, UpdateLogbookDTO logbookDTO, int userId) {
            Logbook logbook = beanMapper.map(logbookDTO, Logbook.class);
            logbook.setPropertyId(propertyId);
            logbook.setCreateId(userId);
            logbook.setCreateTime(DateTimeUtils.nowTimestamp());
            save(logbook);

            return logbook;
        }

        /**
         * 修改 logbook
         *
         * @param updateBeforeLogbook 修改之前的 logbook
         * @param logbookDTO          logbook 内容
         * @param userId              操作人
         * @author yyt
         * @date 2023/3/18
         */
        @Override
        public void updateLogbook(Logbook updateBeforeLogbook, UpdateLogbookDTO logbookDTO, int userId) {
            LambdaUpdateWrapper<Logbook> updateWrapper = new UpdateWrapper<Logbook>().lambda()
                    .eq(Logbook::getId, updateBeforeLogbook.getId())
                    .set(Logbook::getPriority, logbookDTO.getPriority())
                    .set(Logbook::getCategory, logbookDTO.getCategory())
                    .set(Logbook::getMood, logbookDTO.getMood())
                    .set(Logbook::getRoom, logbookDTO.getRoom())
                    .set(Logbook::getCustomer, logbookDTO.getCustomer())
                    .set(Logbook::getContent, logbookDTO.getContent())
                    .set(Logbook::getCheckinDate, logbookDTO.getCheckinDate());
            if (updateBeforeLogbook.getStatus()) {
                // 如果 logbook 已经 resolve 过，则重新更新 resolve 操作人、操作时间
                updateWrapper.set(Logbook::getComplateId, userId).set(Logbook::getComplateTime, DateTimeUtils.nowTimestamp());
            }
            update(updateWrapper);
        }

        /**
         * 校验 logbook 存在
         *
         * @param id 主键 id
         * @return logbook
         * @author yyt
         * @date 2023/3/20
         */
        @Override
        public Logbook checkLogbookExist(int id) {
            Logbook logbook = getById(id);
            if (logbook == null) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the logbook is not found;id:" + id);
            }
            return logbook;
        }

        /**
         * 统计 logbook 数量
         *
         * @param propertyId 资产 id
         * @param status     状态（false:未解决，true:已解决）
         * @return logbook 数量
         * @author yyt
         * @date 2023/3/20
         */
        @Override
        public List<LogbookCountDTO> count(int propertyId, boolean status) {
            return baseMapper.count(propertyId, status);
        }

        /**
         * 修改 logbook 状态
         *
         * @param id                     logbook id
         * @param updateLogbookStatusDTO 修改状态信息
         * @param userId                 操作人
         * @return logbook
         * @author yyt
         * @date 2023/3/21
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Logbook updateStatus(int id, UpdateLogbookStatusDTO updateLogbookStatusDTO, int userId) {
            Logbook logbook = getOne(new QueryWrapper<Logbook>().lambda().eq(Logbook::getId, id).last(" for update "));
            if (logbook.getStatus().equals(updateLogbookStatusDTO.getStatus())) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_UPDATE_FAILED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "failed to update the data that maybe removed or updated by others;id:" + id);
            }

            Logbook updateContent = new Logbook();
            updateContent.setId(id);
            updateContent.setStatus(updateLogbookStatusDTO.getStatus());
            if (!updateLogbookStatusDTO.getStatus()) {
                updateContent.setComplateId(0);
                updateContent.setComplateTime(0L);
            } else {
                updateContent.setComplateId(userId);
                updateContent.setComplateTime(DateTimeUtils.nowTimestamp());

                LogbookResolveResult logbookResolveResult = beanMapper.map(updateLogbookStatusDTO, LogbookResolveResult.class);
                logbookResolveResult.setLogbookId(id);
                logbookResolveResult.setPropertyId(logbook.getPropertyId());
                logbookResolveResultService.saveOrUpdateForUK(logbookResolveResult);
            }
            updateById(updateContent);

            logbook.setStatus(updateContent.getStatus()).setComplateId(updateContent.getComplateId())
                    .setComplateTime(updateContent.getComplateTime());
            return logbook;
        }

        /**
         * 获取打印数据
         *
         * @param printQuery 查询条件
         * @param propertyId 资产 id
         * @return logbook 数据
         * @author yyt
         * @date 2023/3/21
         */
        @Override
        public List<LogbookDTO> getPrintData(PrintQuery printQuery, int propertyId) {
            // 创建时间倒序
            List<Logbook> logbooks = baseMapper.selectList(new QueryWrapper<Logbook>().lambda()
                    .eq(Objects.nonNull(printQuery.getCategory()), Logbook::getCategory, printQuery.getCategory())
                    .eq(Logbook::getPropertyId, propertyId)
                    .eq(Objects.nonNull(printQuery.getStatus()), Logbook::getStatus, printQuery.getStatus())
                    .orderByDesc(Logbook::getCreateTime));
            if (logbooks.isEmpty()) {
                return Collections.emptyList();
            }

            List<Integer> userIds = logbooks.stream().flatMap(item -> Stream.of(item.getCreateId(), item.getComplateId()))
                    .collect(Collectors.toList());
            Map<Integer, String> userNameById = userInternalService.getNameMapByIds(propertyI18nRedisService.get(propertyId).getTenantId(), userIds);

            return beanMapper.mapList(logbooks, LogbookDTO.class,
                    item -> {
                        item.setCreateName(userNameById.get(item.getCreateId()));
                        item.setComplateName(userNameById.get(item.getComplateId()));
                    });
        }

        /**
         * 根据 id 查询 logbook
         *
         * @param id logbook id
         * @return logbook
         * @author yyt
         * @date 2023/4/6
         */
        @Override
        public Logbook getByIdForUpdate(int id) {
            Logbook logbook = getOne(new QueryWrapper<Logbook>().lambda().eq(Logbook::getId, id).last("for update"));
            if (Objects.isNull(logbook)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the logbook is not found;id:" + id);
            }
            return logbook;
        }

        /**
         * 查询 logbook
         *
         * @param query 查询条件
         * @return logbook
         * @author yyt
         * @date 2024/2/8
         **/
        @Override
        public Page<Logbook> page(LogbookQuery query) {
            return baseMapper.selectPage(new Page<>(query.getPage(), query.getSize()), query);
        }

        /**
         * 分页查询 logbook
         *
         * @param propertyId   资产 id
         * @param logbookQuery 查询条件
         * @return logbook
         * @author yyt
         * @date 2026/1/16
         **/
        @Override
        public ListPagedDTO<LogbookDTO> listPage(int propertyId, LogbookQuery logbookQuery) {
            logbookQuery.setPropertyId(propertyId);
            Page<Logbook> logbookPage = page(logbookQuery);

            List<Logbook> logbooks = logbookPage.getRecords();
            Map<Integer, Long> deliveryTimeByLogbookId = Collections.emptyMap();
            if (CollectionUtils.isNotEmpty(logbooks)) {
                deliveryTimeByLogbookId = logbookResolveResultService.getByLogbookIds(logbooks.stream()
                                .map(Logbook::getId).collect(Collectors.toList()))
                        .stream().filter(item -> Objects.nonNull(item.getTheDate()))
                        .collect(Collectors.toMap(LogbookResolveResult::getLogbookId, LogbookResolveResult::getTheDate));
            }
            Map<Integer, Long> finalDeliveryTimeByLogbookId = deliveryTimeByLogbookId;
            return new ListPagedDTO<>(logbookPage.getTotal(), beanMapper.mapList(logbooks, LogbookDTO.class,
                    item -> item.setDeliveryTime(finalDeliveryTimeByLogbookId.get(item.getId()))));
        }

        /**
         * 获取 logbook 详情
         *
         * @param logbook logbook
         * @return logbook 详情
         * @author yyt
         * @date 2026/1/16
         **/
        @Override
        public LogbookDTO getDetail(Logbook logbook) {
            LogbookDTO logbookDTO = beanMapper.map(logbook, LogbookDTO.class);

            LogbookResolveResult logbookResolveResult = logbookResolveResultService.getByLogbookId(logbook.getId());
            if (logbookResolveResult != null) {
                logbookDTO.setResolveResult(beanMapper.map(logbookResolveResult, LogbookResolveResultDTO.class));
            }

            return logbookDTO;
        }

    }