Преглед изворни кода

处理纱线规格 ,处理在线设备,处理长度为0不参与稼动率计算

wukai пре 7 месеци
родитељ
комит
1e2a8c511b

+ 92 - 12
ruoyi-admin/src/main/java/com/ruoyi/biz/controller/ApiController.java

@@ -10,12 +10,13 @@ import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.utils.CacheUtils;
 import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.system.service.ISysConfigService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
@@ -51,10 +52,6 @@ public class ApiController extends BaseController {
     @Resource
     private ITwinCalcDayService twinCalcDayService;
     @Resource
-    private ITwinCalc2hrService calc2hrService;
-    @Resource
-    private ITwinRecordAlarmsService recordAlarmsService;
-    @Resource
     private ITwinCalcStopService stopService;
     @Resource
     private ITwinCalcAlarmsService alarmsService;
@@ -65,10 +62,6 @@ public class ApiController extends BaseController {
     @Resource
     private AsyncServiceImpl asyncService;
     @Resource
-    private ITwinPanHeadInfoService panHeadInfoService;
-    @Resource
-    private ISysConfigService configService;
-    @Resource
     private BrokenYarnExportServiceImpl exportService;
     @Value("${excel.total}")
     private String totalExcelTemplate;
@@ -231,7 +224,7 @@ public class ApiController extends BaseController {
     @ApiOperation("纱线规格")
     @GetMapping("/export/yarn-specifications")
     @CrossOrigin(origins = "*")
-    public void yarnSpecificationsExport(HttpServletResponse response) {
+    public void yarnSpecificationsExport(Integer day, HttpServletResponse response) {
         Object d = CacheUtils.get(Constants.IOT_TOKEN, Constants.INDEX_FORMULA_DETAIL);
         if (d != null) {
             List<FormulaDetail> list = (List<FormulaDetail>) d;
@@ -239,10 +232,25 @@ public class ApiController extends BaseController {
                     .thenComparing(FormulaDetail::getFormula_data_7).thenComparing(FormulaDetail::getFormula_data_8).thenComparing(FormulaDetail::getFormula_data_9)
                     .thenComparing(FormulaDetail::getFormula_data_15));
             Map<String, List<FormulaDetail>> map = list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnD, LinkedHashMap::new, Collectors.toList()));
-
-            try (FileInputStream inputStream = new FileInputStream(yarnExcelTemplate); Workbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
+            LocalDateTime localDateTime = LocalDateTime.now();
+            if (localDateTime.getHour() < 7) {
+                //当天7点前,则是前天数据
+                localDateTime = localDateTime.minusDays(2);
+            } else {
+                //7点后,就是昨日数据
+                localDateTime = localDateTime.minusDays(1);
+            }
+            LocalDate localDate = localDateTime.toLocalDate();
+            Date sd = Date.from(localDate.atStartOfDay(ZoneOffset.of("+8")).toInstant());
+            List<TwinCalcDay> calcDayList = twinCalcDayService.selectTwinCalcDayListByTime(sd, sd);
+            Map<Long, BigDecimal> decimalMap = calcDayList.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, TwinCalcDay::getLength));
+            try (FileInputStream inputStream = new FileInputStream(yarnExcelTemplate); XSSFWorkbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
                 Sheet sheet = wb.getSheetAt(0);
                 AtomicInteger rowNum = new AtomicInteger(2);
+                CellStyle percentStyle = wb.createCellStyle();
+                percentStyle.setDataFormat(wb.createDataFormat().getFormat("0.00%"));
+                // 垂直居中
+                percentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                 CellStyle p2 = wb.createCellStyle();
                 p2.setDataFormat(wb.createDataFormat().getFormat("0.00"));
                 for (String s : map.keySet()) {
@@ -264,6 +272,78 @@ public class ApiController extends BaseController {
                         sheet.addMergedRegion(new CellRangeAddress(sr, er, 2, 2));
                     }
                 }
+                XSSFSheet sheet2 = wb.getSheetAt(1);
+                wb.setSheetName(1, "未来产能预期(" + day + "天)");
+                AtomicInteger rn = new AtomicInteger(2);
+                //1.先按底纱分组
+                Map<String, List<FormulaDetail>> map2 = list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnDd, LinkedHashMap::new, Collectors.toList()));
+                for (String s : map2.keySet()) {
+                    int sr = rn.get();
+                    List<FormulaDetail> l12list = map2.get(s);
+                    //2.再按规格分组
+                    Map<Integer, List<FormulaDetail>> d1map = l12list.stream().collect(Collectors.groupingBy(FormulaDetail::getFormula_data_6, LinkedHashMap::new, Collectors.toList()));
+                    for (Integer l3d : d1map.keySet()) {
+                        int ssr = rn.get();
+                        List<FormulaDetail> l3list = d1map.get(l3d);
+                        //3.再按盘头根数和毛高分组
+                        Map<String, List<FormulaDetail>> d2map = l3list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnPt, LinkedHashMap::new, Collectors.toList()));
+                        for (String pt : d2map.keySet()) {
+                            List<FormulaDetail> ptList = d2map.get(pt);
+                            FormulaDetail detail = ptList.get(0);
+                            String device = "";
+                            BigDecimal length = BigDecimal.ZERO;
+                            for (FormulaDetail dd : ptList) {
+                                BigDecimal temp = decimalMap.get(dd.getDeviceId());
+                                if (temp != null) {
+                                    length = length.add(temp);
+                                }
+//                                device += dd.getDevice() + "/";
+                            }
+                            BigDecimal yLength = length.multiply(BigDecimal.valueOf(day));
+                            Row row = sheet2.createRow(rn.get());
+                            Cell[] cells = new Cell[12];
+                            for (int i = 0; i < cells.length; i++) {
+                                cells[i] = row.createCell(i);
+                            }
+                            cells[0].setCellValue(rn.get() - 1);
+                            cells[1].setCellValue(detail.getFormula_data_4());
+                            cells[2].setCellValue(detail.getFormula_data_5());
+                            cells[3].setCellValue(detail.getFormula_data_6());
+                            cells[4].setCellValue(detail.getFormula_data_10());
+                            cells[5].setCellValue(detail.getFormula_data_11());
+                            cells[6].setCellValue(detail.getFormula_data_12());
+                            cells[7].setCellValue(detail.getFormula_data_15());
+                            cells[8].setCellValue(length.doubleValue());
+                            cells[8].setCellStyle(p2);
+                            cells[9].setCellValue(yLength.doubleValue());
+                            cells[9].setCellStyle(p2);
+                            //规格占比
+                            BigDecimal percent1 = BigDecimal.valueOf(ptList.size()).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
+                            cells[10].setCellValue(percent1.doubleValue());
+                            cells[10].setCellStyle(percentStyle);
+                            //底纱占比
+                            BigDecimal percent2 = BigDecimal.valueOf(l12list.size()).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
+                            cells[11].setCellValue(percent2.doubleValue());
+                            cells[11].setCellStyle(percentStyle);
+                            rn.getAndIncrement();
+                        }
+                        if (d2map.size() > 1) {
+                            int er = rn.get() - 1;
+                            sheet2.addMergedRegion(new CellRangeAddress(ssr, er, 1, 1));
+                            sheet2.addMergedRegion(new CellRangeAddress(ssr, er, 2, 2));
+                            sheet2.addMergedRegion(new CellRangeAddress(ssr, er, 3, 3));
+                        }
+                    }
+                    if (d1map.size() > 1) {
+                        int er = rn.get() - 1;
+                        sheet2.addMergedRegion(new CellRangeAddress(sr, er, 11, 11));
+                    }
+                }
+                int endRn = rn.get() - 1;
+                int[] pos = {13, 1, 20, endRn + 1};
+                int[] xdata = {2, endRn, 0, 0};
+                int[] data = {2, endRn, 10, 10};
+                exportService.drawBar(sheet2, "规格占比", "规格序号", pos, xdata, data, BarDirection.COL);
                 // 清空response
                 response.reset();
                 // 设置response的Header

+ 10 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/domain/FormulaDetail.java

@@ -19,6 +19,9 @@ import java.util.Map;
 public class FormulaDetail {
     @ApiModelProperty("设备信息")
     private String device;
+
+    @ApiModelProperty("设备ID")
+    private Long deviceId;
     @ApiModelProperty("配方号")
     private Integer formula_data_1;
     @ApiModelProperty("机台号")
@@ -91,12 +94,17 @@ public class FormulaDetail {
     private Integer capacity_data_19;
     @ApiModelProperty("纱线规格D")
     private String yarnD;
+    @ApiModelProperty("纱线规格D底纱")
+    private String yarnDd;
     @ApiModelProperty("纱线规格F")
     private String yarnF;
+    @ApiModelProperty("盘头根数信息")
+    private String yarnPt;
 
 
     public FormulaDetail(Map<String, Object> map) {
         TwinDevice twinDevice = (TwinDevice) map.get("device");
+        this.deviceId = twinDevice.getDeviceId();
         this.device = twinDevice.getDeviceName();
         this.formula_data_1 = (int) map.get("Formula_data_1");
         this.formula_data_2 = (int) map.get("Formula_data_2");
@@ -135,8 +143,10 @@ public class FormulaDetail {
         this.capacity_data_18 = (int) map.get("Capacity_data_18");
         this.capacity_data_19 = (int) map.get("Capacity_data_19");
 
+        this.yarnDd = this.formula_data_4 + "/" + formula_data_5;
         this.yarnD = this.formula_data_4 + "/" + formula_data_5 + "/" + formula_data_6;
         this.yarnF = this.formula_data_7 + "/" + formula_data_8 + "/" + formula_data_9;
+        this.yarnPt = this.formula_data_10 + "/" + formula_data_11 + "/" + formula_data_12 + "/" + formula_data_15;
     }
 
     public void setCells(Cell[] cells) {

+ 15 - 4
ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinCalcDay.java

@@ -336,7 +336,6 @@ public class TwinCalcDay extends BaseEntity {
             this.stop3B += day.getStop3B();
 
             this.alarm += day.getAlarm();
-
             this.closeTimeA = closeTimeA.add(day.getCloseTimeA());
             this.closeTimeB = closeTimeB.add(day.getCloseTimeB());
             this.openTimeA = openTimeA.add(day.getOpenTimeA());
@@ -346,9 +345,21 @@ public class TwinCalcDay extends BaseEntity {
         BigDecimal teamTimeB = this.openTimeB.add(this.closeTimeB);
         BigDecimal totalTeamTime = teamTimeA.add(teamTimeB);
         BigDecimal totalOpenTime = this.openTimeA.add(openTimeB);
-        this.efficiencyA = openTimeA.divide(teamTimeA, 2, RoundingMode.HALF_UP);
-        this.efficiencyB = openTimeB.divide(teamTimeB, 2, RoundingMode.HALF_UP);
-        this.efficiency = totalOpenTime.divide(totalTeamTime, 2, RoundingMode.HALF_UP);
+        if (teamTimeA.intValue() == 0) {
+            this.efficiencyA = BigDecimal.ZERO;
+        } else {
+            this.efficiencyA = openTimeA.divide(teamTimeA, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
+        }
+        if (teamTimeB.intValue() == 0) {
+            this.efficiencyB = BigDecimal.ZERO;
+        } else {
+            this.efficiencyB = openTimeB.divide(teamTimeB, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
+        }
+        if (totalTeamTime.intValue() == 0) {
+            this.efficiency = BigDecimal.ZERO;
+        } else {
+            this.efficiency = totalOpenTime.divide(totalTeamTime, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
+        }
     }
 
     public void setCells(Cell[] cells) {

+ 8 - 2
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/ApiServiceImpl.java

@@ -133,6 +133,7 @@ public class ApiServiceImpl implements IApiService {
             TwinDevice twinDevice = list.get(i);
             futureList.add(asyncService.currData(twinDevice));
         }
+        int onlineNum = 0;
         try {
             for (Future<Map<String, Object>> future : futureList) {
                 Map<String, Object> map = future.get();
@@ -143,6 +144,11 @@ public class ApiServiceImpl implements IApiService {
                     //可能会出现接口返回无数据的情况,需要设置设备状态为离线
                     continue;
                 }
+                float cd1 = (float) map.get("Capacity_data_1");
+                if (cd1 != 0f) {
+                    //主轴运行转速(转/分钟) 为0时,表示未开机
+                    onlineNum++;
+                }
                 //处理配方明细数据
                 FormulaDetail detail = new FormulaDetail(map);
                 formulaDetail.add(detail);
@@ -244,8 +250,8 @@ public class ApiServiceImpl implements IApiService {
         indexData.setAlarm(alarmList);
         indexData.setPan(panList);
         IndexDevice device = new IndexDevice();
-        device.setTotal(Integer.parseInt(configService.selectConfigByKey("sys.device.total")));
-        device.setOnline(list.size());
+        device.setTotal(list.size());
+        device.setOnline(onlineNum);
         device.setStop1(stop1);
         device.setStop2(stop2);
         device.setStop6(stop6);

+ 7 - 7
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/BrokenYarnExportServiceImpl.java

@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 /**
- * 多线程执行任
+ * 断纱分析服
  *
  * @author wukai
  * @date 2024/5/4 20:35
@@ -158,10 +158,10 @@ public class BrokenYarnExportServiceImpl {
         int[] pos = {0, 10, 5, 30};
         int[] data = {2, 8, 3, 3};
         int[] xdata = {2, 8, 0, 0};
-        drawBar(sheet, "停机次数占比", "停机原因", pos, xdata, data);
+        drawBar(sheet, "停机次数占比", "停机原因", pos, xdata, data,BarDirection.BAR);
         int[] pos1 = {6, 10, 16, 30};
         int[] data1 = {2, 8, 4, 4};
-        drawBar(sheet, "停机时长占比", "停机原因", pos1, xdata, data1);
+        drawBar(sheet, "停机时长占比", "停机原因", pos1, xdata, data1,BarDirection.BAR);
 
         brokenYarn(wb, yarnStopList, stopTime[1], stopList.size());
         yarn(wb, yarnStopList, dateStyle, timeStyle, p2);
@@ -226,14 +226,14 @@ public class BrokenYarnExportServiceImpl {
         int[] pos = {10, 2, 16, rn};
         int[] data = {2, rn, 1, 1};
         int[] xdata = {2, rn, 0, 0};
-        drawBar(sheet, "断纱停机周TOP", "设备名称", pos, xdata, data);
+        drawBar(sheet, "断纱停机周TOP", "设备名称", pos, xdata, data,BarDirection.BAR);
         drawTopLine(sheet, rn);
     }
 
     private void drawTopLine(XSSFSheet sheet, int endRn) {
         XSSFDrawing drawing = sheet.createDrawingPatriarch();
         // 2 左侧距离单元格个数, 4 顶部距离单元格个数, 7 左侧距离单元格个数, 26 顶部距离单元格个数
-        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, endRn+1, 15, endRn+26);
+        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, endRn + 1, 15, endRn + 26);
         XSSFChart chart = drawing.createChart(anchor);
         // 图表标题
         chart.setTitleText("断纱停机趋势");
@@ -332,7 +332,7 @@ public class BrokenYarnExportServiceImpl {
         chart.plot(data);
     }
 
-    private void drawBar(XSSFSheet sheet, String title, String xTitle, int[] pos, int[] xdata, int[] data) {
+    public void drawBar(XSSFSheet sheet, String title, String xTitle, int[] pos, int[] xdata, int[] data,BarDirection barDirection) {
         // 创建一个画布
         XSSFDrawing drawing = sheet.createDrawingPatriarch();
         // 前四个默认0,[0,5]:从0列5行开始;[7,26]:到7列26行结束
@@ -371,7 +371,7 @@ public class BrokenYarnExportServiceImpl {
         // 设置为可变颜色
         bar.setVaryColors(true);// 如果需要设置成自己想要的颜色,这里可变颜色要设置成false
         // 条形图方向,纵向/横向:纵向
-        bar.setBarDirection(BarDirection.BAR);
+        bar.setBarDirection(barDirection);
 
         // 图表加载数据,条形图1
         XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(countries, area);

+ 12 - 4
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinCalcDayServiceImpl.java

@@ -4,6 +4,7 @@ import com.ruoyi.biz.domain.*;
 import com.ruoyi.biz.mapper.TwinCalcDayMapper;
 import com.ruoyi.biz.service.*;
 import com.ruoyi.biz.tools.Tools;
+import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.text.Convert;
 import com.ruoyi.common.utils.DateUtils;
 import javafx.util.Pair;
@@ -252,6 +253,15 @@ public class TwinCalcDayServiceImpl implements ITwinCalcDayService {
             day.setEfficiencyA(ea);
             day.setEfficiencyB(eb);
             day.setEfficiency(ee);
+            if (day.getLength().intValue() == 0) {
+                day.setOpenTimeA(BigDecimal.ZERO);
+                day.setOpenTimeB(BigDecimal.ZERO);
+                day.setCloseTimeA(BigDecimal.ZERO);
+                day.setCloseTimeB(BigDecimal.ZERO);
+                day.setEfficiencyA(BigDecimal.ZERO);
+                day.setEfficiencyB(BigDecimal.ZERO);
+                day.setEfficiency(BigDecimal.ZERO);
+            }
             List<TwinCalcAlarms> alarms = alarmsList.stream().filter(a -> a.getDeviceId().equals(entry.getKey())).collect(Collectors.toList());
             day.setAlarm((long) alarms.size());
             insertTwinCalcDay(day);
@@ -327,16 +337,14 @@ public class TwinCalcDayServiceImpl implements ITwinCalcDayService {
             calcDay.calcHours(hours);
         }
 
-
         BigDecimal totalTimeA = calcDay.getOpenTimeA().add(calcDay.getCloseTimeA());
         BigDecimal totalTimeB = calcDay.getOpenTimeB().add(calcDay.getCloseTimeB());
         if (!totalTimeA.equals(BigDecimal.ZERO)) {
-            BigDecimal eff = calcDay.getOpenTimeA().divide(totalTimeA, 2, RoundingMode.HALF_UP);
+            BigDecimal eff = calcDay.getOpenTimeA().divide(totalTimeA, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
             calcDay.setEfficiencyA(eff);
-
         }
         if (!totalTimeB.equals(BigDecimal.ZERO)) {
-            BigDecimal eff = calcDay.getOpenTimeB().divide(totalTimeB, 2, RoundingMode.HALF_UP);
+            BigDecimal eff = calcDay.getOpenTimeB().divide(totalTimeB, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
             calcDay.setEfficiencyB(eff);
         }
         return calcDay;

+ 478 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/YarnSpecificationsExportServiceImpl.java

@@ -0,0 +1,478 @@
+package com.ruoyi.biz.service.impl;
+
+import com.ruoyi.biz.domain.TwinCalcDay;
+import com.ruoyi.biz.domain.TwinCalcStop;
+import com.ruoyi.biz.domain.TwinDevice;
+import com.ruoyi.biz.service.ITwinCalcDayService;
+import com.ruoyi.biz.service.ITwinCalcStopService;
+import com.ruoyi.biz.service.ITwinDeviceService;
+import com.ruoyi.biz.tools.Tools;
+import com.ruoyi.common.utils.DateUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.*;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+/**
+ * 纱线规格服务
+ *
+ * @author wukai
+ * @date 2024/5/4 20:35
+ */
+@Service
+@Slf4j
+public class YarnSpecificationsExportServiceImpl {
+    @Resource
+    private ITwinCalcDayService twinCalcDayService;
+    @Resource
+    private ITwinCalcStopService stopService;
+    @Resource
+    private ITwinDeviceService deviceService;
+
+    /**
+     * 基本信息表
+     *
+     * @param wb
+     * @param localDate
+     */
+    public void base(XSSFWorkbook wb, LocalDate localDate) {
+        LocalDate st = localDate.minusDays(7);
+        Date sd = Date.from(st.atStartOfDay(ZoneOffset.of("+8")).toInstant());
+        Date ed = Date.from(localDate.atStartOfDay(ZoneOffset.of("+8")).toInstant());
+        //7天数据
+        List<TwinCalcDay> dayList = twinCalcDayService.selectTwinCalcDayListByTime(sd, ed);
+        //当天数据
+        List<TwinCalcDay> curr = dayList.stream().filter(day -> day.getTime().equals(ed)).collect(Collectors.toList());
+        //1.基本信息
+        XSSFSheet sheet = wb.getSheetAt(0);
+        Cell cell = sheet.getRow(1).getCell(1);
+        cell.setCellValue(localDate);
+
+        //计算开机设备数量,A班开机时间+B班开机时间大于0的。
+        //按设备分组
+        Map<Long, List<TwinCalcDay>> deviceGr = curr.stream().collect(Collectors.groupingBy(TwinCalcDay::getDeviceId, LinkedHashMap::new, Collectors.toList()));
+        int openDevices = 0;
+        BigDecimal totOpenTimes = BigDecimal.ZERO;
+        for (Map.Entry<Long, List<TwinCalcDay>> entry1 : deviceGr.entrySet()) {
+            TwinCalcDay tempDay = new TwinCalcDay(ed);
+            tempDay.calcDays(entry1.getValue());
+            BigDecimal tot = tempDay.getOpenTimeA().add(tempDay.getOpenTimeB());
+            if (tot.intValue() > 0) {
+                openDevices++;
+            }
+            totOpenTimes = totOpenTimes.add(tot);
+        }
+
+        cell = sheet.getRow(2).getCell(1);
+        cell.setCellValue(openDevices);
+        BigDecimal avgOpenTimes = totOpenTimes.divide(BigDecimal.valueOf(openDevices), 0, RoundingMode.HALF_UP);
+
+        cell = sheet.getRow(3).getCell(1);
+        cell.setCellValue(Tools.convertHMS(totOpenTimes.longValue()));
+        cell = sheet.getRow(4).getCell(1);
+        cell.setCellValue(Tools.convertHMS(avgOpenTimes.longValue()));
+
+        drawLine(sheet, dayList);
+    }
+
+    private final String[] stopStr = {"停经片停机", "CCD停机(相机号+断纱/故障)", "人工停机", "断电停机", "设备故障停机", "落布米数达到停机", "盘头剩余圈数达到停机"};
+
+    public void stop(XSSFWorkbook wb, LocalDate localDate) {
+        CreationHelper creationHelper = wb.getCreationHelper();
+        CellStyle percentStyle = wb.createCellStyle();
+        percentStyle.setDataFormat(creationHelper.createDataFormat().getFormat("0.00%"));
+        CellStyle p2 = wb.createCellStyle();
+        p2.setDataFormat(wb.createDataFormat().getFormat("0.00"));
+        CellStyle dateStyle = wb.createCellStyle();
+        dateStyle.setDataFormat(creationHelper.createDataFormat().getFormat(DateUtils.YYYY_MM_DD));
+        CellStyle timeStyle = wb.createCellStyle();
+        timeStyle.setDataFormat(creationHelper.createDataFormat().getFormat(DateUtils.YYYY_MM_DD_HH_MM_SS));
+        CellStyle rightStyle = wb.createCellStyle();
+        rightStyle.setAlignment(HorizontalAlignment.RIGHT);
+        LocalDateTime sdt = LocalDateTime.of(localDate, LocalTime.of(7, 0));
+        LocalDateTime edt = LocalDateTime.of(localDate.plusDays(1), LocalTime.of(6, 59, 59));
+        Date sTime = Date.from(sdt.atZone(ZoneId.systemDefault()).toInstant());
+        Date eTime = Date.from(edt.atZone(ZoneId.systemDefault()).toInstant());
+        List<TwinCalcStop> stopList = stopService.selectTwinCalcStopListByDate(sTime, eTime);
+        Map<Integer, List<TwinCalcStop>> stopDeviceGroup = stopList.stream().collect(Collectors.groupingBy(TwinCalcStop::getStopType, LinkedHashMap::new, Collectors.toList()));
+
+        List<TwinCalcStop> yarnStopList = stopList.stream().filter(stop -> stop.getStopType().equals(2)).collect(Collectors.toList());
+        //1停经片停机,2-CCD停机(相机号+断纱/故障),3-人工停机,4-断电停机,5-设备故障停机,6-落布米数达到停机,7-盘头剩余圈数达到停机
+        //停机次数
+        Integer[] stopNum = new Integer[7];
+        Integer totalNum = 0;
+        //停机时间
+        Long[] stopTime = new Long[7];
+        Arrays.fill(stopTime, 0L);
+        AtomicReference<Long> totalTime = new AtomicReference<>(0L);
+        for (Map.Entry<Integer, List<TwinCalcStop>> entry : stopDeviceGroup.entrySet()) {
+            Integer stopType = entry.getKey();
+            int pos = stopType - 1;
+            List<TwinCalcStop> stops = entry.getValue();
+            stopNum[pos] = stops.size();
+            totalNum += stops.size();
+            stops.forEach(stop -> {
+                Date stopEndTime = stop.getEndTime();
+                // 调整停机时间
+                if (stop.getEndTime().compareTo(eTime) > 0) {
+                    stopEndTime = eTime;
+                }
+                Date stopStartTime = stop.getStartTime();
+                //调整开机时间
+                if (stop.getStartTime().compareTo(sTime) < 0) {
+                    stopStartTime = sTime;
+                }
+                long t = (stopEndTime.getTime() - stopStartTime.getTime()) / 1000;
+                stopTime[pos] += t;
+                totalTime.updateAndGet(v -> v + t);
+            });
+        }
+        XSSFSheet sheet = wb.getSheetAt(1);
+        for (int i = 0; i < stopStr.length; i++) {
+            Row row = sheet.createRow(i + 2);
+            Cell[] cells = new Cell[5];
+            for (int j = 0; j < cells.length; j++) {
+                cells[j] = row.createCell(j);
+            }
+            cells[0].setCellValue(stopStr[i]);
+            cells[1].setCellValue(stopNum[i]);
+            cells[2].setCellValue(Tools.convertHMS(stopTime[i]));
+            cells[2].setCellStyle(rightStyle);
+            float percentNum = BigDecimal.valueOf(stopNum[i]).divide(BigDecimal.valueOf(totalNum), 4, RoundingMode.HALF_UP).floatValue();
+            float percentTimes = BigDecimal.valueOf(stopTime[i]).divide(BigDecimal.valueOf(totalTime.get()), 4, RoundingMode.HALF_UP).floatValue();
+            cells[3].setCellValue(percentNum);
+            cells[3].setCellStyle(percentStyle);
+            cells[4].setCellValue(percentTimes);
+            cells[4].setCellStyle(percentStyle);
+        }
+        int[] pos = {0, 10, 5, 30};
+        int[] data = {2, 8, 3, 3};
+        int[] xdata = {2, 8, 0, 0};
+        drawBar(sheet, "停机次数占比", "停机原因", pos, xdata, data);
+        int[] pos1 = {6, 10, 16, 30};
+        int[] data1 = {2, 8, 4, 4};
+        drawBar(sheet, "停机时长占比", "停机原因", pos1, xdata, data1);
+
+        brokenYarn(wb, yarnStopList, stopTime[1], stopList.size());
+        yarn(wb, yarnStopList, dateStyle, timeStyle, p2);
+
+    }
+
+    public void top(XSSFWorkbook wb, LocalDate localDate) {
+        LocalDateTime sdt = LocalDateTime.of(localDate.minusDays(6), LocalTime.of(7, 0));
+        LocalDateTime edt = LocalDateTime.of(localDate.plusDays(1), LocalTime.of(6, 59, 59));
+        Date sTime = Date.from(sdt.atZone(ZoneId.systemDefault()).toInstant());
+        Date eTime = Date.from(edt.atZone(ZoneId.systemDefault()).toInstant());
+        List<TwinCalcStop> yarnStopList = stopService.selectTwinCalcStopListByDate(sTime, eTime, 2);
+
+        yarnStopList.forEach(stop -> {
+            if (stop.getHour() < 7) {
+                Date d = stop.getDataDate();
+                stop.setDataDate(DateUtils.addDays(d, -1));
+            }
+        });
+        Map<Long, Map<Date, Long>> weekData = yarnStopList.stream().collect(Collectors.groupingBy(TwinCalcStop::getDeviceId, Collectors.groupingBy(TwinCalcStop::getDataDate, Collectors.counting())));
+        List<Date> dateList = yarnStopList.stream().map(TwinCalcStop::getDataDate).distinct().sorted().collect(Collectors.toList());
+        Map<Long, Long> collect = yarnStopList.parallelStream().collect(Collectors.groupingBy(TwinCalcStop::getDeviceId, Collectors.counting()));
+        Map<Long, Long> sortedMap = collect.entrySet()
+                .stream()
+                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
+                .collect(Collectors.toMap(
+                        Map.Entry::getKey,
+                        Map.Entry::getValue,
+                        (e1, e2) -> e1,
+                        LinkedHashMap::new));
+        Map<Long, TwinDevice> deviceMap = deviceService.deviceMap();
+        XSSFSheet sheet = wb.getSheetAt(3);
+        Cell cell = sheet.getRow(0).getCell(0);
+        for (int i = 0; i < dateList.size(); i++) {
+            Cell dateCell = sheet.getRow(1).getCell(i + 2);
+            dateCell.setCellValue(dateList.get(i));
+        }
+
+        String title = "断纱停机周TOP排名\n(" + DateUtils.parseTimeToStr(sdt) + "至" + DateUtils.parseTimeToStr(edt) + ")";
+        cell.setCellValue(title);
+        int rn = 2;
+        for (Map.Entry<Long, Long> entry : sortedMap.entrySet()) {
+            Long deviceId = entry.getKey();
+            Row r1 = sheet.createRow(rn);
+            Cell[] cells = new Cell[9];
+            for (int j = 0; j < cells.length; j++) {
+                cells[j] = r1.createCell(j);
+            }
+            cells[0].setCellValue(deviceMap.get(deviceId).getDeviceName());
+            cells[1].setCellValue(entry.getValue());
+            Map<Date, Long> xx = weekData.get(deviceId);
+            for (int i = 0; i < dateList.size(); i++) {
+                Long v = xx.get(dateList.get(i));
+                if (v == null) {
+                    v = 0L;
+                }
+                cells[i + 2].setCellValue(v);
+            }
+            rn++;
+        }
+
+        int[] pos = {10, 2, 16, rn};
+        int[] data = {2, rn, 1, 1};
+        int[] xdata = {2, rn, 0, 0};
+        drawBar(sheet, "断纱停机周TOP", "设备名称", pos, xdata, data);
+        drawTopLine(sheet, rn);
+    }
+
+    private void drawTopLine(XSSFSheet sheet, int endRn) {
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+        // 2 左侧距离单元格个数, 4 顶部距离单元格个数, 7 左侧距离单元格个数, 26 顶部距离单元格个数
+        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, endRn + 1, 15, endRn + 26);
+        XSSFChart chart = drawing.createChart(anchor);
+        // 图表标题
+        chart.setTitleText("断纱停机趋势");
+        // 图例是否覆盖标题
+        chart.setTitleOverlay(false);
+        XDDFChartLegend legend = chart.getOrAddLegend();
+        // 图例位置:上下左右
+        legend.setPosition(LegendPosition.BOTTOM);
+        // 创建x轴
+        XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.LEFT);
+        // X轴标题
+        bottomAxis.setTitle("日期");
+        // y轴标题
+        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+        leftAxis.setTitle("单位:次");
+        // y轴数据
+        // 分类轴标(X轴)数据,单元格范围位置[0, 0]到[0, 6]
+        XDDFDataSource<String> xData = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(1, 1, 2, 8));
+        // 创建y轴
+        XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
+        for (int i = 2; i < endRn; i++) {
+            // 创建y轴
+            XDDFNumericalDataSource<Double> yData = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(i, i, 2, 8));
+            XDDFLineChartData.Series series = (XDDFLineChartData.Series) data.addSeries(xData, yData);
+            // 图例标题
+            series.setTitle(sheet.getRow(i).getCell(0).getStringCellValue(), null);
+            // 线条样式:true平滑曲线,false折线
+            series.setSmooth(true);
+            // 点的样式
+//            series.setMarkerStyle(MarkerStyle.CIRCLE);
+        }
+        chart.plot(data);
+    }
+
+    private void drawLine(XSSFSheet sheet, List<TwinCalcDay> dayList) {
+        Map<Date, List<TwinCalcDay>> dayGroup = dayList.stream().collect(Collectors.groupingBy(TwinCalcDay::getTime, LinkedHashMap::new, Collectors.toList()));
+        List<TwinCalcDay> jdl = new ArrayList<>();
+        for (Map.Entry<Date, List<TwinCalcDay>> entry : dayGroup.entrySet()) {
+            TwinCalcDay day = new TwinCalcDay(entry.getKey());
+            List<TwinCalcDay> days = entry.getValue();
+            day.calcDays(days);
+            jdl.add(day);
+        }
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+        // 2 左侧距离单元格个数, 4 顶部距离单元格个数, 7 左侧距离单元格个数, 26 顶部距离单元格个数
+        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 7, 12, 25);
+        XSSFChart chart = drawing.createChart(anchor);
+        // 图表标题
+        chart.setTitleText("稼动率周曲线");
+        // 图例是否覆盖标题
+        chart.setTitleOverlay(false);
+        XDDFChartLegend legend = chart.getOrAddLegend();
+        // 图例位置:上下左右
+        legend.setPosition(LegendPosition.TOP);
+        // 创建x轴
+        XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+        // X轴标题
+        bottomAxis.setTitle("日期");
+        // y轴标题
+        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+        leftAxis.setTitle("单位:%");
+
+//            // y轴数据
+        List<String> xtd = new ArrayList<>();
+        List<Double> tef = new ArrayList<>();
+        List<Double> aef = new ArrayList<>();
+        List<Double> bef = new ArrayList<>();
+        jdl.forEach(day -> {
+            aef.add(day.getEfficiencyA().multiply(BigDecimal.valueOf(100)).doubleValue());
+            bef.add(day.getEfficiencyB().multiply(BigDecimal.valueOf(100)).doubleValue());
+            tef.add(day.getEfficiency().multiply(BigDecimal.valueOf(100)).doubleValue());
+            xtd.add(DateUtils.parseDateToStr("MM-dd", day.getTime()));
+        });
+        XDDFDataSource<String> xdate = XDDFDataSourcesFactory.fromArray(xtd.toArray(new String[0]));
+        XDDFNumericalDataSource<Double> tt = XDDFDataSourcesFactory.fromArray(tef.toArray(new Double[0]));
+        XDDFNumericalDataSource<Double> aa = XDDFDataSourcesFactory.fromArray(aef.toArray(new Double[0]));
+        XDDFNumericalDataSource<Double> bb = XDDFDataSourcesFactory.fromArray(bef.toArray(new Double[0]));
+        // 创建y轴
+        XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
+        XDDFLineChartData.Series series = (XDDFLineChartData.Series) data.addSeries(xdate, tt);
+        // 图例标题
+        series.setTitle("总稼动率", null);
+        // 线条样式:true平滑曲线,false折线
+        series.setSmooth(true);
+        // 点的样式
+        series.setMarkerStyle(MarkerStyle.CIRCLE);
+
+        XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xdate, aa);
+        series1.setTitle("A班稼动率", null);
+        series1.setSmooth(true);
+        series1.setMarkerStyle(MarkerStyle.CIRCLE);
+        XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xdate, bb);
+        series2.setTitle("B班稼动率", null);
+        series2.setSmooth(true);
+        series2.setMarkerStyle(MarkerStyle.CIRCLE);
+        chart.plot(data);
+    }
+
+    private void drawBar(XSSFSheet sheet, String title, String xTitle, int[] pos, int[] xdata, int[] data) {
+        // 创建一个画布
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+        // 前四个默认0,[0,5]:从0列5行开始;[7,26]:到7列26行结束
+        // 默认宽度(14-8)*12
+        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, pos[0], pos[1], pos[2], pos[3]);
+        // 创建一个chart对象
+        XSSFChart chart = drawing.createChart(anchor);
+        // 标题
+        chart.setTitleText(title);
+        // 标题覆盖
+        chart.setTitleOverlay(false);
+
+        // 图例位置
+//        XDDFChartLegend legend = chart.getOrAddLegend();
+//        legend.setPosition(LegendPosition.TOP);
+
+        // 分类轴标(X轴),标题位置
+        XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+        bottomAxis.setTitle(xTitle);
+        // 值(Y轴)轴,标题位置
+        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+//        leftAxis.setTitle("停机次数占比");
+
+        // CellRangeAddress(起始行号,终止行号, 起始列号,终止列号)
+        // 分类轴标(X轴)数据,单元格范围位置[0, 0]到[0, 6]
+        XDDFDataSource<String> countries = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(xdata[0], xdata[1], xdata[2], xdata[3]));
+        // XDDFCategoryDataSource countries = XDDFDataSourcesFactory.fromArray(new String[] {"俄罗斯","加拿大","美国","中国","巴西","澳大利亚","印度"});
+        // 数据1,单元格范围位置[1, 0]到[1, 6]
+        XDDFNumericalDataSource<Double> area = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(data[0], data[1], data[2], data[3]));
+        // XDDFNumericalDataSource<Integer> area = XDDFDataSourcesFactory.fromArray(new Integer[] {17098242,9984670,9826675,9596961,8514877,7741220,3287263});
+
+        // bar:条形图,
+        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+
+        leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
+        // 设置为可变颜色
+        bar.setVaryColors(true);// 如果需要设置成自己想要的颜色,这里可变颜色要设置成false
+        // 条形图方向,纵向/横向:纵向
+        bar.setBarDirection(BarDirection.BAR);
+
+        // 图表加载数据,条形图1
+        XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(countries, area);
+//        // 条形图例标题
+        series1.setTitle("百分比", null);
+//			XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.RED));
+//			// 条形图,填充颜色
+//			series1.setFillProperties(fill);
+
+        // 绘制
+        chart.plot(bar);
+    }
+
+    public void brokenYarn(XSSFWorkbook wb, List<TwinCalcStop> yarnStopList, long time, int size) {
+        //3.断纱分析
+        Sheet sheet = wb.getSheetAt(2);
+        int yst = yarnStopList.size();
+        Cell cell = sheet.getRow(1).getCell(1);
+        cell.setCellValue(yst);
+        Map<Long, List<TwinCalcStop>> deviceGroup = yarnStopList.stream().collect(Collectors.groupingBy(TwinCalcStop::getDeviceId, LinkedHashMap::new, Collectors.toList()));
+        cell = sheet.getRow(2).getCell(1);
+        cell.setCellValue(deviceGroup.size());
+        float bl = 0f;
+        long aavg = 0;
+        if (yst > 0) {
+            bl = BigDecimal.valueOf(yst).divide(BigDecimal.valueOf(size), 4, RoundingMode.HALF_UP).floatValue();
+            aavg = time / yst;
+        }
+        cell = sheet.getRow(3).getCell(1);
+        cell.setCellValue(bl);
+
+        cell = sheet.getRow(4).getCell(1);
+        cell.setCellValue(Tools.convertHMS(time));
+        cell = sheet.getRow(5).getCell(1);
+        cell.setCellValue(Tools.convertHMS(aavg));
+    }
+
+    public void yarn(XSSFWorkbook wb, List<TwinCalcStop> yarnStopList, CellStyle dateStyle, CellStyle timeStyle, CellStyle p2) {
+        Map<Long, TwinDevice> deviceMap = deviceService.deviceMap();
+        //5.并发断纱分析
+        Sheet sheet = wb.getSheetAt(4);
+        int rowNum = 2;
+        int rn = 2;
+        yarnStopList.sort(Comparator.comparing(TwinCalcStop::getDataDate).thenComparing(TwinCalcStop::getHour));
+        Map<Date, Map<Integer, List<TwinCalcStop>>> stopHourGroup = yarnStopList.stream().collect(
+                Collectors.groupingBy(TwinCalcStop::getDataDate, LinkedHashMap::new,
+                        Collectors.groupingBy(TwinCalcStop::getHour, LinkedHashMap::new, Collectors.toList())));
+        for (Map.Entry<Date, Map<Integer, List<TwinCalcStop>>> entry : stopHourGroup.entrySet()) {
+            Map<Integer, List<TwinCalcStop>> map = entry.getValue();
+            for (Map.Entry<Integer, List<TwinCalcStop>> entry1 : map.entrySet()) {
+                List<TwinCalcStop> stops = entry1.getValue();
+                Row row = sheet.createRow(rowNum);
+                Cell[] cells = new Cell[7];
+                for (int j = 0; j < cells.length; j++) {
+                    cells[j] = row.createCell(j);
+                }
+                cells[0].setCellValue(entry.getKey());
+                cells[0].setCellStyle(dateStyle);
+                cells[1].setCellValue(entry1.getKey());
+                Map<Long, List<TwinCalcStop>> yarnDeviceGroup = stops.stream().collect(Collectors.groupingBy(TwinCalcStop::getDeviceId, LinkedHashMap::new, Collectors.toList()));
+                cells[2].setCellValue(yarnDeviceGroup.size());
+                int num = stops.size();
+                cells[3].setCellValue(num);
+                //0.最小,1.最大,2.总时间
+                final long[] time = {999999L, 0, 0};
+                //6.设备断纱停机详情
+                Sheet sheet6 = wb.getSheetAt(5);
+                for (TwinCalcStop stop : stops) {
+                    long t = (stop.getEndTime().getTime() - stop.getStartTime().getTime()) / 1000;
+                    if (t < time[0]) {
+                        time[0] = t;
+                    }
+                    if (t > time[1]) {
+                        time[1] = t;
+                    }
+                    time[2] += t;
+
+                    Row r1 = sheet6.createRow(rn);
+                    Cell[] cs = new Cell[6];
+                    for (int j = 0; j < cs.length; j++) {
+                        cs[j] = r1.createCell(j);
+                    }
+                    cs[0].setCellValue(stop.getDataDate());
+                    cs[0].setCellStyle(dateStyle);
+                    cs[1].setCellValue(stop.getHour());
+                    cs[2].setCellValue(deviceMap.get(stop.getDeviceId()).getDeviceName());
+                    cs[3].setCellValue(stopStr[stop.getStopType() - 1]);
+                    cs[4].setCellValue(stop.getStartTime());
+                    cs[4].setCellStyle(timeStyle);
+                    cs[5].setCellValue(stop.getEndTime());
+                    cs[5].setCellStyle(timeStyle);
+                    rn++;
+                }
+
+                cells[4].setCellValue(time[1]);
+                cells[5].setCellValue(time[0]);
+                float avg = BigDecimal.valueOf(time[2]).divide(BigDecimal.valueOf(num), 2, RoundingMode.HALF_UP).floatValue();
+                cells[6].setCellValue(avg);
+                cells[6].setCellStyle(p2);
+                rowNum++;
+            }
+        }
+    }
+}

+ 5 - 4
ruoyi-admin/src/test/java/com/jjt/DeviceTest.java

@@ -18,7 +18,7 @@ import javax.annotation.Resource;
  * @date 2024/5/7 11:49
  */
 @SpringBootTest(classes = RuoYiApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@ActiveProfiles("prod")
+@ActiveProfiles("druid")
 public class DeviceTest {
     @Resource
     private JdbcTemplate jdbcTemplate;
@@ -33,9 +33,9 @@ public class DeviceTest {
         String sql = "update TWIN_DEVICE set online=? where device_code=?";
         for (int i = 1; i <= 140; i++) {
             if (get(i)) {
-                jdbcTemplate.update(sql,1,"C_"+i);
-            }else{
-                jdbcTemplate.update(sql,0,"C_"+i);
+                jdbcTemplate.update(sql, 1, "C_" + i);
+            } else {
+                jdbcTemplate.update(sql, 0, "C_" + i);
             }
         }
     }
@@ -46,6 +46,7 @@ public class DeviceTest {
         iotService.query(sql);
         JSONObject jsonObject = iotService.query(sql);
         JSONObject data = jsonObject.getJSONObject("data");
+        System.err.println(sql + data.toJSONString(1));
         JSONArray values = data.getJSONArray("values");
         JSONArray timestamps = data.getJSONArray("timestamps");
         if (values.size() == 0) {

Разлика између датотеке није приказан због своје велике величине
+ 9 - 9
ruoyi-admin/src/test/java/com/jjt/LastProcess.java


Неке датотеке нису приказане због велике количине промена