basic-server/src/main/java/com/ruoyi/basic/pojo/StandardTemplate.java
@@ -15,6 +15,7 @@ */ @TableName(value ="standard_template") @Data @Schema(description = "åå§è®°å½æ¨¡æ¿") public class StandardTemplate implements Serializable { /** * @@ -75,6 +76,9 @@ @Schema(description = "模æ¿ç¼å·") private String number; @Schema(description = "æ åè¦æ±å¼") private String standardRequirement; /** * ä»·æ ¼(å ) */ basic-server/src/main/java/com/ruoyi/basic/service/impl/StandardTemplateServiceImpl.java
@@ -131,6 +131,9 @@ // æ¥è¯¢æ§æ¨¡æ¿ StandardTemplate standardTemplate = baseMapper.selectById(newTemplate.getId()); newTemplate.setThing(standardTemplate.getThing()); if (newTemplate.getStandardRequirement() == null) { newTemplate.setStandardRequirement(standardTemplate.getStandardRequirement()); } if (newTemplate.getPrice() == null) { newTemplate.setPrice(java.math.BigDecimal.ZERO); } basic-server/src/main/resources/mapper/StandardTemplateMapper.xml
@@ -9,6 +9,7 @@ <result property="name" column="name" jdbcType="VARCHAR"/> <result property="remark" column="remark" jdbcType="VARCHAR"/> <result property="thing" column="thing" jdbcType="VARCHAR"/> <result property="standardRequirement" column="standard_requirement" jdbcType="VARCHAR"/> <result property="createUser" column="create_user" jdbcType="INTEGER"/> <result property="updateUser" column="update_user" jdbcType="INTEGER"/> <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> @@ -17,7 +18,7 @@ <select id="selectStandardTemplatePageList" resultType="com.ruoyi.basic.pojo.StandardTemplate"> select * from ( select st.id, st.name,st.number, st.price, st.remark, u2.name create_user_name, u3.name update_user_name, st.create_time, st.update_time select st.id, st.name,st.number, st.standard_requirement, st.price, st.remark, u2.name create_user_name, u3.name update_user_name, st.create_time, st.update_time from standard_template st left join user u2 on u2.id = st.create_user left join user u3 on u3.id = st.update_user inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java
@@ -1,16 +1,13 @@ package com.ruoyi.inspect.controller; import cn.hutool.core.io.FileUtil; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.basic.dto.IfsInventoryQuantitySupplierDto; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.annotation.PersonalScope; import com.ruoyi.common.core.domain.Result; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.inspect.dto.ReportPageDto; import com.ruoyi.inspect.service.InsOrderPlanService; import com.ruoyi.inspect.service.InsReportEditingService; import com.ruoyi.inspect.service.InsReportService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; @@ -20,16 +17,12 @@ import org.springframework.web.multipart.MultipartFile; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Map; import java.util.Objects; import java.util.Scanner; @RestController @RequestMapping("/insReport") @@ -41,6 +34,9 @@ @Resource private InsOrderPlanService insOrderPlanService; @Resource private InsReportEditingService insReportEditingService; @Value("${wordUrl}") private String wordUrl; @@ -106,7 +102,11 @@ Integer isExamine = (Integer) param.get("isExamine"); String examineTell = (String) param.get("examineTell"); Integer userId = (Integer) param.get("userId"); return Result.success(insReportService.examineReport(id, isExamine, examineTell, userId)); Map<String, String> sessions = new java.util.HashMap<>(); if (param.get("editSessions") instanceof Map<?, ?> values) { values.forEach((key, value) -> sessions.put(String.valueOf(key), String.valueOf(value))); } return Result.success(insReportEditingService.examineReport(id, isExamine, examineTell, userId, sessions)); } @Operation(summary = "æ¹å") @@ -131,34 +131,26 @@ return value instanceof Number ? ((Number) value).intValue() : Integer.valueOf(String.valueOf(value)); } @Anonymous @RequestMapping("/onlyOffice/save") public void saveFile(@RequestParam String fileName, HttpServletRequest request, HttpServletResponse response) { PrintWriter writer = null; try { writer = response.getWriter(); // è·åä¼ è¾çjsonæ°æ® Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A"); String body = scanner.hasNext() ? scanner.next() : ""; JSONObject jsonObject = JSONObject.parseObject(body); @Operation(summary = "è·åæµè§å¨ç«¯æ¥åç¼è¾ä¼è¯") @GetMapping("/editor/config") public Result editConfig(Integer id, Integer reportType) { return Result.success(insReportEditingService.createEditConfig(id, reportType)); } if (jsonObject.containsKey("url")) { String jsonArray = jsonObject.get("lastsave").toString(); // æ´æ°æ¶é´ String fileUrl = jsonObject.get("url").toString(); // æ´æ°æä»¶url HttpUtil.downloadFile(fileUrl, FileUtil.file(wordUrl + "/" + fileName)); } } catch (Exception e) { e.printStackTrace(); writer.write("{\"error\":-1}"); return; } /* * status = 1ï¼æä»¬ç»onlyOfficeçæå¡è¿å{"error":"0"}çä¿¡æ¯ã * è¿æ ·onlyOfficeä¼è®¤ä¸ºåè°æ¥å£æ¯æ²¡é®é¢çï¼è¿æ ·å°±å¯ä»¥å¨çº¿ç¼è¾ææ¡£äºï¼å¦åçè¯ä¼å¼¹åºçªå£è¯´æ */ if (Objects.nonNull(writer)) { writer.write("{\"error\":0}"); } @Operation(summary = "读åå®¡æ ¸ DOCX å 容") @GetMapping("/editor/document") public org.springframework.http.ResponseEntity<byte[]> editDocument(@RequestParam String token) { return org.springframework.http.ResponseEntity.ok().header("Cache-Control", "no-store") .contentType(org.springframework.http.MediaType.parseMediaType( "application/vnd.openxmlformats-officedocument.wordprocessingml.document")) .body(insReportEditingService.readDocument(token)); } @Operation(summary = "ä¿åæµè§å¨å ç¼è¾ç DOCX") @PostMapping(value = "/editor/document", consumes = "multipart/form-data") public Result saveEditDocument(@RequestParam String token, @RequestParam String version, @RequestPart MultipartFile file) { return Result.success(insReportEditingService.saveDocument(token, version, file)); } @Operation(summary = "æ¥åæ¹éä¸è½½") inspect-server/src/main/java/com/ruoyi/inspect/dto/WriteInspectionConditionDto.java
@@ -19,6 +19,9 @@ @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate detectionTime; @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate detectionEndTime; private String detectionPlace; private List<Integer> deviceIds; private Integer insResult; @@ -27,6 +30,8 @@ private boolean temperaturePresent; @JsonIgnore private boolean detectionTimePresent; @JsonIgnore private boolean detectionEndTimePresent; @JsonIgnore private boolean detectionPlacePresent; @JsonIgnore @@ -44,6 +49,11 @@ this.detectionTimePresent = true; } public void setDetectionEndTime(LocalDate detectionEndTime) { this.detectionEndTime = detectionEndTime; this.detectionEndTimePresent = true; } public void setDetectionPlace(String detectionPlace) { this.detectionPlace = detectionPlace; this.detectionPlacePresent = true; inspect-server/src/main/java/com/ruoyi/inspect/mapper/InsReportEditSessionMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,7 @@ package com.ruoyi.inspect.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.inspect.pojo.InsReportEditSession; public interface InsReportEditSessionMapper extends BaseMapper<InsReportEditSession> { } inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsOrderStandardTemplate.java
@@ -58,6 +58,9 @@ @Schema(description = "模æ¿ç¼å·") private String number; @Schema(description = "ä¸åæ¶åå§è®°å½æ¨¡æ¿çæ åè¦æ±å¼") private String standardRequirement; @Schema(description = "模æ¿å±ç¤ºåçæé¡ºåº") private Integer sort; @@ -73,10 +76,14 @@ @Schema(description = "è¯¥æ¨¡æ¿æ£éªæ¶ç湿度") private String humidity; @Schema(description = "æ£æµæ¥æ") @Schema(description = "æ£æµå¼å§æ¥æ") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate detectionTime; @Schema(description = "æ£æµç»ææ¥æï¼åå²ç©ºå¼æå¼å§æ¥æå¤ç") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate detectionEndTime; @Schema(description = "æ£æµå°ç¹") private String detectionPlace; inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReport.java
@@ -14,6 +14,7 @@ */ @TableName(value ="ins_report") @Data @Schema(description = "æ£éªæ¥å") public class InsReport implements Serializable { /** * @@ -59,6 +60,10 @@ @Schema(description = "ä¸´æ¶æ¥åå°å") private String tempUrlPdf; /** æ£éªæ¥å临æ¶é¢è§å°åã */ @Schema(description = "æ£éªæ¥å临æ¶é¢è§å°å") private String inspectionTempUrlPdf; /** * 1ï¼æ¹å 0ï¼ä¸æ¹å */ inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReportEditSession.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,56 @@ package com.ruoyi.inspect.pojo; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; /** æµè§å¨ç«¯ DOCX å®¡æ ¸ç¼è¾ä¼è¯ï¼documentKey ä¿åæä»¶å 容 SHA-256ã */ @Data @TableName("ins_report_edit_session") @Schema(description = "æ¥åå®¡æ ¸å¨çº¿ç¼è¾ä¼è¯") public class InsReportEditSession implements Serializable { @Schema(description = "ä¼è¯ID") @TableId(type = IdType.AUTO) private Long id; @Schema(description = "ç¼è¾ä¼è¯ä»¤ç") private String token; @Schema(description = "æ¥åID") private Integer reportId; @Schema(description = "æ¥åç±»åï¼0æ£æµæ¥åï¼1æ£éªæ¥å") private Integer reportType; @Schema(description = "DOCXæä»¶å 容çSHA-256çæ¬") private String documentKey; @Schema(description = "å®¡æ ¸äººID") private Integer userId; @Schema(description = "ä¼è¯ç¶æ") private String status; @Schema(description = "ä¿å请æ±ID") private String saveRequestId; @Schema(description = "ä¿åç»æè¯´æ") private String message; @Schema(description = "ä¼è¯è¿ææ¶é´") private LocalDateTime expiresAt; @Schema(description = "æè¿ä¿å宿æ¶é´") private LocalDateTime savedAt; @Schema(description = "å建æ¶é´") private LocalDateTime createTime; @Schema(description = "æ´æ°æ¶é´") private LocalDateTime updateTime; } inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportEditingService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,219 @@ package com.ruoyi.inspect.service; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.inspect.mapper.InsReportEditSessionMapper; import com.ruoyi.inspect.mapper.InsReportMapper; import com.ruoyi.inspect.pojo.InsReport; import com.ruoyi.inspect.pojo.InsReportEditSession; import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.nio.file.*; import java.security.MessageDigest; import java.time.LocalDateTime; import java.util.*; /** æµè§å¨å DOCX ç¼è¾ï¼ç»å½é´æãçæ¬æ ¡éªï¼æ å¿ååè°åææ¡£æå¡å¨ä¾èµã */ @Service public class InsReportEditingService { private static final long MAX_BYTES = 100L * 1024 * 1024; @Resource private InsReportMapper reportMapper; @Resource private InsReportEditSessionMapper sessionMapper; @Resource private InsReportService reportService; @Value("${wordUrl}") private String wordUrl; @Transactional(rollbackFor = Exception.class) public Map<String, Object> createEditConfig(Integer id, Integer type) { if (!Objects.equals(type, 0) && !Objects.equals(type, 1)) throw new ErrorException("æ¥åç±»å䏿£ç¡®"); InsReport report = lockEditable(id); Path file = resolveFile(report, type); LocalDateTime now = LocalDateTime.now(); sessionMapper.update(null, Wrappers.<InsReportEditSession>lambdaUpdate() .eq(InsReportEditSession::getReportId, id).eq(InsReportEditSession::getReportType, type) .in(InsReportEditSession::getStatus, "EDITING", "SAVED", "FAILED", "SAVE_REQUESTED") .set(InsReportEditSession::getStatus, "EXPIRED")); InsReportEditSession session = new InsReportEditSession(); session.setReportId(id); session.setReportType(type); session.setToken(UUID.randomUUID().toString()); session.setDocumentKey(version(file)); session.setUserId(SecurityUtils.getUserId().intValue()); // æªæå¼ç¼è¾ç第äºä»½æ¥å确认使ç¨å½åæä¹ åçæ¬ï¼å½åç¼è¾å¨ç±å端ä¿åå±éæäº¤ã session.setStatus("SAVED"); session.setSavedAt(now); session.setExpiresAt(now.plusHours(8)); session.setCreateTime(now); session.setUpdateTime(now); sessionMapper.insert(session); return Map.of("sessionToken", session.getToken(), "version", session.getDocumentKey(), "title", file.getFileName().toString(), "reportType", type); } @Transactional(rollbackFor = Exception.class) public byte[] readDocument(String token) { InsReportEditSession session = findSession(token); InsReport report = lockEditable(session.getReportId()); requireUsable(session); Path file = resolveFile(report, session.getReportType()); requireVersion(session, file); try { return Files.readAllBytes(file); } catch (Exception e) { throw new ErrorException("è¯»åæ¥å失败"); } } @Transactional(rollbackFor = Exception.class) public Map<String, Object> saveDocument(String token, String expectedVersion, MultipartFile file) { InsReportEditSession session = findSession(token); InsReport report = lockEditable(session.getReportId()); requireUsable(session); if (!Objects.equals(expectedVersion, session.getDocumentKey())) { throw new ErrorException("æ¥åçæ¬å·²ååï¼è¯·éæ°æå¼åç¼è¾"); } requireVersion(session, resolveFile(report, session.getReportType())); if (file == null || file.isEmpty() || file.getSize() > MAX_BYTES) { throw new ErrorException("æ¥åä¸è½ä¸ºç©ºï¼ä¸ä¸è½è¶ è¿ 100MB"); } try { // æ ¡éª OOXML ç»æï¼æç» ZIPãHTML æé误ååºåå DOCXã try (InputStream input = file.getInputStream(); XWPFDocument doc = new XWPFDocument(input)) { if (doc.getDocument().getBody() == null) throw new IllegalArgumentException(); } Path root = Paths.get(wordUrl).toAbsolutePath().normalize(); Files.createDirectories(root); Path staged = root.resolve("edited-" + UUID.randomUUID() + ".docx"); file.transferTo(staged); // æ° WordãPDF å ¨é¨çææååå叿°æ®åºæéï¼ä»»ä½å¤±è´¥é½ä¸è¦çæ§æä»¶ã String pdfUrl = reportService.prepareEditedReportPreview(staged.toString()); String documentUrl = "/word/" + staged.getFileName(); var update = Wrappers.<InsReport>lambdaUpdate().eq(InsReport::getId, report.getId()); if (session.getReportType() == 1) { update.set(InsReport::getInspectionUrl, documentUrl).set(InsReport::getInspectionTempUrlPdf, pdfUrl); } else { update.set(InsReport::getUrlS, documentUrl).set(InsReport::getTempUrlPdf, pdfUrl); } reportMapper.update(null, update); session.setDocumentKey(version(staged)); session.setStatus("SAVED"); session.setSavedAt(LocalDateTime.now()); session.setUpdateTime(LocalDateTime.now()); session.setMessage("ä¿åæå"); sessionMapper.updateById(session); return Map.of("version", session.getDocumentKey(), "completed", true, "pdfUrl", pdfUrl); } catch (Exception e) { throw e instanceof ErrorException error ? error : new ErrorException("ä¿å Word 失败ï¼è¯·éè¯ï¼" + e.getMessage()); } } /** ä¿åçæ¬æ ¸å¯¹ãå®¡æ ¸ç¾ååä¼è¯å¤±æä½¿ç¨åä¸ä¸ªæ¥åè¡é䏿°æ®åºäºå¡ã */ @Transactional(rollbackFor = Exception.class) public int examineReport(Integer id, Integer passed, String reason, Integer approver, Map<String, String> tokens) { InsReport report = lockEditable(id); if (!Objects.equals(passed, 0) && !Objects.equals(passed, 1)) throw new ErrorException("å®¡æ ¸ç»æä¸æ£ç¡®"); if (Objects.equals(passed, 1)) { checkSaved(report, 0, tokens); if (StringUtils.isNotBlank(report.getInspectionUrl())) checkSaved(report, 1, tokens); // ç¾åæµç¨ä¼æ¹åæä»¶ï¼å å¤å¶åå¨äºå¡ä¸åæ¢æéï¼å¤±è´¥æ¶æ§çå·²ä¿å稿ä¸åå½±åã stageForSignature(report); } int result = reportService.examineReport(id, passed, reason, approver); sessionMapper.update(null, Wrappers.<InsReportEditSession>lambdaUpdate() .eq(InsReportEditSession::getReportId, id) .in(InsReportEditSession::getStatus, "EDITING", "SAVED", "FAILED", "SAVE_REQUESTED") .set(InsReportEditSession::getStatus, "FINALIZED") .set(InsReportEditSession::getUpdateTime, LocalDateTime.now())); return result; } private void stageForSignature(InsReport report) { try { Path root = Paths.get(wordUrl).toAbsolutePath().normalize(); var update = Wrappers.<InsReport>lambdaUpdate().eq(InsReport::getId, report.getId()); for (int type : StringUtils.isNotBlank(report.getInspectionUrl()) ? new int[]{0, 1} : new int[]{0}) { Path copy = root.resolve("reviewed-" + UUID.randomUUID() + ".docx"); Files.copy(resolveFile(report, type), copy); String url = "/word/" + copy.getFileName(); if (type == 0) update.set(InsReport::getUrlS, url); else update.set(InsReport::getInspectionUrl, url); } reportMapper.update(null, update); } catch (Exception e) { throw new ErrorException("åå¤å®¡æ ¸ç¾åæä»¶å¤±è´¥ï¼è¯·éè¯"); } } private void checkSaved(InsReport report, int type, Map<String, String> tokens) { if (tokens == null || StringUtils.isBlank(tokens.get(String.valueOf(type)))) { throw new ErrorException("è¯·å æå¼å®¡æ ¸ç¼è¾é¡µé¢å¹¶ä¿åæ¥å"); } InsReportEditSession session = findSession(tokens.get(String.valueOf(type))); requireUsable(session); if (!Objects.equals(session.getReportId(), report.getId()) || session.getReportType() != type) { throw new ErrorException("æ¥åç¼è¾ä¼è¯ä¸å¹é "); } requireVersion(session, resolveFile(report, type)); } private InsReport lockEditable(Integer id) { InsReport report = reportMapper.selectOne(Wrappers.<InsReport>lambdaQuery() .eq(InsReport::getId, id).last("FOR UPDATE")); if (report == null) throw new ErrorException("æ¥åä¸åå¨"); if (!Objects.equals(report.getState(), 1) || Objects.equals(report.getIsExamine(), 1) || Objects.equals(report.getIsRatify(), 1)) throw new ErrorException("æ¥åå·²ä¸å¨å¾ å®¡æ ¸ç¶æ"); if (!Objects.equals(report.getExamineUserId(), SecurityUtils.getUserId().intValue())) { throw new ErrorException("åªææå®å®¡æ ¸äººå¯ä»¥ç¼è¾åå®¡æ ¸æ¥å"); } return report; } private InsReportEditSession findSession(String token) { if (StringUtils.isBlank(token)) throw new ErrorException("缺å°ç¼è¾ä¼è¯"); InsReportEditSession session = sessionMapper.selectOne(Wrappers.<InsReportEditSession>lambdaQuery() .eq(InsReportEditSession::getToken, token)); if (session == null || !Objects.equals(session.getUserId(), SecurityUtils.getUserId().intValue())) { throw new ErrorException("ç¼è¾ä¼è¯ä¸åå¨ææ æè®¿é®"); } return session; } private void requireUsable(InsReportEditSession session) { // çå¾ æ¥åéæé´å¯è½å·²è¢«å¦ä¸çªå£å¤±æï¼æ æ¤å¤è¿è¡éå®è¯»ã InsReportEditSession current = sessionMapper.selectOne(Wrappers.<InsReportEditSession>lambdaQuery() .eq(InsReportEditSession::getId, session.getId()).last("FOR UPDATE")); if (current.getExpiresAt().isBefore(LocalDateTime.now()) || !"SAVED".equals(current.getStatus())) { throw new ErrorException("ç¼è¾ä¼è¯å·²å¤±æï¼è¯·éæ°æå¼æ¥å"); } session.setDocumentKey(current.getDocumentKey()); session.setStatus(current.getStatus()); } private Path resolveFile(InsReport report, int type) { String url = type == 1 ? report.getInspectionUrl() : StringUtils.defaultIfBlank(report.getUrlS(), report.getUrl()); if (StringUtils.isBlank(url) || !url.startsWith("/word/") || !url.toLowerCase().endsWith(".docx")) { throw new ErrorException("对åºç DOCX æ¥åä¸åå¨"); } try { Path root = Paths.get(wordUrl).toRealPath(); Path file = root.resolve(url.substring(6)).normalize().toRealPath(); if (!file.startsWith(root) || !Files.isRegularFile(file) || Files.size(file) > MAX_BYTES) throw new IllegalArgumentException(); return file; } catch (Exception e) { throw new ErrorException("æ¥åæä»¶ä¸åå¨æè·¯å¾ä¸åæ³"); } } private void requireVersion(InsReportEditSession session, Path file) { if (!Objects.equals(session.getDocumentKey(), version(file))) throw new ErrorException("æ¥åå·²è¢«æ¿æ¢ï¼è¯·éæ°æå¼åç¼è¾"); } private String version(Path file) { try (InputStream input = Files.newInputStream(file)) { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] buffer = new byte[8192]; int length; while ((length = input.read(buffer)) != -1) digest.update(buffer, 0, length); return HexFormat.of().formatHex(digest.digest()); } catch (Exception e) { throw new ErrorException("æ æ³è¯»åæ¥åçæ¬"); } } } inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java
@@ -40,6 +40,9 @@ int wordInsertUrl(Map<String, Object> map, String url); /** å¨çº¿ç¼è¾ä¿ååéæ°çæå¯¹åºæ¥åçä¸´æ¶ PDFã */ String prepareEditedReportPreview(String absoluteDocxPath); String downAll(String ids); /** inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
@@ -359,6 +359,9 @@ "模æ¿ID " + snapshot.getTemplateId()); if (snapshot.getDetectionTime() == null) { collect.add("è¯·éæ©â" + templateName + "âçæ£æµæ¶é´"); } else if (snapshot.getDetectionEndTime() != null && snapshot.getDetectionEndTime().isBefore(snapshot.getDetectionTime())) { collect.add("â" + templateName + "âçæ£æµç»ææ¥æä¸è½æ©äºå¼å§æ¥æ"); } if (StringUtils.isBlank(snapshot.getDetectionPlace())) { collect.add("请填åâ" + templateName + "âçæ£æµå°ç¹"); @@ -1701,6 +1704,8 @@ refreshed.setInsOrderId(orderId); refreshed.setTemplateId(templateId); refreshed.setNumber(standardTemplate == null ? oldSnapshot.getNumber() : standardTemplate.getNumber()); refreshed.setStandardRequirement(oldSnapshot == null ? standardTemplate.getStandardRequirement() : oldSnapshot.getStandardRequirement()); refreshed.setName(standardTemplate == null ? oldSnapshot.getName() : standardTemplate.getName()); refreshed.setRemark(standardTemplate == null ? oldSnapshot.getRemark() : standardTemplate.getRemark()); refreshed.setThing(standardTemplate == null ? oldSnapshot.getThing() : standardTemplate.getThing()); @@ -1711,6 +1716,7 @@ refreshed.setHumidity(templateHumidityMap.get(templateId)); // å·æ°æ¨¡æ¿ç»ææ¶å¿ é¡»ä¿çæ£éªé¶æ®µå¡«åçä¸å¡æ°æ®ï¼é¿å è¿å ¥å¤æ ¸ååæ¾ä¸ºç©ºã refreshed.setDetectionTime(oldSnapshot == null ? null : oldSnapshot.getDetectionTime()); refreshed.setDetectionEndTime(oldSnapshot == null ? null : oldSnapshot.getDetectionEndTime()); refreshed.setDetectionPlace(oldSnapshot == null ? null : oldSnapshot.getDetectionPlace()); refreshed.setInsResult(oldSnapshot == null ? null : oldSnapshot.getInsResult()); Integer templateSort = templateSortMap.get(templateId); @@ -2058,7 +2064,8 @@ if (Objects.equals(report.getIsRatify(), 1)) { throw new ErrorException("å·²æ¹åæ¥åä¸è½éæ°çæ"); } if (StringUtils.isNotBlank(report.getUrlS())) { // urlS åæ¶ç¨äºäººå·¥ä¸ä¼ åå®¡æ ¸é¡µé¢ä¿åç Wordï¼åªæäººå·¥ä¸ä¼ éè¦å æå¨ååç³»ç»æ¥åã if (StringUtils.isNotBlank(report.getUrlS()) && !isBrowserEditedReportUrl(report.getUrlS())) { throw new ErrorException("å½åæ¥åå·²æå¨ä¸ä¼ ï¼è¯·å è¿åä¸ºç³»ç»æ¥åååéæ°çæ"); } if (report.getInsOrderId() == null) { @@ -2102,7 +2109,12 @@ .eq(InsReport::getId, reportId) .set(InsReport::getWriteTime, report.getWriteTime()) .set(InsReport::getIsPass, report.getIsPass()) .set(InsReport::getUrlS, null) .set(InsReport::getTempUrlPdf, "/word/" + tempPdfName)); } private static boolean isBrowserEditedReportUrl(String url) { return url != null && url.matches("(?i)^/word/(?:edited|reviewed)-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\\.docx$"); } private Map<String, Object> buildExistingReportMarks(InsReport report) { @@ -3667,7 +3679,8 @@ .eq(InsOrderStandardTemplate::getInsOrderId, orderId) .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)); List<LocalDate> detectionDates = templateSnapshots.stream() .map(InsOrderStandardTemplate::getDetectionTime) .flatMap(snapshot -> java.util.stream.Stream.of( snapshot.getDetectionTime(), snapshot.getDetectionEndTime())) .filter(Objects::nonNull) .collect(Collectors.toList()); String insTime = formatReportTestDate(detectionDates); @@ -3683,7 +3696,7 @@ List<Map<String, String>> finalDeviceList = deviceList; String finalModelStr = modelStr; // ç´ç»æ¨¡æ¿è®¢å没æ ins_productï¼æ£æµé¡¹ç®ãåä½åç»æåä»è®¢å模æ¿å¿«ç §ä¸è·åã // ç´ç»æ¨¡æ¿è®¢å没æ ins_productï¼æ£æµé¡¹ç®ãæ åè¦æ±å¼åç»æåä»è®¢å模æ¿å¿«ç §ä¸è·åã List<Map<String, String>> detectionResultRows = directTemplateOrder ? buildTemplateDetectionResultRows(orderId) : buildDetectionResultRows(samples); @@ -3865,7 +3878,7 @@ } /** * æ°çæ£æµæ¥åçç»æè¡¨åºå®ä¸ºååï¼åºå·ãæ£æµé¡¹ç®ãåä½ãæ£æµç»æã * æ°çæ£æµãæ£éªæ¥åå ±ç¨ç»ææ°æ®ï¼æ åè¦æ±å¼åèªåå§è®°å½æ¨¡æ¿é ç½®ã */ private List<Map<String, String>> buildDetectionResultRows(List<SampleProductDto> samples) { List<Map<String, String>> rows = new ArrayList<>(); @@ -3874,6 +3887,7 @@ } boolean multipleSamples = samples.size() > 1; Map<Integer, String> requirementsByTemplate = new HashMap<>(); int sequence = 1; for (SampleProductDto sample : samples) { if (CollectionUtils.isEmpty(sample.getInsProduct())) { @@ -3894,8 +3908,15 @@ Map<String, String> row = new LinkedHashMap<>(); row.put("seq", String.valueOf(sequence++)); row.put("itemName", itemName); row.put("itemName", formatReportItemWithUnit(itemName, product.getUnit())); row.put("unit", defaultReportText(product.getUnit(), "/")); String requirement = product.getTemplateId() == null ? null : requirementsByTemplate.computeIfAbsent(product.getTemplateId(), templateId -> { StandardTemplate sourceTemplate = standardTemplateService.getById(templateId); return defaultReportText(sourceTemplate == null ? null : sourceTemplate.getStandardRequirement(), "/"); }); row.put("standardRequirement", defaultReportText(requirement, "/")); row.put("result", defaultReportText(product.getLastValue(), "/")); row.put("inspectionConclusion", formatInspectionConclusion(product.getInsResult())); rows.add(row); @@ -3921,7 +3942,8 @@ Wrappers.<InsOrderStandardTemplate>lambdaQuery() .eq(InsOrderStandardTemplate::getInsOrderId, orderId) .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)); context.setDetectionDates(snapshots.stream().map(InsOrderStandardTemplate::getDetectionTime) context.setDetectionDates(snapshots.stream().flatMap(snapshot -> java.util.stream.Stream.of( snapshot.getDetectionTime(), snapshot.getDetectionEndTime())) .filter(Objects::nonNull).distinct().sorted().collect(Collectors.toList())); List<Integer> deviceIds = insOrderTemplateDeviceMapper.selectDeviceIdsByOrderId(orderId); if (CollectionUtils.isNotEmpty(deviceIds)) { @@ -3949,6 +3971,12 @@ List<Map<String, String>> rows = new ArrayList<>(); int sequence = 1; for (InsOrderStandardTemplate snapshot : snapshots) { String standardRequirement = snapshot.getStandardRequirement(); // å ¼å®¹æ°å¢è¯¥å段åä¸åçæ§è®°å½ï¼æå¿«ç §æ¶å§ç»ä»¥è®¢åä¿åçå¼ä¸ºåã if (StringUtils.isBlank(standardRequirement) && snapshot.getTemplateId() != null) { StandardTemplate sourceTemplate = standardTemplateService.getById(snapshot.getTemplateId()); standardRequirement = sourceTemplate == null ? null : sourceTemplate.getStandardRequirement(); } List<TemplateExportCell> exportCells = getTemplateExportCells(snapshot.getThing()); JSONObject recordValues = StrUtil.isBlank(snapshot.getRecordValues()) ? new JSONObject() : JSON.parseObject(snapshot.getRecordValues()); @@ -3967,8 +3995,10 @@ row.put("seq", String.valueOf(sequence++)); String reportItemName = defaultReportText(itemName, defaultReportText(snapshot.getName(), "模æ¿ID " + snapshot.getTemplateId())); row.put("itemName", formatExportItemName(reportItemName)); row.put("itemName", formatReportItemWithUnit( formatExportItemName(reportItemName), unit)); row.put("unit", defaultReportText(unit, "/")); row.put("standardRequirement", defaultReportText(standardRequirement, "/")); row.put("result", result); row.put("inspectionConclusion", formatInspectionConclusion(snapshot.getInsResult())); rows.add(row); @@ -4144,6 +4174,14 @@ return itemName.replaceAll("å¹³åå¼\\s*[ï¼,]?\\s*", ""); } private static String formatReportItemWithUnit(String itemName, String unit) { if (StringUtils.isBlank(unit) || "/".equals(unit.trim()) || itemName.contains(unit.trim())) { return itemName; } return itemName + "ï¼" + unit.trim(); } private static String getMapText(Map<String, String> map, String... keys) { if (map == null) { return null; inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -846,6 +846,7 @@ snapshot.setTemplateId(template.getId()); snapshot.setName(template.getName()); snapshot.setNumber(template.getNumber()); snapshot.setStandardRequirement(template.getStandardRequirement()); snapshot.setRemark(template.getRemark()); snapshot.setThing(template.getThing()); snapshot.setSort(selection.getSort()); @@ -1091,6 +1092,7 @@ .select(InsOrderStandardTemplate::getTemplateId, InsOrderStandardTemplate::getTemperature, InsOrderStandardTemplate::getDetectionTime, InsOrderStandardTemplate::getDetectionEndTime, InsOrderStandardTemplate::getDetectionPlace, InsOrderStandardTemplate::getInsResult) .orderByAsc(InsOrderStandardTemplate::getSort, @@ -1100,6 +1102,8 @@ condition.setTemplateId(snapshot.getTemplateId()); condition.setTemperature(snapshot.getTemperature()); condition.setDetectionTime(snapshot.getDetectionTime()); condition.setDetectionEndTime(snapshot.getDetectionEndTime() == null ? snapshot.getDetectionTime() : snapshot.getDetectionEndTime()); condition.setDetectionPlace(snapshot.getDetectionPlace()); condition.setInsResult(snapshot.getInsResult()); condition.setDeviceIds(templateDeviceIds.getOrDefault( inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderTemplateServiceImpl.java
@@ -2,6 +2,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -17,6 +18,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; /** * @author Administrator @@ -67,7 +71,29 @@ vo.setStandardTreeId(standardTreeId); if (standardTreeId != null) { List<StandardTreeTemplateBindingVo> bindings = standardTreeService.selectTemplateBindings(standardTreeId); vo.setTemplateBindings(bindings == null ? new ArrayList<>() : bindings); // æ°ä¿åçä¸å模æ¿è®°å½äºå®é ä¿ççåå§è®°å½æ¨¡æ¿ï¼æ§æ¨¡æ¿æ²¡æè¯¥åæ®µï¼æ²¿ç¨æ ååºç»å®å表ã JSONObject content = StringUtils.isBlank(template.getThing()) ? null : JSON.parseObject(template.getThing()); JSONArray savedSelections = content == null ? null : content.getJSONArray("templateList"); if (savedSelections == null) { vo.setTemplateBindings(bindings == null ? new ArrayList<>() : bindings); } else { Map<Integer, StandardTreeTemplateBindingVo> currentBindings = (bindings == null ? new ArrayList<StandardTreeTemplateBindingVo>() : bindings).stream() .collect(Collectors.toMap(StandardTreeTemplateBindingVo::getTemplateId, Function.identity(), (first, ignored) -> first)); List<StandardTreeTemplateBindingVo> selected = new ArrayList<>(); for (int index = 0; index < savedSelections.size(); index++) { JSONObject selection = savedSelections.getJSONObject(index); if (selection == null) continue; StandardTreeTemplateBindingVo binding = currentBindings.get(selection.getInteger("templateId")); if (binding != null) { binding.setSort(index); selected.add(binding); } } vo.setTemplateBindings(selected); } } else { vo.setTemplateBindings(new ArrayList<>()); } inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java
@@ -77,7 +77,24 @@ if (snapshot == null) { throw new ErrorException("æªæ¾å°å½å模æ¿çåå§è®°å½å¿«ç §"); } boolean hasSnapshotField = dto.isTemperaturePresent() || dto.isDetectionTimePresent() boolean hasDetectionRange = dto.isDetectionTimePresent() || dto.isDetectionEndTimePresent(); if (hasDetectionRange) { if (!dto.isDetectionTimePresent()) { throw new ErrorException("è¯·éæ©å®æ´çæ£æµæ¶é´èå´"); } // å ¼å®¹æ§å®¢æ·ç«¯åªæäº¤åä¸ªæ¥æï¼æ°å®¢æ·ç«¯å¿ 须忶æäº¤èµ·æ¢æ¥ææåæ¶æ¸ 空ã if (!dto.isDetectionEndTimePresent()) { dto.setDetectionEndTime(dto.getDetectionTime()); } if ((dto.getDetectionTime() == null) != (dto.getDetectionEndTime() == null)) { throw new ErrorException("è¯·éæ©å®æ´çæ£æµæ¶é´èå´"); } if (dto.getDetectionTime() != null && dto.getDetectionEndTime().isBefore(dto.getDetectionTime())) { throw new ErrorException("æ£æµç»ææ¥æä¸è½æ©äºå¼å§æ¥æ"); } } boolean hasSnapshotField = dto.isTemperaturePresent() || hasDetectionRange || dto.isDetectionPlacePresent() || dto.isInsResultPresent(); if (hasSnapshotField) { @@ -88,6 +105,8 @@ InsOrderStandardTemplate::getTemperature, dto.getTemperature()) .set(dto.isDetectionTimePresent(), InsOrderStandardTemplate::getDetectionTime, dto.getDetectionTime()) .set(hasDetectionRange, InsOrderStandardTemplate::getDetectionEndTime, dto.getDetectionEndTime()) .set(dto.isDetectionPlacePresent(), InsOrderStandardTemplate::getDetectionPlace, dto.getDetectionPlace()) .set(dto.isInsResultPresent(), inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
@@ -231,8 +231,6 @@ info.setViewStatus(false); info.setJumpPath(MenuJumpPathConstants.REPORT_PREPARATION); informationNotificationService.addInformationNotification(info); String primaryReportUrl = getPrimaryReportUrl(insReport); // 夿æ¯å¦æ¯åææ éè¦æ¿æ¢****æä¾åºå IfsInventoryQuantity one = ifsInventoryQuantityMapper.selectOne(new LambdaQueryWrapper<IfsInventoryQuantity>() .eq(IfsInventoryQuantity::getId, order.getIfsInventoryId())); @@ -253,9 +251,7 @@ }}; writeMarksToReportFiles(insReport, writeMarks); // ä¿®æ¹ä¸´æ¶pdf String tempUrlPdf = wordToPdfTemp(primaryReportUrl.replace("/word", wordUrl)); insReport.setTempUrlPdf("/word/" + tempUrlPdf); refreshTemporaryPreviews(insReport); insReportMapper.updateById(insReport); @@ -383,16 +379,13 @@ info.setViewStatus(false); info.setJumpPath(MenuJumpPathConstants.REPORT_PREPARATION); informationNotificationService.addInformationNotification(info); String primaryReportUrl = getPrimaryReportUrl(insReport); Map<String, Object> examineMarks = new HashMap<String, Object>() {{ put("examineUrl", ReportSignaturePictureUtils.create(imgUrl, signatureUrl)); put("examineDateUrl", Pictures.ofStream(DateImageUtil.createDateImage(null)).create()); }}; writeMarksToReportFiles(insReport, examineMarks); // ä¿®æ¹ä¸´æ¶pdf String tempUrlPdf = wordToPdfTemp(primaryReportUrl.replace("/word", wordUrl)); insReport.setTempUrlPdf("/word/" + tempUrlPdf); refreshTemporaryPreviews(insReport); // åéä¼ä¸å¾®ä¿¡éç¥(éç¥æ¹å人审æ¹) threadPoolTaskExecutor.execute(() -> { @@ -728,6 +721,30 @@ .collect(Collectors.toList()); } private void refreshTemporaryPreviews(InsReport report) { String primaryPdf = wordToPdfTemp(getPrimaryReportUrl(report).replace("/word", wordUrl)); if (StringUtils.isBlank(primaryPdf)) { throw new ErrorException("æ£æµæ¥åé¢è§çæå¤±è´¥"); } report.setTempUrlPdf("/word/" + primaryPdf); if (StringUtils.isNotBlank(report.getInspectionUrl())) { String inspectionPdf = wordToPdfTemp(report.getInspectionUrl().replace("/word", wordUrl)); if (StringUtils.isBlank(inspectionPdf)) { throw new ErrorException("æ£éªæ¥åé¢è§çæå¤±è´¥"); } report.setInspectionTempUrlPdf("/word/" + inspectionPdf); } } @Override public String prepareEditedReportPreview(String absoluteDocxPath) { String pdfName = wordToPdfTemp(absoluteDocxPath); if (StringUtils.isBlank(pdfName)) { throw new ErrorException("æ¥åé¢è§çæå¤±è´¥"); } return "/word/" + pdfName; } private void writeMarksToReportFiles(InsReport report, Map<String, Object> marks) { for (String reportUrl : getApprovalReportUrls(report)) { wordInsertUrl(marks, reportUrl.replace("/word", wordUrl)); @@ -804,7 +821,12 @@ throw new ErrorException("æ¥åæä»¶ä¸åå¨ï¼è¯·è系管çå"); } try { String filename = file.getFileName().toString(); // ç©çæä»¶å¯è½æ¯ reviewed/edited UUIDï¼å¯¹ç¨æ·å§ç»ä½¿ç¨ä¸å¡æ¥åç¼å·ã String reportNumber = StringUtils.isBlank(report.getCode()) ? "æ¥å" : report.getCode(); reportNumber = reportNumber.replaceAll("[\\\\/:*?\"<>|\\p{Cntrl}]", "-").trim(); String suffix = StringUtils.isNotBlank(report.getInspectionUrl()) ? (Objects.equals(reportType, INSPECTION_REPORT) ? "-æ£éªæ¥å" : "-æ£æµæ¥å") : ""; String filename = reportNumber + suffix + ".docx"; String encodedName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20"); response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName); inspect-server/src/main/java/com/ruoyi/inspect/vo/TemplateConditionVo.java
@@ -18,10 +18,14 @@ @Schema(description = "温度") private String temperature; @Schema(description = "æ£æµæ¥æ") @Schema(description = "æ£æµå¼å§æ¥æ") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate detectionTime; @Schema(description = "æ£æµç»ææ¥æ") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate detectionEndTime; @Schema(description = "æ£æµå°ç¹") private String detectionPlace; inspect-server/src/main/resources/static/detection-report-template-v2.docxBinary files differ
inspect-server/src/main/resources/static/inspection-report-template-v2.docxBinary files differ