# ScoreCardGmController.java

    package cloud.wconnect.workperformance.controller.scorecardgm;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    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.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.entity.scorecardgm.ScoreCardGmConfig;
    import cloud.wconnect.workperformance.pojo.dto.scorecardgm.*;
    import cloud.wconnect.workperformance.service.scorecardgm.IScoreCardGmConfigService;
    import cloud.wconnect.workperformance.service.scorecardgm.IScoreCardGmService;
    import jakarta.validation.Valid;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;

    import java.time.YearMonth;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     * <p>
     *  前端控制器
     * </p>
     *
     * @author yyt
     * @since 2023-10-04
     */
    @Validated
    @RestController
    @RequestMapping("/score-card-gm")
    public class ScoreCardGmController {

        @Autowired
        private IScoreCardGmService scoreCardGmService;
        @Autowired
        private IScoreCardGmConfigService scoreCardGmConfigService;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * Total Score 列表
         *
         * @param year     年
         * @param property 资产标识
         * @return Total Score 列表
         * @author yyt
         * @date 2023/10/4
         */
        @ApiId(776)
        @GetMapping
        public List<TotalScoreDTO> listTotalScore(@RequestParam Integer year, @RequestParam String property) {
            return scoreCardGmService.listTotalScore(sessionContext.getPropertyId(property), year);
        }

        /**
         * 查看 Score Card 详情
         *
         * @param year     年
         * @param month    月
         * @param property 资产标识
         * @return ScoreCard 详情
         * @author yyt
         * @date 2023/10/4
         */
        @ApiId(777)
        @GetMapping("/{year:\\d+}/{month:\\d+}")
        public ScoreCardGmDTO getDetail(@PathVariable int year, @PathVariable int month, String property) {
            checkYearMonth(year, month);

            Integer propertyId = sessionContext.getPropertyId(property);
            return scoreCardGmService.getDetail(propertyId, year, month);
        }

        /**
         * 输入 Actual 和 Target，返回计算结果
         *
         * @param property        资产标识
         * @param actualTargetDTO Actual 和 Target
         * @return 计算结果
         * @author yyt
         * @date 2023/10/5
         */
        @ApiId(778)
        @PutMapping("/calculation-result")
        public CalculationResultDTO getResult(String property, @Valid @RequestBody ActualTargetDTO actualTargetDTO) {
            Integer propertyId = sessionContext.getPropertyId(property);
            List<Integer> ids = actualTargetDTO.getConfigList().stream().map(UpdateItemDTO::getId).collect(Collectors.toList());
            List<ScoreCardGmConfig> configs = scoreCardGmConfigService.listByIds(propertyId, ids);
            if (configs.size() != actualTargetDTO.getConfigList().size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("scoreCardGmConfig"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "the scoreCardGmConfig is not found or not belong the property");
            }

            ScoreCardGmConfig config = scoreCardGmConfigService.checkExist(actualTargetDTO.getTargetId());
            checkPropertySame(config, propertyId);
            if (configs.stream().noneMatch(item -> item.getId().equals(config.getId()))) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("scoreCardGmConfig"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the targetId is not found in the configList");
            }

            return scoreCardGmService.calculationResult(actualTargetDTO, config);
        }

        /**
         * 保存 ScoreCard
         *
         * @param year       年
         * @param month      月
         * @param property   资产标识
         * @param configList 指标内容
         * @return {}
         * @author yyt
         * @date 2023/10/5
         */
        @ApiId(779)
        @PostMapping("/{year:\\d+}/{month:\\d+}")
        public Map<String, Object> save(@PathVariable int year, @PathVariable int month, String property,
                        @RequestBody List<@Valid UpdateItemDTO> configList) {
            checkYearMonth(year, month);

            if (CollectionUtils.isEmpty(configList)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("configList"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the configList must not be empty");
            }

            Integer propertyId = sessionContext.getPropertyId(property);
            List<Integer> ids = configList.stream().map(UpdateItemDTO::getId).collect(Collectors.toList());
            List<ScoreCardGmConfig> configs = scoreCardGmConfigService.listByIds(propertyId, ids);
            if (configs.size() != configList.size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("scoreCardGmConfig"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "the scoreCardGmConfig is not found or not belong the property");
            }

            scoreCardGmService.save(propertyId, year, month, configList, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 校验 scheduleDepartmentEmployee property 与 参数 property 一致
         *
         * @param config     ScoreCardGmConfig
         * @param propertyId 参数 property
         * @author yyt
         * @date 2023/10/5
         */
        private void checkPropertySame(ScoreCardGmConfig config, Integer propertyId) {
            if (!config.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(), "the property id parameter is different from " +
                        "the property id of the scoreCardGmConfig;propertyId:" + propertyId
                        + ",scoreCardGmConfigPropertyId:" + config.getPropertyId() + ",scoreCardGmConfigId:" + config.getId());
            }
        }

        /**
         * 检查年、月
         *
         * @param year  年
         * @param month 月
         * @author yyt
         * @date 2023/10/7
         */
        private void checkYearMonth(int year, int month) {
            // 不能查看未来数据
            if (YearMonth.of(year, month).isAfter(YearMonth.now())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_VIEW_FUTURE_DATA,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "Cannot view future data");
            }
        }

    }