package com.qianwen.smartman.modules.workinghour.service; import java.awt.Color; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.text.NumberFormat; import java.time.Duration; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartUtils; import org.jfree.chart.JFreeChart; import org.jfree.chart.StandardChartTheme; import org.jfree.chart.block.BlockBorder; import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator; import org.jfree.chart.labels.CategoryItemLabelGenerator; import org.jfree.chart.labels.ItemLabelAnchor; import org.jfree.chart.labels.ItemLabelPosition; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.StackedBarRenderer; import org.jfree.chart.ui.RectangleEdge; import org.jfree.chart.ui.RectangleInsets; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.qianwen.core.excel.util.ExcelUtil; import com.qianwen.core.mp.base.BaseServiceImpl; import com.qianwen.core.oss.model.BladeFile; import com.qianwen.core.tool.utils.DateUtil; import com.qianwen.smartman.common.enums.DefaultWcsEnum; import com.qianwen.smartman.common.utils.DurationUtil; import com.qianwen.smartman.modules.resource.builder.oss.OssBuilder; import com.qianwen.smartman.modules.smis.entity.Workstation; import com.qianwen.smartman.modules.smis.mapper.WorkstationMapper; import com.qianwen.smartman.modules.workinghour.entity.PartWorkingHour; import com.qianwen.smartman.modules.workinghour.entity.PartWorkingProcess; import com.qianwen.smartman.modules.workinghour.excel.PartWorkingHourExcel; import com.qianwen.smartman.modules.workinghour.mapper.PartWorkingHourMapper; import com.qianwen.smartman.modules.workinghour.mapper.PartWorkingProcessMapper; import cn.hutool.core.date.LocalDateTimeUtil; @Service public class PartWorkingHourExportService extends BaseServiceImpl { @Autowired private PartWorkingHourMapper partWorkingHourMapper; @Autowired private WorkstationMapper workstationMapper; @Autowired private PartWorkingProcessMapper partWorkingProcessMapper; @Autowired private OssBuilder ossBuilder; /** * 导出一条数据 * * @param id * @return * @throws IOException */ @Transactional(readOnly = true) public BladeFile export(long id) throws Exception { // QueryWrapper wrapper = new QueryWrapper<>(); // wrapper.lambda().eq(PartWorkingProcess::getWorkinghourId, id); // xx工件在x机床 PartWorkingHour partWorkingHour = partWorkingHourMapper.selectById(id); Workstation ws = workstationMapper.selectById(partWorkingHour.getWorkstationId()); String fileName = String.format("零件%s的工时数据-%s.xlsx", partWorkingHour.getPartNo(), DateUtil.time()); PartWorkingHourExcel excelObj = new PartWorkingHourExcel(); excelObj.setPartNo(partWorkingHour.getPartNo()); excelObj.setAmount(partWorkingHour.getAmount()); LocalDateTime start = LocalDateTime.now(); LocalDateTime end; Duration duration; if (partWorkingHour.getClampingSecs() != null) { end = start.plusSeconds(partWorkingHour.getClampingSecs()); duration = Duration.between(start, end); excelObj.setClampingSecs(DurationUtil.toChineseDuration(duration)); } final String format = "yyyy-MM-dd:hh:mm:ss"; if (partWorkingHour.getEndTime() != null) { excelObj.setEndTime(LocalDateTimeUtil.format(partWorkingHour.getEndTime(), format)); } if (partWorkingHour.getFirstMeasureSecs() != null) { end = start.plusSeconds(partWorkingHour.getFirstMeasureSecs()); duration = Duration.between(start, end); excelObj.setFirstMeasureSecs(DurationUtil.toChineseDuration(duration)); } if (partWorkingHour.getFirstWorkingSecs() != null) { end = start.plusSeconds(partWorkingHour.getFirstWorkingSecs()); duration = Duration.between(start, end); excelObj.setFirstWorkingSecs(DurationUtil.toChineseDuration(duration)); } if (partWorkingHour.getLastRemoveSecs() != null) { end = start.plusSeconds(partWorkingHour.getLastRemoveSecs()); duration = Duration.between(start, end); excelObj.setLastRemoveSecs(DurationUtil.toChineseDuration(duration)); } if (partWorkingHour.getOccupancySecs() != null) { end = start.plusSeconds(partWorkingHour.getOccupancySecs()); duration = Duration.between(start, end); excelObj.setOccupancySecs(DurationUtil.toChineseDuration(duration)); } excelObj.setPartNo(partWorkingHour.getPartNo()); if (partWorkingHour.getPrepareSecs() != null) { end = start.plusSeconds(partWorkingHour.getPrepareSecs()); duration = Duration.between(start, end); excelObj.setPrepareSecs(DurationUtil.toChineseDuration(duration)); } if (partWorkingHour.getProcessingSecs() != null) { end = start.plusSeconds(partWorkingHour.getProcessingSecs()); duration = Duration.between(start, end); excelObj.setProcessingSecs(DurationUtil.toChineseDuration(duration)); } excelObj.setProcessNo(partWorkingHour.getProcessNo()); if (partWorkingHour.getSingleProcessSecs() != null) { end = start.plusSeconds(partWorkingHour.getSingleProcessSecs()); duration = Duration.between(start, end); excelObj.setSingleProcessSecs(DurationUtil.toChineseDuration(duration)); } excelObj.setStartTime(LocalDateTimeUtil.format(partWorkingHour.getStartTime(), format)); excelObj.setWorkstationName(ws.getName()); excelObj.setVersion(partWorkingHour.getVersion()); MultipartFile multipartFile = ExcelUtil.exportToMultipartFile(fileName, "零件工时", Arrays.asList(excelObj), PartWorkingHourExcel.class); MultipartFile multipartFile2 = writeChart(id,multipartFile); BladeFile bladeFile = this.ossBuilder.tempTemplate().putFile(multipartFile2.getOriginalFilename(), multipartFile2); return bladeFile; } /** * 创建图表 * @param workinghourId * @param multipartFile * @return * @throws Exception */ MultipartFile writeChart(long workinghourId,MultipartFile multipartFile) throws Exception { XSSFWorkbook workbook = new XSSFWorkbook(multipartFile.getInputStream()); byte[] chartBytes = barChart(workinghourId); addPicture(workbook, chartBytes); DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setRepository(new File(System.getProperty("java.io.tmpdir"))); FileItem fileItem = factory.createItem("excel", multipartFile.getContentType(), true, multipartFile.getOriginalFilename()); workbook.write(fileItem.getOutputStream()); workbook.close(); return new CommonsMultipartFile(fileItem); } public static void addPicture(XSSFWorkbook wb, byte[] bytes) { XSSFSheet sheet = wb.getSheetAt(0); // 画图的顶级管理器,一个sheet只能获取一个(一定要注意这点) // HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); XSSFDrawing patriarch = sheet.createDrawingPatriarch(); // 设置图片位置 // 八个参数, 前四个表示图片离起始单元格和结束单元格边缘的位置, // 后四个表示起始和结束单元格的位置, 如下表示从第2列到第12列, 从第1行到第15行,需要注意excel起始位置是0 // {0,0,0,0,2,1,12,15}表示从第2列到第12列,从第1行到第15行,单元格内部的边距都是0 // {0,0,0,0,1,4,20,5}表示从第2列到第12列,从第1行到第15行,单元格内部的边距都是0 // HSSFClientAnchor anchor = new HSSFClientAnchor(anchors[0], anchors[1], // anchors[2], anchors[3], (short) anchors[4], anchors[5], (short) anchors[6], // anchors[7]); XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 0, 3, 30, 10); // 1列-30列;3行-10行 anchor.setAnchorType(AnchorType.DONT_MOVE_AND_RESIZE); // 插入图片 int pictureIndex = wb.addPicture(bytes, XSSFWorkbook.PICTURE_TYPE_JPEG); // XSSFWorkbook.PICTURE_TYPE_JPEG patriarch.createPicture(anchor, pictureIndex); } public byte[] barChart(long workinghourId) throws Exception { // 设置柱子显示对应的数值 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(PartWorkingProcess::getWorkinghourId, workinghourId).orderByAsc(PartWorkingProcess::getStartTime); List processList = partWorkingProcessMapper.selectList(wrapper); // 支持标签显示的所有列数据 List> dataList = new ArrayList<>(); Duration duration; PartWorkingProcess process; for(int i=0;i(Arrays.asList(133))); process = processList.get(i); duration = Duration.between(process.getStartTime(), process.getEndTime()); dataList.add(Arrays.asList(duration.getSeconds())); //dataTable.add(new ArrayList<>(Arrays.asList(process.getProgName(), duration.getSeconds(), process.getDeviceStatus()))); } JFreeChart chart = createStackedBarChart(workinghourId,"加工记录", dataList,processList, JFreeChartUtil.createChartTheme("宋体"), "秒", ""); StackedBarRenderer renderer = new StackedBarRenderer(); CategoryPlot plot = chart.getCategoryPlot(); plot.setOutlineVisible(true); //dataTable.add(new ArrayList<>(Arrays.asList("YZL4-1100-01-50-A-2-2", 242, "运行"))); renderer.setDefaultItemLabelsVisible(true); renderer.setDefaultItemLabelGenerator(new MyCategoryItemLabelGenerator(processList)); renderer.setMaximumBarWidth(0.3); // 柱子颜色,有几段就set几个 Color color; String colorStr; DefaultWcsEnum wcsEnum; for(int i=0;i> dataList,List processList, StandardChartTheme theme, String yAxisTitle, String xAxisTitle) throws Exception { // 设置主题,防止中文乱码 theme = theme == null ? JFreeChartUtil.createChartTheme("") : theme; ChartFactory.setChartTheme(theme); boolean showLegend =false; //List pnamelist = processList.stream().map(p -> p.getProgName()).collect(Collectors.toList()); //DefaultCategoryDataset dataset = JFreeChartUtil.createDefaultCategoryDataset(pnamelist, Arrays.asList("xname"), dataList); DefaultCategoryDataset dataset = createDataSet(processList); JFreeChart chart = ChartFactory.createStackedBarChart(chartTitle, xAxisTitle, yAxisTitle, dataset, PlotOrientation.HORIZONTAL, showLegend, true, false); // 设置抗锯齿,防止字体显示不清楚 chart.setTextAntiAlias(false); // 对柱子进行渲染 JFreeChartUtil.setBarRenderer(chart.getCategoryPlot(), true); //showLegend=false情况下,下列代码会引起NPE // 设置标注无边框 //chart.getLegend().setFrame(new BlockBorder(Color.WHITE)); // 标注位于上侧 //chart.getLegend().setPosition(RectangleEdge.TOP); return chart; } DefaultCategoryDataset createDataSet(List processList){ DefaultCategoryDataset dataset = new DefaultCategoryDataset(); PartWorkingProcess p; for (int xAxisIndex = 0; xAxisIndex < processList.size(); xAxisIndex++) { p = processList.get(xAxisIndex); //String value = rowList.get(xAxisIndex).toString(); String value =p.getStartTime().toString(); Duration duration = Duration.between(p.getStartTime(), p.getEndTime()); value = duration.getSeconds()+""; dataset.setValue(Double.parseDouble(value), xAxisIndex+"", "程序时段"); } return dataset; } } //自定义标签生成 class MyCategoryItemLabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator { // private final Integer category; private List dataTable; public MyCategoryItemLabelGenerator(List dataTable) { super("", NumberFormat.getInstance()); this.dataTable = dataTable; } @Override public String generateLabel(CategoryDataset dataset, int row, int column) { //Number val = dataset.getValue(row, column); PartWorkingProcess dataRow = this.dataTable.get(row); // dataset. /* ALARM(1, "报警"), RUNNING(2, "运行"), STANDBY(3, "待机"), OFFLINE(4, "离线"), DEBUGGING(5, "调试"); */ //DefaultWcsEnum wcsEnum = DefaultWcsEnum.of(dataRow.getDeviceStatus()); //return dataRow.getProgName() + ",:" + val + "," + wcsEnum.getName(); Duration duration = Duration.between(dataRow.getStartTime(), dataRow.getEndTime()); return dataRow.getProgName() + "," + DurationUtil.toChineseDuration(duration); } }