package shkd.repc.repmd.template; import kd.bos.context.RequestContext; import kd.bos.dataentity.entity.DynamicObject; import kd.bos.dataentity.entity.DynamicObjectCollection; import kd.bos.dataentity.utils.StringUtils; import kd.bos.entity.ExtendedDataEntity; import kd.bos.entity.plugin.AbstractOperationServicePlugIn; import kd.bos.entity.plugin.AddValidatorsEventArgs; import kd.bos.entity.plugin.args.AfterOperationArgs; import kd.bos.entity.validate.AbstractValidator; import kd.bos.form.*; import kd.bos.form.control.Control; import kd.bos.form.control.EntryGrid; import kd.bos.form.control.events.ItemClickEvent; import kd.bos.form.events.MessageBoxClosedEvent; import kd.bos.form.plugin.AbstractFormPlugin; import kd.bos.orm.query.QCP; import kd.bos.orm.query.QFilter; import kd.bos.servicehelper.BusinessDataServiceHelper; import kd.sdk.plugin.Plugin; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import shkd.repc.repmd.template.util.ExportTemplateUtil; import shkd.repc.repmd.template.util.Template; import java.math.BigDecimal; import java.util.*; /** * 面积数据导出-二开插件 */ public class AreaDataExportPlugin extends AbstractFormPlugin implements Plugin { @Override public void registerListener(EventObject e) { super.registerListener(e); this.addItemClickListeners("qeug_advcontoolbarap"); } @Override public void itemClick(ItemClickEvent evt) { super.itemClick(evt); if (StringUtils.equals("qeug_areadataexport", evt.getItemKey())) { DynamicObjectCollection productEntry = this.getModel().getEntryEntity("productentry"); if (null==productEntry||productEntry.size()==0){ this.getView().showMessage("暂无可导出数据!"); return; } EntryGrid entryGrid = this.getControl("productentry"); int[] selectRows = entryGrid.getSelectRows(); String top="导出确认提示"; String body; //默认导出 if (selectRows.length==0){ body = "默认导出所有【产品构成】数据?"; this.showExportMessage(top,body,"default"); }else { body = "导出 " + selectRows.length + " 行【产品构成】数据?"; this.showExportMessage(top,body,"select"); } } } @Override public void confirmCallBack(MessageBoxClosedEvent evt) { super.confirmCallBack(evt); String callBackId = evt.getCallBackId(); StringBuilder tipsBuffer = new StringBuilder(); if (StringUtils.equalsIgnoreCase("export_area", callBackId) && evt.getResult().getValue() == 6) { String customValue = evt.getCustomVaule(); boolean isDefaultExport = "default".equals(customValue); // 获取模板 DynamicObject templateObj = getTemplate(); if (templateObj == null) { return; } // 读取系统模板 Control productView = this.getView().getControl("productentry"); Control areaView = this.getView().getControl("qeug_subentryentity"); List<Template> templateList = ExportTemplateUtil.readSysTemplate(templateObj, productView, areaView, tipsBuffer); if (templateList.isEmpty()) { return; } // 创建 Excel XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = createExcelSheet(workbook, templateList, areaView); // 获取表头信息(第三行) List<String> columnHeaders = getColumnHeaders(sheet); // 获取数据 DynamicObjectCollection productEntry = this.getModel().getEntryEntity("productentry"); List<DynamicObject> exportData = isDefaultExport ? new ArrayList<>(productEntry) : getSelectedData(productEntry); // 填充数据 fillExcelData(sheet, exportData, columnHeaders); // 上传文件并提供下载链接 exportAndDownload(workbook, customValue); tipsBuffer.append("导出成功"); this.getView().showSuccessNotification(tipsBuffer.toString()); } } /** * 获取模板对象 */ private DynamicObject getTemplate() { QFilter numberFilter = new QFilter("number", QCP.equals, "repmd_projectbill_IMPT_ENTRY"); return BusinessDataServiceHelper.loadSingle("bos_importentry_template", numberFilter.toArray()); } /** * 创建 Excel Sheet 并填充标题、描述、表头等 */ private XSSFSheet createExcelSheet(XSSFWorkbook workbook, List<Template> templateList, Control areaView) { XSSFSheet sheet = workbook.createSheet("产品构成 # productentry"); ExportTemplateUtil.createTitleRow(sheet, workbook); ExportTemplateUtil.createDescriptionRow(sheet, workbook); ExportTemplateUtil.createTemplateHeaders(sheet, workbook, templateList); ExportTemplateUtil.otherStyleSet(sheet, areaView); return sheet; } /** * 获取第三行的表头信息 */ private List<String> getColumnHeaders(XSSFSheet sheet) { List<String> columnHeaders = new ArrayList<>(); XSSFRow thirdRow = sheet.getRow(2); if (thirdRow != null) { for (int cellIndex = 0; cellIndex < thirdRow.getLastCellNum(); cellIndex++) { XSSFCell cell = thirdRow.getCell(cellIndex); columnHeaders.add(cell != null ? cell.getStringCellValue().trim() : ""); // 避免 null } } return columnHeaders; } /** * 获取选中的数据 */ private List<DynamicObject> getSelectedData(DynamicObjectCollection productEntry) { List<DynamicObject> selectedData = new ArrayList<>(); EntryGrid entryGrid = this.getControl("productentry"); int[] selectedRows = entryGrid.getSelectRows(); for (int row : selectedRows) { selectedData.add(productEntry.get(row)); } return selectedData; } /** * 填充 Excel 数据 */ private void fillExcelData(XSSFSheet sheet, List<DynamicObject> productEntries, List<String> columnHeaders) { int rowIndex = 4; // 从 Excel 第 5 行开始填充 for (DynamicObject productObj : productEntries) { if (productObj == null) continue; String productTypeNumber = productObj.getString("productentry_producttype.number"); String productTypeName = productObj.getString("productentry_producttype.name"); DynamicObjectCollection areaEntries = productObj.getDynamicObjectCollection("qeug_subentryentity"); if (areaEntries != null && !areaEntries.isEmpty()) { for (DynamicObject areaObj : areaEntries) { XSSFRow dataRow = sheet.createRow(rowIndex); int cellIndex = 0; for (String header : columnHeaders) { XSSFCell cell = dataRow.createCell(cellIndex); if ("productentry_producttype.number".equals(header)) { cell.setCellValue(productTypeNumber); } else if ("productentry_producttype.name".equals(header)) { cell.setCellValue(productTypeName); } else { Object value = areaObj.get(header); setCellValue(cell, value); } cellIndex++; } rowIndex++; } } } } /** * 设置 Excel 单元格值 */ private void setCellValue(XSSFCell cell, Object value) { if (value instanceof String) { cell.setCellValue((String) value); } else if (value instanceof BigDecimal) { cell.setCellValue(((BigDecimal) value).doubleValue()); } else if (value instanceof Integer) { cell.setCellValue((Integer) value); } else if (value instanceof Double) { cell.setCellValue((Double) value); } else if (value != null) { cell.setCellValue(value.toString()); } } /** * 导出 Excel 并提供下载链接 */ private void exportAndDownload(XSSFWorkbook workbook, String fileName) { String uploadedFilePath = ExportTemplateUtil.uploadExcel(workbook, fileName); String url = RequestContext.get().getClientFullContextPath() + "/attachment/download.do?path=" + uploadedFilePath; this.getView().openUrl(url); } private void showExportMessage(String top,String body,String customValue){ // 基本信息 // 备注: \r\n 可换行 //String msg = "消息头\r\n message header..."; // 详细消息 //String detail = "消息体\r\nmessage body..."; // 消息框按钮类型 // None:不启用 Toast:简短提示,几秒后消失 MessageBoxOptions options = MessageBoxOptions.OKCancel; // 确认提示类型 // Default:默认提示 Save:保存提交类提示 Delete:删除类提示 Wait:等待类提示 Fail:失败类提示 ConfirmTypes confirmTypes = ConfirmTypes.Default; // 确认框回调 ConfirmCallBackListener callBack = new ConfirmCallBackListener("export_area", this); // 按钮名称 // 注意: 按钮名称参数Map的key值必须和 options 参数相对应, 否则按钮名称修改不生效! // 例: options 使用 MessageBoxOptions.OKCancel, 则 按钮名称参数Map的key必须为2 or 6 // options 使用 MessageBoxOptions.AbortRetryIgnore, 则 按钮名称参数Map的key必须为3 or 4 or 5 // none-0; ok-1; cancel-2; abort-3; retry-4; ignore-5; yes-6; no-7; custom-8 // ----------------------------------------------------------------- // options | btnNameMaps的key的取值 // MessageBoxOptions.None | 2 // MessageBoxOptions.OK | 2 // MessageBoxOptions.OKCancel | 2 & 6 // MessageBoxOptions.AbortRetryIgnore | 3 & 4 & 5 // MessageBoxOptions.YesNoCancel | 6 & 7 & 2 // MessageBoxOptions.YesNo | 6 & 7 // MessageBoxOptions.RetryCancel | 4 & 2 // MessageBoxOptions.Toast | 2 // ----------------------------------------------------------------- Map<Integer, String> btnNameMaps = new HashMap<>(); btnNameMaps.put(2, "取消"); btnNameMaps.put(6, "确认"); // 用户自定义参数,前端会在afterConfirm中返回 //String customValue = "allowExport"; this.getView().showConfirm(top, body, options, confirmTypes, callBack, btnNameMaps,customValue); } }