package com.talentcard.server.service; import java.time.LocalDateTime; import java.util.List; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.talentcard.server.business.BusinessIdGenerator; import com.talentcard.server.common.BusinessException; import com.talentcard.server.common.ErrorCode; import com.talentcard.server.entity.DependentCardApply; import com.talentcard.server.entity.DependentCardApplyStatusLog; import com.talentcard.server.mapper.DependentCardApplyMapper; import com.talentcard.server.mapper.DependentCardApplyStatusLogMapper; import com.talentcard.server.request.DependentCardApplyRequest; import com.talentcard.server.request.DependentCardUnbindRequest; import com.talentcard.server.response.DependentCardApplyDetailResponse; import com.talentcard.server.response.DependentCardApplyItemResponse; import com.talentcard.server.response.DependentCardApplyResponse; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class DependentCardApplyService { private static final String ELITE_CARD_LEVEL = "卓越人才卡"; private static final int MAX_APPLICATION_COUNT = 3; private static final int MAX_FAMILY_CARD_COUNT = 2; private final DependentCardApplyMapper mapper; private final DependentCardApplyStatusLogMapper statusLogMapper; public DependentCardApplyService( DependentCardApplyMapper mapper, DependentCardApplyStatusLogMapper statusLogMapper ) { this.mapper = mapper; this.statusLogMapper = statusLogMapper; } @Transactional public DependentCardApplyResponse submit(DependentCardApplyRequest request) { DependentCardApply ownerCard = ownerCard(request.talentCardId()); int familyCardLimit = familyCardLimit(ownerCard); long applicationCount = mapper.selectCount( Wrappers.lambdaQuery() .eq(DependentCardApply::getTalentCardId, request.talentCardId()) .in( DependentCardApply::getStatus, DependentCardApply.STATUS_PENDING_REVIEW, DependentCardApply.STATUS_APPROVED, DependentCardApply.STATUS_REJECTED ) ); if (applicationCount >= MAX_APPLICATION_COUNT) { throw new BusinessException(ErrorCode.CONFLICT, "同一张主卡最多提交3个家属附属卡申请"); } long occupiedCount = mapper.selectCount( Wrappers.lambdaQuery() .eq(DependentCardApply::getTalentCardId, request.talentCardId()) .in( DependentCardApply::getStatus, DependentCardApply.STATUS_PENDING_REVIEW, DependentCardApply.STATUS_APPROVED ) ); if (occupiedCount >= familyCardLimit) { throw new BusinessException( ErrorCode.CONFLICT, "该主卡家属附属卡名额已满,最多绑定" + familyCardLimit + "个" ); } DependentCardApply apply = new DependentCardApply( BusinessIdGenerator.next("DCA"), number(ownerCard.getTalentId()), number(ownerCard.getTalentCardId()), text(ownerCard.getTalentName()), text(ownerCard.getTalentMobile()), text(ownerCard.getTalentCardNo()), text(ownerCard.getCardLevel()), request.dependentName().trim(), request.dependentMobile().trim(), request.dependentIdCardNo().trim().toUpperCase(), request.relation().trim() ); if (mapper.insert(apply) != 1) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "家属附属卡申请提交失败"); } recordStatus(apply, null, DependentCardApply.STATUS_PENDING_REVIEW, "TALENT", apply.getTalentId(), "小程序提交申请"); return DependentCardApplyResponse.from(apply); } @Transactional(readOnly = true) public List list(Long talentCardId) { requireTalentCardId(talentCardId); return mapper.selectList( Wrappers.lambdaQuery() .eq(DependentCardApply::getTalentCardId, talentCardId) .ne(DependentCardApply::getStatus, DependentCardApply.STATUS_CANCELLED) .orderByDesc(DependentCardApply::getApplyTime) .orderByDesc(DependentCardApply::getId) ).stream() .map(DependentCardApplyItemResponse::from) .toList(); } @Transactional public DependentCardApplyItemResponse unbind(Long id, DependentCardUnbindRequest request) { requireTalentCardId(request.talentCardId()); DependentCardApply apply = mapper.selectByIdForUpdate(id); if (apply == null || !request.talentCardId().equals(apply.getTalentCardId())) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "家属附属卡申请不存在"); } // if (!Integer.valueOf(DependentCardApply.STATUS_APPROVED).equals(apply.getStatus())) { // throw new BusinessException(ErrorCode.INTERNAL_ERROR, "仅已通过审核的家属附属卡可以解绑"); // } int updated = mapper.update( null, Wrappers.lambdaUpdate() .eq(DependentCardApply::getId, id) .eq(DependentCardApply::getTalentCardId, request.talentCardId()) .eq(DependentCardApply::getStatus, DependentCardApply.STATUS_APPROVED) .set(DependentCardApply::getStatus, DependentCardApply.STATUS_CANCELLED) ); if (updated != 1) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "家属附属卡状态已变化,请刷新后重试"); } recordStatus( apply, DependentCardApply.STATUS_APPROVED, DependentCardApply.STATUS_CANCELLED, "TALENT", apply.getTalentId(), "小程序用户主动解绑" ); return DependentCardApplyItemResponse.from(mapper.selectById(id)); } @Transactional(readOnly = true) public DependentCardApplyDetailResponse detail(Long id, Long talentCardId) { Long applyId = requirePositive(id, "申请ID不能为空"); requireTalentCardId(talentCardId); DependentCardApply apply = mapper.selectById(applyId); if (apply == null || !talentCardId.equals(apply.getTalentCardId())) { throw new BusinessException(ErrorCode.NOT_FOUND, "家属附属卡申请不存在"); } return DependentCardApplyDetailResponse.from(apply); } @Transactional public DependentCardApplyItemResponse resubmit(Long id, DependentCardApplyRequest request) { Long applyId = requirePositive(id, "申请ID不能为空"); requireTalentCardId(request.talentCardId()); DependentCardApply apply = mapper.selectByIdForUpdate(applyId); if (apply == null || !request.talentCardId().equals(apply.getTalentCardId())) { throw new BusinessException(ErrorCode.NOT_FOUND, "家属附属卡申请不存在"); } if (!Integer.valueOf(DependentCardApply.STATUS_REJECTED).equals(apply.getStatus())) { throw new BusinessException(ErrorCode.CONFLICT, "仅已驳回的申请可以修改重新提交"); } LocalDateTime applyTime = LocalDateTime.now(); int updated = mapper.update( null, Wrappers.lambdaUpdate() .eq(DependentCardApply::getId, applyId) .eq(DependentCardApply::getTalentCardId, request.talentCardId()) .eq(DependentCardApply::getStatus, DependentCardApply.STATUS_REJECTED) .set(DependentCardApply::getDependentName, request.dependentName().trim()) .set(DependentCardApply::getDependentMobile, request.dependentMobile().trim()) .set(DependentCardApply::getDependentIdCardNo, request.dependentIdCardNo().trim().toUpperCase()) .set(DependentCardApply::getRelation, request.relation().trim()) .set(DependentCardApply::getApplyTime, applyTime) .set(DependentCardApply::getStatus, DependentCardApply.STATUS_PENDING_REVIEW) .set(DependentCardApply::getAuditBy, (Long) null) .set(DependentCardApply::getAuditTime, (LocalDateTime) null) .set(DependentCardApply::getAuditRemark, (String) null) ); if (updated != 1) { throw new BusinessException(ErrorCode.CONFLICT, "申请状态已变化,请刷新后重试"); } recordStatus( apply, DependentCardApply.STATUS_REJECTED, DependentCardApply.STATUS_PENDING_REVIEW, "TALENT", apply.getTalentId(), "小程序修改后重新提交" ); DependentCardApply updatedApply = mapper.selectById(applyId); if (updatedApply == null) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "家属附属卡申请重新提交失败"); } return DependentCardApplyItemResponse.from(updatedApply); } private DependentCardApply ownerCard(Long talentCardId) { requireTalentCardId(talentCardId); DependentCardApply card = mapper.selectOwnerCard(talentCardId); if (card == null) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "主卡不存在或已失效"); } return card; } private int familyCardLimit(DependentCardApply card) { if (!ELITE_CARD_LEVEL.equals(card.getCardLevel())) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "仅卓越人才卡可申请家属附属卡"); } // if (!Integer.valueOf(1).equals(card.getIsFamilyCardEnabled())) { // throw new BusinessException(ErrorCode.INTERNAL_ERROR, "该主卡未开通家属附属卡申请权限"); // } // Integer configuredLimit = card.getFamilyCardLimit(); // if (configuredLimit == null || configuredLimit <= 0) { // throw new BusinessException(ErrorCode.INTERNAL_ERROR, "该主卡未配置家属附属卡名额"); // } return Math.min(2, MAX_FAMILY_CARD_COUNT); } private void recordStatus( DependentCardApply apply, Integer fromStatus, Integer toStatus, String operatorType, Long operatorId, String remark ) { if (statusLogMapper.insert(new DependentCardApplyStatusLog( apply.getId(), apply.getApplyNo(), fromStatus, toStatus, operatorType, operatorId, remark )) != 1) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "家属附属卡状态记录保存失败"); } } private Long requirePositive(Long id, String message) { if (id == null || id <= 0) { throw new BusinessException(ErrorCode.BAD_REQUEST, message); } return id; } private void requireTalentCardId(Long talentCardId) { if (talentCardId == null || talentCardId <= 0) { throw new BusinessException(ErrorCode.INTERNAL_ERROR, "主卡ID不能为空"); } } private Long number(Object value) { return value instanceof Number number ? number.longValue() : null; } private String text(Object value) { return value == null ? null : String.valueOf(value); } }