# HotelKpiStrMonthServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.cons.S3BucketFunctionCons;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiStrMonth;
    import cloud.wconnect.workperformance.mapper.hotelkpi.HotelKpiStrMonthMapper;
    import cloud.wconnect.workperformance.pojo.bo.hotelkpi.str.month.HotelKpiStrMonthBO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.strdata.month.HotelKpiStrMonthDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.strdata.month.HotelKpiStrMonthDateDTO;
    import cloud.wconnect.workperformance.service.AmazonS3Service;
    import cloud.wconnect.workperformance.service.hotelkpi.IHotelKpiStrMonthService;
    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 jakarta.annotation.Resource;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.collections4.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Service;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Collections;
    import java.util.List;

    /**
     * <p>
     * Hotel KPI STR Month Data 服务实现类
     * </p>
     *
     * @author zc
     * @since 2025-08-22
     */
    @Slf4j
    @Service
    @DS("work_performance")
    public class HotelKpiStrMonthServiceImpl extends ServiceImpl<HotelKpiStrMonthMapper, HotelKpiStrMonth> implements IHotelKpiStrMonthService {

        @Resource
        private AmazonS3Service amazonS3Service;
        @Resource
        private ObjectMapper objectMapper;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 根据日期集合获取数据
         *
         * @param propertyId 资产 id
         * @param dateList   日期集合（yyyyMMdd）
         * @return HotelKpiStrMonthDateDTO 集合
         * @author zc
         * @date 2025/8/22
         */
        @Override
        public List<HotelKpiStrMonthDateDTO> listByDates(int propertyId, List<Long> dateList) {
            if (CollectionUtils.isEmpty(dateList)) {
                return Collections.emptyList();
            }
            List<HotelKpiStrMonth> list = list(new LambdaQueryWrapper<HotelKpiStrMonth>()
                    .eq(HotelKpiStrMonth::getPropertyId, propertyId)
                    .in(HotelKpiStrMonth::getDate, dateList));
            if (CollectionUtils.isEmpty(list)) {
                return Collections.emptyList();
            }
            return list.stream().map(item -> {
                HotelKpiStrMonthDTO valueDTO = JsonUtils.convertStringToObject(objectMapper,
                        item.getDetail(), HotelKpiStrMonthDTO.class);
                return new HotelKpiStrMonthDateDTO().setDate(item.getDate())
                        .setReportDate(item.getDataDate())
                        .setFileUrl(item.getFileUrl())
                        .setValue(valueDTO);
            }).toList();
        }

        /**
         * 根据日期范围获取数据
         *
         * @param propertyId 资产 id
         * @param startDate  开始日期（yyyyMMdd）
         * @param endDate    结束日期（yyyyMMdd）
         * @return HotelKpiStrMonthDateDTO 集合
         * @author zc
         * @date 2025/9/11
         */
        @Override
        public List<HotelKpiStrMonthDateDTO> listByDateRange(int propertyId, long startDate, long endDate) {
            List<HotelKpiStrMonth> list = list(new LambdaQueryWrapper<HotelKpiStrMonth>()
                    .eq(HotelKpiStrMonth::getPropertyId, propertyId)
                    .between(HotelKpiStrMonth::getDate, startDate, endDate));
            if (CollectionUtils.isEmpty(list)) {
                return Collections.emptyList();
            }
            return list.stream().map(item -> {
                HotelKpiStrMonthDTO valueDTO = JsonUtils.convertStringToObject(objectMapper,
                        item.getDetail(), HotelKpiStrMonthDTO.class);
                return new HotelKpiStrMonthDateDTO().setDate(item.getDate())
                        .setReportDate(item.getDataDate())
                        .setFileUrl(item.getFileUrl())
                        .setValue(valueDTO);
            }).toList();
        }

        /**
         * 处理 STR 月报
         *
         * @param propertyDTO 资产信息
         * @param bo          数据
         * @param path        文件路径
         * @author zc
         * @date 2025/8/22
         */
        @Override
        public void saveData(PropertyDTO propertyDTO, HotelKpiStrMonthBO bo, String path) {
            // 上传文件到 S3
            uploadReport(path);

            HotelKpiStrMonth strMonth = new HotelKpiStrMonth();
            strMonth.setPropertyId(propertyDTO.getId());
            strMonth.setDate(bo.getDataDate());
            strMonth.setDataDate(bo.getDataDate());
            strMonth.setFileUrl(path);
            strMonth.setDetail(JsonUtils.convertObjToString(objectMapper,
                    beanMapper.map(bo, HotelKpiStrMonthDTO.class)));

            // 保存数据
            baseMapper.insertOrUpdateByUnique(strMonth);
        }

        /**
         * 上传报告，用于点击指标下载报告
         *
         * @param fileUrl S3 路径
         * @author zc
         * @date 2025/8/22
         */
        private void uploadReport(String fileUrl) {
            if (StringUtils.isBlank(fileUrl)) {
                return;
            }
            try (InputStream in = amazonS3Service.getFile(fileUrl)) {
                amazonS3Service.uploadFile(S3BucketFunctionCons.HOTEL_KPI, in, fileUrl);
            } catch (IOException e) {
                log.error("HotelKpiStrMonthServiceImpl Upload Str report error. fileUrl: {}", fileUrl, e);
            }
        }
    }