| | |
| | | import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants; |
| | | import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum; |
| | | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| | | import com.mzt.logapi.starter.annotation.LogRecord; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*; |
| | | |
| | | /** |
| | | * SRM 评标管理 Service 实现类 |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = LOG_EVALUATION_TYPE, subType = LOG_EVALUATION_CREATE_SUB_TYPE, |
| | | bizNo = "{{#createReqVO.tenderProjectId}}", success = LOG_EVALUATION_CREATE_SUCCESS) |
| | | public Long createEvaluation(SrmBidEvaluationSaveReqVO createReqVO) { |
| | | // 检查招标项目状态:BIDDING 或 EVALUATING 才允许评标 |
| | | SrmTenderProjectDO project = tenderProjectMapper.selectById(createReqVO.getTenderProjectId()); |
| | | if (project == null) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS); |
| | | } |
| | | Integer status = project.getTenderStatus(); |
| | | if (!TenderStatusEnum.BIDDING.getCode().equals(status) |
| | | && !TenderStatusEnum.EVALUATING.getCode().equals(status)) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_EVALUATION_FORBIDDEN); |
| | | } |
| | | |
| | | SrmBidEvaluationDO evaluation = BeanUtils.toBean(createReqVO, SrmBidEvaluationDO.class); |
| | | // 强制置空 id,避免前端传入已有 id 导致主键冲突,由数据库序列自动生成 |
| | | evaluation.setId(null); |
| | | // 计算综合评分: 价格*0.4 + 技术*0.3 + 交付*0.2 + 服务*0.1 |
| | | BigDecimal price = nvl(evaluation.getPriceScore()); |
| | | BigDecimal tech = nvl(evaluation.getTechScore()); |
| | |
| | | evaluation.setEvaluationTime(LocalDateTime.now()); |
| | | bidEvaluationMapper.insert(evaluation); |
| | | // 首次评标时更新招标项目状态为评标中 |
| | | SrmTenderProjectDO project = tenderProjectMapper.selectById(createReqVO.getTenderProjectId()); |
| | | if (project != null && TenderStatusEnum.BIDDING.getCode().equals(project.getTenderStatus())) { |
| | | if (TenderStatusEnum.BIDDING.getCode().equals(project.getTenderStatus())) { |
| | | project.setTenderStatus(TenderStatusEnum.EVALUATING.getCode()); |
| | | tenderProjectMapper.updateById(project); |
| | | } |
| | | return evaluation.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateEvaluation(SrmBidEvaluationSaveReqVO updateReqVO) { |
| | | SrmBidEvaluationDO existing = bidEvaluationMapper.selectById(updateReqVO.getId()); |
| | | if (existing == null) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.EVALUATION_NOT_EXISTS_TENDER); |
| | | } |
| | | // 检查招标项目状态:仅 EVALUATING 允许更新评标 |
| | | SrmTenderProjectDO project = tenderProjectMapper.selectById(existing.getTenderProjectId()); |
| | | if (project == null || !TenderStatusEnum.canEvaluate(project.getTenderStatus())) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_EVALUATION_FORBIDDEN); |
| | | } |
| | | SrmBidEvaluationDO evaluation = BeanUtils.toBean(updateReqVO, SrmBidEvaluationDO.class); |
| | | BigDecimal price = nvl(evaluation.getPriceScore()); |
| | | BigDecimal tech = nvl(evaluation.getTechScore()); |
| | | BigDecimal delivery = nvl(evaluation.getDeliveryScore()); |
| | | BigDecimal service = nvl(evaluation.getServiceScore()); |
| | | BigDecimal composite = price.multiply(new BigDecimal("0.4")) |
| | | .add(tech.multiply(new BigDecimal("0.3"))) |
| | | .add(delivery.multiply(new BigDecimal("0.2"))) |
| | | .add(service.multiply(new BigDecimal("0.1"))) |
| | | .setScale(2, RoundingMode.HALF_UP); |
| | | evaluation.setCompositeScore(composite); |
| | | evaluation.setEvaluationTime(LocalDateTime.now()); |
| | | bidEvaluationMapper.updateById(evaluation); |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void calculateRanking(Long tenderProjectId) { |
| | | SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId); |
| | | if (project == null || !TenderStatusEnum.canEvaluate(project.getTenderStatus())) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_EVALUATION_FORBIDDEN); |
| | | } |
| | | List<SrmBidEvaluationDO> list = bidEvaluationMapper.selectListByTenderProjectId(tenderProjectId); |
| | | // 按综合评分降序排名 |
| | | list.sort(Comparator.comparing(e -> e.getCompositeScore() != null ? e.getCompositeScore() : BigDecimal.ZERO, Comparator.reverseOrder())); |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createBidOpen(Long tenderProjectId) { |
| | | // 校验招标项目存在且状态为发布中 |
| | | SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId); |
| | | if (project == null) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS); |
| | | } |
| | | if (!TenderStatusEnum.PUBLISHED.getCode().equals(project.getTenderStatus())) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_PUBLISHED); |
| | | } |
| | | if (bidOpenMapper.selectByTenderProjectId(tenderProjectId) != null) { |
| | | throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_PUBLISHED); |
| | | } |
| | | // 开标后自动更新招标项目状态为投标中 |
| | | SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId); |
| | | if (project != null && TenderStatusEnum.PUBLISHED.getCode().equals(project.getTenderStatus())) { |
| | | project.setTenderStatus(TenderStatusEnum.BIDDING.getCode()); |
| | | tenderProjectMapper.updateById(project); |
| | | } |
| | | project.setTenderStatus(TenderStatusEnum.BIDDING.getCode()); |
| | | tenderProjectMapper.updateById(project); |
| | | SrmBidOpenDO open = new SrmBidOpenDO(); |
| | | open.setTenderProjectId(tenderProjectId); |
| | | open.setOpenTime(LocalDateTime.now()); |