# GmwrHotelKpiServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.cons.gmwr.GmwrHotelKpiCategoryEnum;
    import cloud.wconnect.workperformance.entity.gmwr.GmwrHotelKpi;
    import cloud.wconnect.workperformance.entity.gmwr.GmwrHotelKpiNote;
    import cloud.wconnect.workperformance.entity.gmwr.GmwrWeeks;
    import cloud.wconnect.workperformance.mapper.gmwr.GmwrHotelKpiMapper;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.GmwrHotelKpiItemDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.basic.GmwrHotelKpiBasicDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.basic.GmwrHotelKpiBasicItemDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.basic.GmwrHotelKpiBasicMetricsDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.note.GmwrHotelKpiSyncDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.note.GmwrNoteDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.internal.kpidata.HotelKpiInternalDTO;
    import cloud.wconnect.workperformance.service.gmwr.IGmwrHotelKpiNoteService;
    import cloud.wconnect.workperformance.service.gmwr.IGmwrHotelKpiService;
    import cloud.wconnect.workperformance.service.gmwr.IGmwrHotelKpiViewConfigService;
    import cloud.wconnect.workperformance.service.hotelkpi.internal.IHotelKpiInternalService;
    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 jakarta.annotation.Resource;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;

    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * <p>
     * GM Weekly Report Hotel KPI 服务实现类
     * </p>
     *
     * @author zc
     * @since 2024-10-12
     */
    @Service
    @DS("work_performance")
    public class GmwrHotelKpiServiceImpl extends ServiceImpl<GmwrHotelKpiMapper, GmwrHotelKpi> implements IGmwrHotelKpiService {
        @Resource
        private IGmwrHotelKpiNoteService hotelKpiNoteService;
        @Resource
        private IGmwrHotelKpiViewConfigService hotelKpiViewConfigService;
        @Resource
        private IHotelKpiInternalService hotelKpiInternalService;
        @Resource
        private UserInternalService userInternalService;
        @Resource
        private ObjectMapper objectMapper;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 生成 Hotel KPI 数据
         *
         * @param propertyDTO 资产
         * @param gmwrWeeks   周报
         * @author zc
         * @date 2024/10/19
         */
        @Override
        public void generate(PropertyDTO propertyDTO, GmwrWeeks gmwrWeeks) {
            // 获取显示配置
            List<Integer> viewMetricsTypeList = hotelKpiViewConfigService.listViewConfig(propertyDTO.getId(), null);
            if (CollectionUtils.isEmpty(viewMetricsTypeList)) {
                return;
            }

            List<HotelKpiInternalDTO> hotelKpiInternalDTOList = hotelKpiInternalService.listForWeekly(propertyDTO.getId(),
                    gmwrWeeks.getWeek(), gmwrWeeks.getWeek());
            if (CollectionUtils.isEmpty(hotelKpiInternalDTOList)) {
                return;
            }

            List<GmwrHotelKpiBasicDetailDTO> details = beanMapper.mapList(hotelKpiInternalDTOList.get(0).getDetails(),
                    GmwrHotelKpiBasicDetailDTO.class);
            for (GmwrHotelKpiBasicDetailDTO hotelKpiBasicDetailDTO : details) {
                List<GmwrHotelKpiBasicItemDTO> items = Lists.newArrayList(hotelKpiBasicDetailDTO.getItems());
                for (GmwrHotelKpiBasicItemDTO hotelKpiBasicItemDTO : items) {
                    List<GmwrHotelKpiBasicMetricsDTO> metrics = Lists.newArrayList(hotelKpiBasicItemDTO.getMetrics());
                    metrics.removeIf(metric -> !viewMetricsTypeList.contains(metric.getMetricsType()));
                    hotelKpiBasicItemDTO.setMetrics(metrics);
                }
                items.removeIf(item -> CollectionUtils.isEmpty(item.getMetrics()));
                hotelKpiBasicDetailDTO.setItems(items);
            }
            details.removeIf(detail -> CollectionUtils.isEmpty(detail.getItems()));

            GmwrHotelKpi hotelKpi = new GmwrHotelKpi();
            hotelKpi.setPropertyId(propertyDTO.getId());
            hotelKpi.setReportId(gmwrWeeks.getId());
            hotelKpi.setDetail(JsonUtils.convertObjListToString(objectMapper, details));
            baseMapper.insertOrUpdateByUnique(hotelKpi);
        }

        /**
         * 同步 Hotel KPI
         *
         * @param propertyId 资产 id
         * @param gmwrWeeks  周报
         * @param syncDTO    同步数据
         * @author zc
         * @date 2025/4/28
         */
        @Override
        public void sync(int propertyId, GmwrWeeks gmwrWeeks, GmwrHotelKpiSyncDTO syncDTO) {
            // 提取分类名称
            String categoryTitle = GmwrHotelKpiCategoryEnum.getTitle(syncDTO.getCategory());
            List<GmwrHotelKpiBasicDetailDTO> weeklyReportHotelKpiList = listHotelKpiBasic(gmwrWeeks.getId());
            weeklyReportHotelKpiList.removeIf(detail -> Objects.equals(detail.getTitle(), categoryTitle));

            // 获取 Hotel KPI 数据
            HotelKpiInternalDTO hotelKpiInternalDTO = hotelKpiInternalService.listForWeekly(propertyId,
                    gmwrWeeks.getWeek(), gmwrWeeks.getWeek()).stream().findFirst().orElse(null);
            List<GmwrHotelKpiBasicDetailDTO> hotelKpiList;
            if (Objects.isNull(hotelKpiInternalDTO)) {
                hotelKpiList = Lists.newArrayList();
            } else {
                hotelKpiList = beanMapper.mapList(hotelKpiInternalDTO.getDetails(),
                        GmwrHotelKpiBasicDetailDTO.class);
            }
            // 获取指定分类的显示配置
            List<Integer> viewMetricsTypeList = hotelKpiViewConfigService.listViewConfig(propertyId, syncDTO.getCategory());

            // 移除未显示的指标
            for (GmwrHotelKpiBasicDetailDTO hotelKpiBasicDetailDTO : hotelKpiList) {
                List<GmwrHotelKpiBasicItemDTO> items = Lists.newArrayList(hotelKpiBasicDetailDTO.getItems());
                for (GmwrHotelKpiBasicItemDTO hotelKpiBasicItemDTO : items) {
                    List<GmwrHotelKpiBasicMetricsDTO> metrics = Lists.newArrayList(hotelKpiBasicItemDTO.getMetrics());
                    metrics.removeIf(metric -> !viewMetricsTypeList.contains(metric.getMetricsType()));
                    hotelKpiBasicItemDTO.setMetrics(metrics);
                }
                items.removeIf(item -> CollectionUtils.isEmpty(item.getMetrics()));
                hotelKpiBasicDetailDTO.setItems(items);
            }
            hotelKpiList.removeIf(detail -> CollectionUtils.isEmpty(detail.getItems()));

            weeklyReportHotelKpiList.addAll(hotelKpiList);

            GmwrHotelKpi hotelKpi = new GmwrHotelKpi();
            hotelKpi.setPropertyId(propertyId);
            hotelKpi.setReportId(gmwrWeeks.getId());
            hotelKpi.setDetail(JsonUtils.convertObjListToString(objectMapper, weeklyReportHotelKpiList));
            baseMapper.insertOrUpdateByUnique(hotelKpi);
        }

        /**
         * 获取 Hotel KPI 数据
         *
         * @param tenantId      租户 id
         * @param reportId      周报 id
         * @param categoryTitle Hotel KPI 分类名称
         * @return GmwrHotelKpiItemDTO 集合
         * @author zc
         * @date 2024/12/30
         */
        @Override
        public List<GmwrHotelKpiItemDTO> list(int tenantId, int reportId, String categoryTitle) {
            List<GmwrHotelKpiBasicDetailDTO> basicDetailDTOList = listHotelKpiBasic(reportId).stream()
                    .filter(detail -> Objects.equals(detail.getTitle(), categoryTitle)).toList();
            if (CollectionUtils.isEmpty(basicDetailDTOList)) {
                return Collections.emptyList();
            }

            // 获取备注
            List<GmwrHotelKpiNote> noteList = hotelKpiNoteService.listByReportId(reportId);
            Map<Integer, GmwrHotelKpiNote> category2Note = noteList.stream()
                    .collect(Collectors.toMap(GmwrHotelKpiNote::getCategory, Function.identity()));
            // 获取操作人名称
            Set<Integer> userIds = noteList.stream().map(GmwrHotelKpiNote::getUpdatedBy).collect(Collectors.toSet());
            Map<Integer, String> userId2Name = userInternalService.getNameMapByIds(tenantId, userIds);

            return beanMapper.mapList(basicDetailDTOList.get(0).getItems(), GmwrHotelKpiItemDTO.class, item ->
                    item.getMetrics().forEach(metric -> {
                        // 设置备注
                        GmwrHotelKpiNote note = category2Note.get(metric.getMetricsType());
                        if (Objects.nonNull(note)) {
                            GmwrNoteDTO noteDTO = beanMapper.map(note, GmwrNoteDTO.class, dto ->
                                    dto.setUpdatedName(userId2Name.get(dto.getUpdatedBy())));
                            metric.setNote(noteDTO);
                        }
                    })
            );
        }

        /**
         * 获取 Hotel KPI Basic 数据
         *
         * @param reportId 周报 id
         * @return GmwrHotelKpiBasicDetailDTO 集合
         * @author zc
         * @date 2024/11/6
         */
        @Override
        public List<GmwrHotelKpiBasicDetailDTO> listHotelKpiBasic(int reportId) {
            GmwrHotelKpi hotelKpi = getByReportId(reportId);
            if (Objects.isNull(hotelKpi)) {
                return Lists.newArrayList();
            }
            return JsonUtils.convertStringToList(objectMapper, hotelKpi.getDetail(), GmwrHotelKpiBasicDetailDTO.class);
        }

        /**
         * 根据周报 id 获取 Hotel KPI 数据
         *
         * @param reportId 周报 id
         * @return GmwrHotelKpi
         * @author zc
         * @date 2024/11/6
         */
        @Override
        public GmwrHotelKpi getByReportId(int reportId) {
            return getOne(new LambdaQueryWrapper<GmwrHotelKpi>()
                    .eq(GmwrHotelKpi::getReportId, reportId));
        }
    }