| | |
| | | package com.sinata.appointment.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.sinata.appointment.constants.AppointmentFieldCodes; |
| | | import com.sinata.appointment.constants.BizErrorCode; |
| | | import com.sinata.appointment.dto.MiniVisitorCreateRequest; |
| | |
| | | req.getIdCard(), |
| | | req.getGender(), |
| | | requiredCodes); |
| | | assertIdCardUniqueUnderUser(current.getId(), input.idCard(), null); |
| | | |
| | | MpVisitor row = new MpVisitor(); |
| | | row.setMpUserId(current.getId()); |
| | |
| | | ? SensitiveDataUtil.encryptIdCard(input.idCard()) |
| | | : ""); |
| | | row.setGender(input.gender() == null ? "" : input.gender()); |
| | | row.setIsDefault(hasAnyActiveVisitor(current.getId()) ? 0 : 1); |
| | | mpVisitorMapper.insert(row); |
| | | } |
| | | |
| | |
| | | req.getIdCard(), |
| | | req.getGender(), |
| | | requiredCodes); |
| | | assertIdCardUniqueUnderUser(current.getId(), input.idCard(), row.getId()); |
| | | row.setVisitorName(input.name() == null ? "" : input.name()); |
| | | row.setVisitorMobile(input.mobile() == null ? "" : input.mobile()); |
| | | row.setVisitorCompany(input.company() == null ? "" : input.company()); |
| | |
| | | : ""); |
| | | row.setGender(input.gender() == null ? "" : input.gender()); |
| | | mpVisitorMapper.updateById(row); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void setDefault(Long id, String uuid) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | MpVisitor row = loadOwnedVisitor(id, uuid, current.getId()); |
| | | mpVisitorMapper.update( |
| | | null, |
| | | new LambdaUpdateWrapper<MpVisitor>() |
| | | .eq(MpVisitor::getMpUserId, current.getId()) |
| | | .eq(MpVisitor::getDelFlag, 0) |
| | | .set(MpVisitor::getIsDefault, 0)); |
| | | row.setIsDefault(1); |
| | | mpVisitorMapper.updateById(row); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void delete(Long id, String uuid) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | MpVisitor row = loadOwnedVisitor(id, uuid, current.getId()); |
| | | boolean wasDefault = isDefault(row); |
| | | mpVisitorMapper.deleteById(row.getId()); |
| | | if (wasDefault) { |
| | | resetEarliestVisitorAsDefault(current.getId()); |
| | | } |
| | | } |
| | | |
| | | public MiniVisitorDetailVo detail(Long id, String uuid) { |
| | |
| | | ? SensitiveDataUtil.decryptIdCard(row.getIdCardCipher()) |
| | | : ""); |
| | | vo.setGender(row.getGender()); |
| | | vo.setIsDefault(isDefault(row)); |
| | | return vo; |
| | | } |
| | | |
| | |
| | | new LambdaQueryWrapper<MpVisitor>() |
| | | .eq(MpVisitor::getMpUserId, current.getId()) |
| | | .eq(MpVisitor::getDelFlag, 0) |
| | | .orderByDesc(MpVisitor::getIsDefault) |
| | | .orderByDesc(MpVisitor::getCreateTime) |
| | | .orderByDesc(MpVisitor::getId)); |
| | | return rows.stream().map(row -> toListVo(row, requiredCodes)).collect(Collectors.toList()); |
| | |
| | | vo.setIdCardMasked(null); |
| | | } |
| | | vo.setVisitorCompany(row.getVisitorCompany()); |
| | | vo.setIsDefault(isDefault(row)); |
| | | vo.setMissingFieldCodes(resolveMissingFieldCodes(row, requiredCodes)); |
| | | return vo; |
| | | } |
| | | |
| | | private boolean isDefault(MpVisitor row) { |
| | | return row != null && row.getIsDefault() != null && row.getIsDefault() == 1; |
| | | } |
| | | |
| | | private boolean hasAnyActiveVisitor(Long mpUserId) { |
| | | return mpVisitorMapper.selectCount( |
| | | new LambdaQueryWrapper<MpVisitor>() |
| | | .eq(MpVisitor::getMpUserId, mpUserId) |
| | | .eq(MpVisitor::getDelFlag, 0)) |
| | | > 0; |
| | | } |
| | | |
| | | private void resetEarliestVisitorAsDefault(Long mpUserId) { |
| | | MpVisitor next = |
| | | mpVisitorMapper.selectOne( |
| | | new LambdaQueryWrapper<MpVisitor>() |
| | | .eq(MpVisitor::getMpUserId, mpUserId) |
| | | .eq(MpVisitor::getDelFlag, 0) |
| | | .orderByAsc(MpVisitor::getCreateTime) |
| | | .orderByAsc(MpVisitor::getId) |
| | | .last("limit 1")); |
| | | if (next != null) { |
| | | next.setIsDefault(1); |
| | | mpVisitorMapper.updateById(next); |
| | | } |
| | | } |
| | | |
| | | private List<String> resolveMissingFieldCodes(MpVisitor row, Set<String> requiredCodes) { |
| | |
| | | if (requiredCodes.contains(AppointmentFieldCodes.MOBILE) && !StringUtils.hasText(mobile)) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "来访人电话不能为空"); |
| | | } |
| | | if (StringUtils.hasText(mobile) && !mobile.matches("^\\d{11}$")) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "来访人电话须为11位数字"); |
| | | if (StringUtils.hasText(mobile) && !mobile.matches("^1[3-9]\\d{9}$")) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "来访人电话格式不正确"); |
| | | } |
| | | |
| | | if (requiredCodes.contains(AppointmentFieldCodes.COMPANY) && !StringUtils.hasText(company)) { |
| | |
| | | return new VisitorNormalizedInput(name, mobile, company, idCardPlain, genderText); |
| | | } |
| | | |
| | | private void assertIdCardUniqueUnderUser(Long mpUserId, String idCardPlain, Long excludeVisitorId) { |
| | | String normalizedIdCard = normalizeIdCard(idCardPlain); |
| | | if (!StringUtils.hasText(normalizedIdCard) || mpUserId == null) { |
| | | return; |
| | | } |
| | | List<MpVisitor> rows = |
| | | mpVisitorMapper.selectList( |
| | | new LambdaQueryWrapper<MpVisitor>() |
| | | .eq(MpVisitor::getMpUserId, mpUserId) |
| | | .eq(MpVisitor::getDelFlag, 0)); |
| | | for (MpVisitor row : rows) { |
| | | if (excludeVisitorId != null && excludeVisitorId.equals(row.getId())) { |
| | | continue; |
| | | } |
| | | if (!StringUtils.hasText(row.getIdCardCipher())) { |
| | | continue; |
| | | } |
| | | String existing = normalizeIdCard(SensitiveDataUtil.decryptIdCard(row.getIdCardCipher())); |
| | | if (normalizedIdCard.equals(existing)) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "同一账号下身份证号码不可重复"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String normalizeIdCard(String idCard) { |
| | | String value = trimToNull(idCard); |
| | | return value == null ? null : value.toUpperCase(); |
| | | } |
| | | |
| | | private record VisitorNormalizedInput( |
| | | String name, String mobile, String company, String idCard, String gender) {} |
| | | } |