basic-server/src/main/java/com/ruoyi/basic/controller/StandardTreeController.java
@@ -193,6 +193,12 @@ return Result.success(standardTreeService.selectTemplateBindings(standardTreeId)); } @Operation(summary = "æ ¹æ®æ åæ¹æ³æ¥è¯¢æ åç»å®çåå§è®°å½æ¨¡æ¿") @GetMapping("/selectTemplateBindingsByStandardMethod") public Result selectTemplateBindingsByStandardMethod(Integer standardMethodId) { return Result.success(standardTreeService.selectTemplateBindingsByStandardMethod(standardMethodId)); } @Operation(summary = "ä¿åæ åç»å®çåå§è®°å½æ¨¡æ¿") @PostMapping("/saveTemplateBindings") public Result saveTemplateBindings(@RequestBody StandardTreeTemplateBindingDto dto) { basic-server/src/main/java/com/ruoyi/basic/service/StandardTreeService.java
@@ -43,6 +43,13 @@ List<StandardTreeTemplateBindingVo> selectTemplateBindings(Integer standardTreeId); /** * æ ¹æ®æ åæ¹æ³æ¥è¯¢æ ååºä¸å·²ç»å®çåå§è®°å½æ¨¡æ¿ * @param standardMethodId æ åæ¹æ³ID * @return å·²ç»å®ç模æ¿ï¼å¤ä¸ªæ ååºèç¹ç»å®ç模æ¿ä¼å»éåå¹¶ï¼ */ List<StandardTreeTemplateBindingVo> selectTemplateBindingsByStandardMethod(Integer standardMethodId); boolean saveTemplateBindings(StandardTreeTemplateBindingDto dto); List<TemplateInspectionItemDto> selectTemplateInspectionItems(Integer standardTreeId); basic-server/src/main/java/com/ruoyi/basic/service/impl/StandardTreeServiceImpl.java
@@ -419,6 +419,29 @@ } @Override public List<StandardTreeTemplateBindingVo> selectTemplateBindingsByStandardMethod(Integer standardMethodId) { List<StandardTreeTemplateBindingVo> result = new ArrayList<>(); if (standardMethodId == null) { return result; } List<StandardTree> trees = this.list(Wrappers.<StandardTree>lambdaQuery() .eq(StandardTree::getStandardMethodId, standardMethodId) .isNull(StandardTree::getSampleType) .isNull(StandardTree::getModel) .isNotNull(StandardTree::getSample) .orderByAsc(StandardTree::getId)); Set<Integer> templateIds = new HashSet<>(); for (StandardTree tree : trees) { for (StandardTreeTemplateBindingVo binding : selectTemplateBindings(tree.getId())) { if (templateIds.add(binding.getTemplateId())) { result.add(binding); } } } return result; } @Override @Transactional(rollbackFor = Exception.class) public boolean saveTemplateBindings(StandardTreeTemplateBindingDto dto) { if (dto == null || dto.getStandardTreeId() == null) { basic-server/src/main/java/com/ruoyi/basic/utils/StandardTemplateInspectionItemParser.java
@@ -13,9 +13,10 @@ import java.util.List; import java.util.Set; /** è§£æ Luckysheet åå§è®°å½æ¨¡æ¿ä¸çâæ£éªé¡¹âæ è®°ã */ /** è§£æ Luckysheet åå§è®°å½æ¨¡æ¿ä¸çâæ£éªé¡¹âï¼æªæ è®°æ¶åéå°â导åºå¼âè¡ã */ public final class StandardTemplateInspectionItemParser { private static final String INSPECTION_ITEM_MARK = "æ£éªé¡¹"; private static final String EXPORT_VALUE_MARK = "导åºå¼"; private StandardTemplateInspectionItemParser() { } @@ -34,11 +35,22 @@ } catch (Exception e) { throw new BaseException("åå§è®°å½æ¨¡æ¿æ ¼å¼é误"); } List<TemplateInspectionItemDto> result = new ArrayList<>(); Set<Integer> rows = new HashSet<>(); if (sheets == null) { throw new BaseException("åå§è®°å½æ¨¡æ¿æ ¼å¼é误"); } List<TemplateInspectionItemDto> result = parseMarkedCells(sheets, templateId, templateSort, INSPECTION_ITEM_MARK); if (result.isEmpty()) { result = parseMarkedCells(sheets, templateId, templateSort, EXPORT_VALUE_MARK); } result.sort(Comparator.comparing(TemplateInspectionItemDto::getTemplateRowIndex)); return result; } private static List<TemplateInspectionItemDto> parseMarkedCells(JSONArray sheets, Integer templateId, Integer templateSort, String mark) { List<TemplateInspectionItemDto> result = new ArrayList<>(); Set<Integer> rows = new HashSet<>(); for (Object sheetObject : sheets) { JSONObject sheet = (JSONObject) sheetObject; JSONArray cells = sheet.getJSONArray("celldata"); @@ -48,16 +60,19 @@ for (Object cellObject : cells) { JSONObject cell = (JSONObject) cellObject; JSONObject value = cell.getJSONObject("v"); if (value == null || !isInspectionItem(value)) { if (value == null || !hasMark(value, mark)) { continue; } Integer row = cell.getInteger("r"); String item = getCellText(value); if (row == null || !StringUtils.hasText(item)) { throw new BaseException("âæ£éªé¡¹âæ è®°æå¨åå æ ¼å¿ 须填忣éªé¡¹åç§°"); throw new BaseException("â" + mark + "âæ è®°æå¨åå æ ¼å¿ 须填忣éªé¡¹åç§°"); } if (!rows.add(row)) { throw new BaseException("å䏿¨¡æ¿è¡åªè½é ç½®ä¸ä¸ªâæ£éªé¡¹âæ è®°"); if (EXPORT_VALUE_MARK.equals(mark)) { continue; } throw new BaseException("å䏿¨¡æ¿è¡åªè½é ç½®ä¸ä¸ªâ" + mark + "âæ è®°"); } TemplateInspectionItemDto dto = new TemplateInspectionItemDto(); dto.setTemplateId(templateId); @@ -67,7 +82,6 @@ result.add(dto); } } result.sort(Comparator.comparing(TemplateInspectionItemDto::getTemplateRowIndex)); return result; } @@ -101,8 +115,8 @@ return richText.toString(); } private static boolean isInspectionItem(JSONObject value) { private static boolean hasMark(JSONObject value, String mark) { JSONObject ps = value.getJSONObject("ps"); return ps != null && INSPECTION_ITEM_MARK.equals(ps.getString("value")); return ps != null && mark.equals(ps.getString("value")); } } cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentAlterServiceImpl.java
@@ -13,7 +13,9 @@ import com.ruoyi.common.utils.QueryWrappers; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.system.mapper.UserMapper; import com.ruoyi.manage.util.DocumentPreviewUtils; import com.ruoyi.manage.mapper.*; @@ -239,21 +241,11 @@ @Override public void checkManageDocumentAlterPdf(Long id, HttpServletResponse response) throws Exception { ManageDocumentAlter manageDocumentAlter = manageDocumentAlterMapper.selectById(id); File file = new File(wordUrl + "/" + manageDocumentAlter.getAlterAfterUrl()); FileInputStream fileInputStream = new FileInputStream(file); response.setContentType("application/pdf"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-disposition", "inline;filename=" + file.getName()); response.setContentLength((int)file.length()); OutputStream os = response.getOutputStream(); // å°æä»¶å 容åå ¥è¾åºæµ byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fileInputStream.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); if (manageDocumentAlter == null || ObjectUtils.isEmpty(manageDocumentAlter.getAlterAfterUrl())) { throw new ErrorException("æä»¶æªä¸ä¼ "); } os.flush(); os.close(); // PDF ç´æ¥è¾åºï¼Word/å¾çå¨çº¿è½¬ PDFï¼ä¾å端é¢è§çç« DocumentPreviewUtils.writeAsPdf(new File(wordUrl + "/" + manageDocumentAlter.getAlterAfterUrl()), response); } @Override cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentControlledServiceImpl.java
@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.core.domain.entity.User; import com.ruoyi.common.utils.QueryWrappers; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.manage.mapper.ManageDocumentControlledMapper; import com.ruoyi.manage.mapper.ManageDocumentListMapper; import com.ruoyi.manage.mapper.ManageRecordCheckMapper; @@ -15,6 +16,7 @@ import com.ruoyi.manage.pojo.ManageDocumentList; import com.ruoyi.manage.pojo.ManageRecordCheck; import com.ruoyi.manage.service.ManageDocumentControlledService; import com.ruoyi.manage.util.DocumentPreviewUtils; import com.ruoyi.system.mapper.UserMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -199,21 +201,11 @@ @Override public void checkManageDocumentControlledPdf(Long id, HttpServletResponse response) throws Exception { ManageDocumentControlled manageDocumentControlled = manageDocumentControlledMapper.selectById(id); File file = new File(wordUrl + "/" + manageDocumentControlled.getUrl()); FileInputStream fileInputStream = new FileInputStream(file); response.setContentType("application/pdf"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-disposition", "inline;filename=" + file.getName()); response.setContentLength((int)file.length()); OutputStream os = response.getOutputStream(); // å°æä»¶å 容åå ¥è¾åºæµ byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fileInputStream.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); if (manageDocumentControlled == null || ObjectUtils.isEmpty(manageDocumentControlled.getUrl())) { throw new ErrorException("æä»¶æªä¸ä¼ "); } os.flush(); os.close(); // PDF ç´æ¥è¾åºï¼Word/å¾çå¨çº¿è½¬ PDFï¼ä¾å端é¢è§çç« DocumentPreviewUtils.writeAsPdf(new File(wordUrl + "/" + manageDocumentControlled.getUrl()), response); } } cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentListServiceImpl.java
@@ -11,6 +11,7 @@ import com.ruoyi.common.utils.QueryWrappers; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.manage.mapper.ManageDocumentListMapper; import com.ruoyi.manage.pojo.ManageDocumentList; import com.ruoyi.manage.service.ManageDocumentListService; @@ -25,6 +26,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,29 +61,29 @@ @Override public int uploadFile(Integer id, MultipartFile file) { String urlString; String pathName; String path; ManageDocumentList manageDocumentList = manageDocumentListMapper.selectById(id); if (ObjectUtils.isNotEmpty(manageDocumentList.getUrl())){ // å 餿§æä»¶ File oldFile = new File(wordUrl + "/" + manageDocumentList.getUrl()); oldFile.delete(); if (manageDocumentList == null) { throw new ErrorException("æä»¶æ¸ åä¸åå¨"); } //ä¸ä¼ æ°æä»¶ path = wordUrl; if (file == null || file.isEmpty()) { throw new ErrorException("è¯·éæ©è¦ä¸ä¼ çæä»¶"); } File realpath = new File(wordUrl).getAbsoluteFile(); try { File realpath = new File(path); if (!realpath.exists()) { realpath.mkdirs(); if (!realpath.exists() && !realpath.mkdirs()) { throw new IOException("ç®å½å建失败: " + realpath); } pathName = UUID.randomUUID() + "_" + file.getOriginalFilename(); urlString = realpath + "/" + pathName; file.transferTo(new File(urlString)); // ç¨ Files.copy è䏿¯ transferToï¼transferTo éå°ç¸å¯¹è·¯å¾ä¼æ Tomcat 临æ¶ç®å½è§£æ Files.copy(file.getInputStream(), new File(realpath, pathName).toPath(), StandardCopyOption.REPLACE_EXISTING); } catch (Exception e) { e.printStackTrace(); System.err.println("éä»¶ä¸ä¼ é误"); return 0; throw new ErrorException("éä»¶ä¸ä¼ é误: " + e.getMessage()); } if (ObjectUtils.isNotEmpty(manageDocumentList.getUrl())) { // å 餿§æä»¶ new File(realpath, manageDocumentList.getUrl()).delete(); } manageDocumentList.setUrl(pathName); return manageDocumentListMapper.updateById(manageDocumentList); cnas-manage/src/main/java/com/ruoyi/manage/util/DocumentPreviewUtils.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,90 @@ package com.ruoyi.manage.util; import com.aspose.words.Document; import com.aspose.words.DocumentBuilder; import com.aspose.words.License; import com.aspose.words.SaveFormat; import com.ruoyi.framework.exception.ErrorException; import jakarta.servlet.http.HttpServletResponse; import org.springframework.core.io.ClassPathResource; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; /** * ä½ç³»æä»¶éä»¶é¢è§å·¥å ·ï¼æéä»¶ç»ä¸ä»¥ PDF æµè¾åºç»å端é¢è§/çç« ã * PDF åæ ·è¾åºï¼Wordãå¾çç¨ Aspose.Words å¨çº¿è½¬ PDFï¼Excel/PPT çæ æ³è½¬ PDF çæ ¼å¼ç»åºæç¡®æç¤ºã */ public final class DocumentPreviewUtils { private static final String[] WORD_EXT = {".doc", ".docx", ".rtf", ".txt", ".wps"}; private static final String[] IMAGE_EXT = {".png", ".jpg", ".jpeg", ".bmp", ".gif"}; private DocumentPreviewUtils() { } public static void writeAsPdf(File file, HttpServletResponse response) throws Exception { if (file == null || !file.exists()) { throw new ErrorException("éä»¶ä¸åå¨æå·²è¢«å é¤"); } String name = file.getName().toLowerCase(); if (name.endsWith(".pdf")) { prepare(response, file.getName(), file.length()); try (InputStream in = new FileInputStream(file); OutputStream os = response.getOutputStream()) { in.transferTo(os); os.flush(); } return; } Document doc; if (endsWithAny(name, WORD_EXT)) { applyLicense(); doc = new Document(file.getPath()); } else if (endsWithAny(name, IMAGE_EXT)) { applyLicense(); doc = new Document(); new DocumentBuilder(doc).insertImage(file.getPath()); } else { throw new ErrorException("该æä»¶æ ¼å¼ä¸æ¯æå¨çº¿çç« é¢è§ï¼è¯·ä¸ä¼ PDF æ Word æä»¶"); } // å 转æ¢å°å åï¼è½¬æ¢å¤±è´¥æ¶ååºå¤´è¿æ²¡æäº¤ï¼å端æè½æ¶å°éè¯¯ä¿¡æ¯ ByteArrayOutputStream buffer = new ByteArrayOutputStream(); doc.save(buffer, SaveFormat.PDF); byte[] bytes = buffer.toByteArray(); prepare(response, file.getName() + ".pdf", bytes.length); try (OutputStream os = response.getOutputStream()) { os.write(bytes); os.flush(); } } private static void prepare(HttpServletResponse response, String fileName, long length) { response.setContentType("application/pdf"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-disposition", "inline;filename=" + fileName); response.setContentLength((int) length); } private static boolean endsWithAny(String name, String[] suffixes) { for (String suffix : suffixes) { if (name.endsWith(suffix)) { return true; } } return false; } private static void applyLicense() throws Exception { // åè¯ï¼å¦å转æ¢åå¸¦æ°´å° try (InputStream is = new ClassPathResource("lib/license.xml").getInputStream()) { License license = new License(); license.setLicense(is); } } } cnas-personnel/src/main/java/com/ruoyi/personnel/controller/PersonTrainingController.java
@@ -96,8 +96,17 @@ public Result<?> addOrUpdatePersonTrainingDetailed(@RequestBody PersonTrainingDetailed personTrainingDetailed) { if (ObjectUtils.isEmpty(personTrainingDetailed.getId())) { personTrainingDetailed.setState(3); personTrainingDetailedService.save(personTrainingDetailed); return Result.success(); } personTrainingDetailedService.saveOrUpdate(personTrainingDetailed); // 讲å¸å¯è½å¨å é¨äººååå¤è人åä¹é´åæ¢ï¼å æ¾å¼è¦ç两åï¼é¿å updateById è·³è¿ null å¯¼è´æ§å¼æ®ç personTrainingDetailedService.update(null, Wrappers.<PersonTrainingDetailed>lambdaUpdate() .eq(PersonTrainingDetailed::getId, personTrainingDetailed.getId()) .set(PersonTrainingDetailed::getTrainingLecturerId, personTrainingDetailed.getTrainingLecturerId()) .set(PersonTrainingDetailed::getTrainingLecturerName, personTrainingDetailed.getTrainingLecturerName())); personTrainingDetailed.setTrainingLecturerId(null); personTrainingDetailed.setTrainingLecturerName(null); personTrainingDetailedService.updateById(personTrainingDetailed); return Result.success(); } cnas-personnel/src/main/java/com/ruoyi/personnel/pojo/PersonTrainingDetailed.java
@@ -56,6 +56,9 @@ @Schema(description = "å¹è®è®²å¸_id") private Integer trainingLecturerId; @Schema(description = "å¤è/éç³»ç»è®²å¸å§åï¼å é¨è®²å¸ä»å trainingLecturerId") private String trainingLecturerName; @Schema(description = "计åå¹è®æ¥æ") private String trainingDate; cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingDetailedServiceImpl.java
@@ -2,7 +2,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -47,17 +47,24 @@ PersonTrainingDetailed personTrainingDetailed = new PersonTrainingDetailed(); BeanUtils.copyProperties(i, personTrainingDetailed); // å¹é è®²å¸ User user = userMapper.selectOne(Wrappers.<User>lambdaQuery() .eq(User::getName, i.getTrainingLecturerName())); if (ObjectUtils.isEmpty(user)) { throw new ErrorException("æªæ¾å°è¯¥è®²å¸ï¼" + i.getTrainingLecturerName()); // å¹é 讲å¸ï¼ç³»ç»å å¯ä¸å¹é çåç¨æ·IDï¼å¤è/éç³»ç»è®²å¸æå§åææ¬ä¿å if (StringUtils.isBlank(i.getTrainingLecturerName())) { throw new ErrorException("å¹è®è®²å¸ä¸è½ä¸ºç©º"); } personTrainingDetailed.setTrainingLecturerId(user.getId()); String lecturerName = i.getTrainingLecturerName().trim(); List<User> lecturers = userMapper.selectList(Wrappers.<User>lambdaQuery() .eq(User::getName, lecturerName)); if (lecturers.size() == 1) { personTrainingDetailed.setTrainingLecturerId(lecturers.get(0).getId()); personTrainingDetailed.setTrainingLecturerName(null); } else { personTrainingDetailed.setTrainingLecturerId(null); personTrainingDetailed.setTrainingLecturerName(lecturerName); } personTrainingDetailed.setPlanId(planId); personTrainingDetailed.setState(3); personTrainingDetailed.setTrainingDate(i.getTrainingDate()); personTrainingDetailed.setTrainingDate(normalizeTrainingDate(i.getTrainingDate())); personTrainingDetailedList.add(personTrainingDetailed); @@ -68,6 +75,32 @@ } } /** * å¹è®æ¶é´ç»ä¸æ yyyy-MM-ddã * Excel é被èªå¨è¯å«ææ¥æçåå æ ¼è¯»åºæ¥æ¯ 2026/3/15ï¼æå·¥å½å ¥çæ¯ 2026-03-15ï¼ * è¿éç»ä¸è½¬æ¢ï¼é¿å å¯¼åºæ¶æ ¼å¼ä¸ä¸è´ã */ private String normalizeTrainingDate(String value) { if (value == null || value.isBlank()) { return value; } String text = value.trim().split("\\s+")[0] .replace('å¹´', '-').replace('æ', '-').replace("æ¥", "") .replace('/', '-').replace('.', '-'); String[] parts = text.split("-"); if (parts.length == 3) { try { int year = Integer.parseInt(parts[0].trim()); int month = Integer.parseInt(parts[1].trim()); int day = Integer.parseInt(parts[2].trim()); return String.format("%04d-%02d-%02d", year, month, day); } catch (NumberFormatException ignored) { // 䏿¯å¯è¯å«çæ¥ææ ¼å¼ï¼åæ ·ä¿å } } return value.trim(); } @Override public void deleteAnnualPlanDetailTable(String ids) { String[] split = ids.split(","); cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingServiceImpl.java
@@ -19,6 +19,7 @@ import com.ruoyi.common.utils.WxCpUtils; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.inspect.util.HackLoopTableRenderPolicy; import com.ruoyi.inspect.util.UserUtils; import com.ruoyi.personnel.dto.PersonTrainingDetailedDto; import com.ruoyi.personnel.dto.PersonTrainingDto; import com.ruoyi.personnel.dto.PersonTrainingRecordDto; @@ -131,11 +132,14 @@ message += "CNASå¹è®è®¡åå®¡æ ¸éç¥"; message += "\n请å»èµæºç®¡ç-人å-å¹è®è®¡åå¡«å"; message += "\n" + fileName + "çå¹è®è®¡åå¾ å®¡æ ¸"; //åéä¼ä¸å¾®ä¿¡æ¶æ¯éç¥ //åéä¼ä¸å¾®ä¿¡æ¶æ¯éç¥ï¼æ¥æ¶äººä¸å卿åé失败ä¸å½±åå¯¼å ¥æµç¨ï¼ if (personnel == null || StringUtils.isBlank(personnel.getAccount())) { return; } try { WxCpUtils.inform(personnel.getAccount(), message, null); } catch (Exception e) { throw new RuntimeException(e); e.printStackTrace(); } }); @@ -306,9 +310,10 @@ // æ¥è¯¢äººåå¹è®æç» PersonTrainingDetailedDto detailedDto = personTrainingDetailedMapper.selectTrainingDetail(id); // çæå¹è®èå¸ç¾å detailedDto.setTrainingLecturerRender(StringUtils.isNotBlank(detailedDto.getTrainingLecturerSignatureUrl()) ? Pictures.ofLocal(imgUrl + "/" + detailedDto.getTrainingLecturerSignatureUrl()).create() : null); // çæå¹è®èå¸ç¾åï¼æªé ç½®ç¾åæ¶ç¨éæå¾çå åºï¼æ¨¡æ¿éçå¾çå ä½ä¸è½ä¸º nullï¼ detailedDto.setTrainingLecturerRender(UserUtils.orTransparentPicture( StringUtils.isNotBlank(detailedDto.getTrainingLecturerSignatureUrl()) ? Pictures.ofLocal(imgUrl + "/" + detailedDto.getTrainingLecturerSignatureUrl()).create() : null)); // æ¥è¯¢å¹è®ç人å List<PersonTrainingRecordDto> recordDtos = personTrainingRecordMapper.selectListByTrainingDetailedId(id); @@ -320,15 +325,15 @@ for (PersonTrainingRecordDto recordDto : recordDtos) { switch (count) { case 0: exportDto.setUserNameRender1(StringUtils.isNotBlank(recordDto.getSignatureUrl()) ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null); exportDto.setUserNameRender1(UserUtils.orTransparentPicture(StringUtils.isNotBlank(recordDto.getSignatureUrl()) ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null)); exportDto.setDepartment1(recordDto.getDepartment()); exportDto.setExaminationResults1(recordDto.getExaminationResults()); count ++; break; case 1: exportDto.setUserNameRender2(StringUtils.isNotBlank(recordDto.getSignatureUrl()) ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null); exportDto.setUserNameRender2(UserUtils.orTransparentPicture(StringUtils.isNotBlank(recordDto.getSignatureUrl()) ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null)); exportDto.setDepartment2(recordDto.getDepartment()); exportDto.setExaminationResults2(recordDto.getExaminationResults()); exportDtoList.add(exportDto); @@ -337,14 +342,17 @@ break; } } // åªæåæ°æ¡è®°å½æ¶ï¼æåä¸è¡æææ°æ®ï¼å¶æ°æ¡æ¶ exportDto æ¯ç©ºå¯¹è±¡ï¼ä¸è½å è¿è¡¨æ ¼ if (count != 0) { exportDtoList.add(exportDto); } // è´¨éè´è´£äºº // è´¨éè´è´£äººï¼æªç¾åæ¶ç¨éæå¾çå åºï¼ String assessmentUserUrl = null; if (detailedDto.getAssessmentUserId() != null) { assessmentUserUrl = userMapper.selectById(detailedDto.getAssessmentUserId()).getSignatureUrl(); if (StringUtils.isBlank(assessmentUserUrl)) { throw new ErrorException("æ¾ä¸å°è¯ä»·äººçç¾å"); User assessmentUser = userMapper.selectById(detailedDto.getAssessmentUserId()); if (assessmentUser != null) { assessmentUserUrl = assessmentUser.getSignatureUrl(); } } @@ -359,7 +367,8 @@ new HashMap<String, Object>() {{ put("trainingDetail", detailedDto); put("trainingRecordsList", exportDtoList); put("assessmentUserUrl", StringUtils.isNotBlank(finalAssessmentUserUrl) ? Pictures.ofLocal(imgUrl + "/" + finalAssessmentUserUrl).create() : null); put("assessmentUserUrl", UserUtils.orTransparentPicture(StringUtils.isNotBlank(finalAssessmentUserUrl) ? Pictures.ofLocal(imgUrl + "/" + finalAssessmentUserUrl).create() : null)); }}); try { response.setContentType("application/msword"); cnas-personnel/src/main/resources/mapper/PersonTrainingDetailedMapper.xml
@@ -4,7 +4,7 @@ <select id="queryTheAnnualPlanDetailsTable" resultType="com.ruoyi.personnel.dto.PersonTrainingDetailedDto"> SELECT cptd.*, u1.name training_lecturer_name, COALESCE(u1.name, cptd.training_lecturer_name) training_lecturer_name, dl.name holding_department_name, !isnull(cptr.training_record_id) whether_claim FROM cnas_person_training_detailed cptd left join user u1 on cptd.training_lecturer_id = u1.id @@ -18,7 +18,7 @@ and u1.id = #{userId} </if> <if test="trainingLecturerName != null and trainingLecturerName != ''"> and u1.name like concat('%', #{trainingLecturerName}, '%') and COALESCE(u1.name, cptd.training_lecturer_name) like concat('%', #{trainingLecturerName}, '%') </if> <if test="trainingDate != null and trainingDate != ''"> and date_format(cptd.training_date,'%Y-%m-%d') = #{trainingDate} @@ -29,7 +29,7 @@ <!-- æ ¹æ®ä¸»è¡¨idæ¥è¯¢è¯¦æ --> <select id="selectTrainingList" resultType="com.ruoyi.personnel.dto.PersonTrainingDetailedDto"> SELECT cptd.*, u1.name training_lecturer_name COALESCE(u1.name, cptd.training_lecturer_name) training_lecturer_name FROM cnas_person_training_detailed cptd left join user u1 on cptd.training_lecturer_id = u1.id where cptd.plan_id = #{trainingId} @@ -38,7 +38,7 @@ <!-- æ¥è¯¢è¯¦ç» --> <select id="selectTrainingDetail" resultType="com.ruoyi.personnel.dto.PersonTrainingDetailedDto"> SELECT cptd.*, u1.name training_lecturer_name, COALESCE(u1.name, cptd.training_lecturer_name) training_lecturer_name, u1.signature_url training_lecturer_signature_url FROM cnas_person_training_detailed cptd left join user u1 on cptd.training_lecturer_id = u1.id cnas-process/src/main/java/com/ruoyi/process/controller/QualitySuperviseController.java
@@ -191,6 +191,16 @@ } /** * 被çç£äººå确认çç£è®°å½ * @return */ @Operation(summary = "被çç£äººå确认çç£è®°å½") @PostMapping("/confirmSuperviseRecord") public Result confirmSuperviseRecord(@RequestBody QualitySuperviseDetailsRecord qualitySuperviseDetailsRecord){ return Result.success(qualitySuperviseService.confirmSuperviseRecord(qualitySuperviseDetailsRecord)); } /** * 导åºè´¨éçç£è¯¦æ è®°å½è¡¨ * @return */ cnas-process/src/main/java/com/ruoyi/process/pojo/QualityMonitorDetailsEvaluate.java
@@ -29,10 +29,16 @@ @Schema(description = "å ³èçè´¨æ§æ£éªä»»å¡ID") private Integer insOrderId; @Schema(description = "çç£åç¨æ·IDï¼ä¸è¯ä»·äººåå¼") @Schema(description = "çç£åç¨æ·IDï¼é»è®¤ä¸ºè®¡å䏿å®çè¯ä»·äºº") private Integer supervisorUserId; @Schema(description = "çç£ååç§°ï¼éæ°æ®åºå段") @TableField(exist = false) private String supervisorName; @Schema(description = "被çç£æ£æµåç¨æ·ID") private Integer inspectorUserId; @Schema(description = "被çç£æ£æµååç§°ï¼éæ°æ®åºå段") @TableField(exist = false) private String inspectorName; @Schema(description = "æ£æµæ ·ååç§°") private String sampleName; @Schema(description = "æ£æµæ ·åè§æ ¼") cnas-process/src/main/java/com/ruoyi/process/pojo/QualitySuperviseDetailsRecord.java
@@ -14,7 +14,8 @@ * @since 2024-11-07 */ @Data @TableName("cnas_quality_supervise_details_record") // autoResultMap: testing_process/supervision_evaluation å¤ç¨äºåå²åå, éè¦ MP èªå¨çæç»ææ å° @TableName(value = "cnas_quality_supervise_details_record", autoResultMap = true) @Schema(description = "è´¨éçç£è¯¦æ è®°å½è¡¨") public class QualitySuperviseDetailsRecord { @@ -51,8 +52,9 @@ @Schema(description = "æ£æµæ¥æ") private String testDate; @Schema(description = "æ£æµè¿ç¨") private String testingProcess; @Schema(description = "çç£æ¹å¼(å¤é¡¹é¡¿å·åé)ï¼æ ¸æ¥åå§è®°å½åæ¥åãç°åºçç£å®é æä½è¿ç¨ç") @TableField("testing_process") private String superviseMethod; @Schema(description = "æ åµè®°å½") private String caseReload; @@ -81,8 +83,9 @@ @Schema(description = "æ£æµæ¥å") private String examiningReport; @Schema(description = "çç£æ åµè¯ä»·") private String supervisionEvaluation; @Schema(description = "被çç£äººå确认æè§(ç¨åº4.2.5)") @TableField("supervision_evaluation") private String confirmOpinion; @Schema(description = "ä¸åæ ¼å¤çæè§") private String handlingAdvice; cnas-process/src/main/java/com/ruoyi/process/service/QualityMonitorInspectionEvaluationService.java
@@ -61,6 +61,14 @@ evaluation.setSampleName(detail.getSampleName()); evaluation.setSampleSpec(detail.getSampleSpec()); } // è¯ä»·è®°å½éçâçç£åâå°±æ¯è®¡å䏿å®çâè¯ä»·äººâï¼æªä¿åè¿è¯ä»·æ¶ç´æ¥åæ¾è¯ä»·äºº if (evaluation.getSupervisorUserId() == null) { evaluation.setSupervisorUserId(detail.getEvaluatorUserId()); } // åå²è¯ä»·è®°å½å¯è½æ²¡æä¿å被çç£äººåï¼åéå°è®¡åæç»ä¸çæ£æµå if (evaluation.getInspectorUserId() == null) { evaluation.setInspectorUserId(detail.getInspectorUserId()); } List<QualityMonitorEvaluateResult> rows = evaluation.getDetailsEvaluateId() == null ? List.of() : resultMapper.selectList(Wrappers.<QualityMonitorEvaluateResult>lambdaQuery() .eq(QualityMonitorEvaluateResult::getDetailsEvaluateId, evaluation.getDetailsEvaluateId()) @@ -85,6 +93,15 @@ } evaluation.setResultRows(rows); evaluation.setInspectionTaskState(task == null ? null : task.getInsState()); // çç£åãæ£æµåå¯è½ä¸å¨å端人å䏿å表ä¸ï¼è§è²æç¶æè¢«è¿æ»¤ï¼ï¼åä¼ åç§°ä¿è¯è½æ£å¸¸åæ¾ if (evaluation.getSupervisorUserId() != null) { var supervisor = userMapper.selectById(evaluation.getSupervisorUserId()); if (supervisor != null) evaluation.setSupervisorName(supervisor.getName()); } if (evaluation.getInspectorUserId() != null) { var inspector = userMapper.selectById(evaluation.getInspectorUserId()); if (inspector != null) evaluation.setInspectorName(inspector.getName()); } if (Integer.valueOf(1).equals(evaluation.getIsFinish())) { evaluation.setEvaluationEditReason("è¯ä»·å·²æ¹å彿¡£ï¼åªè½æ¥ç"); } else if (task == null) { @@ -117,9 +134,8 @@ throw new ErrorException("åªææå®è¯ä»·äººå¯ä»¥å¡«åè¯ä»·"); if (input.getSupervisorUserId() == null || input.getSupervisorUserId().equals(detail.getInspectorUserId()) || input.getSupervisorUserId().equals(detail.getEvaluatorUserId()) || userMapper.selectById(input.getSupervisorUserId()) == null) throw new ErrorException("è¯·éæ©ä¸æ£æµåãè¯ä»·äººä¸åççç£å"); throw new ErrorException("è¯·éæ©çç£åï¼é»è®¤ä¸ºè®¡åè¯ä»·äººï¼ä¸è½ä¸æ£æµåç¸åï¼"); Long pendingCount = stateMapper.selectCount(Wrappers.<InsOrderState>lambdaQuery() .eq(InsOrderState::getInsOrderId, task.getId()).ne(InsOrderState::getInsState, 5)); if (pendingCount > 0) throw new ErrorException("åå§è®°å½å¤æ ¸éè¿åæè½è¯ä»·"); cnas-process/src/main/java/com/ruoyi/process/service/QualityMonitorService.java
@@ -30,9 +30,9 @@ /** * å¯¼å ¥çæ§è®¡å * @param file * @return * @return å¯¼å ¥åçæçè稿计å */ boolean importQualityMonitor(MultipartFile file, QualityMonitor qualityMonitor); QualityMonitor importQualityMonitor(MultipartFile file, QualityMonitor qualityMonitor); /** cnas-process/src/main/java/com/ruoyi/process/service/QualitySuperviseService.java
@@ -90,6 +90,13 @@ boolean addSuperviseRecordOpinion(QualitySuperviseDetailsRecord qualitySuperviseDetailsRecord); /** * 被çç£äººå确认çç£è®°å½(ç¨åº4.2.5) * @param qualitySuperviseDetailsRecord è³å°å å« superviseDetailsId å confirmOpinion * @return */ boolean confirmSuperviseRecord(QualitySuperviseDetailsRecord qualitySuperviseDetailsRecord); /** * 导åºçç£è®°å½è¡¨ * @param superviseDetailsId * @param response cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java
@@ -211,7 +211,7 @@ * @return */ @Override public boolean importQualityMonitor(MultipartFile file, QualityMonitor monitor) { public QualityMonitor importQualityMonitor(MultipartFile file, QualityMonitor monitor) { // å½åç»å½ç¨æ· Integer userId = SecurityUtils.getUserId().intValue(); // æä»¶åç§° @@ -226,39 +226,10 @@ qualityMonitor.setWriteUserId(userId); qualityMonitor.setExamineUserId(monitor.getExamineUserId()); qualityMonitor.setWriteTime(LocalDateTime.now()); qualityMonitor.setWorkflowStatus("PENDING_REVIEW"); // å¯¼å ¥åªçæè稿ï¼å¯¼å ¥çè´¨æ§é¡¹ç®è¿éè¦è¡¥å ¨æ£æµæ åãæ£æµåçä¿¡æ¯ï¼ // å®¡æ ¸éç¥å¨ç¼å¶äººç¹å»âæäº¤å®¡æ ¸âæ¶ç»ä¸åéã qualityMonitor.setWorkflowStatus("DRAFT"); baseMapper.insert(qualityMonitor); User user = userMapper.selectById(userId); // æ¶æ¯åé InformationNotification info = new InformationNotification(); // åé人 info.setCreateUser(user.getName()); info.setMessageType("6"); info.setTheme("CNASè´¨éçæ§è®¡åå®¡æ ¸éç¥"); info.setContent(fileName + "è´¨éçæ§è®¡åå¾ å®¡æ ¸"); info.setSenderId(userId); // æ¥æ¶äºº info.setConsigneeId(monitor.getExamineUserId()); info.setJumpPath(MenuJumpPathConstants.QUALITY_MONITOR); informationNotificationService.addInformationNotification(info); // åéä¼ä¸å¾®ä¿¡éç¥ threadPoolTaskExecutor.execute(() -> { // æ¥è¯¢åé人 User people = userMapper.selectById(monitor.getExamineUserId()); String message = ""; message += "CNASè´¨éçæ§è®¡åå®¡æ ¸éç¥"; message += "\n请å»è¿ç¨è¦æ±-è´¨éçæ§è®¡å"; message += "\n" + fileName + "è´¨éçæ§è®¡åå¾ å®¡æ ¸"; //åéä¼ä¸å¾®ä¿¡æ¶æ¯éç¥ try { WxCpUtils.inform(people.getAccount(), message, null); } catch (Exception e) { throw new RuntimeException(e); } }); List<QualityMonitorDetails> detailsUploadList = new ArrayList<>(); @@ -277,6 +248,7 @@ // 对象å¤å¶ QualityMonitorDetails monitorDetails = new QualityMonitorDetails(); BeanUtils.copyProperties(detailsUpload, monitorDetails); monitorDetails.setMonitorWay(normalizeMonitorWay(detailsUpload.getMonitorWay())); monitorDetails.setQualityMonitorId(qualityMonitor.getQualityMonitorId()); if (!detailsUpload.getCompletionMonth().matches("\\d{4}-\\d{2}")) { throw new ErrorException("宿æ¶éæ ¼å¼åºä¸ºyyyy-MM"); @@ -303,7 +275,21 @@ } catch (IOException e) { throw new RuntimeException(e); } return true; return qualityMonitor; } /** * è´¨æ§æ¹å¼ç»ä¸ç¨âãâåéï¼å ¼å®¹å¯¼å ¥æ¨¡æ¿é常è§çéå·/åå·åæ³ã */ private String normalizeMonitorWay(String value) { if (StringUtils.isBlank(value)) { return value; } return java.util.Arrays.stream(value.split("[ã,ï¼;ï¼]")) .map(String::trim) .filter(StringUtils::isNotBlank) .distinct() .collect(Collectors.joining("ã")); } /** @@ -657,7 +643,7 @@ try { response.setContentType("application/msword"); String fileName = URLEncoder.encode( "è´¨éçæ§å®æ½è®¡å", "UTF-8"); "è´¨éæ§å¶æªæ½", "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx"); OutputStream os = response.getOutputStream(); @@ -871,7 +857,7 @@ try { response.setContentType("application/msword"); String fileName = URLEncoder.encode( "çæ§è¯ä»·", "UTF-8"); "è´¨éæ§å¶è¯ä»·è®°å½", "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx"); OutputStream os = response.getOutputStream(); cnas-process/src/main/java/com/ruoyi/process/service/impl/QualitySuperviseServiceImpl.java
@@ -56,6 +56,8 @@ import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.Base64; import java.util.HashMap; import java.util.LinkedHashSet; @@ -178,8 +180,8 @@ throw new ErrorException("æªæ¾å°è¢«çç£åï¼" + superviseDetails.getSupervisee()); } superviseDetails.setSupervisedUserId(user.getId()); // æ ¼å¼åæ¶é´ superviseDetails.setSuperviseTime(detailsUpload.getSuperviseTime()); // ç»ä¸æ¥ææ ¼å¼ï¼é¿å Excel æ 2026-03-15 åæ 2026/3/15 åæ æ³è§£æ superviseDetails.setSuperviseTime(normalizeSuperviseTime(detailsUpload.getSuperviseTime())); detailsUploadList.add(superviseDetails); } @@ -432,6 +434,59 @@ } /** * ç»ä¸çç£æ¥ææ ¼å¼ä¸º yyyy.Mï¼ * 2026-03-15 / 2026/3/15 / 2026.3.15 / 2026å¹´3æ15æ¥ -> 2026.3ï¼ * å·²ç»æ¯ 2026.3 æ "3æã12æ" çåæ³ä¿æåæ ·ã */ private static String normalizeSuperviseTime(String superviseTime) { if (StringUtils.isBlank(superviseTime)) { return superviseTime; } String text = superviseTime.trim(); Matcher matcher = Pattern.compile("^(\\d{4})\\s*[./å¹´-]\\s*(\\d{1,2})(?:\\s*[./æ-]\\s*(\\d{1,2})\\s*æ¥?)?$") .matcher(text); if (matcher.matches()) { int month = Integer.parseInt(matcher.group(2)); if (month >= 1 && month <= 12) { return matcher.group(1) + "." + month; } } return text; } /** * è§£æçç£æ¥æå¯¹åºçå¹´æï¼å ¼å®¹å岿°æ®ä¸ç宿´æ¥æåæ³ã */ private static YearMonth parseSuperviseYearMonth(String superviseTime, String fallbackYear) { if (StringUtils.isNotBlank(superviseTime)) { String first = superviseTime.split("[ã,ï¼;ï¼]+")[0].trim(); Matcher fullDate = Pattern.compile("(\\d{4})\\s*[./å¹´-]\\s*(\\d{1,2})").matcher(first); if (fullDate.find()) { int month = Integer.parseInt(fullDate.group(2)); if (month >= 1 && month <= 12) { return YearMonth.of(Integer.parseInt(fullDate.group(1)), month); } } // "3æã12æ" è¿ç±»æ²¡æå¹´ä»½çåæ³ï¼ä½¿ç¨è®¡å年度 Matcher monthOnly = Pattern.compile("^(\\d{1,2})").matcher(first); if (monthOnly.find()) { int month = Integer.parseInt(monthOnly.group(1)); if (month >= 1 && month <= 12) { int year = LocalDate.now().getYear(); if (StringUtils.isNotBlank(fallbackYear)) { Matcher yearMatcher = Pattern.compile("(\\d{4})").matcher(fallbackYear); if (yearMatcher.find()) { year = Integer.parseInt(yearMatcher.group(1)); } } return YearMonth.of(year, month); } } } return YearMonth.now(); } /** * çç£é¢æ¬¡: æçç£æ¶é´ä¸çæä»½ä¸ªæ°è®¡ç®, å¦ "2026.3" -> "1次/å¹´", "3æã12æ" -> "2次/å¹´" */ private static String buildSuperviseFrequency(String superviseTime) { @@ -439,7 +494,7 @@ return ""; } int count = 0; for (String part : superviseTime.split("[ã,ï¼;ï¼/\\s]+")) { for (String part : normalizeSuperviseTime(superviseTime).split("[ã,ï¼;ï¼/\\s]+")) { if (part.matches(".*\\d.*")) { count++; } @@ -456,7 +511,7 @@ } StringBuilder sb = new StringBuilder(); for (String part : superviseTime.split("[ã,ï¼;ï¼]+")) { String s = part.trim(); String s = normalizeSuperviseTime(part.trim()); if (s.isEmpty()) { continue; } @@ -491,9 +546,11 @@ if (detailsRecord == null) { // æ¥è¯¢è¯¦æ ä¿¡æ¯ QualitySuperviseDetails qualitySuperviseDetails = qualitySuperviseDetailsMapper.selectById(superviseDetailsId); QualitySupervise qualitySupervise = baseMapper.selectById(qualitySuperviseDetails.getSuperviseId()); // æ¥è¯¢ä¸ä¸ä¸ªæç¬¬ä¸æ¡çè®°å½ä¿¡æ¯, å¤æè¢«çç£äººå»å¦å¤ä¸ä¸ª DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.M"); YearMonth yearMonth = YearMonth.parse(qualitySuperviseDetails.getSuperviseTime(), formatter); // çç£æ¥æå ¼å®¹ 2026.3 / 2026-03-15 / 2026/3/15 / 2026å¹´3æ15æ¥ çåæ³ YearMonth yearMonth = parseSuperviseYearMonth(qualitySuperviseDetails.getSuperviseTime(), qualitySupervise == null ? null : qualitySupervise.getSuperviseYear()); YearMonth previousYearMonth = yearMonth.minusMonths(1); LocalDate startDate = previousYearMonth.atDay(1); @@ -515,21 +572,17 @@ String supervisor = null; if (laseRecord != null) { // æ¥è¯¢è®¡åè·åå¦ä¸ä¸ªçç£å QualitySupervise qualitySupervise = baseMapper.selectById(qualitySuperviseDetails.getSuperviseId()); if (StringUtils.isNotBlank(qualitySupervise.getRecordUserIds())) { // 计åæå®ççç£åï¼é¦æ¬¡å¡«åæ¶é»è®¤å¸¦åºç¬¬ä¸ä½ï¼æä¸æè®°å½æ¶ä¸¤ä½çç£åäº¤æ¿ if (qualitySupervise != null && StringUtils.isNotBlank(qualitySupervise.getRecordUserIds())) { List<String> recordUserIds = StrUtil.split(qualitySupervise.getRecordUserIds(), ','); List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery() .in(User::getId, recordUserIds)); if (CollectionUtils.isNotEmpty(users) && users.size() == 2) { // 夿æ¯å¦ä¸æ ·, 䏿 ·è·åå¦å¤ä¸ä¸ª if (users.get(0).getName().equals(laseRecord.getSupervisor())) { if (CollectionUtils.isNotEmpty(users)) { if (laseRecord != null && users.size() > 1 && users.get(0).getName().equals(laseRecord.getSupervisor())) { supervisor = users.get(1).getName(); } else { supervisor = users.get(0).getName(); } } } } @@ -643,6 +696,47 @@ } /** * 被çç£äººå确认çç£è®°å½(ç¨åº4.2.5: 被çç£å¯¹è±¡å¯¹çç£è®°å½ç宿§æåºç¡®è®¤æè§) */ @Override public boolean confirmSuperviseRecord(QualitySuperviseDetailsRecord input) { if (input == null || input.getSuperviseDetailsId() == null) { throw new ErrorException("缺å°çç£è¯¦ç»ä¿¡æ¯id"); } QualitySuperviseDetailsRecord record = qualitySuperviseDetailsRecordMapper.selectOne( Wrappers.<QualitySuperviseDetailsRecord>lambdaQuery() .eq(QualitySuperviseDetailsRecord::getSuperviseDetailsId, input.getSuperviseDetailsId()) .last("limit 1")); if (record == null) { throw new ErrorException("çç£åå°æªæäº¤çç£è®°å½ï¼æ æ³ç¡®è®¤"); } Integer userId = SecurityUtils.getUserId().intValue(); User user = userMapper.selectById(userId); if (user == null) { throw new ErrorException("å½åç¨æ·ä¸åå¨"); } // åªæè¢«çç£äººåæ¬äººæå¯ä»¥ç¡®è®¤ boolean isSupervisee = StrUtil.split(record.getTestMember(), 'ã').stream() .map(String::trim) .anyMatch(name -> name.equals(user.getName())); if (!isSupervisee) { QualitySuperviseDetails detail = qualitySuperviseDetailsMapper.selectById(input.getSuperviseDetailsId()); isSupervisee = detail != null && userId.equals(detail.getSupervisedUserId()); } if (!isSupervisee) { throw new ErrorException("åªæè¢«çç£äººåå¯ä»¥ç¡®è®¤çç£è®°å½"); } String opinion = StringUtils.isBlank(input.getConfirmOpinion()) ? "对çç£è®°å½ç宿§è¡¨ç¤ºè®¤å¯ã" : input.getConfirmOpinion().trim(); qualitySuperviseDetailsRecordMapper.update(null, Wrappers.<QualitySuperviseDetailsRecord>lambdaUpdate() .eq(QualitySuperviseDetailsRecord::getSuperviseDetailsRecordId, record.getSuperviseDetailsRecordId()) .set(QualitySuperviseDetailsRecord::getConfirmOpinion, opinion)); return true; } /** * 导åºçç£è®°å½è¡¨(æ¥å¸¸çç£æ£æ¥è®°å½è¡¨) * @param superviseDetailsId * @param response @@ -670,6 +764,11 @@ put("qualityUrl", signatureOrTransparent(recordDto.getRatifyUserId())); put("qualityDateStr", recordDto.getRatifyTime() != null ? recordDto.getRatifyTime().format(RECORD_DATE_FORMATTER) : ""); // ç¨åº4.2.5: 被çç£äººå对çç£è®°å½ç宿§ç确认æè§, æªç¡®è®¤æ¶æ²¿ç¨çº¸å¼ 表çé»è®¤è¡¨è¿° put("confirmOpinionText", StringUtils.isNotBlank(recordDto.getConfirmOpinion()) ? recordDto.getConfirmOpinion() : "对çç£è®°å½ç宿§è¡¨ç¤ºè®¤å¯ã"); put("superviseMethodText", StringUtils.isNotBlank(recordDto.getSuperviseMethod()) ? recordDto.getSuperviseMethod() : ""); }}); try { @@ -690,7 +789,7 @@ } /** * çç£å 容(9项, æçº¸å¼ 表横æé¡ºåº) * çç£å 容(9项, ä¸åæ§è®°å½è¡¨ LMSY-CX29-JL02 çæ¨ªæé¡ºåºãæåå®å ¨ä¸è´) */ private static final String[] SUPERVISE_CONTENT_ITEMS = { "人åæè¯åå¹è®", "设æ½åç¯å¢æ¡ä»¶", "æ£æµæ¹æ³", cnas-process/src/main/java/com/ruoyi/process/task/QualitySuperviseSchedule.java
@@ -91,8 +91,9 @@ List<QualitySuperviseDetails> qualitySuperviseDetails = qualitySuperviseDetailsMapper.selectList(Wrappers.<QualitySuperviseDetails>lambdaQuery() .eq(QualitySuperviseDetails::getSuperviseTime, format)); // æ ¹æ®å®æçç£å卿çç£åºå Map<String, List<QualitySuperviseDetails>> superviseReasonMap = qualitySuperviseDetails.stream().collect(Collectors.groupingBy(QualitySuperviseDetails::getSuperviseReason)); // æ ¹æ®çç£åå åºå(宿çç£/卿çç£), çç£åå å 许æå·¥å¡«åæä¸ºç©º, è¿éå空å¼å åº Map<String, List<QualitySuperviseDetails>> superviseReasonMap = qualitySuperviseDetails.stream() .collect(Collectors.groupingBy(details -> StrUtil.nullToEmpty(details.getSuperviseReason()))); // è·åå½ææ¥æ DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyå¹´MMæ"); cnas-process/src/main/resources/mapper/QualitySuperviseDetailsRecordMapper.xml
@@ -4,7 +4,10 @@ <!--导åºçç£è®°å½è¡¨--> <select id="selectSuperviseDetailRecord" resultType="com.ruoyi.process.pojo.QualitySuperviseDetailsRecord"> select cqsdr.* <!-- å¤ç¨åå²å testing_process / supervision_evaluationï¼resultType èªå¨æ å°éè¦å«å --> select cqsdr.*, cqsdr.testing_process as supervise_method, cqsdr.supervision_evaluation as confirm_opinion from cnas_quality_supervise_details_record cqsdr where cqsdr.supervise_details_id = #{superviseDetailsId} </select> cnas-process/src/main/resources/static/daily-supervise-record.docxBinary files differ
cnas-process/src/main/resources/static/quality-monitor-details-ratify.docxBinary files differ
cnas-process/src/main/resources/static/quality-monitor-evaluate.docxBinary files differ
cnas-process/src/main/resources/static/quality-monitor.docxBinary files differ
inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsOrder.java
@@ -42,6 +42,9 @@ @Schema(description = "è´¨éçæ§è®¡åæç»ID") private Integer qualityMonitorDetailsId; @Schema(description = "æ°èç´ç»æ¨¡æ¿ä¸åæ¶éæ©çæ ååºäºçº§èç¹ID") private Integer standardTreeId; @Schema(description = "ä¸å客æ·") private String custom; inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsOrderStandardTemplate.java
@@ -64,6 +64,9 @@ @Schema(description = "åå§è®°å½å·²å¡«ååå æ ¼ï¼æåæ ä¿å") private String recordValues; @Schema(description = "é»è®¤è®¾å¤æ¯å¦å·²å¨é¦æ¬¡è¿å ¥æ£éªä»»å¡æ¶åå§åï¼0å¦ï¼1æ¯") private Integer deviceDefaultsInitialized; @Schema(description = "è¯¥æ¨¡æ¿æ£éªæ¶ç温度") private String temperature; inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
@@ -1659,6 +1659,8 @@ refreshed.setRemark(standardTemplate == null ? oldSnapshot.getRemark() : standardTemplate.getRemark()); refreshed.setThing(standardTemplate == null ? oldSnapshot.getThing() : standardTemplate.getThing()); refreshed.setRecordValues(templateRecordValuesMap.get(templateId)); refreshed.setDeviceDefaultsInitialized(oldSnapshot == null ? 1 : oldSnapshot.getDeviceDefaultsInitialized()); refreshed.setTemperature(templateTemperatureMap.get(templateId)); refreshed.setHumidity(templateHumidityMap.get(templateId)); // å·æ°æ¨¡æ¿ç»ææ¶å¿ é¡»ä¿çæ£éªé¶æ®µå¡«åçä¸å¡æ°æ®ï¼é¿å è¿å ¥å¤æ ¸ååæ¾ä¸ºç©ºã inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -581,6 +581,9 @@ .thenComparing(item -> item.getTemplateRowIndex() == null ? Integer.MAX_VALUE : item.getTemplateRowIndex())) .collect(Collectors.toList()); if (templateItems.isEmpty()) { throw new ErrorException("æéåå§è®°å½æ¨¡æ¿æªé ç½®æ£éªé¡¹æå¯¼åºå¼ï¼ä¸è½ä¸å"); } StandardMethod standardMethod = standardMethodService.getById(standard.getStandardMethodId()); if (standardMethod == null || StringUtils.isBlank(standardMethod.getCode())) { @@ -596,6 +599,7 @@ order.setIsExemption(0); order.setFactory(null); order.setLaboratory(standard.getLaboratory()); order.setStandardTreeId(dto.getStandardTreeId()); order.setSampleType(null); order.setSample(standardCode); order.setPrepareUserEn(null); @@ -740,6 +744,9 @@ .sorted(Comparator.comparing((TemplateInspectionItemDto item) -> templateSortMap.get(item.getTemplateId())) .thenComparing(item -> item.getTemplateRowIndex() == null ? Integer.MAX_VALUE : item.getTemplateRowIndex())) .collect(Collectors.toList()); if (templateItems.isEmpty()) { throw new ErrorException("æéåå§è®°å½æ¨¡æ¿æªé ç½®æ£éªé¡¹æå¯¼åºå¼ï¼ä¸è½ä¸å"); } StandardMethod standardMethod = standardMethodService.getById(standard.getStandardMethodId()); if (standardMethod == null || StringUtils.isBlank(standardMethod.getCode())) { throw new ErrorException("æ åç¼å·ä¸åå¨"); @@ -754,6 +761,7 @@ order.setIsExemption(currentOrder.getIsExemption()); order.setFactory(null); order.setLaboratory(standard.getLaboratory()); order.setStandardTreeId(dto.getStandardTreeId()); order.setSampleType(null); order.setSample(standardCode); order.setPrepareUserEn(null); @@ -839,6 +847,7 @@ snapshot.setRemark(template.getRemark()); snapshot.setThing(template.getThing()); snapshot.setSort(selection.getSort()); snapshot.setDeviceDefaultsInitialized(0); insOrderStandardTemplateMapper.insert(snapshot); StandardTreeTemplateBindingVo binding = bindingMap.get(selection.getTemplateId()); @@ -929,7 +938,9 @@ .eq(StandardMethod::getCode, insOrder.getSample()) .select(StandardMethod::getId)).stream() .map(StandardMethod::getId).collect(Collectors.toList()); if (!methodIds.isEmpty() && !orderTemplateIds.isEmpty()) { if (insOrder.getStandardTreeId() != null) { map.put("standardTreeId", insOrder.getStandardTreeId()); } else if (!methodIds.isEmpty() && !orderTemplateIds.isEmpty()) { List<StandardTree> candidates = standardTreeService.list(Wrappers.<StandardTree>lambdaQuery() .in(StandardTree::getStandardMethodId, methodIds) .isNull(StandardTree::getSampleType) @@ -1053,8 +1064,10 @@ } @Override @Transactional(rollbackFor = Exception.class) public Map<String, Object> getInsOrderAndSample(Integer id, String laboratory) { Map<String, Object> map = new HashMap<>(); initializeTemplateDevicesOnFirstOpen(id); // InsOrder insOrder = insOrderMapper.selectById(id); IfsOrderVO ifsOrderVO = insOrderMapper.selectOrderInfoById(id); Map<Integer, List<Integer>> templateDeviceIds = insOrderTemplateDeviceMapper.selectList( @@ -1097,6 +1110,127 @@ return map; } /** 馿¬¡æå¼æ£éªä»»å¡æ¶ï¼å°ä»ä¸ºç©ºç模æ¿è®¾å¤ä»å¯¹åºæ åè¡¥å ¥è®¢åã */ private void initializeTemplateDevicesOnFirstOpen(Integer orderId) { InsOrder order = insOrderMapper.selectById(orderId); if (order == null || !DIRECT_TEMPLATE_LABORATORY.equals(order.getLaboratory()) || !Objects.equals(order.getTypeSource(), -1) || !Objects.equals(order.getState(), 1) || "QUALITY_MONITOR".equals(order.getTaskSource())) { return; } List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateMapper.selectList( Wrappers.<InsOrderStandardTemplate>lambdaQuery() .eq(InsOrderStandardTemplate::getInsOrderId, orderId) .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId) .last("FOR UPDATE")); if (snapshots.isEmpty() || snapshots.stream().allMatch( snapshot -> Objects.equals(snapshot.getDeviceDefaultsInitialized(), 1))) { return; } Set<Integer> existingTemplateIds = insOrderTemplateDeviceMapper.selectList( Wrappers.<InsOrderTemplateDevice>lambdaQuery() .eq(InsOrderTemplateDevice::getInsOrderId, orderId)) .stream().map(InsOrderTemplateDevice::getTemplateId) .filter(Objects::nonNull).collect(Collectors.toSet()); boolean inspectionStarted = order.getFirstInspectDate() != null || (order.getInsState() != null && order.getInsState() > 0) || snapshots.stream().anyMatch(snapshot -> StringUtils.isNotBlank(snapshot.getRecordValues()) || snapshot.getDetectionTime() != null || snapshot.getTemperature() != null || snapshot.getDetectionPlace() != null); Map<Integer, List<Integer>> defaults = inspectionStarted ? Collections.emptyMap() : findStandardDeviceDefaults(order, snapshots); for (InsOrderStandardTemplate snapshot : snapshots) { if (Objects.equals(snapshot.getDeviceDefaultsInitialized(), 1)) { continue; } Integer templateId = snapshot.getTemplateId(); if (!inspectionStarted && !existingTemplateIds.contains(templateId) && defaults.containsKey(templateId)) { List<Integer> deviceIds = defaults.get(templateId); for (int index = 0; index < deviceIds.size(); index++) { InsOrderTemplateDevice relation = new InsOrderTemplateDevice(); relation.setInsOrderId(orderId); relation.setTemplateId(templateId); relation.setDeviceId(deviceIds.get(index)); relation.setSort(index); insOrderTemplateDeviceMapper.insert(relation); } } // æ æ³å¯ä¸ç¡®å®æ¥æºæ¶ä¹åªå°è¯è¿ä¸æ¬¡ï¼é¿å ä»¥åæ ååºè°æ´æ¶æå¤æ¹å¨è®¢åã insOrderStandardTemplateMapper.update(null, Wrappers.<InsOrderStandardTemplate>lambdaUpdate() .eq(InsOrderStandardTemplate::getId, snapshot.getId()) .set(InsOrderStandardTemplate::getDeviceDefaultsInitialized, 1)); } } private Map<Integer, List<Integer>> findStandardDeviceDefaults(InsOrder order, List<InsOrderStandardTemplate> snapshots) { Set<Integer> templateIds = snapshots.stream().map(InsOrderStandardTemplate::getTemplateId) .filter(Objects::nonNull).collect(Collectors.toSet()); Integer standardTreeId = order.getStandardTreeId(); if (standardTreeId == null && StringUtils.isNotBlank(order.getSample()) && !templateIds.isEmpty()) { List<Integer> methodIds = standardMethodService.list(Wrappers.<StandardMethod>lambdaQuery() .eq(StandardMethod::getCode, order.getSample()) .select(StandardMethod::getId)).stream() .map(StandardMethod::getId).collect(Collectors.toList()); if (!methodIds.isEmpty()) { List<StandardTree> candidates = standardTreeService.list(Wrappers.<StandardTree>lambdaQuery() .in(StandardTree::getStandardMethodId, methodIds) .eq(StandardTree::getLaboratory, order.getLaboratory()) .isNotNull(StandardTree::getSample) .isNull(StandardTree::getSampleType) .isNull(StandardTree::getModel)); List<StandardTree> matches = candidates.stream() .filter(tree -> StringUtils.isNotBlank(tree.getSample())) .filter(tree -> { Set<Integer> boundIds = standardTreeService.selectTemplateBindings(tree.getId()).stream() .map(StandardTreeTemplateBindingVo::getTemplateId).collect(Collectors.toSet()); return boundIds.containsAll(templateIds); }).collect(Collectors.toList()); if (matches.size() == 1) { standardTreeId = matches.get(0).getId(); } else { List<StandardTree> exact = matches.stream().filter(tree -> standardTreeService.selectTemplateBindings(tree.getId()).stream() .map(StandardTreeTemplateBindingVo::getTemplateId) .collect(Collectors.toSet()).equals(templateIds)) .collect(Collectors.toList()); if (exact.size() == 1) { standardTreeId = exact.get(0).getId(); } } } } if (standardTreeId == null) { return Collections.emptyMap(); } StandardTree standard = standardTreeService.getById(standardTreeId); if (standard == null || StringUtils.isBlank(standard.getSample()) || !Objects.equals(standard.getLaboratory(), order.getLaboratory()) || standard.getSampleType() != null || standard.getModel() != null) { return Collections.emptyMap(); } if (order.getStandardTreeId() == null) { insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate() .eq(InsOrder::getId, order.getId()) .isNull(InsOrder::getStandardTreeId) .set(InsOrder::getStandardTreeId, standardTreeId)); } List<StandardTreeTemplateBindingVo> bindings = standardTreeService.selectTemplateBindings(standardTreeId); Map<Integer, List<Integer>> defaults = new HashMap<>(); for (StandardTreeTemplateBindingVo binding : bindings) { if (templateIds.contains(binding.getTemplateId())) { defaults.put(binding.getTemplateId(), binding.getDeviceIds() == null ? Collections.emptyList() : binding.getDeviceIds()); } } return defaults; } @Override public IPage<SampleProductDto2> selectSampleAndProductByOrderId(IPage<SampleProductDto2> page, SampleProductDto2 sampleProductDto) { IPage<SampleProductDto2> productDto2IPage = insOrderMapper.selectSampleAndProductByOrderId(page, inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java
@@ -94,6 +94,11 @@ InsOrderStandardTemplate::getInsResult, dto.getInsResult())); } if (dto.isDeviceIdsPresent()) { // æå¨éæ©ææ¸ ç©ºé½è§ä¸ºå·²åå§åï¼åç»è¿å ¥ä»»å¡ä¸å¾å次å¥ç¨æ ååºé»è®¤å¼ã insOrderStandardTemplateMapper.update(null, Wrappers.<InsOrderStandardTemplate>lambdaUpdate() .eq(InsOrderStandardTemplate::getId, snapshot.getId()) .set(InsOrderStandardTemplate::getDeviceDefaultsInitialized, 1)); insOrderTemplateDeviceMapper.delete( Wrappers.<InsOrderTemplateDevice>lambdaQuery() .eq(InsOrderTemplateDevice::getInsOrderId, dto.getId()) inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsSampleReceiptServiceImpl.java
@@ -4,46 +4,44 @@ import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.dto.TemplateInspectionItemDto; import com.ruoyi.basic.utils.StandardTemplateInspectionItemParser; import com.ruoyi.common.utils.GZipUtil; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.inspect.dto.SampleReceiptActionDto; import com.ruoyi.inspect.dto.SampleReceiptPageDto; import com.ruoyi.inspect.dto.SampleReceiptQueryDto; import com.ruoyi.inspect.mapper.InsOrderMapper; import com.ruoyi.inspect.mapper.InsOrderStandardTemplateMapper; import com.ruoyi.inspect.mapper.InsProductMapper; import com.ruoyi.inspect.mapper.InsSampleMapper; import com.ruoyi.inspect.mapper.InsSampleReceiptMapper; import com.ruoyi.inspect.mapper.InsSampleUserMapper; import com.ruoyi.inspect.pojo.InsOrder; import com.ruoyi.inspect.pojo.InsOrderStandardTemplate; import com.ruoyi.inspect.pojo.InsProduct; import com.ruoyi.inspect.pojo.InsSample; import com.ruoyi.inspect.pojo.InsSampleReceipt; import com.ruoyi.inspect.pojo.InsSampleUser; import com.ruoyi.inspect.mapper.*; import com.ruoyi.inspect.pojo.*; import com.ruoyi.inspect.service.InsOrderService; import com.ruoyi.inspect.service.InsOrderStateService; import com.ruoyi.inspect.service.InsSampleReceiptService; import com.ruoyi.system.mapper.UserMapper; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @Service @AllArgsConstructor public class InsSampleReceiptServiceImpl extends ServiceImpl<InsSampleReceiptMapper, InsSampleReceipt> implements InsSampleReceiptService { private static final String DIRECT_TEMPLATE_LABORATORY = "æ°è"; private final InsSampleReceiptMapper receiptMapper; private final InsOrderMapper insOrderMapper; private final InsOrderStandardTemplateMapper insOrderStandardTemplateMapper; @@ -55,13 +53,17 @@ private final UserMapper userMapper; @Override public com.baomidou.mybatisplus.core.metadata.IPage<SampleReceiptPageDto> page(Page<?> page, SampleReceiptQueryDto query) { return receiptMapper.selectPage(page, query); public IPage<SampleReceiptPageDto> page(Page<?> page, SampleReceiptQueryDto query) { IPage<SampleReceiptPageDto> result = receiptMapper.selectPage(page, query); result.getRecords().forEach(this::fillInspectionItemsFromSnapshots); return result; } @Override public SampleReceiptPageDto detail(Integer id) { return receiptMapper.selectDetail(id); SampleReceiptPageDto detail = receiptMapper.selectDetail(id); fillInspectionItemsFromSnapshots(detail); return detail; } @Override @@ -91,7 +93,26 @@ Long productCount = insProductMapper.selectCount(Wrappers.<InsProduct>lambdaQuery() .eq(InsProduct::getInsSampleId, sample.getId()).eq(InsProduct::getState, 1)); if (productCount == 0) { throw new ErrorException("è¯¥å§ææªç»å®æ£éªé¡¹ç®ï¼ä¸è½æäº¤æ£éª"); List<TemplateInspectionItemDto> items = getSnapshotInspectionItems(order.getId()); if (items.isEmpty()) { throw new ErrorException("订ååå§è®°å½æ¨¡æ¿æªé ç½®æ£éªé¡¹æå¯¼åºå¼ï¼ä¸è½æäº¤æ£éª"); } int sort = 0; for (TemplateInspectionItemDto item : items) { InsProduct product = new InsProduct(); product.setInsSampleId(sample.getId()); product.setInspectionItem(item.getInspectionItem()); product.setInspectionItemClass(""); product.setInspectionItemSubclass(""); product.setLaboratory(order.getLaboratory()); product.setSample(order.getSample()); product.setTemplateId(item.getTemplateId()); product.setTemplateRowIndex(item.getTemplateRowIndex()); product.setSonLaboratory(DIRECT_TEMPLATE_LABORATORY); product.setState(1); product.setSort(sort++); insProductMapper.insert(product); } } if (userMapper.selectById(dto.getMainInspectorId()) == null) { throw new ErrorException("主æ£éªäººä¸å卿已åç¨"); @@ -160,9 +181,43 @@ } } private List<TemplateInspectionItemDto> getSnapshotInspectionItems(Integer orderId) { List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateMapper.selectList( Wrappers.<InsOrderStandardTemplate>lambdaQuery() .eq(InsOrderStandardTemplate::getInsOrderId, orderId) .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)); List<TemplateInspectionItemDto> items = new ArrayList<>(); for (InsOrderStandardTemplate snapshot : snapshots) { String thing = snapshot.getThing(); try { thing = GZipUtil.uncompress(thing); } catch (RuntimeException ignored) { // å ¼å®¹æªå缩çå岿¨¡æ¿å¿«ç §ã } items.addAll(StandardTemplateInspectionItemParser.parse( snapshot.getTemplateId(), snapshot.getSort(), thing)); } return items; } private void fillInspectionItemsFromSnapshots(SampleReceiptPageDto row) { if (row == null || row.getOrderId() == null || StringUtils.isNotBlank(row.getInspectionItem())) { return; } try { String names = getSnapshotInspectionItems(row.getOrderId()).stream() .map(TemplateInspectionItemDto::getInspectionItem) .distinct().collect(Collectors.joining("\n")); row.setInspectionItem(names); } catch (RuntimeException ignored) { // å表ä»å¯æ¥çï¼æäº¤æ£éªæ¶ä¼è¿åå ·ä½ç模æ¿è§£æé误ã } } @Override public void export(SampleReceiptQueryDto query, HttpServletResponse response) { List<SampleReceiptPageDto> list = receiptMapper.selectExportList(query); list.forEach(this::fillInspectionItemsFromSnapshots); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("UTF-8"); try {