Open 2259289435 opened 1 year ago
可以再讨论,如果是横向的话那表头也得转向吧,感觉这个需求只需要将数据二次处理即可,N:1指的是什么呢?
在 2022年11月14日,10:40,2259289435 @.***> 写道:
场景:使用 excel 打印,列头少情况下,经常采用数据合并,目的:一节省纸张,二数据量大
举例: 现在 excel 生成的格式为: 行一:跨列标题 行二:列1 列2 行三:数据1 数据1 行四:数据2 数据2
希望的格式为:两条数据合成一行 行一:跨列标题 行二:列1 列2 列1 列2 行三:数据1 数据1 数据2 数据2 行四:数据3 数据3 数据4 数据4 行五:数据5 数据5
现在通过编码去手动合并两行为一个对象显示可以实现,但底层还是数据与行 1 : 1,能否支持数据与行 N :1 ?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.
能将使用场景具体化吗?原始数据是什么,最终效果是怎样,可以截图一个具体excel文件
在 2022年11月14日,10:40,2259289435 @.***> 写道:
场景:使用 excel 打印,列头少情况下,经常采用数据合并,目的:一节省纸张,二数据量大
举例: 现在 excel 生成的格式为: 行一:跨列标题 行二:列1 列2 行三:数据1 数据1 行四:数据2 数据2
希望的格式为:两条数据合成一行 行一:跨列标题 行二:列1 列2 列1 列2 行三:数据1 数据1 数据2 数据2 行四:数据3 数据3 数据4 数据4 行五:数据5 数据5
现在通过编码去手动合并两行为一个对象显示可以实现,但底层还是数据与行 1 : 1,能否支持数据与行 N :1 ?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.
数据: 1 | 南瓜 | 11 2 | 冬瓜 | 12 3 | 西瓜 | 10 4 | 北瓜 | 12 ...
最终效果
数据与行 N : 1,比如上图就是数据与行 3 : 1,好处就是作业人员使用的时候可以一张纸看到尽可能多的数据,并且节省纸张。
现在确实可以通用listmap业务自行二次封装处理,但这种场景是比较通用的一种业务需求,所以想了解能否把这种数据与行自定义对应的能力封装到框架内。
感谢反馈,已了解使用场景,考虑添加扩展属性或注解以支持新特性
临时的你可以使用如下自定义WorksheetWriter实现该功能,原理很简单首先是表头需要特殊处理,将原来的表头复制n次,其次写行数据的时候判断是否需要写行头和行尾。需要注意写出时取消原有的斑马线,如果要实现斑马线需要使用setStyleProcessor()
方法添加一个样式处理器(取模判断是否在一行上即可)
/**
* 自定义平铺WorksheetWriter
*/
public static class TileXMLWorksheetWriter extends XMLWorksheetWriter {
private int tile; // 平铺的数量,也就是每行重复输出多少条数据
private String date; // 可忽略,仅仅是表头上的日期
public TileXMLWorksheetWriter(int tile) {
this.tile = tile;
}
public TileXMLWorksheetWriter(int tile, String date) {
this.tile = tile;
this.date = date;
}
public int getTile() {
return tile;
}
public void setTile(int tile) {
this.tile = tile;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
@Override
protected void writeBefore() throws IOException {
// The header columns
columns = sheet.getAndSortHeaderColumns();
// Give new columns
tileColumns();
boolean nonHeader = sheet.getNonHeader() == 1;
bw.write(Const.EXCEL_XML_DECLARATION);
// Declaration
bw.newLine();
// Root node
writeRootNode();
// Dimension
writeDimension();
// SheetViews default value
writeSheetViews();
// Default row height and width
int fillSpace = 6;
BigDecimal width = BigDecimal.valueOf(!nonHeader ? sheet.getDefaultWidth() : 8.38D);
String defaultWidth = width.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
writeSheetFormat(fillSpace, defaultWidth);
// cols
writeCols(fillSpace, defaultWidth);
// Write body data
beforeSheetDate(nonHeader);
}
protected void tileColumns() {
if (tile == 1) return;
int x = columns.length, y = x * tile, t = columns[columns.length - 1].getRealColIndex();
// Bound check
if (y > Const.Limit.MAX_COLUMNS_ON_SHEET)
throw new TooManyColumnsException(y, Const.Limit.MAX_COLUMNS_ON_SHEET);
Column[] _columns = new Column[y];
for (int i = 0; i < y; i++) {
// 第一个对象的表头不需要复制
Column col = i < x ? columns[i] : new Column(columns[i % x]).addSubColumn(new Column());
col.realColIndex = columns[i % x].realColIndex + t * (i / x);
_columns[i] = col;
// 替换拣货单上的日期
Column _col = col;
do {
if (StringUtil.isNotEmpty(_col.getName()) && _col.getName().contains("{date}"))
_col.setName(_col.getName().replace("{date}", date));
}
while ((_col = _col.next) != null);
}
this.columns = _columns;
// FIXME 这里强行指定合并替换掉原本的头
List<Dimension> mergeCells = Collections.singletonList(new Dimension(1, (short) 1, 1, (short) y));
sheet.putExtProp(Const.ExtendPropertyKey.MERGE_CELLS, mergeCells);
}
@Override
protected void writeRow(Row row) throws IOException {
Cell[] cells = row.getCells();
int len = cells.length, r = row.getIndex() / tile + startRow, c = columns[columns.length - 1].realColIndex / tile, y = row.getIndex() % tile;
if (y == 0) startRow(r - startRow, columns[columns.length - 1].realColIndex);
for (int i = 0; i < len; i++) {
Cell cell = cells[i];
int xf = cell.xf, col = i + c * y;
switch (cell.t) {
case INLINESTR:
case SST:
writeString(cell.sv, r, col, xf);
break;
case NUMERIC:
writeNumeric(cell.nv, r, col, xf);
break;
case LONG:
writeNumeric(cell.lv, r, col, xf);
break;
case DATE:
case DATETIME:
case DOUBLE:
case TIME:
writeDouble(cell.dv, r, col, xf);
break;
case BOOL:
writeBool(cell.bv, r, col, xf);
break;
case DECIMAL:
writeDecimal(cell.mv, r, col, xf);
break;
case CHARACTER:
writeChar(cell.cv, r, col, xf);
break;
case BLANK:
writeNull(r, col, xf);
break;
default:
}
}
// 注意这里可能不会关闭row需要在writeAfter进行二次处理
if (y == tile - 1)
bw.write("</row>");
}
@Override
protected void writeRowAutoSize(Row row) throws IOException {
Cell[] cells = row.getCells();
int len = cells.length, r = row.getIndex() / tile + startRow, c = columns[columns.length - 1].realColIndex / tile, y = row.getIndex() % tile;
if (y == 0) startRow(r - startRow, columns[columns.length - 1].realColIndex);
for (int i = 0; i < len; i++) {
Cell cell = cells[i];
int xf = cell.xf, col = i + c * y;
switch (cell.t) {
case INLINESTR:
case SST:
writeStringAutoSize(cell.sv, r, col, xf);
break;
case NUMERIC:
writeNumericAutoSize(cell.nv, r, col, xf);
break;
case LONG:
writeNumericAutoSize(cell.lv, r, col, xf);
break;
case DATE:
case DATETIME:
case DOUBLE:
case TIME:
writeDoubleAutoSize(cell.dv, r, col, xf);
break;
case BOOL:
writeBool(cell.bv, r, col, xf);
break;
case DECIMAL:
writeDecimalAutoSize(cell.mv, r, col, xf);
break;
case CHARACTER:
writeChar(cell.cv, r, col, xf);
break;
case BLANK:
writeNull(r, col, xf);
break;
default:
}
}
// 注意这里可能不会关闭row需要在writeAfter进行二次处理
if (y == tile - 1)
bw.write("</row>");
}
@Override
protected void writeAfter(int total) throws IOException {
if (total > 0 && (total - 1) % tile < tile - 1) bw.write("</row>");
super.writeAfter(total);
}
}
测试代码
@Test public void tileWriter() throws IOException {
List<TileEntity> data = TileEntity.randomTestData();
new Workbook().cancelOddFill().addSheet(new ListSheet<>(data).setSheetWriter(new TileXMLWorksheetWriter(3, LocalDate.now().toString()))).writeTo(defaultTestPath);
}
测试对象
public static class TileEntity {
@ExcelColumn("{date} 拣货单")
@ExcelColumn(value = "差异", maxWidth = 8.6D)
private String diff;
@ExcelColumn("{date} 拣货单")
@ExcelColumn(value = "序号", maxWidth = 6.8D)
private Integer no;
@ExcelColumn("{date} 拣货单")
@ExcelColumn(value = "商品", maxWidth = 12.0D)
private String product;
@ExcelColumn("{date} 拣货单")
@ExcelColumn(value = "数量", maxWidth = 6.8D)
private Integer num;
public static List<TileEntity> randomTestData() {
int n = random.nextInt(30) + 10;
List<TileEntity> list = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
TileEntity e = new TileEntity();
e.no = i + 1;
e.product = getRandomString(10);
e.num = random.nextInt(20) + 1;
list.add(e);
}
return list;
}
}
场景:使用 excel 打印,列头少情况下,经常采用数据合并,目的:一节省纸张,二数据量大
举例: 现在 excel 生成的格式为: 行一:跨列标题 行二:列1 列2 行三:数据1 数据1 行四:数据2 数据2
希望的格式为:两条数据合成一行 行一:跨列标题 行二:列1 列2 列1 列2 行三:数据1 数据1 数据2 数据2 行四:数据3 数据3 数据4 数据4 行五:数据5 数据5
现在通过编码去手动合并两行为一个对象显示可以实现,但底层还是数据与行 1 : 1,能否支持数据与行 N :1 ?