From d726f4b74afd197b6a8ba0f2afb65abcd6c234c7 Mon Sep 17 00:00:00 2001
From: zhuo <2089219845@qq.com>
Date: 星期六, 22 二月 2025 10:56:08 +0800
Subject: [PATCH] 移植设备核查计划

---
 cnas-device/src/main/resources/mapper/DeviceExamineRecordMapper.xml                                        |   25 
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecord.java                                   |  139 +++
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordService.java                         |   43 
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanDetailsMapper.java                      |   27 
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordDetail.java                             |   70 +
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastService.java                 |   46 +
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastDetailsService.java          |   16 
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrastDetails.java                    |   70 +
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlan.java                                     |   67 +
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanServiceImpl.java                  |  346 +++++++
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanService.java                           |   88 ++
 cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDetailsDto.java                  |   16 
 cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDto.java                         |   47 +
 cnas-device/src/main/resources/mapper/DeviceExaminePlanDetailsMapper.xml                                   |   18 
 cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDetailsDto.java                            |   16 
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExternalApplyMapper.java                           |   34 
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordDetailMapper.java                     |   16 
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordMapper.java                           |   31 
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrast.java                           |   97 ++
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExternalApply.java                                   |  123 ++
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanDetailsService.java                    |   16 
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExternalApplyService.java                         |   42 
 cnas-device/src/main/resources/mapper/DeviceExaminePlanMapper.xml                                          |   33 
 cnas-device/src/main/resources/mapper/DeviceExternalApplyMapper.xml                                        |   23 
 cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordDto.java                                 |   28 
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanDetailsServiceImpl.java           |   20 
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastDetailsMapper.java            |   16 
 cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDto.java                                   |   33 
 cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordDetailService.java                   |   16 
 cnas-device/src/main/java/com/ruoyi/device/controller/DeviceExaminePlanController.java                     |  273 ++++++
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastServiceImpl.java        |  193 ++++
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExternalApplyServiceImpl.java                |  161 +++
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanMapper.java                             |   35 
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordServiceImpl.java                |  198 ++++
 cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastMapper.java                   |   31 
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordDetailServiceImpl.java          |   20 
 cnas-device/src/main/resources/mapper/DeviceExamineRecordContrastMapper.xml                                |   39 
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastDetailsServiceImpl.java |   20 
 cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlanDetails.java                              |   76 +
 39 files changed, 2,608 insertions(+), 0 deletions(-)

diff --git a/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceExaminePlanController.java b/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceExaminePlanController.java
new file mode 100644
index 0000000..5050b64
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceExaminePlanController.java
@@ -0,0 +1,273 @@
+package com.ruoyi.device.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.device.dto.DeviceExaminePlanDto;
+import com.ruoyi.device.dto.DeviceExamineRecordContrastDto;
+import com.ruoyi.device.dto.DeviceExamineRecordDto;
+import com.ruoyi.device.pojo.DeviceExaminePlan;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import com.ruoyi.device.service.DeviceExaminePlanDetailsService;
+import com.ruoyi.device.service.DeviceExaminePlanService;
+import com.ruoyi.device.service.DeviceExamineRecordContrastService;
+import com.ruoyi.device.service.DeviceExamineRecordService;
+import com.ruoyi.framework.exception.ErrorException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝涓昏〃 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:04
+ */
+@Api(tags = "璁惧鏍告煡璁″垝")
+@AllArgsConstructor
+@RestController
+@RequestMapping("/deviceExaminePlan")
+public class DeviceExaminePlanController {
+
+    private DeviceExaminePlanService deviceExaminePlanService;
+
+    private DeviceExaminePlanDetailsService deviceExaminePlanDetailsService;
+
+    private DeviceExamineRecordService deviceExamineRecordService;
+
+    private DeviceExamineRecordContrastService deviceExamineRecordContrastService;
+
+
+    /**
+     * 鏂板璁惧鏍告煡璁″垝
+     * @return
+     */
+    @ApiOperation(value = "鏂板璁惧鏍告煡璁″垝")
+    @PostMapping("/addDeviceExaminePlan")
+    public Result addDeviceExaminePlan(@RequestBody DeviceExaminePlanDto examinePlanDto){
+        return Result.success(deviceExaminePlanService.addDeviceExaminePlan(examinePlanDto));
+    }
+
+    /**
+     * 淇敼璁惧鏍告煡璁″垝
+     * @param examinePlanDto 璁惧鏍告煡璁″垝
+     */
+    @ApiOperation("鎵归噺淇敼璁惧鏍告煡璁″垝")
+    @PostMapping("/updateDeviceExaminePlan")
+    public Result updateDeviceExaminePlan(@RequestBody DeviceExaminePlanDto examinePlanDto) {
+        return Result.success(deviceExaminePlanService.updateDeviceExaminePlan(examinePlanDto));
+    }
+
+    /**
+     * 鏌ヨ璁惧鏍告煡璁″垝璇︽儏
+     */
+    @ApiOperation("鏌ヨ璁惧鏍告煡璁″垝璇︽儏")
+    @GetMapping("/getDeviceExaminePlan")
+    public Result<DeviceExaminePlanDto> getDeviceExaminePlan(Integer planId) {
+        return Result.success(deviceExaminePlanService.getDeviceExaminePlan(planId));
+    }
+
+    /**
+     * 瀵煎叆璁惧鏍告煡璁″垝
+     * @return
+     */
+    @ApiOperation(value = "瀵煎叆璁惧鏍告煡璁″垝")
+    @PostMapping("/importDeviceExaminePlan")
+    public Result importDeviceExaminePlan(MultipartFile file){
+        return Result.success(deviceExaminePlanService.importDeviceExaminePlan(file));
+    }
+
+
+    /**
+     * 璁惧鏍告煡璁″垝鍒犻櫎
+     * @return
+     */
+    @ApiOperation(value = "璁惧鏍告煡璁″垝鍒犻櫎")
+    @GetMapping("/delQualitySupervise")
+    public Result delQualitySupervise(Integer planId){
+        return Result.success(deviceExaminePlanService.removeById(planId));
+    }
+
+
+    /**
+     * 璁惧鏍告煡璁″垝鎵瑰噯
+     * @return
+     */
+    @ApiOperation(value = "鎻愪氦鎵瑰噯")
+    @PostMapping("/submitRatifyDeviceExaminePlan")
+    public Result submitRatifyDeviceExaminePlan(@RequestBody DeviceExaminePlan DeviceExaminePlan){
+        return Result.success(deviceExaminePlanService.submitRatifyDeviceExaminePlan(DeviceExaminePlan));
+    }
+
+    /**
+     * 璁惧鏍告煡璁″垝鎵瑰噯
+     * @return
+     */
+    @ApiOperation(value = "璁惧鏍告煡璁″垝鎵瑰噯")
+    @PostMapping("/ratifyDeviceExaminePlan")
+    public Result ratifyDeviceExaminePlan(@RequestBody DeviceExaminePlan DeviceExaminePlan){
+        return Result.success(deviceExaminePlanService.ratifyDeviceExaminePlan(DeviceExaminePlan));
+    }
+
+
+    /**
+     * 璁惧鏍告煡璁″垝鍒楄〃
+     * @return
+     */
+    @ApiOperation(value = "璁惧鏍告煡璁″垝鍒楄〃")
+    @PostMapping("/pageDeviceExaminePlan")
+    public Result<IPage<DeviceExaminePlanDto>> pageDeviceExaminePlan(Page page, DeviceExaminePlan DeviceExaminePlan) {
+        return Result.success(deviceExaminePlanService.pageDeviceExaminePlan(page, DeviceExaminePlan));
+    }
+
+    /**
+     * 璁惧鏍告煡璁″垝璇︽儏鍒楄〃
+     * @return
+     */
+    @ApiOperation(value = "璁惧鏍告煡璁″垝璇︽儏鍒楄〃")
+    @PostMapping("/pageDeviceExaminePlanDetail")
+    public Result<IPage<DeviceExaminePlanDetails>> pageDeviceExaminePlanDetail(Page page, DeviceExaminePlanDetails deviceExaminePlanDetails) {
+        return Result.success(deviceExaminePlanService.pageDeviceExaminePlanDetail(page, deviceExaminePlanDetails));
+    }
+
+    /**
+     * 鏂板璁惧鏍告煡璁″垝璇︽儏
+     * @return
+     */
+    @ApiOperation(value = "鏂板璁惧鏍告煡璁″垝璇︽儏")
+    @PostMapping("/addDeviceExaminePlanDetail")
+    public Result addDeviceExaminePlanDetail(@RequestBody DeviceExaminePlanDetails deviceExaminePlanDetail){
+        if (deviceExaminePlanDetail.getPlanId() == null) {
+            throw new ErrorException("缂哄皯璁惧鏍告煡璁″垝涓昏〃id");
+        }
+        return Result.success(deviceExaminePlanDetailsService.save(deviceExaminePlanDetail));
+    }
+
+    /**
+     * 淇敼璁惧鏍告煡璁″垝璇︽儏
+     * @return
+     */
+    @ApiOperation(value = "淇敼璁惧鏍告煡璁″垝璇︽儏")
+    @PostMapping("/updateDeviceExaminePlanDetail")
+    public Result updateDeviceExaminePlanDetail(@RequestBody DeviceExaminePlanDetails deviceExaminePlanDetail){
+        return Result.success(deviceExaminePlanDetailsService.updateById(deviceExaminePlanDetail));
+    }
+
+    /**
+     * 鍒犻櫎璁惧鏍告煡璁″垝璇︽儏
+     * @return
+     */
+    @ApiOperation(value = "鍒犻櫎璁惧鏍告煡璁″垝璇︽儏")
+    @GetMapping("/delDeviceExaminePlanDetail")
+    public Result delDeviceExaminePlanDetail(Integer planDetailsId){
+        return Result.success(deviceExaminePlanDetailsService.removeById(planDetailsId));
+    }
+
+    /**
+     * 瀵煎嚭璁惧鏍告煡璁″垝
+     * @param planId 璁惧鏍告煡璁″垝id
+     * @return
+     */
+    @ApiOperation(value = "瀵煎嚭璁惧鏍告煡璁″垝")
+    @GetMapping("/exportDeviceExaminePlanDetail")
+    public void exportDeviceExaminePlanDetail(Integer planId, HttpServletResponse response){
+        deviceExaminePlanService.exportDeviceExaminePlanDetail(planId, response);
+    }
+
+    /*********************************************** 鎶ュ憡 **************************************************/
+
+    /**
+     * 鏌ヨ鏍告煡璁板綍
+     * @return
+     */
+    @ApiOperation(value = "鏌ヨ鏍告煡璁板綍")
+    @GetMapping("/getExamineRecord")
+    public Result<DeviceExamineRecordDto> getExamineRecord(Integer planDetailsId){
+        return Result.success(deviceExamineRecordService.getExamineRecord(planDetailsId));
+    }
+
+    /**
+     * 鏂板鏍告煡璁板綍
+     * @return
+     */
+    @ApiOperation(value = "鏂板鏍告煡璁板綍")
+    @PostMapping("/addExamineRecord")
+    public Result addExamineRecord(@RequestBody DeviceExamineRecordDto deviceExamineRecordDto){
+        return Result.success(deviceExamineRecordService.addExamineRecord(deviceExamineRecordDto));
+    }
+
+
+    /**
+     * 澶嶆牳鏍告煡璁板綍
+     * @return
+     */
+    @ApiOperation(value = "澶嶆牳鏍告煡璁板綍")
+    @PostMapping("/reviewExamineRecord")
+    public Result reviewExamineRecord(@RequestBody DeviceExamineRecordDto deviceExamineRecordDto){
+        return Result.success(deviceExamineRecordService.reviewExamineRecord(deviceExamineRecordDto));
+    }
+
+    /**
+     * 瀵煎嚭澶嶆牳鏍告煡璁板綍
+     * @param planDetailsId
+     * @return
+     */
+    @ApiOperation(value = "瀵煎嚭澶嶆牳鏍告煡璁板綍")
+    @GetMapping("/exportReviewExamineRecordDetail")
+    public void exportReviewExamineRecordDetail(Integer planDetailsId, HttpServletResponse response){
+        deviceExamineRecordService.exportReviewExamineRecordDetail(planDetailsId, response);
+    }
+
+    /*********************************************** 鎶ュ憡瀵规瘮 **************************************************/
+
+
+    /**
+     * 鏌ヨ鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    @ApiOperation(value = "鏌ヨ鏍告煡瀵规瘮璁板綍")
+    @GetMapping("/getExamineRecordContrast")
+    public Result<DeviceExamineRecordContrastDto> getExamineRecordContrast(Integer planDetailsId){
+        return Result.success(deviceExamineRecordContrastService.getExamineRecordContrast(planDetailsId));
+    }
+
+    /**
+     * 鏂板鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    @ApiOperation(value = "鏂板鏍告煡瀵规瘮璁板綍")
+    @PostMapping("/addExamineRecordContrast")
+    public Result addExamineRecordContrast(@RequestBody DeviceExamineRecordContrastDto deviceExamineRecordContrastDto){
+        return Result.success(deviceExamineRecordContrastService.addExamineRecordContrast(deviceExamineRecordContrastDto));
+    }
+
+
+    /**
+     * 瀹℃牳鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    @ApiOperation(value = "瀹℃牳鏍告煡瀵规瘮璁板綍")
+    @PostMapping("/reviewExamineRecordContrast")
+    public Result reviewExamineRecordContrast(@RequestBody DeviceExamineRecordContrastDto deviceExamineRecordContrastDto){
+        return Result.success(deviceExamineRecordContrastService.reviewExamineRecordContrast(deviceExamineRecordContrastDto));
+    }
+
+    /**
+     * 瀵煎嚭瀹℃牳鏍告煡瀵规瘮璁板綍
+     * @param planDetailsId
+     * @return
+     */
+    @ApiOperation(value = "瀵煎嚭瀹℃牳鏍告煡瀵规瘮璁板綍")
+    @GetMapping("/exportReviewExamineRecordContrast")
+    public Result exportReviewExamineRecordContrast(Integer planDetailsId, HttpServletResponse response){
+        deviceExamineRecordContrastService.exportReviewExamineRecordContrast(planDetailsId, response);
+        return Result.success();
+    }
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDetailsDto.java b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDetailsDto.java
new file mode 100644
index 0000000..4ab9e37
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDetailsDto.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.dto;
+
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * Author: yuan
+ * Date: 2024-12-17 鏄熸湡浜� 15:34:44
+ * Description:
+ */
+@Data
+public class DeviceExaminePlanDetailsDto extends DeviceExaminePlanDetails {
+    @ApiModelProperty("搴忓彿")
+    private Integer index;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDto.java b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDto.java
new file mode 100644
index 0000000..76eb24b
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExaminePlanDto.java
@@ -0,0 +1,33 @@
+package com.ruoyi.device.dto;
+
+import com.ruoyi.device.pojo.DeviceExaminePlan;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author zhuo
+ * @Date 2024/12/16
+ */
+@Data
+public class DeviceExaminePlanDto extends DeviceExaminePlan {
+
+    @ApiModelProperty("缂栧埗浜�")
+    private String writeName;
+
+    @ApiModelProperty("鎵瑰噯浜�")
+    private String ratifyName;
+
+    @ApiModelProperty("缂栧埗鏃堕棿")
+    private String writeTimeStr;
+
+    @ApiModelProperty("鎵瑰噯鏃堕棿")
+    private String ratifyTimeStr;
+
+    @ApiModelProperty("骞村害")
+    private String year;
+
+    private List<DeviceExaminePlanDetails> examinePlanDetailsList;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDetailsDto.java b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDetailsDto.java
new file mode 100644
index 0000000..e00c24e
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDetailsDto.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.dto;
+
+import com.ruoyi.device.pojo.DeviceExamineRecordContrastDetails;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * Author: yuan
+ * Date: 2024-12-17 鏄熸湡浜� 13:59:37
+ * Description:
+ */
+@Data
+public class DeviceExamineRecordContrastDetailsDto extends DeviceExamineRecordContrastDetails {
+    @ApiModelProperty("搴忓彿")
+    private Integer index;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDto.java b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDto.java
new file mode 100644
index 0000000..1600591
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordContrastDto.java
@@ -0,0 +1,47 @@
+package com.ruoyi.device.dto;
+
+import com.ruoyi.device.pojo.DeviceExamineRecordContrast;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrastDetails;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author zhuo
+ * @Date 2024/12/16
+ */
+@Data
+public class DeviceExamineRecordContrastDto extends DeviceExamineRecordContrast {
+
+    @ApiModelProperty("鏍告煡璁板綍瀵规瘮璇︽儏")
+    private List<DeviceExamineRecordContrastDetails> recordContrastDetailsList;
+
+
+    @ApiModelProperty("A璁惧鍚嶇О")
+    private String aDeviceName;
+
+    @ApiModelProperty("A璁惧缂栧彿")
+    private String aDeviceNumber;
+
+    @ApiModelProperty("b璁惧鍚嶇О")
+    private String bDeviceName;
+
+    @ApiModelProperty("b璁惧缂栧彿")
+    private String bDeviceNumber;
+
+    @ApiModelProperty("c璁惧鍚嶇О")
+    private String cDeviceName;
+
+    @ApiModelProperty("c璁惧缂栧彿")
+    private String cDeviceNumber;
+
+    @ApiModelProperty("鏍告煡鏃ユ湡")
+    private String checkerTimeStr;
+
+    @ApiModelProperty("瀹℃牳鏃ユ湡")
+    private String reviewTimeStr;
+
+    @ApiModelProperty("瀹為獙瀹�")
+    private String labName;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordDto.java b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordDto.java
new file mode 100644
index 0000000..3b18d7c
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/dto/DeviceExamineRecordDto.java
@@ -0,0 +1,28 @@
+package com.ruoyi.device.dto;
+
+import com.ruoyi.device.pojo.DeviceExamineRecord;
+import com.ruoyi.device.pojo.DeviceExamineRecordDetail;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author zhuo
+ * @Date 2024/12/16
+ */
+@Data
+public class DeviceExamineRecordDto extends DeviceExamineRecord {
+
+    @ApiModelProperty("鏍告煡璁板綍璇︽儏")
+    private List<DeviceExamineRecordDetail> recordDetailList;
+
+    @ApiModelProperty("璁惧鍚嶇О")
+    private String deviceName;
+
+    @ApiModelProperty("璁惧缂栧彿")
+    private String deviceNumber;
+
+    @ApiModelProperty("鏈�鍚庝竴娆′慨鏀规棩鏈�")
+    private String updateTimeStr;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanDetailsMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanDetailsMapper.java
new file mode 100644
index 0000000..b458685
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanDetailsMapper.java
@@ -0,0 +1,27 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝璇︽儏琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:16
+ */
+public interface DeviceExaminePlanDetailsMapper extends BaseMapper<DeviceExaminePlanDetails> {
+
+    /**
+     * 璁惧鏍告煡璁″垝璇︽儏鍒楄〃
+     * @param page
+     * @param ew
+     * @return
+     */
+    IPage<DeviceExaminePlanDetails> pageDeviceExaminePlanDetail(Page page, @Param("ew") QueryWrapper<DeviceExaminePlanDetails> ew);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanMapper.java
new file mode 100644
index 0000000..2161630
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExaminePlanMapper.java
@@ -0,0 +1,35 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.device.dto.DeviceExaminePlanDto;
+import com.ruoyi.device.pojo.DeviceExaminePlan;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝涓昏〃 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:04
+ */
+public interface DeviceExaminePlanMapper extends BaseMapper<DeviceExaminePlan> {
+
+    /**
+     * 璁惧鏍告煡璁″垝鍒楄〃
+     * @param page
+     * @param ew
+     * @return
+     */
+    IPage<DeviceExaminePlanDto> deviceExaminePlanDetailsMapper(Page page, @Param("ew") QueryWrapper<DeviceExaminePlan> ew);
+
+    /**
+     * 鏌ヨ璁惧鏍告煡璁″垝璇︽儏
+     * @param deviceExaminePlanId 璁惧鏍告煡璁″垝id
+     * @return
+     */
+    DeviceExaminePlanDto selectExamineExaminePlanDto(@Param("deviceExaminePlanId") Integer deviceExaminePlanId);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastDetailsMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastDetailsMapper.java
new file mode 100644
index 0000000..07c67b8
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastDetailsMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrastDetails;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮璇︽儏琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:57
+ */
+public interface DeviceExamineRecordContrastDetailsMapper extends BaseMapper<DeviceExamineRecordContrastDetails> {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastMapper.java
new file mode 100644
index 0000000..c20a385
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordContrastMapper.java
@@ -0,0 +1,31 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.device.dto.DeviceExamineRecordContrastDto;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrast;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:43
+ */
+public interface DeviceExamineRecordContrastMapper extends BaseMapper<DeviceExamineRecordContrast> {
+
+    /**
+     * 鏌ヨ鏍告煡瀵规瘮璁板綍
+     * @param planDetailsId
+     * @return
+     */
+    DeviceExamineRecordContrastDto getExamineRecordContrast(Integer planDetailsId);
+
+    /**
+     * 鏌ヨ瀵规瘮璁板綍鐢ㄤ簬瀵煎嚭
+     * @param planDetailsId
+     * @return
+     */
+    DeviceExamineRecordContrastDto selectExamineRecordContrastDto(@Param("planDetailsId") Integer planDetailsId);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordDetailMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordDetailMapper.java
new file mode 100644
index 0000000..990c345
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordDetailMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.device.pojo.DeviceExamineRecordDetail;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍璇︽儏琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:15:11
+ */
+public interface DeviceExamineRecordDetailMapper extends BaseMapper<DeviceExamineRecordDetail> {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordMapper.java
new file mode 100644
index 0000000..145a768
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExamineRecordMapper.java
@@ -0,0 +1,31 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.device.dto.DeviceExamineRecordDto;
+import com.ruoyi.device.pojo.DeviceExamineRecord;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:28
+ */
+public interface DeviceExamineRecordMapper extends BaseMapper<DeviceExamineRecord> {
+
+    /**
+     * 鏌ヨ璁惧鏍告煡璁板綍
+     * @param planDetailsId
+     * @return
+     */
+    DeviceExamineRecordDto getExamineRecord(Integer planDetailsId);
+
+    /**
+     * 澶嶆牳鏍告煡璁板綍
+     * @param planDetailsId 澶嶆牳鏍告煡璁板綍id
+     * @return
+     */
+    DeviceExamineRecordDto selectReviewExamineRecordDto(@Param("planDetailsId") Integer planDetailsId);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExternalApplyMapper.java b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExternalApplyMapper.java
new file mode 100644
index 0000000..b87c009
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/mapper/DeviceExternalApplyMapper.java
@@ -0,0 +1,34 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.device.pojo.DeviceExternalApply;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 鍒╃敤澶栭儴璁惧鐢宠琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-17 10:28:43
+ */
+public interface DeviceExternalApplyMapper extends BaseMapper<DeviceExternalApply> {
+
+    /**
+     * 鍒╃敤澶栭儴璁惧鐢宠鍒楄〃
+     * @param page
+     * @param ew
+     * @return
+     */
+    IPage<DeviceExternalApply> pageDeviceExternalApply(Page page, @Param("ew") QueryWrapper<DeviceExternalApply> ew);
+
+    /**
+     * 瀵煎嚭鏌ヨ鍒╃敤澶栭儴璁惧鐢宠
+     * @param externalApplyId 澶栭儴璁惧鐢宠琛╥d
+     * @return
+     */
+    DeviceExternalApply selectDeviceExternalById(@Param("externalApplyId") Integer externalApplyId);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlan.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlan.java
new file mode 100644
index 0000000..90bab05
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlan.java
@@ -0,0 +1,67 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝涓昏〃
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:04
+ */
+@Getter
+@Setter
+@TableName("device_examine_plan")
+@ApiModel(value = "DeviceExaminePlan瀵硅薄", description = "璁惧鏍告煡璁″垝涓昏〃")
+public class DeviceExaminePlan{
+
+    @TableId(value = "plan_id", type = IdType.AUTO)
+    private Integer planId;
+
+    @ApiModelProperty("璁″垝鍚嶇О")
+    private String planName;
+
+    @ApiModelProperty("璁″垝鍚嶇О")
+    private String planYear;
+
+    @ApiModelProperty("缂栧埗浜�")
+    private Integer writeUserId;
+
+    @ApiModelProperty("缂栧埗鏃堕棿")
+    private LocalDateTime writeTime;
+
+    @ApiModelProperty("鎵瑰噯浜�")
+    private Integer ratifyUserId;
+
+    @ApiModelProperty("鎵瑰噯鏃堕棿")
+    private LocalDateTime ratifyTime;
+
+    @ApiModelProperty("鎵瑰噯鐘舵��,0 涓嶉�氳繃, 1 閫氳繃")
+    private Integer ratifyStatus;
+
+    @ApiModelProperty("鎵瑰噯淇℃伅")
+    private String ratifyRemark;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlanDetails.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlanDetails.java
new file mode 100644
index 0000000..3d43df1
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExaminePlanDetails.java
@@ -0,0 +1,76 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝璇︽儏琛�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:16
+ */
+@Getter
+@Setter
+@TableName("device_examine_plan_details")
+@ApiModel(value = "DeviceExaminePlanDetails瀵硅薄", description = "璁惧鏍告煡璁″垝璇︽儏琛�")
+public class DeviceExaminePlanDetails {
+
+    @TableId(value = "plan_details_id", type = IdType.AUTO)
+    private Integer planDetailsId;
+
+    @ApiModelProperty("涓昏〃id")
+    private Integer planId;
+
+    @ApiModelProperty("璁惧id")
+    private Integer deviceId;
+
+    @ApiModelProperty("璁惧缂栧彿")
+    private String deviceNumber;
+
+    @ApiModelProperty("璁″垝鍚嶇О")
+    private String deviceName;
+
+    @ApiModelProperty("鏍告煡鏃堕棿")
+    private String checkTime;
+
+    @ApiModelProperty("鏍告煡鎸囨爣")
+    private String checkIndex;
+
+    @ApiModelProperty("鏍告煡鏂规硶")
+    private String checkMethod;
+
+    @ApiModelProperty("缁撴灉濡備綍鍒ゅ畾")
+    private String howResults;
+
+    @ApiModelProperty("鏍告煡璐d换浜篿d")
+    private Integer checkChargerUserId;
+
+    @ApiModelProperty("鏍告煡璐d换浜�")
+    private String checkChargerUser;
+
+    @ApiModelProperty("澶囨敞")
+    private String remark;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecord.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecord.java
new file mode 100644
index 0000000..4ec4ab5
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecord.java
@@ -0,0 +1,139 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍琛�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:28
+ */
+@Getter
+@Setter
+@TableName("device_examine_record")
+@ApiModel(value = "DeviceExamineRecord瀵硅薄", description = "璁惧鏍告煡璁板綍琛�")
+public class DeviceExamineRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "record_id", type = IdType.AUTO)
+    private Integer recordId;
+
+    @ApiModelProperty("璁惧鏍告煡璇︽儏id")
+    private Integer planDetailsId;
+
+    @ApiModelProperty("绮惧害绛夌骇")
+    private String accuracyGrade;
+
+    @ApiModelProperty("浣跨敤鐗╄川鍚嶇О")
+    private String materialName;
+
+    @ApiModelProperty("浣跨敤鐗╄川绠$悊缂栧彿")
+    private String materialNumber;
+
+    @ApiModelProperty("浣跨敤鐗╄川绮惧害/涓嶇‘瀹氬害")
+    private String materialAccuracyUncertainty;
+
+    @ApiModelProperty("浣跨敤鐗╄川瑙勬牸鍨嬪彿")
+    private String materialModel;
+
+    @ApiModelProperty("浣跨敤鐗╄川鏍告煡鏂瑰紡")
+    private String materialCheckMethod;
+
+    @ApiModelProperty("浣跨敤鐗╄川鏍告煡椤圭洰")
+    private String materialCheckItems;
+
+    @ApiModelProperty("娓╁害")
+    private String temperature;
+
+    @ApiModelProperty("婀垮害")
+    private String humidity;
+
+    @ApiModelProperty("鍒ゅ畾")
+    private String determine;
+
+    @ApiModelProperty("澶囨敞")
+    private String remark;
+
+    @ApiModelProperty("鏍告煡浜篿d")
+    private Integer checkerUserId;
+
+    @ApiModelProperty("鏍告煡浜�")
+    private String checkerUser;
+
+    @ApiModelProperty("澶嶆牳浜篿d")
+    private Integer reviewUserId;
+
+    @ApiModelProperty("澶嶆牳浜�")
+    private String reviewUser;
+
+    @ApiModelProperty("瀹℃牳鐘舵��0,涓嶉�氳繃, 1閫氳繃")
+    private Integer reviewStatus;
+
+    @ApiModelProperty("瀹℃牳澶囨敞")
+    private String reviewRemark;
+
+    @ApiModelProperty("娴嬭瘯鐐�1")
+    private String dataValue1;
+    @ApiModelProperty("娴嬭瘯鐐�2")
+    private String dataValue2;
+    @ApiModelProperty("娴嬭瘯鐐�3")
+    private String dataValue3;
+    @ApiModelProperty("娴嬭瘯鐐�4")
+    private String dataValue4;
+    @ApiModelProperty("娴嬭瘯鐐�5")
+    private String dataValue5;
+    @ApiModelProperty("娴嬭瘯鐐�6")
+    private String dataValue6;
+
+    @ApiModelProperty("鏈�澶у亸宸�1")
+    private String maximun1;
+    @ApiModelProperty("鏈�澶у亸宸�2")
+    private String maximun2;
+    @ApiModelProperty("鏈�澶у亸宸�3")
+    private String maximun3;
+    @ApiModelProperty("鏈�澶у亸宸�4")
+    private String maximun4;
+    @ApiModelProperty("鏈�澶у亸宸�5")
+    private String maximun5;
+    @ApiModelProperty("鏈�澶у亸宸�6")
+    private String maximun6;
+
+    @ApiModelProperty("鐩稿鍋忓樊1")
+    private String relative1;
+    @ApiModelProperty("鐩稿鍋忓樊2")
+    private String relative2;
+    @ApiModelProperty("鐩稿鍋忓樊3")
+    private String relative3;
+    @ApiModelProperty("鐩稿鍋忓樊4")
+    private String relative4;
+    @ApiModelProperty("鐩稿鍋忓樊5")
+    private String relative5;
+    @ApiModelProperty("鐩稿鍋忓樊6")
+    private String relative6;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrast.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrast.java
new file mode 100644
index 0000000..86953ed
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrast.java
@@ -0,0 +1,97 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮琛�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:43
+ */
+@Getter
+@Setter
+@TableName("device_examine_record_contrast")
+@ApiModel(value = "DeviceExamineRecordContrast瀵硅薄", description = "璁惧鏍告煡璁板綍瀵规瘮琛�")
+public class DeviceExamineRecordContrast implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "record_contrast_id", type = IdType.AUTO)
+    private Integer recordContrastId;
+
+    @ApiModelProperty("鏍告煡鏂瑰紡")
+    private String checkMethod;
+
+    @ApiModelProperty("璁惧鏍告煡璇︽儏id")
+    private Integer planDetailsId;
+
+    @ApiModelProperty("璁惧idA")
+    private Integer aDeviceId;
+
+    @ApiModelProperty("璁惧idb")
+    private Integer bDeviceId;
+
+    @ApiModelProperty("璁惧idc")
+    private Integer cDeviceId;
+
+    @ApiModelProperty("鑼冨洿涓嶇‘瀹氬害A")
+    private String aRangeUncertainty;
+
+    @ApiModelProperty("鑼冨洿涓嶇‘瀹氬害b")
+    private String bRangeUncertainty;
+
+    @ApiModelProperty("鑼冨洿涓嶇‘瀹氬害c")
+    private String cRangeUncertainty;
+
+    @ApiModelProperty("缁煎悎鍒ゅ畾")
+    private String judgment;
+
+    @ApiModelProperty("鏍告煡浜篿d")
+    private Integer checkerUserId;
+
+    @ApiModelProperty("鏍告煡浜�")
+    private String checkerUser;
+
+    @ApiModelProperty("鏍告煡鏃ユ湡")
+    private LocalDateTime checkerTime;
+
+    @ApiModelProperty("瀹℃牳浜篿d")
+    private Integer reviewUserId;
+
+    @ApiModelProperty("瀹℃牳浜�")
+    private String reviewUser;
+
+    @ApiModelProperty("瀹℃牳鐘舵��0,涓嶉�氳繃, 1閫氳繃")
+    private Integer reviewStatus;
+
+    @ApiModelProperty("瀹℃牳澶囨敞")
+    private String reviewRemark;
+
+    @ApiModelProperty("瀹℃牳鏃ユ湡")
+    private LocalDateTime reviewTime;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrastDetails.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrastDetails.java
new file mode 100644
index 0000000..cbe2c0f
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordContrastDetails.java
@@ -0,0 +1,70 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮璇︽儏琛�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:57
+ */
+@Getter
+@Setter
+@TableName("device_examine_record_contrast_details")
+@ApiModel(value = "DeviceExamineRecordContrastDetails瀵硅薄", description = "璁惧鏍告煡璁板綍瀵规瘮璇︽儏琛�")
+public class DeviceExamineRecordContrastDetails implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "record_contrast_details_id", type = IdType.AUTO)
+    private Integer recordContrastDetailsId;
+
+    @ApiModelProperty("璁惧鏍告煡璇︽儏id")
+    private Integer recordContrastId;
+
+    @ApiModelProperty("鏍告煡椤圭洰")
+    private String checkItems;
+
+    @ApiModelProperty("a浠櫒绀哄��")
+    private String indicationA;
+
+    @ApiModelProperty("b浠櫒绀哄��")
+    private String indicationB;
+
+    @ApiModelProperty("c浠櫒绀哄��")
+    private String indicationC;
+
+    @ApiModelProperty("宸��")
+    private String dValue;
+
+    @ApiModelProperty("鍋忓樊")
+    private String deviation;
+
+    @ApiModelProperty("鍒ゅ畾")
+    private String determine;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordDetail.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordDetail.java
new file mode 100644
index 0000000..f15c49d
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExamineRecordDetail.java
@@ -0,0 +1,70 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍璇︽儏琛�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:15:11
+ */
+@Getter
+@Setter
+@TableName("device_examine_record_detail")
+@ApiModel(value = "DeviceExamineRecordDetail瀵硅薄", description = "璁惧鏍告煡璁板綍璇︽儏琛�")
+public class DeviceExamineRecordDetail implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "record_detail_id", type = IdType.AUTO)
+    private Integer recordDetailId;
+
+    @ApiModelProperty("璁捐澶囨牳鏌ヨ褰昳d")
+    private Integer recordId;
+
+    @ApiModelProperty("娴嬭瘯鐐�")
+    private String testPoint;
+
+    @ApiModelProperty("鍐呭鍊�1")
+    private String dataValue1;
+
+    @ApiModelProperty("鍐呭鍊�2")
+    private String dataValue2;
+
+    @ApiModelProperty("鍐呭鍊�3")
+    private String dataValue3;
+
+    @ApiModelProperty("鍐呭鍊�4")
+    private String dataValue4;
+
+    @ApiModelProperty("鍐呭鍊�5")
+    private String dataValue5;
+
+    @ApiModelProperty("鍐呭鍊�6")
+    private String dataValue6;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExternalApply.java b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExternalApply.java
new file mode 100644
index 0000000..844619d
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/pojo/DeviceExternalApply.java
@@ -0,0 +1,123 @@
+package com.ruoyi.device.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 鍒╃敤澶栭儴璁惧鐢宠琛�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-17 10:28:43
+ */
+@Getter
+@Setter
+@TableName("device_external_apply")
+@ApiModel(value = "DeviceExternalApply瀵硅薄", description = "鍒╃敤澶栭儴璁惧鐢宠琛�")
+public class DeviceExternalApply{
+
+    @TableId(value = "external_apply_id", type = IdType.AUTO)
+    private Integer externalApplyId;
+
+    @ApiModelProperty("鍗曚綅鍚嶇О")
+    private String unitName;
+
+    @ApiModelProperty("鍦板潃")
+    private String address;
+
+    @ApiModelProperty("浠櫒鍚嶇О")
+    private String deviceName;
+
+    @ApiModelProperty("浠櫒鍨嬪彿")
+    private String deviceModel;
+
+    @ApiModelProperty("閰嶄欢")
+    private String parts;
+
+    @ApiModelProperty("瀵规柟浠櫒缂栧彿")
+    private String instrumentNumber;
+
+    @ApiModelProperty("鎶�鏈寚鏍�")
+    private String technicalIndex;
+
+    @ApiModelProperty("鎶�鏈姹�")
+    private String technicalRequirements;
+
+    @ApiModelProperty("鍒╃敤鍘熷洜")
+    private String useReason;
+
+    @ApiModelProperty("0鐢宠浜篿d")
+    private Integer applicantUserId;
+
+    @ApiModelProperty("0鐢宠浜�")
+    private String applicantUser;
+
+    @ApiModelProperty("0鐢宠鏃堕棿")
+    private LocalDate applicantDate;
+
+    @ApiModelProperty("1閮ㄩ棬璐熻矗浜烘剰瑙�")
+    private String departmentHeadOpinion;
+
+    @ApiModelProperty("1閮ㄩ棬璐熻矗浜篿d")
+    private Integer departmentHeadUserId;
+
+    @ApiModelProperty("1閮ㄩ棬璐熻矗浜�")
+    private String departmentHeadUser;
+
+    @ApiModelProperty("1閮ㄩ棬璐熻矗浜哄~鍐欐椂闂�")
+    private LocalDate departmentHeadDate;
+
+    @ApiModelProperty("2璁¢噺瀹ゆ剰瑙�")
+    private String meteringRoomOpinion;
+
+    @ApiModelProperty("2璁¢噺瀹や汉id")
+    private Integer meteringRoomUserId;
+
+    @ApiModelProperty("2璁¢噺瀹や汉")
+    private String meteringRoomUser;
+
+    @ApiModelProperty("2璁¢噺瀹や汉濉啓鏃堕棿")
+    private LocalDate meteringRoomDate;
+
+    @ApiModelProperty("3鎵瑰噯浜烘剰瑙�")
+    private String approverOpinion;
+
+    @ApiModelProperty("3鎵瑰噯浜篿d")
+    private Integer approverUserId;
+
+    @ApiModelProperty("3鎵瑰噯浜�")
+    private String approverUser;
+
+    @ApiModelProperty("3鎵瑰噯浜哄~鍐欐椂闂�")
+    private LocalDate approverDate;
+
+    @ApiModelProperty("鏄惁缁撴潫,0: 鏈粨鏉�, 1:缁撴潫")
+    private Integer isFinish;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @TableField(exist = false,select = false)
+    @ApiModelProperty("娴佺▼, 0:鐢宠, 1鐢宠閮ㄩ棬璐熻矗浜烘剰瑙�, 2:璁¢噺瀹ゆ剰瑙�, 3:鎵瑰噯浜�")
+    private Integer flowType;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanDetailsService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanDetailsService.java
new file mode 100644
index 0000000..e3a1924
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanDetailsService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝璇︽儏琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:16
+ */
+public interface DeviceExaminePlanDetailsService extends IService<DeviceExaminePlanDetails> {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanService.java
new file mode 100644
index 0000000..c06f9de
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExaminePlanService.java
@@ -0,0 +1,88 @@
+package com.ruoyi.device.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.device.dto.DeviceExaminePlanDto;
+import com.ruoyi.device.pojo.DeviceExaminePlan;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝涓昏〃 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:04
+ */
+public interface DeviceExaminePlanService extends IService<DeviceExaminePlan> {
+
+    /**
+     * 鏂板璁惧鏍告煡璁″垝
+     * @param examinePlanDto
+     * @return
+     */
+    boolean addDeviceExaminePlan(DeviceExaminePlanDto examinePlanDto);
+
+    /**
+     * 瀵煎叆璁惧鏍告煡璁″垝
+     * @param file
+     * @return
+     */
+    boolean importDeviceExaminePlan(MultipartFile file);
+
+    /**
+     * 鎻愪氦鎵瑰噯
+     * @param deviceExaminePlan
+     * @return
+     */
+    boolean submitRatifyDeviceExaminePlan(DeviceExaminePlan deviceExaminePlan);
+
+    /**
+     * 璁惧鏍告煡璁″垝鎵瑰噯
+     * @param DeviceExaminePlan
+     * @return
+     */
+    boolean ratifyDeviceExaminePlan(DeviceExaminePlan DeviceExaminePlan);
+
+    /**
+     * 璁惧鏍告煡璁″垝鍒楄〃
+     * @param page
+     * @param DeviceExaminePlan
+     * @return
+     */
+    IPage<DeviceExaminePlanDto> pageDeviceExaminePlan(Page page, DeviceExaminePlan DeviceExaminePlan);
+
+    /**
+     * 璁惧鏍告煡璁″垝璇︽儏鍒楄〃
+     * @param page
+     * @param DeviceExaminePlanDetails
+     * @return
+     */
+    IPage<DeviceExaminePlanDetails> pageDeviceExaminePlanDetail(Page page, DeviceExaminePlanDetails DeviceExaminePlanDetails);
+
+
+    /**
+     * 瀵煎嚭璁惧鏍告煡璁″垝
+     * @param deviceExaminePlanId 璁惧鏍告煡璁″垝id
+     * @param response 鍝嶅簲
+     */
+    void exportDeviceExaminePlanDetail(Integer deviceExaminePlanId, HttpServletResponse response);
+
+    /**
+     * 鎵归噺淇敼璁惧鏍告煡璁″垝
+     * @param examinePlanDto
+     * @return
+     */
+    boolean updateDeviceExaminePlan(DeviceExaminePlanDto examinePlanDto);
+
+    /**
+     * 鏌ヨ璁惧鏍告煡璁″垝璇︽儏
+     * @param planId
+     * @return
+     */
+    DeviceExaminePlanDto getDeviceExaminePlan(Integer planId);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastDetailsService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastDetailsService.java
new file mode 100644
index 0000000..da272d0
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastDetailsService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrastDetails;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮璇︽儏琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:57
+ */
+public interface DeviceExamineRecordContrastDetailsService extends IService<DeviceExamineRecordContrastDetails> {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastService.java
new file mode 100644
index 0000000..58110a7
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordContrastService.java
@@ -0,0 +1,46 @@
+package com.ruoyi.device.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.device.dto.DeviceExamineRecordContrastDto;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrast;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:43
+ */
+public interface DeviceExamineRecordContrastService extends IService<DeviceExamineRecordContrast> {
+
+    /**
+     * 鏌ヨ鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    DeviceExamineRecordContrastDto getExamineRecordContrast(Integer planDetailsId);
+
+    /**
+     * 鏂板鏍告煡瀵规瘮璁板綍
+     * @return
+     *
+     */
+    boolean addExamineRecordContrast(DeviceExamineRecordContrastDto deviceExamineRecordContrastDto);
+
+    /**
+     * 瀹℃牳鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    boolean reviewExamineRecordContrast(DeviceExamineRecordContrastDto deviceExamineRecordContrastDto);
+
+    /**
+     * 瀵煎嚭瀹℃牳鏍告煡瀵规瘮璁板綍
+     *
+     * @param recordId 瀹℃牳鏍告煡瀵规瘮璁板綍id
+     * @param response
+     * @return
+     */
+    void exportReviewExamineRecordContrast(Integer recordId, HttpServletResponse response);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordDetailService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordDetailService.java
new file mode 100644
index 0000000..09fd611
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordDetailService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.device.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.device.pojo.DeviceExamineRecordDetail;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍璇︽儏琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:15:11
+ */
+public interface DeviceExamineRecordDetailService extends IService<DeviceExamineRecordDetail> {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordService.java
new file mode 100644
index 0000000..91c7bd7
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExamineRecordService.java
@@ -0,0 +1,43 @@
+package com.ruoyi.device.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.device.dto.DeviceExamineRecordDto;
+import com.ruoyi.device.pojo.DeviceExamineRecord;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:28
+ */
+public interface DeviceExamineRecordService extends IService<DeviceExamineRecord> {
+
+    /**
+     * 鏌ヨ鏍告煡璁板綍
+     * @return
+     */
+    DeviceExamineRecordDto getExamineRecord(Integer planDetailsId);
+
+    /**
+     * 鏂板鏍告煡璁板綍
+     * @return
+     */
+    boolean addExamineRecord(DeviceExamineRecordDto deviceExamineRecordDto);
+
+    /**
+     * 澶嶆牳鏍告煡璁板綍
+     * @return
+     */
+    boolean reviewExamineRecord(DeviceExamineRecordDto deviceExamineRecordDto);
+
+    /**
+     * 瀵煎嚭澶嶆牳鏍告煡璁板綍
+     * @param planDetailsId
+     * @param response 鍝嶅簲
+     */
+    void exportReviewExamineRecordDetail(Integer planDetailsId, HttpServletResponse response);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExternalApplyService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExternalApplyService.java
new file mode 100644
index 0000000..670f7b9
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceExternalApplyService.java
@@ -0,0 +1,42 @@
+package com.ruoyi.device.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.device.pojo.DeviceExternalApply;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ * 鍒╃敤澶栭儴璁惧鐢宠琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-17 10:28:43
+ */
+public interface DeviceExternalApplyService extends IService<DeviceExternalApply> {
+
+    /**
+     * 鍒╃敤澶栭儴璁惧鐢宠鍒楄〃
+     * @param page
+     * @param deviceExternalApply
+     * @return
+     */
+    IPage<DeviceExternalApply> pageDeviceExternalApply(Page page, DeviceExternalApply deviceExternalApply);
+
+    /**
+     * 鏂板鍒╃敤澶栭儴璁惧鐢宠
+     * @param deviceExternalApply
+     * @return
+     */
+    boolean addDeviceExternalApply(DeviceExternalApply deviceExternalApply);
+
+    /**
+     * 瀵煎嚭鍒╃敤澶栭儴璁惧鐢宠
+     *
+     * @param externalApplyId 澶栭儴璁惧鐢宠id
+     * @param response
+     */
+    void exportDeviceExternalApply(Integer externalApplyId, HttpServletResponse response);
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanDetailsServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanDetailsServiceImpl.java
new file mode 100644
index 0000000..c7fcca5
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanDetailsServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.device.mapper.DeviceExaminePlanDetailsMapper;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import com.ruoyi.device.service.DeviceExaminePlanDetailsService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝璇︽儏琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:16
+ */
+@Service
+public class DeviceExaminePlanDetailsServiceImpl extends ServiceImpl<DeviceExaminePlanDetailsMapper, DeviceExaminePlanDetails> implements DeviceExaminePlanDetailsService {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanServiceImpl.java
new file mode 100644
index 0000000..959c349
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExaminePlanServiceImpl.java
@@ -0,0 +1,346 @@
+package com.ruoyi.device.service.impl;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.ruoyi.common.core.domain.entity.InformationNotification;
+import com.ruoyi.common.core.domain.entity.User;
+import com.ruoyi.common.utils.QueryWrappers;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.WxCpUtils;
+import com.ruoyi.device.dto.DeviceExaminePlanDetailsDto;
+import com.ruoyi.device.dto.DeviceExaminePlanDto;
+import com.ruoyi.device.excel.upload.DeviceExaminePlanUpload;
+import com.ruoyi.device.mapper.DeviceExaminePlanDetailsMapper;
+import com.ruoyi.device.mapper.DeviceExaminePlanMapper;
+import com.ruoyi.device.mapper.DeviceMapper;
+import com.ruoyi.device.pojo.Device;
+import com.ruoyi.device.pojo.DeviceExaminePlan;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import com.ruoyi.device.service.DeviceExaminePlanDetailsService;
+import com.ruoyi.device.service.DeviceExaminePlanService;
+import com.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
+import com.ruoyi.inspect.util.UserUtils;
+import com.ruoyi.system.mapper.UserMapper;
+import com.ruoyi.system.service.InformationNotificationService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁″垝涓昏〃 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:04
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class DeviceExaminePlanServiceImpl extends ServiceImpl<DeviceExaminePlanMapper, DeviceExaminePlan> implements DeviceExaminePlanService {
+
+    @Resource
+    private DeviceExaminePlanDetailsMapper deviceExaminePlanDetailsMapper;
+    @Resource
+    private DeviceExaminePlanDetailsService deviceExaminePlanDetailsService;
+    @Resource
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+    @Resource
+    private InformationNotificationService informationNotificationService;
+    @Resource
+    private DeviceMapper deviceMapper;
+    @Resource
+    private UserMapper userMapper;
+
+    /**
+     * 鏂板璁惧鏍告煡璁″垝
+     * @param examinePlanDto
+     * @return
+     */
+    @Override
+    public boolean addDeviceExaminePlan(DeviceExaminePlanDto examinePlanDto) {
+        // 褰撳墠鐧诲綍鐢ㄦ埛
+        Integer userId = SecurityUtils.getUserId().intValue();
+        // 鏂囦欢鍚嶇О
+        examinePlanDto.setWriteUserId(userId);
+        examinePlanDto.setWriteTime(LocalDateTime.now());
+        baseMapper.insert(examinePlanDto);
+
+        // 娣诲姞璇︽儏
+        if (CollectionUtils.isNotEmpty(examinePlanDto.getExaminePlanDetailsList())) {
+            for (DeviceExaminePlanDetails deviceExaminePlanDetails : examinePlanDto.getExaminePlanDetailsList()) {
+                deviceExaminePlanDetails.setPlanId(examinePlanDto.getPlanId());
+            }
+            deviceExaminePlanDetailsService.saveBatch(examinePlanDto.getExaminePlanDetailsList());
+        }
+        return true;
+    }
+
+    /**
+     * 瀵煎叆璁惧鏍告煡璁″垝
+     * @param file
+     * @return
+     */
+    @Override
+    public boolean importDeviceExaminePlan(MultipartFile file) {
+        // 褰撳墠鐧诲綍鐢ㄦ埛
+        Integer userId = SecurityUtils.getUserId().intValue();
+        // 鏂囦欢鍚嶇О
+        String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
+        DeviceExaminePlan examinePlan = new DeviceExaminePlan();
+        examinePlan.setPlanName(fileName);
+        examinePlan.setWriteUserId(userId);
+        examinePlan.setWriteTime(LocalDateTime.now());
+        baseMapper.insert(examinePlan);
+
+        List<DeviceExaminePlanDetails> examinePlanDetails = new ArrayList<>();
+        // 瀵煎叆闄勪欢鍐呭
+        try {
+            // excel瑙f瀽
+            EasyExcel.read(file.getInputStream(), DeviceExaminePlanUpload.class, new AnalysisEventListener<DeviceExaminePlanUpload>() {
+                @Override
+                public void invoke(DeviceExaminePlanUpload detailsUpload, AnalysisContext analysisContext) {
+                    // 鍒ゆ柇鏄惁涓虹┖
+                    if (StringUtils.isNotBlank(detailsUpload.getDeviceName()) &&
+                            StringUtils.isNotBlank(detailsUpload.getDeviceNumber())) {
+                        // 瀵硅薄澶嶅埗
+                        DeviceExaminePlanDetails planDetails = new DeviceExaminePlanDetails();
+                        BeanUtils.copyProperties(detailsUpload, planDetails);
+
+                        planDetails.setPlanId(examinePlan.getPlanId());
+                        examinePlanDetails.add(planDetails);
+                    }
+                }
+
+                @Override
+                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+
+                }
+            }).sheet().doRead();
+            for (DeviceExaminePlanDetails examinePlanDetail : examinePlanDetails) {
+                Device device = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery()
+                        .eq(Device::getManagementNumber, examinePlanDetail.getDeviceNumber().trim()));
+                if (device == null) {
+                    throw new ErrorException("璁惧缂栧彿" + examinePlanDetail.getDeviceNumber() + "鏈煡璇㈠埌璁惧, 璇烽噸鏂板鍏�");
+                }
+                User user = userMapper.selectOne(Wrappers.<User>lambdaQuery()
+                        .eq(User::getName, examinePlanDetail.getCheckChargerUser()));
+                if (user == null) {
+                    throw new ErrorException("璁惧缂栧彿" + examinePlanDetail.getDeviceNumber() + "鏈煡璇㈠埌鏍告煡浜�");
+                }
+                examinePlanDetail.setDeviceId(device.getId());
+                examinePlanDetail.setCheckChargerUserId(user.getId());
+            }
+
+            deviceExaminePlanDetailsService.saveBatch(examinePlanDetails);
+
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return true;
+    }
+
+    /**
+     * 鎻愪氦鎵瑰噯
+     * @param deviceExaminePlan
+     * @return
+     */
+    @Override
+    public boolean submitRatifyDeviceExaminePlan(DeviceExaminePlan deviceExaminePlan) {
+        baseMapper.update(null, Wrappers.<DeviceExaminePlan>lambdaUpdate()
+                .eq(DeviceExaminePlan::getPlanId, deviceExaminePlan.getPlanId())
+                .set(DeviceExaminePlan::getRatifyUserId, deviceExaminePlan.getRatifyUserId())
+                .set(DeviceExaminePlan::getRatifyRemark, null)
+                .set(DeviceExaminePlan::getRatifyStatus, null)
+                .set(DeviceExaminePlan::getRatifyTime, null)
+        );
+
+        DeviceExaminePlan examinePlan = baseMapper.selectById(deviceExaminePlan.getPlanId());
+
+        // 鍙戦�佹秷鎭�
+        Integer userId = SecurityUtils.getUserId().intValue();
+        User user = userMapper.selectById(userId);
+        // 娑堟伅鍙戦��
+        InformationNotification info = new InformationNotification();
+        // 鍙戦�佷汉
+        info.setCreateUser(user.getName());
+        info.setMessageType("6");
+        info.setTheme("CNAS璁惧鏍告煡璁″垝鎵瑰噯閫氱煡");
+        info.setContent(examinePlan.getPlanName() + "鐨勮澶囨牳鏌ヨ鍒掑緟鎵瑰噯");
+        info.setSenderId(userId);
+        // 鎺ユ敹浜�
+        info.setConsigneeId(examinePlan.getRatifyUserId());
+        info.setJumpPath("a6-device");
+        informationNotificationService.addInformationNotification(info);
+
+        // 鍙戦�佷紒涓氬井淇¢�氱煡
+        threadPoolTaskExecutor.execute(() -> {
+            // 鏌ヨ鎺ユ敹浜�
+            User personnel = userMapper.selectById(examinePlan.getRatifyUserId());
+
+            String message = "";
+            message += "CNAS璁惧鏍告煡璁″垝鎵瑰噯閫氱煡";
+            message += "\n璇峰幓璧勬簮绠$悊-璁惧涓�灞傜洰褰�-璁惧鏍告煡璁″垝濉啓";
+            message += "\n" + examinePlan.getPlanName() + "鐨勬牎鍑嗘牳鏌ュ垝寰呮壒鍑�";
+            //鍙戦�佷紒涓氬井淇℃秷鎭�氱煡
+            try {
+                WxCpUtils.inform(personnel.getAccount(), message, null);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        });
+        return false;
+    }
+
+    /**
+     * 璁惧鏍告煡璁″垝鎵瑰噯
+     * @param deviceExaminePlan
+     * @return
+     */
+    @Override
+    public boolean ratifyDeviceExaminePlan(DeviceExaminePlan deviceExaminePlan) {
+        // 褰撳墠鐧诲綍鐢ㄦ埛
+        baseMapper.update(null, Wrappers.<DeviceExaminePlan>lambdaUpdate()
+                .eq(DeviceExaminePlan::getPlanId, deviceExaminePlan.getPlanId())
+                .set(DeviceExaminePlan::getRatifyRemark, deviceExaminePlan.getRatifyRemark())
+                .set(DeviceExaminePlan::getRatifyStatus, deviceExaminePlan.getRatifyStatus())
+                .set(DeviceExaminePlan::getRatifyTime, LocalDateTime.now())
+        );
+        return true;
+    }
+
+    /**
+     * 璁惧鏍告煡璁″垝鍒楄〃
+     * @param page
+     * @param deviceExaminePlan
+     * @return
+     */
+    @Override
+    public IPage<DeviceExaminePlanDto> pageDeviceExaminePlan(Page page, DeviceExaminePlan deviceExaminePlan) {
+        return baseMapper.deviceExaminePlanDetailsMapper(page, QueryWrappers.queryWrappers(deviceExaminePlan));
+    }
+
+    /**
+     * 璁惧鏍告煡璁″垝璇︽儏鍒楄〃
+     * @param page
+     * @param deviceExaminePlanDetails
+     * @return
+     */
+    @Override
+    public IPage<DeviceExaminePlanDetails> pageDeviceExaminePlanDetail(Page page, DeviceExaminePlanDetails deviceExaminePlanDetails) {
+        if (deviceExaminePlanDetails.getPlanId() == null) {
+            return new Page();
+        }
+        return deviceExaminePlanDetailsMapper.pageDeviceExaminePlanDetail(page, QueryWrappers.queryWrappers(deviceExaminePlanDetails));
+    }
+
+    /**
+     * 瀵煎嚭璁惧鏍告煡璁″垝
+     * @param deviceExaminePlanId 璁惧鏍告煡璁″垝id
+     * @param response 鍝嶅簲浣�
+     */
+    @Override
+    public void exportDeviceExaminePlanDetail(Integer deviceExaminePlanId, HttpServletResponse response) {
+        // 鏌ヨ璁惧鏍告煡璁″垝
+        DeviceExaminePlanDto deviceExaminePlanDto = baseMapper.selectExamineExaminePlanDto(deviceExaminePlanId);
+
+        // 鏌ヨ璁惧鏍告煡璁″垝璇︽儏
+        List<DeviceExaminePlanDetails> deviceExaminePlanDetailsList = deviceExaminePlanDetailsMapper.selectList(Wrappers.<DeviceExaminePlanDetails>lambdaQuery().eq(DeviceExaminePlanDetails::getPlanId, deviceExaminePlanId));
+        // 璁剧疆搴忓彿
+        ArrayList<DeviceExaminePlanDetailsDto> deviceExaminePlanDetailsDtoList = new ArrayList<>();
+        deviceExaminePlanDetailsList.forEach(deviceExamineRecordContrastDetail -> {
+            DeviceExaminePlanDetailsDto deviceExaminePlanDetailsDto = new DeviceExaminePlanDetailsDto();
+            BeanUtils.copyProperties(deviceExamineRecordContrastDetail, deviceExaminePlanDetailsDto);
+            deviceExaminePlanDetailsDto.setIndex(deviceExaminePlanDetailsList.indexOf(deviceExamineRecordContrastDetail) + 1);
+            deviceExaminePlanDetailsDtoList.add(deviceExaminePlanDetailsDto);
+        });
+
+        // 鑾峰彇璺緞
+        InputStream inputStream = this.getClass().getResourceAsStream("/static/word/examine-plan-detail.docx");
+        Configure configure = Configure.builder()
+                .bind("deviceExaminePlanDetailsDtoList", new HackLoopTableRenderPolicy())
+                .build();
+        XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(
+                new HashMap<String, Object>() {{
+                    put("deviceExaminePlan", deviceExaminePlanDto);
+                    put("deviceExaminePlanDetailsDtoList", deviceExaminePlanDetailsDtoList);
+                    //鑾峰彇鏍告煡浜虹殑绛惧悕鍦板潃
+                    put("writeUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExaminePlanDto.getWriteUserId()));
+                    //鑾峰彇瀹℃煡浜虹殑绛惧悕鍦板潃
+                    put("reviewUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExaminePlanDto.getRatifyUserId()));
+                }});
+
+        try {
+            response.setContentType("application/msword");
+            String fileName = URLEncoder.encode(
+                    "璁惧鏍告煡璁″垝", "UTF-8");
+            response.setHeader("Content-disposition",
+                    "attachment;filename=" + fileName + ".docx");
+            OutputStream os = response.getOutputStream();
+            template.write(os);
+            os.flush();
+            os.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("瀵煎嚭澶辫触");
+        }
+    }
+
+    @Override
+    public boolean updateDeviceExaminePlan(DeviceExaminePlanDto examinePlanDto) {
+        // 褰撳墠鐧诲綍鐢ㄦ埛
+        Integer userId = SecurityUtils.getUserId().intValue();
+        // 鏂囦欢鍚嶇О
+        examinePlanDto.setWriteUserId(userId);
+        examinePlanDto.setWriteTime(LocalDateTime.now());
+        baseMapper.updateById(examinePlanDto);
+
+        deviceExaminePlanDetailsService.remove(Wrappers.<DeviceExaminePlanDetails>lambdaQuery()
+                .eq(DeviceExaminePlanDetails::getPlanId, examinePlanDto.getPlanId()));
+
+        // 娣诲姞璇︽儏
+        if (CollectionUtils.isNotEmpty(examinePlanDto.getExaminePlanDetailsList())) {
+            for (DeviceExaminePlanDetails deviceExaminePlanDetails : examinePlanDto.getExaminePlanDetailsList()) {
+                deviceExaminePlanDetails.setPlanId(examinePlanDto.getPlanId());
+            }
+            deviceExaminePlanDetailsService.saveBatch(examinePlanDto.getExaminePlanDetailsList());
+        }
+        return true;
+    }
+
+    @Override
+    public DeviceExaminePlanDto getDeviceExaminePlan(Integer planId) {
+        DeviceExaminePlan examinePlan = baseMapper.selectById(planId);
+        DeviceExaminePlanDto deviceExaminePlanDto = new DeviceExaminePlanDto();
+        BeanUtils.copyProperties(examinePlan, deviceExaminePlanDto);
+        // 鏌ヨ璇︽儏
+        List<DeviceExaminePlanDetails> list = deviceExaminePlanDetailsService.list(Wrappers.<DeviceExaminePlanDetails>lambdaQuery()
+                .eq(DeviceExaminePlanDetails::getPlanId, planId)
+                .orderByAsc(DeviceExaminePlanDetails::getCheckTime));
+        deviceExaminePlanDto.setExaminePlanDetailsList(list);
+
+        return deviceExaminePlanDto;
+    }
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastDetailsServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastDetailsServiceImpl.java
new file mode 100644
index 0000000..db6c58a
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastDetailsServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.device.mapper.DeviceExamineRecordContrastDetailsMapper;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrastDetails;
+import com.ruoyi.device.service.DeviceExamineRecordContrastDetailsService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮璇︽儏琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:57
+ */
+@Service
+public class DeviceExamineRecordContrastDetailsServiceImpl extends ServiceImpl<DeviceExamineRecordContrastDetailsMapper, DeviceExamineRecordContrastDetails> implements DeviceExamineRecordContrastDetailsService {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastServiceImpl.java
new file mode 100644
index 0000000..2b2343b
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordContrastServiceImpl.java
@@ -0,0 +1,193 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.ruoyi.common.core.domain.entity.User;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.device.dto.DeviceExamineRecordContrastDetailsDto;
+import com.ruoyi.device.dto.DeviceExamineRecordContrastDto;
+import com.ruoyi.device.mapper.DeviceExaminePlanDetailsMapper;
+import com.ruoyi.device.mapper.DeviceExamineRecordContrastMapper;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrast;
+import com.ruoyi.device.pojo.DeviceExamineRecordContrastDetails;
+import com.ruoyi.device.service.DeviceExamineRecordContrastDetailsService;
+import com.ruoyi.device.service.DeviceExamineRecordContrastService;
+import com.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
+import com.ruoyi.inspect.util.UserUtils;
+import com.ruoyi.system.mapper.UserMapper;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍瀵规瘮琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:43
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class DeviceExamineRecordContrastServiceImpl extends ServiceImpl<DeviceExamineRecordContrastMapper, DeviceExamineRecordContrast> implements DeviceExamineRecordContrastService {
+
+    @Resource
+    private DeviceExamineRecordContrastDetailsService deviceExamineRecordContrastDetailsService;
+    @Resource
+    private DeviceExaminePlanDetailsMapper deviceExaminePlanDetailsMapper;
+    @Resource
+    private UserMapper userMapper;
+    /**
+     * 鏌ヨ鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    @Override
+    public DeviceExamineRecordContrastDto getExamineRecordContrast(Integer planDetailsId) {
+        DeviceExamineRecordContrastDto contrastDto = baseMapper.getExamineRecordContrast(planDetailsId);
+        // 鍒ゆ柇鏄惁涓虹┖
+        if (contrastDto == null) {
+            contrastDto = new DeviceExamineRecordContrastDto();
+            // 鏌ヨ璁惧璇︽儏
+            DeviceExaminePlanDetails deviceExaminePlanDetails = deviceExaminePlanDetailsMapper.selectById(planDetailsId);
+            contrastDto.setPlanDetailsId(deviceExaminePlanDetails.getPlanDetailsId());
+
+        } else {
+            // 鏌ヨ璇︽儏
+            List<DeviceExamineRecordContrastDetails> list = deviceExamineRecordContrastDetailsService.list(Wrappers.<DeviceExamineRecordContrastDetails>lambdaQuery()
+                    .eq(DeviceExamineRecordContrastDetails::getRecordContrastId, contrastDto.getRecordContrastId()));
+            contrastDto.setRecordContrastDetailsList(list);
+        }
+
+        return contrastDto;
+    }
+
+    /**
+     * 鏂板鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    @Override
+    public boolean addExamineRecordContrast(DeviceExamineRecordContrastDto dto) {
+        if (dto.getPlanDetailsId() == null) {
+            throw new ErrorException("缂哄皯璁″垝璇︾粏淇℃伅id");
+        }
+        if (dto.getRecordContrastId() == null) {
+            Integer userId = SecurityUtils.getUserId().intValue();
+            User user = userMapper.selectById(userId);
+            dto.setCheckerUserId(userId);
+            dto.setCheckerUser(user.getName());
+
+            // 鏌ヨ瀹℃煡浜篿d
+            if (dto.getReviewUserId() != null) {
+                User reviewUser = userMapper.selectById(dto.getReviewUserId());
+                dto.setReviewUser(reviewUser.getName());
+            }
+        }
+        this.saveOrUpdate(dto);
+
+        // 鍒犻櫎鍏ㄩ儴璇︽儏
+        deviceExamineRecordContrastDetailsService.remove(Wrappers.<DeviceExamineRecordContrastDetails>lambdaQuery()
+                .eq(DeviceExamineRecordContrastDetails::getRecordContrastId, dto.getRecordContrastId()));
+        //娣诲姞璇︽儏
+        if (CollectionUtils.isNotEmpty(dto.getRecordContrastDetailsList())) {
+            for (DeviceExamineRecordContrastDetails details : dto.getRecordContrastDetailsList()) {
+                details.setRecordContrastId(dto.getRecordContrastId());
+            }
+            deviceExamineRecordContrastDetailsService.saveBatch(dto.getRecordContrastDetailsList());
+        }
+        return false;
+    }
+
+
+    /**
+     * 瀹℃牳鏍告煡瀵规瘮璁板綍
+     * @return
+     */
+    @Override
+    public boolean reviewExamineRecordContrast(DeviceExamineRecordContrastDto dto) {
+        if (dto.getPlanDetailsId() == null) {
+            throw new ErrorException("缂哄皯璁″垝璇︾粏淇℃伅id");
+        }
+        LambdaUpdateWrapper<DeviceExamineRecordContrast> wrapper = Wrappers.<DeviceExamineRecordContrast>lambdaUpdate()
+                .eq(DeviceExamineRecordContrast::getPlanDetailsId, dto.getPlanDetailsId())
+                .set(DeviceExamineRecordContrast::getReviewStatus, dto.getReviewStatus())
+                .set(DeviceExamineRecordContrast::getReviewRemark, dto.getReviewRemark())
+                .set(DeviceExamineRecordContrast::getReviewTime, LocalDateTime.now());
+        // 涓�0娓呴櫎瀹℃牳浜�
+        if (dto.getReviewStatus().equals(0)) {
+            wrapper.set(DeviceExamineRecordContrast::getReviewUserId, null)
+                    .set(DeviceExamineRecordContrast::getReviewUser, null);
+        }
+
+        this.update(wrapper);
+        return true;
+    }
+
+    /**
+     * 瀵煎嚭瀹℃牳鏍告煡瀵规瘮璁板綍
+     *
+     * @param planDetailsId 璇︽儏id
+     * @param response
+     */
+    @Override
+    public void exportReviewExamineRecordContrast(Integer planDetailsId, HttpServletResponse response) {
+        // 鏌ヨ瀵规瘮璁板綍
+        DeviceExamineRecordContrastDto deviceExamineRecordContrast = baseMapper.selectExamineRecordContrastDto(planDetailsId);
+
+        // 鏌ヨ瀵规瘮璁板綍璇︽儏
+        List<DeviceExamineRecordContrastDetails> deviceExamineRecordContrastDetailList = deviceExamineRecordContrastDetailsService.list(Wrappers.<DeviceExamineRecordContrastDetails>lambdaQuery().eq(DeviceExamineRecordContrastDetails::getRecordContrastId, deviceExamineRecordContrast.getRecordContrastId()));
+        // 璁剧疆搴忓彿
+        ArrayList<DeviceExamineRecordContrastDetailsDto> deviceExamineRecordContrastDetailsDtoList = new ArrayList<>();
+        deviceExamineRecordContrastDetailList.forEach(deviceExamineRecordContrastDetail -> {
+            DeviceExamineRecordContrastDetailsDto deviceExamineRecordContrastDetailsDto = new DeviceExamineRecordContrastDetailsDto();
+            BeanUtils.copyProperties(deviceExamineRecordContrastDetail, deviceExamineRecordContrastDetailsDto);
+            deviceExamineRecordContrastDetailsDto.setIndex(deviceExamineRecordContrastDetailList.indexOf(deviceExamineRecordContrastDetail) + 1);
+            deviceExamineRecordContrastDetailsDtoList.add(deviceExamineRecordContrastDetailsDto);
+        });
+
+        // 鑾峰彇璺緞
+        InputStream inputStream = this.getClass().getResourceAsStream("/static/word/review-examine-record-contrast.docx");
+        Configure configure = Configure.builder()
+                .bind("deviceExamineRecordContrastDetailsDtoList", new HackLoopTableRenderPolicy())
+                .build();
+        XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(
+                new HashMap<String, Object>() {{
+                    put("deviceExamineRecordContrast", deviceExamineRecordContrast);
+                    put("deviceExamineRecordContrastDetailsDtoList", deviceExamineRecordContrastDetailsDtoList);
+                    //鑾峰彇鏍告煡浜虹殑绛惧悕鍦板潃
+                    put("checkerUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordContrast.getCheckerUserId()));
+                    //鑾峰彇瀹℃煡浜虹殑绛惧悕鍦板潃
+                    put("reviewUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordContrast.getReviewUserId()));
+                }});
+
+        try {
+            response.setContentType("application/msword");
+            String fileName = URLEncoder.encode(
+                    "瀹℃牳鏍告煡瀵规瘮璁板綍", "UTF-8");
+            response.setHeader("Content-disposition",
+                    "attachment;filename=" + fileName + ".docx");
+            OutputStream os = response.getOutputStream();
+            template.write(os);
+            os.flush();
+            os.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("瀵煎嚭澶辫触");
+        }
+    }
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordDetailServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordDetailServiceImpl.java
new file mode 100644
index 0000000..1ef62d5
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordDetailServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.device.mapper.DeviceExamineRecordDetailMapper;
+import com.ruoyi.device.pojo.DeviceExamineRecordDetail;
+import com.ruoyi.device.service.DeviceExamineRecordDetailService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍璇︽儏琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:15:11
+ */
+@Service
+public class DeviceExamineRecordDetailServiceImpl extends ServiceImpl<DeviceExamineRecordDetailMapper, DeviceExamineRecordDetail> implements DeviceExamineRecordDetailService {
+
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordServiceImpl.java
new file mode 100644
index 0000000..afb5242
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExamineRecordServiceImpl.java
@@ -0,0 +1,198 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.ruoyi.common.core.domain.entity.User;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.device.dto.DeviceExamineRecordDto;
+import com.ruoyi.device.mapper.DeviceExaminePlanDetailsMapper;
+import com.ruoyi.device.mapper.DeviceExamineRecordMapper;
+import com.ruoyi.device.mapper.DeviceMapper;
+import com.ruoyi.device.pojo.Device;
+import com.ruoyi.device.pojo.DeviceExaminePlanDetails;
+import com.ruoyi.device.pojo.DeviceExamineRecord;
+import com.ruoyi.device.pojo.DeviceExamineRecordDetail;
+import com.ruoyi.device.service.DeviceExamineRecordDetailService;
+import com.ruoyi.device.service.DeviceExamineRecordService;
+import com.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
+import com.ruoyi.inspect.util.UserUtils;
+import com.ruoyi.system.mapper.UserMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <p>
+ * 璁惧鏍告煡璁板綍琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-16 07:14:28
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class DeviceExamineRecordServiceImpl extends ServiceImpl<DeviceExamineRecordMapper, DeviceExamineRecord> implements DeviceExamineRecordService {
+
+    @Resource
+    private DeviceExamineRecordDetailService deviceExamineRecordDetailService;
+    @Resource
+    private DeviceExaminePlanDetailsMapper deviceExaminePlanDetailsMapper;
+    @Resource
+    private DeviceMapper deviceMapper;
+    @Resource
+    private UserMapper userMapper;
+
+    /**
+     * 鏌ヨ鏍告煡璁板綍
+     *
+     * @return
+     */
+    @Override
+    public DeviceExamineRecordDto getExamineRecord(Integer planDetailsId) {
+        DeviceExamineRecordDto deviceExamineRecord = baseMapper.getExamineRecord(planDetailsId);
+
+        // 鍒ゆ柇鏄惁涓虹┖
+        if (deviceExamineRecord == null) {
+            deviceExamineRecord = new DeviceExamineRecordDto();
+            // 鏌ヨ璁惧璇︽儏
+            DeviceExaminePlanDetails deviceExaminePlanDetails = deviceExaminePlanDetailsMapper.selectById(planDetailsId);
+            Device device = deviceMapper.selectById(deviceExaminePlanDetails.getDeviceId());
+            if (device != null) {
+                deviceExamineRecord.setDeviceName(device.getDeviceName());
+                deviceExamineRecord.setDeviceNumber(device.getManagementNumber());
+                deviceExamineRecord.setPlanDetailsId(deviceExaminePlanDetails.getPlanDetailsId());
+            }
+        } else {
+            // 鏌ヨ璇︽儏
+            List<DeviceExamineRecordDetail> list = deviceExamineRecordDetailService.list(Wrappers.<DeviceExamineRecordDetail>lambdaQuery()
+                    .eq(DeviceExamineRecordDetail::getRecordId, deviceExamineRecord.getRecordId()));
+            deviceExamineRecord.setRecordDetailList(list);
+        }
+
+        return deviceExamineRecord;
+    }
+
+    /**
+     * 鏂板鏍告煡璁板綍
+     *
+     * @return
+     */
+    @Override
+    public boolean addExamineRecord(DeviceExamineRecordDto deviceExamineRecordDto) {
+        if (deviceExamineRecordDto.getPlanDetailsId() == null) {
+            throw new ErrorException("缂哄皯璁″垝璇︾粏淇℃伅id");
+        }
+        if (deviceExamineRecordDto.getRecordId() == null) {
+            Integer userId = SecurityUtils.getUserId().intValue();
+            User user = userMapper.selectById(SecurityUtils.getUserId());
+            deviceExamineRecordDto.setCheckerUserId(userId);
+            deviceExamineRecordDto.setCheckerUser(user.getName());
+
+            // 鏌ヨ瀹℃煡浜篿d
+            if (deviceExamineRecordDto.getReviewUserId() != null) {
+                User reviewUser = userMapper.selectById(deviceExamineRecordDto.getReviewUserId());
+                deviceExamineRecordDto.setReviewUser(reviewUser.getName());
+            }
+
+        }
+        this.saveOrUpdate(deviceExamineRecordDto);
+
+        // 鍒犻櫎鍏ㄩ儴璇︽儏
+        deviceExamineRecordDetailService.remove(Wrappers.<DeviceExamineRecordDetail>lambdaQuery()
+                .eq(DeviceExamineRecordDetail::getRecordId, deviceExamineRecordDto.getRecordId()));
+        //娣诲姞璇︽儏
+        if (CollectionUtils.isNotEmpty(deviceExamineRecordDto.getRecordDetailList())) {
+            for (DeviceExamineRecordDetail deviceExamineRecordDetail : deviceExamineRecordDto.getRecordDetailList()) {
+                deviceExamineRecordDetail.setRecordId(deviceExamineRecordDto.getRecordId());
+            }
+            deviceExamineRecordDetailService.saveBatch(deviceExamineRecordDto.getRecordDetailList());
+        }
+
+        return true;
+    }
+
+
+    /**
+     * 澶嶆牳鏍告煡璁板綍
+     *
+     * @return
+     */
+    @Override
+    public boolean reviewExamineRecord(DeviceExamineRecordDto dto) {
+        if (dto.getPlanDetailsId() == null) {
+            throw new ErrorException("缂哄皯璁″垝璇︾粏淇℃伅id");
+        }
+        LambdaUpdateWrapper<DeviceExamineRecord> wrapper = Wrappers.<DeviceExamineRecord>lambdaUpdate()
+                .eq(DeviceExamineRecord::getPlanDetailsId, dto.getPlanDetailsId())
+                .set(DeviceExamineRecord::getReviewStatus, dto.getReviewStatus())
+                .set(DeviceExamineRecord::getReviewRemark, dto.getReviewRemark());
+
+        // 涓�0娓呴櫎瀹℃牳浜�
+        if (dto.getReviewStatus().equals(0)) {
+            wrapper.set(DeviceExamineRecord::getReviewUserId, null)
+                    .set(DeviceExamineRecord::getReviewUser, null);
+        }
+
+        this.update(wrapper);
+        return true;
+    }
+
+    /**
+     * 瀵煎嚭澶嶆牳鏍告煡璁板綍
+     *
+     * @param planDetailsId 澶嶆牳鏍告煡璁板綍id
+     * @return
+     */
+    @Override
+    public void exportReviewExamineRecordDetail(Integer planDetailsId, HttpServletResponse response) {
+        // 鏌ヨ澶嶆牳鏍告煡璁板綍
+        DeviceExamineRecordDto deviceExamineRecordDto = baseMapper.selectReviewExamineRecordDto(planDetailsId);
+
+        // 鏌ヨ澶嶆牳鏍告煡璁板綍璇︽儏
+        List<DeviceExamineRecordDetail> deviceExamineRecordDetailList = deviceExamineRecordDetailService.list(Wrappers.<DeviceExamineRecordDetail>lambdaQuery().eq(DeviceExamineRecordDetail::getRecordId, deviceExamineRecordDto.getRecordId()));
+
+        // 鑾峰彇璺緞
+        InputStream inputStream = this.getClass().getResourceAsStream("/static/word/examine-record.docx");
+        Configure configure = Configure.builder()
+                .bind("deviceExamineRecordDetailList", new HackLoopTableRenderPolicy())
+                .build();
+        XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(
+                new HashMap<String, Object>() {{
+                    put("deviceExamineRecordDto", deviceExamineRecordDto);
+                    put("deviceExamineRecordDetailList", deviceExamineRecordDetailList);
+                    //鑾峰彇鏍告煡浜虹殑绛惧悕鍦板潃
+                    put("checkerUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordDto.getCheckerUserId()));
+                    //鑾峰彇瀹℃煡浜虹殑绛惧悕鍦板潃
+                    put("reviewUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordDto.getReviewUserId()));
+                }});
+
+        try {
+            response.setContentType("application/msword");
+            String deviceName = StringUtils.isNotEmpty(deviceExamineRecordDto.getDeviceName()) ? deviceExamineRecordDto.getDeviceName() : "";
+            String fileName = URLEncoder.encode(
+                    deviceName+ "鏍告煡璁板綍", "UTF-8");
+            response.setHeader("Content-disposition",
+                    "attachment;filename=" + fileName + ".docx");
+            OutputStream os = response.getOutputStream();
+            template.write(os);
+            os.flush();
+            os.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("瀵煎嚭澶辫触");
+        }
+    }
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExternalApplyServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExternalApplyServiceImpl.java
new file mode 100644
index 0000000..f6085b2
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceExternalApplyServiceImpl.java
@@ -0,0 +1,161 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.ruoyi.common.core.domain.entity.User;
+import com.ruoyi.common.utils.QueryWrappers;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.device.mapper.DeviceExternalApplyMapper;
+import com.ruoyi.device.pojo.DeviceExternalApply;
+import com.ruoyi.device.service.DeviceExternalApplyService;
+import com.ruoyi.inspect.util.UserUtils;
+import com.ruoyi.system.mapper.UserMapper;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.time.LocalDate;
+import java.util.HashMap;
+
+/**
+ * <p>
+ * 鍒╃敤澶栭儴璁惧鐢宠琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2024-12-17 10:28:43
+ */
+@Service
+public class DeviceExternalApplyServiceImpl extends ServiceImpl<DeviceExternalApplyMapper, DeviceExternalApply> implements DeviceExternalApplyService {
+
+    @Resource
+    private UserMapper userMapper;
+
+    /**
+     * 鍒╃敤澶栭儴璁惧鐢宠鍒楄〃
+     * @param page
+     * @param deviceExternalApply
+     * @return
+     */
+    @Override
+    public IPage<DeviceExternalApply> pageDeviceExternalApply(Page page, DeviceExternalApply deviceExternalApply) {
+        return baseMapper.pageDeviceExternalApply(page, QueryWrappers.queryWrappers(deviceExternalApply));
+    }
+
+    /**
+     * 鏂板鍒╃敤澶栭儴璁惧鐢宠
+     * @param deviceExternalApply
+     * @return
+     */
+    @Override
+    public boolean addDeviceExternalApply(DeviceExternalApply deviceExternalApply) {
+        DeviceExternalApply apply = new DeviceExternalApply();
+        // 褰撳墠鐧诲綍鐢ㄦ埛淇℃伅鍜岄儴闂�
+        User user = userMapper.selectById(SecurityUtils.getUserId().intValue());
+        switch (deviceExternalApply.getFlowType()) {
+            case 0:
+                BeanUtils.copyProperties(deviceExternalApply, apply);
+                // 鐢宠
+                apply.setUseReason(deviceExternalApply.getUseReason());
+                apply.setApplicantUserId(user.getId());
+                apply.setApplicantUser(user.getName());
+                apply.setApplicantDate(LocalDate.now());
+
+                // 澶勭悊浜轰俊鎭�
+                User departmentHeadUser = userMapper.selectById(deviceExternalApply.getDepartmentHeadUserId());
+                apply.setApplicantUserId(departmentHeadUser.getId());
+                apply.setApplicantUser(departmentHeadUser.getName());
+
+                baseMapper.insert(apply);
+                break;
+            case 1:
+                apply.setExternalApplyId(deviceExternalApply.getExternalApplyId());
+                // 鐢宠閮ㄩ棬璐熻矗浜烘剰瑙�
+                apply.setDepartmentHeadOpinion(deviceExternalApply.getDepartmentHeadOpinion());
+                apply.setDepartmentHeadDate(LocalDate.now());
+
+                // 璁¢噺瀹や俊鎭�
+                User meteringRoomUser = userMapper.selectById(deviceExternalApply.getMeteringRoomUserId());
+                apply.setMeteringRoomUserId(meteringRoomUser.getId());
+                apply.setMeteringRoomUser(meteringRoomUser.getName());
+
+                baseMapper.updateById(apply);
+                break;
+            case 2:
+                apply.setExternalApplyId(deviceExternalApply.getExternalApplyId());
+                // 璁¢噺瀹ゆ剰瑙�
+                apply.setMeteringRoomOpinion(deviceExternalApply.getMeteringRoomOpinion());
+                apply.setMeteringRoomDate(LocalDate.now());
+
+                // 鎵瑰噯浜轰俊鎭�
+                User approverUser = userMapper.selectById(deviceExternalApply.getApproverUserId());
+                apply.setApproverUserId(approverUser.getId());
+                apply.setApproverUser(approverUser.getName());
+
+                baseMapper.updateById(apply);
+                break;
+            case 3:
+                apply.setExternalApplyId(deviceExternalApply.getExternalApplyId());
+                //鎵瑰噯浜�
+                apply.setApproverOpinion(deviceExternalApply.getApproverOpinion());
+                apply.setApproverDate(LocalDate.now());
+
+                apply.setIsFinish(1);
+                baseMapper.updateById(apply);
+                break;
+        }
+
+        return true;
+    }
+
+    /**
+     * 瀵煎嚭鍒╃敤澶栭儴璁惧鐢宠
+     *
+     * @param externalApplyId 澶栭儴璁惧鐢宠id
+     * @param response
+     */
+    @Override
+    public void exportDeviceExternalApply(Integer externalApplyId, HttpServletResponse response) {
+        // 鏌ヨ澶栭儴璁惧鐢宠
+        DeviceExternalApply deviceAccidentReport = baseMapper.selectDeviceExternalById(externalApplyId);
+
+        // 鑾峰彇璺緞
+        InputStream inputStream = this.getClass().getResourceAsStream("/static/word/device-external-apply.docx");
+        Configure configure = Configure.builder()
+                .build();
+        XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(
+                new HashMap<String, Object>() {{
+                    put("deviceAccidentReport", deviceAccidentReport);
+                    // 鐢宠浜虹鍚�
+                    put("applicantUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getApplicantUserId()));
+                    // 閮ㄩ棬璐熻矗浜虹鍚�
+                    put("departmentHeadUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getDepartmentHeadUserId()));
+                    // 璁¢噺瀹や汉绛惧悕
+                    put("meteringRoomUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getMeteringRoomUserId()));
+                    // 鎵瑰噯浜虹鍚�
+                    put("approverUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getApproverUserId()));
+                }});
+
+        try {
+            response.setContentType("application/msword");
+            String fileName = URLEncoder.encode(
+                    "鍒╃敤澶栭儴璁惧鐢宠", "UTF-8");
+            response.setHeader("Content-disposition",
+                    "attachment;filename=" + fileName + ".docx");
+            OutputStream os = response.getOutputStream();
+            template.write(os);
+            os.flush();
+            os.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("瀵煎嚭澶辫触");
+        }
+    }
+}
diff --git a/cnas-device/src/main/resources/mapper/DeviceExaminePlanDetailsMapper.xml b/cnas-device/src/main/resources/mapper/DeviceExaminePlanDetailsMapper.xml
new file mode 100644
index 0000000..36852a8
--- /dev/null
+++ b/cnas-device/src/main/resources/mapper/DeviceExaminePlanDetailsMapper.xml
@@ -0,0 +1,18 @@
+<?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.device.mapper.DeviceExaminePlanDetailsMapper">
+
+
+    <!--璁惧鏍告煡璁″垝璇︽儏鍒楄〃-->
+    <select id="pageDeviceExaminePlanDetail" resultType="com.ruoyi.device.pojo.DeviceExaminePlanDetails">
+        select * from (
+        select *
+        from device_examine_plan_details
+        order by check_time asc
+        ) a
+        <if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
+            ${ew.customSqlSegment}
+        </if>
+    </select>
+
+</mapper>
diff --git a/cnas-device/src/main/resources/mapper/DeviceExaminePlanMapper.xml b/cnas-device/src/main/resources/mapper/DeviceExaminePlanMapper.xml
new file mode 100644
index 0000000..cf4b0ae
--- /dev/null
+++ b/cnas-device/src/main/resources/mapper/DeviceExaminePlanMapper.xml
@@ -0,0 +1,33 @@
+<?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.device.mapper.DeviceExaminePlanMapper">
+
+    <!-- 璁惧鏍告煡璁″垝鍒楄〃 -->
+    <select id="deviceExaminePlanDetailsMapper" resultType="com.ruoyi.device.dto.DeviceExaminePlanDto">
+        select *
+        from (select cqm.*,
+        u1.name write_name,
+        u3.name ratify_name
+        from device_examine_plan cqm
+        left join user u1 on u1.id = cqm.write_user_id
+        left join user u3 on u3.id = cqm.ratify_user_id
+        order by cqm.create_time desc) a
+        <if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
+            ${ew.customSqlSegment}
+        </if>
+    </select>
+    <select id="selectExamineExaminePlanDto" resultType="com.ruoyi.device.dto.DeviceExaminePlanDto">
+        select
+            cqm.*,
+            date_format(cqm.write_time, '%Y-%m-%d') writeTimeStr,
+            date_format(cqm.ratify_time, '%Y-%m-%d') ratifyTimeStr,
+            date_format(cqm.create_time, '%Y') year,
+            u1.name write_name,
+            u3.name ratify_name
+        from device_examine_plan cqm
+        left join user u1 on u1.id = cqm.write_user_id
+        left join user u3 on u3.id = cqm.ratify_user_id
+        where cqm.plan_id = #{deviceExaminePlanId}
+    </select>
+
+</mapper>
diff --git a/cnas-device/src/main/resources/mapper/DeviceExamineRecordContrastMapper.xml b/cnas-device/src/main/resources/mapper/DeviceExamineRecordContrastMapper.xml
new file mode 100644
index 0000000..e41b339
--- /dev/null
+++ b/cnas-device/src/main/resources/mapper/DeviceExamineRecordContrastMapper.xml
@@ -0,0 +1,39 @@
+<?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.device.mapper.DeviceExamineRecordContrastMapper">
+
+    <!-- 鏌ヨ鏍告煡瀵规瘮璁板綍 -->
+    <select id="getExamineRecordContrast" resultType="com.ruoyi.device.dto.DeviceExamineRecordContrastDto">
+        select derc.*,
+               d1.device_name aDeviceName,
+               d1.management_number aDeviceNumber,
+               d2.device_name bDeviceName,
+               d2.management_number bDeviceNumber,
+               d3.device_name cDeviceName,
+               d3.management_number cDeviceNumber
+        from device_examine_record_contrast derc
+                 left join device d1 on d1.id = derc.a_device_id
+                 left join device d2 on d2.id = derc.a_device_id
+                 left join device d3 on d3.id = derc.a_device_id
+        where derc.plan_details_id = #{planDetailsId}
+    </select>
+    <select id="selectExamineRecordContrastDto"
+            resultType="com.ruoyi.device.dto.DeviceExamineRecordContrastDto">
+        select derc.*,
+               d1.device_name aDeviceName,
+               d1.management_number aDeviceNumber,
+               d2.device_name bDeviceName,
+               d2.management_number bDeviceNumber,
+               d3.device_name cDeviceName,
+               d3.management_number cDeviceNumber,
+               DATE_FORMAT(derc.create_time, '%Y-%m-%d') checkerTimeStr,
+               DATE_FORMAT(derc.review_time, '%Y-%m-%d') reviewTimeStr,
+               d1.storage_point labName
+        from device_examine_record_contrast derc
+                 left join device d1 on d1.id = derc.a_device_id
+                 left join device d2 on d2.id = derc.a_device_id
+                 left join device d3 on d3.id = derc.a_device_id
+        where derc.plan_details_id = #{planDetailsId}
+    </select>
+
+</mapper>
diff --git a/cnas-device/src/main/resources/mapper/DeviceExamineRecordMapper.xml b/cnas-device/src/main/resources/mapper/DeviceExamineRecordMapper.xml
new file mode 100644
index 0000000..4dd397b
--- /dev/null
+++ b/cnas-device/src/main/resources/mapper/DeviceExamineRecordMapper.xml
@@ -0,0 +1,25 @@
+<?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.device.mapper.DeviceExamineRecordMapper">
+
+    <select id="getExamineRecord" resultType="com.ruoyi.device.dto.DeviceExamineRecordDto">
+        select der.*,
+               d.device_name,
+               d.management_number deviceNumber
+        from device_examine_record der
+                 left join device_examine_plan_details depd on depd.plan_details_id = der.plan_details_id
+                 left join device d on d.id = depd.device_id
+        where der.plan_details_id = #{planDetailsId}
+    </select>
+    <select id="selectReviewExamineRecordDto" resultType="com.ruoyi.device.dto.DeviceExamineRecordDto">
+        select der.*,
+               Date_Format(der.update_time, '%Y-%m-%d') updateTimeStr,
+               d.device_name,
+               d.management_number deviceNumber
+        from device_examine_record der
+                 left join device_examine_plan_details depd on depd.plan_details_id = der.plan_details_id
+                 left join device d on d.id = depd.device_id
+        where der.plan_details_id = #{planDetailsId}
+    </select>
+
+</mapper>
diff --git a/cnas-device/src/main/resources/mapper/DeviceExternalApplyMapper.xml b/cnas-device/src/main/resources/mapper/DeviceExternalApplyMapper.xml
new file mode 100644
index 0000000..b3419fb
--- /dev/null
+++ b/cnas-device/src/main/resources/mapper/DeviceExternalApplyMapper.xml
@@ -0,0 +1,23 @@
+<?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.device.mapper.DeviceExternalApplyMapper">
+
+    <!--鍒╃敤澶栭儴璁惧鐢宠鍒楄〃-->
+    <select id="pageDeviceExternalApply" resultType="com.ruoyi.device.pojo.DeviceExternalApply">
+        select * from (
+        select *
+        from device_external_apply
+        order by create_time desc
+        ) a
+        <if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
+            ${ew.customSqlSegment}
+        </if>
+    </select>
+    <select id="selectDeviceExternalById" resultType="com.ruoyi.device.pojo.DeviceExternalApply">
+        select
+            dea.*
+        from device_external_apply dea
+        where dea.external_apply_id = #{externalApplyId}
+    </select>
+
+</mapper>

--
Gitblit v1.9.3