# HotelKpiHistoryAndForecastServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiHistoryAndForecast;
    import cloud.wconnect.workperformance.mapper.hotelkpi.HotelKpiHistoryAndForecastMapper;
    import cloud.wconnect.workperformance.pojo.bo.hotelkpi.HotelKpiHistoryAndForecastBO;
    import cloud.wconnect.workperformance.service.hotelkpi.IHotelKpiHistoryAndForecastService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import jakarta.annotation.Resource;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.time.LocalDate;
    import java.util.Comparator;
    import java.util.List;

    /**
     * <p>
     * Hotel KPI history and forecast 数据 服务实现类
     * </p>
     *
     * @author zc
     * @since 2024-07-10
     */
    @Service
    @DS("work_performance")
    public class HotelKpiHistoryAndForecastServiceImpl extends ServiceImpl<HotelKpiHistoryAndForecastMapper, HotelKpiHistoryAndForecast> implements IHotelKpiHistoryAndForecastService {

        @Resource
        private BeanMapper beanMapper;

        /**
         * 保存数据
         *
         * @param propertyId               资产 id
         * @param historyAndForecastBOList 数据集合
         * @author zc
         * @date 2024/7/10
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void insertOrUpdateBatch(int propertyId, List<HotelKpiHistoryAndForecastBO> historyAndForecastBOList) {
            if (CollectionUtils.isEmpty(historyAndForecastBOList)) {
                return;
            }
            List<HotelKpiHistoryAndForecast> list = beanMapper.mapList(historyAndForecastBOList,
                    HotelKpiHistoryAndForecast.class, (bo, entity) -> {
                        entity.setPropertyId(propertyId);
                        LocalDate localDate = DateTimeUtils.strToLocalDate(bo.getDateStr(), BaseConstant.DATE_FORMAT_YYYY_MM_DD);
                        entity.setDate(Long.parseLong(DateTimeUtils.localDateToStr(localDate, BaseConstant.DATE_FORMAT_YYYYMMDD)));
                    });

            // 按唯一索引字段排序，避免死锁
            list.sort(Comparator.comparing(HotelKpiHistoryAndForecast::getPropertyId)
                    .thenComparing(HotelKpiHistoryAndForecast::getDate));

            baseMapper.insertOrUpdateBatchByUnique(list);
        }

        /**
         * 获取指定日期范围内的数据
         *
         * @param propertyId 资产ID
         * @param startDate  开始日期（yyyyMMdd）
         * @param endDate    结束日期（yyyyMMdd）
         * @return 指定日期范围内的数据
         * @author zc
         * @date 2025/9/1
         */
        @Override
        public List<HotelKpiHistoryAndForecast> listByDateRange(int propertyId, long startDate, long endDate) {
            return list(new LambdaQueryWrapper<HotelKpiHistoryAndForecast>()
                    .between(HotelKpiHistoryAndForecast::getDate, startDate, endDate)
                    .eq(HotelKpiHistoryAndForecast::getPropertyId, propertyId));
        }
    }