From b72bb7cba52850c078157ffd95a45edf41751110 Mon Sep 17 00:00:00 2001
From: “djh” <“3298565835@qq.com”>
Date: Wed, 27 May 2026 15:05:17 +0800
Subject: [PATCH] 新增复制

---
 multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/AnnualVerificationPlanController.java          |   16 +++
 multi-system/src/main/java/com/gkhy/exam/system/service/CalibrationMonitoringEquipmentService.java          |    1 
 multi-system/src/main/java/com/gkhy/exam/system/service/impl/CalibrationMonitoringEquipmentServiceImpl.java |   78 +++++++++++++++
 multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/CalibrationMonitoringEquipmentController.java  |   15 +++
 multi-system/src/main/java/com/gkhy/exam/system/service/impl/AnnualVerificationPlanServiceImpl.java         |  148 +++++++++++++++++++++++++++++
 multi-system/src/main/java/com/gkhy/exam/system/service/AnnualVerificationPlanService.java                  |    2 
 6 files changed, 260 insertions(+), 0 deletions(-)

diff --git a/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/AnnualVerificationPlanController.java b/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/AnnualVerificationPlanController.java
index ef9dd26..119a9f4 100644
--- a/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/AnnualVerificationPlanController.java
+++ b/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/AnnualVerificationPlanController.java
@@ -66,4 +66,20 @@
         return annualVerificationPlanService.deletedAnnualVerificationPlan(id);
     }
 
+
+    @RepeatSubmit
+    @ApiOperation(value = "一键复制年度检定计划")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "query", name = "companyId", dataType = "int", required = false, value = "公司id,不传则使用当前登录用户公司"),
+            @ApiImplicitParam(paramType = "query", name = "sourceYear", dataType = "String", required = true, value = "源年份"),
+            @ApiImplicitParam(paramType = "query", name = "targetYear", dataType = "String", required = true, value = "目标年份"),
+    })
+    @GetMapping("/copyAnnualVerificationPlan")
+    public CommonResult copyAnnualVerificationPlan(
+            @RequestParam(required = false) Integer companyId,
+            @RequestParam String sourceYear,
+            @RequestParam String targetYear) {
+        return annualVerificationPlanService.copyAnnualVerificationPlan(companyId, sourceYear, targetYear);
+    }
+
 }
diff --git a/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/CalibrationMonitoringEquipmentController.java b/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/CalibrationMonitoringEquipmentController.java
index dabfd56..5259927 100644
--- a/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/CalibrationMonitoringEquipmentController.java
+++ b/multi-admin/src/main/java/com/gkhy/exam/admin/controller/web/CalibrationMonitoringEquipmentController.java
@@ -59,4 +59,19 @@
         return calibrationMonitoringEquipmentService.deletedCalibrationMonitoringEquipment(id);
     }
 
+    @RepeatSubmit
+    @ApiOperation(value = "复制监测和测量设备校准确认数据")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "query", name = "companyId", dataType = "int", required = true, value = "公司ID"),
+            @ApiImplicitParam(paramType = "query", name = "sourceYear", dataType = "string", required = true, value = "源年份"),
+            @ApiImplicitParam(paramType = "query", name = "targetYear", dataType = "string", required = true, value = "目标年份"),
+    })
+    @GetMapping("/copyCalibrationMonitoringEquipment")
+    public CommonResult copyCalibrationMonitoringEquipment(@RequestParam Integer companyId,
+                                                           @RequestParam String sourceYear,
+                                                           @RequestParam String targetYear){
+        return calibrationMonitoringEquipmentService.copyCalibrationMonitoringEquipment(companyId, sourceYear, targetYear);
+    }
+
+
 }
diff --git a/multi-system/src/main/java/com/gkhy/exam/system/service/AnnualVerificationPlanService.java b/multi-system/src/main/java/com/gkhy/exam/system/service/AnnualVerificationPlanService.java
index c1e3111..fbff93a 100644
--- a/multi-system/src/main/java/com/gkhy/exam/system/service/AnnualVerificationPlanService.java
+++ b/multi-system/src/main/java/com/gkhy/exam/system/service/AnnualVerificationPlanService.java
@@ -21,4 +21,6 @@
     CommonResult getAnnualVerificationPlan(Long id);
 
     CommonResult deletedAnnualVerificationPlan(Long id);
+
+    CommonResult copyAnnualVerificationPlan(Integer companyId, String sourceYear, String targetYear);
 }
diff --git a/multi-system/src/main/java/com/gkhy/exam/system/service/CalibrationMonitoringEquipmentService.java b/multi-system/src/main/java/com/gkhy/exam/system/service/CalibrationMonitoringEquipmentService.java
index 6182f7f..3ac8139 100644
--- a/multi-system/src/main/java/com/gkhy/exam/system/service/CalibrationMonitoringEquipmentService.java
+++ b/multi-system/src/main/java/com/gkhy/exam/system/service/CalibrationMonitoringEquipmentService.java
@@ -21,4 +21,5 @@
 
     CommonResult deletedCalibrationMonitoringEquipment(Long id);
 
+    CommonResult copyCalibrationMonitoringEquipment(Integer companyId, String sourceYear, String targetYear);
 }
diff --git a/multi-system/src/main/java/com/gkhy/exam/system/service/impl/AnnualVerificationPlanServiceImpl.java b/multi-system/src/main/java/com/gkhy/exam/system/service/impl/AnnualVerificationPlanServiceImpl.java
index 693bd82..8a4eced 100644
--- a/multi-system/src/main/java/com/gkhy/exam/system/service/impl/AnnualVerificationPlanServiceImpl.java
+++ b/multi-system/src/main/java/com/gkhy/exam/system/service/impl/AnnualVerificationPlanServiceImpl.java
@@ -142,4 +142,152 @@
 
         return CommonResult.success();
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public CommonResult copyAnnualVerificationPlan(Integer companyId, String sourceYear, String targetYear) {
+        if (ObjectUtils.isEmpty(sourceYear) || ObjectUtils.isEmpty(targetYear)) {
+            return CommonResult.failed("源年份和目标年份不能为空");
+        }
+
+        if (ObjectUtils.isEmpty(companyId)) {
+            return CommonResult.failed("公司ID不能为空");
+        }
+
+        if (sourceYear.equals(targetYear)) {
+            return CommonResult.failed("源年份和目标年份不能相同");
+        }
+
+        LambdaQueryWrapper<AnnualVerificationPlan> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(AnnualVerificationPlan::getDelFlag, UserConstant.ENABLE)
+                .eq(AnnualVerificationPlan::getCompanyId, companyId)
+                .eq(AnnualVerificationPlan::getYear, sourceYear);
+
+        AnnualVerificationPlan sourcePlan = annualVerificationPlanMapper.selectOne(queryWrapper);
+        if (sourcePlan == null) {
+            return CommonResult.failed("未找到源年份的年度检定计划");
+        }
+
+        LambdaQueryWrapper<AnnualVerificationPlan> checkWrapper = new LambdaQueryWrapper<>();
+        checkWrapper.eq(AnnualVerificationPlan::getDelFlag, UserConstant.ENABLE)
+                .eq(AnnualVerificationPlan::getCompanyId, companyId)
+                .eq(AnnualVerificationPlan::getYear, targetYear);
+        Long count = annualVerificationPlanMapper.selectCount(checkWrapper);
+        if (count > 0) {
+            return CommonResult.failed("目标年份的年度检定计划已存在");
+        }
+        
+        // 检查是否存在已逻辑删除的计划,如果存在则先进行物理删除或更新(根据业务需求,这里通常意味着可以复用或需要清理)
+        // 但根据指令“已存在数据进行逻辑删除”,通常指如果目标年份已有数据(无论是否删除),可能需要处理。
+        // 然而,标准的“逻辑删除”检查通常只针对未删除的数据。如果指令意思是“如果目标年份已有数据,将其逻辑删除后再插入”或者“检查时忽略已逻辑删除的数据”,
+        // 结合上下文 `copy` 操作,通常如果目标年份已有**有效**计划则禁止复制。
+        // 如果指令意图是:如果目标年份存在**已逻辑删除**的数据,是否需要特殊处理?
+        // 重新解读指令:“已存在数据进行逻辑删除”。这可能意味着:在复制前,如果目标年份已经存在计划(即使是逻辑删除的),也应该被视为“已存在”并阻止,或者需要先清理。
+        // 但更常见的场景是:如果目标年份存在**未删除**的计划,则报错。如果存在**已删除**的计划,可能允许覆盖或报错。
+        // 让我们看原代码逻辑:它只检查了 `ENABLE` 状态。
+        // 如果指令的意思是“对于已存在的数据(指目标年份的计划),执行逻辑删除操作”,这在 copy 场景中不太合理,因为 copy 是创建新数据。
+        // 另一种理解:指令可能是指在检查是否存在时,也要考虑那些已经被逻辑删除的数据?不,通常 `del_flag` 为 disable 的就是被删除的。
+        // 再仔细看图和常见业务:如果目标年份有一个**已被逻辑删除**的计划,是否允许再次复制生成一个新的?
+        // 如果指令是“已存在数据进行逻辑删除”,这可能是指:如果查询到目标年份有数据(不管状态),都视为冲突?或者,如果存在旧数据,先把它逻辑删除?
+        // 考虑到 `copy` 操作的原子性和安全性,通常如果目标年份有任何记录(包括逻辑删除的),为了避免ID冲突或数据混乱,往往不允许直接复制,或者需要更复杂的清理逻辑。
+        // 但是,最直接的解读可能是:原代码只检查了 `ENABLE`,现在要求如果存在任何记录(包括已逻辑删除的),都视为“已存在”并返回失败?
+        // 或者,指令是说:如果目标年份存在计划,**不要**报错,而是将旧计划逻辑删除,然后继续执行复制?
+        // 让我们看返回值类型。方法是 `CommonResult`。如果中间执行了删除,继续执行插入,最后返回 success。
+        // 这种解释更符合“已存在数据进行逻辑删除”作为**动作**的描述,而不是**检查条件**。
+        // 即:如果目标年份已有计划(无论状态),先将其逻辑删除,然后再创建新的。
+        
+        // 步骤1: 查找目标年份的所有计划(包括已删除和未删除)
+        LambdaQueryWrapper<AnnualVerificationPlan> existingWrapper = new LambdaQueryWrapper<>();
+        existingWrapper.eq(AnnualVerificationPlan::getCompanyId, companyId)
+                .eq(AnnualVerificationPlan::getDelFlag, UserConstant.ENABLE)
+                .eq(AnnualVerificationPlan::getYear, targetYear);
+        List<AnnualVerificationPlan> existingPlans = annualVerificationPlanMapper.selectList(existingWrapper);
+        
+        // 步骤2: 如果存在,将它们逻辑删除
+        if (ObjectUtils.isNotEmpty(existingPlans)) {
+            for (AnnualVerificationPlan plan : existingPlans) {
+                // 如果已经是禁用状态,跳过或更新更新时间?通常只需确保它是禁用状态
+                    AnnualVerificationPlan updatePlan = new AnnualVerificationPlan();
+                    updatePlan.setId(plan.getId());
+                    updatePlan.setDelFlag(UserConstant.DISENABLE);
+                    updatePlan.setUpdateTime(LocalDateTime.now());
+                    updatePlan.setUpdateBy(SecurityUtils.getUsername());
+                    annualVerificationPlanMapper.updateById(updatePlan);
+                    
+                    // 同时逻辑删除关联的设备
+                    annualVerificationDeviceMapper.update(new AnnualVerificationDevice(),
+                            new LambdaUpdateWrapper<AnnualVerificationDevice>()
+                                    .eq(AnnualVerificationDevice::getAnnualVerificationId, plan.getId())
+                                    .set(AnnualVerificationDevice::getDelFlag, UserConstant.DISENABLE)
+                                    .set(AnnualVerificationDevice::getUpdateTime, LocalDateTime.now())
+                                    .set(AnnualVerificationDevice::getUpdateBy, SecurityUtils.getUsername()));
+            }
+
+        }
+
+        List<AnnualVerificationDevice> sourceDevices = annualVerificationDeviceMapper.selectList(
+                new LambdaQueryWrapper<AnnualVerificationDevice>()
+                        .eq(AnnualVerificationDevice::getAnnualVerificationId, sourcePlan.getId())
+                        .eq(AnnualVerificationDevice::getDelFlag, UserConstant.ENABLE)
+        );
+
+        AnnualVerificationPlan newPlan = new AnnualVerificationPlan();
+        newPlan.setCompanyId(sourcePlan.getCompanyId());
+        newPlan.setName(sourcePlan.getName().replace(sourceYear, targetYear));
+        newPlan.setYear(targetYear);
+        newPlan.setEstablishmentId(sourcePlan.getEstablishmentId());
+        newPlan.setEstablishmentName(sourcePlan.getEstablishmentName());
+        newPlan.setEstablishmentTime(LocalDateTime.now());
+        newPlan.setProcessId(sourcePlan.getProcessId());
+        newPlan.setProcessName(sourcePlan.getProcessName());
+        newPlan.setProcessTime(LocalDateTime.now());
+        newPlan.setCertificate(sourcePlan.getCertificate());
+        newPlan.setCertificateName(sourcePlan.getCertificateName());
+        newPlan.setDelFlag(UserConstant.ENABLE);
+        newPlan.setCreateBy(SecurityUtils.getUsername());
+        newPlan.setCreateTime(LocalDateTime.now());
+        newPlan.setVersion(0);
+
+        int insertResult = annualVerificationPlanMapper.insert(newPlan);
+        if (insertResult <= 0) {
+            throw new ApiException("复制年度检定计划失败");
+        }
+
+        if (ObjectUtils.isNotEmpty(sourceDevices)) {
+            for (AnnualVerificationDevice sourceDevice : sourceDevices) {
+                AnnualVerificationDevice newDevice = new AnnualVerificationDevice();
+                newDevice.setAnnualVerificationId(newPlan.getId());
+                newDevice.setDeviceNumber(sourceDevice.getDeviceNumber());
+                newDevice.setDeviceName(sourceDevice.getDeviceName());
+                newDevice.setModel(sourceDevice.getModel());
+                newDevice.setCalibrationCycle(sourceDevice.getCalibrationCycle());
+                LocalDateTime newNextCalibrationTime = sourceDevice.getNextCalibrationTime()
+                        .withYear(Integer.parseInt(targetYear));
+                newDevice.setNextCalibrationTime(newNextCalibrationTime);
+
+                LocalDateTime newActCalibrationTime = sourceDevice.getActCalibrationTime()
+                        .withYear(Integer.parseInt(targetYear));
+                newDevice.setActCalibrationTime(newActCalibrationTime);
+                newDevice.setCalibrationUser(sourceDevice.getCalibrationUser());
+                newDevice.setUseUser(sourceDevice.getUseUser());
+                newDevice.setStatus(sourceDevice.getStatus());
+                newDevice.setPlanType(sourceDevice.getPlanType());
+                newDevice.setCertificate(sourceDevice.getCertificate());
+                newDevice.setCertificateName(sourceDevice.getCertificateName());
+                newDevice.setDelFlag(UserConstant.ENABLE);
+                newDevice.setCreateBy(SecurityUtils.getUsername());
+                newDevice.setCreateTime(LocalDateTime.now());
+                newDevice.setVersion(0);
+
+                int deviceInsertResult = annualVerificationDeviceMapper.insert(newDevice);
+                if (deviceInsertResult <= 0) {
+                    throw new ApiException("复制设备信息失败");
+                }
+            }
+        }
+
+        return CommonResult.success("复制成功");
+    }
+
+
 }
diff --git a/multi-system/src/main/java/com/gkhy/exam/system/service/impl/CalibrationMonitoringEquipmentServiceImpl.java b/multi-system/src/main/java/com/gkhy/exam/system/service/impl/CalibrationMonitoringEquipmentServiceImpl.java
index ef53b8b..4355f78 100644
--- a/multi-system/src/main/java/com/gkhy/exam/system/service/impl/CalibrationMonitoringEquipmentServiceImpl.java
+++ b/multi-system/src/main/java/com/gkhy/exam/system/service/impl/CalibrationMonitoringEquipmentServiceImpl.java
@@ -1,10 +1,13 @@
 package com.gkhy.exam.system.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gkhy.exam.common.api.CommonPage;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.constant.UserConstant;
+import com.gkhy.exam.common.exception.ApiException;
 import com.gkhy.exam.common.utils.PageUtils;
 import com.gkhy.exam.common.utils.SecurityUtils;
 import com.gkhy.exam.system.domain.CalibrationMonitoringEquipment;
@@ -12,9 +15,11 @@
 import com.gkhy.exam.system.service.CalibrationMonitoringEquipmentService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -62,4 +67,77 @@
 
         return CommonResult.success();
     }
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public CommonResult copyCalibrationMonitoringEquipment(Integer companyId, String sourceYear, String targetYear) {
+        if (ObjectUtils.isEmpty(companyId)) {
+            return CommonResult.failed("公司ID不能为空");
+        }
+
+        if (ObjectUtils.isEmpty(sourceYear) || ObjectUtils.isEmpty(targetYear)) {
+            return CommonResult.failed("源年份和目标年份不能为空");
+        }
+
+        if (sourceYear.equals(targetYear)) {
+            return CommonResult.failed("源年份和目标年份不能相同");
+        }
+
+        LambdaQueryWrapper<CalibrationMonitoringEquipment> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CalibrationMonitoringEquipment::getDelFlag, UserConstant.ENABLE)
+                .eq(CalibrationMonitoringEquipment::getCompanyId, companyId);
+
+        List<CalibrationMonitoringEquipment> sourceEquipments = calibrationMonitoringEquipmentMapper.selectList(queryWrapper);
+
+        if (ObjectUtils.isEmpty(sourceEquipments)) {
+            return CommonResult.failed("未找到源公司的设备校准数据");
+        }
+
+        List<CalibrationMonitoringEquipment> filteredEquipments = sourceEquipments.stream()
+                .filter(equipment -> equipment.getCalibrationTime() != null
+                        && String.valueOf(equipment.getCalibrationTime().getYear()).equals(sourceYear))
+                .collect(Collectors.toList());
+
+        if (ObjectUtils.isEmpty(filteredEquipments)) {
+            return CommonResult.failed("未找到" + sourceYear + "年的设备校准数据");
+        }
+
+        int successCount = 0;
+        for (CalibrationMonitoringEquipment sourceEquipment : filteredEquipments) {
+            CalibrationMonitoringEquipment newEquipment = new CalibrationMonitoringEquipment();
+
+            newEquipment.setCompanyId(sourceEquipment.getCompanyId());
+            newEquipment.setDeviceName(sourceEquipment.getDeviceName());
+            newEquipment.setDeviceNumber(sourceEquipment.getDeviceNumber());
+            newEquipment.setCalibrationNumber(sourceEquipment.getCalibrationNumber());
+
+            LocalDateTime newCalibrationTime = sourceEquipment.getCalibrationTime()
+                    .withYear(Integer.parseInt(targetYear));
+            newEquipment.setCalibrationTime(newCalibrationTime);
+
+            newEquipment.setCalibrationCompany(sourceEquipment.getCalibrationCompany());
+            newEquipment.setCalibrationResult(sourceEquipment.getCalibrationResult());
+            newEquipment.setConfirmUser(sourceEquipment.getConfirmUser());
+            newEquipment.setConfirmTime(sourceEquipment.getConfirmTime());
+            newEquipment.setExecutiveUser(sourceEquipment.getExecutiveUser());
+            newEquipment.setExecutiveTime(sourceEquipment.getExecutiveTime());
+            newEquipment.setDelFlag(UserConstant.ENABLE);
+            newEquipment.setCreateBy(SecurityUtils.getUsername());
+            newEquipment.setCreateTime(LocalDateTime.now());
+            newEquipment.setVersion(0);
+
+            int insertResult = calibrationMonitoringEquipmentMapper.insert(newEquipment);
+            if (insertResult > 0) {
+                successCount++;
+            }
+        }
+
+        if (successCount == 0) {
+            throw new ApiException("复制设备校准数据失败");
+        }
+
+        return CommonResult.success("成功复制" + successCount + "条设备校准数据");
+    }
+
 }

--
Gitblit v1.9.2