Commit 09aa9ad97f2463a034fe596b2d587194179aa38a
Merge remote-tracking branch 'origin/master-jdk17' into master-jdk17
# Conflicts: # yudao-module-pms/src/test/java/cn/iocoder/yudao/module/pms/service/pm/workitem/PmsWorkItemUserSortServiceImplTest.java
Showing
310 changed files
with
4866 additions
and
809 deletions
Too many changes.
To preserve performance only 100 of 310 files are displayed.
yudao-dependencies/pom.xml
| ... | ... | @@ -34,6 +34,7 @@ |
| 34 | 34 | <kingbase.jdbc.version>9.0.1.jre7</kingbase.jdbc.version> |
| 35 | 35 | <opengauss.jdbc.version>7.0.0-RC3-og</opengauss.jdbc.version> |
| 36 | 36 | <taos.version>3.9.2</taos.version> |
| 37 | + <iotdb.version>2.0.8</iotdb.version> <!-- TODO 特殊:暂不升级 2.0.10/2.0.11,其 TablePreparedStatement.execute 不设置 ResultSet,导致 Mapper 的 SELECT 为空、COUNT 为 null --> | |
| 37 | 38 | <!-- 消息队列 --> |
| 38 | 39 | <rocketmq-spring.version>2.3.6</rocketmq-spring.version> |
| 39 | 40 | <!-- 服务保障相关 --> |
| ... | ... | @@ -58,7 +59,7 @@ |
| 58 | 59 | <mapstruct.version>1.7.0.Beta2</mapstruct.version> |
| 59 | 60 | <hutool-5.version>5.8.47</hutool-5.version> |
| 60 | 61 | <hutool-6.version>6.0.0-M22</hutool-6.version> |
| 61 | - <fastexcel.version>1.3.0</fastexcel.version> | |
| 62 | + <fesod.version>2.1.0-incubating</fesod.version> | |
| 62 | 63 | <aviator.version>5.4.4</aviator.version> |
| 63 | 64 | <velocity.version>2.4.1</velocity.version> |
| 64 | 65 | <fastjson2.version>2.0.65</fastjson2.version> |
| ... | ... | @@ -312,6 +313,12 @@ |
| 312 | 313 | <version>${taos.version}</version> |
| 313 | 314 | </dependency> |
| 314 | 315 | |
| 316 | + <dependency> | |
| 317 | + <groupId>org.apache.iotdb</groupId> | |
| 318 | + <artifactId>iotdb-jdbc</artifactId> | |
| 319 | + <version>${iotdb.version}</version> | |
| 320 | + </dependency> | |
| 321 | + | |
| 315 | 322 | <!-- Job 定时任务相关 --> |
| 316 | 323 | <dependency> |
| 317 | 324 | <groupId>cn.iocoder.boot</groupId> |
| ... | ... | @@ -509,9 +516,9 @@ |
| 509 | 516 | </dependency> |
| 510 | 517 | |
| 511 | 518 | <dependency> |
| 512 | - <groupId>cn.idev.excel</groupId> | |
| 513 | - <artifactId>fastexcel</artifactId> | |
| 514 | - <version>${fastexcel.version}</version> | |
| 519 | + <groupId>org.apache.fesod</groupId> | |
| 520 | + <artifactId>fesod-sheet</artifactId> | |
| 521 | + <version>${fesod.version}</version> | |
| 515 | 522 | </dependency> |
| 516 | 523 | |
| 517 | 524 | <dependency> | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/pom.xml
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java
| ... | ... | @@ -3,13 +3,13 @@ package cn.iocoder.yudao.framework.excel.core.convert; |
| 3 | 3 | import cn.hutool.core.convert.Convert; |
| 4 | 4 | import cn.iocoder.yudao.framework.ip.core.Area; |
| 5 | 5 | import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; |
| 6 | -import cn.idev.excel.converters.Converter; | |
| 7 | -import cn.idev.excel.enums.CellDataTypeEnum; | |
| 8 | -import cn.idev.excel.metadata.GlobalConfiguration; | |
| 9 | -import cn.idev.excel.metadata.data.ReadCellData; | |
| 10 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 11 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 12 | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | +import org.apache.fesod.sheet.converters.Converter; | |
| 8 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 9 | +import org.apache.fesod.sheet.metadata.GlobalConfiguration; | |
| 10 | +import org.apache.fesod.sheet.metadata.data.ReadCellData; | |
| 11 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 12 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | 15 | * Excel 数据地区转换器 | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java
| ... | ... | @@ -3,13 +3,13 @@ package cn.iocoder.yudao.framework.excel.core.convert; |
| 3 | 3 | import cn.hutool.core.convert.Convert; |
| 4 | 4 | import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; |
| 5 | 5 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 6 | -import cn.idev.excel.converters.Converter; | |
| 7 | -import cn.idev.excel.enums.CellDataTypeEnum; | |
| 8 | -import cn.idev.excel.metadata.GlobalConfiguration; | |
| 9 | -import cn.idev.excel.metadata.data.ReadCellData; | |
| 10 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 11 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 12 | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | +import org.apache.fesod.sheet.converters.Converter; | |
| 8 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 9 | +import org.apache.fesod.sheet.metadata.GlobalConfiguration; | |
| 10 | +import org.apache.fesod.sheet.metadata.data.ReadCellData; | |
| 11 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 12 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | 15 | * Excel 数据字典转换器 | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.convert; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 4 | -import cn.idev.excel.converters.Converter; | |
| 5 | -import cn.idev.excel.enums.CellDataTypeEnum; | |
| 6 | -import cn.idev.excel.metadata.GlobalConfiguration; | |
| 7 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 8 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 4 | +import org.apache.fesod.sheet.converters.Converter; | |
| 5 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 6 | +import org.apache.fesod.sheet.metadata.GlobalConfiguration; | |
| 7 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 8 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 9 | 9 | |
| 10 | 10 | /** |
| 11 | 11 | * Excel Json 转换器 | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.convert; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.converters.Converter; | |
| 4 | -import cn.idev.excel.enums.CellDataTypeEnum; | |
| 5 | -import cn.idev.excel.metadata.GlobalConfiguration; | |
| 6 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 7 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 3 | +import org.apache.fesod.sheet.converters.Converter; | |
| 4 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 5 | +import org.apache.fesod.sheet.metadata.GlobalConfiguration; | |
| 6 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 7 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.math.RoundingMode; | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MultiDictConvert.java
| ... | ... | @@ -4,13 +4,13 @@ import cn.hutool.core.convert.Convert; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; |
| 6 | 6 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 7 | -import cn.idev.excel.converters.Converter; | |
| 8 | -import cn.idev.excel.enums.CellDataTypeEnum; | |
| 9 | -import cn.idev.excel.metadata.GlobalConfiguration; | |
| 10 | -import cn.idev.excel.metadata.data.ReadCellData; | |
| 11 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 12 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 13 | 7 | import lombok.extern.slf4j.Slf4j; |
| 8 | +import org.apache.fesod.sheet.converters.Converter; | |
| 9 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 10 | +import org.apache.fesod.sheet.metadata.GlobalConfiguration; | |
| 11 | +import org.apache.fesod.sheet.metadata.data.ReadCellData; | |
| 12 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 13 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 14 | 14 | |
| 15 | 15 | import java.lang.reflect.Array; |
| 16 | 16 | import java.lang.reflect.Field; | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/StringListConvert.java
| ... | ... | @@ -2,11 +2,11 @@ package cn.iocoder.yudao.framework.excel.core.convert; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | -import cn.idev.excel.converters.Converter; | |
| 6 | -import cn.idev.excel.metadata.GlobalConfiguration; | |
| 7 | -import cn.idev.excel.metadata.data.ReadCellData; | |
| 8 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 9 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 5 | +import org.apache.fesod.sheet.converters.Converter; | |
| 6 | +import org.apache.fesod.sheet.metadata.GlobalConfiguration; | |
| 7 | +import org.apache.fesod.sheet.metadata.data.ReadCellData; | |
| 8 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 9 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.util.Collections; |
| 12 | 12 | import java.util.List; | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/ColumnWidthMatchStyleStrategy.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.handler; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.idev.excel.enums.CellDataTypeEnum; | |
| 5 | -import cn.idev.excel.metadata.Head; | |
| 6 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 7 | -import cn.idev.excel.util.MapUtils; | |
| 8 | -import cn.idev.excel.write.metadata.holder.WriteSheetHolder; | |
| 9 | -import cn.idev.excel.write.style.column.AbstractColumnWidthStyleStrategy; | |
| 10 | -import cn.idev.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; | |
| 4 | +import org.apache.fesod.common.util.MapUtils; | |
| 5 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 6 | +import org.apache.fesod.sheet.metadata.Head; | |
| 7 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 8 | +import org.apache.fesod.sheet.write.metadata.holder.WriteSheetHolder; | |
| 9 | +import org.apache.fesod.sheet.write.style.column.AbstractColumnWidthStyleStrategy; | |
| 10 | +import org.apache.fesod.sheet.write.style.column.LongestMatchColumnWidthStyleStrategy; | |
| 11 | 11 | import org.apache.poi.ss.usermodel.Cell; |
| 12 | 12 | |
| 13 | 13 | import java.nio.charset.StandardCharsets; | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java
| ... | ... | @@ -10,13 +10,13 @@ import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 10 | 10 | import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; |
| 11 | 11 | import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; |
| 12 | 12 | import cn.iocoder.yudao.framework.excel.core.function.ExcelColumnSelectFunction; |
| 13 | -import cn.idev.excel.annotation.ExcelIgnore; | |
| 14 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 15 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 16 | -import cn.idev.excel.write.handler.SheetWriteHandler; | |
| 17 | -import cn.idev.excel.write.metadata.holder.WriteSheetHolder; | |
| 18 | -import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder; | |
| 19 | 13 | import lombok.extern.slf4j.Slf4j; |
| 14 | +import org.apache.fesod.sheet.annotation.ExcelIgnore; | |
| 15 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 16 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 17 | +import org.apache.fesod.sheet.write.handler.SheetWriteHandler; | |
| 18 | +import org.apache.fesod.sheet.write.metadata.holder.WriteSheetHolder; | |
| 19 | +import org.apache.fesod.sheet.write.metadata.holder.WriteWorkbookHolder; | |
| 20 | 20 | import org.apache.poi.hssf.usermodel.HSSFDataValidation; |
| 21 | 21 | import org.apache.poi.ss.usermodel.*; |
| 22 | 22 | import org.apache.poi.ss.util.CellRangeAddressList; |
| ... | ... | @@ -86,7 +86,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { |
| 86 | 86 | |
| 87 | 87 | /** |
| 88 | 88 | * 判断字段是否是静态的、最终的、 transient 的 |
| 89 | - * 原因:FastExcel 默认是忽略 static final 或 transient 的字段,所以需要判断 | |
| 89 | + * 原因:Fesod 默认是忽略 static final 或 transient 的字段,所以需要判断 | |
| 90 | 90 | * |
| 91 | 91 | * @param field 字段 |
| 92 | 92 | * @return 是否是静态的、最终的、transient 的 | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.util; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.FastExcelFactory; | |
| 4 | -import cn.idev.excel.context.AnalysisContext; | |
| 5 | -import cn.idev.excel.converters.longconverter.LongStringConverter; | |
| 6 | -import cn.idev.excel.read.listener.ReadListener; | |
| 7 | 3 | import cn.iocoder.yudao.framework.common.util.http.HttpUtils; |
| 8 | 4 | import cn.iocoder.yudao.framework.excel.core.handler.ColumnWidthMatchStyleStrategy; |
| 9 | 5 | import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; |
| 10 | 6 | import jakarta.servlet.http.HttpServletResponse; |
| 7 | +import org.apache.fesod.sheet.FesodSheet; | |
| 8 | +import org.apache.fesod.sheet.context.AnalysisContext; | |
| 9 | +import org.apache.fesod.sheet.converters.Converter; | |
| 10 | +import org.apache.fesod.sheet.converters.longconverter.LongStringConverter; | |
| 11 | +import org.apache.fesod.sheet.enums.CellDataTypeEnum; | |
| 12 | +import org.apache.fesod.sheet.read.listener.ReadListener; | |
| 11 | 13 | import org.springframework.web.multipart.MultipartFile; |
| 12 | 14 | |
| 13 | 15 | import java.io.IOException; |
| ... | ... | @@ -25,6 +27,21 @@ import java.util.Map; |
| 25 | 27 | public class ExcelUtils { |
| 26 | 28 | |
| 27 | 29 | /** |
| 30 | + * Long 转 String 的转换器,避免 Long 类型丢失精度 | |
| 31 | + * | |
| 32 | + * 参考 https://t.zsxq.com/a0w1V 帖子:Fesod 写入 xlsx 时,按 supportExcelTypeKey 为 null 查找全局转换器, | |
| 33 | + * 所以需要返回 null,否则 registerConverter 的 LongStringConverter 不生效。关联 https://github.com/apache/fesod/issues/648 | |
| 34 | + */ | |
| 35 | + private static final Converter<Long> LONG_STRING_CONVERTER = new LongStringConverter() { | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public CellDataTypeEnum supportExcelTypeKey() { | |
| 39 | + return null; | |
| 40 | + } | |
| 41 | + | |
| 42 | + }; | |
| 43 | + | |
| 44 | + /** | |
| 28 | 45 | * 将列表以 Excel 响应给前端 |
| 29 | 46 | * |
| 30 | 47 | * @param response 响应 |
| ... | ... | @@ -38,11 +55,11 @@ public class ExcelUtils { |
| 38 | 55 | public static <T> void write(HttpServletResponse response, String filename, String sheetName, |
| 39 | 56 | Class<T> head, List<T> data) throws IOException { |
| 40 | 57 | // 输出 Excel |
| 41 | - FastExcelFactory.write(response.getOutputStream(), head) | |
| 58 | + FesodSheet.write(response.getOutputStream(), head) | |
| 42 | 59 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 43 | 60 | .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 |
| 44 | 61 | .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 |
| 45 | - .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | |
| 62 | + .registerConverter(LONG_STRING_CONVERTER) // 避免 Long 类型丢失精度 | |
| 46 | 63 | .sheet(sheetName).doWrite(data); |
| 47 | 64 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 |
| 48 | 65 | response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); |
| ... | ... | @@ -62,10 +79,10 @@ public class ExcelUtils { |
| 62 | 79 | public static void write(HttpServletResponse response, String filename, String sheetName, |
| 63 | 80 | List<List<String>> head, List<List<Object>> data) throws IOException { |
| 64 | 81 | // 输出 Excel |
| 65 | - FastExcelFactory.write(response.getOutputStream()) | |
| 82 | + FesodSheet.write(response.getOutputStream()) | |
| 66 | 83 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 67 | 84 | .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 |
| 68 | - .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | |
| 85 | + .registerConverter(LONG_STRING_CONVERTER) // 避免 Long 类型丢失精度 | |
| 69 | 86 | .head(head).sheet(sheetName).doWrite(data); |
| 70 | 87 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 |
| 71 | 88 | response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); |
| ... | ... | @@ -78,7 +95,7 @@ public class ExcelUtils { |
| 78 | 95 | } |
| 79 | 96 | // 参考 https://t.zsxq.com/zM77F 帖子,增加 try 处理,兼容 windows 场景 |
| 80 | 97 | try (InputStream inputStream = file.getInputStream()) { |
| 81 | - return FastExcelFactory.read(inputStream, head, null) | |
| 98 | + return FesodSheet.read(inputStream, head, null) | |
| 82 | 99 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 83 | 100 | .doReadAllSync(); |
| 84 | 101 | } |
| ... | ... | @@ -101,7 +118,7 @@ public class ExcelUtils { |
| 101 | 118 | } |
| 102 | 119 | List<T> rows = new ArrayList<>(Math.min(maxRowCount, 1024)); |
| 103 | 120 | try (InputStream inputStream = file.getInputStream()) { |
| 104 | - FastExcelFactory.read(inputStream, head, new ReadListener<T>() { | |
| 121 | + FesodSheet.read(inputStream, head, new ReadListener<T>() { | |
| 105 | 122 | |
| 106 | 123 | @Override |
| 107 | 124 | public void invoke(T data, AnalysisContext context) { |
| ... | ... | @@ -136,7 +153,7 @@ public class ExcelUtils { |
| 136 | 153 | } |
| 137 | 154 | // 参考 https://t.zsxq.com/zM77F 帖子,增加 try 处理,兼容 windows 场景 |
| 138 | 155 | try (InputStream inputStream = file.getInputStream()) { |
| 139 | - return FastExcelFactory.read(inputStream) | |
| 156 | + return FesodSheet.read(inputStream) | |
| 140 | 157 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 141 | 158 | .headRowNumber(1) |
| 142 | 159 | .sheet() | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/PoiExcelUtils.java
| ... | ... | @@ -27,7 +27,7 @@ import java.util.Collection; |
| 27 | 27 | /** |
| 28 | 28 | * 原生 POI 的 Excel 工具类 |
| 29 | 29 | * |
| 30 | - * 全局 {@link ExcelUtils}(FastExcel)无法表达单元格锁定、公式、动态列等复杂模板时,各模块基于本类实现自定义 Excel 读写 | |
| 30 | + * 全局 {@link ExcelUtils}(Fesod)无法表达单元格锁定、公式、动态列等复杂模板时,各模块基于本类实现自定义 Excel 读写 | |
| 31 | 31 | * |
| 32 | 32 | * @author 芋道源码 |
| 33 | 33 | */ | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java
yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/excel/core/convert/MultiDictConvertTest.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.convert; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.ListUtil; |
| 4 | -import cn.idev.excel.metadata.data.ReadCellData; | |
| 5 | -import cn.idev.excel.metadata.data.WriteCellData; | |
| 6 | -import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 7 | 4 | import cn.iocoder.yudao.framework.common.biz.system.dict.DictDataCommonApi; |
| 8 | 5 | import cn.iocoder.yudao.framework.common.biz.system.dict.dto.DictDataRespDTO; |
| 9 | 6 | import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; |
| 10 | 7 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 11 | 8 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| 9 | +import org.apache.fesod.sheet.metadata.data.ReadCellData; | |
| 10 | +import org.apache.fesod.sheet.metadata.data.WriteCellData; | |
| 11 | +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; | |
| 12 | 12 | import org.junit.jupiter.api.BeforeEach; |
| 13 | 13 | import org.junit.jupiter.api.Test; |
| 14 | 14 | import org.mockito.Mock; | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/excel/core/handler/ColumnWidthMatchStyleStrategyTest.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.handler; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.FastExcelFactory; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 3 | +import org.apache.fesod.sheet.FesodSheet; | |
| 4 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 5 | 5 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| 6 | 6 | import org.junit.jupiter.api.Test; |
| 7 | 7 | |
| ... | ... | @@ -59,7 +59,7 @@ public class ColumnWidthMatchStyleStrategyTest { |
| 59 | 59 | |
| 60 | 60 | private XSSFWorkbook write(List<TestRow> rows) throws Exception { |
| 61 | 61 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
| 62 | - FastExcelFactory.write(outputStream, TestRow.class) | |
| 62 | + FesodSheet.write(outputStream, TestRow.class) | |
| 63 | 63 | .registerWriteHandler(new ColumnWidthMatchStyleStrategy()).sheet().doWrite(rows); |
| 64 | 64 | return new XSSFWorkbook(new ByteArrayInputStream(outputStream.toByteArray())); |
| 65 | 65 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtilsTest.java
| 1 | 1 | package cn.iocoder.yudao.framework.excel.core.util; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.FastExcelFactory; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 3 | +import cn.hutool.core.collection.ListUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.biz.system.dict.DictDataCommonApi; | |
| 5 | +import cn.iocoder.yudao.framework.common.biz.system.dict.dto.DictDataRespDTO; | |
| 6 | +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; | |
| 7 | +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 8 | +import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; | |
| 9 | +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 10 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | |
| 11 | +import lombok.Data; | |
| 12 | +import lombok.experimental.Accessors; | |
| 13 | +import org.apache.fesod.sheet.FesodSheet; | |
| 14 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 15 | +import org.apache.poi.ss.usermodel.Cell; | |
| 16 | +import org.apache.poi.ss.usermodel.CellType; | |
| 17 | +import org.apache.poi.ss.usermodel.Sheet; | |
| 18 | +import org.apache.poi.ss.usermodel.Workbook; | |
| 19 | +import org.apache.poi.ss.usermodel.WorkbookFactory; | |
| 20 | +import org.junit.jupiter.api.BeforeEach; | |
| 5 | 21 | import org.junit.jupiter.api.Test; |
| 22 | +import org.mockito.Mock; | |
| 23 | +import org.springframework.mock.web.MockHttpServletResponse; | |
| 6 | 24 | import org.springframework.mock.web.MockMultipartFile; |
| 7 | 25 | |
| 26 | +import java.io.ByteArrayInputStream; | |
| 8 | 27 | import java.io.ByteArrayOutputStream; |
| 9 | 28 | import java.util.Arrays; |
| 29 | +import java.util.Collections; | |
| 10 | 30 | import java.util.List; |
| 11 | 31 | |
| 32 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | |
| 12 | 33 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 34 | +import static org.junit.jupiter.api.Assertions.assertNotNull; | |
| 35 | +import static org.mockito.ArgumentMatchers.eq; | |
| 36 | +import static org.mockito.Mockito.when; | |
| 13 | 37 | |
| 14 | 38 | /** |
| 15 | 39 | * {@link ExcelUtils} 的单元测试 |
| 16 | 40 | * |
| 17 | 41 | * @author 芋道源码 |
| 18 | 42 | */ |
| 19 | -public class ExcelUtilsTest { | |
| 43 | +public class ExcelUtilsTest extends BaseMockitoUnitTest { | |
| 44 | + | |
| 45 | + private static final String DICT_TYPE = "test_status"; | |
| 46 | + | |
| 47 | + @Mock | |
| 48 | + private DictDataCommonApi dictDataApi; | |
| 49 | + | |
| 50 | + @BeforeEach | |
| 51 | + public void setUp() { | |
| 52 | + DictFrameworkUtils.init(dictDataApi); | |
| 53 | + DictFrameworkUtils.clearCache(); | |
| 54 | + } | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 字段未配置 converter 的 Long 编号,需要导出为文本,避免丢失精度 | |
| 58 | + */ | |
| 59 | + @Test | |
| 60 | + public void testWrite_class() throws Exception { | |
| 61 | + // mock 数据 | |
| 62 | + mockDictDatas(); | |
| 63 | + // 准备参数 | |
| 64 | + MockHttpServletResponse response = new MockHttpServletResponse(); | |
| 65 | + List<TestUser> list = Arrays.asList( | |
| 66 | + new TestUser().setId(1981234567890123456L).setAge(18).setStatus(0), | |
| 67 | + new TestUser().setId(Long.MAX_VALUE).setAge(20).setStatus(1)); | |
| 68 | + | |
| 69 | + // 调用 | |
| 70 | + ExcelUtils.write(response, "用户.xls", "数据", TestUser.class, list); | |
| 71 | + // 断言 | |
| 72 | + try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(response.getContentAsByteArray()))) { | |
| 73 | + Sheet sheet = workbook.getSheet("数据"); | |
| 74 | + // 断言 Long 编号 | |
| 75 | + assertStringCell("1981234567890123456", sheet.getRow(1).getCell(0)); | |
| 76 | + assertStringCell("9223372036854775807", sheet.getRow(2).getCell(0)); | |
| 77 | + // 断言普通数值 | |
| 78 | + assertNumericCell(18, sheet.getRow(1).getCell(1)); | |
| 79 | + assertNumericCell(20, sheet.getRow(2).getCell(1)); | |
| 80 | + // 断言字典转换 | |
| 81 | + assertStringCell("开启", sheet.getRow(1).getCell(2)); | |
| 82 | + assertStringCell("关闭", sheet.getRow(2).getCell(2)); | |
| 83 | + // 断言下拉框 | |
| 84 | + assertNotNull(workbook.getSheet("字典sheet")); | |
| 85 | + assertEquals(1, sheet.getDataValidations().size()); | |
| 86 | + // 断言列宽:19 位 Long 字符串,加上 2 个字符的留白 | |
| 87 | + assertEquals((19 + 2) * 256, sheet.getColumnWidth(0)); | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + @Test | |
| 92 | + public void testWrite_dynamicHead() throws Exception { | |
| 93 | + // 准备参数 | |
| 94 | + MockHttpServletResponse response = new MockHttpServletResponse(); | |
| 95 | + List<List<String>> head = Arrays.asList(Collections.singletonList("编号"), Collections.singletonList("年龄")); | |
| 96 | + List<List<Object>> list = Arrays.asList( | |
| 97 | + Arrays.asList(1981234567890123456L, 18), | |
| 98 | + Arrays.asList(Long.MAX_VALUE, 20)); | |
| 99 | + | |
| 100 | + // 调用 | |
| 101 | + ExcelUtils.write(response, "用户.xls", "数据", head, list); | |
| 102 | + // 断言 | |
| 103 | + try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(response.getContentAsByteArray()))) { | |
| 104 | + Sheet sheet = workbook.getSheet("数据"); | |
| 105 | + assertStringCell("编号", sheet.getRow(0).getCell(0)); | |
| 106 | + // 断言 Long 编号 | |
| 107 | + assertStringCell("1981234567890123456", sheet.getRow(1).getCell(0)); | |
| 108 | + assertStringCell("9223372036854775807", sheet.getRow(2).getCell(0)); | |
| 109 | + // 断言普通数值 | |
| 110 | + assertNumericCell(18, sheet.getRow(1).getCell(1)); | |
| 111 | + assertNumericCell(20, sheet.getRow(2).getCell(1)); | |
| 112 | + } | |
| 113 | + } | |
| 20 | 114 | |
| 21 | 115 | @Test |
| 22 | 116 | public void testRead_maxRowCount() throws Exception { |
| 23 | 117 | // mock 数据 |
| 24 | 118 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
| 25 | - FastExcelFactory.write(outputStream, TestRow.class).sheet().doWrite(Arrays.asList( | |
| 119 | + FesodSheet.write(outputStream, TestRow.class).sheet().doWrite(Arrays.asList( | |
| 26 | 120 | new TestRow("员工一"), new TestRow("员工二"), new TestRow("员工三"))); |
| 27 | 121 | MockMultipartFile file = new MockMultipartFile( |
| 28 | 122 | "file", "employees.xlsx", null, outputStream.toByteArray()); |
| ... | ... | @@ -36,6 +130,41 @@ public class ExcelUtilsTest { |
| 36 | 130 | assertEquals("员工二", rows.get(1).getName()); |
| 37 | 131 | } |
| 38 | 132 | |
| 133 | + private void mockDictDatas() { | |
| 134 | + List<DictDataRespDTO> dictDatas = ListUtil.of( | |
| 135 | + randomPojo(DictDataRespDTO.class, o -> o.setDictType(DICT_TYPE).setValue("0").setLabel("开启")), | |
| 136 | + randomPojo(DictDataRespDTO.class, o -> o.setDictType(DICT_TYPE).setValue("1").setLabel("关闭")) | |
| 137 | + ); | |
| 138 | + when(dictDataApi.getDictDataList(eq(DICT_TYPE))).thenReturn(dictDatas); | |
| 139 | + } | |
| 140 | + | |
| 141 | + private static void assertStringCell(String expected, Cell cell) { | |
| 142 | + assertEquals(CellType.STRING, cell.getCellType()); | |
| 143 | + assertEquals(expected, cell.getStringCellValue()); | |
| 144 | + } | |
| 145 | + | |
| 146 | + private static void assertNumericCell(double expected, Cell cell) { | |
| 147 | + assertEquals(CellType.NUMERIC, cell.getCellType()); | |
| 148 | + assertEquals(expected, cell.getNumericCellValue()); | |
| 149 | + } | |
| 150 | + | |
| 151 | + @Data | |
| 152 | + @Accessors(chain = true) | |
| 153 | + public static class TestUser { | |
| 154 | + | |
| 155 | + @ExcelProperty("编号") | |
| 156 | + private Long id; | |
| 157 | + | |
| 158 | + @ExcelProperty("年龄") | |
| 159 | + private Integer age; | |
| 160 | + | |
| 161 | + @ExcelProperty(value = "状态", converter = DictConvert.class) | |
| 162 | + @DictFormat(DICT_TYPE) | |
| 163 | + @ExcelColumnSelect(dictType = DICT_TYPE) | |
| 164 | + private Integer status; | |
| 165 | + | |
| 166 | + } | |
| 167 | + | |
| 39 | 168 | public static class TestRow { |
| 40 | 169 | |
| 41 | 170 | @ExcelProperty("姓名") | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
| ... | ... | @@ -4,11 +4,15 @@ import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 6 | 6 | import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler; |
| 7 | +import cn.iocoder.yudao.framework.mybatis.core.injector.YudaoSqlInjector; | |
| 8 | +import cn.iocoder.yudao.framework.mybatis.core.util.CaseInsensitiveResultMap; | |
| 7 | 9 | import com.baomidou.mybatisplus.annotation.DbType; |
| 10 | +import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; | |
| 8 | 11 | import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; |
| 9 | 12 | import com.baomidou.mybatisplus.core.handlers.IJsonTypeHandler; |
| 10 | 13 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
| 11 | 14 | import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; |
| 15 | +import com.baomidou.mybatisplus.core.injector.ISqlInjector; | |
| 12 | 16 | import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; |
| 13 | 17 | import com.baomidou.mybatisplus.extension.incrementer.*; |
| 14 | 18 | import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal; |
| ... | ... | @@ -17,12 +21,15 @@ import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 17 | 21 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
| 18 | 22 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 19 | 23 | import org.apache.ibatis.annotations.Mapper; |
| 24 | +import org.apache.ibatis.mapping.ResultMap; | |
| 20 | 25 | import org.mybatis.spring.annotation.MapperScan; |
| 21 | 26 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 22 | 27 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 23 | 28 | import org.springframework.context.annotation.Bean; |
| 29 | +import org.springframework.context.annotation.Primary; | |
| 24 | 30 | import org.springframework.core.env.ConfigurableEnvironment; |
| 25 | 31 | |
| 32 | +import java.util.ArrayList; | |
| 26 | 33 | import java.util.List; |
| 27 | 34 | import java.util.concurrent.TimeUnit; |
| 28 | 35 | |
| ... | ... | @@ -59,6 +66,19 @@ public class YudaoMybatisAutoConfiguration { |
| 59 | 66 | } |
| 60 | 67 | |
| 61 | 68 | @Bean |
| 69 | + @Primary // 特殊:使用 @Primary 的原因,避免 MyBatis Plus Join 再创建 MPJSqlInjector 包装它 | |
| 70 | + public ISqlInjector yudaoSqlInjector() { | |
| 71 | + return new YudaoSqlInjector(); // selectMaps 的结果行,使用 CaseInsensitiveResultMap | |
| 72 | + } | |
| 73 | + | |
| 74 | + @Bean | |
| 75 | + public ConfigurationCustomizer caseInsensitiveResultMapConfigurationCustomizer() { | |
| 76 | + // 注册 CaseInsensitiveResultMap 的 resultMap,用于注解 SQL 的 @ResultMap | |
| 77 | + return configuration -> configuration.addResultMap(new ResultMap.Builder(configuration, | |
| 78 | + CaseInsensitiveResultMap.RESULT_MAP_ID, CaseInsensitiveResultMap.class, new ArrayList<>()).build()); | |
| 79 | + } | |
| 80 | + | |
| 81 | + @Bean | |
| 62 | 82 | @ConditionalOnProperty(prefix = "mybatis-plus.global-config.db-config", name = "id-type", havingValue = "INPUT") |
| 63 | 83 | public IKeyGenerator keyGenerator(ConfigurableEnvironment environment) { |
| 64 | 84 | DbType dbType = IdTypeEnvironmentPostProcessor.getDbType(environment); | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/injector/YudaoSqlInjector.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.injector; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.util.CaseInsensitiveResultMap; | |
| 4 | +import com.baomidou.mybatisplus.core.injector.AbstractMethod; | |
| 5 | +import com.baomidou.mybatisplus.core.metadata.TableInfo; | |
| 6 | +import com.github.yulichang.injector.MPJSqlInjector; | |
| 7 | +import com.github.yulichang.method.mp.SelectMaps; | |
| 8 | +import org.apache.ibatis.mapping.MappedStatement; | |
| 9 | +import org.apache.ibatis.mapping.SqlSource; | |
| 10 | +import org.apache.ibatis.session.Configuration; | |
| 11 | + | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 自定义 SQL 注入器 | |
| 16 | + * | |
| 17 | + * 在 MyBatis Plus Join 的 {@link MPJSqlInjector} 基础上,将 selectMaps 的结果行替换为 {@link CaseInsensitiveResultMap}, | |
| 18 | + * 解决 PostgreSQL、Oracle 等数据库列标签大小写折叠,导致按固定 key 取不到值的问题 | |
| 19 | + * | |
| 20 | + * @author 芋道源码 | |
| 21 | + */ | |
| 22 | +public class YudaoSqlInjector extends MPJSqlInjector { | |
| 23 | + | |
| 24 | + @Override | |
| 25 | + public List<AbstractMethod> getMethodList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo) { | |
| 26 | + List<AbstractMethod> methods = super.getMethodList(configuration, mapperClass, tableInfo); | |
| 27 | + methods.replaceAll(method -> method instanceof SelectMaps ? new CaseInsensitiveSelectMaps() : method); | |
| 28 | + return methods; | |
| 29 | + } | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 结果行为 {@link CaseInsensitiveResultMap} 的 selectMaps | |
| 33 | + * | |
| 34 | + * 仅修改结果类型,SQL 仍由 MyBatis Plus Join 的 {@link SelectMaps} 生成,兼容 MPJ 的 Wrapper | |
| 35 | + */ | |
| 36 | + private static class CaseInsensitiveSelectMaps extends SelectMaps { | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + protected MappedStatement addSelectMappedStatementForOther(Class<?> mapperClass, String id, SqlSource sqlSource, | |
| 40 | + Class<?> resultType) { | |
| 41 | + return super.addSelectMappedStatementForOther(mapperClass, id, sqlSource, CaseInsensitiveResultMap.class); | |
| 42 | + } | |
| 43 | + | |
| 44 | + } | |
| 45 | + | |
| 46 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.pojo.SortingField; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; |
| 9 | +import cn.iocoder.yudao.framework.mybatis.core.util.CaseInsensitiveResultMap; | |
| 9 | 10 | import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; |
| 10 | 11 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 11 | 12 | import com.baomidou.mybatisplus.annotation.DbType; |
| ... | ... | @@ -14,6 +15,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 14 | 15 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 15 | 16 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 16 | 17 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 18 | +import com.baomidou.mybatisplus.core.toolkit.Constants; | |
| 17 | 19 | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; |
| 18 | 20 | import com.baomidou.mybatisplus.extension.toolkit.Db; |
| 19 | 21 | import com.github.yulichang.base.MPJBaseMapper; |
| ... | ... | @@ -23,6 +25,7 @@ import org.apache.ibatis.annotations.Param; |
| 23 | 25 | |
| 24 | 26 | import java.util.Collection; |
| 25 | 27 | import java.util.List; |
| 28 | +import java.util.Map; | |
| 26 | 29 | |
| 27 | 30 | /** |
| 28 | 31 | * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 |
| ... | ... | @@ -99,6 +102,24 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 99 | 102 | return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); |
| 100 | 103 | } |
| 101 | 104 | |
| 105 | + @Override | |
| 106 | + @SuppressWarnings("unchecked") | |
| 107 | + default Map<String, Object> selectJoinMap(@Param(Constants.WRAPPER) MPJBaseJoin<T> wrapper) { | |
| 108 | + return selectJoinOne(CaseInsensitiveResultMap.class, wrapper); | |
| 109 | + } | |
| 110 | + | |
| 111 | + @Override | |
| 112 | + @SuppressWarnings("unchecked") | |
| 113 | + default List<Map<String, Object>> selectJoinMaps(@Param(Constants.WRAPPER) MPJBaseJoin<T> wrapper) { | |
| 114 | + return (List<Map<String, Object>>) ((Object) selectJoinList(CaseInsensitiveResultMap.class, wrapper)); | |
| 115 | + } | |
| 116 | + | |
| 117 | + @Override | |
| 118 | + @SuppressWarnings({"unchecked", "rawtypes"}) | |
| 119 | + default <P extends IPage<Map<String, Object>>> P selectJoinMapsPage(P page, @Param(Constants.WRAPPER) MPJBaseJoin<T> wrapper) { | |
| 120 | + return (P) selectJoinPage((IPage) page, CaseInsensitiveResultMap.class, wrapper); | |
| 121 | + } | |
| 122 | + | |
| 102 | 123 | default T selectOne(String field, Object value) { |
| 103 | 124 | return selectOne(new QueryWrapper<T>().eq(field, value)); |
| 104 | 125 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/CaseInsensitiveResultMap.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.util; | |
| 2 | + | |
| 3 | +import org.springframework.util.LinkedCaseInsensitiveMap; | |
| 4 | + | |
| 5 | +import java.util.Locale; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * key 大小写不敏感的 MyBatis 查询结果 Map | |
| 9 | + * | |
| 10 | + * 背景:使用 Map 接收查询结果时,key 为 JDBC 返回的列标签。PostgreSQL 等会将未加引号的列名、别名折叠为小写, | |
| 11 | + * Oracle、达梦等会折叠为大写,导致 map.get("conversationId") 这类按固定 key 取值的代码,在 MySQL 以外的数据库取不到值。 | |
| 12 | + * | |
| 13 | + * 实现:基于 {@link LinkedCaseInsensitiveMap},get / containsKey / remove 时忽略 key 的大小写, | |
| 14 | + * 同时保留原始的列标签作为 key(遍历、序列化时不变)。固定使用 {@link Locale#ROOT},避免服务器默认 Locale(例如土耳其语)影响 key 的匹配。 | |
| 15 | + * | |
| 16 | + * 使用方式:由 MyBatis 直接创建结果行,Mapper 的返回类型仍声明为 Map,业务无需感知该类 | |
| 17 | + * 1. MyBatis Plus 的 selectMaps:由 YudaoSqlInjector 注入,自动使用该类 | |
| 18 | + * 2. MyBatis Plus Join 的 selectJoinMaps 等:由 BaseMapperX 覆盖,自动使用该类 | |
| 19 | + * 3. XML SQL:将 resultType 设置为该类 | |
| 20 | + * 4. 注解 SQL:添加 @ResultMap({@link #RESULT_MAP_ID}) | |
| 21 | + * | |
| 22 | + * 注意:仅大小写不同的多个 key,会合并为一个,保留后写入的 key 和值 | |
| 23 | + * | |
| 24 | + * @author 芋道源码 | |
| 25 | + * @see <a href="https://t.zsxq.com/kPvqm">星球讨论:Map 查询结果的跨数据库兼容问题</a> | |
| 26 | + */ | |
| 27 | +public class CaseInsensitiveResultMap<V> extends LinkedCaseInsensitiveMap<V> { | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 注解 SQL 使用的 resultMap 编号 | |
| 31 | + * | |
| 32 | + * 由 YudaoMybatisAutoConfiguration 注册到 MyBatis 全局配置;包含“.”,所以不会拼接 Mapper 的 namespace | |
| 33 | + */ | |
| 34 | + public static final String RESULT_MAP_ID = "cn.iocoder.yudao.framework.mybatis.core.util.CaseInsensitiveResultMap"; | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 创建空的结果 Map | |
| 38 | + * | |
| 39 | + * 用途:MyBatis 通过无参构造方法,实例化结果行 | |
| 40 | + */ | |
| 41 | + public CaseInsensitiveResultMap() { | |
| 42 | + super(Locale.ROOT); | |
| 43 | + } | |
| 44 | + | |
| 45 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/CaseInsensitiveResultMapTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.util; | |
| 2 | + | |
| 3 | +import cn.hutool.core.map.MapUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 5 | +import org.junit.jupiter.api.Test; | |
| 6 | +import org.springframework.util.LinkedCaseInsensitiveMap; | |
| 7 | + | |
| 8 | +import java.util.*; | |
| 9 | + | |
| 10 | +import static org.junit.jupiter.api.Assertions.*; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * {@link CaseInsensitiveResultMap} 的单元测试 | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +public class CaseInsensitiveResultMapTest { | |
| 18 | + | |
| 19 | + @Test | |
| 20 | + public void testGet_ignoreCase() { | |
| 21 | + // 准备参数 | |
| 22 | + CaseInsensitiveResultMap<Object> map = new CaseInsensitiveResultMap<>(); | |
| 23 | + map.put("conversationId", 1024L); | |
| 24 | + | |
| 25 | + // 调用,并断言:PostgreSQL 小写、Oracle 大写,都可以取到值 | |
| 26 | + assertEquals(1024L, map.get("conversationId")); | |
| 27 | + assertEquals(1024L, map.get("conversationid")); | |
| 28 | + assertEquals(1024L, map.get("CONVERSATIONID")); | |
| 29 | + assertTrue(map.containsKey("CONVERSATIONID")); | |
| 30 | + assertEquals(1024L, MapUtil.getLong(map, "conversationid")); | |
| 31 | + // 断言:保留原始的 key | |
| 32 | + assertEquals(Collections.singletonList("conversationId"), new ArrayList<>(map.keySet())); | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Test | |
| 36 | + public void testPut_nullValue() { | |
| 37 | + // 准备参数 | |
| 38 | + CaseInsensitiveResultMap<Object> map = new CaseInsensitiveResultMap<>(); | |
| 39 | + map.put("sum_count", null); | |
| 40 | + | |
| 41 | + // 调用,并断言 | |
| 42 | + assertTrue(map.containsKey("SUM_COUNT")); | |
| 43 | + assertNull(map.get("SUM_COUNT")); | |
| 44 | + assertEquals(0, MapUtil.getInt(map, "SUM_COUNT", 0)); | |
| 45 | + } | |
| 46 | + | |
| 47 | + @Test | |
| 48 | + public void testPut_sameKeyIgnoreCase() { | |
| 49 | + // 准备参数 | |
| 50 | + CaseInsensitiveResultMap<Object> map = new CaseInsensitiveResultMap<>(); | |
| 51 | + | |
| 52 | + // 调用:仅大小写不同的 key | |
| 53 | + map.put("id", 1L); | |
| 54 | + map.put("ID", 2L); | |
| 55 | + | |
| 56 | + // 断言:合并为一个,保留后写入的 key 和值 | |
| 57 | + assertEquals(1, map.size()); | |
| 58 | + assertEquals(2L, map.get("id")); | |
| 59 | + assertEquals(Collections.singletonList("ID"), new ArrayList<>(map.keySet())); | |
| 60 | + } | |
| 61 | + | |
| 62 | + @Test | |
| 63 | + public void testGet_turkishDefaultLocale() { | |
| 64 | + Locale defaultLocale = Locale.getDefault(); | |
| 65 | + try { | |
| 66 | + // 准备参数:土耳其语下,大写 I 转小写为无点的 ı | |
| 67 | + Locale.setDefault(Locale.forLanguageTag("tr-TR")); | |
| 68 | + CaseInsensitiveResultMap<Object> map = new CaseInsensitiveResultMap<>(); | |
| 69 | + map.put("CONVERSATIONID", 1024L); | |
| 70 | + LinkedCaseInsensitiveMap<Object> defaultLocaleMap = new LinkedCaseInsensitiveMap<>(); | |
| 71 | + defaultLocaleMap.put("CONVERSATIONID", 1024L); | |
| 72 | + | |
| 73 | + // 调用,并断言:固定 Locale.ROOT,不受默认 Locale 影响 | |
| 74 | + assertEquals(1024L, map.get("conversationId")); | |
| 75 | + // 断言:使用默认 Locale 时,取不到值 | |
| 76 | + assertNull(defaultLocaleMap.get("conversationId")); | |
| 77 | + } finally { | |
| 78 | + Locale.setDefault(defaultLocale); | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + @Test | |
| 83 | + public void testConvertMap_numberKey() { | |
| 84 | + // 准备参数:模拟 Oracle 返回的结果行 | |
| 85 | + List<Map<String, Object>> rows = Arrays.asList(buildRow(1024L, 3), buildRow(2048L, 5)); | |
| 86 | + | |
| 87 | + // 调用:业务转换为数字 key 的 Map | |
| 88 | + Map<Long, Integer> result = CollectionUtils.convertMap(rows, | |
| 89 | + row -> MapUtil.getLong(row, "conversationId"), | |
| 90 | + row -> MapUtil.getInt(row, "count")); | |
| 91 | + | |
| 92 | + // 断言:数字 key 的业务 Map 不受影响 | |
| 93 | + assertInstanceOf(HashMap.class, result); | |
| 94 | + assertEquals(3, result.get(1024L)); | |
| 95 | + assertEquals(5, result.get(2048L)); | |
| 96 | + } | |
| 97 | + | |
| 98 | + private static Map<String, Object> buildRow(Long conversationId, Integer count) { | |
| 99 | + CaseInsensitiveResultMap<Object> row = new CaseInsensitiveResultMap<>(); | |
| 100 | + row.put("CONVERSATIONID", conversationId); | |
| 101 | + row.put("COUNT", count); | |
| 102 | + return row; | |
| 103 | + } | |
| 104 | + | |
| 105 | +} | ... | ... |
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 5 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | |
| 6 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | |
| 7 | +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | |
| 8 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 14 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; | |
| 16 | +import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper; | |
| 17 | +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; | |
| 18 | +import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; | |
| 19 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 20 | +import cn.iocoder.yudao.module.ai.service.model.AiModelService; | |
| 21 | +import cn.iocoder.yudao.module.ai.service.model.AiToolService; | |
| 22 | +import lombok.Data; | |
| 23 | +import org.junit.jupiter.api.AfterEach; | |
| 24 | +import org.junit.jupiter.api.Test; | |
| 25 | +import org.mockito.ArgumentCaptor; | |
| 26 | +import org.mockito.InjectMocks; | |
| 27 | +import org.mockito.Mock; | |
| 28 | +import org.springframework.ai.chat.model.ToolContext; | |
| 29 | +import org.springframework.ai.deepseek.DeepSeekChatModel; | |
| 30 | +import org.springframework.ai.deepseek.api.DeepSeekApi; | |
| 31 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletion; | |
| 32 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionChunk; | |
| 33 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionFinishReason; | |
| 34 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage; | |
| 35 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.ChatCompletionFunction; | |
| 36 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.Role; | |
| 37 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.ToolCall; | |
| 38 | +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionRequest; | |
| 39 | +import org.springframework.ai.tool.ToolCallback; | |
| 40 | +import org.springframework.ai.tool.function.FunctionToolCallback; | |
| 41 | +import org.springframework.ai.tool.resolution.ToolCallbackResolver; | |
| 42 | +import org.springframework.http.ResponseEntity; | |
| 43 | +import org.springframework.mock.web.MockHttpServletRequest; | |
| 44 | +import org.springframework.security.core.context.SecurityContextHolder; | |
| 45 | +import reactor.core.publisher.Flux; | |
| 46 | + | |
| 47 | +import java.util.List; | |
| 48 | +import java.util.Map; | |
| 49 | +import java.util.concurrent.CopyOnWriteArrayList; | |
| 50 | +import java.util.concurrent.atomic.AtomicLong; | |
| 51 | +import java.util.stream.Collectors; | |
| 52 | + | |
| 53 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | |
| 54 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_STREAM_ERROR; | |
| 55 | +import static cn.iocoder.yudao.module.ai.util.AiUtils.TOOL_CONTEXT_LOGIN_USER; | |
| 56 | +import static cn.iocoder.yudao.module.ai.util.AiUtils.TOOL_CONTEXT_TENANT_ID; | |
| 57 | +import static java.util.Arrays.asList; | |
| 58 | +import static java.util.Collections.singletonList; | |
| 59 | +import static org.junit.jupiter.api.Assertions.*; | |
| 60 | +import static org.mockito.ArgumentMatchers.any; | |
| 61 | +import static org.mockito.ArgumentMatchers.eq; | |
| 62 | +import static org.mockito.Mockito.*; | |
| 63 | + | |
| 64 | +/** | |
| 65 | + * {@link AiChatMessageServiceImpl} 的单元测试类 | |
| 66 | + * | |
| 67 | + * 使用真实的 {@link DeepSeekChatModel} 和工具调用,仅 mock 底层的 {@link DeepSeekApi} | |
| 68 | + * | |
| 69 | + * @author 芋道源码 | |
| 70 | + */ | |
| 71 | +public class AiChatMessageServiceImplTest extends BaseMockitoUnitTest { | |
| 72 | + | |
| 73 | + private static final String MODEL_NAME = "deepseek-test"; | |
| 74 | + private static final Double TEMPERATURE = 0.5; | |
| 75 | + private static final Integer MAX_TOKENS = 1024; | |
| 76 | + | |
| 77 | + private static final String TOOL_NAME = "query_weather"; | |
| 78 | + private static final String TOOL_RESULT = "杭州:晴,25℃"; | |
| 79 | + private static final ChatCompletionMessage TOOL_CALL_MESSAGE = new ChatCompletionMessage("我来查询一下杭州的天气", | |
| 80 | + Role.ASSISTANT, null, null, singletonList(new ToolCall("call_1", "function", | |
| 81 | + new ChatCompletionFunction(TOOL_NAME, "{\"city\":\"杭州\"}")))); | |
| 82 | + | |
| 83 | + private static final List<String> TOOL_ANSWER_CHUNKS = asList("杭州今天", "晴,25℃"); | |
| 84 | + private static final String TOOL_ANSWER = String.join("", TOOL_ANSWER_CHUNKS); | |
| 85 | + private static final List<String> PLAIN_ANSWER_CHUNKS = asList("你好,", "我是 AI 助手"); | |
| 86 | + private static final String PLAIN_ANSWER = String.join("", PLAIN_ANSWER_CHUNKS); | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * assistant 消息编号:先插入 user 消息(编号 1),再插入 assistant 消息(编号 2) | |
| 90 | + */ | |
| 91 | + private static final Long ASSISTANT_MESSAGE_ID = 2L; | |
| 92 | + | |
| 93 | + @InjectMocks | |
| 94 | + private AiChatMessageServiceImpl chatMessageService; | |
| 95 | + | |
| 96 | + @Mock | |
| 97 | + private AiChatMessageMapper chatMessageMapper; | |
| 98 | + @Mock | |
| 99 | + private AiChatConversationService chatConversationService; | |
| 100 | + @Mock | |
| 101 | + private AiChatRoleService chatRoleService; | |
| 102 | + @Mock | |
| 103 | + private AiModelService modalService; | |
| 104 | + @Mock | |
| 105 | + private AiKnowledgeDocumentService knowledgeDocumentService; | |
| 106 | + @Mock | |
| 107 | + private AiToolService toolService; | |
| 108 | + @Mock | |
| 109 | + private ToolCallbackResolver toolCallbackResolver; | |
| 110 | + @Mock | |
| 111 | + private DeepSeekApi deepSeekApi; | |
| 112 | + | |
| 113 | + @AfterEach | |
| 114 | + public void after() { | |
| 115 | + SecurityContextHolder.clearContext(); | |
| 116 | + TenantContextHolder.clear(); | |
| 117 | + } | |
| 118 | + | |
| 119 | + @Test | |
| 120 | + public void testSendMessage_toolCall() { | |
| 121 | + // 准备参数 | |
| 122 | + Long userId = randomLongId(); | |
| 123 | + Long roleId = randomLongId(); | |
| 124 | + AiChatMessageSendReqVO reqVO = new AiChatMessageSendReqVO().setConversationId(randomLongId()) | |
| 125 | + .setContent("杭州天气怎么样?"); | |
| 126 | + // mock 对话、模型 | |
| 127 | + mockConversation(reqVO.getConversationId(), userId, roleId); | |
| 128 | + // mock 工具 | |
| 129 | + List<ToolContext> toolContexts = new CopyOnWriteArrayList<>(); | |
| 130 | + mockWeatherTool(roleId, toolContexts); | |
| 131 | + // mock 登录用户、租户 | |
| 132 | + Long tenantId = randomLongId(); | |
| 133 | + mockLoginUser(userId, tenantId); | |
| 134 | + // mock deepSeekApi 的方法:先请求工具,再返回回答 | |
| 135 | + when(deepSeekApi.chatCompletionEntity(any())).thenReturn(buildChatCompletion(TOOL_CALL_MESSAGE), | |
| 136 | + buildChatCompletion(new ChatCompletionMessage(TOOL_ANSWER, Role.ASSISTANT))); | |
| 137 | + | |
| 138 | + // 调用 | |
| 139 | + AiChatMessageSendRespVO respVO = chatMessageService.sendMessage(reqVO, userId); | |
| 140 | + // 断言 | |
| 141 | + assertEquals(TOOL_ANSWER, respVO.getReceive().getContent()); | |
| 142 | + ArgumentCaptor<ChatCompletionRequest> requestCaptor = ArgumentCaptor.forClass(ChatCompletionRequest.class); | |
| 143 | + verify(deepSeekApi, times(2)).chatCompletionEntity(requestCaptor.capture()); | |
| 144 | + assertToolExecuted(requestCaptor.getAllValues(), toolContexts, userId, tenantId); | |
| 145 | + // 断言模型参数 | |
| 146 | + ChatCompletionRequest request = requestCaptor.getAllValues().get(0); | |
| 147 | + assertEquals(MODEL_NAME, request.model()); | |
| 148 | + assertEquals(TEMPERATURE, request.temperature()); | |
| 149 | + assertEquals(MAX_TOKENS, request.maxTokens()); | |
| 150 | + // 断言消息保存 | |
| 151 | + assertAssistantMessageUpdated(TOOL_ANSWER); | |
| 152 | + } | |
| 153 | + | |
| 154 | + @Test | |
| 155 | + public void testSendMessage_withoutTool() { | |
| 156 | + // 准备参数 | |
| 157 | + Long userId = randomLongId(); | |
| 158 | + AiChatMessageSendReqVO reqVO = new AiChatMessageSendReqVO().setConversationId(randomLongId()) | |
| 159 | + .setContent("你好"); | |
| 160 | + // mock 对话、模型 | |
| 161 | + mockConversation(reqVO.getConversationId(), userId, null); | |
| 162 | + // mock deepSeekApi 的方法 | |
| 163 | + when(deepSeekApi.chatCompletionEntity(any())) | |
| 164 | + .thenReturn(buildChatCompletion(new ChatCompletionMessage(PLAIN_ANSWER, Role.ASSISTANT))); | |
| 165 | + | |
| 166 | + // 调用 | |
| 167 | + AiChatMessageSendRespVO respVO = chatMessageService.sendMessage(reqVO, userId); | |
| 168 | + // 断言 | |
| 169 | + assertEquals(PLAIN_ANSWER, respVO.getReceive().getContent()); | |
| 170 | + verify(deepSeekApi).chatCompletionEntity(any()); | |
| 171 | + // 断言消息保存 | |
| 172 | + assertAssistantMessageUpdated(PLAIN_ANSWER); | |
| 173 | + } | |
| 174 | + | |
| 175 | + @Test | |
| 176 | + public void testSendMessage_toolCallThenModelError() { | |
| 177 | + // 准备参数 | |
| 178 | + Long userId = randomLongId(); | |
| 179 | + Long roleId = randomLongId(); | |
| 180 | + AiChatMessageSendReqVO reqVO = new AiChatMessageSendReqVO().setConversationId(randomLongId()) | |
| 181 | + .setContent("杭州天气怎么样?"); | |
| 182 | + // mock 对话、模型 | |
| 183 | + mockConversation(reqVO.getConversationId(), userId, roleId); | |
| 184 | + // mock 工具 | |
| 185 | + List<ToolContext> toolContexts = new CopyOnWriteArrayList<>(); | |
| 186 | + mockWeatherTool(roleId, toolContexts); | |
| 187 | + // mock 登录用户、租户 | |
| 188 | + mockLoginUser(userId, randomLongId()); | |
| 189 | + // mock deepSeekApi 的方法:先请求工具,再抛出异常 | |
| 190 | + RuntimeException modelException = new IllegalStateException("模型服务异常"); | |
| 191 | + when(deepSeekApi.chatCompletionEntity(any())).thenReturn(buildChatCompletion(TOOL_CALL_MESSAGE)) | |
| 192 | + .thenThrow(modelException); | |
| 193 | + | |
| 194 | + // 调用,并断言异常 | |
| 195 | + RuntimeException exception = assertThrows(RuntimeException.class, | |
| 196 | + () -> chatMessageService.sendMessage(reqVO, userId)); | |
| 197 | + assertSame(modelException, exception); | |
| 198 | + // 断言工具已执行、消息未保存 | |
| 199 | + verify(deepSeekApi, times(2)).chatCompletionEntity(any()); | |
| 200 | + assertEquals(1, toolContexts.size()); | |
| 201 | + verify(chatMessageMapper, never()).updateById(any(AiChatMessageDO.class)); | |
| 202 | + } | |
| 203 | + | |
| 204 | + @Test | |
| 205 | + public void testSendChatMessageStream_toolCall() { | |
| 206 | + // 准备参数 | |
| 207 | + Long userId = randomLongId(); | |
| 208 | + Long roleId = randomLongId(); | |
| 209 | + AiChatMessageSendReqVO reqVO = new AiChatMessageSendReqVO().setConversationId(randomLongId()) | |
| 210 | + .setContent("杭州天气怎么样?"); | |
| 211 | + // mock 对话、模型 | |
| 212 | + mockConversation(reqVO.getConversationId(), userId, roleId); | |
| 213 | + // mock 工具 | |
| 214 | + List<ToolContext> toolContexts = new CopyOnWriteArrayList<>(); | |
| 215 | + mockWeatherTool(roleId, toolContexts); | |
| 216 | + // mock 登录用户、租户 | |
| 217 | + Long tenantId = randomLongId(); | |
| 218 | + mockLoginUser(userId, tenantId); | |
| 219 | + // mock deepSeekApi 的方法:先请求工具,再流式返回回答 | |
| 220 | + when(deepSeekApi.chatCompletionStream(any())).thenReturn(Flux.just(buildChatCompletionChunk(TOOL_CALL_MESSAGE)), | |
| 221 | + buildAnswerChunks(TOOL_ANSWER_CHUNKS)); | |
| 222 | + | |
| 223 | + // 调用 | |
| 224 | + List<CommonResult<AiChatMessageSendRespVO>> results = chatMessageService | |
| 225 | + .sendChatMessageStream(reqVO, userId).collectList().block(); | |
| 226 | + // 断言(工具调用轮次不下发) | |
| 227 | + assertNotNull(results); | |
| 228 | + assertTrue(results.stream().allMatch(CommonResult::isSuccess)); | |
| 229 | + assertEquals(TOOL_ANSWER, joinContent(results)); | |
| 230 | + ArgumentCaptor<ChatCompletionRequest> requestCaptor = ArgumentCaptor.forClass(ChatCompletionRequest.class); | |
| 231 | + verify(deepSeekApi, times(2)).chatCompletionStream(requestCaptor.capture()); | |
| 232 | + assertToolExecuted(requestCaptor.getAllValues(), toolContexts, userId, tenantId); | |
| 233 | + // 断言消息保存 | |
| 234 | + assertAssistantMessageUpdated(TOOL_ANSWER); | |
| 235 | + } | |
| 236 | + | |
| 237 | + @Test | |
| 238 | + public void testSendChatMessageStream_withoutTool() { | |
| 239 | + // 准备参数 | |
| 240 | + Long userId = randomLongId(); | |
| 241 | + AiChatMessageSendReqVO reqVO = new AiChatMessageSendReqVO().setConversationId(randomLongId()) | |
| 242 | + .setContent("你好"); | |
| 243 | + // mock 对话、模型 | |
| 244 | + mockConversation(reqVO.getConversationId(), userId, null); | |
| 245 | + // mock deepSeekApi 的方法 | |
| 246 | + when(deepSeekApi.chatCompletionStream(any())).thenReturn(buildAnswerChunks(PLAIN_ANSWER_CHUNKS)); | |
| 247 | + | |
| 248 | + // 调用 | |
| 249 | + List<CommonResult<AiChatMessageSendRespVO>> results = chatMessageService | |
| 250 | + .sendChatMessageStream(reqVO, userId).collectList().block(); | |
| 251 | + // 断言 | |
| 252 | + assertNotNull(results); | |
| 253 | + assertTrue(results.stream().allMatch(CommonResult::isSuccess)); | |
| 254 | + assertEquals(PLAIN_ANSWER, joinContent(results)); | |
| 255 | + verify(deepSeekApi).chatCompletionStream(any()); | |
| 256 | + // 断言消息保存 | |
| 257 | + assertAssistantMessageUpdated(PLAIN_ANSWER); | |
| 258 | + } | |
| 259 | + | |
| 260 | + @Test | |
| 261 | + public void testSendChatMessageStream_toolCallThenModelError() { | |
| 262 | + // 准备参数 | |
| 263 | + Long userId = randomLongId(); | |
| 264 | + Long roleId = randomLongId(); | |
| 265 | + AiChatMessageSendReqVO reqVO = new AiChatMessageSendReqVO().setConversationId(randomLongId()) | |
| 266 | + .setContent("杭州天气怎么样?"); | |
| 267 | + // mock 对话、模型 | |
| 268 | + mockConversation(reqVO.getConversationId(), userId, roleId); | |
| 269 | + // mock 工具 | |
| 270 | + List<ToolContext> toolContexts = new CopyOnWriteArrayList<>(); | |
| 271 | + mockWeatherTool(roleId, toolContexts); | |
| 272 | + // mock 登录用户、租户 | |
| 273 | + mockLoginUser(userId, randomLongId()); | |
| 274 | + // mock deepSeekApi 的方法:先请求工具,再返回异常 | |
| 275 | + when(deepSeekApi.chatCompletionStream(any())).thenReturn(Flux.just(buildChatCompletionChunk(TOOL_CALL_MESSAGE)), | |
| 276 | + Flux.error(new IllegalStateException("模型服务异常"))); | |
| 277 | + | |
| 278 | + // 调用 | |
| 279 | + List<CommonResult<AiChatMessageSendRespVO>> results = chatMessageService | |
| 280 | + .sendChatMessageStream(reqVO, userId).collectList().block(); | |
| 281 | + // 断言 | |
| 282 | + assertNotNull(results); | |
| 283 | + assertEquals(CHAT_STREAM_ERROR.getCode(), CollUtil.getLast(results).getCode()); | |
| 284 | + verify(deepSeekApi, times(2)).chatCompletionStream(any()); | |
| 285 | + assertEquals(1, toolContexts.size()); | |
| 286 | + // 断言消息删除(无内容) | |
| 287 | + verify(chatMessageMapper).deleteById(ASSISTANT_MESSAGE_ID); | |
| 288 | + verify(chatMessageMapper, never()).updateById(any(AiChatMessageDO.class)); | |
| 289 | + } | |
| 290 | + | |
| 291 | + private void mockConversation(Long conversationId, Long userId, Long roleId) { | |
| 292 | + // mock 对话 | |
| 293 | + AiChatConversationDO conversation = new AiChatConversationDO().setId(conversationId).setUserId(userId) | |
| 294 | + .setRoleId(roleId).setModelId(randomLongId()).setTemperature(TEMPERATURE).setMaxTokens(MAX_TOKENS); | |
| 295 | + when(chatConversationService.validateChatConversationExists(eq(conversationId))).thenReturn(conversation); | |
| 296 | + // mock 模型:真实的 DeepSeekChatModel | |
| 297 | + AiModelDO model = new AiModelDO().setId(conversation.getModelId()).setModel(MODEL_NAME) | |
| 298 | + .setPlatform(AiPlatformEnum.DEEP_SEEK.getPlatform()); | |
| 299 | + when(modalService.validateModel(eq(model.getId()))).thenReturn(model); | |
| 300 | + when(modalService.getChatModel(eq(model.getId()))) | |
| 301 | + .thenReturn(DeepSeekChatModel.builder().deepSeekApi(deepSeekApi).build()); | |
| 302 | + // mock 消息插入:依次分配编号 | |
| 303 | + AtomicLong messageId = new AtomicLong(); | |
| 304 | + doAnswer(invocation -> { | |
| 305 | + invocation.<AiChatMessageDO>getArgument(0).setId(messageId.incrementAndGet()); | |
| 306 | + return 1; | |
| 307 | + }).when(chatMessageMapper).insert(any(AiChatMessageDO.class)); | |
| 308 | + } | |
| 309 | + | |
| 310 | + private void mockWeatherTool(Long roleId, List<ToolContext> toolContexts) { | |
| 311 | + // mock 工具:真实的 FunctionToolCallback | |
| 312 | + Long toolId = randomLongId(); | |
| 313 | + ToolCallback toolCallback = FunctionToolCallback.<WeatherRequest, String>builder(TOOL_NAME, | |
| 314 | + (request, toolContext) -> { | |
| 315 | + toolContexts.add(toolContext); | |
| 316 | + return request.getCity() + ":晴,25℃"; | |
| 317 | + }).description("查询城市天气").inputType(WeatherRequest.class).build(); | |
| 318 | + when(chatRoleService.getChatRole(eq(roleId))).thenReturn(new AiChatRoleDO().setId(roleId) | |
| 319 | + .setToolIds(singletonList(toolId))); | |
| 320 | + when(toolService.getToolList(eq(singletonList(toolId)))) | |
| 321 | + .thenReturn(singletonList(new AiToolDO().setId(toolId).setName(TOOL_NAME))); | |
| 322 | + when(toolCallbackResolver.resolve(eq(TOOL_NAME))).thenReturn(toolCallback); | |
| 323 | + } | |
| 324 | + | |
| 325 | + private static void mockLoginUser(Long userId, Long tenantId) { | |
| 326 | + SecurityFrameworkUtils.setLoginUser(new LoginUser().setId(userId), new MockHttpServletRequest()); | |
| 327 | + TenantContextHolder.setTenantId(tenantId); | |
| 328 | + } | |
| 329 | + | |
| 330 | + private static void assertToolExecuted(List<ChatCompletionRequest> requests, List<ToolContext> toolContexts, | |
| 331 | + Long userId, Long tenantId) { | |
| 332 | + // 断言首轮请求带上工具 | |
| 333 | + assertEquals(1, requests.get(0).tools().size()); | |
| 334 | + // 断言工具执行,并拿到登录用户、租户 | |
| 335 | + assertEquals(1, toolContexts.size()); | |
| 336 | + Map<String, Object> context = toolContexts.get(0).getContext(); | |
| 337 | + assertEquals(userId, ((LoginUser) context.get(TOOL_CONTEXT_LOGIN_USER)).getId()); | |
| 338 | + assertEquals(tenantId, context.get(TOOL_CONTEXT_TENANT_ID)); | |
| 339 | + // 断言次轮请求回传工具结果 | |
| 340 | + ChatCompletionMessage toolMessage = CollUtil.getLast(requests.get(1).messages()); | |
| 341 | + assertEquals(Role.TOOL, toolMessage.role()); | |
| 342 | + assertTrue(toolMessage.content().contains(TOOL_RESULT)); | |
| 343 | + } | |
| 344 | + | |
| 345 | + private void assertAssistantMessageUpdated(String content) { | |
| 346 | + ArgumentCaptor<AiChatMessageDO> messageCaptor = ArgumentCaptor.forClass(AiChatMessageDO.class); | |
| 347 | + verify(chatMessageMapper).updateById(messageCaptor.capture()); | |
| 348 | + assertEquals(ASSISTANT_MESSAGE_ID, messageCaptor.getValue().getId()); | |
| 349 | + assertEquals(content, messageCaptor.getValue().getContent()); | |
| 350 | + } | |
| 351 | + | |
| 352 | + private static String joinContent(List<CommonResult<AiChatMessageSendRespVO>> results) { | |
| 353 | + return results.stream().map(result -> result.getData().getReceive().getContent()) | |
| 354 | + .collect(Collectors.joining()); | |
| 355 | + } | |
| 356 | + | |
| 357 | + private static ResponseEntity<ChatCompletion> buildChatCompletion(ChatCompletionMessage message) { | |
| 358 | + ChatCompletion.Choice choice = new ChatCompletion.Choice(buildFinishReason(message), 0, message, null); | |
| 359 | + return ResponseEntity.ok(new ChatCompletion("chatcmpl-1", singletonList(choice), null, MODEL_NAME, | |
| 360 | + null, null, null)); | |
| 361 | + } | |
| 362 | + | |
| 363 | + private static Flux<ChatCompletionChunk> buildAnswerChunks(List<String> contents) { | |
| 364 | + return Flux.fromIterable(contents) | |
| 365 | + .map(content -> buildChatCompletionChunk(new ChatCompletionMessage(content, Role.ASSISTANT))); | |
| 366 | + } | |
| 367 | + | |
| 368 | + private static ChatCompletionChunk buildChatCompletionChunk(ChatCompletionMessage delta) { | |
| 369 | + ChatCompletionChunk.ChunkChoice choice = new ChatCompletionChunk.ChunkChoice(buildFinishReason(delta), | |
| 370 | + 0, delta, null); | |
| 371 | + return new ChatCompletionChunk("chatcmpl-1", singletonList(choice), null, MODEL_NAME, | |
| 372 | + null, null, null, null); | |
| 373 | + } | |
| 374 | + | |
| 375 | + private static ChatCompletionFinishReason buildFinishReason(ChatCompletionMessage message) { | |
| 376 | + return CollUtil.isNotEmpty(message.toolCalls()) ? ChatCompletionFinishReason.TOOL_CALLS | |
| 377 | + : ChatCompletionFinishReason.STOP; | |
| 378 | + } | |
| 379 | + | |
| 380 | + @Data | |
| 381 | + public static class WeatherRequest { | |
| 382 | + | |
| 383 | + private String city; | |
| 384 | + | |
| 385 | + } | |
| 386 | + | |
| 387 | +} | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 4 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 6 | 6 | |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | 8 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.AllArgsConstructor; |
| 7 | 5 | import lombok.Data; |
| 8 | 6 | import lombok.NoArgsConstructor; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.math.BigDecimal; |
| 11 | 11 | import java.time.LocalDateTime; | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java
| ... | ... | @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 10 | 8 | import lombok.ToString; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.time.LocalDateTime; |
| 13 | 13 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java
| ... | ... | @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 10 | 8 | import lombok.ToString; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.time.LocalDateTime; |
| 13 | 13 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.AllArgsConstructor; |
| 7 | 5 | import lombok.Data; |
| 8 | 6 | import lombok.NoArgsConstructor; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.math.BigDecimal; |
| 11 | 11 | import java.time.LocalDateTime; | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java
| ... | ... | @@ -5,11 +5,11 @@ import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; |
| 5 | 5 | import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; |
| 6 | 6 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 7 | 7 | import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunction; |
| 8 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 9 | 8 | import lombok.AllArgsConstructor; |
| 10 | 9 | import lombok.Builder; |
| 11 | 10 | import lombok.Data; |
| 12 | 11 | import lombok.NoArgsConstructor; |
| 12 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 13 | 13 | |
| 14 | 14 | import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; |
| 15 | 15 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | 12 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | import java.util.List; | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | 6 | |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | 8 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryListReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.product.vo.category; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 4 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 6 | 6 | |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | 8 | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java
| ... | ... | @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; |
| 6 | 6 | import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; |
| 7 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 8 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | import org.dromara.core.trans.anno.Trans; |
| 10 | 10 | import org.dromara.core.trans.constant.TransType; |
| 11 | 11 | import org.dromara.core.trans.vo.VO; | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; |
| 4 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 5 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 6 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java
| ... | ... | @@ -4,10 +4,10 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; |
| 6 | 6 | import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; |
| 7 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 8 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 9 | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 10 | 8 | import lombok.Data; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.math.BigDecimal; |
| 13 | 13 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.module.system.enums.DictTypeConstants; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.product.vo.category; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.system.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | 12 | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.module.system.enums.DictTypeConstants; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.system.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.math.BigDecimal; |
| 12 | 12 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 4 | +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 3 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 6 | import lombok.*; |
| 7 | +import org.apache.fesod.sheet.annotation.*; | |
| 8 | + | |
| 5 | 9 | import java.math.BigDecimal; |
| 6 | 10 | import java.time.LocalDateTime; |
| 7 | -import cn.idev.excel.annotation.*; | |
| 8 | -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 9 | -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 10 | 11 | |
| 11 | 12 | @Schema(description = "管理后台 - ERP 客户 Response VO") |
| 12 | 13 | @Data | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java
| ... | ... | @@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import jakarta.validation.constraints.NotNull; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.math.BigDecimal; |
| 12 | 12 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.math.BigDecimal; |
| 11 | 11 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.math.BigDecimal; |
| 11 | 11 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.math.BigDecimal; |
| 11 | 11 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.erp.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.math.BigDecimal; |
| 12 | 12 | import java.time.LocalDateTime; | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | ... | ... |
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.system.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.math.BigDecimal; |
| 12 | 12 | import java.time.LocalDateTime; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/config/vo/auxiliaryitem/FmsAuxiliaryItemImportExcelVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.config.vo.auxiliaryitem; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 4 | 3 | import jakarta.validation.constraints.NotBlank; |
| 5 | 4 | import jakarta.validation.constraints.Size; |
| 6 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | /** |
| 9 | 9 | * FMS 辅助核算项目 Excel 导入 VO | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/config/vo/auxiliaryitem/FmsAuxiliaryItemRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.config.vo.auxiliaryitem; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.time.LocalDateTime; |
| 9 | 9 | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/config/vo/initialbalance/FmsInitialBalanceExcelVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.config.vo.initialbalance; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import lombok.Data; |
| 4 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 6 | 6 | |
| 7 | 7 | import java.math.BigDecimal; |
| 8 | 8 | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/config/vo/subject/FmsSubjectImportExcelVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.config.vo.subject; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 4 | 3 | import jakarta.validation.constraints.NotBlank; |
| 5 | 4 | import lombok.AllArgsConstructor; |
| 6 | 5 | import lombok.Builder; |
| 7 | 6 | import lombok.Data; |
| 8 | 7 | import lombok.NoArgsConstructor; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | /** |
| 11 | 11 | * FMS 科目 Excel 导入 VO | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/config/vo/subject/FmsSubjectRespVO.java
| ... | ... | @@ -4,11 +4,11 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.framework.excel.core.convert.StringListConvert; |
| 6 | 6 | import cn.iocoder.yudao.module.fms.enums.DictTypeConstants; |
| 7 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 8 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 9 | 7 | import com.fasterxml.jackson.annotation.JsonIgnore; |
| 10 | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 11 | 9 | import lombok.Data; |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 11 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 12 | 12 | |
| 13 | 13 | import java.time.LocalDateTime; |
| 14 | 14 | import java.util.List; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/auxiliarybalance/FmsLedgerAuxiliaryBalanceRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.auxiliarybalance; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 7 | 5 | import lombok.experimental.Accessors; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/auxiliarydetail/FmsLedgerAuxiliaryDetailRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.auxiliarydetail; |
| 2 | 2 | |
| 3 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; |
| 4 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 5 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 6 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDate; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/detail/FmsLedgerDetailExportRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.detail; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import lombok.Data; |
| 4 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 6 | 6 | |
| 7 | 7 | import java.math.BigDecimal; |
| 8 | 8 | import java.time.LocalDate; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/detail/FmsLedgerDetailRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.detail; |
| 2 | 2 | |
| 3 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; |
| 4 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 5 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 6 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDate; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/general/FmsLedgerGeneralRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.general; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/quantitydetail/FmsLedgerQuantityDetailRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.quantitydetail; |
| 2 | 2 | |
| 3 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; |
| 4 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 5 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 6 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDate; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/quantitygeneral/FmsLedgerQuantityGeneralRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.quantitygeneral; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnore; | |
| 4 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 5 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 6 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnore; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.util.ArrayList; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/ledger/vo/subjectbalance/FmsLedgerSubjectBalanceRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.ledger.vo.subjectbalance; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 7 | 5 | import lombok.experimental.Accessors; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.util.ArrayList; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/report/vo/FmsReportItemRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.report.vo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/report/vo/balance/FmsBalanceSheetRowRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.report.vo.balance; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/voucher/vo/FmsVoucherExportRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.voucher.vo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | -import cn.idev.excel.annotation.format.DateTimeFormat; | |
| 6 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | +import org.apache.fesod.sheet.annotation.format.DateTimeFormat; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-fms/src/main/java/cn/iocoder/yudao/module/fms/controller/admin/voucher/vo/FmsVoucherStatisticsRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.fms.controller.admin.voucher.vo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/clock/HrmAttendanceClockRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.clock; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 6 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 7 | 5 | import cn.iocoder.yudao.module.hrm.enums.DictTypeConstants; |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.math.BigDecimal; |
| 12 | 12 | import java.time.LocalDateTime; | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/leave/HrmAttendanceLeaveRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.leave; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 6 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 7 | 5 | import cn.iocoder.yudao.module.hrm.enums.DictTypeConstants; |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.math.BigDecimal; |
| 12 | 12 | import java.time.LocalDateTime; | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/statistics/HrmAttendanceDailyDetailRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.statistics; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.clock.HrmAttendanceClockRespVO; |
| 6 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | 5 | import lombok.Data; |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 8 | 8 | |
| 9 | 9 | import java.math.BigDecimal; |
| 10 | 10 | import java.time.LocalDateTime; | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/statistics/HrmAttendanceMonthRecordRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.statistics; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.math.BigDecimal; |
| 9 | 9 | import java.time.LocalDateTime; | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/employee/HrmEmployeeImportExcelVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.employee; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; |
| 6 | 4 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 7 | 5 | import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; |
| ... | ... | @@ -14,6 +12,8 @@ import lombok.AllArgsConstructor; |
| 14 | 12 | import lombok.Builder; |
| 15 | 13 | import lombok.Data; |
| 16 | 14 | import lombok.NoArgsConstructor; |
| 15 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 16 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 17 | 17 | |
| 18 | 18 | import java.time.LocalDateTime; |
| 19 | 19 | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/employee/HrmEmployeeRespVO.java
| ... | ... | @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.employee; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.hrm.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 10 | 8 | import lombok.experimental.Accessors; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.time.LocalDateTime; |
| 13 | 13 | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/changerecord/HrmSalaryChangeRecordRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.changerecord; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 6 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 7 | 5 | import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.option.HrmSalaryOptionValueVO; |
| 8 | 6 | import cn.iocoder.yudao.module.hrm.enums.DictTypeConstants; |
| 9 | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 10 | 8 | import lombok.Data; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.math.BigDecimal; |
| 13 | 13 | import java.time.LocalDateTime; | ... | ... |
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/employeeinfo/HrmSalaryEmployeeInfoRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.employeeinfo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 6 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 7 | 5 | import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.option.HrmSalaryOptionValueVO; |
| 8 | 6 | import cn.iocoder.yudao.module.hrm.enums.DictTypeConstants; |
| 9 | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 10 | 8 | import lombok.Data; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.math.BigDecimal; |
| 13 | 13 | import java.time.LocalDateTime; | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapper.java
| 1 | 1 | package cn.iocoder.yudao.module.im.dal.mysql.statistics; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.util.CaseInsensitiveResultMap; | |
| 3 | 4 | import org.apache.ibatis.annotations.Mapper; |
| 4 | 5 | import org.apache.ibatis.annotations.Param; |
| 6 | +import org.apache.ibatis.annotations.ResultMap; | |
| 5 | 7 | import org.apache.ibatis.annotations.Select; |
| 6 | 8 | |
| 7 | 9 | import java.time.LocalDateTime; |
| ... | ... | @@ -59,6 +61,7 @@ public interface ImStatisticsManagerMapper { |
| 59 | 61 | @Select("SELECT DATE(create_time) AS date, COUNT(*) AS count FROM system_users " + |
| 60 | 62 | "WHERE deleted = 0 AND create_time >= #{beginTime} AND create_time < #{endTime} " + |
| 61 | 63 | "GROUP BY DATE(create_time)") |
| 64 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 62 | 65 | List<Map<String, Object>> selectNewUserDailyCount(@Param("beginTime") LocalDateTime beginTime, |
| 63 | 66 | @Param("endTime") LocalDateTime endTime); |
| 64 | 67 | |
| ... | ... | @@ -74,6 +77,7 @@ public interface ImStatisticsManagerMapper { |
| 74 | 77 | " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION + |
| 75 | 78 | " AND send_time >= #{beginTime} AND send_time < #{endTime}" + |
| 76 | 79 | ") t GROUP BY day") |
| 80 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 77 | 81 | List<Map<String, Object>> selectActiveUserDailyCount(@Param("beginTime") LocalDateTime beginTime, @Param("endTime") LocalDateTime endTime); |
| 78 | 82 | |
| 79 | 83 | // ==================== 群 ==================== |
| ... | ... | @@ -111,6 +115,7 @@ public interface ImStatisticsManagerMapper { |
| 111 | 115 | " GROUP BY g.id" + |
| 112 | 116 | ") t " + |
| 113 | 117 | "GROUP BY `range`") |
| 118 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 114 | 119 | List<Map<String, Object>> selectGroupSizeDistribution(); |
| 115 | 120 | |
| 116 | 121 | // ==================== 消息 ==================== |
| ... | ... | @@ -140,6 +145,7 @@ public interface ImStatisticsManagerMapper { |
| 140 | 145 | "WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION + |
| 141 | 146 | " AND send_time >= #{beginTime} AND send_time < #{endTime} " + |
| 142 | 147 | "GROUP BY DATE(send_time)") |
| 148 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 143 | 149 | List<Map<String, Object>> selectPrivateMessageDailyCount(@Param("beginTime") LocalDateTime beginTime, |
| 144 | 150 | @Param("endTime") LocalDateTime endTime); |
| 145 | 151 | |
| ... | ... | @@ -150,6 +156,7 @@ public interface ImStatisticsManagerMapper { |
| 150 | 156 | "WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION + |
| 151 | 157 | " AND send_time >= #{beginTime} AND send_time < #{endTime} " + |
| 152 | 158 | "GROUP BY DATE(send_time)") |
| 159 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 153 | 160 | List<Map<String, Object>> selectGroupMessageDailyCount(@Param("beginTime") LocalDateTime beginTime, |
| 154 | 161 | @Param("endTime") LocalDateTime endTime); |
| 155 | 162 | |
| ... | ... | @@ -167,6 +174,7 @@ public interface ImStatisticsManagerMapper { |
| 167 | 174 | " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION + |
| 168 | 175 | " AND send_time >= #{beginTime} AND send_time < #{endTime}" + |
| 169 | 176 | ") t GROUP BY type") |
| 177 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 170 | 178 | List<Map<String, Object>> selectMessageTypeDistribution(@Param("beginTime") LocalDateTime beginTime, |
| 171 | 179 | @Param("endTime") LocalDateTime endTime); |
| 172 | 180 | |
| ... | ... | @@ -184,6 +192,7 @@ public interface ImStatisticsManagerMapper { |
| 184 | 192 | " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION + |
| 185 | 193 | " AND send_time >= #{beginTime} AND send_time < #{endTime}" + |
| 186 | 194 | ") t GROUP BY user_id ORDER BY messageCount DESC LIMIT #{limit}") |
| 195 | + @ResultMap(CaseInsensitiveResultMap.RESULT_MAP_ID) | |
| 187 | 196 | List<Map<String, Object>> selectTopSenders(@Param("beginTime") LocalDateTime beginTime, |
| 188 | 197 | @Param("endTime") LocalDateTime endTime, |
| 189 | 198 | @Param("limit") int limit); | ... | ... |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapperTest.java
| ... | ... | @@ -228,6 +228,9 @@ public class ImStatisticsManagerMapperTest extends BaseDbUnitTest { |
| 228 | 228 | assertEquals(3L, ((Number) tops.get(0).get("messageCount")).longValue()); |
| 229 | 229 | assertEquals(2L, ((Number) tops.get(1).get("userId")).longValue()); |
| 230 | 230 | assertEquals(2L, ((Number) tops.get(1).get("messageCount")).longValue()); |
| 231 | + // 断言:key 大小写不敏感,兼容 PostgreSQL 小写、Oracle 大写的列标签 | |
| 232 | + assertEquals(1L, ((Number) tops.get(0).get("userid")).longValue()); | |
| 233 | + assertEquals(3L, ((Number) tops.get(0).get("MESSAGECOUNT")).longValue()); | |
| 231 | 234 | } |
| 232 | 235 | |
| 233 | 236 | // ========== 工具方法 ========== | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.config.vo; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | 12 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import lombok.Data; |
| 5 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 6 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 7 | 7 | |
| 8 | 8 | import java.time.LocalDateTime; |
| 9 | 9 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/erp/vo/Demo03StudentErpRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.erp.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/inner/vo/Demo03StudentInnerRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.inner.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/normal/vo/Demo03StudentNormalRespVO.java
| ... | ... | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.normal.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 6 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 7 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 6 | import lombok.Data; |
| 7 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobRespVO.java
| ... | ... | @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.infra.controller.admin.job.vo.job; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import jakarta.validation.constraints.NotNull; |
| 10 | 8 | import lombok.Data; |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 10 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 11 | 11 | |
| 12 | 12 | import java.time.LocalDateTime; |
| 13 | 13 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.job.vo.log; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | 12 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | 12 | ... | ... |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java
| ... | ... | @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; |
| 6 | -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 8 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | 7 | import lombok.Data; |
| 8 | +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; | |
| 9 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 10 | 10 | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | 12 | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/controller/vo/importExcelVO.vm
| 1 | 1 | package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; |
| 2 | 2 | |
| 3 | -import cn.idev.excel.annotation.ExcelProperty; | |
| 3 | +import org.apache.fesod.sheet.annotation.ExcelProperty; | |
| 4 | 4 | import lombok.AllArgsConstructor; |
| 5 | 5 | import lombok.Builder; |
| 6 | 6 | import lombok.Data; | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/controller/vo/respVO.vm
| ... | ... | @@ -19,7 +19,7 @@ import java.time.LocalDateTime; |
| 19 | 19 | #end |
| 20 | 20 | #end |
| 21 | 21 | ## 处理 Excel 导出 |
| 22 | -import cn.idev.excel.annotation.*; | |
| 22 | +import org.apache.fesod.sheet.annotation.*; | |
| 23 | 23 | #foreach ($column in $columns) |
| 24 | 24 | #if ("$!column.dictType" != "")## 有设置数据字典 |
| 25 | 25 | import ${DictFormatClassName}; | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/dal/do.vm
| ... | ... | @@ -15,7 +15,7 @@ import ${BaseDOClassName}; |
| 15 | 15 | ## 处理 Excel 导出 + Schema 注解(仅 DO 模式) |
| 16 | 16 | #if ($voType == 20) |
| 17 | 17 | import io.swagger.v3.oas.annotations.media.Schema; |
| 18 | -import cn.idev.excel.annotation.*; | |
| 18 | +import org.apache.fesod.sheet.annotation.*; | |
| 19 | 19 | #foreach ($column in $columns) |
| 20 | 20 | #if ("$!column.dictType" != "")## 有设置数据字典 |
| 21 | 21 | import ${DictFormatClassName}; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentRespVO
| ... | ... | @@ -5,7 +5,7 @@ import lombok.*; |
| 5 | 5 | import java.util.*; |
| 6 | 6 | import org.springframework.format.annotation.DateTimeFormat; |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | -import cn.idev.excel.annotation.*; | |
| 8 | +import org.apache.fesod.sheet.annotation.*; | |
| 9 | 9 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 10 | 10 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentRespVO
| ... | ... | @@ -5,7 +5,7 @@ import lombok.*; |
| 5 | 5 | import java.util.*; |
| 6 | 6 | import org.springframework.format.annotation.DateTimeFormat; |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | -import cn.idev.excel.annotation.*; | |
| 8 | +import org.apache.fesod.sheet.annotation.*; | |
| 9 | 9 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 10 | 10 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentRespVO
| ... | ... | @@ -5,7 +5,7 @@ import lombok.*; |
| 5 | 5 | import java.util.*; |
| 6 | 6 | import org.springframework.format.annotation.DateTimeFormat; |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | -import cn.idev.excel.annotation.*; | |
| 8 | +import org.apache.fesod.sheet.annotation.*; | |
| 9 | 9 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 10 | 10 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 11 | 11 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentRespVO
| ... | ... | @@ -5,7 +5,7 @@ import lombok.*; |
| 5 | 5 | import java.util.*; |
| 6 | 6 | import org.springframework.format.annotation.DateTimeFormat; |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | -import cn.idev.excel.annotation.*; | |
| 8 | +import org.apache.fesod.sheet.annotation.*; | |
| 9 | 9 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 10 | 10 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 11 | 11 | ... | ... |