# ServiceRequestCenterOperationRequestController.java

    package cloud.wconnect.it.controller.servicerequestcenter;

    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.util.I18nMessageUtils;
    import cloud.wconnect.commonlib.util.RegularUtil;
    import cloud.wconnect.it.cons.servicerequestcenter.ServiceRequestCenterErrorCons;
    import cloud.wconnect.it.cons.servicerequestcenter.ServiceRequestCenterStatusEnum;
    import cloud.wconnect.it.cons.servicerequestcenter.ServiceRequestCenterTypeEnum;
    import cloud.wconnect.it.entity.servicerequestcenter.ServiceRequestCenter;
    import cloud.wconnect.it.pojo.dto.servicerequestcenter.ChangeDutyUserDTO;
    import cloud.wconnect.it.pojo.dto.servicerequestcenter.ChangeRequestStatusDTO;
    import cloud.wconnect.it.pojo.dto.servicerequestcenter.ChangeRequestTypeDTO;
    import cloud.wconnect.it.pojo.dto.servicerequestcenter.SaveRequestDTO;
    import cloud.wconnect.it.service.servicerequestcenter.IServiceRequestCenterCheckService;
    import cloud.wconnect.it.service.servicerequestcenter.IServiceRequestOperaRequestService;
    import com.google.common.collect.Lists;
    import jakarta.validation.Valid;
    import jodd.util.StringUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;

    import java.util.Collections;
    import java.util.Map;
    import java.util.Objects;

    /**
     * <p>
     *  前端控制器
     * </p>
     *
     * @author yyt
     * @since 2025-12-16
     */
    @RestController
    @RequestMapping("/dashboard/service-request-center")
    public class ServiceRequestCenterOperationRequestController {

        @Autowired
        private IServiceRequestOperaRequestService serviceRequestOperaRequestService;
        @Autowired
        private IServiceRequestCenterCheckService serviceRequestCenterCheckService;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 1667 - 保存 request
         *
         * @param property       资产标识
         * @param saveRequestDTO request 信息
         * @return {}
         * @author yyt
         * @date 2025/12/16
         **/
        @ApiId(1667)
        @PostMapping
        public Map<String, Object> saveRequest(String tenant, String property, @Valid @RequestBody SaveRequestDTO saveRequestDTO) {
            // type 为 财务时，选择功能模块+选择资产 必须为空
            String properties = saveRequestDTO.getProperties();
            if (saveRequestDTO.getType() == ServiceRequestCenterTypeEnum.ACCOUNT.getCode()
                    && (Objects.nonNull(saveRequestDTO.getModules()) || Objects.nonNull(saveRequestDTO.getFunctionIds()) || StringUtil.isNotEmpty(properties))) {
                throw new BadRequestException(CommonErrorI18nConstant.MUST_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("modules or functionIds or properties"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "the modules or properties must be null when type is account");
            } else {
                // 其他类型，资产不能为空
                if (saveRequestDTO.getType() != ServiceRequestCenterTypeEnum.ACCOUNT.getCode() && StringUtil.isEmpty(properties)) {
                    throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                            i18nMessageUtils.getErrorParamMapNotNeedTranslate("properties"),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the properties must not be null");
                }
            }

            // 验证邮箱
            if (!RegularUtil.checkEmail(saveRequestDTO.getContactEmail())) {
                throw new BadRequestException(CommonErrorI18nConstant.FORMAT_ERROR,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("contactEmail"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the contactEmail format is error");
            }

            int propertyId = sessionContext.getPropertyId(property);
            int userId = sessionContext.getLoginUserId();
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();

            // 校验用户有功能权限
            serviceRequestCenterCheckService.checkHasFunctionPermission(tenantId, properties, saveRequestDTO.getFunctionIds(), userId);
            // 校验选择资产属于当前登录用户所属资产
            serviceRequestCenterCheckService.checkPropertyBelongToUser(sessionContext.getPropertyIds(), properties);

            // 保存 request
            serviceRequestOperaRequestService.save(tenantId, propertyId, saveRequestDTO, userId);

            return Collections.emptyMap();
        }

        /**
         * 1669 - close request
         *
         * @param property    资产标识
         * @param id          request id
         * @return {}
         * @author yyt
         * @date 2025/12/17
         **/
        @ApiId(1669)
        @PutMapping("/{id:\\d+}/closure")
        public Map<String, Object> closeRequest(String property, @PathVariable int id) {
            ServiceRequestCenter request = serviceRequestCenterCheckService.checkExist(id);
            // 只要 resolve 才显示 close  按钮
            serviceRequestCenterCheckService.checkStatusMustBe(request.getStatus(), ServiceRequestCenterStatusEnum.RESOLVED.getCode());
            // 检测资产
            serviceRequestCenterCheckService.checkProperty(sessionContext.getTenantSymbolBO().getId(), request, sessionContext.getPropertyIds());

            // 只有创建者可以关闭
            if (request.getCreatedBy() != sessionContext.getLoginUserId()) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(), "the request is not created by you");
            }

            serviceRequestOperaRequestService.closeRequest(request);

            return Collections.emptyMap();
        }

        /**
         * 1675 - 变更 request 状态
         *
         * @param id              request id
         * @param changeStatusDTO 变更状态信息
         * @return {}
         * @author yyt
         * @date 2025/12/18
         **/
        @ApiId(1675)
        @PutMapping("/{id:\\d+}/status")
        public Map<String, Object> changeStatus(@PathVariable int id, @Valid @RequestBody ChangeRequestStatusDTO changeStatusDTO) {
            ServiceRequestCenter request = serviceRequestCenterCheckService.checkExist(id);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            serviceRequestCenterCheckService.checkProperty(tenantId, request, sessionContext.getPropertyIds());

            // 校验用户是否是 员工 / 管理员
            int userId = sessionContext.getLoginUserId();
            serviceRequestCenterCheckService.checkUserIsStaffOrManager(tenantId, userId, request.getType());
            // 检查用户是否是责任人
            serviceRequestCenterCheckService.checkUserIsDutyUser(request.getDutyUser(), userId);
            // 已经 resolve / close 的不支持操作
            serviceRequestCenterCheckService.checkStatusMustNotBe(request.getStatus(), Lists.newArrayList(ServiceRequestCenterStatusEnum.RESOLVED.getCode(), ServiceRequestCenterStatusEnum.CLOSED.getCode()));

            // 校验状态
            Integer newStatus = changeStatusDTO.getNewStatus();
            if (newStatus == ServiceRequestCenterStatusEnum.RESOLVED.getCode()) {
                serviceRequestCenterCheckService.checkStatusMustBe(request.getStatus(), Lists.newArrayList(ServiceRequestCenterStatusEnum.IN_PROGRESS.getCode(), ServiceRequestCenterStatusEnum.OPEN.getCode()));
            } else if (newStatus == ServiceRequestCenterStatusEnum.IN_PROGRESS.getCode()) {
                serviceRequestCenterCheckService.checkStatusMustBe(request.getStatus(), ServiceRequestCenterStatusEnum.OPEN.getCode());
            } else if (newStatus == ServiceRequestCenterStatusEnum.OPEN.getCode()) {
                serviceRequestCenterCheckService.checkStatusMustBe(request.getStatus(), ServiceRequestCenterStatusEnum.IN_PROGRESS.getCode());
            }

            serviceRequestOperaRequestService.changeStatus(tenantId, request, changeStatusDTO, userId);

            return Collections.emptyMap();
        }

        /**
         * 1676 - 变更 request type
         *
         * @param id            request id
         * @param changeTypeDTO 变更类型信息
         * @return {}
         * @author yyt
         * @date 2025/12/18
         **/
        @ApiId(1676)
        @PutMapping("/{id:\\d+}/type")
        public Map<String, Object> changeType(@PathVariable int id, @Valid @RequestBody ChangeRequestTypeDTO changeTypeDTO) {
            ServiceRequestCenter request = serviceRequestCenterCheckService.checkExist(id);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            serviceRequestCenterCheckService.checkProperty(tenantId, request, sessionContext.getPropertyIds());

            // 财务类型单据不支持切换 type
            if (request.getType() == ServiceRequestCenterTypeEnum.ACCOUNT.getCode()) {
                throw new BadRequestException(CommonErrorI18nConstant.MUST_IN_LIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("type", Lists.newArrayList(ServiceRequestCenterTypeEnum.IT.getCode(), ServiceRequestCenterTypeEnum.PRODUCT.getCode())),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the request type is account, can not change type");
            }

            // 已经 resolve / close 的不支持操作
            serviceRequestCenterCheckService.checkStatusMustNotBe(request.getStatus(), Lists.newArrayList(ServiceRequestCenterStatusEnum.RESOLVED.getCode(), ServiceRequestCenterStatusEnum.CLOSED.getCode()));

            // 无责任人时，只有管理员能改变 type
            int userId = sessionContext.getLoginUserId();
            Integer type = request.getType();
            if(request.getDutyUser() == BaseConstant.ZERO) {
                if (!serviceRequestCenterCheckService.checkUserIsManager(tenantId, userId, type)) {
                    throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                            BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(), "you are not manager");
                }
            } else {
                // 有责任人时，员工 + 管理员都能改变 type
                serviceRequestCenterCheckService.checkUserIsStaffOrManager(tenantId, userId, type);
            }

            serviceRequestOperaRequestService.changeType(tenantId, request, changeTypeDTO, userId);

            return Collections.emptyMap();
        }

        /**
         * 1678 - 变更 request 责任人
         *
         * @param id                request id
         * @param changeDutyUserDTO 变更责任人信息
         * @return {}
         * @author yyt
         * @date 2025/12/18
         **/
        @ApiId(1678)
        @PutMapping("/{id:\\d+}/duty-user")
        public Map<String, Object> changeDutyUser(@PathVariable int id, @Valid @RequestBody ChangeDutyUserDTO changeDutyUserDTO) {
            ServiceRequestCenter request = serviceRequestCenterCheckService.checkExist(id);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            serviceRequestCenterCheckService.checkProperty(tenantId, request, sessionContext.getPropertyIds());

            // 已经 resolve / close 的不支持操作
            serviceRequestCenterCheckService.checkStatusMustNotBe(request.getStatus(), Lists.newArrayList(ServiceRequestCenterStatusEnum.RESOLVED.getCode(), ServiceRequestCenterStatusEnum.CLOSED.getCode()));

            int userId = sessionContext.getLoginUserId();

            // 无责任人时，只能管理员能改变
            if(request.getDutyUser() == BaseConstant.ZERO) {
                if (!serviceRequestCenterCheckService.checkUserIsManager(tenantId, userId, request.getType())) {
                    throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                            BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(), "you are not manager");
                }
            } else {
                // 检查登录用户是否是员工/管理员
                serviceRequestCenterCheckService.checkUserIsStaffOrManager(tenantId, userId, request.getType());

                // 有责任人时，只能责任人操作改变
                serviceRequestCenterCheckService.checkUserIsDutyUser(request.getDutyUser(), userId);
            }

            // 检查选择的用户是当前部门下的员工/管理员
            serviceRequestCenterCheckService.checkUserIsStaffOrManager(tenantId, changeDutyUserDTO.getNewDutyUser(), request.getType());
            // 当责任人是自己时，不能再分配给自己
            if (request.getDutyUser() == userId && changeDutyUserDTO.getNewDutyUser() == userId) {
                throw new BadRequestException(ServiceRequestCenterErrorCons.CANNOT_ALLOCATE_TO_YOURSELF,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "cannot allocate to yourself");
            }

            serviceRequestOperaRequestService.changeDutyUser(tenantId, request, changeDutyUserDTO, userId);
            return Collections.emptyMap();
        }

    }