diff --git a/pqs-common/common-autocode/src/main/java/com/njcn/autocode/utils/GenerateCode.java b/pqs-common/common-autocode/src/main/java/com/njcn/autocode/utils/GenerateCode.java index 9785e330b..1987ff45a 100644 --- a/pqs-common/common-autocode/src/main/java/com/njcn/autocode/utils/GenerateCode.java +++ b/pqs-common/common-autocode/src/main/java/com/njcn/autocode/utils/GenerateCode.java @@ -21,7 +21,7 @@ public class GenerateCode { private static final String TARGET_DIR = "D://code"; - private static final String DB_URL = "jdbc:mysql://192.168.1.24:13306/pqsinfo_ln"; + private static final String DB_URL = "jdbc:mysql://192.168.1.103:13306/pqsinfo_zl"; // private static final String DB_URL = "jdbc:oracle:thin:@192.168.1.170:1521:pqsbase"; private static final String USERNAME = "root"; @@ -30,8 +30,8 @@ public class GenerateCode { public static void main(String[] args) { List modules = Stream.of( - new Module("cdf", "com.njcn.device", "", Stream.of( - "pq_icd_path" + new Module("xy", "com.njcn.csdevice", "", Stream.of( + "cs_alarm_set" ).collect(Collectors.toList()), "") ).collect(Collectors.toList()); generateJavaFile(modules); diff --git a/pqs-common/common-echarts/src/main/java/com/njcn/echarts/json/LineGenerator.java b/pqs-common/common-echarts/src/main/java/com/njcn/echarts/json/LineGenerator.java index 9c28debb3..4a5ed4539 100644 --- a/pqs-common/common-echarts/src/main/java/com/njcn/echarts/json/LineGenerator.java +++ b/pqs-common/common-echarts/src/main/java/com/njcn/echarts/json/LineGenerator.java @@ -1,11 +1,7 @@ package com.njcn.echarts.json; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; import cn.hutool.json.JSONUtil; -import cn.hutool.json.ObjectMapper; -import com.google.gson.Gson; -import com.google.gson.JsonObject; import com.njcn.echarts.pojo.bo.TolerateData; import com.njcn.echarts.pojo.constant.PicCommonData; import org.icepear.echarts.Option; @@ -29,7 +25,6 @@ import org.icepear.echarts.render.Engine; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -43,6 +38,17 @@ import java.util.stream.Collectors; public class LineGenerator { private final static Engine ENGINE = new Engine(); + // null段在图表上的固定视觉宽度(数据点数量) + private static final int NULL_PLACEHOLDER_COUNT = 90; + // 压缩结果 + private static class CompressedResult { + // 压缩后的数据 + List> data; + // 每个null段的[起始索引, 结束索引](占位点范围) + List nullRegionIndices; + // null段边界处的真实x值(entry, exit交替) + List nullBoundaryRealXValues; + } /*** @@ -529,6 +535,478 @@ public class LineGenerator { return ENGINE.renderJsonOption(instantOption); } + public static String generateWaveOption(String title, List> aValue, List> bValue, List> cValue, String unit, Float max, Float min, String a, String b, String c, List colors, Boolean isOpen, Double lastTime, List sharedNullBoundaryXValues, Integer nPush) { + DecimalFormat df1 = new DecimalFormat("#.00"); + // 压缩null数据:如果有共享边界则用共享边界,否则独立压缩 + CompressedResult aCompressed; + CompressedResult bCompressed; + CompressedResult cCompressed; + if (sharedNullBoundaryXValues != null && !sharedNullBoundaryXValues.isEmpty()) { + aCompressed = compressNullDataWithSharedBoundaries(aValue, sharedNullBoundaryXValues); + bCompressed = compressNullDataWithSharedBoundaries(bValue, sharedNullBoundaryXValues); + cCompressed = compressNullDataWithSharedBoundaries(cValue, sharedNullBoundaryXValues); + } else { + aCompressed = compressNullData(aValue); + bCompressed = compressNullData(bValue); + cCompressed = compressNullData(cValue); + } + + Option instantOption = new Option(); + //取消渲染动画 + instantOption.setAnimation(false); + //背景色 + instantOption.setBackgroundColor(PicCommonData.PIC_BACK_COLOR); + //标题 + instantOption.setTitle(new Title() + .setText(title) + .setLeft(PicCommonData.CENTER) + .setTextStyle(new Label().setFontSize(14)) + ); + //配置颜色 + instantOption.setColor(colors.toArray(new String[colors.size()])); + //配置图例 + if (isOpen) { + instantOption.setLegend(new Legend().setData(new String[]{a, b}).setLeft("10px")); + } else { + instantOption.setLegend(new Legend().setData(new String[]{a, b, c}).setLeft("10px")); + } + //上下左右的图内间距 + instantOption.setGrid(new Grid().setTop("60px").setLeft("70px").setRight("40px").setBottom("10%")); + //横坐标(使用压缩后的数据) + instantOption.setXAxis(new ValueAxis().setName("ms") + .setSplitLine(new SplitLine().setShow(false)) + .setAxisLine(new AxisLine().setOnZero(false)) + .setType("category") + .setMinInterval(1) + ); + //纵坐标 + instantOption.setYAxis(new ValueAxis() + .setName(unit) + .setMax(df1.format(max * 1.1)) + .setMin(df1.format(min * 1.1)) + .setPosition(PicCommonData.LEFT) + .setAxisLine(new AxisLine().setShow(false).setOnZero(false)) + ); + //数据信息(使用压缩后的数据) + LineSeries aSeries = new LineSeries() + .setName(a) + .setSmooth(true) + .setSymbol("none") + .setConnectNulls(false) + .setData(aCompressed.data); + LineSeries bSeries = new LineSeries() + .setName(b) + .setSmooth(true) + .setSymbol("none") + .setConnectNulls(false) + .setData(bCompressed.data); + LineSeries cSeries = new LineSeries() + .setName(c) + .setSmooth(true) + .setSymbol("none") + .setConnectNulls(false) + .setData(cCompressed.data); + instantOption.setSeries(new LineSeries[]{aSeries, bSeries, cSeries}); + + // 渲染基础JSON + String jsonStr = ENGINE.renderJsonOption(instantOption); + cn.hutool.json.JSONObject optionJson = JSONUtil.parseObj(jsonStr); + cn.hutool.json.JSONArray seriesArray = optionJson.getJSONArray("series"); + + // 隐藏x轴默认标签,设置boundaryGap=false,只通过markLine显示关键节点 + Object xAxisRaw = optionJson.get("xAxis"); + cn.hutool.json.JSONObject xAxisJson; + if (xAxisRaw instanceof cn.hutool.json.JSONArray) { + xAxisJson = ((cn.hutool.json.JSONArray) xAxisRaw).getJSONObject(0); + } else { + xAxisJson = (cn.hutool.json.JSONObject) xAxisRaw; + } + cn.hutool.json.JSONObject axisLabelJson = new cn.hutool.json.JSONObject(); + axisLabelJson.set("show", false); + xAxisJson.set("axisLabel", axisLabelJson); + xAxisJson.set("boundaryGap", false); + + // 添加null markLine/markArea(基于压缩后的数据) + addNullMarkLinesForCategoryAxis(seriesArray.getJSONObject(0), aCompressed, lastTime); + addNullMarkLinesForCategoryAxis(seriesArray.getJSONObject(1), bCompressed, lastTime); + addNullMarkLinesForCategoryAxis(seriesArray.getJSONObject(2), cCompressed, lastTime); + // 在第一个series追加自定义横坐标标签markLine + addAxisLabelMarkLines(seriesArray.getJSONObject(0), aCompressed, lastTime, nPush); + return optionJson.toString(); + } + + /** 提取null边界的真实x值,供其他数据集共享使用 */ + public static List extractNullBoundaryXValues(List> data) { + List boundaries = findNullSegmentBoundaryIndices(data); + List xValues = new ArrayList<>(); + for (int idx : boundaries) { + xValues.add(data.get(idx).get(0)); + } + return xValues; + } + + /** 使用共享的null边界x值来压缩数据,确保不同数据集压缩结果结构一致 */ + private static CompressedResult compressNullDataWithSharedBoundaries(List> originalData, List sharedBoundaryXValues) { + if (sharedBoundaryXValues == null || sharedBoundaryXValues.isEmpty()) { + return compressNullData(originalData); + } + + // 用共享的x值找到本数据集中对应的索引 + List boundaries = new ArrayList<>(); + for (Float x : sharedBoundaryXValues) { + boundaries.add(findClosestValidIndex(originalData, x)); + } + + CompressedResult result = new CompressedResult(); + result.data = new ArrayList<>(); + result.nullRegionIndices = new ArrayList<>(); + result.nullBoundaryRealXValues = new ArrayList<>(sharedBoundaryXValues); + + int srcIdx = 0; + for (int b = 0; b < boundaries.size(); b += 2) { + int entryBoundary = boundaries.get(b); + int exitBoundary = boundaries.get(b + 1); + + while (srcIdx <= entryBoundary) { + result.data.add(originalData.get(srcIdx)); + srcIdx++; + } + + int nullStartIdx = result.data.size(); + float entryX = sharedBoundaryXValues.get(b); + float exitX = sharedBoundaryXValues.get(b + 1); + + for (int p = 0; p < NULL_PLACEHOLDER_COUNT; p++) { + List point = new ArrayList<>(); + point.add(entryX + (exitX - entryX) * p / NULL_PLACEHOLDER_COUNT); + point.add(null); + result.data.add(point); + } + + int nullEndIdx = result.data.size() - 1; + result.nullRegionIndices.add(new int[]{nullStartIdx, nullEndIdx}); + + srcIdx = exitBoundary; + } + + while (srcIdx < originalData.size()) { + result.data.add(originalData.get(srcIdx)); + srcIdx++; + } + + return result; + } + + + + /** + * 压缩null数据:删除所有null数据点,替换为固定NULL_PLACEHOLDER_COUNT个占位点 + * 这样null段在图表上永远只占固定视觉宽度,前后有效数据正常展开 + */ + private static CompressedResult compressNullData(List> originalData) { + List boundaries = findNullSegmentBoundaryIndices(originalData); + + CompressedResult result = new CompressedResult(); + result.data = new ArrayList<>(); + result.nullRegionIndices = new ArrayList<>(); + result.nullBoundaryRealXValues = new ArrayList<>(); + + if (boundaries.isEmpty()) { + result.data.addAll(originalData); + return result; + } + + int srcIdx = 0; + for (int b = 0; b < boundaries.size(); b += 2) { + // 最后一个有效点的索引(null段入口边界) + int entryBoundary = boundaries.get(b); + // 第一个恢复有效点的索引(null段出口边界) + int exitBoundary = boundaries.get(b + 1); + + // 复制有效数据:从srcIdx到entryBoundary + while (srcIdx <= entryBoundary) { + result.data.add(originalData.get(srcIdx)); + srcIdx++; + } + + // 记录边界真实x值 + result.nullBoundaryRealXValues.add(originalData.get(entryBoundary).get(0)); + result.nullBoundaryRealXValues.add(originalData.get(exitBoundary).get(0)); + + // 插入固定数量的null占位点 + int nullStartIdx = result.data.size(); + float entryX = originalData.get(entryBoundary).get(0); + float exitX = originalData.get(exitBoundary).get(0); + + for (int p = 0; p < NULL_PLACEHOLDER_COUNT; p++) { + List point = new ArrayList<>(); + point.add(entryX + (exitX - entryX) * p / NULL_PLACEHOLDER_COUNT); + point.add(null); + result.data.add(point); + } + + int nullEndIdx = result.data.size() - 1; + result.nullRegionIndices.add(new int[]{nullStartIdx, nullEndIdx}); + + // 跳过原始null数据点,srcIdx跳到exitBoundary + srcIdx = exitBoundary; + } + + // 复制最后一个null段之后的剩余有效数据 + while (srcIdx < originalData.size()) { + result.data.add(originalData.get(srcIdx)); + srcIdx++; + } + + return result; + } + + /** + * 在压缩数据中查找最接近目标x值的有效数据点索引(跳过null点) + */ + private static int findClosestValidIndex(List> data, float targetX) { + int closestIdx = -1; + float minDiff = Float.MAX_VALUE; + for (int i = 0; i < data.size(); i++) { + Float y = data.get(i).get(1); + if (y == null) continue; + float diff = Math.abs(data.get(i).get(0) - targetX); + if (diff < minDiff) { + minDiff = diff; + closestIdx = i; + } + } + return closestIdx; + } + + private static void addAxisLabelMarkLines(cn.hutool.json.JSONObject seriesObj, CompressedResult compressed, Double lastTime, Integer nPush) { + boolean hasNull = !compressed.nullRegionIndices.isEmpty(); + + // 收集需要标注的横坐标位置:[数据索引, 显示的时间值] + List labelPositions = new ArrayList<>(); + // 开头ms(始终显示) + labelPositions.add(new int[]{findClosestValidIndex(compressed.data, -nPush), -nPush}); + // 0ms(始终显示) + labelPositions.add(new int[]{findClosestValidIndex(compressed.data, 0f), 0}); + // npush ms(仅在有null时显示) + if (hasNull) { + labelPositions.add(new int[]{findClosestValidIndex(compressed.data, nPush), nPush}); + } + // null段边界真实时间值(仅在有null时显示) + if (hasNull) { + for (Float realX : compressed.nullBoundaryRealXValues) { + int idx = findClosestValidIndex(compressed.data, realX); + if (idx >= 0) { + labelPositions.add(new int[]{idx, (int) Math.round(realX)}); + } + } + } + // lastTime(始终显示) + if (lastTime != null) { + labelPositions.add(new int[]{findClosestValidIndex(compressed.data, lastTime.floatValue()), lastTime.intValue()}); + } + + // 最后一组数据(始终显示,数据结束位置横坐标) + if (lastTime != null) { + float lastTime20 = lastTime.floatValue() + nPush; + int lastTime20Idx = findClosestValidIndex(compressed.data, lastTime20); + if (lastTime20Idx >= 0) { + labelPositions.add(new int[]{(lastTime20Idx-2), (int) Math.round(lastTime20)}); + } + } + + // 获取或创建markLine + cn.hutool.json.JSONObject existingMarkLine = seriesObj.getJSONObject("markLine"); + cn.hutool.json.JSONArray markLineData; + + if (existingMarkLine == null) { + // 无null的情况:自己创建markLine,包含虚线和横坐标标签 + markLineData = new cn.hutool.json.JSONArray(); + + // x=0 虚线 + int zeroIdx = findClosestValidIndex(compressed.data, 0f); + if (zeroIdx >= 0) { + cn.hutool.json.JSONObject zeroLine = new cn.hutool.json.JSONObject(); + zeroLine.set("xAxis", zeroIdx); + cn.hutool.json.JSONObject zeroLabel = new cn.hutool.json.JSONObject(); + zeroLabel.set("show", false); + zeroLine.set("label", zeroLabel); + markLineData.add(zeroLine); + } + // lastTime 虚线 + if (lastTime != null) { + int lastTimeIdx = findClosestValidIndex(compressed.data, lastTime.floatValue()); + if (lastTimeIdx >= 0) { + cn.hutool.json.JSONObject lastTimeLine = new cn.hutool.json.JSONObject(); + lastTimeLine.set("xAxis", lastTimeIdx); + cn.hutool.json.JSONObject lastTimeLabelObj = new cn.hutool.json.JSONObject(); + lastTimeLabelObj.set("show", false); + lastTimeLine.set("label", lastTimeLabelObj); + markLineData.add(lastTimeLine); + } + } + + // 先收集所有标签到markLineData + for (int[] pos : labelPositions) { + cn.hutool.json.JSONObject line = new cn.hutool.json.JSONObject(); + line.set("xAxis", pos[0]); + cn.hutool.json.JSONObject lineLineStyle = new cn.hutool.json.JSONObject(); + lineLineStyle.set("width", 0); + line.set("lineStyle", lineLineStyle); + cn.hutool.json.JSONObject lineLabel = new cn.hutool.json.JSONObject(); + lineLabel.set("show", true); + lineLabel.set("formatter", String.valueOf(pos[1])); + lineLabel.set("position", "start"); + lineLabel.set("color", "#333"); + lineLabel.set("fontSize", 10); + line.set("label", lineLabel); + markLineData.add(line); + } + // 最后一次性设置到markLine和series + existingMarkLine = new cn.hutool.json.JSONObject(); + existingMarkLine.set("symbol", new String[]{"none", "none"}); + cn.hutool.json.JSONObject lineStyle = new cn.hutool.json.JSONObject(); + lineStyle.set("type", "dashed"); + lineStyle.set("color", "#999"); + lineStyle.set("width", 1); + existingMarkLine.set("lineStyle", lineStyle); + cn.hutool.json.JSONObject globalLabel = new cn.hutool.json.JSONObject(); + globalLabel.set("show", false); + existingMarkLine.set("label", globalLabel); + existingMarkLine.set("data", markLineData); + seriesObj.set("markLine", existingMarkLine); + } else { + // 有null的情况:追加标签到已有的markLine + markLineData = existingMarkLine.getJSONArray("data"); + for (int[] pos : labelPositions) { + cn.hutool.json.JSONObject line = new cn.hutool.json.JSONObject(); + line.set("xAxis", pos[0]); + cn.hutool.json.JSONObject lineLineStyle = new cn.hutool.json.JSONObject(); + lineLineStyle.set("width", 0); + line.set("lineStyle", lineLineStyle); + cn.hutool.json.JSONObject lineLabel = new cn.hutool.json.JSONObject(); + lineLabel.set("show", true); + lineLabel.set("formatter", String.valueOf(pos[1])); + lineLabel.set("position", "start"); + lineLabel.set("color", "#333"); + lineLabel.set("fontSize", 10); + line.set("label", lineLabel); + markLineData.add(line); + } + } + } + + private static List findNullSegmentBoundaryIndices(List> data) { + List indices = new ArrayList<>(); + boolean inNullSegment = false; + for (int i = 0; i < data.size(); i++) { + Float y = data.get(i).get(1); + if (y == null) { + if (!inNullSegment) { + indices.add(i > 0 ? i - 1 : i); + inNullSegment = true; + } + } else { + if (inNullSegment) { + indices.add(i); + inNullSegment = false; + } + } + } + if (inNullSegment) { + indices.add(data.size() - 1); + } + return indices; + } + + private static void addNullMarkLinesForCategoryAxis(cn.hutool.json.JSONObject seriesObj, CompressedResult compressed, Double lastTime) { + if (compressed.nullRegionIndices.isEmpty()) { + return; + } + cn.hutool.json.JSONArray markLineData = new cn.hutool.json.JSONArray(); + // x=0 虚线 + int zeroIdx = findClosestValidIndex(compressed.data, 0f); + if (zeroIdx >= 0) { + cn.hutool.json.JSONObject zeroLine = new cn.hutool.json.JSONObject(); + zeroLine.set("xAxis", zeroIdx); + cn.hutool.json.JSONObject zeroLabel = new cn.hutool.json.JSONObject(); + zeroLabel.set("show", false); + zeroLine.set("label", zeroLabel); + markLineData.add(zeroLine); + } + // null段边界的垂直虚线 + for (int r = 0; r < compressed.nullRegionIndices.size(); r++) { + int[] region = compressed.nullRegionIndices.get(r); + int nullStartIdx = region[0]; // 第一个占位点索引 + int nullEndIdx = region[1]; // 最后一个占位点索引 + + // 入口虚线:nullStartIdx - 1(null前最后一个有效数据点) + cn.hutool.json.JSONObject entryLine = new cn.hutool.json.JSONObject(); + entryLine.set("xAxis", nullStartIdx - 1); + cn.hutool.json.JSONObject entryLabel = new cn.hutool.json.JSONObject(); + entryLabel.set("show", false); + entryLine.set("label", entryLabel); + markLineData.add(entryLine); + + // 出口虚线:nullEndIdx(null后第一个有效数据点) + cn.hutool.json.JSONObject exitLine = new cn.hutool.json.JSONObject(); + exitLine.set("xAxis", nullEndIdx); + cn.hutool.json.JSONObject exitLabel = new cn.hutool.json.JSONObject(); + exitLabel.set("show", false); + exitLine.set("label", exitLabel); + markLineData.add(exitLine); + } + // 时间持续时间结束的数据点 + if (lastTime != null) { + int lastTimeIdx = findClosestValidIndex(compressed.data, lastTime.floatValue()); + if (lastTimeIdx >= 0) { + cn.hutool.json.JSONObject lastTimeLine = new cn.hutool.json.JSONObject(); + lastTimeLine.set("xAxis", lastTimeIdx); + cn.hutool.json.JSONObject lastTimeLabel = new cn.hutool.json.JSONObject(); + lastTimeLabel.set("show", false); + lastTimeLine.set("label", lastTimeLabel); + markLineData.add(lastTimeLine); + } + } + + cn.hutool.json.JSONObject markLine = new cn.hutool.json.JSONObject(); + markLine.set("symbol", new String[]{"none", "none"}); + cn.hutool.json.JSONObject lineStyle = new cn.hutool.json.JSONObject(); + lineStyle.set("type", "dashed"); + lineStyle.set("color", "#999"); + lineStyle.set("width", 1); + markLine.set("lineStyle", lineStyle); + cn.hutool.json.JSONObject globalLabel = new cn.hutool.json.JSONObject(); + globalLabel.set("show", false); + markLine.set("label", globalLabel); + markLine.set("data", markLineData); + seriesObj.set("markLine", markLine); + + // markArea - 灰色背景覆盖null区域(从入口边界到出口边界) + cn.hutool.json.JSONArray markAreaData = new cn.hutool.json.JSONArray(); + for (int r = 0; r < compressed.nullRegionIndices.size(); r++) { + int[] region = compressed.nullRegionIndices.get(r); + int nullStartIdx = region[0]; + int nullEndIdx = region[1]; + + cn.hutool.json.JSONArray areaPair = new cn.hutool.json.JSONArray(); + cn.hutool.json.JSONObject start = new cn.hutool.json.JSONObject(); + start.set("xAxis", nullStartIdx - 1); // 从入口边界有效数据点 + cn.hutool.json.JSONObject end = new cn.hutool.json.JSONObject(); + end.set("xAxis", nullEndIdx); // 到出口边界有效数据点 + areaPair.add(start); + areaPair.add(end); + markAreaData.add(areaPair); + } + cn.hutool.json.JSONObject markArea = new cn.hutool.json.JSONObject(); + cn.hutool.json.JSONObject itemStyle = new cn.hutool.json.JSONObject(); + itemStyle.set("color", "rgba(180, 180, 180, 0.2)"); + itemStyle.set("borderWidth", 0); + markArea.set("itemStyle", itemStyle); + markArea.set("data", markAreaData); + seriesObj.set("markArea", markArea); + } + /** * @param title 标题 * @param values 数据值 diff --git a/pqs-common/common-echarts/src/main/java/com/njcn/echarts/util/DrawPicUtil.java b/pqs-common/common-echarts/src/main/java/com/njcn/echarts/util/DrawPicUtil.java index 8301490a0..b58b82c76 100644 --- a/pqs-common/common-echarts/src/main/java/com/njcn/echarts/util/DrawPicUtil.java +++ b/pqs-common/common-echarts/src/main/java/com/njcn/echarts/util/DrawPicUtil.java @@ -10,9 +10,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Objects; /** * @author hongawen @@ -55,7 +56,6 @@ public class DrawPicUtil { return Objects.requireNonNull(picResult.getBody()).indexOf("image/png") > 0 ? picResult.getBody() : ""; } - /*** * @author hongawen * 绘制波形图 @@ -77,6 +77,11 @@ public class DrawPicUtil { return drawPic(instantJson, width, height); } + public String drawWavePic(String title, List> aValue, List> bValue, List> cValue, String unit, Float max, Float min, String a, String b, String c, List colors, Boolean isOpen, Double lastTime, List sharedNullBoundaryXValues,Integer nPush) { + String instantJson = LineGenerator.generateWaveOption(title, aValue, bValue, cValue, unit, max, min, a, b, c, colors, isOpen, lastTime, sharedNullBoundaryXValues,nPush); + return drawPic(instantJson, 0, 0); + } + /*** * 绘制itic曲线图 diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java index 96067485f..068c6c574 100644 --- a/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java +++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java @@ -1,10 +1,9 @@ package com.njcn.event.file.component; import cn.hutool.core.img.ImgUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.CharsetUtil; import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.utils.FileUtil; +import com.njcn.echarts.json.LineGenerator; import com.njcn.echarts.pojo.constant.PicCommonData; import com.njcn.echarts.util.DrawPicUtil; import com.njcn.event.file.pojo.bo.WaveDataDetail; @@ -12,21 +11,17 @@ import com.njcn.event.file.pojo.dto.WaveDataDTO; import com.njcn.event.file.pojo.enums.WaveFileResponseEnum; import com.njcn.oss.constant.OssPath; import com.njcn.oss.utils.FileStorageUtil; -import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import sun.awt.image.BufferedImageGraphicsConfig; -import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; +import java.util.Base64; import java.util.List; +import java.util.Map; /** * @author hongawen @@ -49,36 +44,39 @@ public class WavePicComponent { * @date 2023/9/21 15:32 * @return String 文件地址 */ - public String generateInstantImageZl(List waveDataDetails) { + public String generateInstantImageZl(Integer nPush, List waveDataDetails, Double lastTime) { String firstPic = null, secondPic = null, thirdPic = null, forthPic = null; + WaveDataDetail waveDataDetail0 = waveDataDetails.get(0); + // 从instantData提取null边界x值,作为共享参考(与Shun图保持一致) + List sharedNullBoundaries = LineGenerator.extractNullBoundaryXValues(waveDataDetail0.getInstantData().getAValue()); for (WaveDataDetail waveDataDetail : waveDataDetails) { if (waveDataDetail.getChannelName().toUpperCase().startsWith("SU")) { firstPic = drawPicUtil.drawWavePic("电压-电网侧", waveDataDetail.getInstantData().getAValue(), waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } else if (waveDataDetail.getChannelName().toUpperCase().startsWith("SI")) { thirdPic = drawPicUtil.drawWavePic("电流-电网侧", waveDataDetail.getInstantData().getAValue(), waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } else if (waveDataDetail.getChannelName().toUpperCase().startsWith("LU")) { secondPic = drawPicUtil.drawWavePic("电压-负载侧", waveDataDetail.getInstantData().getAValue(), waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } else { forthPic = drawPicUtil.drawWavePic("电流-负载侧", waveDataDetail.getInstantData().getAValue(), waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } } @@ -91,36 +89,39 @@ public class WavePicComponent { * @date 2023/9/21 15:32 * @return String 文件地址 */ - public String generateRmsImageZl(List waveDataDetails) { + public String generateRmsImageZl(Integer nPush, List waveDataDetails, Double lastTime) { String firstPic = null, secondPic = null, thirdPic = null, forthPic = null; + WaveDataDetail waveDataDetail0 = waveDataDetails.get(0); + // 从instantData提取null边界x值,作为共享参考(与Shun图保持一致) + List sharedNullBoundaries = LineGenerator.extractNullBoundaryXValues(waveDataDetail0.getInstantData().getAValue()); for (WaveDataDetail waveDataDetail : waveDataDetails) { if (waveDataDetail.getChannelName().toUpperCase().startsWith("SU")) { firstPic = drawPicUtil.drawWavePic("电压-电网侧", waveDataDetail.getRmsData().getAValue(), waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } else if (waveDataDetail.getChannelName().toUpperCase().startsWith("SI")) { thirdPic = drawPicUtil.drawWavePic("电流-电网侧", waveDataDetail.getRmsData().getAValue(), waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } else if (waveDataDetail.getChannelName().toUpperCase().startsWith("LU")) { secondPic = drawPicUtil.drawWavePic("电压-负载侧", waveDataDetail.getRmsData().getAValue(), waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } else { forthPic = drawPicUtil.drawWavePic("电流-负载侧", waveDataDetail.getRmsData().getAValue(), waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(), waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(), waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), - waveDataDetail.getColors(), waveDataDetail.getIsOpen() + waveDataDetail.getColors(), waveDataDetail.getIsOpen(),lastTime,sharedNullBoundaries,nPush ); } } @@ -209,6 +210,47 @@ public class WavePicComponent { return picPath; } + /*** + * 绘制瞬时波形图 App端用来绘制图片,会去掉部分数据,只保留开始数据 结束数据 + * @author xy + * @return String 文件地址 + */ + public String generateImageShun(Integer nPush, List waveDataDetails, Double lastTime) { + String picPath = null; + WaveDataDetail waveDataDetail = waveDataDetails.get(0); + // 从instantData提取null边界x值,作为共享参考 + List sharedNullBoundaries = LineGenerator.extractNullBoundaryXValues(waveDataDetail.getInstantData().getAValue()); + + String firstPic = drawPicUtil.drawWavePic(getTitle(waveDataDetail.getChannelName()), waveDataDetail.getInstantData().getAValue(), + waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(), + waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(), + waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), + waveDataDetail.getColors(), waveDataDetail.getIsOpen(), lastTime, sharedNullBoundaries,nPush + ); + String secondPic; + if (waveDataDetails.size() == 1) { + if (firstPic.contains(PicCommonData.PNG_PREFIX)) { + firstPic = firstPic.replace(PicCommonData.PNG_PREFIX, ""); + } + byte[] bytes = Base64.getDecoder().decode(firstPic); + picPath = fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png")); + } else if (waveDataDetails.size() == 2) { + waveDataDetail = waveDataDetails.get(1); + secondPic = drawPicUtil.drawWavePic(getTitle(waveDataDetail.getChannelName()), waveDataDetail.getInstantData().getAValue(), + waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(), + waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(), + waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), + waveDataDetail.getColors(), waveDataDetail.getIsOpen(), lastTime, sharedNullBoundaries,nPush + ); + picPath = composeImage(firstPic, secondPic); + } + return picPath; + } + + public String getTitle(String channelName) { + return channelName.toUpperCase().startsWith("U1") ? "电压" : "电流"; + } + /*** * 绘制RMS波形图 * @author hongawen @@ -248,6 +290,44 @@ public class WavePicComponent { return picPath; } + /*** + * 绘制RMS波形图 App端用来绘制图片,会去掉部分数据,只保留开始数据 结束数据 + * @author xy + * @return String 文件地址 + */ + public String generateImageRms(Integer nPush, List waveDataDetails, Double lastTime) { + String picPath = null; + WaveDataDetail waveDataDetail = waveDataDetails.get(0); + + // 从instantData提取null边界x值,作为共享参考(与Shun图保持一致) + List sharedNullBoundaries = LineGenerator.extractNullBoundaryXValues(waveDataDetail.getInstantData().getAValue()); + + String firstPic = drawPicUtil.drawWavePic(getTitle(waveDataDetail.getChannelName()), waveDataDetail.getRmsData().getAValue(), + waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(), + waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(), + waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), + waveDataDetail.getColors(), waveDataDetail.getIsOpen(), lastTime, sharedNullBoundaries,nPush + ); + String secondPic; + if (waveDataDetails.size() == 1) { + if (firstPic.contains(PicCommonData.PNG_PREFIX)) { + firstPic = firstPic.replace(PicCommonData.PNG_PREFIX, ""); + } + byte[] bytes = Base64.getDecoder().decode(firstPic); + picPath = fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png")); + } else if (waveDataDetails.size() == 2) { + waveDataDetail = waveDataDetails.get(1); + secondPic = drawPicUtil.drawWavePic(getTitle(waveDataDetail.getChannelName()), waveDataDetail.getRmsData().getAValue(), + waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(), + waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(), + waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(), + waveDataDetail.getColors(), waveDataDetail.getIsOpen(), lastTime, sharedNullBoundaries,nPush + ); + picPath = composeImage(firstPic, secondPic); + } + return picPath; + } + /*** * 合成图片 * @author hongawen diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java index 218418d09..833771fad 100644 --- a/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java +++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java @@ -7,6 +7,7 @@ import com.njcn.event.file.pojo.dto.WaveDataDTO; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * @author hongawen @@ -80,28 +81,49 @@ public class WaveUtil { //根据相别来确认标题的名称 for (int m = 0; m < iPhase; m++) { if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("A")) { - float tmpShunFirstA = sunData.get(j).get(iPhase * i + m + 1) * xishu; - shunFirstA = tmpShunFirstA; - sAValue.add(new ArrayList() {{ - add(x); - add(tmpShunFirstA); - }}); + if (Objects.isNull(sunData.get(j).get(iPhase * i + m + 1))) { + sAValue.add(new ArrayList() {{ + add(x); + add(null); + }}); + } else { + float tmpShunFirstA = sunData.get(j).get(iPhase * i + m + 1) * xishu; + shunFirstA = tmpShunFirstA; + sAValue.add(new ArrayList() {{ + add(x); + add(tmpShunFirstA); + }}); + } } if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("B")) { - float tmpShunFirstB = sunData.get(j).get(iPhase * i + m + 1) * xishu; - shunFirstB = tmpShunFirstB; - sBValue.add(new ArrayList() {{ - add(x); - add(tmpShunFirstB); - }}); + if (Objects.isNull(sunData.get(j).get(iPhase * i + m + 1))) { + sBValue.add(new ArrayList() {{ + add(x); + add(null); + }}); + } else { + float tmpShunFirstB = sunData.get(j).get(iPhase * i + m + 1) * xishu; + shunFirstB = tmpShunFirstB; + sBValue.add(new ArrayList() {{ + add(x); + add(tmpShunFirstB); + }}); + } } if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("C")) { - float tmpShunFirstC = sunData.get(j).get(iPhase * i + m + 1) * xishu; - shunFirstC = tmpShunFirstC; - sCValue.add(new ArrayList() {{ - add(x); - add(tmpShunFirstC); - }}); + if (Objects.isNull(sunData.get(j).get(iPhase * i + m + 1))) { + sCValue.add(new ArrayList() {{ + add(x); + add(null); + }}); + } else { + float tmpShunFirstC = sunData.get(j).get(iPhase * i + m + 1) * xishu; + shunFirstC = tmpShunFirstC; + sCValue.add(new ArrayList() {{ + add(x); + add(tmpShunFirstC); + }}); + } } } sfMax = getMax(sfMax, shunFirstA, shunFirstB, shunFirstC); @@ -124,28 +146,50 @@ public class WaveUtil { //根据相别来确认标题的名称 for (int m = 0; m < iPhase; m++) { if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("A")) { - float tmpRmsFirstA = rmsData.get(k).get(iPhase * i + m + 1) * xishu; - rmsFirstA = tmpRmsFirstA; - rAValue.add(new ArrayList() {{ - add(x); - add(tmpRmsFirstA); - }}); + if (Objects.isNull(rmsData.get(k).get(iPhase * i + m + 1))) { + rAValue.add(new ArrayList() {{ + add(x); + add(null); + }}); + } else { + float tmpRmsFirstA = rmsData.get(k).get(iPhase * i + m + 1) * xishu; + rmsFirstA = tmpRmsFirstA; + rAValue.add(new ArrayList() {{ + add(x); + add(tmpRmsFirstA); + }}); + } } if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("B")) { - float tmpRmsFirstB = rmsData.get(k).get(iPhase * i + m + 1) * xishu; - rmsFirstB = tmpRmsFirstB; - rBValue.add(new ArrayList() {{ - add(x); - add(tmpRmsFirstB); - }}); + if (Objects.isNull(rmsData.get(k).get(iPhase * i + m + 1))) { + rBValue.add(new ArrayList() {{ + add(x); + add(null); + }}); + } else { + float tmpRmsFirstB = rmsData.get(k).get(iPhase * i + m + 1) * xishu; + rmsFirstB = tmpRmsFirstB; + rBValue.add(new ArrayList() {{ + add(x); + add(tmpRmsFirstB); + }}); + } + } if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("C")) { - float tmpRmsFirstC = rmsData.get(k).get(iPhase * i + m + 1) * xishu; - rmsFirstC = tmpRmsFirstC; - rCValue.add(new ArrayList() {{ - add(x); - add(tmpRmsFirstC); - }}); + if (Objects.isNull(rmsData.get(k).get(iPhase * i + m + 1))) { + rCValue.add(new ArrayList() {{ + add(x); + add(null); + }}); + } else { + float tmpRmsFirstC = rmsData.get(k).get(iPhase * i + m + 1) * xishu; + rmsFirstC = tmpRmsFirstC; + rCValue.add(new ArrayList() {{ + add(x); + add(tmpRmsFirstC); + }}); + } } } rfMax = getMax(sfMax, rmsFirstA, rmsFirstB, rmsFirstC); diff --git a/pqs-common/common-web/src/main/java/com/njcn/web/utils/RestTemplateUtil.java b/pqs-common/common-web/src/main/java/com/njcn/web/utils/RestTemplateUtil.java index ed3b7f868..91d8b1e62 100644 --- a/pqs-common/common-web/src/main/java/com/njcn/web/utils/RestTemplateUtil.java +++ b/pqs-common/common-web/src/main/java/com/njcn/web/utils/RestTemplateUtil.java @@ -1,5 +1,8 @@ package com.njcn.web.utils; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.*; @@ -149,7 +152,8 @@ public class RestTemplateUtil { * @return ResponseEntity 响应对象封装类 */ public static ResponseEntity post(String url, Object requestBody, Class responseType) { - return restTemplate.postForEntity(url, requestBody, responseType); + Object actualBody = convertHutoolJsonToStandard(requestBody); + return restTemplate.postForEntity(url, actualBody, responseType); } /** @@ -162,7 +166,8 @@ public class RestTemplateUtil { * @return ResponseEntity 响应对象封装类 */ public static ResponseEntity post(String url, Object requestBody, Class responseType, Object... uriVariables) { - return restTemplate.postForEntity(url, requestBody, responseType, uriVariables); + Object actualBody = convertHutoolJsonToStandard(requestBody); + return restTemplate.postForEntity(url, actualBody, responseType, uriVariables); } /** @@ -175,7 +180,21 @@ public class RestTemplateUtil { * @return ResponseEntity 响应对象封装类 */ public static ResponseEntity post(String url, Object requestBody, Class responseType, Map uriVariables) { - return restTemplate.postForEntity(url, requestBody, responseType, uriVariables); + Object actualBody = convertHutoolJsonToStandard(requestBody); + return restTemplate.postForEntity(url, actualBody, responseType, uriVariables); + } + + private static Object convertHutoolJsonToStandard(Object requestBody) { + if (requestBody instanceof JSONObject || requestBody instanceof JSONArray) { + try { + com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper(); + return objectMapper.readValue(JSONUtil.toJsonStr(requestBody), Object.class); + } catch (Exception e) { + log.warn("Hutool JSON转标准结构失败,尝试直接使用字符串", e); + return requestBody; + } + } + return requestBody; } /** diff --git a/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/pojo/dto/MonitorCommLedgerInfoDTO.java b/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/pojo/dto/MonitorCommLedgerInfoDTO.java index b1eddca0a..9806944e3 100644 --- a/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/pojo/dto/MonitorCommLedgerInfoDTO.java +++ b/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/pojo/dto/MonitorCommLedgerInfoDTO.java @@ -25,6 +25,9 @@ public class MonitorCommLedgerInfoDTO implements Serializable { private String busBarName; + private String objName; + + private String voltageLevel; private String shortCapacity; diff --git a/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/line/mapper/mapping/DeptLineMapper.xml b/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/line/mapper/mapping/DeptLineMapper.xml index bbf68e567..213a3d039 100644 --- a/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/line/mapper/mapping/DeptLineMapper.xml +++ b/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/line/mapper/mapping/DeptLineMapper.xml @@ -88,7 +88,9 @@ voltage.name busBarname, pq_voltage.scale voltageLevel, bd.name bdName, - gd.name gdName + gd.name gdName, + supervision_user_report.project_name objName + from pq_dept_line pq_dept_line inner join pq_line point on pq_dept_line.line_id = point.id inner join pq_line_detail lineDetail on point.id = lineDetail.id @@ -98,6 +100,7 @@ inner join pq_device device on dev.id = device.id inner join pq_line bd on dev.pid = bd.id inner join pq_line gd on bd.pid = gd.id + left join supervision_user_report on lineDetail.Obj_Id = supervision_user_report.id where device.Dev_Model = 1 and point.state = 1 and device.Dev_Data_Type in diff --git a/pqs-event/event-common/src/main/java/com/njcn/event/common/service/CommMonitorEventReportService.java b/pqs-event/event-common/src/main/java/com/njcn/event/common/service/CommMonitorEventReportService.java index b67218667..8326d25e0 100644 --- a/pqs-event/event-common/src/main/java/com/njcn/event/common/service/CommMonitorEventReportService.java +++ b/pqs-event/event-common/src/main/java/com/njcn/event/common/service/CommMonitorEventReportService.java @@ -20,6 +20,13 @@ public interface CommMonitorEventReportService { void getLineExport(ExportParam exportParam, LineDetailDataCommDTO lineDetailDataCommDTO, HttpServletResponse response); + /** + * 暂降事件报告 + * @param exportParam + * @param lineDetailDataCommDTO + * @param response + */ + void getWlLineExport(ExportParam exportParam, LineDetailDataCommDTO lineDetailDataCommDTO, HttpServletResponse response); /** * 暂态事件报告 diff --git a/pqs-event/event-common/src/main/java/com/njcn/event/common/service/impl/CommMonitorEventReportServiceImpl.java b/pqs-event/event-common/src/main/java/com/njcn/event/common/service/impl/CommMonitorEventReportServiceImpl.java index 3dcf96519..527ff81bd 100644 --- a/pqs-event/event-common/src/main/java/com/njcn/event/common/service/impl/CommMonitorEventReportServiceImpl.java +++ b/pqs-event/event-common/src/main/java/com/njcn/event/common/service/impl/CommMonitorEventReportServiceImpl.java @@ -479,6 +479,389 @@ public class CommMonitorEventReportServiceImpl implements CommMonitorEventReport } + @Override + public void getWlLineExport(ExportParam exportParam, LineDetailDataCommDTO lineDetailData, HttpServletResponse response) { + //创建word文档(poi生成word) + XWPFDocument doc = new XWPFDocument(); //创建Word文件 + //设置标题样式 + WordUtils.setHeadingStyle(doc); + XWPFParagraph p = doc.createParagraph(); //新建一个段落 + //设置对齐 + p.setAlignment(ParagraphAlignment.CENTER); + p.setVerticalAlignment(TextAlignment.CENTER); + XWPFRun r = p.createRun();//创建段落文本 + r.addBreak(); + r.addBreak(); + r.addBreak(); + r.addBreak(); + r.addBreak(); + r.addBreak(); + r.setText(""); + r.setBold(true);//设置为粗体 + r.setFontSize(14);//字体大小 + r.addBreak(); + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.CENTER); + XWPFRun r1 = p.createRun();//创建段落文本 + r1.setText("电压暂降事件分析报告"); + r1.setBold(true);//设置为粗体 + r1.setFontSize(36);//字体大小 + r1.addBreak(); + r1.addBreak(); + r1.addBreak(); + r1.addBreak(); + r1.addBreak(); + r1.addBreak(); + r1.addBreak(); + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.CENTER); + XWPFRun r2 = p.createRun();//创建段落文本 + //获取当前时间 + Date date = new Date(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy 年 MM 月 dd 日"); + String time = dateFormat.format(date); + + r2.setText("日期: " + time); + r2.setBold(true);//设置为粗体 + r2.setFontSize(14);//字体大小 + + r2.addBreak(); + r2.addBreak(); + r2.addBreak(); + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.CENTER); + XWPFRun r3 = p.createRun();//创建段落文本 + r3.setText("电压暂降事件区域报告"); + r3.setFontSize(24);//字体大小 + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.LEFT); + createTitle(doc, "1. 引言", "标题 1", 0, 15); + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.BOTH); + XWPFRun r5 = p.createRun();//创建段落文本 + r5.setText("对所选中区间内电压暂降事件进行分析,能够直观清晰查看响应的暂降事件信息。"); + r5.setFontSize(11);//字体大小 + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.LEFT); + createTitle(doc, "2. 报告分析对象", "标题 1", 0, 15); + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.BOTH); + XWPFRun r7 = p.createRun();//创建段落文本 + r7.setText(exportParam.getLineName()); + r7.setFontSize(11);//字体大小 + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.LEFT); + createTitle(doc, "3. 报告分析时间", "标题 1", 0, 15); + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.BOTH); + XWPFRun r9 = p.createRun();//创建段落文本 + r9.setText(exportParam.getSearchBeginTime() + " 至 " + exportParam.getSearchEndTime()); + r9.setFontSize(11);//字体大小 + + p = doc.createParagraph(); //新建一个段落 + p.setAlignment(ParagraphAlignment.LEFT); + createTitle(doc, "4. 总汇信息", "标题 1", 0, 15); + + //查询参数 + StatisticsParam param = new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(), exportParam.getFlag()); + //获取暂降原因字典 + List reasonData = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.EVENT_REASON.getName()).getData(); + //获取暂降类型字典 + List typeData = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.EVENT_TYPE.getName()).getData(); + //influxdb查询结果(pqs_eventdetail表) + List info = info(param, true); + + //记录数 + int i = 1; + //1.监测点信息 + if (exportParam.isXq()) { + createTitle(doc, "4." + i + " 监测点信息", "标题 2", 200, 15); + XWPFTable table = createTable(doc); + XWPFParagraph centerParagraph = WordUtils.getCenterParagraph(doc); + insertRow(doc, table, centerParagraph, true, "项目", "描述"); + insertRow(doc, table, centerParagraph, false, "监测点名称", lineDetailData.getLineName()); + insertRow(doc, table, centerParagraph, false, "电压等级", lineDetailData.getScale()); + insertRow(doc, table, centerParagraph, false, "PT变比", lineDetailData.getPt()); + insertRow(doc, table, centerParagraph, false, "CT变比", lineDetailData.getCt()); + insertRow(doc, table, centerParagraph, false, "协议容量", lineDetailData.getDealCapacity() + ""); + insertRow(doc, table, centerParagraph, false, "设备容量", lineDetailData.getDevCapacity() + ""); + insertRow(doc, table, centerParagraph, false, "最小短路容量", lineDetailData.getShortCapacity() + ""); + insertRow(doc, table, centerParagraph, false, "接线方式", lineDetailData.getPtType()); + if (exportParam.getType() == 0) { + insertRow(doc, table, centerParagraph, false, "基准容量", lineDetailData.getStandardCapacity() + ""); + } + i++; + } + //2.暂降事件暂降事件列表和暂降点图 + //2.1.判断列表和点图是否是要导出 + if (exportParam.isLb() || exportParam.isSjdF47() || exportParam.isSjdITIC()) { + List plot = eventReportService.getPlot(info, reasonData, typeData); + //暂降事件列表 + if (exportParam.isLb()) { + createTitle(doc, "4." + i + " 暂降事件列表", "标题 2", 200, 15); + XWPFTable table = createTable(doc); + XWPFParagraph centerParagraph = WordUtils.getCenterParagraph(doc); + insertRow(doc, table, centerParagraph, true, "序号", "暂降发生时刻", "暂降幅值(%)", "持续时间(s)", "暂降类型", "暂降原因", "严重度"); + for (int j = 0; j < plot.size(); j++) { + EventDetail eventDetail = plot.get(j); + String s = eventDetail.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); + + insertRow(doc, table, centerParagraph, false, j + 1 + "", s, BigDecimal.valueOf(eventDetail.getFeatureAmplitude() * 100).setScale(2, RoundingMode.HALF_UP).toString(), eventDetail.getDuration() + "", Objects.isNull(eventDetail.getAdvanceType()) ? "/" : eventDetail.getAdvanceType(), Objects.isNull(eventDetail.getAdvanceReason()) ? "/" : eventDetail.getAdvanceReason(), Objects.isNull(eventDetail.getSeverity()) ? "/" : eventDetail.getSeverity() + ""); + } + i++; + } + //暂降事件点图 + if (exportParam.isSjdF47() || exportParam.isSjdITIC()) { + ArrayList> ass = getAss(plot); + createTitle(doc, "4." + i + " 暂降事件点图", "标题 2", 200, 15); + int two = 1; + if (exportParam.isSjdITIC()) { + createTitle(doc, "4." + i + "." + two + " ITIC 曲线", "标题 3", 400, 15); + String itic = drawPicUtil.drawItic(ass); + createPic(doc, itic, "ITIC曲线"); + two++; + } + if (exportParam.isSjdF47()) { + createTitle(doc, "4." + i + "." + two + " F47 曲线", "标题 3", 400, 15); + String f47 = drawPicUtil.drawF47(ass); + createPic(doc, f47, "SEMI F47曲线"); + two++; + } + i++; + } + } + + + //3.暂降密度 + if (exportParam.isMdbg() || exportParam.isMdtx()) { + createTitle(doc, "4." + i + " 暂降密度", "标题 2", 200, 15); + int two = 1; + if (exportParam.isMdtx()) { + createTitle(doc, "4." + i + "." + two + " 暂降密度点图", "标题 3", 400, 15); + Integer[][] eventDensityData = eventReportService.getCoords(info); + String str = drawPicUtil.drawEventDensity(eventDensityData); + createPic(doc, str, "暂降密度图"); + two++; + } + if (exportParam.isMdbg()) { + XWPFParagraph centerParagraph = WordUtils.getCenterParagraph(doc); + createTitle(doc, "4." + i + "." + two + " DISDIP 表格:国际发配电联盟(UNIPEDE)", "标题 3", 400, 15); +// List eventDisdip = eventAnalysisService.eventDisdip(new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(),exportParam.getFlag())); + List eventDisdip = eventReportService.eventDisdip(info); + + XWPFTable table1 = createTable(doc); + insertRow(doc, table1, centerParagraph, true, "剩余电压", "20ms", "100ms", "500ms", "1s", "3s", "20s", "60s", "180s"); + for (int j = 0; j < eventDisdip.size(); j++) { + DISDIPVO disdipvo = eventDisdip.get(j); + insertRow(doc, table1, centerParagraph, false, disdipvo.getName(), disdipvo.getTwentyMs(), disdipvo.getOneHundredMs(), disdipvo.getFiveHundredMs(), disdipvo.getOneS(), disdipvo.getThreeS(), disdipvo.getTwentyS(), disdipvo.getSixtyS(), disdipvo.getOneEightyS()); + } + two++; + createTitle(doc, "4." + i + "." + two + " IEC 61000-4-11:(用电终端的电压暂降抗度)", "标题 3", 400, 15); +// List iec411VOS = eventAnalysisService.IEC411(new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(),exportParam.getFlag())); + List iec411VOS = eventReportService.IEC411(info); + XWPFTable table2 = createTable(doc); + insertRow(doc, table2, centerParagraph, true, "剩余电压", "10~20ms", "20~100ms", "0.1~0.2s", "0.2~0.5s", "0.5~1s", ">1s"); + for (int j = 0; j < iec411VOS.size(); j++) { + IEC411VO iec411VO = iec411VOS.get(j); + insertRow(doc, table2, centerParagraph, false, iec411VO.getName(), iec411VO.getTenTwentyMs(), iec411VO.getTwentyOneHundredMs(), iec411VO.getZeroPiontOneTwoS(), iec411VO.getZeroPiontTwoFiveS(), iec411VO.getZeroPiontFive1S(), iec411VO.getGreater1S()); + } + two++; + createTitle(doc, "4." + i + "." + two + " IEC 61000-2-8:(公共电网电压暂降测量统计)", "标题 3", 400, 15); +// List iec28VOS = eventAnalysisService.IEC28(new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(),exportParam.getFlag())); + List iec28VOS = eventReportService.IEC28(info); + XWPFTable table3 = createTable(doc); + insertRow(doc, table3, centerParagraph, true, "剩余电压", "0.02~0.1s", "0.1~0.25s", "0.25~0.5s", "0.5s~1s", "1~3s", "3~20s", "20~60s", "60~180s"); + for (int j = 0; j < iec28VOS.size(); j++) { + IEC28VO iec28VO = iec28VOS.get(j); + insertRow(doc, table3, centerParagraph, false, iec28VO.getName(), iec28VO.getQ(), iec28VO.getW(), iec28VO.getE(), iec28VO.getR(), iec28VO.getT(), iec28VO.getY(), iec28VO.getU(), iec28VO.getI()); + } + two++; + } + i++; + } + //4.暂降幅值概率分布 + if (exportParam.isGlfbfz() || exportParam.isGlfbsj()) { + createTitle(doc, "4." + i + " 暂降幅值概率分布图", "标题 2", 200, 15); +// ProbabilityVO probabilityVO = eventAnalysisService.getProbabilityDistribution(new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(),exportParam.getFlag())); + ProbabilityVO probabilityVO = eventReportService.getProbabilityDistribution(info); + int two = 1; + if (exportParam.isGlfbfz()) { + createTitle(doc, "4." + i + "." + two + " 暂降幅值的概率分函数", "标题 3", 400, 15); + List ybardata = probabilityVO.getPereventvalue(); + List ylinedata = probabilityVO.getEventvalue(); + String fz = drawPicUtil.drawEventAmplitude(ylinedata, ybardata); + createPic(doc, fz, "暂降幅值的概率分布函数"); + two++; + } + if (exportParam.isGlfbsj()) { + createTitle(doc, "4." + i + "." + two + " 持续时间的概率分函数", "标题 3", 400, 15); + List ybardata = probabilityVO.getPersisttime(); + List ylinedata = probabilityVO.getSisttime(); + String sj = drawPicUtil.drawPersistentTime(ylinedata, ybardata); + createPic(doc, sj, "持续时间的概率分布函数"); + two++; + } + i++; + } + + + //5.月份统计 + if (exportParam.isTjbg() || exportParam.isTjtx()) { + createTitle(doc, "4." + i + " 月份统计", "标题 2", 200, 15); + int two = 1; + List reasonTypeTime = eventAnalysisService.getReasonTypeTime(param); + //暂时时间端按月查询不能查询 +// List reasonTypeTime = eventReportService.getReasonTypeTime(param,null); + if (exportParam.isTjtx()) { + createTitle(doc, "4." + i + "." + two + " 月份统计图", "标题 3", 400, 15); + List count = new ArrayList<>(); + List name = new ArrayList<>(); + if (exportParam.getFlag() == 0) { + for (TimeVO timeVO : reasonTypeTime) { + name.add(timeVO.getMonth() + ""); + count.add(Integer.parseInt(timeVO.getTimes())); + } + } else { + for (TimeVO timeVO : reasonTypeTime) { + name.add(timeVO.getDay() + ""); + count.add(Integer.parseInt(timeVO.getTimes())); + } + } + String yftj = drawPicUtil.drawMonth(name, count, reasonTypeTime.get(0).getYear(), exportParam.getFlag()); + createPic(doc, yftj, "月份统计图"); + two++; + } + if (exportParam.isTjbg()) { + XWPFParagraph centerParagraph = WordUtils.getCenterParagraph(doc); + createTitle(doc, "4." + i + "." + two + " 时间统计表格", "标题 3", 400, 15); + + XWPFTable table1 = createTable(doc); + if (exportParam.getFlag() == 0) { + insertRow(doc, table1, centerParagraph, true, "时间(月)", "电压暂降次数"); + } else { + insertRow(doc, table1, centerParagraph, true, "时间(天)", "电压暂降次数"); + } + if (exportParam.getFlag() == 0) { + for (int j = 0; j < reasonTypeTime.size(); j++) { + TimeVO timeVO = reasonTypeTime.get(j); + insertRow(doc, table1, centerParagraph, false, timeVO.getMonth(), timeVO.getTimes()); + } + } else { + for (int j = 0; j < reasonTypeTime.size(); j++) { + TimeVO timeVO = reasonTypeTime.get(j); + insertRow(doc, table1, centerParagraph, false, timeVO.getFulltime(), timeVO.getTimes()); + } + } + two++; + } + i++; + } + + + //6.原因统计 + //6.1整合提出查询语句 + Boolean fly = exportParam.isYybg() || exportParam.isYytx() || exportParam.isLxbg() || exportParam.isLxtx(); + if (fly) { + List tempDictType = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_STATIS.getCode()).getData(); + List typeIds = tempDictType.stream().filter(x -> DicDataEnum.VOLTAGE_DIP.getCode().equals(x.getCode()) || DicDataEnum.SHORT_INTERRUPTIONS.getCode().equals(x.getCode())) + .map(DictData::getId).collect(Collectors.toList()); + List tempInfo = info.stream().filter(temp -> typeIds.contains(temp.getEventType())).collect(Collectors.toList()); + StatisticVO statistic = eventReportService.getStatistic(tempInfo, reasonData, typeData); + if (exportParam.isYybg() || exportParam.isYytx()) { + createTitle(doc, "4." + i + " 原因统计", "标题 2", 200, 15); +// StatisticVO statistic = eventAnalysisService.getStatistic(new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(),exportParam.getFlag())); + int two = 1; + if (exportParam.isYytx()) { + createTitle(doc, "4." + i + "." + two + " 原因统计图", "标题 3", 400, 15); + List xdata = new ArrayList<>(); + List> reasonList = new ArrayList<>(); + + List reason = statistic.getReason(); + for (ReasonsVO reasonsVO : reason) { + Map map = new LinkedHashMap<>(); + map.put("value", reasonsVO.getTimes()); + map.put("name", reasonsVO.getReason()); + reasonList.add(map); + xdata.add(reasonsVO.getReason()); + } + String tr = drawPicUtil.drawReason(xdata, reasonList); + createPic(doc, tr, "暂降原因图"); + two++; + } + if (exportParam.isYybg()) { + XWPFParagraph centerParagraph = WordUtils.getCenterParagraph(doc); + createTitle(doc, "4." + i + "." + two + " 原因统计表格", "标题 3", 400, 15); + XWPFTable table1 = createTable(doc); + insertRow(doc, table1, centerParagraph, true, "暂降原因", "电压暂降次数"); + List reason = statistic.getReason(); + for (int j = 0; j < reason.size(); j++) { + ReasonsVO reasonsVO = reason.get(j); + insertRow(doc, table1, centerParagraph, false, reasonsVO.getReason(), reasonsVO.getTimes() + ""); + } + two++; + } + i++; + } + //7.类型统计 + if (exportParam.isLxbg() || exportParam.isLxtx()) { + createTitle(doc, "4." + i + " 类型统计", "标题 2", 200, 15); +// StatisticVO statistic = eventAnalysisService.getStatistic(new StatisticsParam(exportParam.getLineId(), exportParam.getSearchBeginTime(), exportParam.getSearchEndTime(),exportParam.getFlag())); + int two = 1; + if (exportParam.isLxtx()) { + createTitle(doc, "4." + i + "." + two + " 类型统计图", "标题 3", 400, 15); + List xdata = new ArrayList<>(); + List types = statistic.getTypes(); + + List> reasonList = new ArrayList<>(); + for (TypesVO type : types) { + Map map = new LinkedHashMap<>(); + map.put("value", type.getTimes()); + map.put("name", type.getType()); + reasonList.add(map); + xdata.add(type.getType()); + } + String tr = drawPicUtil.drawType(xdata, reasonList); + createPic(doc, tr, "暂降类型图"); + two++; + } + if (exportParam.isLxbg()) { + createTitle(doc, "4." + i + "." + two + " 类型统计表格", "标题 3", 400, 15); + XWPFParagraph centerParagraph = WordUtils.getCenterParagraph(doc); + XWPFTable table1 = createTable(doc); + insertRow(doc, table1, centerParagraph, true, "暂降原因", "电压暂降次数"); + List types = statistic.getTypes(); + for (int j = 0; j < types.size(); j++) { + TypesVO typesVO = types.get(j); + insertRow(doc, table1, centerParagraph, false, typesVO.getType(), typesVO.getTimes() + ""); + } + two++; + } + i++; + } + } + + + try { + ServletOutputStream outputStream = response.getOutputStream(); + String fileName = URLEncoder.encode(exportParam.getLineName() + ".docx", "UTF-8"); + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + response.setContentType("application/octet-stream;charset=UTF-8"); + doc.write(outputStream); + outputStream.close(); + } catch (Exception e) { + throw new BusinessException(CommonResponseEnum.FAIL, "导出监测点暂降报告异常"); + } + + } /** * 创建标题 @@ -598,6 +981,23 @@ public class CommMonitorEventReportServiceImpl implements CommMonitorEventReport return BeanUtil.copyToList(info, EventDetail.class); } + private List info(StatisticsParam statisticsParam, Boolean dip) { + // 构建查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(RmpEventDetailPO::getMeasurementPointId, statisticsParam.getLineIndex()) + .ge(StrUtil.isNotBlank(statisticsParam.getStartTime()), RmpEventDetailPO::getStartTime, DateUtil.beginOfDay(DateUtil.parse(statisticsParam.getStartTime()))) + .le(StrUtil.isNotBlank(statisticsParam.getEndTime()), RmpEventDetailPO::getStartTime, DateUtil.endOfDay(DateUtil.parse(statisticsParam.getEndTime()))) + .orderByDesc(RmpEventDetailPO::getStartTime); + if (dip) { + List data = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_STATIS.getCode()).getData(); + List typeList = data.stream().filter(it->it.getCode().equals(DicDataEnum.VOLTAGE_DIP.getCode()) || it.getCode().equals(DicDataEnum.SHORT_INTERRUPTIONS.getCode())).map(DictData::getId).collect(Collectors.toList()); List list = new ArrayList<>(); + queryWrapper.in(RmpEventDetailPO::getEventType, typeList); + } + // 数据暂降查询 + List info = rmpEventDetailMapper.selectList(queryWrapper); + return BeanUtil.copyToList(info, EventDetail.class); + } + /** * 生成暂降事件报告 diff --git a/pqs-harmonic/harmonic-api/src/main/java/com/njcn/harmonic/pojo/param/report/AreaHarmReportParam.java b/pqs-harmonic/harmonic-api/src/main/java/com/njcn/harmonic/pojo/param/report/AreaHarmReportParam.java index 3df93949f..b0642426e 100644 --- a/pqs-harmonic/harmonic-api/src/main/java/com/njcn/harmonic/pojo/param/report/AreaHarmReportParam.java +++ b/pqs-harmonic/harmonic-api/src/main/java/com/njcn/harmonic/pojo/param/report/AreaHarmReportParam.java @@ -17,4 +17,6 @@ public class AreaHarmReportParam { private String deptId; + private String scale; + } diff --git a/pqs-harmonic/harmonic-boot/src/main/java/com/njcn/harmonic/service/report/impl/AreaHarmonicServiceImpl.java b/pqs-harmonic/harmonic-boot/src/main/java/com/njcn/harmonic/service/report/impl/AreaHarmonicServiceImpl.java index efa3cea65..0db7712fd 100644 --- a/pqs-harmonic/harmonic-boot/src/main/java/com/njcn/harmonic/service/report/impl/AreaHarmonicServiceImpl.java +++ b/pqs-harmonic/harmonic-boot/src/main/java/com/njcn/harmonic/service/report/impl/AreaHarmonicServiceImpl.java @@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; @@ -132,7 +133,7 @@ public class AreaHarmonicServiceImpl implements AreaHarmonicService { tableList.add(new ArrayList<>()); // 1. 台账表格 - List ledgerTable = buildLedgerTable(param.getDeptId()); + List ledgerTable = buildLedgerTable(param.getDeptId(),param.getScale()); if(CollUtil.isEmpty(ledgerTable)){ throw new BusinessException(CommonResponseEnum.FAIL,"当前部门不存在在运监测点"); } @@ -145,7 +146,7 @@ public class AreaHarmonicServiceImpl implements AreaHarmonicService { List qualityData = getPowerQualityData(param); if (CollUtil.isNotEmpty(qualityData)) { // 构建监控点名称映射 - Map monitorNameMap = buildMonitorNameMap(param.getDeptId()); + Map monitorNameMap = buildMonitorNameMap(param.getDeptId(),param.getScale()); // 过滤有效数据(在线监控数>0) List validData = qualityData.stream() @@ -176,8 +177,8 @@ public class AreaHarmonicServiceImpl implements AreaHarmonicService { /** * 构建台账表格 */ - private List buildLedgerTable(String deptId) { - List ledgerList = getLedgerInfo(deptId); + private List buildLedgerTable(String deptId, String scale) { + List ledgerList = getLedgerInfo(deptId,scale); if (CollUtil.isEmpty(ledgerList)) { return new ArrayList<>(); } @@ -190,7 +191,7 @@ public class AreaHarmonicServiceImpl implements AreaHarmonicService { MonitorCommLedgerInfoDTO ledger = ledgerList.get(i); return new String[]{ String.valueOf(i + 1), - ledger.getMonitorName(), + StringUtils.hasText(ledger.getObjName())? ledger.getObjName()+"_"+ledger.getMonitorName():ledger.getMonitorName(), ledger.getBdName(), ledger.getBusBarName(), voltageLevelMap.getOrDefault(ledger.getVoltageLevel(), ""), @@ -750,10 +751,14 @@ public class AreaHarmonicServiceImpl implements AreaHarmonicService { /** * 获取台账信息 */ - private List getLedgerInfo(String deptId) { + private List getLedgerInfo(String deptId, String scale) { DeptGetLineParam param = new DeptGetLineParam(); param.setDeptId(deptId); - return commTerminalGeneralClient.deptGetLineInfo(param).getData(); + List data = commTerminalGeneralClient.deptGetLineInfo(param).getData(); + if(StringUtils.hasText(scale)){ + data=data.stream().filter(temp->Objects.equals(scale,temp.getVoltageLevel())).collect(Collectors.toList()); + } + return data; } /** @@ -770,13 +775,14 @@ public class AreaHarmonicServiceImpl implements AreaHarmonicService { /** * 构建监控点名称映射 */ - private Map buildMonitorNameMap(String deptId) { - List ledgerList = getLedgerInfo(deptId); + private Map buildMonitorNameMap(String deptId, String scale) { + List ledgerList = getLedgerInfo(deptId, scale); return ledgerList.stream() .collect(Collectors.toMap( - MonitorCommLedgerInfoDTO::getMonitorId, - MonitorCommLedgerInfoDTO::getMonitorName - )); + MonitorCommLedgerInfoDTO::getMonitorId, + temp-> StringUtils.hasText(temp.getObjName())? temp.getObjName()+"_"+temp.getMonitorName():temp.getMonitorName() + + )); } /** diff --git a/pqs-system/system-api/src/main/java/com/njcn/system/api/CsStatisticalSetFeignClient.java b/pqs-system/system-api/src/main/java/com/njcn/system/api/CsStatisticalSetFeignClient.java index b743c8ca7..adb84cbef 100644 --- a/pqs-system/system-api/src/main/java/com/njcn/system/api/CsStatisticalSetFeignClient.java +++ b/pqs-system/system-api/src/main/java/com/njcn/system/api/CsStatisticalSetFeignClient.java @@ -1,16 +1,20 @@ package com.njcn.system.api; +import com.njcn.common.pojo.annotation.OperateInfo; import com.njcn.common.pojo.constant.ServerInfo; - +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.response.HttpResult; - +import com.njcn.common.utils.HttpResultUtil; import com.njcn.system.api.fallback.CsStatistiacalFeignClientFallbackFactory; +import com.njcn.system.pojo.po.CsStatisticalSetPO; import com.njcn.system.pojo.po.EleEpdPqd; import com.njcn.system.pojo.vo.CsStatisticalSetVO; - +import io.swagger.annotations.ApiOperation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; @@ -35,10 +39,12 @@ public interface CsStatisticalSetFeignClient { HttpResult queryStatistical(@RequestParam("id")String id); @PostMapping("/queryStatisticalSelect") - HttpResult> queryStatisticalSelect(@RequestParam("id")String id); - - + @ApiOperation("根据统计类型id组查询已绑定指标") + HttpResult> queryStatisticalSelect(@RequestBody List list); + @PostMapping("/queryStatisticalById") + @ApiOperation("根据id查询数据") + HttpResult> queryStatisticalById(@RequestBody List list); } diff --git a/pqs-system/system-api/src/main/java/com/njcn/system/api/fallback/CsStatistiacalFeignClientFallbackFactory.java b/pqs-system/system-api/src/main/java/com/njcn/system/api/fallback/CsStatistiacalFeignClientFallbackFactory.java index 0c9fa2d79..961696908 100644 --- a/pqs-system/system-api/src/main/java/com/njcn/system/api/fallback/CsStatistiacalFeignClientFallbackFactory.java +++ b/pqs-system/system-api/src/main/java/com/njcn/system/api/fallback/CsStatistiacalFeignClientFallbackFactory.java @@ -3,12 +3,8 @@ package com.njcn.system.api.fallback; import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.response.HttpResult; -import com.njcn.system.api.AreaFeignClient; -import com.njcn.system.api.ConfigFeignClient; import com.njcn.system.api.CsStatisticalSetFeignClient; -import com.njcn.system.pojo.dto.AreaTreeDTO; -import com.njcn.system.pojo.po.Area; -import com.njcn.system.pojo.po.Config; +import com.njcn.system.pojo.po.CsStatisticalSetPO; import com.njcn.system.pojo.po.EleEpdPqd; import com.njcn.system.pojo.vo.CsStatisticalSetVO; import com.njcn.system.utils.SystemEnumUtil; @@ -56,9 +52,16 @@ public class CsStatistiacalFeignClientFallbackFactory implements FallbackFactory throw new BusinessException(finalExceptionEnum); } @Override - public HttpResult> queryStatisticalSelect(String id) { + public HttpResult> queryStatisticalSelect(List list) { log.error("{}异常,降级处理,异常为:{}","根据统计类型id查询已绑定指标下拉框",cause.toString()); - throw new BusinessException(finalExceptionEnum); } + throw new BusinessException(finalExceptionEnum); + } + + @Override + public HttpResult> queryStatisticalById(List list) { + log.error("{}异常,降级处理,异常为:{}","根据id查询数据异常",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } }; } } diff --git a/pqs-system/system-boot/src/main/java/com/njcn/system/controller/CsStatisticalSetController.java b/pqs-system/system-boot/src/main/java/com/njcn/system/controller/CsStatisticalSetController.java index 4c3ecddae..1a9425fcc 100644 --- a/pqs-system/system-boot/src/main/java/com/njcn/system/controller/CsStatisticalSetController.java +++ b/pqs-system/system-boot/src/main/java/com/njcn/system/controller/CsStatisticalSetController.java @@ -6,13 +6,11 @@ import com.njcn.common.pojo.enums.common.LogEnum; import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.response.HttpResult; import com.njcn.common.utils.HttpResultUtil; - import com.njcn.system.pojo.param.CsStatisticalSetAddParam; +import com.njcn.system.pojo.po.CsStatisticalSetPO; import com.njcn.system.pojo.po.EleEpdPqd; import com.njcn.system.pojo.vo.CsStatisticalSetVO; - import com.njcn.system.service.CsStatisticalSetPOService; - import com.njcn.web.controller.BaseController; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -64,17 +62,22 @@ public class CsStatisticalSetController extends BaseController { @PostMapping("/queryStatisticalSelect") @OperateInfo(info = LogEnum.BUSINESS_COMMON) @ApiOperation("根据统计类型id组查询已绑定指标") - public HttpResult> queryStatisticalSelect(@RequestParam("id")String id){ + public HttpResult> queryStatisticalSelect(@RequestBody List list){ log.info("根据模板录入字典数据"); - String methodDescribe = getMethodDescribe("EleEpdPqd"); - List result = csStatisticalSetPOService.queryStatisticalSelect(id); + String methodDescribe = getMethodDescribe("queryStatisticalSelect"); + List result = csStatisticalSetPOService.queryStatisticalSelect(list); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe); } - - - - + @PostMapping("/queryStatisticalById") + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @ApiOperation("根据id查询数据") + public HttpResult> queryStatisticalById(@RequestBody List list){ + log.info("根据模板录入字典数据"); + String methodDescribe = getMethodDescribe("queryStatisticalById"); + List result = csStatisticalSetPOService.queryStatisticalById(list); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe); + } } diff --git a/pqs-system/system-boot/src/main/java/com/njcn/system/service/CsStatisticalSetPOService.java b/pqs-system/system-boot/src/main/java/com/njcn/system/service/CsStatisticalSetPOService.java index bd0e847b1..af7147c69 100644 --- a/pqs-system/system-boot/src/main/java/com/njcn/system/service/CsStatisticalSetPOService.java +++ b/pqs-system/system-boot/src/main/java/com/njcn/system/service/CsStatisticalSetPOService.java @@ -23,5 +23,7 @@ public interface CsStatisticalSetPOService extends IMppService queryStatisticalSelect(String id); + List queryStatisticalSelect(List list); + + List queryStatisticalById(List list); } diff --git a/pqs-system/system-boot/src/main/java/com/njcn/system/service/impl/CsStatisticalSetPOServiceImpl.java b/pqs-system/system-boot/src/main/java/com/njcn/system/service/impl/CsStatisticalSetPOServiceImpl.java index b8db31b19..fd7c62a1b 100644 --- a/pqs-system/system-boot/src/main/java/com/njcn/system/service/impl/CsStatisticalSetPOServiceImpl.java +++ b/pqs-system/system-boot/src/main/java/com/njcn/system/service/impl/CsStatisticalSetPOServiceImpl.java @@ -18,7 +18,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -108,9 +111,9 @@ public class CsStatisticalSetPOServiceImpl extends MppServiceImpl queryStatisticalSelect(String id) { + public List queryStatisticalSelect(List list) { QueryWrapper queryWrap = new QueryWrapper<>(); - queryWrap.lambda().eq(CsStatisticalSetPO::getStatisicalId, id); + queryWrap.lambda().in(CsStatisticalSetPO::getStatisicalId, list); List result = this.baseMapper.selectList(queryWrap); List collect = result.stream().map(CsStatisticalSetPO::getTargetId).collect(Collectors.toList()); if (CollectionUtils.isEmpty(collect)) { @@ -118,6 +121,13 @@ public class CsStatisticalSetPOServiceImpl extends MppServiceImpl queryStatisticalById(List list) { + QueryWrapper queryWrap = new QueryWrapper<>(); + queryWrap.lambda().in(CsStatisticalSetPO::getStatisicalId, list); + return this.baseMapper.selectList(queryWrap); + } } diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/api/SmsSendFeignClient.java b/pqs-user/user-api/src/main/java/com/njcn/user/api/SmsSendFeignClient.java new file mode 100644 index 000000000..68008dbe2 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/api/SmsSendFeignClient.java @@ -0,0 +1,23 @@ +package com.njcn.user.api; + +import com.njcn.common.pojo.constant.ServerInfo; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.user.api.fallback.SmsSendClientFallbackFactory; +import io.swagger.annotations.ApiOperation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author xy + */ +@FeignClient(value = ServerInfo.USER, path = "/sms", fallbackFactory = SmsSendClientFallbackFactory.class,contextId = "sms") +public interface SmsSendFeignClient { + + @PostMapping("/send/simple") + @ApiOperation("发送短信(简化参数)") + HttpResult sendSmsSimple(@RequestParam("receiver") String receiver + , @RequestParam("content") String content + , @RequestParam("messageType") String messageType); + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/api/fallback/SmsSendClientFallbackFactory.java b/pqs-user/user-api/src/main/java/com/njcn/user/api/fallback/SmsSendClientFallbackFactory.java new file mode 100644 index 000000000..94bfc65b2 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/api/fallback/SmsSendClientFallbackFactory.java @@ -0,0 +1,34 @@ +package com.njcn.user.api.fallback; + +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.user.api.SmsSendFeignClient; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author xy + */ +@Slf4j +@Component +public class SmsSendClientFallbackFactory implements FallbackFactory { + @Override + public SmsSendFeignClient create(Throwable cause) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (cause.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) cause.getCause(); + } + Enum finalExceptionEnum = exceptionEnum; + return new SmsSendFeignClient() { + + @Override + public HttpResult sendSmsSimple(String receiver, String content, String messageType) { + log.error("{}异常,降级处理,异常为:{}","发送短信(简化参数)数据异常",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } + }; + } +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/dto/CredentialReqDTO.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/dto/CredentialReqDTO.java new file mode 100644 index 000000000..10c228871 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/dto/CredentialReqDTO.java @@ -0,0 +1,35 @@ +package com.njcn.user.pojo.dto; + +/** + * @author caozehui + * @data 2026-03-31 + */ + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; + +/** + * 系统凭证请求 DTO + * + * @author msgpush + */ +@Data +public class CredentialReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 上游系统名称 + */ + @NotEmpty(message = "上游系统名称不能为空") + private String systemName; + + /** + * 密钥(用于生成凭证) + */ + @NotEmpty(message = "密钥不能为空") + private String secretKey; + +} \ No newline at end of file diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/dto/SendResult.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/dto/SendResult.java new file mode 100644 index 000000000..268b6de81 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/dto/SendResult.java @@ -0,0 +1,21 @@ +package com.njcn.user.pojo.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author xy + */ +@Data +@AllArgsConstructor +public class SendResult implements Serializable { + + private final boolean success; + private final String messageId; + private final String failReason; + private final boolean isTimeOut; + private final boolean unauthorized; + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/SmsSendRecord.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/SmsSendRecord.java new file mode 100644 index 000000000..fa1cc143d --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/SmsSendRecord.java @@ -0,0 +1,45 @@ +package com.njcn.user.pojo.po.app; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author xy + */ +@Data +@TableName("sms_send_record") +public class SmsSendRecord implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + private String receiver; + + private String content; + + private String messageType; + + private String credentialToken; + + private Integer sendStatus; + + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String failReason; + + private Integer retryCount; + + private Integer maxRetry; + + private Long responseTime; + + private LocalDateTime sendTime; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/vo/app/MessageRecordReqVO.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/vo/app/MessageRecordReqVO.java new file mode 100644 index 000000000..cdc49ac1c --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/vo/app/MessageRecordReqVO.java @@ -0,0 +1,36 @@ +package com.njcn.user.pojo.vo.app; + +import cn.hutool.core.lang.RegexPool; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +@Data +@Schema(description = "管理后台 - 消息记录发送 Request VO") +public class MessageRecordReqVO { + + private String channel; + + @Schema(description = "消息类型", example = "verify_code/order_notify/marketing/system_notify") + @NotBlank(message = "消息类型不能为空") + private String messageType; + + @Schema(description = "接收者") + @NotBlank(message = "接收者不能为空") + @Pattern(regexp = RegexPool.EMAIL + "|" + RegexPool.MOBILE, message = "必须是有效的邮箱或手机号格式") + private String receiver; + + @Schema(description = "标题") + private String title; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "模板编码") + private String templateCode; + + @Schema(description = "模板参数") + private String templateParams; +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/controller/message/SmsSendController.java b/pqs-user/user-boot/src/main/java/com/njcn/user/controller/message/SmsSendController.java new file mode 100644 index 000000000..66c93d344 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/controller/message/SmsSendController.java @@ -0,0 +1,77 @@ +package com.njcn.user.controller.message; + +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.user.pojo.vo.app.MessageRecordReqVO; +import com.njcn.user.service.ISmsSendService; +import com.njcn.web.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +/** + * @author xy + */ +@Slf4j +@RestController +@RequestMapping("/sms") +@Api(tags = "短信发送管理") +@AllArgsConstructor +public class SmsSendController extends BaseController { + + private final ISmsSendService smsSendService; + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/send") + @ApiOperation("发送短信(同步,包含重试)") + public HttpResult sendSms(@RequestBody MessageRecordReqVO vo) { + String methodDescribe = getMethodDescribe("sendSms"); + + try { + smsSendService.sendSmsWithRetry(vo); + return HttpResultUtil.assembleCommonResponseResult( + CommonResponseEnum.SUCCESS, + "短信发送成功", + methodDescribe + ); + } catch (Exception e) { + log.error("短信发送失败", e); + return HttpResultUtil.assembleCommonResponseResult( + CommonResponseEnum.FAIL, + e.getMessage(), + methodDescribe + ); + } + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/send/simple") + @ApiOperation("发送短信(简化参数)") + public HttpResult sendSmsSimple( + @RequestParam String receiver, + @RequestParam String content, + @RequestParam(defaultValue = "verify_code") String messageType) { + String methodDescribe = getMethodDescribe("sendSmsSimple"); + + try { + smsSendService.sendSmsWithRetry(receiver, content, messageType); + return HttpResultUtil.assembleCommonResponseResult( + CommonResponseEnum.SUCCESS, + "短信发送成功", + methodDescribe + ); + } catch (Exception e) { + log.error("短信发送失败", e); + return HttpResultUtil.assembleCommonResponseResult( + CommonResponseEnum.FAIL, + e.getMessage(), + methodDescribe + ); + } + } +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/CsSmsSendRecordMapper.java b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/CsSmsSendRecordMapper.java new file mode 100644 index 000000000..cdaa7eb63 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/CsSmsSendRecordMapper.java @@ -0,0 +1,7 @@ +package com.njcn.user.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.user.pojo.po.app.SmsSendRecord; + +public interface CsSmsSendRecordMapper extends BaseMapper { +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/SmsSendServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/SmsSendServiceImpl.java new file mode 100644 index 000000000..25549e0bf --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/SmsSendServiceImpl.java @@ -0,0 +1,416 @@ +package com.njcn.user.mapper; + +import com.alibaba.nacos.shaded.com.google.gson.Gson; +import com.alibaba.nacos.shaded.com.google.gson.JsonObject; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.redis.utils.RedisUtil; +import com.njcn.user.pojo.dto.CredentialReqDTO; +import com.njcn.user.pojo.dto.SendResult; +import com.njcn.user.pojo.po.app.SmsSendRecord; +import com.njcn.user.pojo.vo.app.MessageRecordReqVO; +import com.njcn.user.service.ISmsSendService; +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Collections; +import java.util.concurrent.TimeUnit; + +/** + * @author xy + */ +@Slf4j +@Service +@AllArgsConstructor +@RequiredArgsConstructor +public class SmsSendServiceImpl extends ServiceImpl implements ISmsSendService { + + @Value("${msg.credential_url:http://192.168.2.126:48083/admin-api/push/credential/generate}") + private String CREDENTIAL_URL; + @Value("${msg.sms_send_url:http://192.168.2.126:48083/admin-api/push/message/send/sms}") + private String SMS_SEND_URL; + @Value("${msg.connect_timeout:5000}") + private Integer CONNECT_TIMEOUT; + @Value("${msg.read_timeout:30000}") + private Integer READ_TIMEOUT; + @Value("${msg.system_name:NPQS-9500}") + private String SYSTEM_NAME; + @Value("${msg.secret_key:123456}") + private String SECRET_KEY; + + private static final int[] RETRY_DELAYS = {1, 2, 3}; + private static final int MAX_RETRY = 3; + private static final String CREDENTIAL_CACHE_KEY = "SMS_CREDENTIAL_TOKEN"; + private static final Gson GSON = new Gson(); + + @Resource + private RedisUtil redisUtil; + + @Override + public void sendSmsWithRetry(String receiver, String content, String messageType) { + MessageRecordReqVO vo = new MessageRecordReqVO(); + vo.setReceiver(receiver); + vo.setContent(content); + vo.setMessageType(messageType); + sendSmsWithRetry(vo); + } + + @Override + public void sendSmsWithRetry(MessageRecordReqVO messageRecordReqVO) { + SmsSendRecord record = initRecord(messageRecordReqVO); + + this.save(record); + + try { + String credentialToken = getOrRefreshCredentialWithRetry(record); + + if (credentialToken == null) { + record.setSendStatus(0); + record.setFailReason("获取凭证失败,已重试3次"); + log.error("获取凭证失败,短信未发送,接收者: {}", messageRecordReqVO.getReceiver()); + this.updateById(record); + throw new BusinessException("获取凭证失败,已重试3次"); + } + + record.setCredentialToken(credentialToken); + record.setSendTime(LocalDateTime.now()); + this.updateById(record); + + boolean success = attemptSendWithRetry(messageRecordReqVO, credentialToken, record); + + if (success) { + record.setSendStatus(1); + record.setFailReason(null); + log.info("短信发送成功,接收者: {}", messageRecordReqVO.getReceiver()); + } else { + record.setSendStatus(0); + if (record.getFailReason() == null) { + record.setFailReason("超过最大重试次数,发送失败"); + } + log.error("短信发送失败,接收者: {},已重试{}次,原因: {}", + messageRecordReqVO.getReceiver(), record.getRetryCount(), record.getFailReason()); + throw new BusinessException("短信发送失败: " + record.getFailReason()); + } + } catch (BusinessException e) { + record.setSendStatus(0); + record.setFailReason(e.getMessage()); + log.error("短信发送业务异常,接收者: {}", messageRecordReqVO.getReceiver(), e); + this.updateById(record); + throw e; + } catch (Exception e) { + record.setSendStatus(0); + record.setFailReason("发送异常: " + e.getMessage()); + log.error("短信发送异常,接收者: {}", messageRecordReqVO.getReceiver(), e); + this.updateById(record); + throw new BusinessException("短信发送异常: " + e.getMessage()); + } finally { + this.updateById(record); + } + } + + private SmsSendRecord initRecord(MessageRecordReqVO vo) { + SmsSendRecord record = new SmsSendRecord(); + record.setReceiver(vo.getReceiver()); + record.setContent(vo.getContent()); + record.setMessageType(vo.getMessageType()); + record.setSendStatus(-1); + record.setRetryCount(0); + record.setMaxRetry(MAX_RETRY); + record.setCreateTime(LocalDateTime.now()); + return record; + } + + private String getOrRefreshCredentialWithRetry(SmsSendRecord record) { + Object cachedToken = redisUtil.getObjectByKey(CREDENTIAL_CACHE_KEY); + if (cachedToken != null) { + log.info("使用缓存的凭证令牌"); + return cachedToken.toString(); + } + + log.info("缓存中无凭证,开始获取新凭证(最多重试3次)"); + + for (int i = 1; i <= 3; i++) { + try { + String token = fetchNewCredential(); + log.info("第{}次尝试获取凭证成功", i); + return token; + } catch (Exception e) { + log.warn("第{}次获取凭证失败: {}", i, e.getMessage()); + + record.setFailReason("获取凭证第" + i + "次失败: " + e.getMessage()); + this.updateById(record); + + try { + int waitSeconds = i * 10; + log.info("等待{}秒后重试...", waitSeconds); + TimeUnit.SECONDS.sleep(waitSeconds); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + log.error("凭证获取重试被中断"); + record.setFailReason("获取凭证实例被中断"); + this.updateById(record); + return null; + } + } + } + + log.error("获取凭证失败,已重试3次"); + return null; + } + + private String fetchNewCredential() { + CredentialReqDTO reqDTO = new CredentialReqDTO(); + reqDTO.setSystemName(SYSTEM_NAME); + reqDTO.setSecretKey(SECRET_KEY); + + HttpURLConnection connection = null; + try { + URL url = new URL(CREDENTIAL_URL); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setConnectTimeout(CONNECT_TIMEOUT); + connection.setReadTimeout(READ_TIMEOUT); + connection.setDoOutput(true); + + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(GSON.toJson(reqDTO).getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + outputStream.close(); + + int responseCode = connection.getResponseCode(); + if (responseCode != 200) { + throw new BusinessException("获取凭证失败,HTTP响应码: " + responseCode); + } + + BufferedReader reader = new BufferedReader( + new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)); + StringBuilder response = new StringBuilder(); + String inputLine; + while ((inputLine = reader.readLine()) != null) { + response.append(inputLine); + } + reader.close(); + + JsonObject jsonResponse = GSON.fromJson(response.toString(), JsonObject.class); + int code = jsonResponse.get("code").getAsInt(); + + if (code != 0) { + String msg = jsonResponse.has("msg") ? jsonResponse.get("msg").getAsString() : "未知错误"; + throw new BusinessException("获取凭证失败,错误码: " + code + ",错误信息: " + msg); + } + + JsonObject data = jsonResponse.getAsJsonObject("data"); + String token = data.get("credentialToken").getAsString(); + long expiresTimestamp = data.get("expiresTime").getAsLong(); + + LocalDateTime expiresTime = LocalDateTime.ofInstant( + Instant.ofEpochMilli(expiresTimestamp), + ZoneId.systemDefault() + ); + + long expireSeconds = calculateExpireSeconds(expiresTime); + redisUtil.saveByKeyWithExpire(CREDENTIAL_CACHE_KEY, token, expireSeconds); + + log.info("获取新凭证成功,过期时间: {},缓存有效期: {}秒", expiresTime, expireSeconds); + return token; + + } catch (SocketTimeoutException e) { + throw new BusinessException("获取凭证超时(30秒),请检查网络连接"); + } catch (ConnectException e) { + throw new BusinessException("无法连接到凭证服务,请检查服务是否启动和网络是否正常"); + } catch (IOException e) { + throw new BusinessException("获取凭证IO异常: " + e.getMessage()); + } finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + private long calculateExpireSeconds(LocalDateTime expiresTime) { + long expireSeconds = java.time.Duration.between( + LocalDateTime.now(), + expiresTime + ).getSeconds(); + + expireSeconds = expireSeconds - 60; + + return Math.max(expireSeconds, 60); + } + + private boolean attemptSendWithRetry(MessageRecordReqVO vo, String token, SmsSendRecord record) { + for (int attempt = 0; attempt <= MAX_RETRY; attempt++) { + if (attempt > 0) { + int delayMinutes = RETRY_DELAYS[attempt - 1]; + log.info("第{}次重试,等待{}分钟后发送...", attempt, delayMinutes); + + try { + TimeUnit.MINUTES.sleep(delayMinutes); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("重试等待被中断", e); + record.setFailReason("重试等待被中断"); + return false; + } + record.setRetryCount(attempt); + } + + SendResult result = executeSendSms(vo, token, record); + + if (result.isSuccess()) { + record.setFailReason(null); + log.info("第{}次尝试发送成功,消息ID: {}", attempt, result.getMessageId()); + return true; + } + + record.setFailReason(result.getFailReason()); + + if (result.isUnauthorized()) { + log.warn("凭证失效(401),重新获取凭证后重试..."); + String newToken = getOrRefreshCredentialWithRetry(record); + if (newToken == null) { + record.setFailReason("凭证刷新失败,无法重新获取凭证"); + return false; + } + token = newToken; + record.setCredentialToken(newToken); + this.updateById(record); + continue; + } + + if (!result.isTimeOut()) { + log.warn("发送失败且非超时,不再重试,原因: {},响应时间: {}ms", + result.getFailReason(), record.getResponseTime()); + return false; + } + + log.warn("第{}次发送超时,将重试,响应时间: {}ms", + attempt, record.getResponseTime()); + } + + record.setFailReason("超过最大重试次数,发送超时"); + return false; + } + + private SendResult executeSendSms(MessageRecordReqVO vo, String token, SmsSendRecord record) { + HttpURLConnection connection = null; + long startTime = System.currentTimeMillis(); + + try { + URL url = new URL(SMS_SEND_URL); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("X-Credential-Token", token); + connection.setConnectTimeout(CONNECT_TIMEOUT); + connection.setReadTimeout(READ_TIMEOUT); + connection.setDoOutput(true); + + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(GSON.toJson(Collections.singletonList(vo)).getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + outputStream.close(); + + int responseCode = connection.getResponseCode(); + long responseTime = System.currentTimeMillis() - startTime; + record.setResponseTime(responseTime); + + BufferedReader reader = new BufferedReader( + new InputStreamReader( + responseCode == 200 ? connection.getInputStream() : connection.getErrorStream(), + StandardCharsets.UTF_8 + ) + ); + StringBuilder response = new StringBuilder(); + String inputLine; + while ((inputLine = reader.readLine()) != null) { + response.append(inputLine); + } + reader.close(); + + if (responseCode != 200) { + String failReason = "HTTP响应码异常: " + responseCode; + if (response.length() > 0) { + failReason += ",响应: " + response.toString(); + } + record.setFailReason(failReason); + return new SendResult(false, null, failReason, false, false); + } + + JsonObject jsonResponse = GSON.fromJson(response.toString(), JsonObject.class); + int code = jsonResponse.get("code").getAsInt(); + + if (code == 401) { + String failReason = "凭证失效(HTTP 401)"; + record.setFailReason(failReason); + redisUtil.delete(CREDENTIAL_CACHE_KEY); + return new SendResult(false, null, failReason, false, true); + } else { + if (code != 0) { + String msg = jsonResponse.has("msg") ? jsonResponse.get("msg").getAsString() : "未知错误"; + String failReason = "业务错误码: " + code + ",错误信息: " + msg; + record.setFailReason(failReason); + return new SendResult(false, null, failReason, false, false); + } + } + + JsonObject firstResult = jsonResponse.getAsJsonArray("data").get(0).getAsJsonObject(); + boolean result = firstResult.get("result").getAsBoolean(); + String messageId = firstResult.has("messageId") ? firstResult.get("messageId").getAsString() : null; + String detail = firstResult.has("detail") ? firstResult.get("detail").getAsString() : null; + + if (result) { + log.info("短信发送成功,接收者: {},消息ID: {},详情: {},耗时: {}ms", + vo.getReceiver(), messageId, detail, responseTime); + return new SendResult(true, messageId, null, false, false); + } else { + String failReason = "发送失败: " + detail; + record.setFailReason(failReason); + return new SendResult(false, messageId, failReason, false, false); + } + + } catch (SocketTimeoutException e) { + long responseTime = System.currentTimeMillis() - startTime; + record.setResponseTime(responseTime); + String failReason = "请求超时(30秒)"; + record.setFailReason(failReason); + log.warn("短信发送超时,接收者: {},耗时: {}ms", vo.getReceiver(), responseTime); + return new SendResult(false, null, failReason, true, false); + } catch (ConnectException e) { + long responseTime = System.currentTimeMillis() - startTime; + record.setResponseTime(responseTime); + String failReason = "无法连接到短信服务"; + record.setFailReason(failReason); + log.error("短信服务连接失败,接收者: {}", vo.getReceiver(), e); + return new SendResult(false, null, failReason, false, false); + } catch (IOException e) { + long responseTime = System.currentTimeMillis() - startTime; + record.setResponseTime(responseTime); + String failReason = "IO异常: " + e.getMessage(); + record.setFailReason(failReason); + log.error("短信发送IO异常,接收者: {},耗时: {}ms", vo.getReceiver(), responseTime, e); + return new SendResult(false, null, failReason, false, false); + } finally { + if (connection != null) { + connection.disconnect(); + } + } + } +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/ISmsSendService.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/ISmsSendService.java new file mode 100644 index 000000000..4ba4611f8 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/ISmsSendService.java @@ -0,0 +1,12 @@ +package com.njcn.user.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.user.pojo.po.app.SmsSendRecord; +import com.njcn.user.pojo.vo.app.MessageRecordReqVO; + +public interface ISmsSendService extends IService { + + void sendSmsWithRetry(String receiver, String content, String messageType); + + void sendSmsWithRetry(MessageRecordReqVO messageRecordReqVO); +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java index 11acca295..8636e4378 100644 --- a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java @@ -1,6 +1,5 @@ package com.njcn.user.service.impl; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.njcn.common.pojo.constant.PatternRegex; @@ -19,7 +18,6 @@ import com.njcn.user.pojo.po.Role; import com.njcn.user.pojo.po.User; import com.njcn.user.pojo.po.UserSet; import com.njcn.user.pojo.po.app.AppInfoSet; -import com.njcn.user.pojo.po.app.AppSendMsg; import com.njcn.user.service.*; import com.njcn.user.util.SmsApiUtil; import com.njcn.user.util.SmsUtil; @@ -46,22 +44,14 @@ import java.util.*; public class AppUserServiceImpl extends ServiceImpl implements IAppUserService { private static final Logger logger = LoggerFactory.getLogger(AppUserServiceImpl.class); - private final RedisUtil redisUtil; - private final IAppSendMsgService appSendMsgService; - private final IUserSetService userSetService; - private final IRoleService roleService; - private final IUserRoleService userRoleService; - private final IAppInfoSetService appInfoSetService; - - private final SmsUtil smsUtil; - private final SmsApiUtil smsApiUtil; + private final ISmsSendService smsSendService; @Override @Transactional(rollbackFor = Exception.class) @@ -69,8 +59,6 @@ public class AppUserServiceImpl extends ServiceImpl impleme if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); } - SendSmsResponse sendSmsResponse = null; - ResponseEntity response = null; String msgTemplate = SmsUtil.getMessageTemplate(type); String vcode = null; try { @@ -97,70 +85,17 @@ public class AppUserServiceImpl extends ServiceImpl impleme //开始执行短信发送 String mobiles = phone; String content = SmsUtil.getLianTongMessageTemplate(type, vcode); - response = smsApiUtil.sendBatchSms(mobiles, content); + smsSendService.sendSmsWithRetry(mobiles,content,"verify_code"); String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone; //成功发送短信验证码后,保存进redis redisUtil.saveByKeyWithExpire(key, vcode, 300L); - //短信入库 - addZdSendMessage(phone,vcode,msgTemplate,response); } catch (Exception e) { logger.error("发送短信异常,异常为:"+e.getMessage()); - //短信入库 - addZdSendMessage(phone,vcode,msgTemplate,response); throw new BusinessException(e.getMessage()); } return "OK"; } -// @Override -// @Transactional(rollbackFor = Exception.class) -// public String setMessage(String phone, String devCode, String type) { -// if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ -// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); -// } -// SendSmsResponse sendSmsResponse = null; -// String msgTemplate = SmsUtil.getMessageTemplate(type); -// String vcode = null; -// try { -// //type为4,账号替换为新手机号 -// if (!msgTemplate.equalsIgnoreCase(MessageEnum.REGISTER.getTemplateCode())) { -// User user = this.lambdaQuery().eq(User::getPhone,phone).one(); -// if ("4".equalsIgnoreCase(type)) { -// //注册,无需判断手机号与设备的匹配 -// if (user != null) { -// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_FAIL); -// } -// } else { -// if (null == user) { -// throw new BusinessException(UserResponseEnum.LOGIN_PHONE_NOT_REGISTER); -// } else { -// user.setDevCode(devCode); -// logger.info("更新手机id:" + devCode); -// this.updateById(user); -// } -// } -// } -// vcode = getMessageCode(); -// //获取短信发送结果 -// sendSmsResponse = smsUtil.sendSms(phone,msgTemplate,"code",vcode); -// String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone; -// if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { -// //成功发送短信验证码后,保存进redis,验证码失效为5分钟 -// redisUtil.saveByKeyWithExpire(key, vcode,300L); -// } else { -// throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); -// } -// //短信入库 -// addSendMessage(phone,vcode,msgTemplate,sendSmsResponse); -// } catch (Exception e) { -// logger.error("发送短信异常,异常为:"+e.getMessage()); -// //短信入库 -// addSendMessage(phone,vcode,msgTemplate,sendSmsResponse); -// throw new BusinessException(e.getMessage()); -// } -// return sendSmsResponse.getCode(); -// } - @Override @Transactional(rollbackFor = {Exception.class}) public void register(String phone, String code, String devCode) { @@ -172,7 +107,6 @@ public class AppUserServiceImpl extends ServiceImpl impleme } judgeCode(phone, code); String password = null; - ResponseEntity response = null; //先根据手机号查询是否已被注册 User user = this.lambdaQuery().eq(User::getPhone,phone).ne(User::getState,0).one(); if (!Objects.isNull(user)){ @@ -198,73 +132,13 @@ public class AppUserServiceImpl extends ServiceImpl impleme //发送用户初始密码 password = redisUtil.getStringByKey(newUser.getId()); String content = SmsUtil.getLianTongMessageTemplate("3", password); - response = smsApiUtil.sendBatchSms(phone, content); - if (response != null && response.getStatusCodeValue() == 200) { - //成功发送短信验证码后,删除用户密码信息 - redisUtil.delete(newUser.getId()); - } else { - throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); - } - addZdSendMessage(phone,password,MessageEnum.getTemplateByCode(3),response); + smsSendService.sendSmsWithRetry(phone,content,"verify_code"); + redisUtil.delete(newUser.getId()); //删除验证码 deleteCode(phone); } } -// @Override -// @Transactional(rollbackFor = {Exception.class}) -// public void register(String phone, String code, String devCode) { -// if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ -// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); -// } -// if (StringUtils.isBlank(devCode)) { -// throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG); -// } -// judgeCode(phone, code); -// String password = null; -// SendSmsResponse sendSmsResponse = null; -// //先根据手机号查询是否已被注册 -// User user = this.lambdaQuery().eq(User::getPhone,phone).ne(User::getState,0).one(); -// if (!Objects.isNull(user)){ -// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_REPEAT); -// } else { -// //新增用户配置表 -// UserSet userSet = userSetService.addAppUserSet(); -// //新增用户表 -// User newUser = cloneUserBoToUser(phone,devCode,userSet); -// //新增用户角色关系表 -// Role role = roleService.getRoleByCode(AppRoleEnum.TOURIST.getCode()); -// userRoleService.addUserRole(newUser.getId(), Collections.singletonList(role.getId())); -// //消息默认配置 -// AppInfoSet appInfoSet = new AppInfoSet(); -// appInfoSet.setUserId(newUser.getId()); -// appInfoSet.setHarmonicInfo(1); -// appInfoSet.setEventInfo(1); -// appInfoSet.setRunInfo(1); -// appInfoSet.setAlarmInfo(1); -// appInfoSet.setFunctionBug(0); -// appInfoSet.setExFactoryBug(0); -// appInfoSetService.save(appInfoSet); -// //发送用户初始密码 -// try { -// password = redisUtil.getStringByKey(newUser.getId()); -// sendSmsResponse = smsUtil.sendSms(phone,MessageEnum.getTemplateByCode(3),"pwd",password); -// if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { -// //成功发送短信验证码后,删除用户密码信息 -// redisUtil.delete(newUser.getId()); -// } else { -// throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); -// } -// addSendMessage(phone,password,MessageEnum.getTemplateByCode(3),sendSmsResponse); -// } catch (ClientException e) { -// logger.error("发送短信异常,异常为:"+e.getMessage()); -// addSendMessage(phone,password,MessageEnum.getTemplateByCode(3),sendSmsResponse); -// } -// //删除验证码 -// deleteCode(phone); -// } -// } - @Override public void modifyPsd(String userId, String phone, String code, String password, String devCode) { if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ @@ -426,41 +300,4 @@ public class AppUserServiceImpl extends ServiceImpl impleme return user; } - /** - * 验证码入库 - */ - public void addSendMessage(String phone, String vcode, String template, SendSmsResponse sendSmsResponse) { - AppSendMsg appSendMsg = new AppSendMsg(); - appSendMsg.setPhone(phone); - appSendMsg.setMessage(vcode); - appSendMsg.setSendTime(LocalDateTime.now()); - if (Objects.isNull(sendSmsResponse)){ - appSendMsg.setSendStatus("无状态"); - appSendMsg.setRemark(null); - } else { - appSendMsg.setSendStatus(sendSmsResponse.getCode() == null ? "无状态" : sendSmsResponse.getCode()); - appSendMsg.setRemark(sendSmsResponse.getMessage()); - } - appSendMsg.setTemplate(template); - appSendMsgService.save(appSendMsg); - } - - /** - * 中国电信验证码入库 - */ - public void addZdSendMessage(String phone, String vcode, String template, ResponseEntity response) { - AppSendMsg appSendMsg = new AppSendMsg(); - appSendMsg.setPhone(phone); - appSendMsg.setMessage(vcode); - appSendMsg.setSendTime(LocalDateTime.now()); - if (Objects.isNull(response)){ - appSendMsg.setSendStatus("无状态"); - appSendMsg.setRemark(null); - } else { - appSendMsg.setSendStatus(String.valueOf(response.getStatusCodeValue())); - } - appSendMsg.setTemplate(template); - appSendMsgService.save(appSendMsg); - } - } diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/UserServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/UserServiceImpl.java index db4c745a9..87874d7dd 100644 --- a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/UserServiceImpl.java +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/UserServiceImpl.java @@ -480,11 +480,21 @@ public class UserServiceImpl extends ServiceImpl implements IU @Override public List getMarketList() { Role roleByCode = roleService.getRoleByCode(AppRoleEnum.MARKET_USER.getCode()); - List userRoles = userRoleMapper.selectUserRole(Stream.of(roleByCode.getId()).collect(Collectors.toList())); - List collect = userRoles.stream().map(UserRole::getUserId).collect(Collectors.toList()); - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.ne(User::getState, UserState.DELETE).in(User::getId, collect); - return this.list(queryWrapper); + List userRoles = userRoleMapper.selectUserRole( + Collections.singletonList(roleByCode.getId()) + ); + List userIds = userRoles.stream() + .map(UserRole::getUserId) + .collect(Collectors.toList()); + + if (userIds.isEmpty()) { + return Collections.emptyList(); + } + + return this.lambdaQuery() + .ne(User::getState, UserState.DELETE) + .in(User::getId, userIds) + .list(); } @Override