| | |
| | | import cn.afterturn.easypoi.excel.entity.ImportParams; |
| | | import cn.hutool.core.util.PhoneUtil; |
| | | import cn.hutool.json.JSONObject; |
| | | import cn.hutool.core.util.PhoneUtil; |
| | | import com.xiaopeng.api.model.account.SysUser; |
| | | import com.xiaopeng.api.model.operation.XpWhitelist; |
| | | import com.xiaopeng.api.model.operation.XpWhitelistOperlog; |
| | |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.Comparator; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | ImportParams params = new ImportParams(); |
| | | // params.setTitleRows(1); // 标题行数 |
| | | params.setHeadRows(1); //表头行数 |
| | | InputStream inputStream = null; |
| | | // List<CustomerImportFailedData> failedData = new ArrayList<>(); |
| | | List<WhitelistImportExcel> whitelistImportExcels; |
| | | try { |
| | | inputStream = file.getInputStream(); |
| | | try (InputStream inputStream = file.getInputStream()) { |
| | | whitelistImportExcels = ExcelImportUtil.importExcel(inputStream, |
| | | WhitelistImportExcel.class, params); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | log.error("白名单导入失败:{}", e.getMessage()); |
| | | throw new ServiceException("白名单导入失败!"); |
| | | } finally { |
| | | try { |
| | | inputStream.close(); |
| | | } catch (IOException e) { |
| | | throw new ServiceException(e.getMessage()); |
| | | } |
| | | } |
| | | if (CollectionUtils.isEmpty(whitelistImportExcels)) { |
| | | throw new ServiceException("白名单数据为空!"); |
| | | } |
| | | // 校验手机号白名单是否有重复的 |
| | | long count = whitelistImportExcels.stream().map(WhitelistImportExcel::getAccount) |
| | | .distinct().count(); |
| | | if (count != whitelistImportExcels.size()) { |
| | | return AjaxResult.error("白名单手机号存在重复!"); |
| | | } |
| | | Map<String, Long> codeMap = xpWhitelistService.list().stream() |
| | | .collect(Collectors.toMap( |
| | | XpWhitelist::getAccount, |
| | | XpWhitelist::getId, |
| | | (existing, replacement) -> replacement // 如果冲突,用新的覆盖 |
| | | )); |
| | | JSONObject result = new JSONObject(); |
| | | List<XpWhitelist> addList = new ArrayList<>(); |
| | | for (WhitelistImportExcel whitelistImportExcel : whitelistImportExcels) { |
| | | // 手机号正则校验 |
| | | boolean isPhone = PhoneUtil.isPhone(whitelistImportExcel.getAccount()); |
| | | if (!isPhone) { |
| | | result.append("白名单:[", whitelistImportExcel.getAccount() + "]手机号格式错误"); |
| | | |
| | | int sampleLimitPerReason = 20; |
| | | int totalCount = whitelistImportExcels.size(); |
| | | Map<String, Long> reasonCountMap = new HashMap<>(); |
| | | Map<String, LinkedHashSet<String>> reasonSampleMap = new HashMap<>(); |
| | | |
| | | // 先做基础校验 + 文件内去重(允许部分成功) |
| | | Set<String> seenAccounts = new HashSet<>(); |
| | | List<WhitelistImportExcel> candidates = new ArrayList<>(); |
| | | for (int i = 0; i < whitelistImportExcels.size(); i++) { |
| | | WhitelistImportExcel row = whitelistImportExcels.get(i); |
| | | String account = trimToNull(row.getAccount()); |
| | | String nickName = trimToNull(row.getNickName()); |
| | | row.setAccount(account); |
| | | row.setNickName(nickName); |
| | | |
| | | int excelRowNumber = i + params.getHeadRows() + 1; |
| | | if (!StringUtils.hasLength(account)) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "账号为空", "第" + excelRowNumber + "行", sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | Long id = codeMap.get(whitelistImportExcel.getAccount()); |
| | | if (id != null) { |
| | | result.append("白名单:[", whitelistImportExcel.getAccount() + "]已存在"); |
| | | if (!PhoneUtil.isPhone(account)) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "账号格式不正确", account, sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | if (!seenAccounts.add(account)) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "文件内账号重复", account, sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | candidates.add(row); |
| | | } |
| | | |
| | | // 批量查询数据库已存在账号(避免全表扫描) |
| | | Set<String> existsAccounts = Collections.emptySet(); |
| | | if (!CollectionUtils.isEmpty(candidates)) { |
| | | Set<String> candidateAccounts = candidates.stream() |
| | | .map(WhitelistImportExcel::getAccount) |
| | | .filter(StringUtils::hasLength) |
| | | .collect(Collectors.toSet()); |
| | | if (!CollectionUtils.isEmpty(candidateAccounts)) { |
| | | existsAccounts = xpWhitelistService.lambdaQuery() |
| | | .select(XpWhitelist::getAccount) |
| | | .in(XpWhitelist::getAccount, candidateAccounts) |
| | | .list() |
| | | .stream() |
| | | .map(XpWhitelist::getAccount) |
| | | .filter(StringUtils::hasLength) |
| | | .collect(Collectors.toSet()); |
| | | } |
| | | } |
| | | |
| | | List<XpWhitelist> addList = new ArrayList<>(); |
| | | SysUser sysUser = tokenService.getLoginUser().getSysUser(); |
| | | for (WhitelistImportExcel whitelistImportExcel : candidates) { |
| | | if (existsAccounts.contains(whitelistImportExcel.getAccount())) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "账号已存在", whitelistImportExcel.getAccount(), sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | XpWhitelist xpWhitelist = new XpWhitelist(); |
| | |
| | | xpWhitelist.setStatus(true); |
| | | xpWhitelist.setIsPriorityDispatch(true); |
| | | xpWhitelist.setWhitelistSource(1); |
| | | xpWhitelist.setCreateBy(tokenService.getLoginUser().getSysUser().getNickName()); |
| | | xpWhitelist.setCreateBy(sysUser.getNickName()); |
| | | addList.add(xpWhitelist); |
| | | } |
| | | if (!result.isEmpty()) { |
| | | return AjaxResult.success(result.toString()); |
| | | |
| | | int successCount = addList.size(); |
| | | int failCount = totalCount - successCount; |
| | | |
| | | String message; |
| | | if (failCount == 0) { |
| | | message = "成功添加" + successCount + "条白名单记录"; |
| | | } else if (successCount == 0) { |
| | | message = "所有帐号添加失败,请检查格式或唯一性"; |
| | | } else { |
| | | String reasonDetail = buildReasonDetail(reasonCountMap, reasonSampleMap); |
| | | message = "成功添加" + successCount + "条," + failCount + "条添加失败:原因" + reasonDetail; |
| | | } |
| | | |
| | | if (successCount == 0) { |
| | | return AjaxResult.error(message, message); |
| | | } |
| | | |
| | | xpWhitelistService.saveBatch(addList); |
| | | SysUser sysUser = tokenService.getLoginUser().getSysUser(); |
| | | StringBuilder operationContent = new StringBuilder("共计导入"+addList.size()+"条数据"); |
| | | StringBuilder operationContent = new StringBuilder("白名单导入:成功添加") |
| | | .append(successCount).append("条,失败").append(failCount).append("条"); |
| | | if (failCount > 0) { |
| | | operationContent.append(";原因").append(buildReasonSummary(reasonCountMap)); |
| | | } |
| | | String opContent = truncate(operationContent.toString(), 200); |
| | | XpWhitelistOperlog xpWhitelistOperlog = new XpWhitelistOperlog(); |
| | | xpWhitelistOperlog.setOperationName(sysUser.getNickName()); |
| | | xpWhitelistOperlog.setOperationAccount(sysUser.getPhoneNumber()); |
| | | xpWhitelistOperlog.setOperationType(4); |
| | | xpWhitelistOperlog.setOperationIp(IpUtils.getIpAddr()); |
| | | xpWhitelistOperlog.setOperationAccountId(sysUser.getId()); |
| | | xpWhitelistOperlog.setOperationContent(operationContent.toString()); |
| | | xpWhitelistOperlog.setCreateBy(tokenService.getLoginUser().getSysUser().getNickName()); |
| | | xpWhitelistOperlog.setOperationContent(opContent); |
| | | xpWhitelistOperlog.setCreateBy(sysUser.getNickName()); |
| | | xpWhitelistOperlogService.save(xpWhitelistOperlog); |
| | | return AjaxResult.success(); |
| | | |
| | | return AjaxResult.success(message, message); |
| | | } |
| | | |
| | | private static String trimToNull(String value) { |
| | | if (!StringUtils.hasLength(value)) { |
| | | return null; |
| | | } |
| | | String trimmed = value.trim(); |
| | | return StringUtils.hasLength(trimmed) ? trimmed : null; |
| | | } |
| | | |
| | | private static void incReason(Map<String, Long> reasonCountMap, String reason) { |
| | | reasonCountMap.merge(reason, 1L, Long::sum); |
| | | } |
| | | |
| | | private static void recordFail(Map<String, Long> reasonCountMap, |
| | | Map<String, LinkedHashSet<String>> reasonSampleMap, |
| | | String reason, |
| | | String sample, |
| | | int sampleLimitPerReason) { |
| | | incReason(reasonCountMap, reason); |
| | | if (!StringUtils.hasLength(sample) || sampleLimitPerReason <= 0) { |
| | | return; |
| | | } |
| | | LinkedHashSet<String> samples = reasonSampleMap.computeIfAbsent(reason, k -> new LinkedHashSet<>()); |
| | | if (samples.size() >= sampleLimitPerReason) { |
| | | return; |
| | | } |
| | | samples.add(sample); |
| | | } |
| | | |
| | | private static String buildReasonSummary(Map<String, Long> reasonCountMap) { |
| | | if (reasonCountMap == null || reasonCountMap.isEmpty()) { |
| | | return "请检查格式或唯一性"; |
| | | } |
| | | return reasonCountMap.entrySet().stream() |
| | | .sorted(Comparator.<Map.Entry<String, Long>>comparingLong(e -> e.getValue() == null ? 0L : e.getValue()) |
| | | .reversed() |
| | | .thenComparing(Map.Entry::getKey)) |
| | | .map(e -> e.getKey() + "(" + (e.getValue() == null ? 0L : e.getValue()) + ")") |
| | | .collect(Collectors.joining(",")); |
| | | } |
| | | |
| | | private static String buildReasonDetail(Map<String, Long> reasonCountMap, |
| | | Map<String, LinkedHashSet<String>> reasonSampleMap) { |
| | | if (reasonCountMap == null || reasonCountMap.isEmpty()) { |
| | | return "请检查格式或唯一性"; |
| | | } |
| | | Map<String, LinkedHashSet<String>> safeSamples = reasonSampleMap == null ? Collections.emptyMap() : reasonSampleMap; |
| | | return reasonCountMap.entrySet().stream() |
| | | .sorted(Comparator.<Map.Entry<String, Long>>comparingLong(e -> e.getValue() == null ? 0L : e.getValue()) |
| | | .reversed() |
| | | .thenComparing(Map.Entry::getKey)) |
| | | .map(entry -> { |
| | | String reason = entry.getKey(); |
| | | long count = entry.getValue() == null ? 0L : entry.getValue(); |
| | | LinkedHashSet<String> samples = safeSamples.getOrDefault(reason, new LinkedHashSet<>()); |
| | | String samplePart = ""; |
| | | if (!samples.isEmpty()) { |
| | | long remaining = count - samples.size(); |
| | | String suffix = remaining > 0 ? "等" + remaining + "个" : ""; |
| | | samplePart = "[" + String.join(",", samples) + (StringUtils.hasLength(suffix) ? ("," + suffix) : "") + "]"; |
| | | } |
| | | return reason + "(" + count + ")" + samplePart; |
| | | }) |
| | | .collect(Collectors.joining(";")); |
| | | } |
| | | |
| | | private static String truncate(String value, int maxLength) { |
| | | if (value == null || maxLength <= 0) { |
| | | return value; |
| | | } |
| | | if (value.length() <= maxLength) { |
| | | return value; |
| | | } |
| | | return value.substring(0, maxLength); |
| | | } |
| | | |
| | | @ApiOperation(value = "白名单导出") |