From 82ce59218139d9fefeae7b9e5fbc88b499ff023f Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 08 十月 2026 13:35:06 +0800
Subject: [PATCH] feat(inspect): 新增新聚检验订单编辑功能并优化报告生成流程 - 新增 updateNewJuInsOrder 接口支持新聚检验订单修改 - 增加文件上传大小限制至200MB,请求大小限制至400MB - 在设备信息中新增出厂编号字段显示 - 优化温湿度处理逻辑,报告中仅显示温度信息 - 新增印章管理功能,支持MA标志章、报告章和骑缝章配置 - 完善检验报告生成流程,增加多种报告类型常量定义 - 优化附件上传功能,增加空值检查和返回值处理 - 调整委托编号生成逻辑,完善新聚订单可编辑性判断 - 更新CNAS流程中报告编号使用正式报告编号替代委托编号

---
 cnas-process/src/main/resources/mapper/ProcessReportMapper.xml                                   |   54 +
 cnas-process/src/main/resources/static/report-deal.docx                                          |    0 
 inspect-server/src/main/java/com/ruoyi/inspect/vo/TemplateConditionVo.java                       |    3 
 basic-server/src/main/java/com/ruoyi/basic/service/impl/SealConfigServiceImpl.java               |  115 ++++
 inspect-server/src/main/java/com/ruoyi/inspect/dto/WriteInspectionConditionDto.java              |    8 
 inspect-server/src/main/resources/static/inspection-report-template-v2.docx                      |    0 
 cnas-process/src/main/java/com/ruoyi/process/pojo/ProcessReport.java                             |   14 
 inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java                |    6 
 inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java               |   15 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/InsOrderTypeConstants.java                  |    6 
 inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java                         |    3 
 basic-server/src/main/java/com/ruoyi/basic/service/SealConfigService.java                        |   33 +
 inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java                    |  302 ++++++++++
 basic-server/src/main/java/com/ruoyi/basic/dto/SealConfigExport.java                             |   31 +
 cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java        |   23 
 inspect-server/src/main/resources/mapper/InsOrderMapper.xml                                      |    3 
 inspect-server/src/main/resources/mapper/InsReportMapper.xml                                     |    3 
 cnas-process/src/main/java/com/ruoyi/process/listener/NewJuOrderInspectionListener.java          |   17 
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java             |  227 +++++++
 inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReport.java                               |   24 
 inspect-server/src/main/resources/static/detection-report-template-v2.docx                       |    0 
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java         |   43 
 inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java                      |    2 
 inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderPlanController.java            |    2 
 cnas-process/src/main/java/com/ruoyi/process/service/impl/ProcessReportServiceImpl.java          |  153 +++++
 basic-server/src/main/java/com/ruoyi/basic/controller/SealConfigController.java                  |  120 ++++
 cnas-process/src/main/java/com/ruoyi/process/controller/ProcessReportController.java             |    6 
 ruoyi-admin/src/main/resources/application.yml                                                   |    8 
 basic-server/src/main/java/com/ruoyi/basic/pojo/SealConfig.java                                  |   64 ++
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java           |    6 
 ruoyi-admin/src/main/resources/application-xjxj.yml                                              |    2 
 cnas-process/src/main/java/com/ruoyi/process/service/ProcessReportService.java                   |    3 
 inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java                     |    5 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/PersonalScopeAspect.java               |    5 
 basic-server/src/main/java/com/ruoyi/basic/mapper/SealConfigMapper.java                          |   15 
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java            |  282 +++++++--
 inspect-server/src/main/java/com/ruoyi/inspect/dto/SampleOrderDto.java                           |    3 
 inspect-server/src/main/java/com/ruoyi/inspect/vo/InsOrderPrintingVo.java                        |    8 
 basic-server/src/main/resources/mapper/SealConfigMapper.xml                                      |   12 
 inspect-server/src/main/java/com/ruoyi/inspect/util/PreserveReportPicturePlaceholderHandler.java |   13 
 40 files changed, 1,497 insertions(+), 142 deletions(-)

diff --git a/basic-server/src/main/java/com/ruoyi/basic/controller/SealConfigController.java b/basic-server/src/main/java/com/ruoyi/basic/controller/SealConfigController.java
new file mode 100644
index 0000000..51f2ba9
--- /dev/null
+++ b/basic-server/src/main/java/com/ruoyi/basic/controller/SealConfigController.java
@@ -0,0 +1,120 @@
+package com.ruoyi.basic.controller;
+
+import com.alibaba.excel.EasyExcel;
+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.extension.plugins.pagination.Page;
+import com.ruoyi.basic.dto.SealConfigExport;
+import com.ruoyi.basic.pojo.SealConfig;
+import com.ruoyi.basic.service.SealConfigService;
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.exception.base.BaseException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+/**
+ * 鍗扮珷绠$悊(鎶ュ憡鐢ㄥ嵃) 鎺у埗灞�
+ */
+@Api(tags = "鍗扮珷绠$悊")
+@RestController
+@RequestMapping("/sealConfig")
+public class SealConfigController {
+
+    @Resource
+    private SealConfigService sealConfigService;
+
+    @Value("${file.path}")
+    private String filePath;
+
+    @ApiOperation(value = "鏌ヨ鍗扮珷鍒楄〃")
+    @GetMapping("/pageSeal")
+    public Result<IPage<SealConfig>> pageSeal(Page page, SealConfig query) {
+        return Result.success(sealConfigService.pageSeal(page, query));
+    }
+
+    @ApiOperation(value = "鏂板鍗扮珷")
+    @PostMapping("/addSeal")
+    public Result addSeal(@RequestBody SealConfig seal) {
+        return Result.success(sealConfigService.addSeal(seal));
+    }
+
+    @ApiOperation(value = "淇敼鍗扮珷")
+    @PostMapping("/updateSeal")
+    public Result updateSeal(@RequestBody SealConfig seal) {
+        return Result.success(sealConfigService.updateSeal(seal));
+    }
+
+    @ApiOperation(value = "鍒犻櫎鍗扮珷")
+    @DeleteMapping("/delSeal")
+    public Result delSeal(Integer id) {
+        return Result.success(sealConfigService.delSeal(id));
+    }
+
+    @ApiOperation(value = "鍚敤鍗扮珷涓嬫媺鍒楄〃锛堜緵鎶ュ憡鎵瑰噯閫夋嫨鍗扮珷锛�")
+    @GetMapping("/selectEnabled")
+    public Result selectEnabled() {
+        return Result.success(sealConfigService.selectEnabled());
+    }
+
+    @ApiOperation(value = "涓婁紶鍗扮珷鍥剧墖")
+    @PostMapping("/upload")
+    public Result upload(MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            throw new BaseException("璇烽�夋嫨鍗扮珷鍥剧墖");
+        }
+        String originalName = file.getOriginalFilename() == null ? "" : file.getOriginalFilename();
+        String suffix = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase();
+        if (!"jpg".equals(suffix) && !"jpeg".equals(suffix) && !"png".equals(suffix)) {
+            throw new BaseException("浠呮敮鎸� jpg / png 鍥剧墖");
+        }
+        String fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmssSSS")) + "." + suffix;
+        try {
+            File dir = new File(filePath);
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+            file.transferTo(new File(dir.getPath() + File.separator + fileName));
+        } catch (IOException e) {
+            throw new BaseException("鍗扮珷鍥剧墖涓婁紶澶辫触");
+        }
+        return Result.success(fileName);
+    }
+
+    @ApiOperation(value = "瀵煎嚭鍗扮珷")
+    @GetMapping("/exportSeal")
+    public void exportSeal(SealConfig query, HttpServletResponse response) {
+        List<SealConfigExport> list = sealConfigService.listForExport(query);
+        response.setContentType("application/vnd.ms-excel");
+        response.setCharacterEncoding("UTF-8");
+        String fileName;
+        try {
+            fileName = URLEncoder.encode("鍗扮珷绠$悊", "UTF-8");
+        } catch (Exception e) {
+            throw new BaseException("瀵煎嚭澶辫触");
+        }
+        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+        try {
+            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
+                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
+            WriteSheet mainSheet = EasyExcel.writerSheet(0, "鍗扮珷绠$悊").head(SealConfigExport.class).build();
+            excelWriter.write(list, mainSheet);
+            excelWriter.finish();
+        } catch (IOException e) {
+            throw new BaseException("瀵煎嚭澶辫触");
+        }
+    }
+}
diff --git a/basic-server/src/main/java/com/ruoyi/basic/dto/SealConfigExport.java b/basic-server/src/main/java/com/ruoyi/basic/dto/SealConfigExport.java
new file mode 100644
index 0000000..df3a2bf
--- /dev/null
+++ b/basic-server/src/main/java/com/ruoyi/basic/dto/SealConfigExport.java
@@ -0,0 +1,31 @@
+package com.ruoyi.basic.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+/**
+ * 鍗扮珷绠$悊瀵煎嚭瀵硅薄
+ */
+@Data
+@ExcelIgnoreUnannotated
+public class SealConfigExport {
+
+    @ExcelProperty(value = "鍗扮珷缂栧彿")
+    private String code;
+
+    @ExcelProperty(value = "鍗扮珷鍚嶇О")
+    private String name;
+
+    @ExcelProperty(value = "浣跨敤鑼冨洿")
+    private String useScope;
+
+    @ExcelProperty(value = "鐘舵��")
+    private String statusName;
+
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private String createTime;
+}
diff --git a/basic-server/src/main/java/com/ruoyi/basic/mapper/SealConfigMapper.java b/basic-server/src/main/java/com/ruoyi/basic/mapper/SealConfigMapper.java
new file mode 100644
index 0000000..e0fe90b
--- /dev/null
+++ b/basic-server/src/main/java/com/ruoyi/basic/mapper/SealConfigMapper.java
@@ -0,0 +1,15 @@
+package com.ruoyi.basic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.basic.pojo.SealConfig;
+
+/**
+ * 鍗扮珷绠$悊(鎶ュ憡鐢ㄥ嵃) Mapper
+ */
+public interface SealConfigMapper extends BaseMapper<SealConfig> {
+
+    /**
+     * 鏌ヨ褰撳墠鏈�澶х殑鍗扮珷缂栧彿鍚庣紑鏁板瓧锛堢敤浜庤嚜鍔ㄧ敓鎴� YZ-00N锛夈��
+     */
+    Integer selectMaxCodeSuffix();
+}
diff --git a/basic-server/src/main/java/com/ruoyi/basic/pojo/SealConfig.java b/basic-server/src/main/java/com/ruoyi/basic/pojo/SealConfig.java
new file mode 100644
index 0000000..f1167f0
--- /dev/null
+++ b/basic-server/src/main/java/com/ruoyi/basic/pojo/SealConfig.java
@@ -0,0 +1,64 @@
+package com.ruoyi.basic.pojo;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 鍗扮珷绠$悊(鎶ュ憡鐢ㄥ嵃)琛ㄥ璞�
+ *
+ * <p>鍖哄埆浜庢寜瀹為獙瀹ょ淮鎶ょ殑鏃� seal 琛紝鏈〃鐢ㄤ簬闆嗕腑缁存姢鍑哄叿鎶ュ憡鎵�闇�鐨勫悇绫诲嵃绔狅紝
+ * 渚涒�滄姤鍛婄紪鍒�-鎵瑰噯鈥濇椂鐨勫嵃绔犲閫変笅鎷変娇鐢紙浠呭惎鐢ㄧ姸鎬佺殑鍗扮珷鍙�夛級銆�</p>
+ */
+@TableName(value = "cnas_seal")
+@Data
+public class SealConfig implements Serializable {
+
+    @ApiModelProperty(value = "涓婚敭")
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "鍗扮珷缂栧彿锛堜繚瀛樻椂鑷姩鐢熸垚锛屽 YZ-001锛�")
+    private String code;
+
+    @ApiModelProperty(value = "鍗扮珷鍚嶇О")
+    private String name;
+
+    @ApiModelProperty(value = "鍗扮珷鍥剧墖锛堢浉瀵� file.path 鐨勬枃浠跺悕锛�")
+    private String address;
+
+    @ApiModelProperty(value = "浣跨敤鑼冨洿")
+    private String useScope;
+
+    @ApiModelProperty(value = "鐘舵�侊細1鍚敤 0鍋滅敤")
+    private Integer status;
+
+    @ApiModelProperty(value = "澶囨敞")
+    private String remark;
+
+    @ApiModelProperty(value = "鍒涘缓浜篿d")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "鏇存柊浜篿d")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+}
diff --git a/basic-server/src/main/java/com/ruoyi/basic/service/SealConfigService.java b/basic-server/src/main/java/com/ruoyi/basic/service/SealConfigService.java
new file mode 100644
index 0000000..6c16579
--- /dev/null
+++ b/basic-server/src/main/java/com/ruoyi/basic/service/SealConfigService.java
@@ -0,0 +1,33 @@
+package com.ruoyi.basic.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.basic.dto.SealConfigExport;
+import com.ruoyi.basic.pojo.SealConfig;
+
+import java.util.List;
+
+/**
+ * 鍗扮珷绠$悊(鎶ュ憡鐢ㄥ嵃) 鏈嶅姟绫�
+ */
+public interface SealConfigService extends IService<SealConfig> {
+
+    IPage<SealConfig> pageSeal(Page page, SealConfig query);
+
+    int addSeal(SealConfig seal);
+
+    int updateSeal(SealConfig seal);
+
+    int delSeal(Integer id);
+
+    /**
+     * 鏌ヨ鍚敤鐘舵�佺殑鍗扮珷锛堜緵鎶ュ憡鎵瑰噯鍗扮珷澶氶�変笅鎷変娇鐢級銆�
+     */
+    List<SealConfig> selectEnabled();
+
+    /**
+     * 鎸夋潯浠舵煡璇㈠鍑哄垪琛ㄣ��
+     */
+    List<SealConfigExport> listForExport(SealConfig query);
+}
diff --git a/basic-server/src/main/java/com/ruoyi/basic/service/impl/SealConfigServiceImpl.java b/basic-server/src/main/java/com/ruoyi/basic/service/impl/SealConfigServiceImpl.java
new file mode 100644
index 0000000..e74f895
--- /dev/null
+++ b/basic-server/src/main/java/com/ruoyi/basic/service/impl/SealConfigServiceImpl.java
@@ -0,0 +1,115 @@
+package com.ruoyi.basic.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+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.SealConfigExport;
+import com.ruoyi.basic.mapper.SealConfigMapper;
+import com.ruoyi.basic.pojo.SealConfig;
+import com.ruoyi.basic.service.SealConfigService;
+import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.QueryWrappers;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鍗扮珷绠$悊(鎶ュ憡鐢ㄥ嵃) 鏈嶅姟瀹炵幇
+ */
+@Service
+public class SealConfigServiceImpl extends ServiceImpl<SealConfigMapper, SealConfig> implements SealConfigService {
+
+    @Resource
+    private SealConfigMapper sealConfigMapper;
+
+    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    @Override
+    public IPage<SealConfig> pageSeal(Page page, SealConfig query) {
+        QueryWrapper<SealConfig> wrapper = QueryWrappers.queryWrappers(query);
+        if (wrapper == null) {
+            wrapper = Wrappers.query();
+        }
+        wrapper.orderByDesc("create_time").orderByAsc("code");
+        return this.page(page, wrapper);
+    }
+
+    @Override
+    public int addSeal(SealConfig seal) {
+        validate(seal);
+        seal.setCode(generateCode());
+        return sealConfigMapper.insert(seal);
+    }
+
+    @Override
+    public int updateSeal(SealConfig seal) {
+        if (seal.getId() == null) {
+            throw new BaseException("鍗扮珷id涓嶈兘涓虹┖");
+        }
+        validate(seal);
+        // 缂栧彿涓嶅厑璁稿墠绔慨鏀癸紝淇濇寔鑷姩鐢熸垚鍊间笉鍙�
+        SealConfig db = sealConfigMapper.selectById(seal.getId());
+        if (db != null) {
+            seal.setCode(db.getCode());
+        }
+        return sealConfigMapper.updateById(seal);
+    }
+
+    @Override
+    public int delSeal(Integer id) {
+        return sealConfigMapper.deleteById(id);
+    }
+
+    @Override
+    public List<SealConfig> selectEnabled() {
+        return this.list(Wrappers.<SealConfig>lambdaQuery()
+                .eq(SealConfig::getStatus, 1)
+                .orderByAsc(SealConfig::getCode));
+    }
+
+    @Override
+    public List<SealConfigExport> listForExport(SealConfig query) {
+        QueryWrapper<SealConfig> wrapper = QueryWrappers.queryWrappers(query);
+        if (wrapper == null) {
+            wrapper = Wrappers.query();
+        }
+        wrapper.orderByAsc("code");
+        List<SealConfig> list = this.list(wrapper);
+        List<SealConfigExport> exports = new ArrayList<>();
+        for (SealConfig seal : list) {
+            SealConfigExport export = new SealConfigExport();
+            export.setCode(seal.getCode());
+            export.setName(seal.getName());
+            export.setUseScope(seal.getUseScope());
+            export.setStatusName(seal.getStatus() != null && seal.getStatus() == 1 ? "鍚敤" : "鍋滅敤");
+            export.setRemark(seal.getRemark());
+            export.setCreateTime(seal.getCreateTime() == null ? "" : seal.getCreateTime().format(DATE_FORMAT));
+            exports.add(export);
+        }
+        return exports;
+    }
+
+    private void validate(SealConfig seal) {
+        if (StringUtils.isBlank(seal.getName())) {
+            throw new BaseException("鍗扮珷鍚嶇О涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isBlank(seal.getAddress())) {
+            throw new BaseException("鍗扮珷鍥剧墖涓嶈兘涓虹┖");
+        }
+    }
+
+    /**
+     * 鑷姩鐢熸垚鍗扮珷缂栧彿锛歒Z-001銆乊Z-002 ...
+     */
+    private String generateCode() {
+        Integer max = sealConfigMapper.selectMaxCodeSuffix();
+        int next = (max == null ? 0 : max) + 1;
+        return String.format("YZ-%03d", next);
+    }
+}
diff --git a/basic-server/src/main/resources/mapper/SealConfigMapper.xml b/basic-server/src/main/resources/mapper/SealConfigMapper.xml
new file mode 100644
index 0000000..cebefa4
--- /dev/null
+++ b/basic-server/src/main/resources/mapper/SealConfigMapper.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.basic.mapper.SealConfigMapper">
+
+    <select id="selectMaxCodeSuffix" resultType="java.lang.Integer">
+        select ifnull(max(cast(substring(code, 4) as unsigned)), 0)
+        from cnas_seal
+        where code like 'YZ-%'
+    </select>
+</mapper>
diff --git a/cnas-process/src/main/java/com/ruoyi/process/controller/ProcessReportController.java b/cnas-process/src/main/java/com/ruoyi/process/controller/ProcessReportController.java
index 1c683bf..f3a7eef 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/controller/ProcessReportController.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/controller/ProcessReportController.java
@@ -68,4 +68,10 @@
         processReportService.exportProcessReport(dto, response);
     }
 
+    @ApiOperation(value = "涓嬭浇鎵瑰噯鍚庣殑鏈夌珷鎶ュ憡")
+    @GetMapping("/downloadStampedReport")
+    public void downloadStampedReport(Integer id, String format, HttpServletResponse response) {
+        processReportService.downloadStampedReport(id, format, response);
+    }
+
 }
diff --git a/cnas-process/src/main/java/com/ruoyi/process/listener/NewJuOrderInspectionListener.java b/cnas-process/src/main/java/com/ruoyi/process/listener/NewJuOrderInspectionListener.java
index c444fa5..c93886d 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/listener/NewJuOrderInspectionListener.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/listener/NewJuOrderInspectionListener.java
@@ -30,9 +30,20 @@
             return;
         }
         // 骞傜瓑锛氬悓涓�鎴愬搧璁㈠崟宸叉湁妫�楠屽鎵樺崟鍒欒烦杩�
-        Long count = inspectionOrderMapper.selectCount(Wrappers.<InspectionOrder>lambdaQuery()
-                .eq(InspectionOrder::getInsOrderId, order.getId()));
-        if (count > 0) {
+        InspectionOrder existingOrder = inspectionOrderMapper.selectOne(Wrappers.<InspectionOrder>lambdaQuery()
+                .eq(InspectionOrder::getInsOrderId, order.getId()).last("limit 1"));
+        if (existingOrder != null) {
+            existingOrder.setEntrustCode(order.getEntrustCode());
+            existingOrder.setSampleName(StringUtils.isNotBlank(order.getSampleView()) ? order.getSampleView() : order.getSample());
+            existingOrder.setProduction(order.getProduction());
+            existingOrder.setQuantity(order.getTestQuantity());
+            existingOrder.setCommissionUnit(order.getCompany());
+            existingOrder.setCommissionUser(order.getPrepareUser());
+            existingOrder.setCommissionPhone(order.getPhone());
+            existingOrder.setIsLeave(Integer.valueOf(1).equals(order.getIsLeave()) ? 1 : 2);
+            existingOrder.setProcessing(Integer.valueOf(1).equals(order.getSampleDisposal()) ? 0 : 1);
+            existingOrder.setSend(Integer.valueOf(1).equals(order.getReportDelivery()) ? 1 : 0);
+            inspectionOrderMapper.updateById(existingOrder);
             return;
         }
         InspectionOrder inspectionOrder = new InspectionOrder();
diff --git a/cnas-process/src/main/java/com/ruoyi/process/pojo/ProcessReport.java b/cnas-process/src/main/java/com/ruoyi/process/pojo/ProcessReport.java
index 478721d..8a63d8f 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/pojo/ProcessReport.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/pojo/ProcessReport.java
@@ -36,12 +36,6 @@
     @ApiModelProperty("妫�楠屾姤鍛婄紪鍙�")
     private String insReportCode;
 
-    @ApiModelProperty("椤垫暟")
-    private String pages;
-
-    @ApiModelProperty("鍙戦�佷唤鏁�")
-    private String number;
-
     @ApiModelProperty("鍙戝線浣曞")
     private String send;
 
@@ -74,4 +68,12 @@
 
     @ApiModelProperty("濮旀墭鍗昳d")
     private Integer inspectionOrderId;
+
+    @ApiModelProperty("棰嗘姤鍛婃棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate receiveDate;
+
+    @ApiModelProperty("棰嗘姤鍛婁汉")
+    private String receiveUser;
+
 }
diff --git a/cnas-process/src/main/java/com/ruoyi/process/service/ProcessReportService.java b/cnas-process/src/main/java/com/ruoyi/process/service/ProcessReportService.java
index faf5c48..edaa0c7 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/service/ProcessReportService.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/service/ProcessReportService.java
@@ -23,4 +23,7 @@
     IPage<ProcessReportDto> pageProcessReport(Page page, ProcessReportDto processReport);
 
     void exportProcessReport(ProcessReportDto dto, HttpServletResponse response);
+
+    /** 涓嬭浇鎵瑰噯鍚庣敓鎴愮殑鏈夌珷鎶ュ憡锛宖ormat锛歱df 鎴� word銆� */
+    void downloadStampedReport(Integer id, String format, HttpServletResponse response);
 }
diff --git a/cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java b/cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java
index 9b18aec..20475eb 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java
@@ -146,14 +146,7 @@
         /*鏂板7.8鎶ュ憡缁撴灉*/
         ProcessReport processReport = new ProcessReport();
         processReport.setInspectionOrderId(inspectionOrder.getInsOrderId());
-        processReport.setInsReportCode(inspectionOrder.getEntrustCode());//鎶ュ憡缂栧彿=濮旀墭缂栧彿
-        //椤垫暟
-        try {
-            com.aspose.words.Document doc = new com.aspose.words.Document(path);
-            processReport.setPages(doc.getPageCount()+"");
-        } catch (Exception e) {
-        }
-        processReport.setNumber("1");//鍙戦�佷唤鏁伴粯璁�1
+        processReport.setInsReportCode(insReport.getCode());//鎶ュ憡缂栧彿浣跨敤姝e紡鎶ュ憡缂栧彿
         processReport.setSend(inspectionOrder.getCommissionUnit());//鍙戝線浣曞=濮旀墭鍗曚綅
         processReport.setMethod(inspectionOrder.getSend()==1?"鑷彇":"鍏朵粬");//鍙戦�佹柟寮�
         processReport.setSendTime(insReport.getRatifyTime().toLocalDate());//鍙戦�佹棩鏈�
@@ -247,9 +240,17 @@
         inspectionOrderDetailService.saveBatch(InspectionOrder.getOrderDetailList());
 
         //淇敼7.9鎶ュ憡缁撴灉
-        ProcessReport processReport = processReportService.getOne(Wrappers.<ProcessReport>lambdaQuery().eq(ProcessReport::getInspectionOrderId, InspectionOrder.getInspectionOrderId()));
-        processReport.setInsReportCode(InspectionOrder.getEntrustCode());//鎶ュ憡缂栧彿=濮旀墭缂栧彿
-        processReportService.updateById(processReport);
+        ProcessReport processReport = processReportService.getOne(Wrappers.<ProcessReport>lambdaQuery()
+                .eq(ProcessReport::getInspectionOrderId, InspectionOrder.getInsOrderId())
+                .last("limit 1"));
+        InsReport insReport = insReportService.getOne(Wrappers.<InsReport>lambdaQuery()
+                .eq(InsReport::getInsOrderId, InspectionOrder.getInsOrderId())
+                .orderByDesc(InsReport::getId)
+                .last("limit 1"));
+        if (processReport != null && insReport != null) {
+            processReport.setInsReportCode(insReport.getCode());//鎶ュ憡缂栧彿浣跨敤姝e紡鎶ュ憡缂栧彿
+            processReportService.updateById(processReport);
+        }
 
         return true;
     }
diff --git a/cnas-process/src/main/java/com/ruoyi/process/service/impl/ProcessReportServiceImpl.java b/cnas-process/src/main/java/com/ruoyi/process/service/impl/ProcessReportServiceImpl.java
index 5bca8b2..42c93eb 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/service/impl/ProcessReportServiceImpl.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/service/impl/ProcessReportServiceImpl.java
@@ -15,7 +15,12 @@
 import com.ruoyi.common.utils.QueryWrappers;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.SignatureImageUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.inspect.mapper.InsOrderMapper;
+import com.ruoyi.inspect.mapper.InsReportMapper;
+import com.ruoyi.inspect.pojo.InsOrder;
+import com.ruoyi.inspect.pojo.InsReport;
 import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
 import com.ruoyi.process.dto.ProcessReportDto;
 import com.ruoyi.process.mapper.ProcessReportMapper;
@@ -33,11 +38,14 @@
 import java.io.*;
 import java.net.URLEncoder;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -56,17 +64,162 @@
     private ProcessReportMapper processReportMapper;
     @Value("${file.path}")
     private String imgUrl;
+    @Value("${wordUrl}")
+    private String wordUrl;
 
     @Resource
     private UserMapper userMapper;
 
+    @Resource
+    private InsReportMapper insReportMapper;
+
+    @Resource
+    private InsOrderMapper insOrderMapper;
+
     @Override
     public IPage<ProcessReportDto> pageProcessReport(Page page, ProcessReportDto processReport) {
+        // #21 鎵撳紑鍒楄〃鏃讹紝鑷姩甯﹀嚭宸查�氳繃瀹℃壒锛堟壒鍑嗙姸鎬�=鎵瑰噯锛変絾灏氭湭鐧昏鐨勬楠屽崟
+        autoBringOutApproved();
         IPage<ProcessReportDto> processReportIPage = processReportMapper.pageProcessReport(page, QueryWrappers.queryWrappers(processReport));
 
         return processReportIPage;
     }
 
+    /**
+     * 鎵弿宸叉壒鍑嗕絾灏氭湭杩涘叆鎶ュ憡缁撴灉鐧昏琛ㄧ殑妫�楠屾姤鍛婏紝鑷姩鐢熸垚寰呯櫥璁拌褰曪紙浠ユ姤鍛婄紪鍙峰幓閲嶏紝骞傜瓑锛夈��
+     */
+    private void autoBringOutApproved() {
+        List<InsReport> approved = insReportMapper.selectList(Wrappers.<InsReport>lambdaQuery()
+                .eq(InsReport::getIsRatify, 1)
+                .eq(InsReport::getIsPass, 1));
+        if (approved.isEmpty()) {
+            return;
+        }
+        Set<String> existing = this.list(Wrappers.<ProcessReport>lambdaQuery()
+                .select(ProcessReport::getInsReportCode)).stream()
+                .map(ProcessReport::getInsReportCode)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toCollection(HashSet::new));
+        for (InsReport report : approved) {
+            String code = report.getCode();
+            if (StringUtils.isBlank(code) || existing.contains(code)) {
+                continue;
+            }
+            ProcessReport pr = new ProcessReport();
+            pr.setInsReportCode(code);
+            pr.setInspectionOrderId(report.getInsOrderId());
+            if (report.getRatifyTime() != null) {
+                pr.setSendTime(report.getRatifyTime().toLocalDate());
+            }
+            if (report.getInsOrderId() != null) {
+                InsOrder order = insOrderMapper.selectById(report.getInsOrderId());
+                if (order != null) {
+                    pr.setSend(order.getCompany());
+                    pr.setMethod(getReportDeliveryName(order));
+                }
+            }
+            this.save(pr);
+            existing.add(code);
+        }
+    }
+
+    private String getReportDeliveryName(InsOrder order) {
+        if (order.getReportDelivery() != null) {
+            switch (order.getReportDelivery()) {
+                case 1:
+                    return "鑷彇";
+                case 2:
+                    return "蹇��";
+                case 3:
+                    return "鐢靛瓙浼犻��";
+                default:
+                    break;
+            }
+        }
+        // 鍏煎灏氭湭缁存姢 report_delivery 鐨勫巻鍙插鎵樺崟銆�
+        return order.getSend() != null && order.getSend() == 1 ? "鑷彇" : "鍏朵粬";
+    }
+
+    @Override
+    public void downloadStampedReport(Integer id, String format, HttpServletResponse response) {
+        if (id == null) {
+            throw new ErrorException("鎶ュ憡缁撴灉涓嶈兘涓虹┖");
+        }
+        ProcessReport processReport = getById(id);
+        if (processReport == null) {
+            throw new ErrorException("鎶ュ憡缁撴灉涓嶅瓨鍦�");
+        }
+        if (StringUtils.isBlank(processReport.getInsReportCode())
+                && processReport.getInspectionOrderId() == null) {
+            throw new ErrorException("璇ヨ褰曟湭鍏宠仈妫�楠屾姤鍛婏紝鏃犳硶涓嬭浇");
+        }
+
+        String downloadFormat = StringUtils.isBlank(format) ? "pdf" : format.trim().toLowerCase();
+        if (!"pdf".equals(downloadFormat) && !"word".equals(downloadFormat)) {
+            throw new ErrorException("涓嬭浇鏍煎紡涓嶆纭�");
+        }
+
+        com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<InsReport> query =
+                Wrappers.<InsReport>lambdaQuery()
+                        .eq(InsReport::getIsRatify, 1)
+                        .eq(StringUtils.isNotBlank(processReport.getInsReportCode()),
+                                InsReport::getCode, processReport.getInsReportCode())
+                        .eq(processReport.getInspectionOrderId() != null,
+                                InsReport::getInsOrderId, processReport.getInspectionOrderId())
+                        .orderByDesc(InsReport::getId)
+                        .last("limit 1");
+        InsReport report = insReportMapper.selectOne(query);
+        if (report == null) {
+            throw new ErrorException("鏈壘鍒板凡鎵瑰噯鐨勬姤鍛婏紝鏃犳硶涓嬭浇鏈夌珷鎶ュ憡");
+        }
+
+        String fileUrl;
+        String extension;
+        String contentType;
+        if ("word".equals(downloadFormat)) {
+            fileUrl = StringUtils.isNotBlank(report.getUrlS()) ? report.getUrlS() : report.getUrl();
+            extension = ".docx";
+            contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+        } else {
+            fileUrl = report.getTempUrlPdf();
+            extension = ".pdf";
+            contentType = "application/pdf";
+        }
+        if ("pdf".equals(downloadFormat) && StringUtils.isBlank(fileUrl)) {
+            String reportUrl = StringUtils.isNotBlank(report.getUrlS()) ? report.getUrlS() : report.getUrl();
+            if (StringUtils.isNotBlank(reportUrl) && reportUrl.toLowerCase().endsWith(".docx")) {
+                fileUrl = reportUrl.substring(0, reportUrl.length() - 5) + ".pdf";
+            }
+        }
+        if (StringUtils.isBlank(fileUrl) || !fileUrl.replace('\\', '/').startsWith("/word/")) {
+            throw new ErrorException("鏈夌珷鎶ュ憡灏氭湭鐢熸垚锛岃鍏堝畬鎴愭姤鍛婃壒鍑�");
+        }
+
+        Path root = Paths.get(wordUrl).toAbsolutePath().normalize();
+        Path file = root.resolve(fileUrl.replace('\\', '/').substring("/word/".length())).normalize();
+        if (!file.startsWith(root) || !Files.isRegularFile(file)) {
+            throw new ErrorException("鏈夌珷鎶ュ憡鏂囦欢涓嶅瓨鍦紝璇烽噸鏂版壒鍑嗙敓鎴�");
+        }
+
+        try {
+            String filename = StringUtils.isNotBlank(processReport.getInsReportCode())
+                    ? processReport.getInsReportCode() + extension : file.getFileName().toString();
+            String encodedName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20");
+            response.setContentType(contentType);
+            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName);
+            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
+            response.setHeader("download-filename", encodedName);
+            response.setContentLengthLong(Files.size(file));
+            try (InputStream inputStream = Files.newInputStream(file);
+                 OutputStream outputStream = response.getOutputStream()) {
+                IOUtils.copy(inputStream, outputStream);
+                outputStream.flush();
+            }
+        } catch (IOException e) {
+            throw new ErrorException("鏈夌珷鎶ュ憡涓嬭浇澶辫触");
+        }
+    }
+
     @Override
     public void exportProcessReport(ProcessReportDto dto, HttpServletResponse response) {
         List<ProcessReportDto> processReports = processReportMapper.exportProcessReport();
diff --git a/cnas-process/src/main/resources/mapper/ProcessReportMapper.xml b/cnas-process/src/main/resources/mapper/ProcessReportMapper.xml
index 62e82d0..d40c71a 100644
--- a/cnas-process/src/main/resources/mapper/ProcessReportMapper.xml
+++ b/cnas-process/src/main/resources/mapper/ProcessReportMapper.xml
@@ -5,8 +5,6 @@
     <resultMap id="BaseResultMap" type="com.ruoyi.process.pojo.ProcessReport">
         <id column="id" property="id"/>
         <result column="ins_report_code" property="insReportCode"/>
-        <result column="pages" property="pages"/>
-        <result column="number" property="number"/>
         <result column="send" property="send"/>
         <result column="method" property="method"/>
         <result column="send_time" property="sendTime"/>
@@ -19,19 +17,65 @@
         <result column="update_time" property="updateTime"/>
     </resultMap>
     <select id="pageProcessReport" resultType="com.ruoyi.process.dto.ProcessReportDto">
-        select * from (select cpr.* ,
+        select * from (select cpr.id,
+        cpr.ins_report_code,
+        cpr.send,
+        case io.report_delivery
+            when 1 then '鑷彇'
+            when 2 then '蹇��'
+            when 3 then '鐢靛瓙浼犻��'
+            else cpr.method
+        end method,
+        cpr.send_time,
+        cpr.send_user,
+        cpr.signatory,
+        cpr.remark,
+        cpr.create_user,
+        cpr.create_time,
+        cpr.update_user,
+        cpr.update_time,
+        cpr.inspection_order_id,
+        cpr.receive_date,
+        cpr.receive_user,
         u1.name sendUserName
         from cnas_process_report cpr
-        left join user u1 on send_user=u1.id )A
+        left join user u1 on send_user=u1.id
+        inner join ins_report ir on ir.code = cpr.ins_report_code
+            and ir.ins_order_id = cpr.inspection_order_id
+            and ir.is_ratify = 1 and ir.is_pass = 1
+        left join ins_order io on io.id = ir.ins_order_id )A
         <if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
             ${ew.customSqlSegment}
         </if>
     </select>
     <select id="exportProcessReport" resultType="com.ruoyi.process.dto.ProcessReportDto">
         select ROW_NUMBER() OVER (ORDER BY cpr.id) AS indexs,
-        cpr.* ,
+        cpr.id,
+        cpr.ins_report_code,
+        cpr.send,
+        case io.report_delivery
+            when 1 then '鑷彇'
+            when 2 then '蹇��'
+            when 3 then '鐢靛瓙浼犻��'
+            else cpr.method
+        end method,
+        cpr.send_time,
+        cpr.send_user,
+        cpr.signatory,
+        cpr.remark,
+        cpr.create_user,
+        cpr.create_time,
+        cpr.update_user,
+        cpr.update_time,
+        cpr.inspection_order_id,
+        cpr.receive_date,
+        cpr.receive_user,
         u1.signature_url sendUserUrl
         from cnas_process_report cpr
         left join user u1 on send_user=u1.id
+        inner join ins_report ir on ir.code = cpr.ins_report_code
+            and ir.ins_order_id = cpr.inspection_order_id
+            and ir.is_ratify = 1 and ir.is_pass = 1
+        left join ins_order io on io.id = ir.ins_order_id
     </select>
 </mapper>
diff --git a/cnas-process/src/main/resources/static/report-deal.docx b/cnas-process/src/main/resources/static/report-deal.docx
index 7f515a5..5150370 100644
--- a/cnas-process/src/main/resources/static/report-deal.docx
+++ b/cnas-process/src/main/resources/static/report-deal.docx
Binary files differ
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java
index 35c07d1..4b6ccdf 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java
@@ -88,6 +88,12 @@
         return Result.success(insOrderService.addInsOrder(insPlaceOrderDto.getSampleList(), insPlaceOrderDto.getInsOrder()));
     }
 
+    @ApiOperation(value = "淇敼鏂拌仛妫�楠屼笅鍗曟暟鎹�")
+    @PostMapping("/updateNewJuInsOrder")
+    public Result<?> updateNewJuInsOrder(@RequestBody InsPlaceOrderDto insPlaceOrderDto) {
+        return Result.success(insOrderService.updateNewJuInsOrder(insPlaceOrderDto));
+    }
+
     @ApiOperation(value = "鏌ヨ璁㈠崟鏈�闀块璁℃椂闂�")
     @GetMapping("/selectOrderManDay")
     public Result<?> selectOrderManDay(Integer id) {
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderPlanController.java b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderPlanController.java
index cbce3a2..6fcd611 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderPlanController.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderPlanController.java
@@ -175,7 +175,7 @@
         return Result.success(map);
     }
 
-    @ApiOperation(value = "濉啓娓╁害涓庢箍搴�")
+    @ApiOperation(value = "濉啓娓╁害")
     @PostMapping("/write")
     public Result<?> write(@RequestBody WriteInspectionConditionDto dto) {
         return Result.success(insProductService.write(dto));
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java
index 06a045e..41cdfad 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java
@@ -115,7 +115,20 @@
         Integer id = (Integer) param.get("id");
         Integer isRatify = (Integer) param.get("isRatify");
         String ratifyTell = (String) param.get("ratifyTell");
-        return Result.success(insReportService.ratifyReport(id, isRatify, ratifyTell));
+        Object sealIdsObj = param.get("sealIds");
+        String sealIds = sealIdsObj == null ? null : String.valueOf(sealIdsObj);
+        Integer maSealId = toInteger(param.get("maSealId"));
+        Integer reportSealId = toInteger(param.get("reportSealId"));
+        Integer seamSealId = toInteger(param.get("seamSealId"));
+        return Result.success(insReportService.ratifyReport(
+                id, isRatify, ratifyTell, sealIds, maSealId, reportSealId, seamSealId));
+    }
+
+    private Integer toInteger(Object value) {
+        if (value == null || String.valueOf(value).trim().isEmpty()) {
+            return null;
+        }
+        return value instanceof Number ? ((Number) value).intValue() : Integer.valueOf(String.valueOf(value));
     }
 
     @Anonymous
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java b/inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java
index 689a9ea..061c90b 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java
@@ -15,6 +15,9 @@
 @Data
 public class InsPlaceOrderDto{
 
+    @ApiModelProperty("缂栬緫鐨勮鍗旾D")
+    private Integer orderId;
+
     @ApiModelProperty("鏍峰搧")
     private List<SampleProductDto> sampleList;
 
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/dto/SampleOrderDto.java b/inspect-server/src/main/java/com/ruoyi/inspect/dto/SampleOrderDto.java
index 2a60950..2113508 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/dto/SampleOrderDto.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/dto/SampleOrderDto.java
@@ -17,6 +17,9 @@
 @ExcelIgnoreUnannotated
 public class SampleOrderDto extends InsOrder {
 
+    @ApiModelProperty("鏄惁鍏佽缂栬緫")
+    private Boolean editable;
+
     @ApiModelProperty("妫�楠屽璞�")
     private String sampleType;
 
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/dto/WriteInspectionConditionDto.java b/inspect-server/src/main/java/com/ruoyi/inspect/dto/WriteInspectionConditionDto.java
index 518d940..70c5067 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/dto/WriteInspectionConditionDto.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/dto/WriteInspectionConditionDto.java
@@ -16,7 +16,6 @@
     private Integer templateId;
     private String remark;
     private String temperature;
-    private String humidity;
 
     @JsonFormat(pattern = "yyyy-MM-dd")
     private LocalDate detectionTime;
@@ -27,8 +26,6 @@
 
     @JsonIgnore
     private boolean temperaturePresent;
-    @JsonIgnore
-    private boolean humidityPresent;
     @JsonIgnore
     private boolean detectionTimePresent;
     @JsonIgnore
@@ -41,11 +38,6 @@
     public void setTemperature(String temperature) {
         this.temperature = temperature;
         this.temperaturePresent = true;
-    }
-
-    public void setHumidity(String humidity) {
-        this.humidity = humidity;
-        this.humidityPresent = true;
     }
 
     public void setDetectionTime(LocalDate detectionTime) {
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReport.java b/inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReport.java
index 2f2e668..9e90240 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReport.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/pojo/InsReport.java
@@ -135,4 +135,28 @@
     @ApiModelProperty(value = "鏄惁鏄�氳繃鐨勬姤鍛�, 0:鏈�氳繃, 1:閫氳繃")
     private Integer isPass;
 
+    @ApiModelProperty(value = "鎵瑰噯鏃堕�夌敤鐨勫嵃绔爄d锛堝閫夛紝閫楀彿鍒嗛殧锛�")
+    private String sealIds;
+
+    @ApiModelProperty(value = "鎵瑰噯鏃堕�夌敤鐨勫嵃绔犲悕绉帮紙澶氫釜锛岄�楀彿鍒嗛殧锛�")
+    private String sealNames;
+
+    @ApiModelProperty(value = "MA鏍囧織绔爄d锛圥DF绗�1椤靛乏涓婅锛�")
+    private Integer maSealId;
+
+    @ApiModelProperty(value = "MA鏍囧織绔犲悕绉�")
+    private String maSealName;
+
+    @ApiModelProperty(value = "鎶ュ憡绔爄d锛堝搴旀ā鏉� seal1銆乻eal2锛�")
+    private Integer reportSealId;
+
+    @ApiModelProperty(value = "鎶ュ憡绔犲悕绉�")
+    private String reportSealName;
+
+    @ApiModelProperty(value = "PDF楠戠紳绔犵殑鍗扮珷id")
+    private Integer seamSealId;
+
+    @ApiModelProperty(value = "PDF楠戠紳绔犵殑鍗扮珷鍚嶇О")
+    private String seamSealName;
+
 }
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java
index aba8a3e..a3025a2 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java
@@ -37,6 +37,8 @@
 
     int addNewJuInsOrder(InsPlaceOrderDto insPlaceOrderDto);
 
+    int updateNewJuInsOrder(InsPlaceOrderDto insPlaceOrderDto);
+
     Map<String, Object> getInsOrder(Integer id);
 
     int upInsOrderOfState(InsOrder insOrder);
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java
index 5b504f4..9029a60 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java
@@ -22,7 +22,7 @@
 
     Map<String,Object> pageInsReport(Page page, ReportPageDto reportPageDto);
 
-    void wordToPdf(String path,String sealUrl, boolean isRawMater);
+    void wordToPdf(String path, String maSealUrl, String seamSealUrl, boolean isRawMater);
 
     int inReport(String url, Integer id);
 
@@ -35,7 +35,8 @@
     int examineReport(Integer id, Integer isExamine, String examineTell, Integer userId);
 
     //鎵瑰噯
-    int ratifyReport(Integer id, Integer isRatify, String ratifyTell);
+    int ratifyReport(Integer id, Integer isRatify, String ratifyTell, String sealIds,
+                     Integer maSealId, Integer reportSealId, Integer seamSealId);
 
     int wordInsertUrl(Map<String, Object> map, String url);
 
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
index 3394113..d1b2df8 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
@@ -84,7 +84,6 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * 妫�楠屼换鍔�-涓氬姟瀹炵幇灞�
@@ -380,6 +379,9 @@
 
     @Override
     public int uploadFile(Integer orderId, MultipartFile file) {
+        if (orderId == null || file == null || file.isEmpty()) {
+            throw new ErrorException("璇烽�夋嫨瑕佷笂浼犵殑闄勪欢");
+        }
         String urlString;
         String pathName;
         String path;
@@ -406,7 +408,7 @@
             urlString = realpath + "/" + pathName;
             file.transferTo(new File(urlString));
             insOrderFile.setFileUrl(pathName);
-            return insOrderFileMapper.insert(insOrderFile);
+            return insOrderFileMapper.insert(insOrderFile) > 0 ? insOrderFile.getId() : 0;
         } catch (Exception e) {
             e.printStackTrace();
             System.err.println("闄勪欢涓婁紶閿欒");
@@ -1684,8 +1686,9 @@
         boolean directTemplateOrder = isDirectTemplateOrder(orderId);
         if (currentState != null && Objects.equals(currentState.getInsState(), 5)
                 && existingReport != null && StringUtils.isNotBlank(existingReport.getUrl())
+                && Objects.equals(existingReport.getIsPass(), 1)
                 && (!directTemplateOrder || StringUtils.isNotBlank(existingReport.getInspectionUrl()))) {
-            // 闃叉澶嶆牳椤甸潰閲嶅鐐瑰嚮鎴栫綉缁滈噸璇曢噸澶嶇敓鎴愭姤鍛娿�侀噸澶嶅彂璧锋姤鍛婂鎵广��
+            // 浠呭浠嶅湪鎶ュ憡缂栧埗涓殑璁板綍闃查噸澶嶏紱閫�鍥炴楠屼换鍔$殑鎶ュ憡闇�瑕佺户缁墽琛屽苟鎭㈠ is_pass銆�
             return 1;
         }
         if (directTemplateOrder && Objects.equals(type, 1)
@@ -1964,10 +1967,12 @@
         if (StringUtils.isBlank(tempPdfName)) {
             throw new ErrorException("鎶ュ憡棰勮鏂囦欢鐢熸垚澶辫触");
         }
-        // generateReport 浼氬啓鍏ュ綋鍓嶆椂闂达紱閲嶆柊鐢熸垚涓嶅簲鏀瑰彉鍘熷鎵硅褰曟椂闂淬��
+        // generateReport 浼氬啓鍏ュ綋鍓嶆椂闂达紝閮ㄥ垎鎶ュ憡杩樹細鏆傛椂鍐欏叆 is_pass=0锛�
+        // 閲嶆柊鐢熸垚涓嶅簲鏀瑰彉鍘熷鎵硅褰曟椂闂村拰鍙鐘舵�併��
         insReportMapper.update(null, Wrappers.<InsReport>lambdaUpdate()
                 .eq(InsReport::getId, reportId)
                 .set(InsReport::getWriteTime, report.getWriteTime())
+                .set(InsReport::getIsPass, report.getIsPass())
                 .set(InsReport::getTempUrlPdf, "/word/" + tempPdfName));
     }
 
@@ -3535,7 +3540,7 @@
         String insTime = formatReportTestDate(detectionDates);
         String insTimeEn = formatReportTestDateEn(detectionDates, monthNames);
 
-        // 妫�楠岀幆澧冿細浼樺厛姹囨�诲悇妯℃澘濉啓鐨勬俯婀垮害锛屾姤鍛婂睍绀哄叏閮ㄦā鏉跨殑鏈�灏忓�煎埌鏈�澶у�笺��
+        // 妫�楠岀幆澧冿細浼樺厛姹囨�诲悇妯℃澘濉啓鐨勬俯搴︼紝鎶ュ憡灞曠ず鍏ㄩ儴妯℃澘鐨勬渶灏忓�煎埌鏈�澶у�笺��
         String environment = buildReportEnvironment(orderId, insOrder);
         String finalEnvironment = environment;
         LocalDateTime finalSendTime = sendTime;
@@ -3619,6 +3624,7 @@
         String finalResultRemark = resultRemark;
         String equipmentText = buildEquipmentText(finalDeviceList);
         String issueDate = now.format(DateTimeFormatter.ofPattern("yyyy骞碝M鏈坉d鏃�"));
+        String conclusionDate = now.format(DateTimeFormatter.ofPattern("yyyy 骞� MM 鏈� dd 鏃�"));
         String finalReportModelStr = finalModelStr;
         LocalDateTime finalReportSendTime = finalSendTime;
         XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(
@@ -3662,6 +3668,7 @@
                     put("customer", finalCustomerName);
                     put("category", finalDetectionCategory);
                     put("date", issueDate);
+                    put("conclusionDate", conclusionDate);
                     put("maker", defaultReportText(insOrder.getProduction(), "/"));
                     put("env", finalEnvironment);
                     put("qty", defaultReportText(insOrder.getTestQuantity(), "/"));
@@ -3891,12 +3898,18 @@
         for (Map<String, String> device : deviceList) {
             String name = getMapText(device, "deviceName", "device_name");
             String managementNumber = getMapText(device, "managementNumber", "management_number");
+            String factoryNo = getMapText(device, "factoryNo", "factory_no");
             if (StringUtils.isBlank(name) || "/".equals(name.trim())) {
                 continue;
             }
-            String number = StringUtils.isBlank(managementNumber) || "/".equals(managementNumber.trim())
-                    ? "鍑哄巶缂栧彿" : managementNumber.trim();
-            String item = name.trim() + "锛�" + number;
+            String number = managementNumber;
+            if (StringUtils.isBlank(number) || "/".equals(number.trim())) {
+                number = factoryNo;
+            }
+            if (StringUtils.isBlank(number) || "/".equals(number.trim())) {
+                continue;
+            }
+            String item = name.trim() + "锛�" + number.trim();
             equipmentItems.add(item);
         }
         if (equipmentItems.isEmpty()) {
@@ -3915,22 +3928,12 @@
         List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateService.list(
                 Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                         .eq(InsOrderStandardTemplate::getInsOrderId, orderId)
-                        .select(InsOrderStandardTemplate::getTemperature,
-                                InsOrderStandardTemplate::getHumidity));
+                        .select(InsOrderStandardTemplate::getTemperature));
         List<String> temperatures = snapshots.stream()
                 .map(InsOrderStandardTemplate::getTemperature)
                 .filter(StringUtils::isNotBlank)
                 .collect(Collectors.toList());
-        List<String> humidities = snapshots.stream()
-                .map(InsOrderStandardTemplate::getHumidity)
-                .filter(StringUtils::isNotBlank)
-                .collect(Collectors.toList());
-
-        String temperature = formatConditionRange(temperatures, order.getTemperature(), "鈩�");
-        String humidity = formatConditionRange(humidities, order.getHumidity(), "%RH");
-        return Stream.of(temperature, humidity)
-                .filter(StringUtils::isNotBlank)
-                .collect(Collectors.joining(" "));
+        return formatConditionRange(temperatures, order.getTemperature(), "鈩�");
     }
 
     private static String formatConditionRange(List<String> values, String fallback, String unit) {
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
index e1bc8a1..e999547 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -125,8 +125,32 @@
         }
         // 妫�楠屼腑锛氭柊鑱氫笅鍗曞厤瀹℃牳鍗冲彈鐞嗭紝闇�鏍峰搧鎺ユ敹鎻愪氦鍚庯紙ins_sample_receipt.status=1锛夋墠灞曠ず
         String receiptSubmitted = sampleOrderDto.getState() != null && sampleOrderDto.getState() == 1 ? "1" : null;
-        return insOrderMapper.selectInsOrderPage(page, QueryWrappers.queryWrappers(sampleOrderDto), laboratory,
-                isOrderAll, receiptSubmitted);
+        IPage<SampleOrderDto> result = insOrderMapper.selectInsOrderPage(page,
+                QueryWrappers.queryWrappers(sampleOrderDto), laboratory, isOrderAll, receiptSubmitted);
+        List<Integer> candidateIds = result.getRecords().stream()
+                .filter(row -> Integer.valueOf(-1).equals(row.getTypeSource())
+                        && Integer.valueOf(1).equals(row.getState()))
+                .map(SampleOrderDto::getId)
+                .collect(Collectors.toList());
+        if (!candidateIds.isEmpty()) {
+            Set<Integer> receivedIds = insSampleReceiptMapper.selectList(Wrappers.<InsSampleReceipt>lambdaQuery()
+                            .in(InsSampleReceipt::getInsOrderId, candidateIds)
+                            .eq(InsSampleReceipt::getStatus, 1)
+                            .select(InsSampleReceipt::getInsOrderId)).stream()
+                    .map(InsSampleReceipt::getInsOrderId).collect(Collectors.toSet());
+            Set<Integer> taskIds = insOrderStateService.list(Wrappers.<InsOrderState>lambdaQuery()
+                            .in(InsOrderState::getInsOrderId, candidateIds)
+                            .select(InsOrderState::getInsOrderId)).stream()
+                    .map(InsOrderState::getInsOrderId).collect(Collectors.toSet());
+            Set<Integer> assignedIds = insSampleUserMapper.selectList(Wrappers.<InsSampleUser>lambdaQuery()
+                            .in(InsSampleUser::getInsSampleId, candidateIds)
+                            .select(InsSampleUser::getInsSampleId)).stream()
+                    .map(InsSampleUser::getInsSampleId).collect(Collectors.toSet());
+            result.getRecords().forEach(row -> row.setEditable(
+                    candidateIds.contains(row.getId()) && !receivedIds.contains(row.getId())
+                            && !taskIds.contains(row.getId()) && !assignedIds.contains(row.getId())));
+        }
+        return result;
     }
 
 
@@ -487,6 +511,9 @@
         }
         // 濮旀墭瑕佹眰瀛楁鏍¢獙锛氬洓缁勫崟閫夊繀閫夛紝鍒嗗寘/蹇�掕仈鍔ㄥ繀濉�
         InsOrder reqOrder = dto.getInsOrder();
+        if (reqOrder.getSampleDate() == null) {
+            throw new ErrorException("閫佹牱鏃ユ湡涓嶈兘涓虹┖");
+        }
         if (reqOrder.getSubcontractType() == null || reqOrder.getSampleDisposal() == null
                 || reqOrder.getResultEvaluation() == null || reqOrder.getReportDelivery() == null) {
             throw new ErrorException("璇烽�夋嫨鍒嗗寘鍐呭銆佹牱鍝佸缃�佸缁撴灉璇勪环鍜屾姤鍛婁氦浠樻柟寮�");
@@ -633,6 +660,170 @@
         return order.getId();
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateNewJuInsOrder(InsPlaceOrderDto dto) {
+        if (dto == null || dto.getOrderId() == null || dto.getInsOrder() == null || dto.getStandardTreeId() == null) {
+            throw new ErrorException("涓嬪崟淇℃伅鎴栨爣鍑嗕笉鑳戒负绌�");
+        }
+        InsOrder currentOrder = insOrderMapper.selectById(dto.getOrderId());
+        if (currentOrder == null) {
+            throw new ErrorException("妫�楠屽崟涓嶅瓨鍦�");
+        }
+        if (!Integer.valueOf(1).equals(currentOrder.getState()) || !Integer.valueOf(-1).equals(currentOrder.getTypeSource())) {
+            throw new ErrorException("褰撳墠濮旀墭涓嶅厑璁哥紪杈�");
+        }
+        assertNewJuOrderEditable(dto.getOrderId());
+
+        String sampleCode = StringUtils.trim(dto.getSampleCode());
+        if (StringUtils.isBlank(sampleCode) || sampleCode.length() < 2) {
+            throw new ErrorException("鏍峰搧缂栧彿涓嶈兘涓虹┖涓斾笉鑳藉皯浜�2浣�");
+        }
+        InsOrder order = dto.getInsOrder();
+        if (order.getSampleDate() == null) {
+            throw new ErrorException("閫佹牱鏃ユ湡涓嶈兘涓虹┖");
+        }
+        if (order.getSubcontractType() == null || order.getSampleDisposal() == null
+                || order.getResultEvaluation() == null || order.getReportDelivery() == null) {
+            throw new ErrorException("璇烽�夋嫨鍒嗗寘鍐呭銆佹牱鍝佸缃�佸缁撴灉璇勪环鍜屾姤鍛婁氦浠樻柟寮�");
+        }
+        if (Integer.valueOf(1).equals(order.getSubcontractType()) && StringUtils.isBlank(order.getSubcontractCompany())) {
+            throw new ErrorException("鍒嗗寘鍐呭涓烘湁鏃讹紝鍒嗗寘鍗曚綅淇℃伅涓嶈兘涓虹┖");
+        }
+        if (Integer.valueOf(2).equals(order.getReportDelivery())
+                && (StringUtils.isBlank(order.getReportAddress()) || StringUtils.isBlank(order.getReportReceiver()))) {
+            throw new ErrorException("鎶ュ憡浜や粯鏂瑰紡涓哄揩閫掓椂锛岃濉啓鎶ュ憡瀵勯�佸湴鍧�鍜屾敹浠朵汉鍙婄數璇�");
+        }
+
+        StandardTree standard = standardTreeService.getById(dto.getStandardTreeId());
+        if (standard == null || StringUtils.isBlank(standard.getSample())
+                || standard.getSampleType() != null || standard.getModel() != null) {
+            throw new ErrorException("璇烽�夋嫨鏍囧噯搴撲簩绾ф爣鍑�");
+        }
+        List<StandardTreeTemplateBindingVo> bindings = standardTreeService.selectTemplateBindings(dto.getStandardTreeId());
+        if (bindings.isEmpty()) {
+            throw new ErrorException("璇ユ爣鍑嗗皻鏈粦瀹氬彲鐢ㄧ殑鍘熷璁板綍妯℃澘");
+        }
+        Map<Integer, StandardTreeTemplateBindingVo> bindingMap = bindings.stream()
+                .collect(Collectors.toMap(StandardTreeTemplateBindingVo::getTemplateId, binding -> binding, (first, ignored) -> first));
+        List<OrderTemplateSelectionDto> selections = dto.getTemplateList();
+        if (selections == null) {
+            selections = bindings.stream().map(binding -> {
+                OrderTemplateSelectionDto selection = new OrderTemplateSelectionDto();
+                selection.setTemplateId(binding.getTemplateId());
+                selection.setSort(binding.getSort());
+                return selection;
+            }).collect(Collectors.toList());
+        }
+        if (selections.isEmpty()) {
+            throw new ErrorException("璇疯嚦灏戜繚鐣欎竴涓師濮嬭褰曟ā鏉�");
+        }
+        Set<Integer> selectedTemplateIds = new HashSet<>();
+        for (int index = 0; index < selections.size(); index++) {
+            OrderTemplateSelectionDto selection = selections.get(index);
+            if (selection == null || selection.getTemplateId() == null || !bindingMap.containsKey(selection.getTemplateId())) {
+                throw new ErrorException("鎵�閫夊師濮嬭褰曟ā鏉夸笉灞炰簬褰撳墠鏍囧噯");
+            }
+            if (!selectedTemplateIds.add(selection.getTemplateId())) {
+                throw new ErrorException("鍘熷璁板綍妯℃澘涓嶈兘閲嶅閫夋嫨");
+            }
+            if (selection.getSort() == null) {
+                selection.setSort(index);
+            }
+        }
+        selections.sort(Comparator.comparing(OrderTemplateSelectionDto::getSort)
+                .thenComparing(OrderTemplateSelectionDto::getTemplateId));
+        Map<Integer, Integer> templateSortMap = selections.stream().collect(Collectors.toMap(
+                OrderTemplateSelectionDto::getTemplateId, OrderTemplateSelectionDto::getSort));
+        List<TemplateInspectionItemDto> templateItems = standardTreeService.selectTemplateInspectionItems(dto.getStandardTreeId()).stream()
+                .filter(item -> selectedTemplateIds.contains(item.getTemplateId()))
+                .sorted(Comparator.comparing((TemplateInspectionItemDto item) -> templateSortMap.get(item.getTemplateId()))
+                        .thenComparing(item -> item.getTemplateRowIndex() == null ? Integer.MAX_VALUE : item.getTemplateRowIndex()))
+                .collect(Collectors.toList());
+        StandardMethod standardMethod = standardMethodService.getById(standard.getStandardMethodId());
+        if (standardMethod == null || StringUtils.isBlank(standardMethod.getCode())) {
+            throw new ErrorException("鏍囧噯缂栧彿涓嶅瓨鍦�");
+        }
+        String standardCode = standardMethod.getCode().trim();
+
+        order.setId(currentOrder.getId());
+        order.setState(currentOrder.getState());
+        order.setInsState(currentOrder.getInsState());
+        order.setExamineTime(currentOrder.getExamineTime());
+        order.setSendTime(currentOrder.getSendTime());
+        order.setIsExemption(currentOrder.getIsExemption());
+        order.setFactory(null);
+        order.setLaboratory(standard.getLaboratory());
+        order.setSampleType(null);
+        order.setSample(standardCode);
+        order.setPrepareUserEn(null);
+        order.setPrepareCode(null);
+        order.setRemarkEn(null);
+        order.setTemperature(null);
+        order.setHumidity(null);
+        if (!Integer.valueOf(1).equals(order.getSubcontractType())) {
+            order.setSubcontractCompany(null);
+        }
+        if (!Integer.valueOf(2).equals(order.getReportDelivery())) {
+            order.setReportAddress(null);
+            order.setReportReceiver(null);
+        }
+        insOrderMapper.updateById(order);
+
+        List<InsSample> samples = insSampleMapper.selectList(Wrappers.<InsSample>lambdaQuery()
+                .eq(InsSample::getInsOrderId, currentOrder.getId()).orderByAsc(InsSample::getId));
+        if (samples.size() != 1) {
+            throw new ErrorException("妫�楠屾牱鍝佹暟鎹紓甯�");
+        }
+        InsSample sample = samples.get(0);
+        sample.setSampleCode(sampleCode);
+        sample.setLaboratory(standard.getLaboratory());
+        sample.setSampleType(null);
+        sample.setSample(standardCode);
+        sample.setModel(null);
+        insSampleMapper.updateById(sample);
+        insProductMapper.delete(Wrappers.<InsProduct>lambdaQuery().eq(InsProduct::getInsSampleId, sample.getId()));
+        insOrderStandardTemplateMapper.delete(Wrappers.<InsOrderStandardTemplate>lambdaQuery()
+                .eq(InsOrderStandardTemplate::getInsOrderId, currentOrder.getId()));
+        insOrderTemplateDeviceMapper.delete(Wrappers.<InsOrderTemplateDevice>lambdaQuery()
+                .eq(InsOrderTemplateDevice::getInsOrderId, currentOrder.getId()));
+        int productSort = 0;
+        for (TemplateInspectionItemDto item : templateItems) {
+            InsProduct product = new InsProduct();
+            product.setInsSampleId(sample.getId());
+            product.setInspectionItem(item.getInspectionItem());
+            product.setInspectionItemClass("");
+            product.setInspectionItemSubclass("");
+            product.setLaboratory(standard.getLaboratory());
+            product.setSample(standardCode);
+            product.setTemplateId(item.getTemplateId());
+            product.setTemplateRowIndex(item.getTemplateRowIndex());
+            product.setSonLaboratory(DIRECT_TEMPLATE_LABORATORY);
+            product.setState(1);
+            product.setSort(productSort++);
+            insProductMapper.insert(product);
+        }
+        saveTemplateSnapshots(currentOrder.getId(), selections, bindingMap);
+        String entrustCode = buildEntrustCode(order, Collections.singletonList(sample));
+        assertEntrustCodeUnique(entrustCode, currentOrder.getId());
+        insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate().eq(InsOrder::getId, currentOrder.getId())
+                .set(InsOrder::getEntrustCode, entrustCode));
+        applicationEventPublisher.publishEvent(new com.ruoyi.inspect.event.NewJuOrderPlacedEvent(currentOrder.getId()));
+        return currentOrder.getId();
+    }
+
+    private void assertNewJuOrderEditable(Integer orderId) {
+        Long receiptCount = insSampleReceiptMapper.selectCount(Wrappers.<InsSampleReceipt>lambdaQuery()
+                .eq(InsSampleReceipt::getInsOrderId, orderId).eq(InsSampleReceipt::getStatus, 1));
+        Long taskCount = insOrderStateService.count(Wrappers.<InsOrderState>lambdaQuery()
+                .eq(InsOrderState::getInsOrderId, orderId));
+        Long userCount = insSampleUserMapper.selectCount(Wrappers.<InsSampleUser>lambdaQuery()
+                .eq(InsSampleUser::getInsSampleId, orderId));
+        if (receiptCount > 0 || taskCount > 0 || userCount > 0) {
+            throw new ErrorException("璇ュ鎵樺凡杩涘叆妫�楠岋紝涓嶈兘缂栬緫");
+        }
+    }
+
     private void saveTemplateSnapshots(Integer orderId, List<OrderTemplateSelectionDto> selections,
                                        Map<Integer, StandardTreeTemplateBindingVo> bindingMap) {
         for (OrderTemplateSelectionDto selection : selections) {
@@ -732,6 +923,36 @@
         map.put("sampleCode", orderSamples.isEmpty() ? null : orderSamples.get(0).getSampleCode());
         map.put("insOrderTemplate", map1);
         map.put("templateList", templateList);
+        Set<Integer> orderTemplateIds = templateList.stream()
+                .map(OrderTemplateSummaryVo::getTemplateId).collect(Collectors.toSet());
+        List<Integer> methodIds = standardMethodService.list(Wrappers.<StandardMethod>lambdaQuery()
+                        .eq(StandardMethod::getCode, insOrder.getSample())
+                        .select(StandardMethod::getId)).stream()
+                .map(StandardMethod::getId).collect(Collectors.toList());
+        if (!methodIds.isEmpty() && !orderTemplateIds.isEmpty()) {
+            List<StandardTree> candidates = standardTreeService.list(Wrappers.<StandardTree>lambdaQuery()
+                    .in(StandardTree::getStandardMethodId, methodIds)
+                    .isNull(StandardTree::getSampleType)
+                    .isNull(StandardTree::getModel));
+            Map<StandardTree, Set<Integer>> matches = candidates.stream()
+                    .filter(tree -> StringUtils.isNotBlank(tree.getSample())
+                            && Objects.equals(tree.getLaboratory(), insOrder.getLaboratory()))
+                    .collect(Collectors.toMap(tree -> tree,
+                            tree -> standardTreeService.selectTemplateBindings(tree.getId()).stream()
+                                    .map(StandardTreeTemplateBindingVo::getTemplateId)
+                                    .collect(Collectors.toSet())));
+            matches.entrySet().removeIf(entry -> !entry.getValue().containsAll(orderTemplateIds));
+            if (matches.size() == 1) {
+                map.put("standardTreeId", matches.keySet().iterator().next().getId());
+            } else if (matches.size() > 1) {
+                List<StandardTree> exactMatches = matches.entrySet().stream()
+                        .filter(entry -> entry.getValue().equals(orderTemplateIds))
+                        .map(Map.Entry::getKey).collect(Collectors.toList());
+                if (exactMatches.size() == 1) {
+                    map.put("standardTreeId", exactMatches.get(0).getId());
+                }
+            }
+        }
         return map;
     }
 
@@ -850,7 +1071,6 @@
                                 .eq(InsOrderStandardTemplate::getInsOrderId, id)
                                 .select(InsOrderStandardTemplate::getTemplateId,
                                         InsOrderStandardTemplate::getTemperature,
-                                        InsOrderStandardTemplate::getHumidity,
                                         InsOrderStandardTemplate::getDetectionTime,
                                         InsOrderStandardTemplate::getDetectionPlace,
                                         InsOrderStandardTemplate::getInsResult)
@@ -860,7 +1080,6 @@
                     TemplateConditionVo condition = new TemplateConditionVo();
                     condition.setTemplateId(snapshot.getTemplateId());
                     condition.setTemperature(snapshot.getTemperature());
-                    condition.setHumidity(snapshot.getHumidity());
                     condition.setDetectionTime(snapshot.getDetectionTime());
                     condition.setDetectionPlace(snapshot.getDetectionPlace());
                     condition.setInsResult(snapshot.getInsResult());
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java
index b5d0e0f..8f642dc 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsProductServiceImpl.java
@@ -77,8 +77,8 @@
             if (snapshot == null) {
                 throw new ErrorException("鏈壘鍒板綋鍓嶆ā鏉跨殑鍘熷璁板綍蹇収");
             }
-            boolean hasSnapshotField = dto.isTemperaturePresent() || dto.isHumidityPresent()
-                    || dto.isDetectionTimePresent() || dto.isDetectionPlacePresent()
+            boolean hasSnapshotField = dto.isTemperaturePresent() || dto.isDetectionTimePresent()
+                    || dto.isDetectionPlacePresent()
                     || dto.isInsResultPresent();
             if (hasSnapshotField) {
                 insOrderStandardTemplateMapper.update(null,
@@ -86,8 +86,6 @@
                                 .eq(InsOrderStandardTemplate::getId, snapshot.getId())
                                 .set(dto.isTemperaturePresent(),
                                         InsOrderStandardTemplate::getTemperature, dto.getTemperature())
-                                .set(dto.isHumidityPresent(),
-                                        InsOrderStandardTemplate::getHumidity, dto.getHumidity())
                                 .set(dto.isDetectionTimePresent(),
                                         InsOrderStandardTemplate::getDetectionTime, dto.getDetectionTime())
                                 .set(dto.isDetectionPlacePresent(),
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
index 5333df2..4ae8fce 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
@@ -19,6 +19,8 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.deepoove.poi.XWPFTemplate;
 import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.data.PictureRenderData;
+import com.deepoove.poi.data.PictureType;
 import com.deepoove.poi.data.Pictures;
 import com.itextpdf.text.BadElementException;
 import com.itextpdf.text.DocumentException;
@@ -26,7 +28,9 @@
 import com.itextpdf.text.pdf.PdfReader;
 import com.itextpdf.text.pdf.PdfStamper;
 import com.ruoyi.basic.mapper.IfsInventoryQuantityMapper;
+import com.ruoyi.basic.mapper.SealConfigMapper;
 import com.ruoyi.basic.pojo.IfsInventoryQuantity;
+import com.ruoyi.basic.pojo.SealConfig;
 import com.ruoyi.basic.vo.IfsInventoryQuantityVO;
 import com.ruoyi.common.config.WechatProperty;
 import com.ruoyi.common.constant.InsOrderTypeConstants;
@@ -47,6 +51,7 @@
 import com.ruoyi.inspect.service.InsReportService;
 import com.ruoyi.inspect.service.RawMaterialOrderService;
 import com.ruoyi.inspect.util.PreserveReportPicturePlaceholderHandler;
+import com.ruoyi.inspect.util.ReportSealLayoutUtil;
 import com.ruoyi.inspect.util.ReportSignaturePictureUtils;
 import com.ruoyi.system.mapper.UserMapper;
 import com.ruoyi.system.service.InformationNotificationService;
@@ -116,6 +121,8 @@
     private InsOrderMapper insOrderMapper;
     @Resource
     private IfsInventoryQuantityMapper ifsInventoryQuantityMapper;
+    @Resource
+    private SealConfigMapper sealConfigMapper;
     @Resource
     private InsUnqualifiedHandlerMapper insUnqualifiedHandlerMapper;
     @Resource
@@ -397,7 +404,8 @@
     //鎵瑰噯
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public int ratifyReport(Integer id, Integer isRatify, String ratifyTell) {
+    public int ratifyReport(Integer id, Integer isRatify, String ratifyTell, String sealIds,
+                            Integer maSealId, Integer reportSealId, Integer seamSealId) {
         InsReport insReport = insReportMapper.selectById(id);
         if (Objects.equals(insReport.getExamineUserId(), SecurityUtils.getUserId().intValue())) {
             throw new ErrorException("瀹℃牳浜哄拰鎵瑰噯浜轰笉鑳戒负鍚屼竴浜猴紝璇烽噸鏂伴�夋嫨鎵瑰噯浜�");
@@ -471,33 +479,64 @@
         InsOrder order = insOrderMapper.selectById(insOrderId);
         boolean isRawMater = order.getTypeSource() != null && order.getTypeSource().equals(1);
 
-        //鑾峰彇鍦烘墍鐨勬姤鍛婁笓鐢ㄧ珷
-        String sealUrl;
-        String laboratory = insOrderMapper.selectById(insReport.getInsOrderId()).getLaboratory();
-        try {
-            String type = "";
-            if (isRawMater && order.getOrderType().equals(InsOrderTypeConstants.ENTER_THE_FACTORY)) {
-                type = "杩涘巶鎶ュ憡";
-            } else {
-                type = "濮旀墭鎶ュ憡";
-            }
-            sealUrl = insReportMapper.getLaboratoryByName(laboratory, type);
-        } catch (Exception e) {
-            throw new ErrorException(laboratory + "鎵句笉鍒版姤鍛婁笓鐢ㄧ珷");
+        // 鏂扮増鎸夌敤閫旈�夋嫨锛歁A绔犮�佹姤鍛婄珷锛堟ā鏉� seal1/seal2锛夈�丳DF楠戠紳绔犮��
+        // 鍏煎鏃у墠绔細鍙紶 sealIds 鏃讹紝绗竴鏋氱珷缁х画浣滀负鎶ュ憡绔犲拰楠戠紳绔狅紝MA绔犵暀绌恒��
+        SealConfig maSeal;
+        SealConfig reportSeal;
+        SealConfig seamSeal;
+        boolean positionMode = maSealId != null || reportSealId != null || seamSealId != null;
+        if (positionMode) {
+            maSeal = resolveSeal(maSealId);
+            reportSeal = resolveSeal(reportSealId);
+            seamSeal = resolveSeal(seamSealId);
+        } else {
+            SealConfig legacySeal = resolveSeals(sealIds).get(0);
+            maSeal = null;
+            reportSeal = legacySeal;
+            seamSeal = legacySeal;
         }
-        if (StringUtils.isBlank(sealUrl)) {
-            throw new ErrorException(laboratory + "鎵句笉鍒版姤鍛婁笓鐢ㄧ珷");
+
+        LinkedHashMap<Integer, SealConfig> chosenById = new LinkedHashMap<>();
+        Arrays.asList(maSeal, reportSeal, seamSeal).stream()
+                .filter(Objects::nonNull)
+                .forEach(seal -> chosenById.put(seal.getId(), seal));
+        List<SealConfig> chosenSeals = new ArrayList<>(chosenById.values());
+        if (chosenSeals.isEmpty()) {
+            throw new ErrorException("璇疯嚦灏戦�夋嫨涓�绉嶆姤鍛婂嵃绔�");
         }
+
+        insReport.setSealIds(chosenSeals.stream().map(s -> String.valueOf(s.getId())).collect(Collectors.joining(",")));
+        insReport.setSealNames(chosenSeals.stream().map(SealConfig::getName).collect(Collectors.joining(",")));
+        insReport.setMaSealId(maSeal == null ? null : maSeal.getId());
+        insReport.setMaSealName(maSeal == null ? null : maSeal.getName());
+        insReport.setReportSealId(reportSeal == null ? null : reportSeal.getId());
+        insReport.setReportSealName(reportSeal == null ? null : reportSeal.getName());
+        insReport.setSeamSealId(seamSeal == null ? null : seamSeal.getId());
+        insReport.setSeamSealName(seamSeal == null ? null : seamSeal.getName());
         String primaryReportUrl = getPrimaryReportUrl(insReport);
         String finalUrl = primaryReportUrl.replace("/word", wordUrl);
 
-        Map<String, Object> ratifyMarks = new HashMap<String, Object>() {{
-            put("ratifyUrl", ReportSignaturePictureUtils.create(imgUrl, signatureUrl));
-            put("ratifyDateUrl", Pictures.ofStream(DateImageUtil.createDateImage(null)).create());
-            put("seal1", Pictures.ofLocal(imgUrl + "/" + sealUrl).create());
-            put("seal2", Pictures.ofLocal(imgUrl + "/" + sealUrl).create());
-        }};
-        writeMarksToReportFiles(insReport, ratifyMarks);
+        Map<String, Object> ratifyMarks = new HashMap<>();
+        ratifyMarks.put("ratifyUrl", ReportSignaturePictureUtils.create(imgUrl, signatureUrl));
+        ratifyMarks.put("ratifyDateUrl", Pictures.ofStream(DateImageUtil.createDateImage(null)).create());
+        if (reportSeal != null) {
+            ratifyMarks.put("seal1", createSealPicture(reportSeal.getAddress()));
+            ratifyMarks.put("seal2", createSealPicture(reportSeal.getAddress()));
+        }
+        writeApprovalMarksToReportFiles(insReport, ratifyMarks);
+
+        // 鍗扮珷蹇呴』浣跨敤娴姩瀹氫綅锛屽惁鍒欒鍐呭浘鐗囦細鎾戦珮娈佃惤/琛ㄦ牸骞舵敼鍙樺師鎶ュ憡鍒嗛〉銆�
+        for (String reportUrl : getApprovalReportUrls(insReport)) {
+            try {
+                ReportSealLayoutUtil.apply(
+                        reportUrl.replace("/word", wordUrl),
+                        reportSeal == null ? null : Paths.get(imgUrl, reportSeal.getAddress()).toString(),
+                        maSeal == null ? null : Paths.get(imgUrl, maSeal.getAddress()).toString());
+            } catch (Exception e) {
+                log.error("鎶ュ憡鍗扮珷娴姩瀹氫綅澶辫触: {}", reportUrl, e);
+                throw new ErrorException("鎶ュ憡鐩栫珷澶辫触锛岃妫�鏌ュ嵃绔犲浘鐗囧拰鎶ュ憡鏂囦欢");
+            }
+        }
 
         // 淇敼涓存椂pdf
         insReport.setTempUrlPdf(primaryReportUrl.replace(".docx", ".pdf"));
@@ -508,7 +547,9 @@
         insOrderMapper.updateById(insOrder);
 
         for (String reportUrl : getApprovalReportUrls(insReport)) {
-            wordToPdf(reportUrl.replace("/word", wordUrl), sealUrl,
+            wordToPdf(reportUrl.replace("/word", wordUrl),
+                    null,
+                    seamSeal == null ? null : seamSeal.getAddress(),
                     isRawMater && order.getOrderType().equals(InsOrderTypeConstants.ENTER_THE_FACTORY));
         }
 
@@ -539,10 +580,97 @@
         return insReportMapper.updateById(insReport);
     }
 
+    /**
+     * 瑙f瀽鎵瑰噯鏃堕�夋嫨鐨勫嵃绔狅紙閫楀彿鍒嗛殧鐨勫嵃绔爄d锛夈��
+     * 鏈紶鎴栧叏閮ㄦ棤鏁堟椂鍥為��鍒扮涓�涓惎鐢ㄥ嵃绔狅紙榛樿鈥�1鍙风珷鈥濓級銆�
+     */
+    private List<SealConfig> resolveSeals(String sealIds) {
+        List<SealConfig> chosen = new ArrayList<>();
+        if (StringUtils.isNotBlank(sealIds)) {
+            List<Integer> ids = new ArrayList<>();
+            for (String s : sealIds.split(",")) {
+                if (StringUtils.isNotBlank(s)) {
+                    ids.add(Integer.valueOf(s.trim()));
+                }
+            }
+            if (!ids.isEmpty()) {
+                Map<Integer, SealConfig> byId = sealConfigMapper.selectBatchIds(ids).stream()
+                        .collect(Collectors.toMap(SealConfig::getId, x -> x));
+                for (Integer sid : ids) {
+                    SealConfig seal = byId.get(sid);
+                    if (seal != null && Objects.equals(seal.getStatus(), 1)
+                            && StringUtils.isNotBlank(seal.getAddress())) {
+                        chosen.add(seal);
+                    }
+                }
+            }
+        }
+        if (chosen.isEmpty()) {
+            List<SealConfig> enabled = sealConfigMapper.selectList(Wrappers.<SealConfig>lambdaQuery()
+                    .eq(SealConfig::getStatus, 1).orderByAsc(SealConfig::getCode));
+            if (!enabled.isEmpty()) {
+                chosen.add(enabled.get(0));
+            }
+        }
+        if (chosen.isEmpty()) {
+            throw new ErrorException("鏈壘鍒板彲鐢ㄥ嵃绔狅紝璇峰厛鍦ㄥ嵃绔犵鐞嗕腑缁存姢骞跺惎鐢ㄥ嵃绔�");
+        }
+        return chosen;
+    }
+
+    private SealConfig resolveSeal(Integer sealId) {
+        if (sealId == null) {
+            return null;
+        }
+        SealConfig seal = sealConfigMapper.selectById(sealId);
+        if (seal == null) {
+            throw new ErrorException("鎵�閫夊嵃绔犱笉瀛樺湪锛岃閲嶆柊閫夋嫨");
+        }
+        if (!Objects.equals(seal.getStatus(), 1)) {
+            throw new ErrorException("鍗扮珷鈥�" + seal.getName() + "鈥濆凡鍋滅敤锛岃閲嶆柊閫夋嫨");
+        }
+        if (StringUtils.isBlank(seal.getAddress())) {
+            throw new ErrorException("鍗扮珷鈥�" + seal.getName() + "鈥濇湭涓婁紶鍥剧墖锛岃閲嶆柊閫夋嫨");
+        }
+        return seal;
+    }
+
+    /**
+     * 鎸夊浘鐗囧唴瀹硅瘑鍒嵃绔犳牸寮忥紝鍏煎鍘嗗彶鏁版嵁涓墿灞曞悕琚繚瀛樹负鈥淿png鈥濈瓑闈炴爣鍑嗘枃浠跺悕鐨勬儏鍐点��
+     */
+    private PictureRenderData createSealPicture(String sealUrl) {
+        Path sealPath = Paths.get(imgUrl, sealUrl);
+        if (!Files.isRegularFile(sealPath)) {
+            throw new ErrorException("鍗扮珷鍥剧墖鏂囦欢涓嶅瓨鍦紝璇烽噸鏂颁笂浼犲嵃绔犲浘鐗�");
+        }
+        try {
+            byte[] imageBytes = Files.readAllBytes(sealPath);
+            PictureType pictureType = PictureType.suggestFileType(imageBytes);
+            return Pictures.ofBytes(imageBytes, pictureType).create();
+        } catch (Exception e) {
+            log.error("璇诲彇鍗扮珷鍥剧墖澶辫触: {}", sealPath, e);
+            throw new ErrorException("鍗扮珷鍥剧墖鏃犳硶璇嗗埆锛岃閲嶆柊涓婁紶 jpg 鎴� png 鍥剧墖");
+        }
+    }
+
     @Override
     public int wordInsertUrl(Map<String, Object> map, String url) {
         Configure configure = Configure.builder()
                 .setValidErrorHandler(new PreserveReportPicturePlaceholderHandler())
+                .build();
+        XWPFTemplate template = XWPFTemplate.compile(url, configure).render(map);
+        try {
+            template.writeAndClose(Files.newOutputStream(Paths.get(url)));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return 1;
+    }
+
+    private int wordInsertApprovalMarks(Map<String, Object> map, String url) {
+        Configure configure = Configure.builder()
+                .setValidErrorHandler(new PreserveReportPicturePlaceholderHandler(
+                        new HashSet<>(Arrays.asList("seal1", "seal2"))))
                 .build();
         XWPFTemplate template = XWPFTemplate.compile(url, configure).render(map);
         try {
@@ -571,6 +699,12 @@
     private void writeMarksToReportFiles(InsReport report, Map<String, Object> marks) {
         for (String reportUrl : getApprovalReportUrls(report)) {
             wordInsertUrl(marks, reportUrl.replace("/word", wordUrl));
+        }
+    }
+
+    private void writeApprovalMarksToReportFiles(InsReport report, Map<String, Object> marks) {
+        for (String reportUrl : getApprovalReportUrls(report)) {
+            wordInsertApprovalMarks(marks, reportUrl.replace("/word", wordUrl));
         }
     }
 
@@ -775,16 +909,17 @@
     }
 
     @Override
-    public void wordToPdf(String path, String sealUrl, boolean isRawMater) {
+    public void wordToPdf(String path, String maSealUrl, String seamSealUrl, boolean isRawMater) {
         try {
-            wordToPdf(path, path.replace(".docx", ".pdf"), sealUrl, isRawMater);
+            wordToPdf(path, path.replace(".docx", ".pdf"), maSealUrl, seamSealUrl, isRawMater);
         } catch (Exception e) {
             throw new ErrorException("杞崲澶辫触");
         }
     }
 
 
-    public String wordToPdf(String wordPath, String pdfPath, String sealUrl, boolean isRawMater) {
+    public String wordToPdf(String wordPath, String pdfPath, String maSealUrl,
+                            String seamSealUrl, boolean isRawMater) {
         FileOutputStream os = null;
         try {
             //鍑瘉 涓嶇劧鍒囨崲鍚庢湁姘村嵃
@@ -795,27 +930,31 @@
                 log.info("License楠岃瘉涓嶉�氳繃...");
                 return null;
             }
-            //鐢熸垚涓�涓┖鐨凱DF鏂囦欢
-            File file;
-            //鍒ゆ柇鏄惁鏄繘鍘傛姤鍛�
-            if (!isRawMater) {
-                file = new File(pdfPath.replace(".pdf", "-1.pdf"));
-            } else {
-                file = new File(pdfPath.replace(".pdf", ".pdf"));
-            }
+            String effectiveSeamSealUrl = isRawMater ? null : seamSealUrl;
+            boolean addPdfMarks = StringUtils.isNotBlank(maSealUrl)
+                    || StringUtils.isNotBlank(effectiveSeamSealUrl);
+            String sourcePdfPath = addPdfMarks ? pdfPath.replace(".pdf", "-stamp-source.pdf") : pdfPath;
+            File file = new File(sourcePdfPath);
             os = new FileOutputStream(file);
             //瑕佽浆鎹㈢殑word鏂囦欢
             com.aspose.words.Document doc = new com.aspose.words.Document(wordPath);
             doc.save(os, SaveFormat.PDF);
+            os.close();
+            os = null;
 
-            //娣诲姞楠戠紳绔�
-            if (!isRawMater) {
-                stamperCheckMarkPDF(pdfPath.replace(".pdf", "-1.pdf"), pdfPath, imgUrl + "/" + sealUrl);
+            // MA绔犲浐瀹氬湪绗�1椤靛乏涓婅锛涢獞缂濈珷鎸夐〉鍒囩墖鍥哄畾鍦ㄥ彸渚т腑閮ㄣ��
+            if (addPdfMarks) {
+                stamperReportMarksPDF(
+                        sourcePdfPath,
+                        pdfPath,
+                        StringUtils.isBlank(maSealUrl) ? null : Paths.get(imgUrl, maSealUrl).toString(),
+                        StringUtils.isBlank(effectiveSeamSealUrl)
+                                ? null : Paths.get(imgUrl, effectiveSeamSealUrl).toString());
             }
-
-
+            return new File(pdfPath).getName();
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("鐢熸垚鐩栫珷PDF澶辫触: {}", wordPath, e);
+            throw new ErrorException("鎶ュ憡杞琍DF鎴栫洊绔犲け璐�");
         } finally {
             if (os != null) {
                 try {
@@ -825,7 +964,6 @@
                 }
             }
         }
-        return null;
     }
 
     /**
@@ -850,7 +988,8 @@
                 subImg = img.getSubimage(i * sw, 0, sw, h);
             }
             ByteArrayOutputStream out = new ByteArrayOutputStream();
-            ImageIO.write(subImg, Path.substring(Path.lastIndexOf('.') + 1), out);
+            // 缁熶竴缂栫爜涓� PNG锛屽吋瀹瑰巻鍙测�淿png鈥濈瓑娌℃湁鏍囧噯鎵╁睍鍚嶇殑鍥剧墖鏂囦欢銆�
+            ImageIO.write(subImg, "png", out);
             nImage[i] = com.itextpdf.text.Image.getInstance(out.toByteArray());
 
         }
@@ -858,33 +997,46 @@
     }
 
     /**
-     * 鐩栭獞缂濈珷
+     * 鎸夊弬鑰冩姤鍛婄洊 PDF 鏍囧織绔狅細MA绔犱綅浜庣1椤靛乏涓婅锛岄獞缂濈珷浣嶄簬姣忛〉鍙充晶涓儴銆�
      *
      * @param infilePath  鍘烶DF璺緞
      * @param outFilePath 杈撳嚭PDF璺緞
      */
-    public static void stamperCheckMarkPDF(String infilePath, String outFilePath, String picPath) throws IOException, DocumentException {
+    public static void stamperReportMarksPDF(String infilePath, String outFilePath,
+                                             String maPicPath, String seamPicPath)
+            throws IOException, DocumentException {
         PdfReader reader = new PdfReader(infilePath);//閫夋嫨闇�瑕佸嵃绔犵殑pdf
         PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(outFilePath));//鍔犲畬鍗扮珷鍚庣殑pdf
 
-
-        com.itextpdf.text.Rectangle pageSize = reader.getPageSize(1);//鑾峰緱绗竴椤�
-        float height = pageSize.getHeight();
-        float width = pageSize.getWidth();
-
         int nums = reader.getNumberOfPages();
-        com.itextpdf.text.Image[] nImage = slicingImages(picPath, nums);//鐢熸垚楠戠紳绔犲垏鍓插浘鐗�
+        boolean hasMaSeal = maPicPath != null && !maPicPath.trim().isEmpty();
+        boolean hasSeamSeal = seamPicPath != null && !seamPicPath.trim().isEmpty();
+        com.itextpdf.text.Image[] seamImages = hasSeamSeal ? slicingImages(seamPicPath, nums) : null;
 
         for (int n = 1; n <= nums; n++) {
+            com.itextpdf.text.Rectangle pageSize = reader.getPageSize(n);
+            float height = pageSize.getHeight();
+            float width = pageSize.getWidth();
             PdfContentByte over = stamp.getOverContent(n);//璁剧疆鍦ㄧ鍑犻〉鎵撳嵃鍗扮珷
-            com.itextpdf.text.Image img = nImage[n - 1];//閫夋嫨鍥剧墖
-            float newHeight = 100f;
-            float newWidth = img.getWidth() / (img.getHeight() / 100);
-            img.scaleAbsolute(newWidth, newHeight);//鎺у埗鍥剧墖澶у皬
-            img.setAbsolutePosition(width - newWidth, height / 2 - newHeight / 2);//鎺у埗鍥剧墖浣嶇疆
-            over.addImage(img);
+
+            if (n == 1 && hasMaSeal) {
+                com.itextpdf.text.Image maImage = com.itextpdf.text.Image.getInstance(maPicPath);
+                maImage.scaleToFit(100f, 90f);
+                maImage.setAbsolutePosition(30f, height - maImage.getScaledHeight() - 30f);
+                over.addImage(maImage);
+            }
+
+            if (hasSeamSeal) {
+                com.itextpdf.text.Image seamImage = seamImages[n - 1];
+                float newHeight = 100f;
+                float newWidth = seamImage.getWidth() / (seamImage.getHeight() / newHeight);
+                seamImage.scaleAbsolute(newWidth, newHeight);
+                seamImage.setAbsolutePosition(width - newWidth, height / 2 - newHeight / 2);
+                over.addImage(seamImage);
+            }
         }
         stamp.close();
+        reader.close();
     }
 
     @Override
@@ -1018,20 +1170,22 @@
     @Transactional(rollbackFor = Exception.class)
     public boolean sendBackTask(Integer id) {
         InsReport report = insReportMapper.selectById(id);
-        // 鏍规嵁璁㈠崟鏌ヨ璇曢獙瀹�
-        String laboratory = insOrderMapper.selectLaboratoryByOrderId(report.getInsOrderId());
+        if (report == null || report.getInsOrderId() == null) {
+            throw new ErrorException("鎶ュ憡涓嶅瓨鍦ㄦ垨鏈叧鑱旀楠屽崟");
+        }
 
-        // 淇敼璁㈠崟鐘舵��
+        // 鎶ュ憡鐢辫鍗曚笅鍚勮瘯楠屽鍏卞悓褰㈡垚锛涢��鍥炴椂鍏ㄩ儴鎭㈠涓哄緟澶嶆牳锛岄伩鍏嶅彧闅忔満閫�鍥炰竴涓瘯楠屽銆�
         insOrderStateMapper.update(null, Wrappers.<InsOrderState>lambdaUpdate()
                 .eq(InsOrderState::getInsOrderId, report.getInsOrderId())
-                .eq(InsOrderState::getLaboratory, laboratory)
                 .set(InsOrderState::getInsState, 4));
 
-        Integer insSampleId = insSampleUserMapper.selectOne(Wrappers.<InsSampleUser>lambdaQuery()
+        InsSampleUser sampleUser = insSampleUserMapper.selectOne(Wrappers.<InsSampleUser>lambdaQuery()
                 .eq(InsSampleUser::getInsSampleId, report.getInsOrderId())
                 .orderByDesc(InsSampleUser::getId)
-                .last("limit 1")).getId();
-        insSampleUserMapper.deleteById(insSampleId);
+                .last("limit 1"));
+        if (sampleUser != null) {
+            insSampleUserMapper.deleteById(sampleUser.getId());
+        }
 
         // 淇敼鎶ュ憡琛屼负鏈樉绀�
         insReportMapper.update(null, Wrappers.<InsReport>lambdaUpdate()
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/util/PreserveReportPicturePlaceholderHandler.java b/inspect-server/src/main/java/com/ruoyi/inspect/util/PreserveReportPicturePlaceholderHandler.java
index 9fb72f7..14b801c 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/util/PreserveReportPicturePlaceholderHandler.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/util/PreserveReportPicturePlaceholderHandler.java
@@ -5,6 +5,7 @@
 import com.deepoove.poi.template.ElementTemplate;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -27,13 +28,23 @@
     ));
 
     private final Configure.ClearHandler clearHandler = new Configure.ClearHandler();
+    private final Set<String> clearPictureTags;
+
+    public PreserveReportPicturePlaceholderHandler() {
+        this(Collections.emptySet());
+    }
+
+    public PreserveReportPicturePlaceholderHandler(Set<String> clearPictureTags) {
+        this.clearPictureTags = clearPictureTags == null ? Collections.emptySet() : clearPictureTags;
+    }
 
     @Override
     public void handler(RenderContext<?> context) {
         ElementTemplate template = context.getEleTemplate();
         if (template != null
                 && Character.valueOf('@').equals(template.getSign())
-                && DEFERRED_PICTURE_TAGS.contains(template.getTagName())) {
+                && DEFERRED_PICTURE_TAGS.contains(template.getTagName())
+                && !clearPictureTags.contains(template.getTagName())) {
             return;
         }
         clearHandler.handler(context);
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java b/inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java
new file mode 100644
index 0000000..9791a1e
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java
@@ -0,0 +1,302 @@
+package com.ruoyi.inspect.util;
+
+import com.aspose.words.Document;
+import com.aspose.words.LayoutCollector;
+import com.aspose.words.LayoutEnumerator;
+import com.aspose.words.License;
+import com.aspose.words.Node;
+import com.aspose.words.NodeCollection;
+import com.aspose.words.NodeType;
+import com.aspose.words.PageSetup;
+import com.aspose.words.Paragraph;
+import com.aspose.words.RelativeHorizontalPosition;
+import com.aspose.words.RelativeVerticalPosition;
+import com.aspose.words.SaveFormat;
+import com.aspose.words.Section;
+import com.aspose.words.Shape;
+import com.aspose.words.ShapeType;
+import com.aspose.words.WrapType;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 灏嗘姤鍛婁腑鐨勫嵃绔犳敼涓烘诞鍔ㄥ浘鐗囷紝閬垮厤鍥剧墖鍙備笌姝f枃琛岄珮璁$畻鑰屾敼鍙樺師鎶ュ憡鍒嗛〉銆�
+ */
+public final class ReportSealLayoutUtil {
+
+    private static final double MA_LEFT = 30D;
+    private static final double MA_TOP = 30D;
+    private static final double MA_MAX_WIDTH = 90D;
+    private static final double MA_MAX_HEIGHT = 80D;
+    private static final double REPORT_MAX_WIDTH = 105D;
+    private static final double REPORT_MAX_HEIGHT = 105D;
+    private static final double LAST_PAGE_MAX_WIDTH = 110D;
+    private static final double LAST_PAGE_MAX_HEIGHT = 110D;
+    private static final double POSITION_GAP = 14D;
+
+    private ReportSealLayoutUtil() {
+    }
+
+    public static void apply(String wordPath, String reportSealPath, String maSealPath) throws Exception {
+        applyAsposeLicense();
+        Document document = new Document(wordPath);
+        byte[] reportSealBytes = readImage(reportSealPath);
+        byte[] maSealBytes = readImage(maSealPath);
+
+        if (reportSealBytes != null) {
+            removeMatchingImages(document, reportSealBytes);
+            document.updatePageLayout();
+            addCoverReportSeal(document, reportSealPath);
+            addConclusionReportSeal(document, reportSealPath);
+            addLastPageReportSeal(document, reportSealPath);
+        }
+        if (maSealBytes != null) {
+            removeMatchingImages(document, maSealBytes);
+            document.updatePageLayout();
+            // reportSeal 涓� maSeal 鍙兘閫夋嫨鍚屼竴寮犲浘鐗囷紝绉婚櫎鍚庨渶瑕佹仮澶嶄笁涓姤鍛婄珷浣嶇疆銆�
+            if (reportSealBytes != null && Arrays.equals(reportSealBytes, maSealBytes)) {
+                addCoverReportSeal(document, reportSealPath);
+                addConclusionReportSeal(document, reportSealPath);
+                addLastPageReportSeal(document, reportSealPath);
+            }
+            addFirstPageMaSeal(document, maSealPath);
+        }
+
+        document.updatePageLayout();
+        document.save(wordPath, SaveFormat.DOCX);
+    }
+
+    private static void applyAsposeLicense() throws Exception {
+        try (InputStream inputStream = ReportSealLayoutUtil.class.getResourceAsStream("/lib/license.xml")) {
+            if (inputStream == null) {
+                throw new IllegalStateException("鏈壘鍒� Aspose 鎺堟潈鏂囦欢");
+            }
+            License license = new License();
+            license.setLicense(inputStream);
+            if (!license.getIsLicensed()) {
+                throw new IllegalStateException("Aspose 鎺堟潈楠岃瘉澶辫触");
+            }
+        }
+    }
+
+    private static byte[] readImage(String imagePath) throws Exception {
+        if (imagePath == null || imagePath.trim().isEmpty()) {
+            return null;
+        }
+        Path path = java.nio.file.Paths.get(imagePath);
+        return Files.isRegularFile(path) ? Files.readAllBytes(path) : null;
+    }
+
+    private static void removeMatchingImages(Document document, byte[] imageBytes) throws Exception {
+        for (Shape shape : imageShapes(document)) {
+            if (sameImage(shape, imageBytes)) {
+                shape.remove();
+            }
+        }
+    }
+
+    private static void addFirstPageMaSeal(Document document, String imagePath) throws Exception {
+        Paragraph anchor = firstBodyParagraph(document);
+        double[] size = fitImage(imagePath, MA_MAX_WIDTH, MA_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft(MA_LEFT);
+        shape.setTop(MA_TOP);
+        anchor.appendChild(shape);
+    }
+
+    private static void addCoverReportSeal(Document document, String imagePath) throws Exception {
+        Paragraph anchor = firstBodyParagraph(document);
+        PageSetup pageSetup = document.getFirstSection().getPageSetup();
+        double[] size = fitImage(imagePath, REPORT_MAX_WIDTH, REPORT_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft(pageSetup.getLeftMargin() + 20D);
+        shape.setTop(pageSetup.getPageHeight() - pageSetup.getBottomMargin()
+                - size[1] - POSITION_GAP);
+        shape.setBehindText(true);
+        anchor.appendChild(shape);
+    }
+
+    private static void addConclusionReportSeal(Document document, String imagePath) throws Exception {
+        document.updatePageLayout();
+        LayoutCollector collector = new LayoutCollector(document);
+        Paragraph anchor = findBodyParagraphContaining(document, "鐩栫珷", collector, null);
+        if (anchor == null) {
+            return;
+        }
+        Rectangle2D rectangle = getLayoutRectangle(document, collector, anchor);
+        Section section = (Section) anchor.getAncestor(NodeType.SECTION);
+        PageSetup pageSetup = section.getPageSetup();
+        int page = collector.getStartPageIndex(anchor);
+        Paragraph placementAnchor = findPageBodyAnchor(document, collector, page);
+        if (placementAnchor == null) {
+            placementAnchor = anchor;
+        }
+        double[] size = fitImage(imagePath, REPORT_MAX_WIDTH, REPORT_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft((pageSetup.getPageWidth() - size[0]) / 2D);
+        double preferredTop = rectangle == null
+                ? pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1] - 120D
+                : rectangle.getY() - size[1] + rectangle.getHeight() / 2D;
+        shape.setTop(clamp(preferredTop,
+                pageSetup.getTopMargin(),
+                pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1]));
+        // 缁撹绔犱綅浜庤〃鏍煎崟鍏冩牸鍐咃紝蹇呴』缃簬鏂囧瓧涓婃柟锛屽惁鍒欎細琚崟鍏冩牸搴曠汗閬綇銆�
+        shape.setBehindText(false);
+        placementAnchor.appendChild(shape);
+    }
+
+    private static void addLastPageReportSeal(Document document, String imagePath) throws Exception {
+        int lastPage = document.getPageCount();
+        LayoutCollector collector = new LayoutCollector(document);
+        Paragraph anchor = findLastPageAnchor(document, collector, lastPage);
+        if (anchor == null) {
+            return;
+        }
+        Section section = (Section) anchor.getAncestor(NodeType.SECTION);
+        PageSetup pageSetup = section.getPageSetup();
+        double[] size = fitImage(imagePath, LAST_PAGE_MAX_WIDTH, LAST_PAGE_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft((pageSetup.getPageWidth() - size[0]) / 2D);
+        Rectangle2D rectangle = getLayoutRectangle(document, collector, anchor);
+        double preferredTop = rectangle == null
+                ? pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1] - POSITION_GAP
+                : rectangle.getY() + rectangle.getHeight() + POSITION_GAP;
+        shape.setTop(clamp(preferredTop,
+                pageSetup.getTopMargin(),
+                pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1]));
+        shape.setBehindText(true);
+        anchor.appendChild(shape);
+    }
+
+    private static Shape createFloatingImage(Document document, String imagePath,
+                                              double width, double height) throws Exception {
+        Shape shape = new Shape(document, ShapeType.IMAGE);
+        shape.getImageData().setImage(imagePath);
+        shape.setWidth(width);
+        shape.setHeight(height);
+        shape.setWrapType(WrapType.NONE);
+        shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
+        shape.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
+        shape.setAllowOverlap(true);
+        return shape;
+    }
+
+    private static Paragraph firstBodyParagraph(Document document) {
+        Paragraph paragraph = document.getFirstSection().getBody().getFirstParagraph();
+        if (paragraph != null) {
+            return paragraph;
+        }
+        return document.getFirstSection().getBody().appendParagraph("");
+    }
+
+    private static Paragraph findLastPageAnchor(Document document, LayoutCollector collector, int lastPage)
+            throws Exception {
+        Paragraph fallback = null;
+        NodeCollection paragraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
+        for (int i = paragraphs.getCount() - 1; i >= 0; i--) {
+            Paragraph paragraph = (Paragraph) paragraphs.get(i);
+            if (paragraph.getAncestor(NodeType.BODY) == null) {
+                continue;
+            }
+            if (collector.getStartPageIndex(paragraph) != lastPage) {
+                continue;
+            }
+            if (fallback == null) {
+                fallback = paragraph;
+            }
+            if (paragraph.getText().contains("鎶ュ憡缁撴潫")) {
+                return paragraph;
+            }
+        }
+        return fallback;
+    }
+
+    private static Paragraph findBodyParagraphContaining(Document document, String text,
+                                                          LayoutCollector collector, Integer page)
+            throws Exception {
+        NodeCollection paragraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
+        for (int i = 0; i < paragraphs.getCount(); i++) {
+            Paragraph paragraph = (Paragraph) paragraphs.get(i);
+            if (paragraph.getAncestor(NodeType.BODY) == null || !paragraph.getText().contains(text)) {
+                continue;
+            }
+            if (page == null || collector.getStartPageIndex(paragraph) == page) {
+                return paragraph;
+            }
+        }
+        return null;
+    }
+
+    private static Paragraph findPageBodyAnchor(Document document, LayoutCollector collector, int page)
+            throws Exception {
+        NodeCollection paragraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
+        for (int i = 0; i < paragraphs.getCount(); i++) {
+            Paragraph paragraph = (Paragraph) paragraphs.get(i);
+            if (paragraph.getAncestor(NodeType.BODY) == null
+                    || paragraph.getAncestor(NodeType.CELL) != null) {
+                continue;
+            }
+            if (collector.getStartPageIndex(paragraph) == page) {
+                return paragraph;
+            }
+        }
+        return null;
+    }
+
+    private static Rectangle2D getLayoutRectangle(Document document, LayoutCollector collector,
+                                                   Paragraph paragraph) throws Exception {
+        Object entity = collector.getEntity(paragraph);
+        if (entity == null) {
+            NodeCollection runs = paragraph.getChildNodes(NodeType.RUN, true);
+            for (int i = 0; i < runs.getCount() && entity == null; i++) {
+                entity = collector.getEntity(runs.get(i));
+            }
+        }
+        if (entity == null) {
+            return null;
+        }
+        LayoutEnumerator enumerator = new LayoutEnumerator(document);
+        enumerator.setCurrent(entity);
+        return enumerator.getRectangle();
+    }
+
+    private static double clamp(double value, double min, double max) {
+        return Math.max(min, Math.min(value, max));
+    }
+
+    private static List<Shape> imageShapes(Document document) throws Exception {
+        List<Shape> result = new ArrayList<>();
+        NodeCollection nodes = document.getChildNodes(NodeType.SHAPE, true);
+        for (int i = 0; i < nodes.getCount(); i++) {
+            Shape shape = (Shape) nodes.get(i);
+            if (shape.hasImage()) {
+                result.add(shape);
+            }
+        }
+        return result;
+    }
+
+    private static boolean sameImage(Shape shape, byte[] imageBytes) throws Exception {
+        return Arrays.equals(shape.getImageData().toByteArray(), imageBytes);
+    }
+
+    private static double[] fitImage(String imagePath, double maxWidth, double maxHeight) throws Exception {
+        BufferedImage image = ImageIO.read(new ByteArrayInputStream(Files.readAllBytes(
+                java.nio.file.Paths.get(imagePath))));
+        if (image == null || image.getWidth() <= 0 || image.getHeight() <= 0) {
+            return new double[]{maxWidth, maxHeight};
+        }
+        double scale = Math.min(maxWidth / image.getWidth(), maxHeight / image.getHeight());
+        return new double[]{image.getWidth() * scale, image.getHeight() * scale};
+    }
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/vo/InsOrderPrintingVo.java b/inspect-server/src/main/java/com/ruoyi/inspect/vo/InsOrderPrintingVo.java
index e5b823f..6d4942e 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/vo/InsOrderPrintingVo.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/vo/InsOrderPrintingVo.java
@@ -4,7 +4,7 @@
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
-import java.time.LocalDateTime;
+import java.time.LocalDate;
 
 /**
  * @Author zhuo
@@ -25,9 +25,9 @@
     @ApiModelProperty("瑙勬牸鍨嬪彿")
     private String sampleModel;
 
-    @ApiModelProperty("濮旀墭鏃ユ湡")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime sendTime;
+    @ApiModelProperty("閫佹牱鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate sampleDate;
 
     @ApiModelProperty("濮旀墭浜�")
     private String prepareUser;
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/vo/TemplateConditionVo.java b/inspect-server/src/main/java/com/ruoyi/inspect/vo/TemplateConditionVo.java
index 5ced399..b538302 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/vo/TemplateConditionVo.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/vo/TemplateConditionVo.java
@@ -18,9 +18,6 @@
     @ApiModelProperty("娓╁害")
     private String temperature;
 
-    @ApiModelProperty("婀垮害")
-    private String humidity;
-
     @ApiModelProperty("妫�娴嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
     private LocalDate detectionTime;
diff --git a/inspect-server/src/main/resources/mapper/InsOrderMapper.xml b/inspect-server/src/main/resources/mapper/InsOrderMapper.xml
index 798924f..3f6eabd 100644
--- a/inspect-server/src/main/resources/mapper/InsOrderMapper.xml
+++ b/inspect-server/src/main/resources/mapper/InsOrderMapper.xml
@@ -246,6 +246,7 @@
                en_device_name,
                specification_model,
                management_number,
+               factory_no,
                date_format(activation_date,'%Y-%m-%d')
         latest_traceability
         from device
@@ -416,7 +417,7 @@
         from (select io2.id insOrderId,
                      io2.sample_view,
                      io2.production,
-                     io2.send_time,
+                     io2.sample_date,
                      GROUP_CONCAT(DISTINCT isa.model SEPARATOR ' ') AS sample_model,
                      io2.prepare_user,
                      io2.entrust_code,
diff --git a/inspect-server/src/main/resources/mapper/InsReportMapper.xml b/inspect-server/src/main/resources/mapper/InsReportMapper.xml
index 07d0518..3b9e27b 100644
--- a/inspect-server/src/main/resources/mapper/InsReportMapper.xml
+++ b/inspect-server/src/main/resources/mapper/InsReportMapper.xml
@@ -89,6 +89,9 @@
         case when type_source = 0 then '鎴愬搧涓嬪崟' else '鍘熸潗鏂欎笅鍗�' end                    type_source,
         case
         when order_type = '鎶芥' then '鎶芥'
+        when order_type = 'Commissioned testing' then '濮旀墭妫�娴�'
+        when order_type = 'Inter-laboratory comparison' then '瀹為獙瀹ら棿姣斿'
+        when order_type = 'Proficiency testing' then '鑳藉姏楠岃瘉'
         when order_type = 'Customer-ordered test' then '濮旀墭妫�楠�'
         when order_type = '杩涘巶妫�楠�' then '杩涘巶妫�楠�'
         when order_type = 'Quarterly inspection' then '瀛e害妫�楠�'
diff --git a/inspect-server/src/main/resources/static/detection-report-template-v2.docx b/inspect-server/src/main/resources/static/detection-report-template-v2.docx
index 81ec55c..c646665 100644
--- a/inspect-server/src/main/resources/static/detection-report-template-v2.docx
+++ b/inspect-server/src/main/resources/static/detection-report-template-v2.docx
Binary files differ
diff --git a/inspect-server/src/main/resources/static/inspection-report-template-v2.docx b/inspect-server/src/main/resources/static/inspection-report-template-v2.docx
index 2c2a1a7..f343020 100644
--- a/inspect-server/src/main/resources/static/inspection-report-template-v2.docx
+++ b/inspect-server/src/main/resources/static/inspection-report-template-v2.docx
Binary files differ
diff --git a/ruoyi-admin/src/main/resources/application-xjxj.yml b/ruoyi-admin/src/main/resources/application-xjxj.yml
index d349ad1..1bac20d 100644
--- a/ruoyi-admin/src/main/resources/application-xjxj.yml
+++ b/ruoyi-admin/src/main/resources/application-xjxj.yml
@@ -74,7 +74,7 @@
 #    port: 6379
     port: 11102
     # 鏁版嵁搴撶储寮�
-    database: 0
+    database: 6
     #    # 瀵嗙爜
     password:
     # 杩炴帴瓒呮椂鏃堕棿
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 2fbeb92..9a875aa 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -16,7 +16,9 @@
 # 寮�鍙戠幆澧冮厤缃�
 server:
   # 鏈嶅姟鍣ㄧ殑HTTP绔彛
-  port: 8001
+  # 鏈嶅姟鍣ㄧ鍙�
+#  port: 9509
+  port: 9509
   servlet:
     # 搴旂敤鐨勮闂矾寰�
     context-path: /lims
@@ -55,9 +57,9 @@
   servlet:
     multipart:
       # 鍗曚釜鏂囦欢澶у皬
-      max-file-size: 10MB
+      max-file-size: 200MB
       # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
-      max-request-size: 20MB
+      max-request-size: 400MB
   # 鏈嶅姟妯″潡
 #  devtools:
 #    restart:
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/InsOrderTypeConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/InsOrderTypeConstants.java
index 676efa1..8bfc585 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/InsOrderTypeConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/InsOrderTypeConstants.java
@@ -7,6 +7,12 @@
  * @Date 2024/8/11
  */
 public class InsOrderTypeConstants {
+    // 濮旀墭妫�娴�
+    public static final String COMMISSIONED_TEST = "Commissioned testing";
+    // 瀹為獙瀹ら棿姣斿
+    public static final String INTER_LABORATORY_COMPARISON = "Inter-laboratory comparison";
+    // 鑳藉姏楠岃瘉
+    public static final String PROFICIENCY_TESTING = "Proficiency testing";
     // 妫�楠岀被鍨�
     public static final String SPOT_CHECK = "鎶芥";
     // 濮旀墭妫�楠�
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/PersonalScopeAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/PersonalScopeAspect.java
index c336760..767f98e 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/PersonalScopeAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/PersonalScopeAspect.java
@@ -41,6 +41,11 @@
         // 鑾峰彇鐩爣鏂规硶涓婄殑娉ㄨВ
         PersonalScope annotation = signature.getMethod().getAnnotation(PersonalScope.class);
 
+        // 瓒呯骇绠$悊鍛樻煡鐪嬫姤鍛婄紪鍒舵椂涓嶉檺鍒朵负鈥滀粎鐪嬫垜鈥�
+        if (SecurityUtils.isAdmin(userId) && "business:reportPreparation".equals(annotation.permsName())) {
+            return;
+        }
+
         // 鑾峰彇鏉冮檺鍒ゆ柇鏄惁鏄粎鐪嬫垜
         SysRoleVo sysRoleVo = sysRoleMenuMapper.selectRoleMenu(annotation.permsName(), userId);
 

--
Gitblit v1.9.3