From de775139ac660c9d2e38ae54364f25e6724ca668 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 28 八月 2026 15:41:38 +0800
Subject: [PATCH] feat(device): 1.添加设备导入导出功能并优化数据库关联查询 2.计量溯源性-标准物质清单导入导出
---
cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java | 186 ++++++++++++++++++
cnas-device/src/main/java/com/ruoyi/device/excel/upload/DeviceImport.java | 73 +++++++
cnas-require/src/main/java/com/ruoyi/require/service/FeStandardSubstanceService.java | 7
cnas-require/src/main/java/com/ruoyi/require/service/impl/FeStandardSubstanceServiceImpl.java | 137 +++++++++++++
inspect-server/src/main/resources/mapper/InsSampleMapper.xml | 1
cnas-device/src/main/resources/mapper/DeviceMapper.xml | 18
cnas-device/src/main/java/com/ruoyi/device/service/DeviceService.java | 5
cnas-require/src/main/java/com/ruoyi/require/excel/FeStandardSubstanceImport.java | 46 ++++
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java | 54 +++++
cnas-device/src/main/java/com/ruoyi/device/controller/DeviceController.java | 29 ++
cnas-require/src/main/java/com/ruoyi/require/controller/FeStandardSubstanceController.java | 13 +
11 files changed, 550 insertions(+), 19 deletions(-)
diff --git a/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceController.java b/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceController.java
index 9a58b5b..d1d30c5 100644
--- a/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceController.java
+++ b/cnas-device/src/main/java/com/ruoyi/device/controller/DeviceController.java
@@ -26,7 +26,6 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -51,7 +50,7 @@
@ApiOperation(value = "鏌ヨ璁惧璇︽儏")
@GetMapping("/getDeviceById")
- public Result getDeviceById(Integer deviceId){
+ public Result getDeviceById(Integer deviceId) {
return Result.success(deviceService.getById(deviceId));
}
@@ -59,7 +58,7 @@
//璁惧宸ュ叿鏄庣粏
@ApiOperation(value = "鏌ヨ璁惧璇︽儏鍒楄〃")
@GetMapping("/selectDeviceParameter")
- public Result selectDeviceParameter(Page page, DeviceDto itemParameter, Boolean laboratoryNameIsNull){
+ public Result selectDeviceParameter(Page page, DeviceDto itemParameter, Boolean laboratoryNameIsNull) {
return Result.success(deviceService.selectDeviceParameter(page, itemParameter, laboratoryNameIsNull));
}
@@ -137,8 +136,8 @@
@ApiOperation(value = "閫氳繃椤圭洰鑾峰彇璁惧鍒楄〃")
@GetMapping("/selectDeviceByCategory")
- public Result selectDeviceByCategory(String inspectionItem, String inspectionItemSubclass,String laboratory) {
- return Result.success(deviceService.selectDeviceByCategory(inspectionItem, inspectionItemSubclass,laboratory));
+ public Result selectDeviceByCategory(String inspectionItem, String inspectionItemSubclass, String laboratory) {
+ return Result.success(deviceService.selectDeviceByCategory(inspectionItem, inspectionItemSubclass, laboratory));
}
@ApiOperation(value = "閫氳繃璁惧缂栧彿鑾峰彇璁惧鍒楄〃")
@@ -150,7 +149,7 @@
@ApiOperation("/鏁伴噰-鏁版嵁閲囬泦")
@PostMapping("/dataCollection")
- public Result<?> dataAcquisition(HttpServletRequest request,@RequestBody DeviceCollectionDto dto) {
+ public Result<?> dataAcquisition(HttpServletRequest request, @RequestBody DeviceCollectionDto dto) {
return deviceService.dataAcquisition(request, dto);
}
@@ -205,13 +204,25 @@
@ApiOperation(value = "璁惧妗f瀵煎嚭")
@GetMapping("/exportDeviceFile")
- public void exportDeviceFile(@RequestParam Integer deviceId, HttpServletResponse response){
- deviceService.exportDeviceFile(deviceId,response);
+ public void exportDeviceFile(@RequestParam Integer deviceId, HttpServletResponse response) {
+ deviceService.exportDeviceFile(deviceId, response);
}
@ApiOperation(value = "浠櫒璁惧涓�瑙堣〃瀵煎嚭")
@GetMapping("/exportEquipmentDetails")
- public void exportEquipmentDetails(HttpServletResponse response){
+ public void exportEquipmentDetails(HttpServletResponse response) {
deviceService.exportEquipmentDetails(response);
}
+
+ @ApiOperation(value = "涓嬭浇璁惧瀵煎叆妯℃澘")
+ @GetMapping("/importTemplate")
+ public void importTemplate(HttpServletResponse response) {
+ deviceService.downloadImportTemplate(response);
+ }
+
+ @ApiOperation(value = "瀵煎叆璁惧")
+ @PostMapping("/importDevice")
+ public Result importDevice(MultipartFile file) {
+ return Result.success(deviceService.importDevice(file));
+ }
}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/excel/upload/DeviceImport.java b/cnas-device/src/main/java/com/ruoyi/device/excel/upload/DeviceImport.java
new file mode 100644
index 0000000..86904df
--- /dev/null
+++ b/cnas-device/src/main/java/com/ruoyi/device/excel/upload/DeviceImport.java
@@ -0,0 +1,73 @@
+package com.ruoyi.device.excel.upload;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import lombok.Data;
+
+@Data
+@ColumnWidth(22)
+public class DeviceImport {
+
+ @ExcelProperty("浠櫒鍚嶇О*")
+ private String deviceName;
+
+ @ExcelProperty("瑙勬牸鍨嬪彿*")
+ private String specificationModel;
+
+ @ExcelProperty("绠$悊缂栧彿*")
+ private String managementNumber;
+
+ @ExcelProperty("鏍″噯鏈夋晥鏈�*(yyyy-MM-dd)")
+ private String activationDate;
+
+ @ExcelProperty("鎵�灞為儴闂�*")
+ private String laboratoryName;
+
+ @ExcelProperty("褰撳墠鐘舵��*")
+ private String deviceStatus;
+
+ @ExcelProperty("鏍″噯鍛ㄦ湡(鏈�)*")
+ private String calibrationDate;
+
+ @ExcelProperty("鑻辨枃鍚嶇О")
+ private String enDeviceName;
+
+ @ExcelProperty("鐢熶骇鍘傚")
+ private String manufacturer;
+
+ @ExcelProperty("鍑哄巶缂栧彿")
+ private String factoryNo;
+
+ @ExcelProperty("璧勪骇缂栫爜")
+ private String assetCode;
+
+ @ExcelProperty("浜у湴")
+ private String origin;
+
+ @ExcelProperty("璐疆鏃ユ湡(yyyy-MM-dd)")
+ private String acquisitionDate;
+
+ @ExcelProperty("璐熻矗浜�")
+ private String equipmentManagerName;
+
+ @ExcelProperty("瀛樻斁鐐�")
+ private String storagePoint;
+
+ @ExcelProperty("鎶�鏈寚鏍�")
+ private String technicalIndicators;
+
+ @ExcelProperty("鏍″噯鏈嶅姟鏈烘瀯")
+ private String calibrationServices;
+
+ @ExcelProperty("鏈�杩戞牎鍑嗘棩鏈�(yyyy-MM-dd)")
+ private String lastCalibrationDate;
+
+ @ExcelProperty("涓嬫鏍″噯鏃ユ湡(yyyy-MM-dd)")
+ private String nextCalibrationDate;
+
+ @ExcelProperty("璁惧绫诲瀷")
+ private String largeCategory;
+
+ @ExcelProperty("鍗曚环(涓囧厓)")
+ private String unitPrice;
+}
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceService.java b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceService.java
index 72073e9..a7c4845 100644
--- a/cnas-device/src/main/java/com/ruoyi/device/service/DeviceService.java
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/DeviceService.java
@@ -8,6 +8,7 @@
import com.ruoyi.device.dto.DeviceCollectionDto;
import com.ruoyi.device.dto.DeviceDto;
import com.ruoyi.device.pojo.Device;
+import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -54,4 +55,8 @@
* @param response
*/
void exportEquipmentDetails(HttpServletResponse response);
+
+ void downloadImportTemplate(HttpServletResponse response);
+
+ int importDevice(MultipartFile file);
}
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 c743869..570a0f8 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;
@@ -495,4 +506,179 @@
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> managementNumbers = new HashSet<>();
+ for (int i = 0; i < rows.size(); i++) {
+ String managementNumber = required(rows.get(i).getManagementNumber(), i + 2, "绠$悊缂栧彿");
+ if (!managementNumbers.add(managementNumber)) {
+ throw new RuntimeException("绗�" + (i + 2) + "琛岋細绠$悊缂栧彿" + managementNumber + "鍦ㄦ枃浠朵腑閲嶅");
+ }
+ }
+ Set<String> existingNumbers = baseMapper.selectList(Wrappers.<Device>lambdaQuery()
+ .in(Device::getManagementNumber, managementNumbers)
+ .select(Device::getManagementNumber))
+ .stream().map(Device::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, "绠$悊缂栧彿");
+ if (existingNumbers.contains(managementNumber)) {
+ throw new RuntimeException("绗�" + rowNumber + "琛岋細绠$悊缂栧彿" + 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(required(row.getDeviceName(), rowNumber, "浠櫒鍚嶇О"));
+ device.setSpecificationModel(required(row.getSpecificationModel(), rowNumber, "瑙勬牸鍨嬪彿"));
+ device.setManagementNumber(managementNumber);
+ device.setActivationDate(parseDate(row.getActivationDate(), rowNumber, "鏍″噯鏈夋晥鏈�", true));
+ 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(), rowNumber, "璐疆鏃ユ湡", false));
+ device.setStoragePoint(trim(row.getStoragePoint()));
+ device.setTechnicalIndicators(trim(row.getTechnicalIndicators()));
+ device.setCalibrationServices(trim(row.getCalibrationServices()));
+ device.setLastCalibrationDate(parseDate(row.getLastCalibrationDate(), rowNumber, "鏈�杩戞牎鍑嗘棩鏈�", false));
+ device.setNextCalibrationDate(parseDate(row.getNextCalibrationDate(), rowNumber, "涓嬫鏍″噯鏃ユ湡", false));
+ 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, int rowNumber, String column, boolean required) {
+ String text = trim(input);
+ if (StringUtils.isBlank(text)) {
+ if (required) {
+ throw new RuntimeException("绗�" + rowNumber + "琛岋細" + column + "涓嶈兘涓虹┖");
+ }
+ return null;
+ }
+ try {
+ return LocalDate.parse(text.substring(0, Math.min(text.length(), 10)).replace('/', '-'), DateTimeFormatter.ofPattern("yyyy-M-d"))
+ .atStartOfDay();
+ } catch (Exception e) {
+ throw new RuntimeException("绗�" + rowNumber + "琛岋細" + column + "鏍煎紡搴斾负yyyy-MM-dd", e);
+ }
+ }
+
+ 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 trim(String value) {
+ return value == null ? null : value.trim();
+ }
}
diff --git a/cnas-device/src/main/resources/mapper/DeviceMapper.xml b/cnas-device/src/main/resources/mapper/DeviceMapper.xml
index 2c2436a..5460a17 100644
--- a/cnas-device/src/main/resources/mapper/DeviceMapper.xml
+++ b/cnas-device/src/main/resources/mapper/DeviceMapper.xml
@@ -98,22 +98,22 @@
cmr.next_calibration_date as next_calibration_date_two,
GROUP_CONCAT(distinct inspection_item SEPARATOR ';') AS insProductItem,
u.name ,
- l.laboratory_name
+ sd.dept_name AS laboratory_name
FROM
device d
LEFT JOIN `user` u ON u.id = d.equipment_manager
- LEFT JOIN laboratory l ON l.id = d.subordinate_departments_id
+ LEFT JOIN sys_dept sd ON sd.dept_id = d.subordinate_departments_id AND sd.del_flag = '0'
LEFT JOIN device_metric_record cmr ON d.id = cmr.device_id
LEFT JOIN structure_item_parameter sip ON FIND_IN_SET(sip.id, d.ins_product_ids)
<where>
<if test="laboratoryNameIsNull != null and laboratoryNameIsNull == true">
- l.laboratory_name is null
+ sd.dept_name is null
</if>
AND cmr.type = 'calibrate' or cmr.type is null or cmr.type = ''
</where>
GROUP BY
d.id,
- u.name, l.laboratory_name
+ u.name, sd.dept_name
) a
<if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
${ew.customSqlSegment}
@@ -149,14 +149,14 @@
<select id="treeDevice" resultMap="treeDeviceDto">
select
d.id,
- case when l.laboratory_name is null || l.laboratory_name ='' then '鍏朵粬' else l.laboratory_name end as laboratory_name,
+ case when sd.dept_name is null || sd.dept_name ='' then '鍏朵粬' else sd.dept_name end as laboratory_name,
case when d.storage_point is null || d.storage_point ='' then '鍏朵粬' else d.storage_point end as storage_point,
d.device_name,
d.management_number,
null as value,
d.activation_date
from device d
- LEFT JOIN laboratory l ON l.id = d.subordinate_departments_id
+ LEFT JOIN sys_dept sd ON sd.dept_id = d.subordinate_departments_id AND sd.del_flag = '0'
<where>
<if test="deviceName!=null and deviceName!=''">
and device_name like concat('%',#{deviceName},'%')
@@ -167,18 +167,18 @@
<select id="selectDeviceByCode" resultType="com.ruoyi.device.dto.DeviceDto">
SELECT d.*,
GROUP_CONCAT(DISTINCT inspection_item SEPARATOR ';') AS ins_product_item,
- l.laboratory_name,
+ sd.dept_name AS laboratory_name,
u1.name equipmentManager_name,
u2.name authorized_person_name
FROM device d
LEFT JOIN structure_item_parameter sip ON FIND_IN_SET(sip.id, d.ins_product_ids)
- LEFT JOIN laboratory l ON d.subordinate_departments_id = l.id
+ LEFT JOIN sys_dept sd ON d.subordinate_departments_id = sd.dept_id AND sd.del_flag = '0'
LEFT JOIN user u1 ON u1.id = d.equipment_manager
LEFT JOIN user u2 ON u2.id = d.authorized_person
WHERE d.id = #{id}
GROUP BY d.id,
- l.laboratory_name,
+ sd.dept_name,
u1.name,
u2.name
</select>
diff --git a/cnas-require/src/main/java/com/ruoyi/require/controller/FeStandardSubstanceController.java b/cnas-require/src/main/java/com/ruoyi/require/controller/FeStandardSubstanceController.java
index 912fb7b..3951970 100644
--- a/cnas-require/src/main/java/com/ruoyi/require/controller/FeStandardSubstanceController.java
+++ b/cnas-require/src/main/java/com/ruoyi/require/controller/FeStandardSubstanceController.java
@@ -8,6 +8,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.require.excel.FeStandardSubstanceExcel;
+import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.require.pojo.FeStandardSubstance;
import com.ruoyi.require.service.FeStandardSubstanceService;
import io.swagger.annotations.Api;
@@ -77,4 +78,16 @@
.sheet("sheet")
.doWrite(studentList);
}
+
+ @ApiOperation(value = "涓嬭浇鏍囧噯鐗╄川瀵煎叆妯℃澘")
+ @GetMapping("/importTemplate")
+ public void importTemplate(HttpServletResponse response) {
+ feStandardSubstanceService.downloadImportTemplate(response);
+ }
+
+ @ApiOperation(value = "瀵煎叆鏍囧噯鐗╄川娓呭崟")
+ @PostMapping("/importStandardSubstance")
+ public Result importStandardSubstance(MultipartFile file) {
+ return Result.success(feStandardSubstanceService.importStandardSubstance(file));
+ }
}
diff --git a/cnas-require/src/main/java/com/ruoyi/require/excel/FeStandardSubstanceImport.java b/cnas-require/src/main/java/com/ruoyi/require/excel/FeStandardSubstanceImport.java
new file mode 100644
index 0000000..1588fd8
--- /dev/null
+++ b/cnas-require/src/main/java/com/ruoyi/require/excel/FeStandardSubstanceImport.java
@@ -0,0 +1,46 @@
+package com.ruoyi.require.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import lombok.Data;
+
+@Data
+@ColumnWidth(22)
+public class FeStandardSubstanceImport {
+
+ @ExcelProperty("鏍囧噯鐗╄川鍚嶇О*")
+ private String name;
+
+ @ExcelProperty("瑙勬牸鍨嬪彿*")
+ private String model;
+
+ @ExcelProperty("鐢熶骇鍘傚*")
+ private String factoryManufacturer;
+
+ @ExcelProperty("鍑哄巶缂栧彿*")
+ private String factoryNum;
+
+ @ExcelProperty("绠$悊缂栧彿*")
+ private String manageNum;
+
+ @ExcelProperty("涓嶇‘瀹氬害*")
+ private String uncertainty;
+
+ @ExcelProperty("鏁伴噺*")
+ private String quantity;
+
+ @ExcelProperty("璐疆鏃ユ湡*(yyyy-MM-dd)")
+ private String acquisitionDate;
+
+ @ExcelProperty("鏈夋晥鏈�*(yyyy-MM-dd)")
+ private String effectiveDate;
+
+ @ExcelProperty("妗f缂栧彿*")
+ private String fileNum;
+
+ @ExcelProperty("瀛樻斁浣嶇疆*")
+ private String position;
+
+ @ExcelProperty("澶囨敞")
+ private String remark;
+}
diff --git a/cnas-require/src/main/java/com/ruoyi/require/service/FeStandardSubstanceService.java b/cnas-require/src/main/java/com/ruoyi/require/service/FeStandardSubstanceService.java
index 19b2d9a..fd3d973 100644
--- a/cnas-require/src/main/java/com/ruoyi/require/service/FeStandardSubstanceService.java
+++ b/cnas-require/src/main/java/com/ruoyi/require/service/FeStandardSubstanceService.java
@@ -4,6 +4,9 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.require.pojo.FeStandardSubstance;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
/**
* <p>
@@ -16,4 +19,8 @@
public interface FeStandardSubstanceService extends IService<FeStandardSubstance> {
IPage<FeStandardSubstance> page(Page page, FeStandardSubstance feStandardSubstance);
+
+ void downloadImportTemplate(HttpServletResponse response);
+
+ int importStandardSubstance(MultipartFile file);
}
diff --git a/cnas-require/src/main/java/com/ruoyi/require/service/impl/FeStandardSubstanceServiceImpl.java b/cnas-require/src/main/java/com/ruoyi/require/service/impl/FeStandardSubstanceServiceImpl.java
index 2dd1a9c..d4aac72 100644
--- a/cnas-require/src/main/java/com/ruoyi/require/service/impl/FeStandardSubstanceServiceImpl.java
+++ b/cnas-require/src/main/java/com/ruoyi/require/service/impl/FeStandardSubstanceServiceImpl.java
@@ -1,12 +1,33 @@
package com.ruoyi.require.service.impl;
+import com.alibaba.excel.EasyExcel;
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.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.require.excel.FeStandardSubstanceImport;
import com.ruoyi.require.mapper.FeStandardSubstanceMapper;
import com.ruoyi.require.pojo.FeStandardSubstance;
import com.ruoyi.require.service.FeStandardSubstanceService;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.net.URLEncoder;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* <p>
@@ -23,4 +44,120 @@
public IPage<FeStandardSubstance> page(Page page, FeStandardSubstance feStandardSubstance) {
return this.baseMapper.getPage(page,feStandardSubstance);
}
+
+ @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(), FeStandardSubstanceImport.class)
+ .sheet("鏍囧噯鐗╄川瀵煎叆妯℃澘")
+ .doWrite(Collections.emptyList());
+ } catch (Exception e) {
+ throw new RuntimeException("鏍囧噯鐗╄川瀵煎叆妯℃澘涓嬭浇澶辫触", e);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int importStandardSubstance(MultipartFile file) {
+ if (file == null || file.isEmpty()) {
+ throw new ErrorException("璇烽�夋嫨闇�瑕佸鍏ョ殑Excel鏂囦欢");
+ }
+ String fileName = file.getOriginalFilename();
+ if (fileName == null || !fileName.toLowerCase(Locale.ROOT).endsWith(".xlsx")) {
+ throw new ErrorException("浠呮敮鎸�.xlsx鏍煎紡鏂囦欢");
+ }
+
+ final List<FeStandardSubstanceImport> rows;
+ try {
+ rows = EasyExcel.read(file.getInputStream())
+ .head(FeStandardSubstanceImport.class)
+ .sheet()
+ .doReadSync();
+ } catch (Exception e) {
+ throw new ErrorException("Excel瑙f瀽澶辫触锛岃浣跨敤涓嬭浇鐨勫鍏ユā鏉�");
+ }
+ if (CollectionUtils.isEmpty(rows)) {
+ throw new ErrorException("瀵煎叆鏂囦欢娌℃湁鏍囧噯鐗╄川鏁版嵁");
+ }
+
+ Set<String> manageNumbers = new HashSet<>();
+ for (int i = 0; i < rows.size(); i++) {
+ String manageNum = required(rows.get(i).getManageNum(), i + 2, "绠$悊缂栧彿");
+ if (!manageNumbers.add(manageNum)) {
+ throw new ErrorException("绗�" + (i + 2) + "琛岋細绠$悊缂栧彿" + manageNum + "鍦ㄦ枃浠朵腑閲嶅");
+ }
+ }
+ Set<String> existingNumbers = baseMapper.selectList(Wrappers.<FeStandardSubstance>lambdaQuery()
+ .in(FeStandardSubstance::getManageNum, manageNumbers)
+ .select(FeStandardSubstance::getManageNum))
+ .stream().map(FeStandardSubstance::getManageNum).collect(Collectors.toSet());
+
+ List<FeStandardSubstance> substances = new ArrayList<>();
+ for (int i = 0; i < rows.size(); i++) {
+ int rowNumber = i + 2;
+ FeStandardSubstanceImport row = rows.get(i);
+ String manageNum = required(row.getManageNum(), rowNumber, "绠$悊缂栧彿");
+ if (existingNumbers.contains(manageNum)) {
+ throw new ErrorException("绗�" + rowNumber + "琛岋細绠$悊缂栧彿" + manageNum + "宸插瓨鍦�");
+ }
+
+ FeStandardSubstance substance = new FeStandardSubstance();
+ substance.setName(required(row.getName(), rowNumber, "鏍囧噯鐗╄川鍚嶇О"));
+ substance.setModel(required(row.getModel(), rowNumber, "瑙勬牸鍨嬪彿"));
+ substance.setFactoryManufacturer(required(row.getFactoryManufacturer(), rowNumber, "鐢熶骇鍘傚"));
+ substance.setFactoryNum(required(row.getFactoryNum(), rowNumber, "鍑哄巶缂栧彿"));
+ substance.setManageNum(manageNum);
+ substance.setUncertainty(required(row.getUncertainty(), rowNumber, "涓嶇‘瀹氬害"));
+ substance.setQuantity(parseQuantity(row.getQuantity(), rowNumber));
+ substance.setAcquisitionDate(parseDate(row.getAcquisitionDate(), rowNumber, "璐疆鏃ユ湡"));
+ substance.setEffectiveDate(parseDate(row.getEffectiveDate(), rowNumber, "鏈夋晥鏈�"));
+ substance.setFileNum(required(row.getFileNum(), rowNumber, "妗f缂栧彿"));
+ substance.setPosition(required(row.getPosition(), rowNumber, "瀛樻斁浣嶇疆"));
+ substance.setRemark(trim(row.getRemark()));
+ substance.setState(0);
+ substances.add(substance);
+ }
+ saveBatch(substances);
+ return substances.size();
+ }
+
+ private Long parseQuantity(String input, int rowNumber) {
+ String value = required(input, rowNumber, "鏁伴噺");
+ try {
+ long quantity = Long.parseLong(value);
+ if (quantity <= 0) {
+ throw new NumberFormatException();
+ }
+ return quantity;
+ } catch (NumberFormatException e) {
+ throw new ErrorException("绗�" + rowNumber + "琛岋細鏁伴噺蹇呴』鏄ぇ浜�0鐨勬暣鏁�");
+ }
+ }
+
+ private LocalDateTime parseDate(String input, int rowNumber, String column) {
+ String value = required(input, rowNumber, column);
+ try {
+ return LocalDate.parse(value.substring(0, Math.min(value.length(), 10)).replace('/', '-'), DateTimeFormatter.ofPattern("yyyy-M-d"))
+ .atStartOfDay();
+ } catch (Exception e) {
+ throw new ErrorException("绗�" + rowNumber + "琛岋細" + column + "鏍煎紡搴斾负yyyy-MM-dd");
+ }
+ }
+
+ private String required(String input, int rowNumber, String column) {
+ String value = trim(input);
+ if (StringUtils.isBlank(value)) {
+ throw new ErrorException("绗�" + rowNumber + "琛岋細" + column + "涓嶈兘涓虹┖");
+ }
+ return value;
+ }
+
+ private String trim(String value) {
+ return value == null ? null : value.trim();
+ }
}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
index 1315240..cb1f287 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -874,6 +874,19 @@
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateInsOrder(InsOrderUpdateDto insOrderUpdateDto) {
+ InsOrder currentOrder = insOrderMapper.selectById(insOrderUpdateDto.getInsOrder().getId());
+ if (currentOrder == null || !Objects.equals(currentOrder.getState(), 2)) {
+ throw new ErrorException("鍙湁閫�鍥炵殑妫�楠屽崟鍙互淇敼");
+ }
+ boolean hasSelectedProduct = CollectionUtils.isNotEmpty(insOrderUpdateDto.getSampleProduct())
+ && insOrderUpdateDto.getSampleProduct().stream()
+ .filter(sample -> CollectionUtils.isNotEmpty(sample.getInsProduct()))
+ .flatMap(sample -> sample.getInsProduct().stream())
+ .anyMatch(product -> Objects.equals(product.getState(), 1));
+ if (!hasSelectedProduct) {
+ throw new ErrorException("璇疯嚦灏戦�夋嫨涓�涓楠岄」");
+ }
+
// 淇敼璁㈠崟
insOrderUpdateDto.getInsOrder().setState(0);
insOrderUpdateDto.getInsOrder().setTell("");
@@ -881,11 +894,50 @@
// 淇敼妫�楠岄」
for (SampleProductDto sampleProductDto : insOrderUpdateDto.getSampleProduct()) {
+ Long sampleCount = insSampleMapper.selectCount(Wrappers.<InsSample>lambdaQuery()
+ .eq(InsSample::getId, sampleProductDto.getId())
+ .eq(InsSample::getInsOrderId, insOrderUpdateDto.getInsOrder().getId()));
+ if (sampleCount == 0) {
+ throw new ErrorException("妫�楠屾牱鍝佹暟鎹紓甯�");
+ }
+
insSampleService.update(Wrappers.<InsSample>lambdaUpdate()
.eq(InsSample::getId, sampleProductDto.getId())
.set(InsSample::getSpecialStandardMethod, sampleProductDto.getSpecialStandardMethod()));
- insProductService.updateBatchById(sampleProductDto.getInsProduct());
+ List<InsProduct> products = sampleProductDto.getInsProduct();
+ if (CollectionUtils.isEmpty(products)) {
+ continue;
+ }
+
+ Set<Integer> productIds = insProductMapper.selectList(Wrappers.<InsProduct>lambdaQuery()
+ .eq(InsProduct::getInsSampleId, sampleProductDto.getId()))
+ .stream()
+ .map(InsProduct::getId)
+ .collect(Collectors.toSet());
+ if (products.stream().anyMatch(product -> product.getId() != null && !productIds.contains(product.getId()))) {
+ throw new ErrorException("妫�楠岄」鏁版嵁寮傚父");
+ }
+
+ List<Integer> removedIds = products.stream()
+ .filter(product -> product.getId() != null && !Objects.equals(product.getState(), 1))
+ .map(InsProduct::getId)
+ .collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(removedIds)) {
+ insProductService.removeByIds(removedIds);
+ }
+
+ List<InsProduct> existingProducts = products.stream()
+ .filter(product -> product.getId() != null && Objects.equals(product.getState(), 1))
+ .collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(existingProducts)) {
+ insProductService.updateBatchById(existingProducts);
+ }
+
+ List<InsProduct> newProducts = products.stream()
+ .filter(product -> product.getId() == null && Objects.equals(product.getState(), 1))
+ .collect(Collectors.toList());
+ addInsProductMethod(sampleProductDto.getId(), newProducts);
}
return true;
diff --git a/inspect-server/src/main/resources/mapper/InsSampleMapper.xml b/inspect-server/src/main/resources/mapper/InsSampleMapper.xml
index 4698777..ac53df7 100644
--- a/inspect-server/src/main/resources/mapper/InsSampleMapper.xml
+++ b/inspect-server/src/main/resources/mapper/InsSampleMapper.xml
@@ -518,6 +518,7 @@
ipr.equip_value,
ip.method_s,
ip.radius,
+ ip.structure_item_parameter_id,
isa.special_standard_method
from ins_sample isa
left join ins_product ip on isa.id = ip.ins_sample_id
--
Gitblit v1.9.3