فهرست منبع

教育培训任务代码,生成pdf代码提交

jingyuanchao 2 سال پیش
والد
کامیت
2f4118bc24
22فایلهای تغییر یافته به همراه696 افزوده شده و 48 حذف شده
  1. 15 3
      soc-api/soc-api-system/src/main/java/com/xunmei/system/api/RemoteFileService.java
  2. 11 7
      soc-api/soc-api-system/src/main/java/com/xunmei/system/api/factory/RemoteFileFallbackFactory.java
  3. 1 0
      soc-common/soc-common-core/src/main/java/com/xunmei/common/core/constant/ErrorMsgConstants.java
  4. 2 0
      soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/dto/CoreEduTrainingTaskEditDto.java
  5. 20 0
      soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/dto/CoreEduTrainingTaskSignDto.java
  6. 1 1
      soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/vo/CoreEduTrainingTaskDetailVo.java
  7. 84 0
      soc-common/soc-common-core/src/main/java/com/xunmei/common/core/enums/ExportPdfType.java
  8. 71 0
      soc-common/soc-common-core/src/main/java/com/xunmei/common/core/json/EnumSerializer.java
  9. 10 2
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/controller/CoreEduTrainingTaskController.java
  10. 1 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/mapper/CoreEduTrainingTaskToUserMapper.java
  11. 5 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/ICoreEduTrainingTaskService.java
  12. 95 1
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/impl/CoreEduTrainingTaskServiceImpl.java
  13. 8 0
      soc-modules/soc-modules-core/src/main/resources/mapper/edu/CoreEduTrainingTaskToUserMapper.xml
  14. 9 0
      soc-modules/soc-modules-file/pom.xml
  15. 19 23
      soc-modules/soc-modules-file/src/main/java/com/xunmei/file/controller/SysFileController.java
  16. 7 3
      soc-modules/soc-modules-file/src/main/java/com/xunmei/file/service/ISysFileService.java
  17. 40 7
      soc-modules/soc-modules-file/src/main/java/com/xunmei/file/service/LocalSysFileServiceImpl.java
  18. 267 0
      soc-modules/soc-modules-file/src/main/java/com/xunmei/file/utils/PdfUtil.java
  19. 26 0
      soc-modules/soc-modules-file/src/main/java/com/xunmei/file/vo/ItextPdfTableVo.java
  20. BIN
      soc-modules/soc-modules-file/src/main/resources/file/black.png
  21. BIN
      soc-modules/soc-modules-file/src/main/resources/lib/itext-4.2.1.jar
  22. 4 1
      soc-modules/soc-modules-system/src/main/java/com/xunmei/system/controller/SysDeptController.java

+ 15 - 3
soc-api/soc-api-system/src/main/java/com/xunmei/system/api/RemoteFileService.java

@@ -7,17 +7,19 @@ import com.xunmei.system.api.factory.RemoteFileFallbackFactory;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RequestPart;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.Map;
+
 /**
  * 文件服务
- * 
+ *
  * @author xunmei
  */
 @FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
-public interface RemoteFileService
-{
+public interface RemoteFileService {
     /**
      * 上传文件
      *
@@ -26,4 +28,14 @@ public interface RemoteFileService
      */
     @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     public R<SysFile> upload(@RequestPart(value = "file") MultipartFile file);
+
+    /**
+     * 生成教育培训登记簿
+     *
+     * @param data     文件信息
+     * @param cacheDir 缓存目录
+     * @return 结果
+     */
+    @PostMapping(value = "/generateEduTrainingPdf")
+    R<String> generateEduTrainingPdf(@RequestParam Map<String, Object> data, @RequestParam String fileName);
 }

+ 11 - 7
soc-api/soc-api-system/src/main/java/com/xunmei/system/api/factory/RemoteFileFallbackFactory.java

@@ -9,27 +9,31 @@ import org.springframework.cloud.openfeign.FallbackFactory;
 import org.springframework.stereotype.Component;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.Map;
+
 /**
  * 文件服务降级处理
- * 
+ *
  * @author xunmei
  */
 @Component
-public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService>
-{
+public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService> {
     private static final Logger log = LoggerFactory.getLogger(RemoteFileFallbackFactory.class);
 
     @Override
     public RemoteFileService create(Throwable throwable)
     {
         log.error("文件服务调用失败:{}", throwable.getMessage());
-        return new RemoteFileService()
-        {
+        return new RemoteFileService() {
             @Override
-            public R<SysFile> upload(MultipartFile file)
-            {
+            public R<SysFile> upload(MultipartFile file) {
                 return R.fail("上传文件失败:" + throwable.getMessage());
             }
+
+            @Override
+            public R<String> generateEduTrainingPdf(Map<String, Object> data, String cacheDir) {
+                return null;
+            }
         };
     }
 }

+ 1 - 0
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/constant/ErrorMsgConstants.java

@@ -7,4 +7,5 @@ public class ErrorMsgConstants {
 
     public static final String QUERY_ORG_DATA_ERROR = "获取机构信息失败!";
     public static final String QUERY_DICT_DATA_ERROR = "获取字典信息失败!";
+    public static final String GENERATE_PDF_ERROR = "生成PDF文件失败!";
 }

+ 2 - 0
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/dto/CoreEduTrainingTaskEditDto.java

@@ -6,6 +6,7 @@ import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingTaskToUser;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import javax.validation.constraints.NotNull;
 import java.util.Date;
 import java.util.List;
 
@@ -13,6 +14,7 @@ import java.util.List;
 public class CoreEduTrainingTaskEditDto {
 
 
+    @NotNull
     @JsonSerialize(using = com.fasterxml.jackson.databind.ser.std.ToStringSerializer.class)
     private Long id;
 

+ 20 - 0
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/dto/CoreEduTrainingTaskSignDto.java

@@ -0,0 +1,20 @@
+package com.xunmei.common.core.domain.edu.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CoreEduTrainingTaskSignDto {
+
+    @NotNull(message = "请选择任务进行签名!")
+    @ApiModelProperty(value = "教育培训任务Id")
+    private Long id;
+
+    @NotBlank(message = "未获取到签名信息!")
+    @ApiModelProperty(value = "签名图片文件地址")
+    private String signImage;
+
+}

+ 1 - 1
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/vo/CoreEduTrainingTaskDetailVo.java

@@ -55,7 +55,7 @@ public class CoreEduTrainingTaskDetailVo {
 
 
     @ApiModelProperty(value = "记录人名称")
-    private Long recorderName;
+    private String recorderName;
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     @ApiModelProperty(value = "计划任务开始日期")

+ 84 - 0
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/enums/ExportPdfType.java

@@ -0,0 +1,84 @@
+package com.xunmei.common.core.enums;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.xunmei.common.core.json.EnumSerializer;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author jingyuanchao
+ * @date 2022/10/17 15:58
+ */
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonSerialize(using = EnumSerializer.class)
+public enum ExportPdfType {
+    SECURITY_PERFORMANCE(0, "安保履职登记簿"),
+    EDUCATION_TRAINING(1, "教育培训登记簿"),
+    SAFETY_DRILL(2, "预案演练登记簿"),
+    SAFETY_CHECK_REPORT(3, "网点安全保卫履职每日"),
+    SAFETY_EDUCATION_REPORT(4, "网点安全保卫履职每月"),
+    PLAN_DRILL_REPORT(5, "网点安全保卫履职每季"),
+    INTELLIGENT_OPERATION_REPORT(6, "网点设备状态监测"),
+    DAY_OF_JKRESUMTPION(7, "金库安全保卫履职每日"),
+    QUARTER_OF_JKREUMPTION(8, "金库安全保卫履职每季"),
+    WEEK_OF_YJZXREUMPTION(9, "一级支行部门履职每周"),
+    MONTH_OF_YJZXREUMPTION(10, "一级支行部门履职每月"),
+    QUARTER_OF_YJZXREUMPTION(11, "一级支行部门履职每季"),
+    QUARTER_OF_YJZXFGHZREUMPTION(12, "一级支行分管行长季度"),
+    HALFYEAR_OF_YJZXFGHZREUMPTION(13, "一级支行分管行长半年"),
+    HALFYEAR_OF_YJZXREUMPTION(14, "一级支行部门履职半年"),
+    YEAR_OF_YJZXREUMPTION(15, "一级支行部门履职每年"),
+    WEEK_OF_JKREUMPTION(16, "金库安全保卫履职每周"),
+    MONTH_OF_JKREUMPTION(17, "金库安全保卫履职每月"),
+    YEAR_OF_JKREUMPTION(18, "金库安全保卫履职每年"),
+    WEEK_OF_WDREUMPTION(19, "网点安全保卫履职每周"),
+    YEAE_OF_WDREUMPTION(20, "网点安全保卫履职每年"),
+    DAY_OF_WDPROTECTION_DATA(21, "营业网点布防情况统计每日"),
+    DAY_OF_JKPROTECTION_DATA(22, "金库布防情况统计每日"),
+    VISIT_RECORD(23, "来访管理登记簿"),
+    JK_OPERATION_REPORT(24, "金库设备状态监测"),
+    DEVICE_STATISTICS_NUM(25, "营业网点安防消防设备器材统计"),
+
+    SAFE_CHECK_REPORT(26, "安全检查登记簿"),
+
+
+    ;
+
+
+    /**
+     * 所有枚举
+     */
+    private static final Map<Integer, ExportPdfType> enumMap = new LinkedHashMap<>();
+
+    static {
+        for (ExportPdfType typeEnum : ExportPdfType.values()) {
+            enumMap.put(typeEnum.num, typeEnum);
+        }
+    }
+
+    private int num;
+    private String text;
+
+    /**
+     * 根据code获取name
+     */
+    public static String getName(Integer num) {
+        ExportPdfType e = enumMap.get(num);
+        return e != null ? e.getText() : "";
+    }
+
+    /**
+     * 根据code获取name
+     */
+    public static ExportPdfType getEnums(Integer num) {
+        return enumMap.get(num);
+    }
+
+}

+ 71 - 0
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/json/EnumSerializer.java

@@ -0,0 +1,71 @@
+package com.xunmei.common.core.json;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.ReflectionUtils;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class EnumSerializer extends StdSerializer {
+
+    public static final String GET = "get";
+    private static final Map<Class, MethodDescriptor[]> CLASS_MAP = new HashMap<>();
+
+    public EnumSerializer() {
+        super(Object.class);
+    }
+
+    private static synchronized MethodDescriptor[] description(final Class aClass) {
+        if (CLASS_MAP.containsKey(aClass)) {
+            return CLASS_MAP.get(aClass);
+        }
+        final List<MethodDescriptor> result = new ArrayList<>(aClass.getMethods().length);
+        ReflectionUtils.doWithLocalMethods(aClass, method -> {
+            final String name = method.getName();
+            if (!StringUtils.equalsIgnoreCase(name, "getText")) {
+                return;
+            }
+            final MethodDescriptor methodDescriptor = new MethodDescriptor();
+            methodDescriptor.method = method;
+            methodDescriptor.fieldName = (StringUtils.substringAfter(method.getName(), GET));
+            result.add(methodDescriptor);
+        });
+        return result.toArray(new MethodDescriptor[result.size()]);
+    }
+
+    @Override
+    public void serialize(final Object o, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
+        // 写入枚举本身的值
+        final Enum e = (Enum) o;
+        jsonGenerator.writeString(e.name());
+
+        // 获取前缀
+        final String prefix = jsonGenerator.getOutputContext()
+                .getCurrentName();
+        if (prefix == null) {
+            return;
+        }
+
+        // 获取枚举其他属性, 获取输出
+        for (final MethodDescriptor methodDescriptor : CLASS_MAP.computeIfAbsent(o.getClass(), EnumSerializer::description)) {
+            jsonGenerator.writeObjectField(
+                    prefix + methodDescriptor.fieldName,
+                    ReflectionUtils.invokeMethod(methodDescriptor.method, o)
+            );
+        }
+    }
+
+    private static final class MethodDescriptor {
+        private Method method;
+        private String fieldName;
+    }
+
+
+}

+ 10 - 2
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/controller/CoreEduTrainingTaskController.java

@@ -5,6 +5,7 @@ import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingTask;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskEditDto;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskPageDto;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskReportDto;
+import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskSignDto;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskPageVo;
 import com.xunmei.common.core.web.controller.BaseController;
 import com.xunmei.common.core.web.domain.AjaxResult;
@@ -73,7 +74,7 @@ public class CoreEduTrainingTaskController extends BaseController {
     @RequiresPermissions("core:eduTask:edit")
     @Log(title = "教育任务", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody CoreEduTrainingTaskEditDto coreEduTrainingTask) {
+    public AjaxResult edit(@RequestBody @Validated CoreEduTrainingTaskEditDto coreEduTrainingTask) {
         return toAjax(coreEduTrainingTaskService.updateCoreEduTrainingTask(coreEduTrainingTask));
     }
 
@@ -104,9 +105,16 @@ public class CoreEduTrainingTaskController extends BaseController {
      */
     @ApiOperation(value = "导出CoreEduTrainingTask")
     @RequiresPermissions("core:eduTask:report")
-    @Log(title = "教育任务", businessType = BusinessType.DELETE)
     @DeleteMapping("report")
     public AjaxResult report(@RequestBody @Validated CoreEduTrainingTaskReportDto request) {
         return success(coreEduTrainingTaskService.selectCoreEduTrainingTaskReport(request));
     }
+
+    @ApiOperation(value = "教育培训签名")
+    @RequiresPermissions("core:eduTask:sign")
+    @Log(title = "教育任务签名", businessType = BusinessType.DELETE)
+    @DeleteMapping("sign")
+    public AjaxResult sign(@RequestBody @Validated CoreEduTrainingTaskSignDto request) {
+        return success(coreEduTrainingTaskService.selectCoreEduTrainingTaskSign(request));
+    }
 }

+ 1 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/mapper/CoreEduTrainingTaskToUserMapper.java

@@ -12,4 +12,5 @@ import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingTaskToUser;
  */
 public interface CoreEduTrainingTaskToUserMapper extends BaseMapper<CoreEduTrainingTaskToUser> {
 
+    int updateSign(CoreEduTrainingTaskToUser taskToUser);
 }

+ 5 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/ICoreEduTrainingTaskService.java

@@ -6,6 +6,7 @@ import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingTask;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskEditDto;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskPageDto;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskReportDto;
+import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskSignDto;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanDataVo;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskDetailVo;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskPageVo;
@@ -82,4 +83,8 @@ public interface ICoreEduTrainingTaskService extends IService<CoreEduTrainingTas
     void createTaskForNow(CoreEduTrainingPlanDataVo plan, Date start, Date end);
 
     List<CoreEduTrainingTaskReportVo> selectCoreEduTrainingTaskReport(CoreEduTrainingTaskReportDto request);
+
+    Integer selectCoreEduTrainingTaskSign(CoreEduTrainingTaskSignDto request);
+
+    String buildEduPdf(Long id);
 }

+ 95 - 1
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/impl/CoreEduTrainingTaskServiceImpl.java

@@ -12,16 +12,20 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.xunmei.common.core.constant.ErrorMsgConstants;
 import com.xunmei.common.core.constant.SecurityConstants;
 import com.xunmei.common.core.domain.DateRange;
+import com.xunmei.common.core.domain.R;
 import com.xunmei.common.core.domain.edu.domain.*;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskEditDto;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskPageDto;
 import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskReportDto;
+import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskSignDto;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanDataVo;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskDetailVo;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskPageVo;
 import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskReportVo;
+import com.xunmei.common.core.enums.ExportPdfType;
 import com.xunmei.common.core.enums.edu.EduTrainingDoStatus;
 import com.xunmei.common.core.enums.edu.EduTrainingType;
+import com.xunmei.common.core.exception.SystemException;
 import com.xunmei.common.core.utils.DateUtils;
 import com.xunmei.common.core.web.page.TableDataInfo;
 import com.xunmei.common.security.utils.SecurityUtils;
@@ -31,15 +35,20 @@ import com.xunmei.core.edu.mapper.CoreEduTrainingTaskToUserMapper;
 import com.xunmei.core.edu.service.ICoreEduTrainingTaskService;
 import com.xunmei.core.edu.service.ICoreEduTrainingTaskToRoleService;
 import com.xunmei.core.edu.service.ICoreEduTrainingTaskToUserService;
+import com.xunmei.system.api.RemoteFileService;
 import com.xunmei.system.api.RemoteOrgService;
 import com.xunmei.system.api.domain.SysOrg;
+import com.xunmei.system.api.domain.SysUser;
 import com.xunmei.system.api.function.RemoteCallHandlerExecutor;
+import io.netty.util.internal.StringUtil;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.io.File;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.NumberFormat;
@@ -60,6 +69,8 @@ public class CoreEduTrainingTaskServiceImpl extends ServiceImpl<CoreEduTrainingT
     @Autowired
     private RemoteOrgService orgService;
     @Autowired
+    private RemoteFileService fileService;
+    @Autowired
     private ICoreEduTrainingTaskToRoleService coreEduTrainingTaskToRoleService;
     @Autowired
     private CoreEduTrainingTaskToRoleMapper taskToRoleMapper;
@@ -107,7 +118,7 @@ public class CoreEduTrainingTaskServiceImpl extends ServiceImpl<CoreEduTrainingT
     public CoreEduTrainingTaskDetailVo selectCoreEduTrainingTaskById(Long id) {
         CoreEduTrainingTaskDetailVo detailVo = coreEduTrainingTaskMapper.selectEduTrainingTaskDetail(id);
         List<CoreEduTrainingTaskToUser> userList = taskToUserMapper.selectByMap(MapUtil.of("edu_training_task_id", id));
-        if(ObjectUtil.isNotEmpty(userList)){
+        if (ObjectUtil.isNotEmpty(userList)) {
             detailVo.setTaskUserList(userList);
         }
         return detailVo;
@@ -149,6 +160,10 @@ public class CoreEduTrainingTaskServiceImpl extends ServiceImpl<CoreEduTrainingT
 
         List<CoreEduTrainingTaskToUser> taskUserList = request.getTaskUserList();
         if (taskUserList != null && taskUserList.size() > 0) {
+            for (CoreEduTrainingTaskToUser taskToUser : taskUserList) {
+                taskToUser.setEduTrainingTaskId(request.getId());
+                taskToUser.setSign(0);
+            }
             coreEduTrainingTaskToUserService.saveBatch(taskUserList);
         }
         if (ObjectUtil.equal(request.getSubmitType(), 2)) {
@@ -287,6 +302,85 @@ public class CoreEduTrainingTaskServiceImpl extends ServiceImpl<CoreEduTrainingT
         percent.setMaximumFractionDigits(4);
         return percent.format(r.doubleValue());
     }
+
+    @Override
+    public Integer selectCoreEduTrainingTaskSign(CoreEduTrainingTaskSignDto request) {
+        SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
+        CoreEduTrainingTaskToUser taskToUser = taskToUserMapper.selectOne(new LambdaQueryWrapper<CoreEduTrainingTaskToUser>()
+                .eq(CoreEduTrainingTaskToUser::getEduTrainingTaskId, request.getId())
+                .eq(CoreEduTrainingTaskToUser::getType, 1)
+                .eq(CoreEduTrainingTaskToUser::getUserId, sysUser.getId()));
+        if (taskToUser == null) {
+            throw new SystemException("未获取到当前用户于该教育培训的详细信息");
+        }
+        taskToUser.setSign(1);
+        taskToUser.setSignImage(request.getSignImage());
+        return taskToUserMapper.updateSign(taskToUser);
+    }
+
+    @Override
+    public String buildEduPdf(Long id) {
+        CoreEduTrainingTaskDetailVo task = this.selectCoreEduTrainingTaskById(id);
+        SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(task.getOrgId(), SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+        String[] strings = sysOrg.getPath().split("-");
+        List<Long> list = Arrays.stream(strings).map(Long::valueOf).collect(Collectors.toList());
+        List<SysOrg> sysOrgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgByIdList(list, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+        String orgName = sysOrgList.stream().map(SysOrg::getName).collect(Collectors.joining("_"));
+
+        String fileName = orgName + "_" + ExportPdfType.EDUCATION_TRAINING.getText() + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".pdf";
+        Map<String, Object> data = this.getFtlEdu(task);
+
+        R<String> r = RemoteCallHandlerExecutor.executeRemoteCall(() -> fileService.generateEduTrainingPdf(data, fileName), ErrorMsgConstants.GENERATE_PDF_ERROR);
+        if (ObjectUtil.hasEmpty(r, r.getData())) {
+            throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+        }
+
+       /* //新方式生成pdf
+        try {
+            String url = createEduPdfByNewType(data, dest);
+            //此处set以后 jpa框架自动保存入库
+            edu.setPdfUrl(url);
+
+            final RegisterBookPdf bookPdf = new RegisterBookPdf();
+            bookPdf.setId(IDHelper.id());
+            bookPdf.setRegisterBookType(ExportPdfType.EDUCATION_TRAINING);
+            bookPdf.setDate(new Date());
+            bookPdf.setOrgId(edu.getOrgId());
+            bookPdf.setPdfUrl(url);
+            registerBookPdfMapper.insert(bookPdf);
+            return url;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }*/
+        return r.getData();
+    }
+
+    private Map<String, Object> getFtlEdu(CoreEduTrainingTaskDetailVo task) {
+        Map<String, Object> data = new HashMap<>();
+        String time = DateUtil.format(task.getTrainingStartDateTime(), "yyyy年MM月dd日");
+        String address = task.getOrgName();
+        String hostName = task.getHostName() == null ? StringUtil.EMPTY_STRING : task.getHostName();
+        String recorderName = task.getRecorderName() == null ? StringUtil.EMPTY_STRING : task.getRecorderName();
+        String content = task.getContent();
+        String note = task.getNote();
+        data.put("time", StringUtils.isNotEmpty(time) ? time : StringUtil.EMPTY_STRING);
+        data.put("address", StringUtils.isNotEmpty(address) ? time : StringUtil.EMPTY_STRING);
+        data.put("hostName", StringUtils.isNotEmpty(hostName) ? hostName : StringUtil.EMPTY_STRING);
+        data.put("recorderName", StringUtils.isNotEmpty(recorderName) ? recorderName : StringUtil.EMPTY_STRING);
+        data.put("content", StringUtils.isNotEmpty(content) ? "内容: " + content : StringUtil.EMPTY_STRING);
+        data.put("note", StringUtils.isNotEmpty(note) ? "总结: " + note : StringUtil.EMPTY_STRING);
+        data.put("image", ObjectUtil.isNotEmpty(task.getTaskUserList()) ? task.getTaskUserList() : StringUtil.EMPTY_STRING);
+        return data;
+    }
+
+    private String generateFilePath(String fileName) {
+        String resource = "cache";
+        File file = new File(resource);
+        if (!file.exists()) {
+            file.mkdirs();
+        }
+        return resource + File.separator + fileName;
+    }
 }
 
 

+ 8 - 0
soc-modules/soc-modules-core/src/main/resources/mapper/edu/CoreEduTrainingTaskToUserMapper.xml

@@ -14,4 +14,12 @@
         select edu_training_task_id, user_id, type
         from core_edu_training_task_to_user
     </sql>
+
+    <update id="updateSign">
+        update core_edu_training_task_to_user
+        set sign      = 1,
+            sign_image=#{signImage}
+        where edu_training_task_id = #{eduTrainingTaskId}
+          and user_id = #{userId}
+    </update>
 </mapper>

+ 9 - 0
soc-modules/soc-modules-file/pom.xml

@@ -61,6 +61,15 @@
             <artifactId>hutool-all</artifactId>
         </dependency>
 
+
+        <dependency>
+            <groupId>com.lowagie</groupId>
+            <artifactId>itext</artifactId>
+            <version>4.2.2</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/src/main/resources/lib/itext-4.2.1.jar</systemPath>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 19 - 23
soc-modules/soc-modules-file/src/main/java/com/xunmei/file/controller/SysFileController.java

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
 
 /**
  * 文件请求处理
@@ -21,8 +22,7 @@ import javax.servlet.http.HttpServletResponse;
  */
 @RestController
 @RequestMapping("/file")
-public class SysFileController
-{
+public class SysFileController {
     private static final Logger log = LoggerFactory.getLogger(SysFileController.class);
 
     @Autowired
@@ -41,17 +41,14 @@ public class SysFileController
     public String prefix;
 
 
-
     private static final String FILE_SUFFIX = "FILE_CODE_";
 
     /**
      * 文件上传请求
      */
     @PostMapping("/upload")
-    public R<SysFile> upload(MultipartFile file)
-    {
-        try
-        {
+    public R<SysFile> upload(MultipartFile file) {
+        try {
             // 上传并返回访问地址
             String url = sysFileService.uploadFile(file);
             SysFile sysFile = new SysFile();
@@ -61,21 +58,17 @@ public class SysFileController
             sysFile.setUrl(url);
             sysFile.setCode(code);
             return R.ok(sysFile);
-        }
-        catch (Exception e)
-        {
+        } catch (Exception e) {
             log.error("上传文件失败", e);
             return R.fail(e.getMessage());
         }
     }
 
     @PostMapping("/uploadFile")
-    public R<SysFile> uploadFile(MultipartFile file,String busType)
-    {
-        try
-        {
+    public R<SysFile> uploadFile(MultipartFile file, String busType) {
+        try {
             // 上传并返回访问地址
-            String url = sysFileService.uploadFile(file,busType);
+            String url = sysFileService.uploadFile(file, busType);
             SysFile sysFile = new SysFile();
             sysFile.setName(FileUtils.getName(url));
             String code = DesUtil.encrypt(url, secretKey);
@@ -83,21 +76,18 @@ public class SysFileController
             sysFile.setUrl(url);
             sysFile.setCode(code);
             return R.ok(sysFile);
-        }
-        catch (Exception e)
-        {
+        } catch (Exception e) {
             log.error("上传文件失败", e);
             return R.fail(e.getMessage());
         }
     }
 
 
-
     @PostMapping("/downloadFile")
-    public void downloadFile(HttpServletResponse response,@RequestBody SysFile sysFile){
+    public void downloadFile(HttpServletResponse response, @RequestBody SysFile sysFile) {
         try {
             String filePath = DesUtil.decode(sysFile.getCode(), secretKey);
-            sysFileService.downloadFile(response,filePath);
+            sysFileService.downloadFile(response, filePath);
         } catch (Exception e) {
             log.error("下载文件失败", e);
             throw new RuntimeException(e);
@@ -106,19 +96,25 @@ public class SysFileController
 
     /**
      * 路径参数
+     *
      * @param response
      * @param code
      */
     @GetMapping("/getFile/{code}")
-    public void getFile(HttpServletResponse response, @PathVariable String code){
+    public void getFile(HttpServletResponse response, @PathVariable String code) {
         try {
             String filePath = DesUtil.decode(code, secretKey);
-            sysFileService.downloadFile(response,filePath);
+            sysFileService.downloadFile(response, filePath);
         } catch (Exception e) {
             log.error("下载文件失败", e);
             throw new RuntimeException(e);
         }
     }
 
+    @PostMapping(value = "/generateEduTrainingPdf")
+    R<String> generateEduTrainingPdf(@RequestParam Map<String, Object> data, @RequestParam String cacheDir) throws Exception {
 
+        return R.ok(sysFileService.generateEduTrainingPdf(data, cacheDir));
+
+    }
 }

+ 7 - 3
soc-modules/soc-modules-file/src/main/java/com/xunmei/file/service/ISysFileService.java

@@ -3,7 +3,7 @@ package com.xunmei.file.service;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayOutputStream;
+import java.util.Map;
 
 /**
  * 文件上传接口
@@ -29,14 +29,18 @@ public interface ISysFileService
      * @return 访问地址
      * @throws Exception
      */
-    String uploadFile(MultipartFile file,String busType) throws Exception;
+    String uploadFile(MultipartFile file, String busType) throws Exception;
 
     /**
      * 文件下载接口
+     *
      * @param response
      * @param filePath
      * @return
      * @throws Exception
      */
-    void downloadFile(HttpServletResponse response,String filePath)throws Exception;
+    void downloadFile(HttpServletResponse response, String filePath) throws Exception;
+
+    String generateEduTrainingPdf(Map<String, Object> data, String cacheDir) throws Exception;
+
 }

+ 40 - 7
soc-modules/soc-modules-file/src/main/java/com/xunmei/file/service/LocalSysFileServiceImpl.java

@@ -1,8 +1,16 @@
 package com.xunmei.file.service;
 
+import cn.hutool.core.date.DateUtil;
+import com.lowagie.text.Document;
+import com.lowagie.text.Font;
+import com.lowagie.text.pdf.BaseFont;
+import com.lowagie.text.pdf.PdfPTable;
+import com.lowagie.text.pdf.PdfWriter;
 import com.xunmei.common.core.utils.uuid.UUID;
 import com.xunmei.file.utils.FileDownUtils;
 import com.xunmei.file.utils.FileUploadUtils;
+import com.xunmei.file.utils.PdfUtil;
+import com.xunmei.file.vo.ItextPdfTableVo;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -19,6 +27,8 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.Map;
 
 /**
  * 本地文件存储
@@ -27,8 +37,7 @@ import java.nio.charset.StandardCharsets;
  */
 @Primary
 @Service
-public class LocalSysFileServiceImpl implements ISysFileService
-{
+public class LocalSysFileServiceImpl implements ISysFileService {
 
     private static final Logger log = LoggerFactory.getLogger(LocalSysFileServiceImpl.class);
 
@@ -41,6 +50,10 @@ public class LocalSysFileServiceImpl implements ISysFileService
     @Autowired
     private HttpServletRequest request;
 
+    private static String getLocalFilePath(String businessType, String fileName) {
+        return File.separator + businessType + File.separator + DateUtil.format(new Date(), "yyyy" + File.separator + "MM" + File.separator + "dd" + File.separator) + fileName;
+    }
+
     /**
      * 本地文件上传接口
      *
@@ -49,8 +62,7 @@ public class LocalSysFileServiceImpl implements ISysFileService
      * @throws Exception
      */
     @Override
-    public String uploadFile(MultipartFile file) throws Exception
-    {
+    public String uploadFile(MultipartFile file) throws Exception {
         String name = FileUploadUtils.upload(localFilePath, file);
 //        String url = domain + localFilePrefix + name;
         return name;
@@ -58,17 +70,17 @@ public class LocalSysFileServiceImpl implements ISysFileService
 
     @Override
     public String uploadFile(MultipartFile file, String busType) throws Exception {
-        String name = FileUploadUtils.upload(localFilePath, file,busType);
+        String name = FileUploadUtils.upload(localFilePath, file, busType);
 //        String url = domain + localFilePrefix + name;
         return name;
     }
 
     @Override
-    public void downloadFile(HttpServletResponse response, String filePath){
+    public void downloadFile(HttpServletResponse response, String filePath) {
         ByteArrayOutputStream out = null;
         try {
             filePath = localFilePath + filePath;
-            filePath = URLDecoder.decode(filePath,"UTF-8");
+            filePath = URLDecoder.decode(filePath, "UTF-8");
             out = FileDownUtils.downloadFile(filePath);
             String fileSuffix = FileDownUtils.getFileSuffix(filePath);
             String formFileName = UUID.randomUUID().toString() + fileSuffix;
@@ -100,4 +112,25 @@ public class LocalSysFileServiceImpl implements ISysFileService
             }
         }
     }
+
+    @Override
+    public String generateEduTrainingPdf(Map<String, Object> data, String filename) throws Exception {
+        String filePath = this.localFilePath + getLocalFilePath("edu", filename);
+        final ItextPdfTableVo pdfTableVo = PdfUtil.createTable(filePath, 6, 10);
+        final Document document = pdfTableVo.getDocument();
+        final PdfWriter writer = pdfTableVo.getWriter();
+        final PdfPTable table = pdfTableVo.getTable();
+        final BaseFont fs = pdfTableVo.getFs();
+        final Font tableFont = pdfTableVo.getTableFont();
+
+        PdfUtil.dealHeader(document, fs, "学 习 教 育 记 录", 24);
+
+        PdfUtil.dealEduBody(document, table, tableFont, data);
+
+        document.close();
+        writer.close();
+
+        return filePath;
+    }
+
 }

+ 267 - 0
soc-modules/soc-modules-file/src/main/java/com/xunmei/file/utils/PdfUtil.java

@@ -0,0 +1,267 @@
+package com.xunmei.file.utils;
+
+
+import cn.hutool.core.io.resource.ClassPathResource;
+import com.lowagie.text.*;
+import com.lowagie.text.pdf.*;
+import com.xunmei.file.vo.ItextPdfTableVo;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PdfUtil {
+
+
+    public static void main(String[] args) throws Exception {
+        //Itext4Pdf();
+        long start = System.currentTimeMillis();
+        // createPdf("d:/test.pdf");
+        long end = System.currentTimeMillis();
+        System.out.println(end - start);
+    }
+
+    public static ItextPdfTableVo createTable(String filename, int numColumns, int fontSize) throws Exception {
+        Document document = new Document(PageSize.A4, 0, 0, 50, 0);//SUPPRESS
+        FileOutputStream fos = new FileOutputStream(filename);
+        final PdfWriter writer = PdfWriter.getInstance(document, fos);
+        document.open();
+        // 使用语言包字
+        BaseFont abf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
+        // 外部字体
+        BaseFont fs = BaseFont.createFont("/fonts/msyh.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
+        Font tableFont = new Font(fs, fontSize, Font.NORMAL);
+        PdfPTable table = new PdfPTable(numColumns);
+        // 设置各列列宽
+        // table.setTotalWidth(new float[]{90, 100, 100, 120, 100, 100});
+        table.setSpacingBefore(16f);
+        ItextPdfTableVo itextPdfTableVo = new ItextPdfTableVo();
+        itextPdfTableVo.setDocument(document);
+        itextPdfTableVo.setWriter(writer);
+        itextPdfTableVo.setAbf(abf);
+        itextPdfTableVo.setFs(fs);
+        itextPdfTableVo.setTableFont(tableFont);
+        itextPdfTableVo.setTable(table);
+        return itextPdfTableVo;
+    }
+
+
+    public static PdfPCell createPDFCell(Font tableFont, PdfPTable table, String content, int align, Integer colspan, Integer rowspan) {
+        final PdfPCell cell = cell(tableFont, content, align, colspan, rowspan);
+        table.addCell(cell);
+        return cell;
+    }
+
+    public static PdfPCell createPDFCell(Font tableFont, PdfPTable table, String content, int align, Integer colspan, Integer rowspan, Integer lineSpacing) {
+        final PdfPCell cell = cell(tableFont, content, align, colspan, rowspan, lineSpacing);
+        table.addCell(cell);
+        return cell;
+    }
+
+    //底部无边框的单元格
+    public static PdfPCell createPDFCellWithoutBorder(Font tableFont, PdfPTable table, String content, int align, Integer colspan, Integer rowspan) {
+        final PdfPCell cell = cell(tableFont, content, align, colspan, rowspan);
+        cell.setBorder(Rectangle.LEFT | Rectangle.RIGHT);
+        table.addCell(cell);
+        return cell;
+    }
+
+    private static PdfPCell cell(Font tableFont, String content, int align, Integer colspan, Integer rowspan) {
+        PdfPCell cell = new PdfPCell(new Phrase(content, tableFont));
+        if (colspan != null && colspan > 0) {
+            cell.setColspan(colspan);
+        }
+        if (rowspan != null && rowspan > 0) {
+            cell.setRowspan(rowspan);
+        }
+        if (PdfPCell.ALIGN_MIDDLE != align) {
+            cell.setHorizontalAlignment(align);
+            cell.setPaddingLeft(8f);
+            cell.setPaddingRight(8f);
+            cell.setPaddingBottom(8f);
+        } else {
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);//设置单元格的垂直对齐方式
+            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+        }
+        return cell;
+    }
+
+    private static PdfPCell cell(Font tableFont, String content, int align, Integer colspan, Integer rowspan, Integer lineSpacing) {
+        PdfPCell cell = new PdfPCell(new Phrase(content, tableFont));
+        if (colspan != null && colspan > 0) {
+            cell.setColspan(colspan);
+        }
+        if (rowspan != null && rowspan > 0) {
+            cell.setRowspan(rowspan);
+        }
+        cell.setLeading(lineSpacing, 0);
+        if (PdfPCell.ALIGN_MIDDLE != align) {
+            cell.setHorizontalAlignment(align);
+            cell.setPaddingLeft(8f);
+            cell.setPaddingRight(8f);
+            cell.setPaddingBottom(8f);
+        } else {
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);//设置单元格的垂直对齐方式
+            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+        }
+        return cell;
+    }
+
+    /**
+     * 生成文字类型的水印
+     */
+    public static void createWatermark(Document document, PdfWriter writer, Font waterMarkFont, String content) throws DocumentException, IOException {
+        PdfContentByte waterMarkPdfContent = writer.getDirectContentUnder();
+        Phrase phrase = new Phrase(content, waterMarkFont);
+        float pageWidth = document.right() + document.left();//获取pdf内容正文页面宽度
+        float pageHeight = document.top() + document.bottom();//获取pdf内容正文页面高度
+        //两行三列
+        ColumnText.showTextAligned(waterMarkPdfContent, Element.ALIGN_CENTER, phrase,
+                pageWidth * 0.25f, pageHeight * 0.2f, 45);
+        ColumnText.showTextAligned(waterMarkPdfContent, Element.ALIGN_CENTER, phrase,
+                pageWidth * 0.25f, pageHeight * 0.5f, 45);
+        ColumnText.showTextAligned(waterMarkPdfContent, Element.ALIGN_CENTER, phrase,
+                pageWidth * 0.25f, pageHeight * 0.8f, 45);
+        ColumnText.showTextAligned(waterMarkPdfContent, Element.ALIGN_CENTER, phrase,
+                pageWidth * 0.65f, pageHeight * 0.2f, 45);
+        ColumnText.showTextAligned(waterMarkPdfContent, Element.ALIGN_CENTER, phrase,
+                pageWidth * 0.65f, pageHeight * 0.5f, 45);
+        ColumnText.showTextAligned(waterMarkPdfContent, Element.ALIGN_CENTER, phrase,
+                pageWidth * 0.65f, pageHeight * 0.8f, 45);
+    }
+
+
+    public static void dealHeader(Document document, BaseFont fs, String title, int fontSize) throws DocumentException {
+        //文件title
+        Paragraph p = new Paragraph(title, new Font(fs, fontSize, Font.NORMAL));
+        p.setAlignment(Paragraph.ALIGN_CENTER);
+        // 文件title 段落下空白
+        p.setSpacingAfter(10f);
+        p.setAlignment(Element.ALIGN_CENTER);
+        document.add(p);
+    }
+
+    public static void dealEduBody(Document document, PdfPTable table, Font tableFont, Map<String, Object> data) throws Exception {
+        //第一行
+        createPDFCell(tableFont, table, "时间", Element.ALIGN_CENTER, 1, 1);
+        createPDFCell(tableFont, table, data.get("time").toString(), Element.ALIGN_CENTER, 2, 1);
+        createPDFCell(tableFont, table, "地点", Element.ALIGN_CENTER, 1, 1);
+        createPDFCell(tableFont, table, data.get("address").toString(), Element.ALIGN_CENTER, 2, 1);
+        //第二行
+        createPDFCell(tableFont, table, "主持人", Element.ALIGN_CENTER, 1, 1);
+        createPDFCell(tableFont, table, data.get("hostName").toString(), Element.ALIGN_CENTER, 2, 1);
+        createPDFCell(tableFont, table, "记录人", Element.ALIGN_CENTER, 1, 1);
+        createPDFCell(tableFont, table, data.get("recorderName").toString(), Element.ALIGN_CENTER, 2, 1);
+        //内容
+        PdfPCell contentCell = new PdfPCell();
+        contentCell.setColspan(6);
+        Paragraph content = new Paragraph();
+        String text = data.get("content").toString();
+        content.add(new Chunk(text, tableFont));
+        contentCell.addElement(content);
+        contentCell.setBorder(Rectangle.LEFT | Rectangle.RIGHT);
+        table.addCell(contentCell);
+
+        //总结
+        PdfPCell noteCell = new PdfPCell();
+        noteCell.setColspan(6);
+        Paragraph paragraph = new Paragraph();
+        String noteText = data.get("note").toString();
+        paragraph.add(new Chunk(noteText, tableFont));
+        noteCell.addElement(paragraph);
+        noteCell.setBorder(Rectangle.LEFT | Rectangle.RIGHT);
+        table.addCell(noteCell);
+        //图片填充
+        final PdfPTable imageTable = getImage((List<String>) data.get("image"), 12);
+        final PdfPCell cell = new PdfPCell();
+        cell.setNoWrap(false);
+        cell.setPaddingLeft(8f);
+        cell.setPaddingRight(8f);
+        cell.setPaddingBottom(8f);
+        cell.setPaddingTop(8f);
+        cell.setColspan(6);
+        cell.setBorder(Rectangle.LEFT | Rectangle.RIGHT | Rectangle.BOTTOM);
+        cell.addElement(imageTable);
+        table.addCell(cell);
+
+        //第三行
+        createPDFCell(tableFont, table, "参会人员签字", Element.ALIGN_CENTER, 1, 1);
+        createPDFCell(tableFont, table, data.get("users").toString(), Element.ALIGN_CENTER, 5, 1);
+
+        document.add(table);
+    }
+
+    private static PdfPTable getImage(List<String> images, int totalImages) throws Exception {
+        if (images == null) {
+            images = new ArrayList<>();
+        }
+        PdfPTable innerTable = new PdfPTable(3);
+        /*for (int i = 0; i < 7; i++) {
+            //模拟数据
+            images.add("1.jpg");
+        }*/
+        //这里根据实际图片数量来判断是否需要补充白色图片,保证每行显示3张图片,用以填充空白
+        final int reallySize = images.size();
+        //此处重新new对象, JPA会自动将images的更新持久化到数据,导致数据出错
+        List<String> list = new ArrayList<>(images);
+        for (int i = 0; i < totalImages - reallySize && totalImages > reallySize; i++) {
+            ClassPathResource resource = new ClassPathResource("file" + File.separator + "black.png");
+            String path = resource.getPath();
+            list.add(path);
+        }
+        //分割,每行显示3张图片,获取分割的行数
+        List<List<String>> rows = new ArrayList<>();
+        for (int i = 0; i < list.size(); i += 3) {
+            List<String> row = list.subList(i, Math.min(i + 3, list.size()));
+            rows.add(row);
+        }
+
+        for (List<String> row : rows) {
+            for (String image : row) {
+                Image imageData = null;
+                if (image.contains("black.png")) {
+                    imageData = Image.getInstance(image);
+                    //判断意外情况,比如环境中不存在该图片,则跳过
+                    if (imageData == null) {
+                        continue;
+                    }
+                } else {
+                    byte[] bytes = convertFileToByteArray(new File(image));
+                    imageData = Image.getInstance(bytes);
+                }
+                imageData.scaleAbsolute(100, 100);
+                PdfPCell cell = new PdfPCell(Image.getInstance(imageData));
+                cell.setBorder(Rectangle.NO_BORDER);
+                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
+                innerTable.addCell(cell);
+            }
+            //实际上这儿永远不会存在不满足3个的情况,因为上面会根据图片数量补全到十二个
+            //具体补全数量可以根据实际图片大小与页面尺寸来调整
+            int size = row.size();
+            while (size < 3) {
+                PdfPCell emptyCell = new PdfPCell();
+                emptyCell.setBorder(Rectangle.NO_BORDER);
+                innerTable.addCell(emptyCell);
+                size++;
+            }
+        }
+        PdfPTable outerTable = new PdfPTable(1);
+        PdfPCell innerCell = new PdfPCell(innerTable);
+        innerCell.setBorder(Rectangle.NO_BORDER);
+        outerTable.addCell(innerCell);
+        return outerTable;
+    }
+
+    public static byte[] convertFileToByteArray(File file) throws IOException {
+        FileInputStream fis = new FileInputStream(file);
+        byte[] byteArray = new byte[(int) file.length()];
+        fis.read(byteArray);
+        fis.close();
+        return byteArray;
+    }
+}

+ 26 - 0
soc-modules/soc-modules-file/src/main/java/com/xunmei/file/vo/ItextPdfTableVo.java

@@ -0,0 +1,26 @@
+package com.xunmei.file.vo;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.Font;
+import com.lowagie.text.pdf.BaseFont;
+import com.lowagie.text.pdf.PdfPTable;
+import com.lowagie.text.pdf.PdfWriter;
+import lombok.Data;
+
+/**
+ * @author jingyuanchao
+ * @date 2023/4/19 15:11
+ */
+
+@Data
+public class ItextPdfTableVo {
+
+
+    private Document document;
+    private PdfWriter writer;
+    private BaseFont abf;
+    private BaseFont fs;
+    private Font tableFont;
+    private PdfPTable table;
+
+}

BIN
soc-modules/soc-modules-file/src/main/resources/file/black.png


BIN
soc-modules/soc-modules-file/src/main/resources/lib/itext-4.2.1.jar


+ 4 - 1
soc-modules/soc-modules-system/src/main/java/com/xunmei/system/controller/SysDeptController.java

@@ -27,6 +27,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 
@@ -214,7 +215,9 @@ public class SysDeptController extends BaseController {
         if (ObjectUtil.isEmpty(orgList)) {
             return new ArrayList<>();
         }
-        return orgService.listByIds(orgList);
+        List<SysOrg> sysOrgs = orgService.listByIds(orgList);
+        sysOrgs.sort(Comparator.comparing(SysOrg::getId));
+        return sysOrgs;
     }
 
     @ApiOperation(value = "根据用户id获取机构信息", notes = "根据用户id获取机构信息")