From bf2026a38d4d36371060673d4651b6e05ca90632 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期二, 01 九月 2026 17:07:30 +0800
Subject: [PATCH] feat(device): 1.更新设备导入验证逻辑和检验任务功能 2.报告编制

---
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java |  194 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 194 insertions(+), 0 deletions(-)

diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java
index 0cb7415..a58e4be 100644
--- a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
+import com.alibaba.excel.EasyExcel;
 import com.alibaba.fastjson2.JSON;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
@@ -15,9 +16,12 @@
 import com.ruoyi.basic.mapper.StructureItemParameterMapper;
 import com.ruoyi.basic.pojo.StructureItemParameter;
 import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.common.core.domain.entity.User;
 import com.ruoyi.common.utils.QueryWrappers;
 import com.ruoyi.device.dto.*;
+import com.ruoyi.device.excel.upload.DeviceImport;
 import com.ruoyi.device.mapper.CollectBridgeMapper;
 import com.ruoyi.device.mapper.DeviceMaintenanceMapper;
 import com.ruoyi.device.mapper.DeviceMapper;
@@ -31,6 +35,8 @@
 import com.ruoyi.inspect.mapper.InsSampleMapper;
 import com.ruoyi.inspect.pojo.InsProduct;
 import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
+import com.ruoyi.system.mapper.SysDictDataMapper;
+import com.ruoyi.system.mapper.SysDeptMapper;
 import com.ruoyi.system.mapper.UserMapper;
 import lombok.AllArgsConstructor;
 import org.apache.logging.log4j.util.Strings;
@@ -42,6 +48,7 @@
 import javax.servlet.http.HttpServletResponse;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.math.BigDecimal;
 import java.net.URLEncoder;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
@@ -60,6 +67,10 @@
     private DeviceMapper deviceMapper;
 
     private UserMapper userMapper;
+
+    private SysDeptMapper sysDeptMapper;
+
+    private SysDictDataMapper sysDictDataMapper;
 
     private StructureItemParameterMapper structureItemParameterMapper;
 
@@ -353,6 +364,7 @@
             template.write(os);
             os.flush();
             os.close();
+            inputStream.close();
         } catch (Exception e) {
             e.printStackTrace();
             throw new RuntimeException("瀵煎嚭澶辫触");
@@ -488,9 +500,191 @@
             template.write(os);
             os.flush();
             os.close();
+            inputStream.close();
         } catch (Exception e) {
             e.printStackTrace();
             throw new RuntimeException("瀵煎嚭澶辫触");
         }
     }
+
+    @Override
+    public void downloadImportTemplate(HttpServletResponse response) {
+        response.reset();
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+        try {
+            String fileName = URLEncoder.encode("璁惧瀵煎叆妯℃澘.xlsx", "UTF-8");
+            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
+            EasyExcel.write(response.getOutputStream(), DeviceImport.class)
+                    .sheet("璁惧瀵煎叆妯℃澘")
+                    .doWrite(Collections.emptyList());
+        } catch (Exception e) {
+            throw new RuntimeException("璁惧瀵煎叆妯℃澘涓嬭浇澶辫触", e);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int importDevice(org.springframework.web.multipart.MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            throw new RuntimeException("璇烽�夋嫨闇�瑕佸鍏ョ殑Excel鏂囦欢");
+        }
+        String fileName = file.getOriginalFilename();
+        if (fileName == null || !fileName.toLowerCase(Locale.ROOT).endsWith(".xlsx")) {
+            throw new RuntimeException("浠呮敮鎸�.xlsx鏍煎紡鏂囦欢");
+        }
+
+        final List<DeviceImport> rows;
+        try {
+            rows = EasyExcel.read(file.getInputStream())
+                    .head(DeviceImport.class)
+                    .sheet()
+                    .doReadSync();
+        } catch (Exception e) {
+            throw new RuntimeException("Excel瑙f瀽澶辫触锛岃浣跨敤涓嬭浇鐨勫鍏ユā鏉�", e);
+        }
+        if (CollectionUtils.isEmpty(rows)) {
+            throw new RuntimeException("瀵煎叆鏂囦欢娌℃湁璁惧鏁版嵁");
+        }
+
+        Set<String> fileKeys = new HashSet<>();
+        for (int i = 0; i < rows.size(); i++) {
+            String managementNumber = required(rows.get(i).getManagementNumber(), i + 2, "绠$悊缂栧彿");
+            String deviceName = required(rows.get(i).getDeviceName(), i + 2, "浠櫒鍚嶇О");
+            String specificationModel = required(rows.get(i).getSpecificationModel(), i + 2, "瑙勬牸鍨嬪彿");
+            if (!fileKeys.add(deviceKey(deviceName, specificationModel, managementNumber))) {
+                throw new RuntimeException("绗�" + (i + 2) + "琛岋細浠櫒鍚嶇О+瑙勬牸鍨嬪彿+绠$悊缂栧彿鍦ㄦ枃浠朵腑閲嶅");
+            }
+        }
+        Set<String> existingKeys = baseMapper.selectList(Wrappers.<Device>lambdaQuery()
+                        .select(Device::getDeviceName, Device::getSpecificationModel, Device::getManagementNumber))
+                .stream().map(d -> deviceKey(d.getDeviceName(), d.getSpecificationModel(), d.getManagementNumber())).collect(Collectors.toSet());
+
+        Map<String, List<SysDept>> departmentMap = sysDeptMapper.selectDeptList(new SysDept()).stream()
+                .filter(item -> StringUtils.isNotBlank(item.getDeptName()))
+                .collect(Collectors.groupingBy(item -> item.getDeptName().trim()));
+        Map<String, List<User>> userMap = userMapper.selectList(Wrappers.<User>lambdaQuery()
+                        .isNotNull(User::getName).select(User::getId, User::getName))
+                .stream().collect(Collectors.groupingBy(item -> item.getName().trim()));
+        Map<String, String> statusMap = dictMap("device_status");
+        Map<String, String> typeMap = dictMap("device_type");
+
+        List<Device> devices = new ArrayList<>();
+        for (int i = 0; i < rows.size(); i++) {
+            int rowNumber = i + 2;
+            DeviceImport row = rows.get(i);
+            String managementNumber = required(row.getManagementNumber(), rowNumber, "绠$悊缂栧彿");
+            String deviceName = required(row.getDeviceName(), rowNumber, "浠櫒鍚嶇О");
+            String specificationModel = required(row.getSpecificationModel(), rowNumber, "瑙勬牸鍨嬪彿");
+            if (existingKeys.contains(deviceKey(deviceName, specificationModel, managementNumber))) {
+                throw new RuntimeException("绗�" + rowNumber + "琛岋細浠櫒鍚嶇О鈥�" + deviceName + "鈥�+瑙勬牸鍨嬪彿鈥�" + specificationModel + "鈥�+绠$悊缂栧彿鈥�" + managementNumber + "鈥濆凡瀛樺湪");
+            }
+
+            String laboratoryName = required(row.getLaboratoryName(), rowNumber, "鎵�灞為儴闂�");
+            List<SysDept> departments = departmentMap.get(laboratoryName);
+            if (CollectionUtils.isEmpty(departments) || departments.size() > 1) {
+                throw new RuntimeException("绗�" + rowNumber + "琛岋細鎵�灞為儴闂ㄢ��" + laboratoryName + "鈥濅笉瀛樺湪鎴栦笉鍞竴");
+            }
+
+            Device device = new Device();
+            device.setDeviceName(deviceName);
+            device.setSpecificationModel(specificationModel);
+            device.setManagementNumber(managementNumber);
+            device.setActivationDate(parseDate(row.getActivationDate()));
+            device.setSubordinateDepartmentsId(departments.get(0).getDeptId().intValue());
+            device.setDeviceStatus(Integer.valueOf(dictValue(statusMap, row.getDeviceStatus(), rowNumber, "褰撳墠鐘舵��", true)));
+            device.setCalibrationDate(required(row.getCalibrationDate(), rowNumber, "鏍″噯鍛ㄦ湡(鏈�)"));
+            device.setEnDeviceName(trim(row.getEnDeviceName()));
+            device.setManufacturer(trim(row.getManufacturer()));
+            device.setFactoryNo(trim(row.getFactoryNo()));
+            device.setAssetCode(trim(row.getAssetCode()));
+            device.setOrigin(trim(row.getOrigin()));
+            device.setAcquisitionDate(parseDate(row.getAcquisitionDate()));
+            device.setStoragePoint(trim(row.getStoragePoint()));
+            device.setTechnicalIndicators(trim(row.getTechnicalIndicators()));
+            device.setCalibrationServices(trim(row.getCalibrationServices()));
+            device.setLastCalibrationDate(parseDate(row.getLastCalibrationDate()));
+            device.setNextCalibrationDate(parseDate(row.getNextCalibrationDate()));
+            device.setLargeCategory(dictValue(typeMap, row.getLargeCategory(), rowNumber, "璁惧绫诲瀷", false));
+            device.setUnitPrice(parseDecimal(row.getUnitPrice(), rowNumber, "鍗曚环(涓囧厓)"));
+
+            String managerName = trim(row.getEquipmentManagerName());
+            if (StringUtils.isNotBlank(managerName)) {
+                List<User> users = userMap.get(managerName);
+                if (CollectionUtils.isEmpty(users) || users.size() > 1) {
+                    throw new RuntimeException("绗�" + rowNumber + "琛岋細璐熻矗浜衡��" + managerName + "鈥濅笉瀛樺湪鎴栦笉鍞竴");
+                }
+                device.setEquipmentManager(users.get(0).getId());
+            }
+            devices.add(device);
+        }
+        saveBatch(devices);
+        return devices.size();
+    }
+
+    private Map<String, String> dictMap(String dictType) {
+        return sysDictDataMapper.selectDictDataByType(dictType).stream()
+                .collect(Collectors.toMap(item -> item.getDictLabel().trim(), SysDictData::getDictValue, (first, second) -> first));
+    }
+
+    private String dictValue(Map<String, String> values, String input, int rowNumber, String column, boolean required) {
+        String text = trim(input);
+        if (StringUtils.isBlank(text)) {
+            if (required) {
+                throw new RuntimeException("绗�" + rowNumber + "琛岋細" + column + "涓嶈兘涓虹┖");
+            }
+            return null;
+        }
+        String value = values.get(text);
+        if (value == null && values.containsValue(text)) {
+            value = text;
+        }
+        if (value == null) {
+            throw new RuntimeException("绗�" + rowNumber + "琛岋細" + column + "鈥�" + text + "鈥濅笉鍦ㄧ郴缁熷瓧鍏镐腑");
+        }
+        return value;
+    }
+
+    private LocalDateTime parseDate(String input) {
+        String text = trim(input);
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        String datePart = text.replace('/', '-').split("\\s+")[0];
+        try {
+            return LocalDate.parse(datePart, DateTimeFormatter.ofPattern("yyyy-M-d")).atStartOfDay();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private BigDecimal parseDecimal(String input, int rowNumber, String column) {
+        String text = trim(input);
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        try {
+            return new BigDecimal(text);
+        } catch (NumberFormatException e) {
+            throw new RuntimeException("绗�" + rowNumber + "琛岋細" + column + "蹇呴』鏄暟瀛�", e);
+        }
+    }
+
+    private String required(String input, int rowNumber, String column) {
+        String value = trim(input);
+        if (StringUtils.isBlank(value)) {
+            throw new RuntimeException("绗�" + rowNumber + "琛岋細" + column + "涓嶈兘涓虹┖");
+        }
+        return value;
+    }
+
+    private String deviceKey(String deviceName, String specificationModel, String managementNumber) {
+        return (deviceName == null ? "" : deviceName.trim()) + "|"
+                + (specificationModel == null ? "" : specificationModel.trim()) + "|"
+                + (managementNumber == null ? "" : managementNumber.trim());
+    }
+
+    private String trim(String value) {
+        return value == null ? null : value.trim();
+    }
 }

--
Gitblit v1.9.3