# HKEfficiencyController.java

    package cloud.wconnect.workperformance.controller.hkefficiency;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.pojo.dto.hkefficiency.HkEfficiencyDTO;
    import cloud.wconnect.workperformance.pojo.dto.hkefficiency.HkEfficiencyPropertyDTO;
    import cloud.wconnect.workperformance.pojo.dto.hkefficiency.HkEfficiencyTotalDTO;
    import cloud.wconnect.workperformance.pojo.query.hkefficiency.HkEfficiencyListQuery;
    import cloud.wconnect.workperformance.service.hkefficiency.IHkEfficiencyService;
    import com.google.common.collect.Sets;
    import jakarta.annotation.Resource;
    import jakarta.validation.Valid;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;

    import java.text.MessageFormat;
    import java.time.LocalDate;
    import java.time.temporal.ChronoUnit;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 控制器类：Housekeeping Efficiency
     * </p>
     *
     * @author zc
     * @since 2023-03-29
     */
    @Validated
    @RestController
    @RequestMapping("/housekeeping-efficiency")
    public class HKEfficiencyController {
        @Resource
        private IHkEfficiencyService hkEfficiencyService;
        @Resource
        private PropertyI18nRedisService propertyI18nRedisService;
        @Resource
        private SessionContext sessionContext;
        @Resource
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 获取指定时间区间的 Housekeeping Efficiency 数据
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return Housekeeping Efficiency 数据
         * @author zc
         * @date 2023/3/29
         */
        @ApiId(207)
        @GetMapping
        public ListPagedDTO<HkEfficiencyDTO> list(@RequestParam String property, @Valid HkEfficiencyListQuery query) {
            // 校验查询时间区间
            dateParamCheck(query.getStartDate(), query.getEndDate());
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            return hkEfficiencyService.list(propertyDTO, query);
        }

        /**
         * 获取时间段内 Total
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return HousekeepingEfficiencyTotalDTO
         * @author zc
         * @date 2023/12/14
         */
        @ApiId(1003)
        @GetMapping("/total")
        public HkEfficiencyTotalDTO getWorkHour(@RequestParam String property, @Valid HkEfficiencyListQuery query) {
            // 校验查询时间区间
            dateParamCheck(query.getStartDate(), query.getEndDate());
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            // 当前列表数据
            List<HkEfficiencyDTO> hkEfficiencyDTOList = hkEfficiencyService.list(propertyDTO, query).getList();
            return hkEfficiencyService.getTotal(propertyDTO, hkEfficiencyDTOList);
        }

        /**
         * 保存 Housekeeping Efficiency 数据
         *
         * @param property 资产标识
         * @param list     Housekeeping Efficiency 数据
         * @return empty map
         * @author zc
         * @date 2023/3/29
         */
        @ApiId(208)
        @PostMapping
        public Map<Object, Object> save(@RequestParam String property, @RequestBody List<@Valid HkEfficiencyDTO> list) {
            if (CollectionUtils.isEmpty(list)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("saveList"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The list cannot be empty");
            }
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            hkEfficiencyService.save(propertyDTO, sessionContext.getLoginUserId(), list);
            return Collections.emptyMap();
        }

        /**
         * 获取统计查询数据
         *
         * @param yearRange       所选年范围
         * @param propertyIdRange 所选 property 范围
         * @return 统计查询数据
         * @author zc
         * @date 2023/3/29
         */
        @ApiId(209)
        @GetMapping("/statistics")
        public List<HkEfficiencyPropertyDTO> statistics(@RequestParam String yearRange, @RequestParam String propertyIdRange) {
            if (StringUtils.isBlank(yearRange)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("yearRange"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The yearRange cannot be blank");
            }
            if (StringUtils.isBlank(propertyIdRange)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("propertyIdRange"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The propertyIdRange cannot be blank");
            }
            List<Integer> queryPropertyIds = Arrays.stream(StringUtils.split(propertyIdRange, ","))
                    .map(Integer::parseInt).toList();
            if (!Sets.newHashSet(sessionContext.getPropertyIds()).containsAll(queryPropertyIds)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        "Cannot be operated others property data; propertyIds: " + queryPropertyIds);
            }
            List<PropertyDTO> propertyDTOList = propertyI18nRedisService.list(queryPropertyIds);
            List<Integer> years = Arrays.stream(yearRange.split(","))
                    .map(Integer::parseInt).collect(Collectors.toList());
            return hkEfficiencyService.listStatistics(years, propertyDTOList);
        }

        /**
         * 校验日期查询条件
         *
         * @param startDate 开始时间
         * @param endDate   结束时间
         * @author zc
         * @date 2023/12/14
         */
        private void dateParamCheck(long startDate, long endDate) {
            if (startDate > endDate) {
                throw new BadRequestException(CommonErrorI18nConstant.START_DATE_CANNOT_GREATER_THAN_END_DATE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The startDate cannot be greater than endDate; startDate:{0}, endDate:{1}",
                                startDate, endDate));
            }
            // 校验开始时间与结束时间区间不能超过 400 天
            LocalDate startLocalDate = DateTimeUtils.strToLocalDate(String.valueOf(startDate), BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate endLocalDate = DateTimeUtils.strToLocalDate(String.valueOf(endDate), BaseConstant.DATE_FORMAT_YYYYMMDD);
            if (ChronoUnit.DAYS.between(startLocalDate, endLocalDate) + 1 > 400) {
                throw new BadRequestException(CommonErrorI18nConstant.SELECT_DATE_LIMIT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(400),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The startDate and endDate intervals cannot exceed 400 days; startDate:{0}, endDate:{1}",
                                startDate, endDate));
            }
        }
    }