# RqCompRoomFormController.java

    package cloud.wconnect.frontoffice.controller.comproom;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.BeanMapper;
    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.cons.CommonFieldI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.exception.InternalServerErrorException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.pojo.dto.jsonview.Views;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.frontoffice.cons.ApproveStatusEnum;
    import cloud.wconnect.frontoffice.cons.comproom.CompRoomErrorI18nConstant;
    import cloud.wconnect.frontoffice.cons.comproom.CompRoomFieldConstant;
    import cloud.wconnect.frontoffice.entity.comproom.*;
    import cloud.wconnect.frontoffice.pojo.dto.comproom.CompRoomApproveDTO;
    import cloud.wconnect.frontoffice.pojo.dto.comproom.CompRoomCommentDTO;
    import cloud.wconnect.frontoffice.pojo.dto.comproom.CompRoomDTO;
    import cloud.wconnect.frontoffice.pojo.dto.comproom.CompRoomUserDTO;
    import cloud.wconnect.frontoffice.pojo.query.comproom.CompRoomExportQuery;
    import cloud.wconnect.frontoffice.pojo.query.comproom.CompRoomQuery;
    import cloud.wconnect.frontoffice.pojo.vo.comproom.*;
    import cloud.wconnect.frontoffice.service.comproom.*;
    import com.fasterxml.jackson.annotation.JsonView;
    import com.google.common.collect.ImmutableMap;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Sets;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.jxls.transform.poi.JxlsPoiTemplateFillerBuilder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.web.bind.annotation.*;

    import jakarta.servlet.http.HttpServletResponse;
    import jakarta.validation.Valid;

    import java.io.IOException;
    import java.io.InputStream;
    import java.text.MessageFormat;
    import java.util.*;
    import java.util.stream.Collectors;

    import static java.util.stream.Collectors.toSet;

    /**
     * <p>
     * 前端控制器
     * </p>
     *
     * @author lichen
     * @since 2023-03-28
     */
    @RestController
    @RequestMapping("/comp-room")
    public class RqCompRoomFormController {

        @Autowired
        private IRqCompRoomFormService compRoomService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private ICompRoomApproveLogService approveLogService;
        @Autowired
        private ICompRoomComplimentaryService compRoomComplimentaryService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private ICompRoomApproveLevelService approveLevelService;
        @Autowired
        private ICompRoomApproveConfigService approveConfigService;
        @Autowired
        private ICompRoomCommentService commentService;

        /**
         * 查询comp room列表
         *
         * @param property      资产标识
         * @param compRoomQuery 查询条件
         * @return cloud.wconnect.commonlib.pojo.dto.ListPagedDTO<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomVO>
         * @author lichen
         * @date 2023/8/19
         */
        @ApiId(198)
        @GetMapping
        @JsonView({Views.ListView.class})
        public ListPagedDTO<CompRoomVO> page(String property, @Valid CompRoomQuery compRoomQuery) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            return compRoomService.pageList(tenantId, propertyId, compRoomQuery);
        }

        /**
         * 查询Comp Room的创建人集合
         *
         * @param property 资产标识
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.dto.comproom.CompRoomUserDTO>
         * @author lichen
         * @date 2023/8/19
         */
        @ApiId(199)
        @GetMapping("/requesters")
        public List<CompRoomUserDTO> listCreateBys(String property) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            return compRoomService.listCreateBy(tenantId, propertyId);
        }

        /**
         * 查询Comp Room详情
         *
         * @param id       Comp Room主键id
         * @param property 资产标识
         * @return cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomVO
         * @author lichen
         * @date 2023/8/19
         */
        @ApiId(200)
        @GetMapping("/{id:\\d+}")
        @JsonView({Views.DetailsView.class})
        public CompRoomVO detail(@PathVariable("id") long id, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            //校验是否存在
            RqCompRoomForm compRoom = compRoomService.checkExist(id);
            //校验是否归属当前资产
            checkBelong(compRoom, propertyId);
            //查询用户信息
            Map<Integer, String> userId2Name = userInternalService.getNameMapByIds(tenantId,
                    Lists.newArrayList(compRoom.getCreatedBy(), compRoom.getUpdatedBy()));

            CompRoomVO compRoomVO = beanMapper.map(compRoom, CompRoomVO.class, vo -> {
                vo.setCreatedName(userId2Name.get(vo.getCreatedBy()));
                vo.setUpdatedName(userId2Name.get(vo.getUpdatedBy()));
            });

            if (StringUtils.isNotBlank(compRoom.getRelIds())) {
                List<Long> relIds = Arrays.stream(compRoom.getRelIds().split(","))
                        .map(Long::valueOf).collect(Collectors.toList());
                //查询报告数据
                List<CompRoomComplimentary> compRoomComplimentaries = compRoomComplimentaryService.listByIds(relIds);
                compRoomVO.setReportDatas(beanMapper.mapList(compRoomComplimentaries, CompRoomComplimentaryVO.class));
            }
            return compRoomVO;
        }

        /**
         * 保存comp room
         *
         * @param property    资产标识
         * @param compRoomDTO comp room dto
         * @return java.util.Map
         * @author lichen
         * @date 2023/8/21
         */
        @ApiId(204)
        @PostMapping
        public Map save(String property, @Valid @RequestBody CompRoomDTO compRoomDTO) {
            List<String> roomNumberList = compRoomDTO.getRoomNumberList();
            //校验房间号不能重复
            if (roomNumberList.size() != Sets.newHashSet(roomNumberList).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.ROOM_NUMBER),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The roomNumberList cannot repeat");
            }
            //房间号和房间数不为空时，房间号必须录入完整
            if (CollectionUtils.isNotEmpty(roomNumberList) && Objects.nonNull(compRoomDTO.getNumberOfRooms())
                    && roomNumberList.size() != compRoomDTO.getNumberOfRooms()) {
                throw new BadRequestException(CompRoomErrorI18nConstant.ROOM_NUMBER_AND_ROOM_COUNT_MUST_BE_THE_SAME,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The roomNumberList must input integrity");
            }

            int propertyId = sessionContext.getPropertyId(property);
            int loginUserId = sessionContext.getLoginUserId();

            compRoomDTO.setPropertyId(propertyId);

            Long id = compRoomDTO.getId();
            if (id == BaseConstant.LONG_ZERO) {//新增
                if (CollectionUtils.isNotEmpty(roomNumberList)) {
                    //校验是否唯一
                    compRoomService.checkRoomNumberAndCheckInDateSole(propertyId, compRoomDTO.getCheckInDate(), roomNumberList, null);
                }
                return ImmutableMap.of("id", compRoomService.save(compRoomDTO, loginUserId));
            } else {//修改
                //校验存在
                RqCompRoomForm oriCompRoom = compRoomService.checkExist(id);
                //校验是否归属于当前资产
                checkBelong(oriCompRoom, propertyId);
                if (CollectionUtils.isNotEmpty(roomNumberList)) {
                    //校验是否唯一
                    compRoomService.checkRoomNumberAndCheckInDateSole(propertyId, compRoomDTO.getCheckInDate(), roomNumberList, id);
                }
                //校验只有pending的数据可以修改
                if (oriCompRoom.getApproveStatus() != ApproveStatusEnum.PENDING.getStatus()) {
                    throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_STATE_CAN_OPERATE,
                            i18nMessageUtils.getErrorParamMapNeedTranslate(ApproveStatusEnum.PENDING.getI18nCode(),
                                    CompRoomFieldConstant.OPERATE_EDIT),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "Only Pending can be modified");
                }
                //只有创建人可以修改数据
                if (oriCompRoom.getCreatedBy() != loginUserId) {
                    throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_USER_CAN_OPERATE,
                            i18nMessageUtils.getErrorParamMapNeedTranslate(CompRoomFieldConstant.CREATOR,
                                    CompRoomFieldConstant.OPERATE_EDIT),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "Only the creator can be modified");
                }
                compRoomService.update(oriCompRoom, compRoomDTO, loginUserId);
                return ImmutableMap.of("id", id);
            }
        }

        /**
         * 送审数据
         *
         * @param id       主键id
         * @param property 资产id
         * @return java.util.Map
         * @author lichen
         * @date 2023/8/21
         */
        @ApiId(201)
        @PutMapping("/{id:\\d+}/to-approve")
        public Map toApprove(@PathVariable("id") long id, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            int loginUserId = sessionContext.getLoginUserId();
            //校验存在
            RqCompRoomForm oriCompRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(oriCompRoom, propertyId);
            //只有pending状态的数据可以送审
            if (oriCompRoom.getApproveStatus() != ApproveStatusEnum.PENDING.getStatus()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_STATE_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(ApproveStatusEnum.PENDING.getI18nCode(),
                                CompRoomFieldConstant.OPERATE_SUBMIT),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "only Pending data can to Approve");
            }
            //只有创建人可以送审
            if (oriCompRoom.getCreatedBy() != sessionContext.getLoginUserId()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_USER_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CompRoomFieldConstant.CREATOR,
                                CompRoomFieldConstant.OPERATE_SUBMIT),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Only the creator can submit the data");
            }
            //送审
            compRoomService.toApprove(oriCompRoom, loginUserId);
            return Collections.EMPTY_MAP;
        }

        /**
         * 导出
         *
         * @param property            资产标识
         * @param compRoomExportQuery 查询对象
         * @param response            响应对象
         * @return void
         * @author lichen
         * @date 2023/8/19
         */
        @ApiId(288)
        @GetMapping("/export")
        public void export(String property, @Valid CompRoomExportQuery compRoomExportQuery, HttpServletResponse response) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //获取时区
            String timezone = propertyDTO.getTimezone();

            Long endDate = compRoomExportQuery.getEndDate();
            Long beginDate = compRoomExportQuery.getBeginDate();
            if (endDate < beginDate) {
                throw new BadRequestException(CommonErrorI18nConstant.START_DATE_CANNOT_GREATER_THAN_END_DATE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The end time must be greater than or equal to the start time");
            }
            //校验时间间隔
            if (DateTimeUtils.dateDiffOfDays(beginDate, endDate, timezone) > 31) {
                throw new BadRequestException(CommonErrorI18nConstant.SELECT_DATE_LIMIT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("31"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The Date range is over 31 days");
            }

            //设置response
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-Disposition", String.join("", "attachment; filename=", "compRoom.xlsx"));

            //查询comp room数据
            List<CompRoomExcelVO> compRoomExcelVOS = compRoomService.listExportData(propertyDTO, compRoomExportQuery);

            //模板名称
            String templateFileName = StringUtils.join("tmpl-xls/comp_room_tmpl_", LocaleContextHolder.getLocale(), ".xlsx");
            //导出Excel
            try (InputStream is = new ClassPathResource(templateFileName).getInputStream()) {
                HashMap<String, Object> data = new HashMap<>();
                data.put("compRooms", compRoomExcelVOS);
                //文件名
                String fileName = propertyDTO.getAbbr() + "_CompRoom.xlsx";
                response.setContentType("application/vnd.ms-excel");
                response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
                response.setHeader("Content-Disposition", String.join("", "attachment; filename=", fileName));
                //填充模板
                JxlsPoiTemplateFillerBuilder.newInstance()
                        .withTemplate(is)
                        .buildAndFill(data, response::getOutputStream);
            } catch (IOException exp) {
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "IO exception occured when exporting adj excel file. property Id: " + propertyId);
            }
        }

        /**
         * 撤回数据
         *
         * @param id       comp room主键id
         * @param property 资产标识
         * @return java.util.Map
         * @author lichen
         * @date 2023/8/22
         */
        @ApiId(203)
        @PutMapping("/{id:\\d+}/withdrawn")
        public Map withdrawn(@PathVariable("id") long id, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            int loginUserId = sessionContext.getLoginUserId();

            //校验存在
            RqCompRoomForm oriCompRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(oriCompRoom, propertyId);
            //只有approveing数据可以撤回
            if (oriCompRoom.getApproveStatus() != ApproveStatusEnum.APPROVEING.getStatus()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_STATE_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(ApproveStatusEnum.APPROVEING.getI18nCode(),
                                CompRoomFieldConstant.OPERATE_WITHDRAW),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Only approveing data can be withdrawn");
            }
            //当前审批层级的审批人
            CompRoomApproveLevel approveLevel = approveLevelService.getByApproveIndex(propertyId, oriCompRoom.getApproveIndex());
            List<Integer> userIdsByApproval = approveConfigService.listByLevelId(propertyId, approveLevel.getId()).stream().map(CompRoomApproveConfig::getUserId).toList();

            //判断当前登录用户是否可以撤回，创建人或审批人可以撤回
            boolean b = oriCompRoom.getCreatedBy() == loginUserId || userIdsByApproval.contains(loginUserId);
            if (!b) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_USER_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(
                                List.of(CompRoomFieldConstant.CREATOR, CompRoomFieldConstant.APPROVAL_USER),
                                CompRoomFieldConstant.OPERATE_WITHDRAW),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Only the creator and approval user can withdraw");
            }

            //数据更新为pending
            RqCompRoomForm updateEntity = new RqCompRoomForm();
            updateEntity.setId(oriCompRoom.getId());
            updateEntity.setApproveStatus(ApproveStatusEnum.PENDING.getStatus());
            updateEntity.setApproveIndex(BaseConstant.ZERO);
            updateEntity.setBatchId(BaseConstant.LONG_ZERO);
            compRoomService.updateById(updateEntity);
            return Collections.EMPTY_MAP;
        }

        /**
         * 更新归档状态
         *
         * @param id        comp room主键id
         * @param property  资产标识
         * @param isArchive 是否归档
         * @return java.lang.Boolean
         * @author lichen
         * @date 2023/8/22
         */
        @ApiId(549)
        @PutMapping("/{id:\\d+}/update-archive-status")
        public Map updateArchiveStatus(@PathVariable("id") long id, String property,
                                       @RequestParam(name = "isArchive") Boolean isArchive) {
            int propertyId = sessionContext.getPropertyId(property);
            //校验存在
            RqCompRoomForm oriCompRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(oriCompRoom, propertyId);
            //只有审批通过或审批拒绝的可以归档
            if (oriCompRoom.getApproveStatus() != ApproveStatusEnum.APPROVED.getStatus()
                    && oriCompRoom.getApproveStatus() != ApproveStatusEnum.REJECTED.getStatus()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_STATE_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(
                                List.of(ApproveStatusEnum.APPROVED.getI18nCode(), ApproveStatusEnum.REJECTED.getI18nCode()),
                                CompRoomFieldConstant.OPERATE_ARCHIVE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "only approved data can Active or InActive");
            }
            //更新comp room
            RqCompRoomForm updateEntity = new RqCompRoomForm();
            updateEntity.setId(oriCompRoom.getId());
            updateEntity.setUpdatedBy(sessionContext.getLoginUserId());
            updateEntity.setUpdatedTime(DateTimeUtils.nowTimestamp());
            updateEntity.setIsArchive(isArchive);
            compRoomService.updateById(updateEntity);
            return Collections.emptyMap();
        }

        /**
         * 审批数据
         *
         * @param id         comp room主键id
         * @param property   资产标识
         * @param approveDTO 审批dto
         * @return java.util.Map
         * @author lichen
         * @date 2023/8/22
         */
        @ApiId(202)
        @PutMapping("/{id:\\d+}/approve")
        public Map approve(@PathVariable("id") long id, String property,
                           @Valid @RequestBody CompRoomApproveDTO approveDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            //校验存在
            RqCompRoomForm oriCompRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(oriCompRoom, propertyId);
            //校验状态
            if (oriCompRoom.getApproveStatus() != ApproveStatusEnum.APPROVEING.getStatus()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_STATE_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(ApproveStatusEnum.APPROVEING.getI18nCode(),
                                CompRoomFieldConstant.OPERATE_APPROVAL),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "only Approveing data can Approve");
            }
            //设置审批人
            approveDTO.setApproveBy(sessionContext.getLoginUserId());
            //审核数据
            compRoomService.approve(oriCompRoom, approveDTO);
            return Collections.EMPTY_MAP;
        }

        /**
         * 查询审批日志
         *
         * @param id       comp room主键id
         * @param property 资产标识
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomApproveLevelVO>
         * @author lichen
         * @date 2023/8/22
         */
        @ApiId(550)
        @GetMapping("/{id:\\d+}/approve-log")
        @JsonView({Views.DetailsView.class})
        public List<CompRoomApproveLevelVO> listApproveLog(@PathVariable("id") long id, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //校验存在
            RqCompRoomForm compRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(compRoom, propertyId);
            //pending状态时，返回空的数据
            if (compRoom.getApproveStatus() == ApproveStatusEnum.PENDING.getStatus()) {
                return Collections.emptyList();
            }
            //查询审批树
            return approveLogService.listApproveLogTree(compRoom, propertyDTO);
        }

        /**
         * 关联报告数据
         *
         * @param property  资产
         * @param id        comp room id
         * @param reportIds 报告数据id集合
         * @return java.util.Map
         * @author lichen
         * @date 2024/1/5
         */
        @ApiId(1016)
        @PutMapping("/{id:\\d+}/associated")
        public Map associated(String property, @PathVariable Long id, @RequestBody List<Long> reportIds) {
            if (CollectionUtils.isNotEmpty(reportIds) && reportIds.size() != Sets.newHashSet(reportIds).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("reportIds"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "reportIds cannot repeat");
            }

            int propertyId = sessionContext.getPropertyId(property);
            //校验存在
            RqCompRoomForm compRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(compRoom, propertyId);

            List<CompRoomComplimentary> compRoomComplimentaries = Collections.emptyList();
            if (CollectionUtils.isNotEmpty(reportIds)) {
                //校验报告数据是否存在
                compRoomComplimentaries = compRoomComplimentaryService.checkExist(reportIds);
                //校验是否归属于当前资产
                if (compRoomComplimentaries.stream().anyMatch(item -> !item.getPropertyId().equals(propertyId))) {
                    throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(), BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                            MessageFormat.format("The Guests In-House Complimentary not belong to current property, id:{0}, currentPropertyId:{1}",
                                    reportIds.toString(), propertyId));
                }
            }

            //关联报告数据
            compRoomService.associated(compRoom, compRoomComplimentaries);
            return Collections.emptyMap();
        }

        /**
         * 删除免费房
         *
         * @param property 资产标识
         * @param id       免费房ID
         * @return java.util.Map
         * @author lichen
         * @date 2024/6/11
         */
        @ApiId(1192)
        @DeleteMapping("/{id:\\d+}")
        public Map delete(String property, @PathVariable Long id) {
            int propertyId = sessionContext.getPropertyId(property);
            //校验存在
            RqCompRoomForm compRoom = compRoomService.checkExist(id);
            //校验是否归属于当前资产
            checkBelong(compRoom, propertyId);
            //审批中的数据不可以删除
            if (compRoom.getApproveStatus() == ApproveStatusEnum.APPROVEING.getStatus()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_STATE_CANNOT_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(ApproveStatusEnum.APPROVEING.getI18nCode(),
                                CompRoomFieldConstant.OPERATE_DELETE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Approveing data cannot delete");
            }
            //删除免费房
            compRoomService.delete(compRoom);
            return Collections.emptyMap();
        }

        /**
         * 查询备注集合
         *
         * @param property   资产标识
         * @param compRoomId 免费房id
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.comproom.CompRoomCommentVO>
         * @author lichen
         * @date 2024/6/19
         */
        @ApiId(1200)
        @GetMapping("/{compRoomId:\\d+}/comment")
        public List<CompRoomCommentVO> listComment(String property, @PathVariable long compRoomId) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            //校验存在
            RqCompRoomForm compRoom = compRoomService.checkExist(compRoomId);
            //校验是否归属于当前资产
            checkBelong(compRoom, propertyId);

            //查询黑名单的备注信息
            List<CompRoomComment> commentList = commentService.listByCompRoomId(Collections.singletonList(compRoom.getId()));
            //查询用户信息
            Set<Integer> userIds = commentList.stream().map(CompRoomComment::getCreatedBy).collect(toSet());
            Map<Integer, UserDTO> userId2DTO = userInternalService.getUserMapByIds(tenantId, userIds);
            return beanMapper.mapList(commentList, CompRoomCommentVO.class, (entity, vo) -> {
                UserDTO userDTO = userId2DTO.getOrDefault(entity.getCreatedBy(), new UserDTO());
                //设置创建人姓名
                vo.setCreatedName(userDTO.getName());
                vo.setAvatar(userDTO.getAvatar());
            });
        }

        /**
         * 保存备注信息
         *
         * @param compRoomId         免费房id
         * @param cid                备注id
         * @param property           资产标识
         * @param compRoomCommentDTO 备注DTO
         * @return java.util.Map
         * @author lichen
         * @date 2024/6/19
         */
        @ApiId(1201)
        @PostMapping("/{compRoomId:\\d+}/comment/{cid:\\d+}")
        public Map saveComment(@PathVariable long compRoomId, @PathVariable long cid,
                               String property, @RequestBody @Valid CompRoomCommentDTO compRoomCommentDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            //校验存在
            RqCompRoomForm compRoom = compRoomService.checkExist(compRoomId);
            //校验是否归属于当前资产
            checkBelong(compRoom, propertyId);
            if (cid > 0) {
                //校验备注
                CompRoomComment oriComment = commentService.checkExist(cid);
                if (!oriComment.getCompRoomId().equals(compRoomId)) {
                    throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(), BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                            MessageFormat.format("The comment is not belong to the current compRoom, compRoomId:{0}, commentBelongCompRoomId:{1}, commentId{2}",
                                    compRoomId, oriComment.getCompRoomId(), cid));
                }
                //校验只有创建人可以修改数据
                if (oriComment.getCreatedBy() != sessionContext.getLoginUserId()) {
                    throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_USER_CAN_OPERATE,
                            i18nMessageUtils.getErrorParamMapNeedTranslate(CompRoomFieldConstant.CREATOR,
                                    CompRoomFieldConstant.OPERATE_EDIT),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "Only the creator can modify the data");
                }
                //修改备注
                commentService.update(oriComment, compRoomCommentDTO);
                return ImmutableMap.of("id", cid);
            } else {//新增
                Long commentId = commentService.save(propertyId, compRoomId, compRoomCommentDTO, sessionContext.getLoginUserId());
                return ImmutableMap.of("id", commentId);
            }
        }

        /**
         * 删除免费房备注
         *
         * @param compRoomId 免费房id
         * @param cid        备注id
         * @param property   资产标识
         * @return java.util.Map
         * @author lichen
         * @date 2024/6/19
         */
        @ApiId(1202)
        @DeleteMapping("/{compRoomId:\\d+}/comment/{cid:\\d+}")
        public Map deleteComment(@PathVariable long compRoomId, @PathVariable long cid, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            //校验存在
            RqCompRoomForm compRoom = compRoomService.checkExist(compRoomId);
            //校验是否归属于当前资产
            checkBelong(compRoom, propertyId);
            //校验备注
            CompRoomComment oriComment = commentService.checkExist(cid);
            if (!oriComment.getCompRoomId().equals(compRoomId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(), BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The comment is not belong to the current comp room, compRoomId:{0}, commentBelongCompRoomId:{1}, commentId{2}",
                                compRoomId, oriComment.getCompRoomId(), cid));
            }
            //校验只有创建人可以删除数据
            if (oriComment.getCreatedBy() != sessionContext.getLoginUserId()) {
                throw new BadRequestException(CommonErrorI18nConstant.SPECIFIC_USER_CAN_OPERATE,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CompRoomFieldConstant.CREATOR,
                                CompRoomFieldConstant.OPERATE_DELETE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Only the creator can delete the data");
            }
            //删除
            commentService.remove(oriComment);
            return Collections.emptyMap();
        }

        /**
         * 校验是否归属当前资产
         *
         * @param compRoom   comp room数据
         * @param propertyId 资产id
         * @return void
         * @author lichen
         * @date 2023/8/19
         */
        private void checkBelong(RqCompRoomForm compRoom, Integer propertyId) {
            if (compRoom.getPropertyId().compareTo(propertyId) != 0) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(), BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The comp room not belong to current property, compRoomId:{0}, currentPropertyId:{1}",
                                compRoom.getId(), propertyId));
            }
        }
    }