liding
2026-09-01 bf2026a38d4d36371060673d4651b6e05ca90632
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;
@@ -25,17 +29,18 @@
import com.ruoyi.device.pojo.*;
import com.ruoyi.device.service.DataConfigService;
import com.ruoyi.device.service.DeviceService;
import com.ruoyi.device.service.DocumentService;
import com.ruoyi.device.service.DeviceDocumentsService;
import com.ruoyi.device.utils.DataAcquisition;
import com.ruoyi.framework.exception.ErrorException;
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;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -43,8 +48,10 @@
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;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@@ -61,15 +68,17 @@
    private UserMapper userMapper;
    private SysDeptMapper sysDeptMapper;
    private SysDictDataMapper sysDictDataMapper;
    private StructureItemParameterMapper structureItemParameterMapper;
    private DataConfigService dataConfigService;
    private QrShowServiceImpl qrShowService;
    private InsSampleMapper insSampleMapper;
    private DocumentService documentService;
    private DeviceDocumentsService documentService;
    private DeviceMetricRecordMapper deviceMetricRecordMapper;
@@ -96,10 +105,6 @@
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int upDeviceParameter(Device itemParameter) {
        // 删除数采集配置数据
        dataConfigService.deleteDataConfig();
        // 需要同时更改 device表
        return deviceMapper.updateById(itemParameter);
    }
@@ -117,11 +122,6 @@
    @Override
    public List<Device> search(Integer status, String deviceName, String specificationModel, String largeCategory) {
        return deviceMapper.search(status, deviceName, specificationModel, largeCategory);
    }
    @Override
    public List<Device> selectDevicePrincipal() {
        return deviceMapper.selectDevicePrincipal();
    }
    @Override
@@ -171,7 +171,7 @@
        }
        deviceDto.setAuthorizedPersonName(name);
        //查询设备校准信息
        DeviceMetricRecord calibrate = qrShowService.getDeviceMetricRecord(id, "calibrate");
        DeviceMetricRecord calibrate = getDeviceMetricRecord(id, "calibrate");
        deviceDto.setCalibrateNo(calibrate.getCertificateSerialNumber());
        // 到了停用日期,自动将状态改为停用
@@ -185,6 +185,21 @@
            }
        }
        return deviceDto;
    }
    /**
     * 查询设备校准/核查记录
     * @param deviceId
     * @param type
     * @return
     */
    public DeviceMetricRecord getDeviceMetricRecord(int deviceId, String type){
        return Optional.ofNullable(
                deviceMetricRecordMapper.selectOne(Wrappers.<DeviceMetricRecord>lambdaQuery()
                        .eq(DeviceMetricRecord::getDeviceId, deviceId)
                        .eq(DeviceMetricRecord::getType, type)
                        .orderByDesc(DeviceMetricRecord::getCreateTime)
                        .last("limit 1"))).orElse(new DeviceMetricRecord());
    }
    @Override
@@ -309,7 +324,7 @@
        // 设备信息
        Device device = baseMapper.selectById(deviceId);
        // 设备档案
        List<Document> documentList = documentService.list(Wrappers.<Document>lambdaQuery().eq(Document::getDeviceId, deviceId));
        List<DeviceDocuments> documentList = documentService.list(Wrappers.<DeviceDocuments>lambdaQuery().eq(DeviceDocuments::getDeviceId, deviceId));
        // 设备校准表
        List<DeviceMetricRecord> deviceMetricRecordList = deviceMetricRecordMapper.selectList(Wrappers.<DeviceMetricRecord>lambdaQuery().eq(DeviceMetricRecord::getDeviceId, deviceId));
        // 设备维修表
@@ -349,6 +364,7 @@
            template.write(os);
            os.flush();
            os.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导出失败");
@@ -393,11 +409,11 @@
                DeviceMaintenance deviceMaintenance = deviceMaintenanceList.get(i);
                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                // 维修日期
                deviceMetricRecordAndMaintenanceDto.setMaintenanceDateString(deviceMaintenance.getDate().format(dateTimeFormatter));
                deviceMetricRecordAndMaintenanceDto.setMaintenanceDateString(deviceMaintenance.getMaintenanceDate().format(dateTimeFormatter));
                // 处理方法
                deviceMetricRecordAndMaintenanceDto.setHandlingMethod(deviceMaintenance.getContent());
                deviceMetricRecordAndMaintenanceDto.setHandlingMethod(deviceMaintenance.getMaintenanceContent());
                // 备注
                deviceMetricRecordAndMaintenanceDto.setComments(deviceMaintenance.getComments());
                deviceMetricRecordAndMaintenanceDto.setComments(deviceMaintenance.getRemark());
            }
            deviceMetricRecordAndMaintenanceDtoList.add(deviceMetricRecordAndMaintenanceDto);
@@ -411,13 +427,13 @@
     * @param documentList              档案列表
     * @param documentExportWordDtoList 返回给word的数据列表
     */
    private static void extracted(List<Document> documentList, List<DocumentExportWordDto> documentExportWordDtoList) {
    private static void extracted(List<DeviceDocuments> documentList, List<DocumentExportWordDto> documentExportWordDtoList) {
        // 给档案加序号   并且分为左右两个列表在word中显示
        for (int i = 0; i < documentList.size(); i++) {
            // 创建word表格中一行的数据对象
            DocumentExportWordDto documentExportWordDto = new DocumentExportWordDto();
            // 获取档案信息
            Document document = documentList.get(i);
            DeviceDocuments document = documentList.get(i);
            // 格式化日期
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            // 根据序号 分别加入两个列表
@@ -484,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解析失败,请使用下载的导入模板", 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();
    }
}