|
|
@@ -0,0 +1,373 @@
|
|
|
+package com.energy.manage.service.service.vibration.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
+import cn.hutool.core.text.StrFormatter;
|
|
|
+import cn.hutool.core.text.csv.CsvUtil;
|
|
|
+import cn.hutool.core.text.csv.CsvWriter;
|
|
|
+import cn.hutool.core.util.CharsetUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.energy.manage.common.reponse.HttpResult;
|
|
|
+import com.energy.manage.service.client.skf.AuthClient;
|
|
|
+import com.energy.manage.service.client.skf.DynamicMeasurementsClient;
|
|
|
+import com.energy.manage.service.constant.client.skf.SkfClientConstants;
|
|
|
+import com.energy.manage.service.domain.client.skf.AutoTokenVO;
|
|
|
+import com.energy.manage.service.domain.client.skf.DynamicMeasurementsVo;
|
|
|
+import com.energy.manage.service.domain.client.skf.HierarchyListVo;
|
|
|
+import com.energy.manage.service.service.vibration.VibrationService;
|
|
|
+import com.energy.manage.service.util.HttpGetClient;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.Month;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.format.TextStyle;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class VibrationServiceImpl implements VibrationService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private AuthClient authClient;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DynamicMeasurementsClient dynamicMeasurementsClient;
|
|
|
+
|
|
|
+ // 定义时间格式
|
|
|
+ private final String dateTimeFormatter = "yyyy-MM-dd";
|
|
|
+
|
|
|
+ private final String dateFormatter = "MM-dd";
|
|
|
+
|
|
|
+ private String dynamicMeasurementsUrl = "http://192.168.50.242:5000/v1/points/{}/dynamicMeasurements";
|
|
|
+
|
|
|
+ private ZoneId shanghaiZone = ZoneId.of("Asia/Shanghai");
|
|
|
+
|
|
|
+ private String yesterdayTime = LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern(dateFormatter));
|
|
|
+
|
|
|
+ @Value("${skf.data.path}")
|
|
|
+ private String skfDataPath;
|
|
|
+
|
|
|
+ // @Value("${skf.data.condition}")
|
|
|
+ private String condition = "七台河数据2";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void extractSkfPointData() {
|
|
|
+
|
|
|
+ // 获取组织结构
|
|
|
+ List<HierarchyListVo> hierarchyListVoList = getHierarchyLists();
|
|
|
+ log.info("获取SKF数据组织结构树 >>> " + JSON.toJSONString(hierarchyListVoList));
|
|
|
+
|
|
|
+ // 企业
|
|
|
+ company:
|
|
|
+ for (HierarchyListVo companyHierarchyListVo : hierarchyListVoList) {
|
|
|
+ // 风场
|
|
|
+ field:
|
|
|
+ for (HierarchyListVo fieldHierarchyListVo : companyHierarchyListVo.getChildren()) {
|
|
|
+ if (CollectionUtils.isEmpty(fieldHierarchyListVo.getChildren())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ //风机,特殊情况需要单独处理(风机到部件到具体测点有可能少一层部件)需要根据不同风场进行单独处理,风机直接获取测点id,跳过部件
|
|
|
+ engine:
|
|
|
+ for (HierarchyListVo engineHierarchyListVo : fieldHierarchyListVo.getChildren()) {
|
|
|
+ if (CollectionUtils.isEmpty(engineHierarchyListVo.getChildren())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+// List<String> subs = StrUtil.split(condition,",");
|
|
|
+// if(CollUtil.contains(subs,fieldHierarchyListVo.getName())){
|
|
|
+// getIointIdCreateDataCsv(engineHierarchyListVo,companyHierarchyListVo.getName(),
|
|
|
+// fieldHierarchyListVo.getName(),engineHierarchyListVo.getName(), engineHierarchyListVo.getName());
|
|
|
+// }else{
|
|
|
+ //部件
|
|
|
+ assembly:
|
|
|
+ for (HierarchyListVo assemblyHierarchyListVo : engineHierarchyListVo.getChildren()) {
|
|
|
+ if (CollectionUtils.isEmpty(assemblyHierarchyListVo.getChildren())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 具体测点
|
|
|
+ for (HierarchyListVo pointHierarchyListVo : assemblyHierarchyListVo.getChildren()) {
|
|
|
+ //获取测点id值,调用skf接口获取振动测点值
|
|
|
+ log.info("部件测点路径:>>> " + companyHierarchyListVo.getName() + " -> " + fieldHierarchyListVo.getName() +
|
|
|
+ " -> " + engineHierarchyListVo.getName() + " -> " + assemblyHierarchyListVo.getName() + " -> " + pointHierarchyListVo.getName());
|
|
|
+ // 测点id
|
|
|
+ Integer pointId = pointHierarchyListVo.getId();
|
|
|
+ log.info("测点id >>> " + pointId);
|
|
|
+
|
|
|
+ List<DynamicMeasurementsVo> dynamicMeasurementsList = getDynamicMeasurementsList(pointId);
|
|
|
+ if (CollectionUtil.isEmpty(dynamicMeasurementsList)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 拼接服务器地址
|
|
|
+ String dataPath = skfDataPath + companyHierarchyListVo.getName() + "/" + fieldHierarchyListVo.getName() + "/"
|
|
|
+ + engineHierarchyListVo.getName() + "/" + getCurrentYearByTimeZone(this.shanghaiZone) + "/"
|
|
|
+ + yesterdayTime;
|
|
|
+
|
|
|
+ String fileNamePrefix = fieldHierarchyListVo.getName() + "_" + engineHierarchyListVo.getName() + "_" +
|
|
|
+ pointHierarchyListVo.getName();
|
|
|
+
|
|
|
+ // 获取具体数据并生成csv
|
|
|
+ dynamicMeasurementsConvertData(dynamicMeasurementsList, dataPath, fileNamePrefix);
|
|
|
+ }
|
|
|
+ }
|
|
|
+// }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.info(" >>> skf接口处理完毕 <<<");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过测点id获取测点数据并生成csv文件
|
|
|
+ *
|
|
|
+ * @param poinIdhierarchyListVo
|
|
|
+ * @param companyName
|
|
|
+ * @param fieldName
|
|
|
+ * @param engineName
|
|
|
+ * @param assemblyName
|
|
|
+ */
|
|
|
+ private void getIointIdCreateDataCsv(HierarchyListVo poinIdhierarchyListVo, String companyName, String fieldName,
|
|
|
+ String engineName, String assemblyName) {
|
|
|
+ if (poinIdhierarchyListVo == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 具体测点
|
|
|
+ for (HierarchyListVo pointHierarchyListVo : poinIdhierarchyListVo.getChildren()) {
|
|
|
+ //获取测点id值,调用skf接口获取振动测点值
|
|
|
+ log.info("部件测点路径:>>> " + companyName + " -> " + fieldName +
|
|
|
+ " -> " + engineName + " -> " + assemblyName + " -> " + pointHierarchyListVo.getName());
|
|
|
+ // 测点id
|
|
|
+ Integer pointId = pointHierarchyListVo.getId();
|
|
|
+ log.info("测点id >>> " + pointId);
|
|
|
+
|
|
|
+ List<DynamicMeasurementsVo> dynamicMeasurementsList = getDynamicMeasurementsList(pointId);
|
|
|
+ if (CollectionUtil.isEmpty(dynamicMeasurementsList)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 拼接服务器地址
|
|
|
+ String dataPath = skfDataPath + companyName + "/" + fieldName + "/"
|
|
|
+ + engineName + "/" + getCurrentYearByTimeZone(this.shanghaiZone) + "/"
|
|
|
+ + yesterdayTime;
|
|
|
+
|
|
|
+ String fileNamePrefix = fieldName + "_" + engineName + "_" +
|
|
|
+ pointHierarchyListVo.getName();
|
|
|
+
|
|
|
+ // 获取具体数据并生成csv
|
|
|
+ dynamicMeasurementsConvertData(dynamicMeasurementsList, dataPath, fileNamePrefix);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将测点数据转换抽取
|
|
|
+ *
|
|
|
+ * @param dynamicMeasurementsList
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private void dynamicMeasurementsConvertData(List<DynamicMeasurementsVo> dynamicMeasurementsList, String dataPath, String fileNamePrefix) {
|
|
|
+ dynamic:
|
|
|
+ for (DynamicMeasurementsVo dynamicMeasurementsVo : dynamicMeasurementsList) {
|
|
|
+ List<Double> doubleList = Lists.newLinkedList();
|
|
|
+ List<DynamicMeasurementsVo.MeasurementsDTO> dynamicMeasurementsVoMeasurements = dynamicMeasurementsVo.getMeasurements();
|
|
|
+ for (DynamicMeasurementsVo.MeasurementsDTO dto : dynamicMeasurementsVoMeasurements) {
|
|
|
+ CollectionUtil.addAll(doubleList, dto.getValues());
|
|
|
+ }
|
|
|
+ if (CollectionUtils.isEmpty(doubleList)) {
|
|
|
+ break dynamic;
|
|
|
+ }
|
|
|
+ String fileName = fileNamePrefix + "_" + dynamicMeasurementsVo.getSpeed() + "_" + utctolocal(dynamicMeasurementsVo.getReadingTimeUTC()) + "_cms.csv";
|
|
|
+ //生成csv文件
|
|
|
+ createCsvFile(doubleList, dataPath, fileName);
|
|
|
+ log.info("抽取skf数据并生成csv文件 >>>> " + fileName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过测点id获取数据
|
|
|
+ *
|
|
|
+ * @param pointId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<DynamicMeasurementsVo> getDynamicMeasurementsList(Integer pointId) {
|
|
|
+ // 获取开始的时间
|
|
|
+ String fromDateUTC = LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern(dateTimeFormatter));
|
|
|
+ // 获取结束的时间,当前时间
|
|
|
+ String toDateUTC = LocalDate.now().format(DateTimeFormatter.ofPattern(dateTimeFormatter));
|
|
|
+
|
|
|
+ String skfToken = getSkfAutoToken();
|
|
|
+ if (StringUtils.isEmpty(skfToken)) {
|
|
|
+ log.info(" >>>>>> 获取skftoken失败 <<<<<< ");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ log.info(" >>>>>> 获取skftoken成功 <<<<<< " + skfToken);
|
|
|
+ List<DynamicMeasurementsVo> lists = Lists.newArrayList();
|
|
|
+ String url = StrFormatter.format(dynamicMeasurementsUrl, pointId);
|
|
|
+ // 动态参数
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("fromDateUTC", fromDateUTC);
|
|
|
+ params.put("toDateUTC", toDateUTC);
|
|
|
+
|
|
|
+ //发送请求
|
|
|
+ HttpResult result = HttpGetClient.sendWithAuthAndParams(url, skfToken, params);
|
|
|
+
|
|
|
+ // 处理响应结果
|
|
|
+ if (result.isSuccess()) {
|
|
|
+ log.info("请求成功,状态码: " + result.getStatusCode());
|
|
|
+ result.getData().ifPresent(data -> System.out.println("响应内容: " + data));
|
|
|
+ lists = JSONArray.parseArray(result.getData().get(), DynamicMeasurementsVo.class);
|
|
|
+ return lists;
|
|
|
+ } else {
|
|
|
+ log.error("请求失败: " + result.getMessage());
|
|
|
+ if (result.getStatusCode() != -1) {
|
|
|
+ log.error("状态码: " + result.getStatusCode() + " >>>>>> 无测点数据");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过接口获取SKF数据组织结构树
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<HierarchyListVo> getHierarchyLists() {
|
|
|
+ String skfToken = getSkfAutoToken();
|
|
|
+ if (StringUtils.isEmpty(skfToken)) {
|
|
|
+ log.info(" >>>>>> 获取skftoken失败 <<<<<< ");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<HierarchyListVo> list = dynamicMeasurementsClient.getSkfHierarchy(skfToken);
|
|
|
+ return CollectionUtils.isEmpty(list) ? null : list;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取token
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getSkfAutoToken() {
|
|
|
+ // 获取token
|
|
|
+ AutoTokenVO autoTokenVO = authClient.getSkfToken(SkfClientConstants.SKF_TOKEN_GRANT_TYPE,
|
|
|
+ SkfClientConstants.SKF_TOKEN_USERNAME, SkfClientConstants.SKF_TOKEN_PASSWORD);
|
|
|
+ return "Bearer " + autoTokenVO.getAccess_token();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出csv格式工具类
|
|
|
+ *
|
|
|
+ * @param result 导出数据
|
|
|
+ * @param fileName 文件名
|
|
|
+ */
|
|
|
+ private void createCsvFile(List result, String path, String fileName) {
|
|
|
+ try {
|
|
|
+ // 输出的文件流保存到本地文件
|
|
|
+ File tempFile = new File(path);
|
|
|
+ if (!tempFile.exists()) {
|
|
|
+ tempFile.mkdirs();
|
|
|
+ }
|
|
|
+ //构造文件
|
|
|
+ String fullPath = path + "/" + fileName;
|
|
|
+ File csvFile = new File(fullPath);
|
|
|
+ //导入HuTool中CSV工具包的CsvWriter类,设置导出字符类型, CHARSET_UTF_8
|
|
|
+ CsvWriter writer = CsvUtil.getWriter(csvFile, CharsetUtil.CHARSET_UTF_8);
|
|
|
+ //通过CsvWriter中的write方法写入数据
|
|
|
+ writer.write(result);
|
|
|
+ writer.close(); //关闭CsvWriter
|
|
|
+ log.info("CSV 文件生成成功!路径:" + fullPath);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("CSV 文件生成失:" + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取指定时区的当前年份(解决跨时区年份偏差问题)
|
|
|
+ * 适用场景:服务器时区与业务时区不一致(如服务器用UTC,业务用北京时区)
|
|
|
+ *
|
|
|
+ * @param zoneId 时区(如 ZoneId.of("Asia/Shanghai") 北京时区,ZoneId.of("UTC") 世界标准时间)
|
|
|
+ * @return 4位年份整数(如 2025)
|
|
|
+ * @throws IllegalArgumentException 若传入无效时区ID
|
|
|
+ */
|
|
|
+ public static int getCurrentYearByTimeZone(ZoneId zoneId) {
|
|
|
+ if (zoneId == null) {
|
|
|
+ throw new IllegalArgumentException("时区不能为空,请传入有效的ZoneId(如ZoneId.of(\"Asia/Shanghai\"))");
|
|
|
+ }
|
|
|
+ // 指定时区获取当前日期,再提取年份
|
|
|
+ return LocalDate.now(zoneId).getYear();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取“M月d日”格式(中文口语化格式,如 9月8日、12月31日)
|
|
|
+ * 适用场景:中文展示(前端页面、通知文案)
|
|
|
+ *
|
|
|
+ * @param zoneId 时区(可为null,默认系统时区)
|
|
|
+ * @return M月d日 格式的月日字符串
|
|
|
+ */
|
|
|
+ public static String getMonthDayAsChinese(ZoneId zoneId) {
|
|
|
+ ZoneId actualZone = (zoneId == null) ? ZoneId.systemDefault() : zoneId;
|
|
|
+ // 格式模板:M=一位/两位数月,d=一位/两位数日(自动省略前导0,更符合中文习惯)
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M月d日");
|
|
|
+ return LocalDate.now(actualZone).format(formatter);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 适用场景:月份名称展示(如“当前月份:九月”)、枚举判断等
|
|
|
+ *
|
|
|
+ * @param zoneId 时区
|
|
|
+ * @param locale 语言地区(如 Locale.CHINA 中文,Locale.ENGLISH 英文)
|
|
|
+ * @return 本地化的月份名称(如“九月”“September”)
|
|
|
+ */
|
|
|
+ private String getCurrentMonthAsName(ZoneId zoneId, Locale locale) {
|
|
|
+ ZoneId actualZone = (zoneId == null) ? ZoneId.systemDefault() : zoneId;
|
|
|
+ Locale actualLocale = (locale == null) ? Locale.getDefault() : locale;
|
|
|
+
|
|
|
+ // 1. 获取Month枚举(如 SEPTEMBER)
|
|
|
+ Month currentMonth = LocalDate.now(actualZone).getMonth();
|
|
|
+ // 2. 转换为本地化完整名称(TextStyle.FULL 表示完整名称,如“九月”而非“九”)
|
|
|
+ return currentMonth.getDisplayName(TextStyle.FULL, actualLocale);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前月份(数字形式,1-12)
|
|
|
+ * 适用场景:数值判断(如“当前月份是否为12月”)、数据库存储等
|
|
|
+ *
|
|
|
+ * @param zoneId 时区(如 ZoneId.of("Asia/Shanghai"),默认系统时区)
|
|
|
+ * @return 月份数字(1=1月,12=12月)
|
|
|
+ */
|
|
|
+ public static int getCurrentMonthAsNumber(ZoneId zoneId) {
|
|
|
+ // 若未指定时区,使用系统默认时区
|
|
|
+ ZoneId actualZone = (zoneId == null) ? ZoneId.systemDefault() : zoneId;
|
|
|
+ // LocalDate.now(时区) 获取指定时区的当前日期,getMonthValue() 提取1-12的月份
|
|
|
+ return LocalDate.now(actualZone).getMonthValue();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 时间转换
|
|
|
+ *
|
|
|
+ * @param utcTime
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String utctolocal(String utcTime) {
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
|
|
+ LocalDateTime dateTime = LocalDateTime.parse(utcTime, formatter);
|
|
|
+ return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
|
|
+ }
|
|
|
+
|
|
|
+}
|