diff --git a/src/main/java/com/budwk/app/sys/controller/v4/SysV4ServController.java b/src/main/java/com/budwk/app/sys/controller/v4/SysV4ServController.java index 7f3e393..c920b80 100644 --- a/src/main/java/com/budwk/app/sys/controller/v4/SysV4ServController.java +++ b/src/main/java/com/budwk/app/sys/controller/v4/SysV4ServController.java @@ -57,6 +57,8 @@ public class SysV4ServController { $condition """); Cnd cnd = Cnd.NEW(); + // 先取每个流程的最新定义,再判断是否启用,避免最新版本停用后回退展示旧版本。 + cnd.and("t.state", "=", 1); if (StrUtil.isNotBlank(keyword)) { cnd.where().andLike("t.disPlayName", keyword); } diff --git a/src/main/java/com/budwk/app/zhgh/activity/sports/service/impl/ActivitySportsApplyUserServiceImpl.java b/src/main/java/com/budwk/app/zhgh/activity/sports/service/impl/ActivitySportsApplyUserServiceImpl.java index 6a6b238..eb5dce6 100644 --- a/src/main/java/com/budwk/app/zhgh/activity/sports/service/impl/ActivitySportsApplyUserServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/activity/sports/service/impl/ActivitySportsApplyUserServiceImpl.java @@ -620,6 +620,27 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl { entities.add(new ExcelExportEntity(option.getOptionName(), option.getOptionName(), 20)); }); + // 签字列先按空白文本导出,图片另行写入,避开 EasyPOI 对 Map 图片字段的反射。 ExcelExportEntity userSignEntity = new ExcelExportEntity("签字", "userSign", 20); - userSignEntity.setType(2); - userSignEntity.setExportImageType(2); entities.add(userSignEntity); // 导出 - Workbook workbook = new HSSFWorkbook(); + Workbook workbook = new XSSFWorkbook(); listMap.forEach((k, v) -> { + List signatures = new ArrayList<>(); + v.forEach(row -> { + Object signature = row.remove("userSign"); + signatures.add(signature instanceof byte[] ? (byte[]) signature : null); + }); ExcelExportService service = new ExcelExportService(); ExportParams exportParams = new ExportParams(); exportParams.setSheetName(k); - exportParams.setType(ExcelType.HSSF); + exportParams.setType(ExcelType.XSSF); + int firstSheet = workbook.getNumberOfSheets(); service.createSheetForMap(workbook, exportParams, entities, v); + // 无标题、单层列头的数据从第二行开始;按新增 Sheet 顺序兼容 EasyPOI 自动拆表。 + int signatureIndex = 0; + for (int sheetIndex = firstSheet; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { + Sheet sheet = workbook.getSheetAt(sheetIndex); + Drawing drawing = sheet.createDrawingPatriarch(); + for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum() && signatureIndex < signatures.size(); rowIndex++) { + byte[] signature = signatures.get(signatureIndex++); + if (signature != null && signature.length > 0) { + insertReceiveSignature(workbook, sheet, drawing, rowIndex, entities.size() - 1, signature); + } + } + } }); - CommonDownloadUtil.download("领取表.xls", workbook, response); + CommonDownloadUtil.download("领取表.xlsx", workbook, response); + } + + /** + * 将签字字节数组写入领取表指定单元格。行列索引从 0 开始,图片统一转为 PNG; + * 无法解码的图片仅记录日志并保留空白签字格,不中断其他人员的导出。 + */ + private void insertReceiveSignature(Workbook workbook, Sheet sheet, Drawing drawing, + int rowIndex, int columnIndex, byte[] signature) { + try (ByteArrayInputStream input = new ByteArrayInputStream(signature); + ByteArrayOutputStream output = new ByteArrayOutputStream()) { + BufferedImage image = ImageIO.read(input); + if (image == null) { + log.warn("领取表签字图片无法识别,Sheet={},行={}", sheet.getSheetName(), rowIndex + 1); + return; + } + ImageIO.write(image, "png", output); + Row row = sheet.getRow(rowIndex); + row.setHeightInPoints(Math.max(row.getHeightInPoints(), 50)); + ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor(); + anchor.setCol1(columnIndex); + anchor.setCol2(columnIndex + 1); + anchor.setRow1(rowIndex); + anchor.setRow2(rowIndex + 1); + anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE); + drawing.createPicture(anchor, workbook.addPicture(output.toByteArray(), Workbook.PICTURE_TYPE_PNG)); + } catch (Exception e) { + log.error("领取表签字图片写入失败,Sheet={},行={}", sheet.getSheetName(), rowIndex + 1, e); + } } } diff --git a/src/main/resources/static/assets/platform/css/home-portal.css b/src/main/resources/static/assets/platform/css/home-portal.css index 1f9174f..a558c20 100644 --- a/src/main/resources/static/assets/platform/css/home-portal.css +++ b/src/main/resources/static/assets/platform/css/home-portal.css @@ -124,7 +124,10 @@ #v4-home-app .todo-center .el-tabs__nav { display: flex; width: 100%; border-color: #e9eff6; border-radius: 6px 6px 0 0; } #v4-home-app .todo-center .el-tabs__item { flex: 1; min-width: 0; padding: 0 7px; font-size: 12px; height: 36px; line-height: 36px; text-align: center; } #v4-home-app .todo-center .el-tabs__item.is-active { border-bottom: 2px solid #1687f5; color: #1687f5; } -#v4-home-app .portal-task-list { display: flex; flex-direction: column; justify-content: space-evenly; flex: 1; min-height: 180px; } +/* 任务从标签栏下方依次排列,避免单条记录被剩余高度推到中间。 */ +#v4-home-app .portal-task-list { display: flex; flex-direction: column; justify-content: flex-start; flex: 1; min-height: 180px; } +/* 空数据提示独立占满列表区域,保留居中展示。 */ +#v4-home-app .portal-task-list > .portal-empty { flex: 1; } #v4-home-app .portal-task-row { display: flex; gap: 10px; align-items: center; padding: 8px 6px; border-bottom: 1px solid #eef3f8; } #v4-home-app .portal-task-row:last-child { border-bottom: 0; } #v4-home-app .portal-task-row:hover { background: #f7fbff; } diff --git a/src/main/resources/views/layouts/v4/home/index.html b/src/main/resources/views/layouts/v4/home/index.html index 34aaa19..eb141cc 100644 --- a/src/main/resources/views/layouts/v4/home/index.html +++ b/src/main/resources/views/layouts/v4/home/index.html @@ -181,7 +181,7 @@ layout("/layouts/v4/baseLayout.html"){ - +