fixed(级联下拉框数据错误)

1.修复过多级联下拉选项导致的无法写入问题
This commit is contained in:
Emil.Zhang 2024-11-06 15:01:38 +08:00
parent 80e6943d2e
commit 0385a444c2
2 changed files with 98 additions and 58 deletions

View File

@ -55,6 +55,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
* 下拉可选项 * 下拉可选项
*/ */
private final List<DropDownOptions> dropDownOptions; private final List<DropDownOptions> dropDownOptions;
private final DictService dictService;
/** /**
* 当前单选进度 * 当前单选进度
*/ */
@ -63,7 +64,6 @@ public class ExcelDownHandler implements SheetWriteHandler {
* 当前联动选择进度 * 当前联动选择进度
*/ */
private int currentLinkedOptionsSheetIndex; private int currentLinkedOptionsSheetIndex;
private final DictService dictService;
public ExcelDownHandler(List<DropDownOptions> options) { public ExcelDownHandler(List<DropDownOptions> options) {
this.dropDownOptions = options; this.dropDownOptions = options;
@ -139,8 +139,8 @@ public class ExcelDownHandler implements SheetWriteHandler {
} else if (everyOptions.getOptions().size() > 10) { } else if (everyOptions.getOptions().size() > 10) {
// 当一级选项参数个数大于10使用额外表的形式 // 当一级选项参数个数大于10使用额外表的形式
dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions()); dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions());
} else if (everyOptions.getOptions().size() != 0) { } else {
// 当一级选项个数不为空使用默认形式 // 否则使用默认形式
dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions()); dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions());
} }
}); });
@ -171,10 +171,24 @@ public class ExcelDownHandler implements SheetWriteHandler {
Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName)); Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName));
// 将下拉表隐藏 // 将下拉表隐藏
workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true); workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true);
// 完善横向的一级选项数据 // 选项数据
List<String> firstOptions = options.getOptions(); List<String> firstOptions = options.getOptions();
Map<String, List<String>> secoundOptionsMap = options.getNextOptions(); Map<String, List<String>> secoundOptionsMap = options.getNextOptions();
// 采用按行填充数据的方式避免EasyExcel出现数据无法写入的问题
// Attempting to write a row in the range that is already written to disk
// 使用ArrayList记载数据防止乱序
List<String> columnNames = new ArrayList<>();
// 写入第一行即第一级的数据
Row firstRow = linkedOptionsDataSheet.createRow(0);
for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) {
String columnName = firstOptions.get(columnIndex);
firstRow.createCell(columnIndex)
.setCellValue(columnName);
columnNames.add(columnName);
}
// 创建名称管理器 // 创建名称管理器
Name name = workbook.createName(); Name name = workbook.createName();
// 设置名称管理器的别名 // 设置名称管理器的别名
@ -190,28 +204,12 @@ public class ExcelDownHandler implements SheetWriteHandler {
// 设置数据校验为序列模式引用的是名称管理器中的别名 // 设置数据校验为序列模式引用的是名称管理器中的别名
this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName)); this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName));
for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) { // 创建二级选项的名称管理器
// 先提取主表中一级下拉的列名 for (int columIndex = 0; columIndex < columnNames.size(); columIndex++) {
// 列名
String firstOptionsColumnName = getExcelColumnName(columIndex); String firstOptionsColumnName = getExcelColumnName(columIndex);
// 一次循环是每一个一级选项 // 对应的一级值
int finalI = columIndex; String thisFirstOptionsValue = columnNames.get(columIndex);
// 本次循环的一级选项值
String thisFirstOptionsValue = firstOptions.get(columIndex);
// 创建第一行的数据
Optional.ofNullable(linkedOptionsDataSheet.getRow(0))
// 如果不存在则创建第一行
.orElseGet(() -> linkedOptionsDataSheet.createRow(finalI))
// 第一行当前列
.createCell(columIndex)
// 设置值为当前一级选项值
.setCellValue(thisFirstOptionsValue);
// 第二行开始设置第二级别选项参数
List<String> secondOptions = secoundOptionsMap.get(thisFirstOptionsValue);
if (CollUtil.isEmpty(secondOptions)) {
// 必须保证至少有一个关联选项否则将导致Excel解析错误
secondOptions = Collections.singletonList("暂无_0");
}
// 以该一级选项值创建子名称管理器 // 以该一级选项值创建子名称管理器
Name sonName = workbook.createName(); Name sonName = workbook.createName();
@ -222,7 +220,9 @@ public class ExcelDownHandler implements SheetWriteHandler {
linkedOptionsSheetName, linkedOptionsSheetName,
firstOptionsColumnName, firstOptionsColumnName,
firstOptionsColumnName, firstOptionsColumnName,
secondOptions.size() + 1 // 二级选项存在则设置为(选项个数+1)否则设置为2行
Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue))
.orElseGet(ArrayList::new).size(), 1) + 1
); );
// 设置名称管理器的引用位置 // 设置名称管理器的引用位置
sonName.setRefersToFormula(sonFunction); sonName.setRefersToFormula(sonFunction);
@ -235,25 +235,51 @@ public class ExcelDownHandler implements SheetWriteHandler {
// 二级只能主表每一行的每一列添加二级校验 // 二级只能主表每一行的每一列添加二级校验
markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction)); markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction));
} }
}
for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) { // 将二级数据处理为按行区分
// 从第二行开始填充二级选项 Map<Integer, List<String>> columnValueMap = new HashMap<>();
int finalRowIndex = rowIndex + 1; int currentRow = 1;
int finalColumIndex = columIndex; while (currentRow >= 0) {
boolean flag = false;
Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex)) List<String> rowData = new ArrayList<>();
// 没有则创建 for (String columnName : columnNames) {
.orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex)); List<String> data = secoundOptionsMap.get(columnName);
Optional if (CollUtil.isEmpty(data)) {
// 在本级一级选项所在的列 // 添加空字符串填充位置
.ofNullable(row.getCell(finalColumIndex)) rowData.add(" ");
// 不存在则创建 continue;
.orElseGet(() -> row.createCell(finalColumIndex)) }
// 设置二级选项值 // 取第一个
.setCellValue(secondOptions.get(rowIndex)); String str = data.get(0);
rowData.add(str);
// 通过移除的方式避免重复
data.remove(0);
// 设置可以继续
flag = true;
}
columnValueMap.put(currentRow, rowData);
// 可以继续则增加行数否则置为负数跳出循环
if (flag) {
currentRow++;
} else {
currentRow = -1;
} }
} }
// 填充第二级选项数据
columnValueMap.forEach((rowIndex, rowValues) -> {
Row row = linkedOptionsDataSheet.createRow(rowIndex);
for (int columnIndex = 0; columnIndex < rowValues.size(); columnIndex++) {
String rowValue = rowValues.get(columnIndex);
// 填充位置的部分不渲染
if (StrUtil.isNotBlank(rowValue)) {
row.createCell(columnIndex)
.setCellValue(rowValue);
}
}
});
currentLinkedOptionsSheetIndex++; currentLinkedOptionsSheetIndex++;
} }

View File

@ -1,5 +1,6 @@
package org.dromara.demo.service.impl; package org.dromara.demo.service.impl;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.Data; import lombok.Data;
@ -121,8 +122,9 @@ public class ExportExcelServiceImpl implements IExportExcelService {
List<DemoCityData> provinceList = new ArrayList<>(); List<DemoCityData> provinceList = new ArrayList<>();
// 实际业务中一般采用数据库读取的形式这里直接拼接创建 // 实际业务中一般采用数据库读取的形式这里直接拼接创建
provinceList.add(new DemoCityData(0, null, "安徽省")); provinceList.add(new DemoCityData(0, null, "P100000"));
provinceList.add(new DemoCityData(1, null, "江苏省")); provinceList.add(new DemoCityData(1, null, "P200000"));
provinceList.add(new DemoCityData(2, null, "P300000"));
return provinceList; return provinceList;
} }
@ -137,11 +139,11 @@ public class ExportExcelServiceImpl implements IExportExcelService {
List<DemoCityData> cityList = new ArrayList<>(); List<DemoCityData> cityList = new ArrayList<>();
// 实际业务中一般采用数据库读取的形式这里直接拼接创建 // 实际业务中一般采用数据库读取的形式这里直接拼接创建
cityList.add(new DemoCityData(0, 0, "合肥市")); cityList.add(new DemoCityData(0, 0, "C110000"));
cityList.add(new DemoCityData(1, 0, "芜湖市")); cityList.add(new DemoCityData(1, 0, "C120000"));
cityList.add(new DemoCityData(2, 1, "南京市")); cityList.add(new DemoCityData(2, 1, "C210000"));
cityList.add(new DemoCityData(3, 1, "无锡市")); cityList.add(new DemoCityData(3, 1, "C220000"));
cityList.add(new DemoCityData(4, 1, "徐州市")); cityList.add(new DemoCityData(4, 1, "C230000"));
selectParentData(provinceList, cityList); selectParentData(provinceList, cityList);
@ -157,17 +159,29 @@ public class ExportExcelServiceImpl implements IExportExcelService {
private List<DemoCityData> getAreaList(List<DemoCityData> cityList) { private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
List<DemoCityData> areaList = new ArrayList<>(); List<DemoCityData> areaList = new ArrayList<>();
int minCount = 500;
int maxCount = 10000;
// 实际业务中一般采用数据库读取的形式这里直接拼接创建 // 实际业务中一般采用数据库读取的形式这里直接拼接创建
areaList.add(new DemoCityData(0, 0, "瑶海区")); for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
areaList.add(new DemoCityData(1, 0, "庐江区")); areaList.add(new DemoCityData(areaList.size(), 0, String.format("A11%04d", i)));
areaList.add(new DemoCityData(2, 1, "南宁县")); }
areaList.add(new DemoCityData(3, 1, "镜湖区"));
areaList.add(new DemoCityData(4, 2, "玄武区")); for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
areaList.add(new DemoCityData(5, 2, "秦淮区")); areaList.add(new DemoCityData(areaList.size(), 1, String.format("A12%04d", i)));
areaList.add(new DemoCityData(6, 3, "宜兴市")); }
areaList.add(new DemoCityData(7, 3, "新吴区"));
areaList.add(new DemoCityData(8, 4, "鼓楼区")); for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
areaList.add(new DemoCityData(9, 4, "丰县")); areaList.add(new DemoCityData(areaList.size(), 2, String.format("A21%04d", i)));
}
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
areaList.add(new DemoCityData(areaList.size(), 3, String.format("A22%04d", i)));
}
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
areaList.add(new DemoCityData(areaList.size(), 4, String.format("A23%04d", i)));
}
selectParentData(cityList, areaList); selectParentData(cityList, areaList);