| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.alibaba.excel.EasyExcel; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.sinata.appointment.constants.BizErrorCode; |
| | |
| | | import com.sinata.appointment.dto.FieldConfigPatchRequest; |
| | | import com.sinata.appointment.dto.SensitiveWordCreateRequest; |
| | | import com.sinata.appointment.dto.SensitiveWordEnabledPatchRequest; |
| | | import com.sinata.appointment.dto.SensitiveWordImportResultVo; |
| | | import com.sinata.appointment.dto.SensitiveWordListVo; |
| | | import com.sinata.appointment.dto.SensitiveWordUpdateRequest; |
| | | import com.sinata.appointment.dto.VisitReasonCreateRequest; |
| | |
| | | import com.sinata.appointment.mapper.SysBizSettingMapper; |
| | | import com.sinata.appointment.mapper.SysDeptMapper; |
| | | import com.sinata.appointment.util.UuidAssert; |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.IOException; |
| | | import java.time.LocalDate; |
| | | import java.time.YearMonth; |
| | | import java.time.format.DateTimeParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.UUID; |
| | | import java.util.stream.Collectors; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.StringUtils; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | |
| | | loadActiveSensitiveWord(id, uuid); |
| | | bizSensitiveWordMapper.deleteById(id); |
| | | sensitiveWordFilterService.evictCache(); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public SensitiveWordImportResultVo importSensitiveWords(MultipartFile file) { |
| | | if (file == null || file.isEmpty()) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "导入文件不能为空"); |
| | | } |
| | | String filename = file.getOriginalFilename() == null ? "" : file.getOriginalFilename().toLowerCase(); |
| | | if (!filename.endsWith(".xlsx") && !filename.endsWith(".xls")) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请上传 xls 或 xlsx 文件"); |
| | | } |
| | | |
| | | List<Map<Integer, String>> rows; |
| | | try { |
| | | rows = EasyExcel.read(file.getInputStream()).sheet().headRowNumber(0).doReadSync(); |
| | | } catch (IOException ex) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "读取导入文件失败"); |
| | | } |
| | | |
| | | SensitiveWordImportResultVo result = new SensitiveWordImportResultVo(); |
| | | Set<String> fileWords = new LinkedHashSet<>(); |
| | | Set<String> existingWords = loadExistingSensitiveWords(); |
| | | int rowNo = 0; |
| | | for (Map<Integer, String> row : rows) { |
| | | rowNo++; |
| | | String raw = row == null ? null : row.get(0); |
| | | if (rowNo == 1 && isSensitiveWordHeader(raw)) { |
| | | continue; |
| | | } |
| | | if (!StringUtils.hasText(raw)) { |
| | | continue; |
| | | } |
| | | result.setTotalRows(result.getTotalRows() + 1); |
| | | String word; |
| | | try { |
| | | word = normalizeSensitiveWord(raw); |
| | | } catch (BizException ex) { |
| | | result.setInvalidCount(result.getInvalidCount() + 1); |
| | | addImportError(result, "第" + rowNo + "行:" + ex.getMessage()); |
| | | continue; |
| | | } |
| | | if (fileWords.contains(word) || existingWords.contains(word)) { |
| | | result.setDuplicateCount(result.getDuplicateCount() + 1); |
| | | continue; |
| | | } |
| | | BizSensitiveWord entity = new BizSensitiveWord(); |
| | | entity.setWord(word); |
| | | entity.setEnabled(1); |
| | | bizSensitiveWordMapper.insert(entity); |
| | | fileWords.add(word); |
| | | existingWords.add(word); |
| | | result.setSuccessCount(result.getSuccessCount() + 1); |
| | | } |
| | | if (result.getSuccessCount() > 0) { |
| | | sensitiveWordFilterService.evictCache(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | public byte[] sensitiveWordImportTemplateExcel() { |
| | | try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { |
| | | List<List<String>> head = List.of(List.of("敏感词")); |
| | | List<List<String>> rows = List.of(List.of("示例敏感词")); |
| | | EasyExcel.write(bos).head(head).sheet("敏感词导入").doWrite(rows); |
| | | return bos.toByteArray(); |
| | | } catch (IOException ex) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "生成导入模板失败"); |
| | | } |
| | | } |
| | | |
| | | public List<BizFieldConfig> listFieldConfigs() { |
| | |
| | | return normalized; |
| | | } |
| | | |
| | | private Set<String> loadExistingSensitiveWords() { |
| | | List<BizSensitiveWord> rows = |
| | | bizSensitiveWordMapper.selectList( |
| | | new LambdaQueryWrapper<BizSensitiveWord>() |
| | | .eq(BizSensitiveWord::getDelFlag, 0) |
| | | .select(BizSensitiveWord::getWord)); |
| | | Set<String> words = new HashSet<>(); |
| | | for (BizSensitiveWord row : rows) { |
| | | if (StringUtils.hasText(row.getWord())) { |
| | | words.add(row.getWord().trim()); |
| | | } |
| | | } |
| | | return words; |
| | | } |
| | | |
| | | private boolean isSensitiveWordHeader(String value) { |
| | | if (!StringUtils.hasText(value)) { |
| | | return false; |
| | | } |
| | | String text = value.trim(); |
| | | return "敏感词".equals(text) || "敏感词库".equals(text) || "word".equalsIgnoreCase(text); |
| | | } |
| | | |
| | | private void addImportError(SensitiveWordImportResultVo result, String message) { |
| | | if (result.getErrorMessages().size() < 20) { |
| | | result.getErrorMessages().add(message); |
| | | } |
| | | } |
| | | |
| | | private void assertReasonNameUnique(String reasonName, Long excludeId) { |
| | | LambdaQueryWrapper<BizVisitReason> q = |
| | | new LambdaQueryWrapper<BizVisitReason>() |