diff --git a/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ExportCSV.java b/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/ExportCSVReportFormPlugin.java similarity index 54% rename from sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ExportCSV.java rename to sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/ExportCSVReportFormPlugin.java index 3b38e6d..fe8442f 100644 --- a/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ExportCSV.java +++ b/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/ExportCSVReportFormPlugin.java @@ -1,4 +1,4 @@ -package shkd.sys.sys.plugin.report.util; +package shkd.sys.sys.plugin.report; import dm.jdbc.util.StringUtil; import kd.bos.cache.CacheFactory; @@ -7,12 +7,17 @@ import kd.bos.dataentity.entity.DynamicObjectCollection; import kd.bos.dataentity.metadata.IMetadata; import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection; import kd.bos.entity.MainEntityType; +import kd.bos.entity.NumberFormatProvider; +import kd.bos.entity.datamodel.FmtField; +import kd.bos.entity.report.AbstractReportColumn; import kd.bos.entity.report.IReportListModel; +import kd.bos.entity.report.ReportColumn; import kd.bos.form.control.Toolbar; import kd.bos.form.control.events.ItemClickEvent; import kd.bos.report.ReportList; import kd.bos.report.plugin.AbstractReportFormPlugin; -import org.apache.commons.io.FileUtils; +import kd.bos.report.proxy.ReportListProxy; +import shkd.sys.sys.plugin.report.util.CsvExportUtil; import java.io.IOException; import java.nio.file.Files; @@ -22,9 +27,10 @@ import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; -import java.util.stream.IntStream; -public class ExportCSV extends AbstractReportFormPlugin { +import static shkd.sys.sys.plugin.report.util.ReportUtils.processFieldValue; + +public class ExportCSVReportFormPlugin extends AbstractReportFormPlugin { @Override public void registerListener(EventObject e) { @@ -34,45 +40,69 @@ public class ExportCSV extends AbstractReportFormPlugin { // 监听工具栏这个按钮的点击事件 export.addItemClickListener(this); export.addClickListener(this); + } + /** + * 处理列表项点击事件,当点击的项为 "shkd_exportcsv" 时,执行导出 CSV 文件的操作。 + * + * @param evt 列表项点击事件对象,包含被点击项的相关信息 + */ @Override public void itemClick(ItemClickEvent evt) { super.itemClick(evt); String itemKey = evt.getItemKey(); if (StringUtil.equals("shkd_exportcsv", itemKey)) { + // 获取数据实体类型及其属性集合 MainEntityType dataEntityType = this.getModel().getDataEntityType(); DataEntityPropertyCollection properties = dataEntityType.getProperties(); String reportName = dataEntityType.getDisplayName().getLocaleValue(); - List keyHeaders = properties.stream() - .filter(Objects::nonNull) - .map(IMetadata::getName) - .collect(Collectors.toList()); - List headers = properties.stream() - .filter(Objects::nonNull) - .filter(o -> Objects.nonNull(o.getDisplayName())) - .map(o -> o.getDisplayName().getLocaleValue()) + // 获取报表列表控件及模型,并取得行数和列信息 + ReportList reportList = this.getControl("reportlistap"); + IReportListModel reportListModel = reportList.getReportModel(); + int rowCount = reportListModel.getRowCount(); + ReportListProxy reportListProxy = new ReportListProxy(reportList); + List columns = reportListProxy.getColumnList(reportListModel); + List cols = reportListProxy.getReportColumnList(columns, true); + + // 获取所有行数据并初始化数字格式化提供器 + DynamicObjectCollection rowData = reportListModel.getRowData(0, rowCount, false); + NumberFormatProvider numberFormatProvider = ReportColumn.initNumberFormatProvider(rowData, cols); + + // 提取需要导出的字段名(排除 fseq 字段) + List headerKeys = numberFormatProvider.getFmtFields().stream() + .filter(o -> !Objects.equals(o.getFieldName(), "fseq")) + .map(FmtField::getFieldName) .collect(Collectors.toList()); - String timestamp = LocalDateTime.now() - .format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")); + // 构建属性名到显示名称的映射表,便于快速查找 + Map nameToDisplay = + properties.stream() + .filter(Objects::nonNull) + .filter(p -> p.getDisplayName() != null) + .collect(Collectors.toMap( + IMetadata::getName, + p -> p.getDisplayName().getLocaleValue(), + (v1, v2) -> v1)); - int random = ThreadLocalRandom.current().nextInt(100, 1000); // 3 位随机数 - - String reportNameExt = timestamp + random; - - IReportListModel reportList = ((ReportList) this.getControl("reportlistap")).getReportModel(); - int rowCount = reportList.getRowCount(); - - DynamicObjectCollection rowData = reportList.getRowData(0, rowCount, false); + // 按照字段顺序获取对应的显示名称,缺失则使用空字符串 + List headers = headerKeys.stream() + .map(k -> nameToDisplay.getOrDefault(k, "")) + .collect(Collectors.toList()); + // 构造每一行的数据列表,处理复杂对象的name属性及本地化 List> rows2 = rowData.stream() - .map(obj -> keyHeaders.stream() - .map(obj::get) // 使用 DynamicObject 的 get 方法获取属性值 + .map(obj -> headerKeys.stream() + .map(key -> processFieldValue(obj.get(key))) .collect(Collectors.toList())) .collect(Collectors.toList()); + // 生成时间戳和随机数作为文件名的一部分 + String timestamp = LocalDateTime.now() + .format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")); + int random = ThreadLocalRandom.current().nextInt(100, 1000); // 3 位随机数 + String reportNameExt = timestamp + random; try { // 定义本地测试目录和完整文件路径 @@ -84,8 +114,8 @@ public class ExportCSV extends AbstractReportFormPlugin { // // Path tempFile = dirPath.resolve(reportName + reportNameExt + ".csv"); // CsvExportUtil.writeCsvToFile(tempFile, headers, rows2); -// -// // 打印文件路径用于本地验证 + + // 打印文件路径用于本地验证 // System.out.println("CSV 文件已保存至: " + tempFile.toAbsolutePath()); Path tempFile = Files.createTempFile(reportName + reportNameExt, ".csv"); diff --git a/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ReportUtils.java b/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ReportUtils.java index d0d414b..b4c92a5 100644 --- a/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ReportUtils.java +++ b/sys/shkd-sys-sys/src/main/java/shkd/sys/sys/plugin/report/util/ReportUtils.java @@ -49,4 +49,63 @@ public class ReportUtils { } return filters; } + + /** + * 处理字段值,支持简单值和复杂对象(如含name属性的对象) + * + * @param value 原始字段值 + * @return 处理后的字符串值 + */ + public static Object processFieldValue(Object value) { + if (value == null) { + return ""; + } + + // 如果是DynamicObject或类似结构,尝试获取name属性 + try { + // 尝试调用get("name")方法获取name属性 + Object nameValue = value.getClass().getMethod("get", String.class).invoke(value, "name"); + if (nameValue != null) { + // 如果name是一个本地化对象,则进一步处理 + return processLocalizedValue(nameValue); + } + // 如果没有name属性,直接返回原值的toString() + return value.toString(); + } catch (Exception e) { + // 如果调用失败,说明不是复杂对象,直接返回toString() + return value.toString(); + } + } + + /** + * 处理本地化值对象,优先获取ZH_TW,其次ZH_CN + * + * @param localizedObj 本地化对象 + * @return 对应语言的值 + */ + public static String processLocalizedValue(Object localizedObj) { + if (localizedObj == null) { + return ""; + } + + try { + + // 尝试获取ZH_CN本地化值 + Object zhCnValue = localizedObj.getClass().getMethod("get", String.class).invoke(localizedObj, "zh_CN"); + if (zhCnValue != null) { + return zhCnValue.toString(); + } +// // 尝试获取ZH_TW本地化值 +// Object zhTwValue = localizedObj.getClass().getMethod("get", String.class).invoke(localizedObj, "zh_TW"); +// if (zhTwValue != null) { +// return zhTwValue.toString(); +// } + + // 都没有则返回默认toString() + return localizedObj.toString(); + } catch (Exception e) { + // 异常情况下返回toString() + return localizedObj.toString(); + } + } }