| | |
| | | |
| | | @Service |
| | | public class TalentService { |
| | | private static final Set<String> TALENT_LEVELS = Set.of("卓越人才卡", "杰出人才卡", "菁英人才卡", "普通游客"); |
| | | |
| | | private static final String[] IMPORT_HEADERS = { |
| | | "姓名", "手机号", "身份证号", "性别", "卡片等级", "人才卡号", "外地/本地", "工作单位", "工作地址", "联系地址" |
| | | "姓名(必填)", "手机号码(必填)", "身份证号(必填)", "性别(必填)", "卡片等级(必填)", "人才卡号(必填)", |
| | | "外地/本地(必填)", "工作单位(必填)", "工作地址(必填)", "联系地址(必填)", "服务专员(必填)" |
| | | }; |
| | | private static final Set<String> TALENT_LEVELS = Set.of("卓越人才卡", "杰出人才卡", "普通人才卡", "普通游客"); |
| | | private record ImportTalentRow(TalentCreateRequest request, Long advisorId) {} |
| | | |
| | | private final JdbcTemplate jdbcTemplate; |
| | | |
| | |
| | | headerRow.createCell(index).setCellValue(IMPORT_HEADERS[index]); |
| | | headerRow.getCell(index).setCellStyle(headerStyle); |
| | | } |
| | | int[] widths = { 16, 18, 24, 10, 18, 20, 14, 24, 28, 28 }; |
| | | int[] widths = { 16, 18, 24, 10, 18, 20, 14, 24, 28, 28, 18 }; |
| | | for (int index = 0; index < widths.length; index++) { |
| | | sheet.setColumnWidth(index, widths[index] * 256); |
| | | } |
| | |
| | | public Map<String, Object> importExcel(InputStream inputStream) { |
| | | List<Map<String, Object>> failures = new ArrayList<>(); |
| | | List<TalentCreateRequest> validRows = new ArrayList<>(); |
| | | List<Long> advisorIds = new ArrayList<>(); |
| | | Set<String> fileMobiles = new HashSet<>(); |
| | | Set<String> fileIdCards = new HashSet<>(); |
| | | Set<String> fileCardNos = new HashSet<>(); |
| | |
| | | String workUnit = cellText(row, 7, formatter); |
| | | String workAddress = cellText(row, 8, formatter); |
| | | String contactAddress = cellText(row, 9, formatter); |
| | | String advisorName = cellText(row, 10, formatter); |
| | | String error = validateImportRow(name, mobile, idCardNo, gender, level, talentCardNo, area, workUnit, workAddress, |
| | | contactAddress, fileMobiles, fileIdCards, fileCardNos); |
| | | if (error != null) { |
| | | failures.add(importFailure(rowIndex + 1, name, error)); |
| | | continue; |
| | | } |
| | | Long advisorId = advisorIdByName(advisorName); |
| | | if (advisorId == null) { |
| | | failures.add(importFailure(rowIndex + 1, name, advisorName.isBlank() ? "服务专员不能为空" : "服务专员不存在、已停用或名称不唯一")); |
| | | continue; |
| | | } |
| | | fileMobiles.add(mobile); |
| | | fileIdCards.add(idCardNo); |
| | | fileCardNos.add(talentCardNo); |
| | | advisorIds.add(advisorId); |
| | | validRows.add(new TalentCreateRequest(null, name, mobile, idCardNo, genderValue(gender), workUnit, level, talentCardNo, |
| | | "外地".equals(area) ? "OUTSIDE" : "LOCAL", workAddress, contactAddress)); |
| | | } |
| | |
| | | throw new BusinessException(ErrorCode.BAD_REQUEST, "Excel 文件无法解析,请使用下载的导入模板"); |
| | | } |
| | | |
| | | for (TalentCreateRequest request : validRows) { |
| | | create(request); |
| | | for (int index = 0; index < validRows.size(); index++) { |
| | | Map<String, Object> created = create(validRows.get(index)); |
| | | updateAdvisor(((Number) created.get("id")).longValue(), advisorIds.get(index)); |
| | | } |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("successCount", validRows.size()); |
| | |
| | | String talentCardNo, String area, String workUnit, String workAddress, String contactAddress, |
| | | Set<String> fileMobiles, Set<String> fileIdCards, Set<String> fileCardNos) { |
| | | if (name.isBlank()) return "姓名不能为空"; |
| | | if (mobile.isBlank()) return "手机号不能为空"; |
| | | if (idCardNo.isBlank()) return "身份证号不能为空"; |
| | | if (gender.isBlank()) return "性别不能为空"; |
| | | if (level.isBlank()) return "卡片等级不能为空"; |
| | | if (talentCardNo.isBlank()) return "人才卡号不能为空"; |
| | | if (area.isBlank()) return "外地/本地不能为空"; |
| | | if (workUnit.isBlank()) return "工作单位不能为空"; |
| | | if (workAddress.isBlank()) return "工作地址不能为空"; |
| | | if (contactAddress.isBlank()) return "联系地址不能为空"; |
| | | if (name.isBlank()) return "姓名不能为空"; |
| | | if (name.length() > 64) return "姓名不能超过64个字符"; |
| | | if (!mobile.matches("^1\\d{10}$")) return "手机号须为11位数字"; |
| | | if (!idCardNo.matches("^[0-9A-Z]{18}$")) return "身份证号须为18位数字或大写英文字母"; |
| | | if (!gender.isBlank() && !Set.of("男", "女").contains(gender)) return "性别只能填写男或女"; |
| | | if (!TALENT_LEVELS.contains(level)) return "卡片等级须填写卓越人才卡、杰出人才卡、普通人才卡或普通游客"; |
| | | if (!TALENT_LEVELS.contains(level)) return "卡片等级须填写卓越人才卡、杰出人才卡、菁英人才卡或普通游客"; |
| | | if (!talentCardNo.matches("^[0-9A-Z-]{1,64}$")) return "人才卡号只能包含大写字母、数字和短横线"; |
| | | if (!area.isBlank() && !Set.of("本地", "外地").contains(area)) return "外地/本地只能填写本地或外地"; |
| | | if (workUnit.length() > 128) return "工作单位不能超过128个字符"; |
| | |
| | | return null; |
| | | } |
| | | |
| | | private Long advisorIdByName(String advisorName) { |
| | | if (advisorName == null || advisorName.isBlank()) return null; |
| | | List<Long> ids = jdbcTemplate.queryForList( |
| | | "select id from talent_card_advisor where status = 1 and advisor_name = ?", |
| | | Long.class, advisorName.trim()); |
| | | return ids.size() == 1 ? ids.get(0) : null; |
| | | } |
| | | |
| | | private Byte genderValue(String gender) { |
| | | if ("男".equals(gender)) return 1; |
| | | if ("女".equals(gender)) return 2; |