package cn.iocoder.yudao.module.srm.service.tender; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmBidEvaluationSaveReqVO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmBidEvaluationDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmBidOpenDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderProjectDO; import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidEvaluationMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidOpenMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderProjectMapper; 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 jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.Comparator; import java.util.List; /** * SRM 评标管理 Service 实现类 */ @Service @Validated public class SrmBidEvaluationServiceImpl implements SrmBidEvaluationService { @Resource private SrmBidEvaluationMapper bidEvaluationMapper; @Resource private SrmBidOpenMapper bidOpenMapper; @Resource private SrmTenderProjectMapper tenderProjectMapper; // ========== 评标管理 ========== @Override @Transactional(rollbackFor = Exception.class) public Long createEvaluation(SrmBidEvaluationSaveReqVO createReqVO) { 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()); 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.insert(evaluation); // 首次评标时更新招标项目状态为评标中 SrmTenderProjectDO project = tenderProjectMapper.selectById(createReqVO.getTenderProjectId()); if (project != null && 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); } 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 public List getEvaluationList(Long tenderProjectId) { return bidEvaluationMapper.selectListByTenderProjectId(tenderProjectId); } @Override @Transactional(rollbackFor = Exception.class) public void calculateRanking(Long tenderProjectId) { List list = bidEvaluationMapper.selectListByTenderProjectId(tenderProjectId); // 按综合评分降序排名 list.sort(Comparator.comparing(e -> e.getCompositeScore() != null ? e.getCompositeScore() : BigDecimal.ZERO, Comparator.reverseOrder())); for (int i = 0; i < list.size(); i++) { SrmBidEvaluationDO evaluation = list.get(i); evaluation.setRanking(i + 1); bidEvaluationMapper.updateById(evaluation); } } // ========== 开标管理 ========== @Override @Transactional(rollbackFor = Exception.class) public Long createBidOpen(Long tenderProjectId) { 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); } SrmBidOpenDO open = new SrmBidOpenDO(); open.setTenderProjectId(tenderProjectId); open.setOpenTime(LocalDateTime.now()); bidOpenMapper.insert(open); return open.getId(); } @Override public SrmBidOpenDO getBidOpen(Long id) { return bidOpenMapper.selectById(id); } private static BigDecimal nvl(BigDecimal value) { return value != null ? value : BigDecimal.ZERO; } }