cnas-server/src/main/java/com/yuanchu/mom/controller/DeviceController.java
@@ -1,20 +1,16 @@ package com.yuanchu.mom.controller; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yuanchu.mom.annotation.ValueAuth; import com.yuanchu.mom.annotation.ValueClassify; import com.yuanchu.mom.dto.DataConfigDto; import com.yuanchu.mom.dto.DeviceDto; import com.yuanchu.mom.pojo.DataConfig; import com.yuanchu.mom.pojo.Device; import com.yuanchu.mom.pojo.PkMaster; import com.yuanchu.mom.service.DataConfigService; import com.yuanchu.mom.service.DeviceService; import com.yuanchu.mom.service.PkMasterService; import com.yuanchu.mom.utils.DataAcquisition; import com.yuanchu.mom.utils.JackSonUtil; import com.yuanchu.mom.vo.Result; import io.swagger.annotations.Api; @@ -154,24 +150,6 @@ return Result.success(deviceService.selectDeviceByCode(code)); } // @ValueClassify("设备") // @ApiOperation(value = "查询数采配置") // @PostMapping("/getNumberCollect") // public Result<?> getNumberCollect(Integer id) { // DeviceDto1 deviceDto1 = new DeviceDto1(); // BeanUtils.copyProperties(deviceService.getById(id),deviceDto1); // return Result.success(deviceDto1); // } // // @ValueClassify("设备") // @ApiOperation(value = "维护数采配置") // @PostMapping("/numberCollect") // public Result<?> numberCollect(@RequestBody DeviceDto1 deviceDto1) { // Device device = new Device(); // BeanUtils.copyProperties(deviceDto1,device); // return Result.success(deviceService.updateById(device)); // } @ValueAuth @ValueClassify("设备") @ApiOperation("/数采-数据采集") @@ -186,49 +164,16 @@ @ApiOperation(value = "判断该设备是否可以数采") @GetMapping("/determineWhetherToCollectData") public Result<?> determineWhetherToCollectData(@RequestParam("managementNumber") String managementNumber, HttpServletRequest request) { String ip = DataAcquisition.getIp(request); Device device = deviceService.getOne(Wrappers.<Device>lambdaQuery() .eq(Device::getManagementNumber, managementNumber) .eq(Device::getIp, ip)); if (ObjectUtils.isEmpty(device)) { return Result.success(false); } if (ObjectUtils.isEmpty(device.getFileType()) || ObjectUtils.isEmpty(device.getCollectUrl())) { return Result.success(false); } else { return Result.success(true); } return deviceService.determineWhetherToCollectData(managementNumber, request); } @ValueClassify("设备") @ApiOperation(value = "维护数采配置") @PostMapping("/saveDataAcquisitionConfiguration") public Result<?> saveDataAcquisitionConfiguration(@RequestParam(value = "deviceId") Integer deviceId, @RequestBody DataConfigDto dataConfigList) { if (dataConfigList.getIsDevice()) { Device device = new Device(); device.setId(deviceId); device.setCollectUrl(dataConfigList.getCollectUrl()); device.setStorageUrl(dataConfigList.getStorageUrl()); device.setIp(dataConfigList.getIp()); device.setFileType(dataConfigList.getFileType()); device.setMdbEntrustCode(dataConfigList.getMdbEntrustCode()); device.setMdbSampleCode(dataConfigList.getMdbSampleCode()); deviceService.updateById(device); } else { dataConfigService.saveOrUpdateBatch(dataConfigList.getDataConfigList()); } dataConfigService.saveDataAcquisitionConfiguration(deviceId, dataConfigList); return Result.success(); } // @ValueClassify("设备") // @ApiOperation(value = "查询数采配置") // @GetMapping("/queryDataAcquisitionConfiguration") // public Result<?> queryDataAcquisitionConfiguration(@RequestParam("deviceId") Integer deviceId, @RequestParam("insProductItem") String insProductItem) { // List<DataConfig> list = dataConfigService.list(Wrappers.<DataConfig>lambdaQuery() // .eq(DataConfig::getDeviceId, deviceId) // .eq(DataConfig::getInsProductItem, insProductItem)); // return Result.success(list); // } @ValueClassify("设备") @ApiOperation(value = "查询数采配置") @@ -237,15 +182,7 @@ @RequestParam("isDevice") Boolean isDevice, @RequestParam(value = "inspectionItem", required = false) String inspectionItem, @RequestParam(value = "inspectionItemSubclass", required = false) String inspectionItemSubclass) { if (isDevice) { List<DataConfig> list = dataConfigService.list(Wrappers.<DataConfig>lambdaQuery() .eq(DataConfig::getDeviceId, deviceId) .eq(DataConfig::getInspectionItem, inspectionItem) .eq(DataConfig::getInspectionItemSubclass, inspectionItemSubclass)); return Result.success(list); } else { return Result.success(dataConfigService.selectDataConfigList(deviceId)); } return dataConfigService.queryDataAcquisitionConfiguration(deviceId, isDevice, inspectionItem, inspectionItemSubclass); } @ValueClassify("设备") @@ -287,5 +224,12 @@ public Result<?> temDataAcquisition2(@RequestBody PkMaster pkMaster) { return Result.success(pkMasterService.temDataAcquisition2(pkMaster)); } @ApiOperation(value = "数采-公式计算") @PostMapping("/formulaCalculation") @ValueAuth public Result<?> formulaCalculation(@RequestBody Map<String, Object> map) { return Result.success(deviceService.formulaCalculation(map)); } } cnas-server/src/main/java/com/yuanchu/mom/dto/DataConfigDto.java
@@ -26,8 +26,11 @@ private String ip; @ApiModelProperty("数采-委托字段") private String mdbEntrustCode; private String entrustCode; @ApiModelProperty("数采-样品字段") private String mdbSampleCode; private String sampleCode; @ApiModelProperty("数采-db,mdb文件名称") private String dbFileName; } cnas-server/src/main/java/com/yuanchu/mom/dto/DeviceConfigDtoPage.java
@@ -70,6 +70,12 @@ @ApiModelProperty(value = "检验项目id") private Integer structureItemParameterId; private String mdbEntrustCode; private String mdbSampleCode; @ApiModelProperty("数采-委托字段") private String entrustCode; @ApiModelProperty("数采-样品字段") private String sampleCode; @ApiModelProperty("数采-db,mdb文件名称") private String dbFileName; } cnas-server/src/main/java/com/yuanchu/mom/pojo/DataConfig.java
@@ -63,4 +63,7 @@ @ApiModelProperty("检验项id") private Integer structureItemParameterId; @ApiModelProperty("序号") private String serialNumber; } cnas-server/src/main/java/com/yuanchu/mom/pojo/Device.java
@@ -136,8 +136,11 @@ private Boolean isItADataAcquisitionDevice; @ApiModelProperty("数采-委托字段") private String mdbEntrustCode; private String entrustCode; @ApiModelProperty("数采-样品字段") private String mdbSampleCode; private String sampleCode; @ApiModelProperty("数采-db,mdb文件名称") private String dbFileName; } cnas-server/src/main/java/com/yuanchu/mom/service/DataConfigService.java
@@ -1,10 +1,9 @@ package com.yuanchu.mom.service; import com.baomidou.mybatisplus.extension.service.IService; import com.yuanchu.mom.dto.DeviceConfigDtoPage; import com.yuanchu.mom.dto.DataConfigDto; import com.yuanchu.mom.pojo.DataConfig; import java.util.List; import com.yuanchu.mom.vo.Result; /** * <p> @@ -16,7 +15,9 @@ */ public interface DataConfigService extends IService<DataConfig> { List<DeviceConfigDtoPage> selectDataConfigList(Integer deviceId); void deleteDataConfig(); void saveDataAcquisitionConfiguration(Integer deviceId, DataConfigDto dataConfigList); Result<?> queryDataAcquisitionConfiguration(Integer deviceId, Boolean isDevice, String inspectionItem, String inspectionItemSubclass); } cnas-server/src/main/java/com/yuanchu/mom/service/DeviceService.java
@@ -5,7 +5,6 @@ import com.yuanchu.mom.dto.ADto; import com.yuanchu.mom.dto.DeviceDto; import com.yuanchu.mom.pojo.Device; import com.yuanchu.mom.pojo.PkMaster; import com.yuanchu.mom.vo.Result; import javax.servlet.http.HttpServletRequest; @@ -42,4 +41,8 @@ List<ADto> menu(); List<Map<String, Object>> treeDevice(String deviceName); Result<?> determineWhetherToCollectData(String managementNumber, HttpServletRequest request); Object formulaCalculation(Map<String, Object> map); } cnas-server/src/main/java/com/yuanchu/mom/service/impl/DataConfigServiceImpl.java
@@ -1,11 +1,15 @@ package com.yuanchu.mom.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yuanchu.mom.common.GetLook; import com.yuanchu.mom.dto.DeviceConfigDtoPage; import com.yuanchu.mom.dto.DataConfigDto; import com.yuanchu.mom.mapper.DataConfigMapper; import com.yuanchu.mom.mapper.DeviceMapper; import com.yuanchu.mom.pojo.DataConfig; import com.yuanchu.mom.pojo.Device; import com.yuanchu.mom.service.DataConfigService; import com.yuanchu.mom.vo.Result; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; @@ -25,11 +29,9 @@ private GetLook getLook; private DeviceMapper deviceMapper; private DataConfigMapper dataConfigMapper; @Override public List<DeviceConfigDtoPage> selectDataConfigList(Integer deviceId) { return dataConfigMapper.selectDataConfigList(deviceId); } @Override public void deleteDataConfig() { @@ -38,4 +40,35 @@ dataConfigMapper.deleteBatchIds(integers); } } @Override public void saveDataAcquisitionConfiguration(Integer deviceId, DataConfigDto dataConfigList) { if (dataConfigList.getIsDevice()) { Device device = new Device(); device.setId(deviceId); device.setCollectUrl(dataConfigList.getCollectUrl()); device.setStorageUrl(dataConfigList.getStorageUrl()); device.setIp(dataConfigList.getIp()); device.setFileType(dataConfigList.getFileType()); device.setEntrustCode(dataConfigList.getEntrustCode()); device.setSampleCode(dataConfigList.getSampleCode()); device.setDbFileName(dataConfigList.getDbFileName()); deviceMapper.updateById(device); } else { this.saveOrUpdateBatch(dataConfigList.getDataConfigList()); } } @Override public Result<?> queryDataAcquisitionConfiguration(Integer deviceId, Boolean isDevice, String inspectionItem, String inspectionItemSubclass) { if (isDevice) { List<DataConfig> list = baseMapper.selectList(Wrappers.<DataConfig>lambdaQuery() .eq(DataConfig::getDeviceId, deviceId) .eq(DataConfig::getInspectionItem, inspectionItem) .eq(DataConfig::getInspectionItemSubclass, inspectionItemSubclass)); return Result.success(list); } else { return Result.success(dataConfigMapper.selectDataConfigList(deviceId)); } } } cnas-server/src/main/java/com/yuanchu/mom/service/impl/DeviceServiceImpl.java
@@ -2,7 +2,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -31,11 +31,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.math.BigDecimal; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -149,6 +151,7 @@ String ip = DataAcquisition.getIp(request); List<Device> device = baseMapper.selectList(Wrappers.<Device>lambdaQuery() .eq(Device::getIp, ip)); // 1、检验 if(device.size() > 1) { String str = ""; for (Device device1 : device) { @@ -163,6 +166,7 @@ if (ObjectUtils.isEmpty(device.get(0).getFileType()) || ObjectUtils.isEmpty(device.get(0).getCollectUrl())) { throw new ErrorException("未给该:" + device.get(0).getDeviceName() + "设备配置采集路径或文件后缀!"); } // 2、取设备关联的检验项,检验子项 List<DataConfig> list1 = new ArrayList<>(); inspectionItemSubclass.forEach(i -> { List<DataConfig> list = dataConfigService.list(Wrappers.<DataConfig>lambdaQuery() @@ -172,12 +176,14 @@ .orderBy(false, false, DataConfig::getId)); list1.addAll(list); }); Map<String, String> map = DataAcquisition.dataAcquisitionEntrance(list1, device.get(0), entrustCode, sampleCode, ip); // 3、采集,取数据,参与公式计算 Map<String, Object> map = DataAcquisition.dataAcquisitionEntrance(list1, device.get(0), entrustCode, sampleCode, ip); // 4、造循环次数 if (ObjectUtils.isNotEmpty(map)) { String frequency = DataAcquisition.createFrequency(entrustCode, sampleCode); map.put("frequency", frequency); return Result.success(DataAcquisition.createFrequency(entrustCode, sampleCode, map)); } else { return Result.success(null); } return Result.success(map); } @Override @@ -966,4 +972,184 @@ ));*/ return listMap; } @Override public Result<?> determineWhetherToCollectData(String managementNumber, HttpServletRequest request) { String ip = DataAcquisition.getIp(request); Device device = baseMapper.selectOne(Wrappers.<Device>lambdaQuery() .eq(Device::getManagementNumber, managementNumber) .eq(Device::getIp, ip)); if (ObjectUtils.isEmpty(device)) { return Result.success(false); } if (ObjectUtils.isEmpty(device.getFileType()) || ObjectUtils.isEmpty(device.getCollectUrl())) { return Result.success(false); } else { return Result.success(true); } } @Override public Object formulaCalculation(Map<String, Object> map) { map.forEach((key, value) -> { Map<String, Object> jsonObject = JSONObject.parseObject(JSON.toJSONString(map.get(key)), Map.class); for (Map.Entry<String, Object> entry : jsonObject.entrySet()) { String sonKey = entry.getKey(); Object sonValue = entry.getValue(); if (!sonKey.equals("frequency")) { Map<String, Object> formulaData = JSONObject.parseObject(JSON.toJSONString(sonValue), Map.class); if (formulaData.containsKey("result") && formulaData.containsKey("isCalculation") && formulaData.containsKey("formula")) { String formula = formulaData.get("formula").toString(); Boolean isCalculation = Boolean.valueOf(formulaData.get("isCalculation").toString()); if (isCalculation) { List<Object> resultList = new ArrayList<>(); try { resultList = JSONObject.parseArray(JSON.toJSONString(formulaData.get("result")), Object.class); } catch (Exception e) { Object result = formulaData.get("result").toString(); resultList.add(result); } ArrayList<Object> list = new ArrayList<>(); resultList.forEach(i -> { List<Object> strings = Arrays.asList(i.toString().split(",")); String result = calculationFormula(strings, formula); list.add(result); }); formulaData.put("isCalculation", false); formulaData.put("result", list); } } jsonObject.put(sonKey, formulaData); } } map.put(key, jsonObject); }); return map; } public String calculationFormula(List<Object> list, String formula) { //首先将list转换为bigdecmic List<BigDecimal> bigDecimalList = list.stream() .map(obj -> { return new BigDecimal((obj).toString()); }).collect(Collectors.toList()); System.out.println(bigDecimalList); //将中文的(转换英文的()) formula = formula.replace("(", "(") .replace(")", ")") .replace(",", ","); //然后提取公式 String strs = formula.substring(0, formula.indexOf("(")); String upperStr = strs.toUpperCase(); if (upperStr.matches(".*\\d.*")) { upperStr = ""; } System.out.println(upperStr); //然后获取最外面括号里面的值,再根据","分割 int start = formula.indexOf("("); int end = -1; int a = 0; for (int i = start; i < formula.length(); i++) { char c = formula.charAt(i); if (c == '(') { a++; } else if (c == ')') { a--; if (a == 0) { end = i; } } } if (start == -1 || end == -1) { throw new ErrorException("公式括号不匹配: " + formula); } String argumentsStr = formula.substring(start + 1, end); List<String> arguments = new ArrayList<>(); int bracketCount = 0; StringBuilder currentArgument = new StringBuilder(); for (char c : argumentsStr.toCharArray()) { if (c == ',' && bracketCount == 0) { arguments.add(currentArgument.toString()); currentArgument.setLength(0); } else { if (c == '(') bracketCount++; if (c == ')') bracketCount--; currentArgument.append(c); } } arguments.add(currentArgument.toString()); String[] bracketStrs = arguments.toArray(new String[0]); List<BigDecimal> results = new ArrayList<>(); for (String expr : bracketStrs) { System.out.println("替换前" + expr); Pattern pattern = Pattern.compile("([A-Z])(\\d+)"); Matcher matcher = pattern.matcher(expr); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String letter = matcher.group(1); int index = Integer.parseInt(matcher.group(2)) - 1; // 将1-based转为0-based if (index < bigDecimalList.size()) { matcher.appendReplacement(sb, bigDecimalList.get(index).toString()); } else { throw new RuntimeException("公式中的下标 " + index + " 超出范围"); } } matcher.appendTail(sb); System.out.println("替换后" + sb.toString()); // 计算表达式 ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); try { Object result = engine.eval(sb.toString()); results.add(new BigDecimal(result.toString())); } catch (Exception e) { throw new IllegalArgumentException("无法计算公式: " + sb, e); } } // 根据函数名称进行相应计算 BigDecimal finalResult; if (upperStr.equals("") || upperStr == null) { finalResult = results.get(0); } else { switch (upperStr) { case "MAX": finalResult = results.stream().max(BigDecimal::compareTo) .orElseThrow(() -> new IllegalArgumentException("无法计算MAX值")); break; case "MIN": finalResult = results.stream().min(BigDecimal::compareTo) .orElseThrow(() -> new IllegalArgumentException("无法计算MIN值")); break; case "SUM": finalResult = results.stream().reduce(BigDecimal.ZERO, BigDecimal::add); break; case "ABS": finalResult = results.stream().map(BigDecimal::abs).reduce(BigDecimal.ZERO, BigDecimal::add); break; case "AVERAGE": finalResult = results.stream().reduce(BigDecimal.ZERO, BigDecimal::divide) .divide(BigDecimal.valueOf(results.size()), 2, BigDecimal.ROUND_HALF_UP); break; case "MEDIAN": int size = results.size(); if (size % 2 == 1) { finalResult = results.get(size / 2); } else { BigDecimal sum = results.get(size / 2 - 1).add(results.get(size / 2)); finalResult = sum.divide(BigDecimal.valueOf(2), 2, BigDecimal.ROUND_HALF_UP); } break; default: throw new UnsupportedOperationException("暂不支持函数: " + upperStr); } } System.out.println(results); System.out.println("计算结果: " + finalResult); return finalResult.toString(); // 否则:没有公式代表不需要计算,直接提取List里面的数据 } } cnas-server/src/main/java/com/yuanchu/mom/utils/DataAcquisition.java
@@ -10,11 +10,9 @@ import com.yuanchu.mom.pojo.DataConfig; import com.yuanchu.mom.pojo.Device; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -38,13 +36,13 @@ * @param device * @return */ public static Map<String, String> dataAcquisitionEntrance(List<DataConfig> dataConfig, Device device, String entrustCode, String sampleCode, String ip) { public static Map<String, Object> dataAcquisitionEntrance(List<DataConfig> dataConfig, Device device, String entrustCode, String sampleCode, String ip) { /** * filePath 文件采集路径 * fileExtension 文件后缀 * entrustCode 委托编号 * sampleCode 样品编号 * mdbEntrustCode mdb文件需要:委托编号字段 * mdbEntrustCode mdb文件需要:委托编号字段 为什么没有去这个mdb前缀呢?因为已经给客户的部分电脑上安装了采集器,而用户不接受重新安装采集器,所以就没有去除 * mdbSampleCode mdb文件需要:样品编号字段 */ String http = HTTP + ip + GETFILE + @@ -52,8 +50,9 @@ "&fileExtension=" + device.getFileType() + "&entrustCode=" + entrustCode + "&sampleCode=" + sampleCode + "&mdbEntrustCode=" + device.getMdbEntrustCode() + "&mdbSampleCode=" + device.getMdbSampleCode(); "&mdbEntrustCode=" + device.getEntrustCode() + "&mdbSampleCode=" + device.getSampleCode() + "&dbFileName=" + device.getDbFileName(); String result = null; try { result = HttpUtil.get(http); @@ -62,33 +61,28 @@ } JSONObject jsonObject = JSON.parseObject(result); if (Objects.equals(jsonObject.get("code"), 1)) { if (ObjectUtils.isEmpty(jsonObject.get("msg"))) { throw new ErrorException("未查询到数据,可能文件路径配置错误!"); throw new ErrorException(jsonObject.get("msg") + ""); } else { System.out.println(jsonObject); throw new ErrorException("未知错误,请联系管理员!"); } } else { String data = jsonObject.get("data").toString(); String data = jsonObject.get("data") + ""; // 考虑到一个检测项可能会存在多个数采配置,所以需要进行分组 Map<String, List<DataConfig>> userMap = dataConfig.stream() .peek(i -> i.setInsProductItem( i.getInspectionItem().equals(i.getInspectionItemSubclass()) ? i.getInspectionItem() + "," : i.getInspectionItem() + "," + i.getInspectionItemSubclass() )) .collect(Collectors.groupingBy(DataConfig::getInsProductItem)); Map<String, String> map; Map<String, Object> map; switch (device.getFileType()) { case ".docx": map = analysisString(data, userMap); map = analysisString(data, userMap, device, entrustCode, sampleCode); break; case ".xlsx": map = analysisList(data, userMap); map = analysisList(data, userMap, device, entrustCode, sampleCode); break; case ".txt": map = analysisTxt(data, userMap); map = analysisTxt(data, userMap, device, entrustCode, sampleCode); break; case ".csv": map = analysisList(data, userMap); map = analysisList(data, userMap, device, entrustCode, sampleCode); break; case ".mdb": map = analysisMdb(data, userMap); @@ -97,7 +91,7 @@ map = analysisDb(data, userMap); break; case ".png": map = readPngString(data, userMap); map = readPngString(data, userMap, device); break; default: map = null; @@ -106,15 +100,45 @@ // 如果存在存储地址,则移动地址 if (ObjectUtils.isNotEmpty(device.getStorageUrl())) { String s = HTTP + ip + MOVEFILE + "?startFilePath=" + device.getCollectUrl() + "&endFilePath=" + device.getStorageUrl() + "&fileType=" + device.getFileType(); String storageUrlResult = HttpUtil.get(s); JSONObject storageUrlResultJson = JSON.parseObject(storageUrlResult); HttpUtil.get(s); } return map; } } public static String createFrequency(String entrustCode, String sampleCode) { String key = frequency + ":" + entrustCode + ":" + sampleCode; public static Map<String, Object> createFrequency(String entrustCode, String sampleCode, Map<String, Object> map) { HashSet<String> set = new HashSet<>(); map.forEach((key, value) -> { String[] split = key.split(","); String inspectionItem = split[0]; // 只要有一个不为空就set进去 if (ObjectUtils.isNotEmpty(value)) { set.add(inspectionItem); } }); Map<String, Object> result = new HashMap<>(); for (String inspectionItemKey : set) { Map<String, Object> hashMap = new HashMap<>(); map.forEach((key, value) -> { String[] split = key.split(","); String inspectionItem = split[0]; if (inspectionItemKey.equals(inspectionItem)) { if (split.length > 1) { hashMap.put(split[1], value); } else { hashMap.put(split[0], value); } } }); String frequency = createKey(entrustCode, sampleCode, inspectionItemKey); hashMap.put("frequency", frequency); result.put(inspectionItemKey, hashMap); } return result; } public static String createKey(String entrustCode, String sampleCode, String inspectionItemKey) { String key = frequency + ":" + entrustCode + ":" + sampleCode + ":" + inspectionItemKey; boolean b = RedisUtil.hasKey(key); String frequencyValue; if (b) { @@ -134,27 +158,46 @@ * @param dataConfig * @return */ private static Map<String, String> analysisDb(String data, Map<String, List<DataConfig>> dataConfig) { private static Map<String, Object> analysisDb(String data, Map<String, List<DataConfig>> dataConfig) { JSONObject jsonObject = JSON.parseObject(data); Map<String, String> map = new HashMap<>(); Map<String, Object> map = new HashMap<>(); if (jsonObject.isEmpty()) { return map; } JSONArray dataList = JSONArray.parseArray(jsonObject.get("data").toString()); dataConfig.forEach((k, v) -> { AtomicInteger numberOfDataEntries = new AtomicInteger(); List<Object> list = new ArrayList<>(); for (int config = 0; config < v.size(); config++) { String referx = getRefer(v.get(config).getReferx()); String refery = getRefer(v.get(config).getRefery()); for (int i = 0; i < dataList.size(); i++) { JSONObject jsonObject1 = JSON.parseObject(dataList.get(i).toString()); Object o = jsonObject1.get(referx); Object o = jsonObject1.get(refery); if (ObjectUtils.isNotEmpty(o)) { numberOfDataEntries.addAndGet(1); list.add(o); } } } // 拼接数采配置 List<Object> result = new ArrayList<>(); for (int i = 0; i < numberOfDataEntries.get(); i++) { String aggregate = ""; for (int j = 0; j < v.size(); j++) { int index; if (j == 0) { index = i; } else { index = numberOfDataEntries.get() + i; } aggregate += list.get(index).toString() + ","; } int lastIndex = aggregate.lastIndexOf(","); String substring = aggregate.substring(0, lastIndex); result.add(substring); } // 进行公式计算 String resultValue = calculationFormula(list, v.get(0), k); Object resultValue = calculationFormula(result, v.get(0), k); map.put(k, resultValue); }); return map; @@ -165,27 +208,46 @@ * @param dataConfig * @return */ private static Map<String, String> analysisMdb(String data, Map<String, List<DataConfig>> dataConfig) { private static Map<String, Object> analysisMdb(String data, Map<String, List<DataConfig>> dataConfig) { JSONObject jsonObject = JSON.parseObject(data); Map<String, String> map = new HashMap<>(); Map<String, Object> map = new HashMap<>(); if (jsonObject.isEmpty()) { return map; } JSONArray dataList = JSONArray.parseArray(jsonObject.get("data").toString()); dataConfig.forEach((k, v) -> { AtomicInteger numberOfDataEntries = new AtomicInteger(); List<Object> list = new ArrayList<>(); for (int config = 0; config < v.size(); config++) { String referx = getRefer(v.get(config).getReferx()); String refery = getRefer(v.get(config).getRefery()); for (int i = 0; i < dataList.size(); i++) { JSONObject jsonObject1 = JSON.parseObject(dataList.get(i).toString()); Object o = jsonObject1.get(referx); Object o = jsonObject1.get(refery); if (ObjectUtils.isNotEmpty(o)) { numberOfDataEntries.addAndGet(1); list.add(o); } } } // 拼接数采配置 List<Object> result = new ArrayList<>(); for (int i = 0; i < numberOfDataEntries.get(); i++) { String aggregate = ""; for (int j = 0; j < v.size(); j++) { int index; if (j == 0) { index = i; } else { index = numberOfDataEntries.get() + i; } aggregate += list.get(index).toString() + ","; } int lastIndex = aggregate.lastIndexOf(","); String substring = aggregate.substring(0, lastIndex); result.add(substring); } // 进行公式计算 String resultValue = calculationFormula(list, v.get(0), k); Object resultValue = calculationFormula(result, v.get(0), k); map.put(k, resultValue); }); return map; @@ -200,8 +262,8 @@ * @param dataConfig 用户配置好的x,y轴定位数据与参照物 * @return */ private static Map<String, String> readPngString(String data, Map<String, List<DataConfig>> dataConfig) { Map<String, String> map = new HashMap<>(); private static Map<String, Object> readPngString(String data, Map<String, List<DataConfig>> dataConfig, Device device) { Map<String, Object> map = new HashMap<>(); dataConfig.forEach((k, v) -> { List<Object> list = new ArrayList<>(); for (int config = 0; config < v.size(); config++) { @@ -230,7 +292,7 @@ } } // 进行公式计算 String resultValue = calculationFormula(list, v.get(0), k); Object resultValue = calculationFormula(list, v.get(0), k); map.put(k, resultValue); }); return map; @@ -243,143 +305,26 @@ * @param dataConfig 存储公式的对象 * @return */ private static String calculationFormula(List<Object> list, DataConfig dataConfig, String insProductItem) { private static Object calculationFormula(List<Object> list, DataConfig dataConfig, String insProductItem) { if (list.size() == 0) { return null; } Map<String, Object> hashMap = new HashMap<>(); // 如果不为空,进行公式计算 if (ObjectUtils.isNotEmpty(dataConfig.getFormula())) { String formula = dataConfig.getFormula(); //首先将list转换为bigdecmic List<BigDecimal> bigDecimalList = list.stream() .map(obj -> { return new BigDecimal((obj).toString()); }).collect(Collectors.toList()); System.out.println(bigDecimalList); //将中文的(转换英文的()) formula = formula.replace("(", "(") .replace(")", ")") .replace(",", ","); //然后提取公式 String strs = formula.substring(0,formula.indexOf("(")); String upperStr = strs.toUpperCase(); if (upperStr.matches(".*\\d.*")){ upperStr=""; } System.out.println(upperStr); //然后获取最外面括号里面的值,再根据","分割 int start = formula.indexOf("("); int end = -1; int a = 0; for (int i = start; i < formula.length(); i++) { char c = formula.charAt(i); if (c == '(') { a++; } else if (c == ')') { a--; if (a == 0) { end = i; } } } if (start == -1 || end == -1) { throw new ErrorException("公式括号不匹配: " + formula); } String argumentsStr = formula.substring(start + 1, end); List<String> arguments = new ArrayList<>(); int bracketCount = 0; StringBuilder currentArgument = new StringBuilder(); for (char c : argumentsStr.toCharArray()) { if (c == ',' && bracketCount == 0) { arguments.add(currentArgument.toString()); currentArgument.setLength(0); } else { if (c == '(') bracketCount++; if (c == ')') bracketCount--; currentArgument.append(c); } } arguments.add(currentArgument.toString()); String[] bracketStrs = arguments.toArray(new String[0]); List<BigDecimal> results = new ArrayList<>(); for (String expr : bracketStrs) { System.out.println("替换前" + expr); Pattern pattern = Pattern.compile("([A-Z])(\\d+)"); Matcher matcher = pattern.matcher(expr); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String letter = matcher.group(1); int index = Integer.parseInt(matcher.group(2)) - 1; // 将1-based转为0-based if (index < bigDecimalList.size()) { matcher.appendReplacement(sb, bigDecimalList.get(index).toString()); } else { throw new RuntimeException("公式中的下标 " + index + " 超出范围"); } } matcher.appendTail(sb); System.out.println("替换后" + sb.toString()); // 计算表达式 ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); try { Object result = engine.eval(sb.toString()); results.add(new BigDecimal(result.toString())); } catch (Exception e) { throw new IllegalArgumentException("无法计算公式: " + sb, e); } } // 根据函数名称进行相应计算 BigDecimal finalResult; if (upperStr.equals("")||upperStr==null) { finalResult=results.get(0); }else { switch (upperStr) { case "MAX": finalResult = results.stream().max(BigDecimal::compareTo) .orElseThrow(() -> new IllegalArgumentException("无法计算MAX值")); break; case "MIN": finalResult = results.stream().min(BigDecimal::compareTo) .orElseThrow(() -> new IllegalArgumentException("无法计算MIN值")); break; case "SUM": finalResult = results.stream().reduce(BigDecimal.ZERO, BigDecimal::add); break; case "ABS": finalResult = results.stream().map(BigDecimal::abs).reduce(BigDecimal.ZERO, BigDecimal::add); break; case "AVERAGE": finalResult = results.stream().reduce(BigDecimal.ZERO, BigDecimal::divide) .divide(BigDecimal.valueOf(results.size()), 2, BigDecimal.ROUND_HALF_UP); break; case "MEDIAN": int size = results.size(); if (size % 2 == 1) { finalResult = results.get(size / 2); } else { BigDecimal sum = results.get(size / 2 - 1).add(results.get(size / 2)); finalResult = sum.divide(BigDecimal.valueOf(2), 2, BigDecimal.ROUND_HALF_UP); } break; default: throw new UnsupportedOperationException("暂不支持函数: " + upperStr); } } System.out.println(results); System.out.println("计算结果: " + finalResult); return finalResult.toString(); hashMap.put("isCalculation", true); hashMap.put("formula", dataConfig.getFormula()); // 否则:没有公式代表不需要计算,直接提取List里面的数据 } else { // 这里只会取列表第一个数据 hashMap.put("isCalculation", false); } // 为了给前端做数据区分 if (list.size() > 1) { throw new ErrorException("未给:" + insProductItem + " 配置公式,可是却采集到了" + list.size() + "个值!分别为:" + list); hashMap.put("result", list); } else { return list.get(0).toString(); hashMap.put("result", list.get(0).toString()); } } return hashMap; } /** @@ -389,12 +334,20 @@ * @param dataConfig 用户配置好的x,y轴定位数据与参照物 * @return */ private static Map<String, String> analysisTxt(String data, Map<String, List<DataConfig>> dataConfig) { Map<String, String> map = new HashMap<>(); private static Map<String, Object> analysisTxt(String data, Map<String, List<DataConfig>> dataConfig, Device device, String entrustCode, String sampleCode) { Map<String, Object> map = new HashMap<>(); dataConfig.forEach((k, v) -> { List<Object> list = analyzeData(data, v, k, ","); List<Object> list = new ArrayList<>(); // 委托编号与样品编号不存在,定:1、Y定范围,X定横坐标;2、只存在Y;3、只存在X if (ObjectUtils.isEmpty(device.getEntrustCode()) && ObjectUtils.isEmpty(device.getSampleCode())) { list = analyzeData(data, v, k, ","); // 委托编号与样品编号存在 } else if (ObjectUtils.isNotEmpty(device.getEntrustCode()) && ObjectUtils.isNotEmpty(device.getSampleCode())) { list = analyzeDataEntrustCodAndSampleCode(data, v, k, ",", device, entrustCode, sampleCode); } // 进行公式计算 String resultValue = calculationFormula(list, v.get(0), k); Object resultValue = calculationFormula(list, v.get(0), k); map.put(k, resultValue); }); return map; @@ -405,16 +358,24 @@ * @param dataConfig 用户配置好的x,y轴定位数据与参照物 * @return */ private static Map<String, String> analysisString(String data, Map<String, List<DataConfig>> dataConfig) { private static Map<String, Object> analysisString(String data, Map<String, List<DataConfig>> dataConfig, Device device, String entrustCode, String sampleCode) { String processingDataAfterSpaces = data .replaceAll(" +", splitIdentifier) .replaceAll("\r", "") .replaceAll(" ", ""); Map<String, String> map = new HashMap<>(); Map<String, Object> map = new HashMap<>(); dataConfig.forEach((k, v) -> { List<Object> list = analyzeData(processingDataAfterSpaces, v, k, splitIdentifier); List<Object> list = new ArrayList<>(); // 委托编号与样品编号不存在,定:1、Y定范围,X定横坐标;2、只存在Y;3、只存在X if (ObjectUtils.isEmpty(device.getEntrustCode()) && ObjectUtils.isEmpty(device.getSampleCode())) { list = analyzeData(processingDataAfterSpaces, v, k, splitIdentifier); // 委托编号与样品编号存在 } else if (ObjectUtils.isNotEmpty(device.getEntrustCode()) && ObjectUtils.isNotEmpty(device.getSampleCode())) { list = analyzeDataEntrustCodAndSampleCode(processingDataAfterSpaces, v, k, splitIdentifier, device, entrustCode, sampleCode); } // 进行公式计算 String resultValue = calculationFormula(list, v.get(0), k); Object resultValue = calculationFormula(list, v.get(0), k); map.put(k, resultValue); }); return map; @@ -427,16 +388,95 @@ * @param dataConfig 用户配置好的x,y轴定位数据与参照物 * @return */ public static Map<String, String> analysisList(String data, Map<String, List<DataConfig>> dataConfig) { Map<String, String> map = new HashMap<>(); public static Map<String, Object> analysisList(String data, Map<String, List<DataConfig>> dataConfig, Device device, String entrustCode, String sampleCode) { Map<String, Object> map = new HashMap<>(); dataConfig.forEach((k, v) -> { // 用户可能给一个子项目配置了多个配置,即一个项目取多个值,所以需要循环 List<Object> list = analyzeData(data, v, k, splitIdentifier); List<Object> list = new ArrayList<>(); // 委托编号与样品编号不存在,定:1、Y定范围,X定横坐标;2、只存在Y;3、只存在X if (ObjectUtils.isEmpty(device.getEntrustCode()) && ObjectUtils.isEmpty(device.getSampleCode())) { list = analyzeData(data, v, k, splitIdentifier); // 委托编号与样品编号存在 } else if (ObjectUtils.isNotEmpty(device.getEntrustCode()) && ObjectUtils.isNotEmpty(device.getSampleCode())) { list = analyzeDataEntrustCodAndSampleCode(data, v, k, splitIdentifier, device, entrustCode, sampleCode); } // 进行公式计算 String resultValue = calculationFormula(list, v.get(0), k); Object resultValue = calculationFormula(list, v.get(0), k); map.put(k, resultValue); }); return map; } private static List<Object> analyzeDataEntrustCodAndSampleCode(String data, List<DataConfig> v, String k, String splitIdentifier, Device device, String entrustCodeValue, String sampleCodeValue) { entrustCodeValue = entrustCodeValue.replaceAll(" ", ""); sampleCodeValue = sampleCodeValue.replaceAll(" ", ""); // 最终结果 List<Object> list = new ArrayList<>(); int numberOfDataEntries = 0; // 取entrustCode与sampleCode所在位 for (int config = 0; config < v.size(); config++) { numberOfDataEntries = 0; Integer entrustCodeY = null; Integer sampleCodeY = null; Integer referYCoordinate = null; String refery = getRefer(v.get(config).getRefery()); String entrustCode = getRefer(device.getEntrustCode()); // 委托编号字段 String sampleCode = getRefer(device.getSampleCode()); // 样品编号字段 if (ObjectUtils.isEmpty(refery)) { continue; } // 去除所有的空格,通过\n将字符串分割为行 String[] aColumnY = data.replaceAll(" ", "").split("\n"); for (int i = 0; i < aColumnY.length; i++) { // 如果通过判断,定位到Y轴 if (aColumnY[i].contains(entrustCode) && aColumnY[i].contains(sampleCode)) { String[] aLine = aColumnY[i].split(splitIdentifier); for (int j = 0; j < aLine.length; j++) { if (aLine[j].contains(entrustCode)) { entrustCodeY = j; } if (aLine[j].contains(sampleCode) ) { sampleCodeY = j; } if (aLine[j].contains(refery)) { referYCoordinate = j; } } } if (ObjectUtils.isNotEmpty(entrustCodeY) && ObjectUtils.isNotEmpty(sampleCodeY) && ObjectUtils.isNotEmpty(referYCoordinate)) { String[] aLine = aColumnY[i].split(splitIdentifier); try { if (aLine[entrustCodeY].contains(entrustCodeValue) && aLine[sampleCodeY].contains(sampleCodeValue)) { String result = aLine[referYCoordinate]; // 防止计算公式的时候出现:[null] 这种数据 if (ObjectUtils.isNotEmpty(result)) { numberOfDataEntries += 1; list.add(result); } } } catch (Exception e) {} } } } // 拼接数采配置 List<Object> result = new ArrayList<>(); for (int i = 0; i < numberOfDataEntries; i++) { String aggregate = ""; for (int j = 0; j < v.size(); j++) { int index; if (j == 0) { index = i; } else { index = numberOfDataEntries + i; } aggregate += list.get(index).toString() + ","; } int lastIndex = aggregate.lastIndexOf(","); String substring = aggregate.substring(0, lastIndex); result.add(substring); } return result; } // 由于在方法中会大量的判断,所以做一个方法 @@ -453,12 +493,24 @@ return ObjectUtils.isNotEmpty(refer) ? refer.replaceAll(" ", "") : ""; } /** * 委托编号与样品编号都为空执行 * * @param data * @param v * @param k * @param split * @return */ public static List<Object> analyzeData(String data, List<DataConfig> v, String k, String split) { List<Object> list = new ArrayList<>(); for (int config = 0; config < v.size(); config++) { // 取两个用户配置的参照物 String referx = getRefer(v.get(config).getReferx()); String refery = getRefer(v.get(config).getRefery()); if (ObjectUtils.isEmpty(refery) && ObjectUtils.isEmpty(referx)) { continue; } // 最终结果 String result = null; // 通过\n将字符串分割为行 @@ -466,10 +518,30 @@ Integer end = null; // 采集数据:Y轴 for (int i = 0; i < aColumnY.length; i++) { // 如果Y参照不为空与X参照为空则执行,同时该行包含Y参照 if (ObjectUtils.isNotEmpty(refery) && ObjectUtils.isEmpty(referx) && aColumnY[i].contains(refery)) { // 取Y坐标值 int y = getXOrY(v.get(config).getY(), k, "Y"); String[] aLineX = aColumnY[i].split(split); for (int j = 0; j < aLineX.length; j++) { if (aLineX[j].contains(refery)) { String[] split1 = new String[0]; try { split1 = aColumnY[i + y].split(split); } catch (Exception e) { throw new ErrorException(k + ":Y轴定位超出!"); } try { result = split1[j]; } catch (Exception e) { throw new ErrorException(k + ":X轴定位超出!"); } } } // 如果Y参照不为空与X参照不为空则执行,此处Y定区域 } else if (ObjectUtils.isNotEmpty(refery) && ObjectUtils.isNotEmpty(referx)) { // 取x的值,防止报错 int x = getXOrY(v.get(config).getX(), k, "X"); // 如果Y与X用户都配置了则执行 if (ObjectUtils.isNotEmpty(refery)) { // 取Y坐标值 int y = getXOrY(v.get(config).getY(), k, "Y"); // 缓存Y的结束值 @@ -490,9 +562,11 @@ } } } // 如果只配置了X,则执行下面的代码 // 如果X参照不为空同时该行包含X参照,则执行下面的代码 } else if (aColumnY[i].contains(referx) && ObjectUtils.isEmpty(refery)) { String[] aLineX = aColumnY[i].split(split); // 取x的值,防止报错 int x = getXOrY(v.get(config).getX(), k, "X"); for (int j = 0; j < aLineX.length; j++) { if (aLineX[j].contains(referx)) { try { cnas-server/src/main/resources/mapper/DataConfigMapper.xml
@@ -18,8 +18,9 @@ d.collect_url, d.storage_url, d.ip, d.mdb_entrust_code, d.mdb_sample_code, d.entrust_code, d.sample_code, d.db_file_name, ip.inspection_item, if(ip.inspection_item_subclass is not null and ip.inspection_item_subclass != '', ip.inspection_item_subclass, ip.inspection_item) inspection_item_subclass, inspect-server/src/main/java/com/yuanchu/mom/service/impl/InsOrderServiceImpl.java
@@ -5,7 +5,7 @@ import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; @@ -36,10 +36,6 @@ import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -648,11 +644,18 @@ .collect(Collectors.groupingBy(CostStatisticsDto::getCompany)); try { // 新建ExcelWriter ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build(); // 新建ExcelWriter ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) .registerWriteHandler(new SimpleColumnWidthStyleStrategy(25)) .build(); for (Map.Entry<String, List<CostStatisticsDto>> companyDataEntry : groupByCompany.entrySet()) { String sheetName = companyDataEntry.getKey(); List<CostStatisticsDto> dataList = companyDataEntry.getValue(); WriteSheet mainSheet = EasyExcel.writerSheet(sheetName).head(CostStatisticsDto.class).build(); WriteSheet mainSheet = EasyExcel.writerSheet(sheetName) .head(CostStatisticsDto.class) .registerWriteHandler(new SimpleColumnWidthStyleStrategy(25)) .build(); excelWriter.write(dataList, mainSheet); } // 关闭流