parent
f3e38ff394
commit
b5b8df9b8d
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
package ${basePackage}.frame.excel.exception;
|
||||
|
||||
/**
|
||||
* Excel文件读取失败异常
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class ReadErrorException extends Exception {
|
||||
public ReadErrorException() {
|
||||
}
|
||||
|
||||
public ReadErrorException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package ${basePackage}.frame.excel.exception;
|
||||
|
||||
/**
|
||||
* 值转换异常
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class ValueConverterException extends Exception {
|
||||
|
||||
public ValueConverterException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package ${basePackage}.frame.excel.handler;
|
||||
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.Head;
|
||||
import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class HeadWriteHandler extends AbstractCellWriteHandler {
|
||||
|
||||
@Override
|
||||
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
|
||||
super.afterCellDispose(writeSheetHolder, writeTableHolder, cellDataList, cell, head, relativeRowIndex, isHead);
|
||||
if (isHead) {
|
||||
handlerHead(head);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void handlerHead(Head head);
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package ${basePackage}.frame.excel.handler;
|
||||
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.Head;
|
||||
import com.alibaba.excel.write.handler.CellWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Drawing;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WCellWriteHandler implements CellWriteHandler {
|
||||
private CellStyle[] styles;
|
||||
|
||||
private Map<Integer, String> errMap;
|
||||
|
||||
public WCellWriteHandler(CellStyle[] styles, Map<Integer, String> errMap) {
|
||||
this.styles = styles;
|
||||
this.errMap = errMap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean isHead) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean isHead) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean isHead) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer rowIndex, Boolean isHead) {
|
||||
if (isHead) {
|
||||
// 创建批注
|
||||
Drawing<?> drawingPatriarch = writeSheetHolder.getSheet().createDrawingPatriarch();
|
||||
// for (int i = 0; i < wHeads.size(); i++) {
|
||||
// WHead wHead = wHeads.get(i);
|
||||
// if (wHead.getNote() != null && !"".equals(wHead.getNote())) {
|
||||
// // 创建一个批注
|
||||
// Comment comment = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) i, 0, (short) i + 1, 2));
|
||||
// // 输入批注信息
|
||||
// comment.setString(new XSSFRichTextString(wHead.getNote()));
|
||||
// // 将批注添加到标题对象中
|
||||
// writeSheetHolder.getSheet().getRow(0).getCell(i).setCellComment(comment);
|
||||
// }
|
||||
// }
|
||||
cell.setCellStyle(styles[0]);
|
||||
} else if (!"".equals(errMap.getOrDefault(rowIndex, ""))) {
|
||||
// cell.getCellStyle().setFillForegroundColor(IndexedColors.RED.getIndex());
|
||||
// cell.getCellStyle().setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
cell.setCellStyle(styles[1]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package ${basePackage}.frame.excel.handler;
|
||||
|
||||
import com.alibaba.excel.write.handler.RowWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class WRowWriteHandler implements RowWriteHandler {
|
||||
private int errColIndex;
|
||||
private Map<Integer, String> errMap;
|
||||
|
||||
public WRowWriteHandler(int errColIndex, Map<Integer, String> errMap) {
|
||||
this.errColIndex = errColIndex;
|
||||
this.errMap = errMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean isHead) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean isHead) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer rowIndex, Boolean isHead) {
|
||||
if (!isHead && !"".equals(errMap.getOrDefault(rowIndex, ""))) {
|
||||
Cell cell = row.createCell(errColIndex);
|
||||
cell.getCellStyle().setWrapText(true);
|
||||
cell.setCellValue(errMap.get(rowIndex));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package ${basePackage}.frame.excel.handler;
|
||||
|
||||
|
||||
import com.alibaba.excel.write.handler.SheetWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.DataValidation;
|
||||
import org.apache.poi.ss.usermodel.DataValidationConstraint;
|
||||
import org.apache.poi.ss.usermodel.DataValidationHelper;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import ${basePackage}.frame.excel.WHead;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WSheetWriteHandler implements SheetWriteHandler {
|
||||
private List<WHead> wHeads;
|
||||
private CellStyle[] styles;
|
||||
|
||||
public WSheetWriteHandler(List<WHead> wHeads, CellStyle[] styles) {
|
||||
this.wHeads = wHeads;
|
||||
this.styles = styles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
|
||||
{
|
||||
styles[1] = writeWorkbookHolder.getWorkbook().createCellStyle();
|
||||
styles[1].setFillForegroundColor(IndexedColors.RED.getIndex());
|
||||
styles[1].setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
}
|
||||
|
||||
{
|
||||
styles[0] = writeWorkbookHolder.getWorkbook().createCellStyle();
|
||||
styles[0].setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||
styles[0].setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
styles[0].setBorderBottom(BorderStyle.THIN);
|
||||
styles[0].setBorderLeft(BorderStyle.THIN);
|
||||
styles[0].setBorderRight(BorderStyle.THIN);
|
||||
styles[0].setBorderTop(BorderStyle.THIN);
|
||||
styles[0].setAlignment(HorizontalAlignment.CENTER);
|
||||
Font font = writeWorkbookHolder.getWorkbook().createFont();
|
||||
font.setColor(IndexedColors.BLACK.getIndex());
|
||||
font.setFontHeightInPoints((short) 12);
|
||||
font.setBold(true);
|
||||
styles[0].setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
|
||||
for (int i = 0; i < wHeads.size(); i++) {
|
||||
WHead col = wHeads.get(i);
|
||||
if (col.getSelectList() != null && col.getSelectList().length > 0) {
|
||||
CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(0, 500, i, i);
|
||||
DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();
|
||||
DataValidationConstraint constraint = helper.createExplicitListConstraint(col.getSelectList());
|
||||
DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
|
||||
writeSheetHolder.getSheet().addValidationData(dataValidation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package ${basePackage}.frame.excel.listener;
|
||||
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.event.AnalysisEventListener;
|
||||
import ${basePackage}.frame.excel.WHead;
|
||||
import ${basePackage}.frame.excel.exception.TemplateNotMatchException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class CheckHeadReadListener extends AnalysisEventListener {
|
||||
private List<WHead> wHeads;
|
||||
private TemplateNotMatchException[] es;
|
||||
|
||||
public CheckHeadReadListener(List<WHead> wHeads, TemplateNotMatchException[] es) {
|
||||
this.wHeads = wHeads;
|
||||
this.es = es;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeHeadMap(Map headMap, AnalysisContext context) {
|
||||
if (wHeads.size() != headMap.size()) {
|
||||
es[0] = new TemplateNotMatchException("文件列数量与模板不一致!");
|
||||
return;
|
||||
}
|
||||
es[0] = null;
|
||||
for (int i = 0; i < wHeads.size(); i++) {
|
||||
WHead wCol = wHeads.get(i);
|
||||
String cellValue = headMap.get(i).toString();
|
||||
if (!wCol.getName().equals(cellValue)) {
|
||||
es[0] = new TemplateNotMatchException(String.format("第 %d 列应为[ %s ]", i + 1, wCol.getName()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Object o, AnalysisContext analysisContext) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext(AnalysisContext context) {
|
||||
return es[0] != null;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package ${basePackage}.frame.excel.listener;
|
||||
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.event.AnalysisEventListener;
|
||||
|
||||
|
||||
public class HeadReadListener extends AnalysisEventListener {
|
||||
|
||||
@Override
|
||||
public void invoke(Object o, AnalysisContext analysisContext) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext(AnalysisContext context) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 基本单元格样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class BaseCellStyle {
|
||||
/**
|
||||
* 样式
|
||||
*/
|
||||
protected CellStyle style;
|
||||
|
||||
public BaseCellStyle(Workbook workbook) {
|
||||
style = workbook.createCellStyle();
|
||||
style.setFillPattern(CellStyle.NO_FILL);
|
||||
//下边框
|
||||
style.setBorderBottom(CellStyle.SOLID_FOREGROUND);
|
||||
//下边框颜色
|
||||
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
|
||||
//左边框
|
||||
style.setBorderLeft(CellStyle.SOLID_FOREGROUND);
|
||||
//左边框颜色
|
||||
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
|
||||
//右边框
|
||||
style.setBorderRight(CellStyle.SOLID_FOREGROUND);
|
||||
//右边框颜色
|
||||
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
|
||||
//上边框
|
||||
style.setBorderTop(CellStyle.SOLID_FOREGROUND);
|
||||
//上边框颜色
|
||||
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
|
||||
|
||||
style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //上下居中
|
||||
style.setBorderBottom(CellStyle.SOLID_FOREGROUND); //下边框
|
||||
style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); //下边框颜色
|
||||
style.setBorderLeft(CellStyle.SOLID_FOREGROUND); //左边框
|
||||
style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); //左边框颜色
|
||||
style.setBorderRight(CellStyle.SOLID_FOREGROUND); //右边框
|
||||
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); //右边框颜色
|
||||
style.setBorderTop(CellStyle.SOLID_FOREGROUND); //上边框
|
||||
style.setTopBorderColor(IndexedColors.BLACK.getIndex()); //上边框颜色
|
||||
}
|
||||
|
||||
public CellStyle getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
public void setStyle(CellStyle style) {
|
||||
this.style = style;
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 基本字体样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class BaseFont {
|
||||
/**
|
||||
* 字体
|
||||
*/
|
||||
protected Font font;
|
||||
|
||||
public BaseFont(Workbook workbook) {
|
||||
font = workbook.createFont();
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 数据单元格样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class DataCellStyle extends BaseCellStyle {
|
||||
|
||||
public DataCellStyle(Workbook workbook, short align, boolean error) {
|
||||
super(workbook);
|
||||
style.setAlignment(align);
|
||||
if (error) {
|
||||
style.setFillForegroundColor(HSSFColor.RED.index); //背景颜色红色
|
||||
style.setFillPattern(CellStyle.SOLID_FOREGROUND); //设置单元格填充样式
|
||||
}
|
||||
}
|
||||
|
||||
public DataCellStyle(Workbook workbook, short align) {
|
||||
this(workbook, align, false);
|
||||
}
|
||||
|
||||
public DataCellStyle(Workbook workbook, boolean error) {
|
||||
this(workbook, CellStyle.ALIGN_LEFT, error);
|
||||
}
|
||||
|
||||
public DataCellStyle(Workbook workbook) {
|
||||
this(workbook, CellStyle.ALIGN_LEFT, false);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 错误单元格样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class ErrorCellStyle extends BaseCellStyle {
|
||||
|
||||
public ErrorCellStyle(Workbook workbook) {
|
||||
super(workbook);
|
||||
style.setFillForegroundColor(HSSFColor.RED.index); //背景颜色红色
|
||||
style.setFillPattern(CellStyle.SOLID_FOREGROUND); //设置单元格填充样式
|
||||
}
|
||||
|
||||
public CellStyle getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
public void setStyle(CellStyle style) {
|
||||
this.style = style;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 表头单元格样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class HeadCellStyle extends BaseCellStyle {
|
||||
public HeadCellStyle(Workbook workbook) {
|
||||
super(workbook);
|
||||
style.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index); //背景颜色-灰色
|
||||
style.setFillPattern(CellStyle.SOLID_FOREGROUND); // 设置单元格填充样式
|
||||
style.setAlignment(CellStyle.ALIGN_CENTER); // 居中
|
||||
style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);//上下居中
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 一般字体样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class NormalFont extends BaseFont {
|
||||
public NormalFont(Workbook workbook) {
|
||||
super(workbook);
|
||||
font.setColor(HSSFColor.BLACK.index); //字体颜色-黑色
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 红色字体样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class RedFont extends BaseFont {
|
||||
public RedFont(Workbook workbook) {
|
||||
super(workbook);
|
||||
font.setColor(HSSFColor.RED.index);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package ${basePackage}.frame.excel.style;
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* 成功单元格样式
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 2017-01-01
|
||||
*/
|
||||
public class SuccessCellStyle extends BaseCellStyle {
|
||||
|
||||
public SuccessCellStyle(Workbook workbook) {
|
||||
super(workbook);
|
||||
style.setFillForegroundColor(HSSFColor.GREEN.index); //背景颜色红色
|
||||
style.setFillPattern(CellStyle.SOLID_FOREGROUND); //设置单元格填充样式
|
||||
}
|
||||
|
||||
public CellStyle getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
public void setStyle(CellStyle style) {
|
||||
this.style = style;
|
||||
}
|
||||
}
|
Loading…
Reference in new issue